]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/zd1211rw/zd_mac.c
[PATCH] zd1211rw: Use compare_ether_addr()
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / zd1211rw / zd_mac.c
index 00ca704ece35b65f0951404d5d1f037869d9921b..19172f571524734df56cc0a8f13fa2c33560143c 100644 (file)
@@ -41,6 +41,8 @@ static void housekeeping_disable(struct zd_mac *mac);
 
 static void set_multicast_hash_handler(struct work_struct *work);
 
+static void do_rx(unsigned long mac_ptr);
+
 int zd_mac_init(struct zd_mac *mac,
                struct net_device *netdev,
                struct usb_interface *intf)
@@ -53,6 +55,10 @@ int zd_mac_init(struct zd_mac *mac,
        INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
        INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work);
 
+       skb_queue_head_init(&mac->rx_queue);
+       tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac);
+       tasklet_disable(&mac->rx_tasklet);
+
        ieee_init(ieee);
        softmac_init(ieee80211_priv(netdev));
        zd_chip_init(&mac->chip, netdev, intf);
@@ -140,6 +146,8 @@ out:
 void zd_mac_clear(struct zd_mac *mac)
 {
        flush_workqueue(zd_workqueue);
+       skb_queue_purge(&mac->rx_queue);
+       tasklet_kill(&mac->rx_tasklet);
        zd_chip_clear(&mac->chip);
        ZD_ASSERT(!spin_is_locked(&mac->lock));
        ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
@@ -148,7 +156,7 @@ void zd_mac_clear(struct zd_mac *mac)
 static int reset_mode(struct zd_mac *mac)
 {
        struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-       struct zd_ioreq32 ioreqs[3] = {
+       struct zd_ioreq32 ioreqs[] = {
                { CR_RX_FILTER, STA_RX_FILTER },
                { CR_SNIFFER_ON, 0U },
        };
@@ -156,10 +164,9 @@ static int reset_mode(struct zd_mac *mac)
        if (ieee->iw_mode == IW_MODE_MONITOR) {
                ioreqs[0].value = 0xffffffff;
                ioreqs[1].value = 0x1;
-               ioreqs[2].value = ENC_SNIFFER;
        }
 
-       return zd_iowrite32a(&mac->chip, ioreqs, 3);
+       return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
 int zd_mac_open(struct net_device *netdev)
@@ -168,6 +175,8 @@ int zd_mac_open(struct net_device *netdev)
        struct zd_chip *chip = &mac->chip;
        int r;
 
+       tasklet_enable(&mac->rx_tasklet);
+
        r = zd_chip_enable_int(chip);
        if (r < 0)
                goto out;
@@ -218,6 +227,8 @@ int zd_mac_stop(struct net_device *netdev)
         */
 
        zd_chip_disable_rx(chip);
+       skb_queue_purge(&mac->rx_queue);
+       tasklet_disable(&mac->rx_tasklet);
        housekeeping_disable(mac);
        ieee80211softmac_stop(netdev);
 
@@ -470,13 +481,13 @@ static void bssinfo_change(struct net_device *netdev, u32 changes)
 
        if (changes & IEEE80211SOFTMAC_BSSINFOCHG_RATES) {
                /* Set RTS rate to highest available basic rate */
-               u8 rate = ieee80211softmac_highest_supported_rate(softmac,
+               u8 hi_rate = ieee80211softmac_highest_supported_rate(softmac,
                        &bssinfo->supported_rates, 1);
-               rate = rate_to_zd_rate(rate);
+               hi_rate = rate_to_zd_rate(hi_rate);
 
                spin_lock_irqsave(&mac->lock, flags);
-               if (rate != mac->rts_rate) {
-                       mac->rts_rate = rate;
+               if (hi_rate != mac->rts_rate) {
+                       mac->rts_rate = hi_rate;
                        need_set_rts_cts = 1;
                }
                spin_unlock_irqrestore(&mac->lock, flags);
@@ -892,16 +903,21 @@ static int fill_ctrlset(struct zd_mac *mac,
 static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
 {
        int i, r;
+       struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 
        for (i = 0; i < txb->nr_frags; i++) {
                struct sk_buff *skb = txb->fragments[i];
 
                r = fill_ctrlset(mac, txb, i);
-               if (r)
+               if (r) {
+                       ieee->stats.tx_dropped++;
                        return r;
+               }
                r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
-               if (r)
+               if (r) {
+                       ieee->stats.tx_dropped++;
                        return r;
+               }
        }
 
        /* FIXME: shouldn't this be handled by the upper layers? */
@@ -958,14 +974,14 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
        switch (ieee->iw_mode) {
        case IW_MODE_ADHOC:
                if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
-                   memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0)
+                   compare_ether_addr(hdr->addr3, ieee->bssid) != 0)
                        return 0;
                break;
        case IW_MODE_AUTO:
        case IW_MODE_INFRA:
                if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
                    IEEE80211_FCTL_FROMDS ||
-                   memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0)
+                   compare_ether_addr(hdr->addr2, ieee->bssid) != 0)
                        return 0;
                break;
        default:
@@ -973,9 +989,9 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
                return 0;
        }
 
-       return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
+       return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 ||
               (is_multicast_ether_addr(hdr->addr1) &&
-               memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) ||
+               compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) ||
               (netdev->flags & IFF_PROMISC);
 }
 
@@ -1031,7 +1047,7 @@ static void update_qual_rssi(struct zd_mac *mac,
        hdr = (struct ieee80211_hdr_3addr *)buffer;
        if (length < offsetof(struct ieee80211_hdr_3addr, addr3))
                return;
-       if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0)
+       if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0)
                return;
 
        spin_lock_irqsave(&mac->lock, flags);
@@ -1051,9 +1067,23 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
 
        *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
        if (status->frame_status & ZD_RX_ERROR) {
-               /* FIXME: update? */
+               struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+               ieee->stats.rx_errors++;
+               if (status->frame_status & ZD_RX_TIMEOUT_ERROR)
+                       ieee->stats.rx_missed_errors++;
+               else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR)
+                       ieee->stats.rx_fifo_errors++;
+               else if (status->frame_status & ZD_RX_DECRYPTION_ERROR)
+                       ieee->ieee_stats.rx_discards_undecryptable++;
+               else if (status->frame_status & ZD_RX_CRC32_ERROR) {
+                       ieee->stats.rx_crc_errors++;
+                       ieee->ieee_stats.rx_fcs_errors++;
+               }
+               else if (status->frame_status & ZD_RX_CRC16_ERROR)
+                       ieee->stats.rx_crc_errors++;
                return -EINVAL;
        }
