# For kernels 2.6.24.x only. Applying ieee80211 patch is required too. Some distros may require the 2.6.25.x version of the patch # Features: sets monitor mode properly, discards invalid frames, ... diff -pur linux-2.6.24.4-zd1211rw/drivers/net/wireless/zd1211rw/zd_mac.c linux-2.6.24.4-sud/drivers/net/wireless/zd1211rw/zd_mac.c --- linux-2.6.24.4-zd1211rw/drivers/net/wireless/zd1211rw/zd_mac.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.4-sud/drivers/net/wireless/zd1211rw/zd_mac.c 2008-04-12 21:21:59.000000000 +0200 @@ -163,8 +163,17 @@ void zd_mac_clear(struct zd_mac *mac) static int set_rx_filter(struct zd_mac *mac) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER; - return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); + struct zd_ioreq32 ioreqs[] = { + { CR_RX_FILTER, STA_RX_FILTER }, + { CR_SNIFFER_ON, 0U }, + }; + + if (ieee->iw_mode == IW_MODE_MONITOR) { + ioreqs[0].value = 0xffffffff; + ioreqs[1].value = 0x1; + } + + return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs)); } static int set_sniffer(struct zd_mac *mac) @@ -236,7 +245,13 @@ int zd_mac_open(struct net_device *netde goto disable_rx; housekeeping_enable(mac); - ieee80211softmac_start(netdev); + netif_carrier_on(netdev); + ieee80211softmac_start(netdev); + if(!netif_queue_stopped(netdev)) + netif_start_queue(netdev); + else + netif_wake_queue(netdev); + return 0; disable_rx: zd_chip_disable_rx(chip); @@ -768,6 +783,8 @@ static void cs_set_modulation(struct zd_ struct ieee80211_hdr_4addr *hdr) { struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + struct ieee80211softmac_txrates *txrates = &softmac->txrates; u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl)); u8 rate; int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0; @@ -788,6 +805,7 @@ static void cs_set_control(struct zd_mac struct ieee80211_hdr_4addr *header) { struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); unsigned int tx_length = le16_to_cpu(cs->tx_length); u16 fctl = le16_to_cpu(header->frame_ctl); u16 ftype = WLAN_FC_GET_TYPE(fctl); @@ -801,13 +819,21 @@ static void cs_set_control(struct zd_mac cs->control = 0; - /* First fragment */ - if (WLAN_GET_SEQ_FRAG(le16_to_cpu(header->seq_ctl)) == 0) + if(ieee->iw_mode == IW_MODE_MONITOR) + { cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; - - /* Multicast */ - if (is_multicast_ether_addr(header->addr1)) cs->control |= ZD_CS_MULTICAST; + } + else + { + /* First fragment */ + if (WLAN_GET_SEQ_FRAG(le16_to_cpu(header->seq_ctl)) == 0) + cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; + + /* Multicast */ + if (is_multicast_ether_addr(header->addr1)) + cs->control |= ZD_CS_MULTICAST; + } /* PS-POLL */ if (ftype == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) @@ -834,6 +860,7 @@ static int fill_ctrlset(struct zd_mac *m struct ieee80211_txb *txb, int frag_num) { + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); int r; struct sk_buff *skb = txb->fragments[frag_num]; struct ieee80211_hdr_4addr *hdr = @@ -857,7 +884,10 @@ static int fill_ctrlset(struct zd_mac *m cs->tx_length = cpu_to_le16(frag_len); - cs_set_control(mac, cs, hdr); +/* if(ieee->iw_mode == IW_MODE_MONITOR) + cs->control = ZD_CS_MULTICAST; + else*/ + cs_set_control(mac, cs, hdr); packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; ZD_ASSERT(packet_length <= 0xffff); @@ -913,7 +943,11 @@ static int zd_mac_tx(struct zd_mac *mac, ieee->stats.tx_dropped++; return r; } - r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len); + + if(ieee->iw_mode == IW_MODE_MONITOR) + r = zd_usb_tx_inject(&mac->chip.usb, skb->data, skb->len); + else + r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len); if (r) { ieee->stats.tx_dropped++; return r; @@ -933,6 +967,8 @@ struct zd_rt_hdr { u8 rt_rate; u16 rt_channel; u16 rt_chbitmask; + u8 rt_antsignal; + u8 rt_antnoise; } __attribute__((packed)); static void fill_rt_header(void *buffer, struct zd_mac *mac, @@ -946,7 +982,9 @@ static void fill_rt_header(void *buffer, hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr)); hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_RATE)); + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)); hdr->rt_flags = 0; if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256)) @@ -960,6 +998,9 @@ static void fill_rt_header(void *buffer, hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ | ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) == ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK)); + + hdr->rt_antsignal = status->signal_strength; + hdr->rt_antnoise = stats->noise; } /* Returns 1 if the data packet is for us and 0 otherwise. */ @@ -1067,7 +1108,8 @@ static int fill_rx_stats(struct ieee8021 *pstatus = status = (struct rx_status *) (buffer + (length - sizeof(struct rx_status))); - if (status->frame_status & ZD_RX_ERROR) { + if ((status->frame_status & ZD_RX_ERROR) || + (status->frame_status & ~0x21)) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); ieee->stats.rx_errors++; if (status->frame_status & ZD_RX_TIMEOUT_ERROR) diff -pur linux-2.6.24.4-zd1211rw/drivers/net/wireless/zd1211rw/zd_usb.c linux-2.6.24.4-sud/drivers/net/wireless/zd1211rw/zd_usb.c --- linux-2.6.24.4-zd1211rw/drivers/net/wireless/zd1211rw/zd_usb.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.4-sud/drivers/net/wireless/zd1211rw/zd_usb.c 2008-04-12 19:48:06.000000000 +0200 @@ -814,6 +814,46 @@ out: return r; } +/* Puts the frame on the USB endpoint. It doesn't wait for + * completion. The frame must contain the control set. + */ +int zd_usb_tx_inject(struct zd_usb *usb, const u8 *frame, unsigned int length) +{ + int r; + struct usb_device *udev = zd_usb_to_usbdev(usb); + struct urb *urb; + void *buffer; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + r = -ENOMEM; + goto out; + } + + buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC, + &urb->transfer_dma); + if (!buffer) { + r = -ENOMEM; + goto error_free_urb; + } + memcpy(buffer, frame, length); + + usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), + buffer, length, tx_urb_complete, NULL); + + r = usb_submit_urb(urb, GFP_ATOMIC); + if (r) + goto error; + return 0; +error: + usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer, + urb->transfer_dma); +error_free_urb: + usb_free_urb(urb); +out: + return r; +} + static inline void init_usb_interrupt(struct zd_usb *usb) { struct zd_usb_interrupt *intr = &usb->intr; diff -pur linux-2.6.24.4-zd1211rw/drivers/net/wireless/zd1211rw/zd_usb.h linux-2.6.24.4-sud/drivers/net/wireless/zd1211rw/zd_usb.h --- linux-2.6.24.4-zd1211rw/drivers/net/wireless/zd1211rw/zd_usb.h 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.4-sud/drivers/net/wireless/zd1211rw/zd_usb.h 2008-04-12 19:48:06.000000000 +0200 @@ -222,6 +222,7 @@ int zd_usb_enable_rx(struct zd_usb *usb) void zd_usb_disable_rx(struct zd_usb *usb); int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length); +int zd_usb_tx_inject(struct zd_usb *usb, const u8 *frame, unsigned int length); int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, const zd_addr_t *addresses, unsigned int count);