+
        memset(stats, 0, sizeof(struct ieee80211_rx_stats));
        stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
                               + sizeof(struct rx_status));
@@ -1072,43 +1102,81 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
        return 0;
 }
 
-int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 {
        int r;
        struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
        struct ieee80211_rx_stats stats;
        const struct rx_status *status;
-       struct sk_buff *skb;
 
-       if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
-                    IEEE80211_FCS_LEN + sizeof(struct rx_status))
-               return -EINVAL;
+       if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
+                      IEEE80211_FCS_LEN + sizeof(struct rx_status))
+       {
+               ieee->stats.rx_errors++;
+               ieee->stats.rx_length_errors++;
+               goto free_skb;
+       }
 
-       r = fill_rx_stats(&stats, &status, mac, buffer, length);
-       if (r)
-               return r;
+       r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
+       if (r) {
+               /* Only packets with rx errors are included here.
+                * The error stats have already been set in fill_rx_stats.
+                */
+               goto free_skb;
+       }
 
-       length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+
-                 sizeof(struct rx_status);
-       buffer += ZD_PLCP_HEADER_SIZE;
+       __skb_pull(skb, ZD_PLCP_HEADER_SIZE);
+       __skb_trim(skb, skb->len -
+                       (IEEE80211_FCS_LEN + sizeof(struct rx_status)));
 
-       update_qual_rssi(mac, buffer, length, stats.signal, stats.rssi);
+       update_qual_rssi(mac, skb->data, skb->len, stats.signal,
+                        status->signal_strength);
 
-       r = filter_rx(ieee, buffer, length, &stats);
-       if (r <= 0)
-               return r;
+       r = filter_rx(ieee, skb->data, skb->len, &stats);
+       if (r <= 0) {
+               if (r < 0) {
+                       ieee->stats.rx_errors++;
+                       dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
+               }
+               goto free_skb;
+       }
 
-       skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
-       if (!skb)
-               return -ENOMEM;
        if (ieee->iw_mode == IW_MODE_MONITOR)
-               fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac,
+               fill_rt_header(skb_push(skb, sizeof(struct zd_rt_hdr)), mac,
                               &stats, status);
-       memcpy(skb_put(skb, length), buffer, length);
 
        r = ieee80211_rx(ieee, skb, &stats);
-       if (!r)
-               dev_kfree_skb_any(skb);
+       if (r)
+               return;
+free_skb:
+       /* We are always in a soft irq. */
+       dev_kfree_skb(skb);
+}
+
+static void do_rx(unsigned long mac_ptr)
+{
+       struct zd_mac *mac = (struct zd_mac *)mac_ptr;
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&mac->rx_queue)) != NULL)
+               zd_mac_rx(mac, skb);
+}
+
+int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+{
+       struct sk_buff *skb;
+
+       skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
+       if (!skb) {
+               struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+               dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
+               ieee->stats.rx_dropped++;
+               return -ENOMEM;
+       }
+       skb_reserve(skb, sizeof(struct zd_rt_hdr));
+       memcpy(__skb_put(skb, length), buffer, length);
+       skb_queue_tail(&mac->rx_queue, skb);
+       tasklet_schedule(&mac->rx_tasklet);
        return 0;
 }