[PATCH] ieee80211: Move IV/ICV stripping into ieee80211_rx
[safe/jmp/linux-2.6] / drivers / net / wireless / bcm43xx / bcm43xx_wx.c
index 2081938..a659442 100644 (file)
 
 #define MAX_WX_STRING          80
 
-
 static int bcm43xx_wx_get_name(struct net_device *net_dev,
                                struct iw_request_info *info,
                               union iwreq_data *data,
                               char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
-       int i, nr_80211;
+       int i;
        struct bcm43xx_phyinfo *phy;
        char suffix[7] = { 0 };
        int have_a = 0, have_b = 0, have_g = 0;
 
-       bcm43xx_lock(bcm, flags);
-       nr_80211 = bcm43xx_num_80211_cores(bcm);
-       for (i = 0; i < nr_80211; i++) {
-               phy = bcm->phy + i;
+       mutex_lock(&bcm->mutex);
+       for (i = 0; i < bcm->nr_80211_available; i++) {
+               phy = &(bcm->core_80211_ext[i].phy);
                switch (phy->type) {
                case BCM43xx_PHYTYPE_A:
                        have_a = 1;
@@ -78,7 +75,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
                        assert(0);
                }
        }
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        i = 0;
        if (have_a) {
@@ -107,13 +104,14 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
                                      char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       struct ieee80211softmac_device *softmac = bcm->softmac;
        unsigned long flags;
        u8 channel;
        int freq;
        int err = -EINVAL;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
+
        if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
                channel = data->freq.m;
                freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -121,19 +119,20 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
                channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
                freq = data->freq.m;
        }
-       if (!bcm43xx_is_valid_channel(bcm, channel))
+       if (!ieee80211_is_valid_channel(bcm->ieee, channel))
                goto out_unlock;
-       if (bcm->initialized) {
+       if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
                //ieee80211softmac_disassoc(softmac, $REASON);
                bcm43xx_mac_suspend(bcm);
                err = bcm43xx_radio_selectchannel(bcm, channel, 0);
                bcm43xx_mac_enable(bcm);
        } else {
-               bcm->current_core->radio->initial_channel = channel;
+               bcm43xx_current_radio(bcm)->initial_channel = channel;
                err = 0;
        }
 out_unlock:
-       bcm43xx_unlock_mmio(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -144,15 +143,15 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
                                      char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
+       struct bcm43xx_radioinfo *radio;
        int err = -ENODEV;
        u16 channel;
 
-       bcm43xx_lock(bcm, flags);
-       channel = bcm->current_core->radio->channel;
+       mutex_lock(&bcm->mutex);
+       radio = bcm43xx_current_radio(bcm);
+       channel = radio->channel;
        if (channel == 0xFF) {
-               assert(!bcm->initialized);
-               channel = bcm->current_core->radio->initial_channel;
+               channel = radio->initial_channel;
                if (channel == 0xFF)
                        goto out_unlock;
        }
@@ -163,7 +162,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
 
        err = 0;
 out_unlock:
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -181,10 +180,15 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev,
        if (mode == IW_MODE_AUTO)
                mode = BCM43xx_INITIAL_IWMODE;
 
-       bcm43xx_lock_mmio(bcm, flags);
-       if (bcm->ieee->iw_mode != mode)
-               bcm43xx_set_iwmode(bcm, mode);
-       bcm43xx_unlock_mmio(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
+       if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+               if (bcm->ieee->iw_mode != mode)
+                       bcm43xx_set_iwmode(bcm, mode);
+       } else
+               bcm->ieee->iw_mode = mode;
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -195,30 +199,11 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev,
                               char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
 
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
        data->mode = bcm->ieee->iw_mode;
-       bcm43xx_unlock(bcm, flags);
-
-       return 0;
-}
-
-static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev,
-                                     struct iw_request_info *info,
-                                     union iwreq_data *data,
-                                     char *extra)
-{
-       /*TODO*/
-       return 0;
-}
+       mutex_unlock(&bcm->mutex);
 
-static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev,
-                                     struct iw_request_info *info,
-                                     union iwreq_data *data,
-                                     char *extra)
-{
-       /*TODO*/
        return 0;
 }
 
@@ -230,8 +215,8 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        struct iw_range *range = (struct iw_range *)extra;
        const struct ieee80211_geo *geo;
-       unsigned long flags;
        int i, j;
+       struct bcm43xx_phyinfo *phy;
 
        data->data.length = sizeof(*range);
        memset(range, 0, sizeof(*range));
@@ -241,15 +226,14 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
        range->throughput = 27 * 1000 * 1000;
 
        range->max_qual.qual = 100;
-       /* TODO: Real max RSSI */
-       range->max_qual.level = 0;
-       range->max_qual.noise = 0;
-       range->max_qual.updated = 7;
+       range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */
+       range->max_qual.noise = 146;
+       range->max_qual.updated = IW_QUAL_ALL_UPDATED;
 
-       range->avg_qual.qual = 70;
+       range->avg_qual.qual = 50;
        range->avg_qual.level = 0;
        range->avg_qual.noise = 0;
-       range->avg_qual.updated = 7;
+       range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
 
        range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
        range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
@@ -269,12 +253,13 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
                          IW_ENC_CAPA_CIPHER_TKIP |
                          IW_ENC_CAPA_CIPHER_CCMP;
 
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       phy = bcm43xx_current_phy(bcm);
 
        range->num_bitrates = 0;
        i = 0;
-       if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ||
-           bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
+       if (phy->type == BCM43xx_PHYTYPE_A ||
+           phy->type == BCM43xx_PHYTYPE_G) {
                range->num_bitrates = 8;
                range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
                range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
@@ -285,8 +270,8 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
                range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
                range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
        }
-       if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B ||
-           bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
+       if (phy->type == BCM43xx_PHYTYPE_B ||
+           phy->type == BCM43xx_PHYTYPE_G) {
                range->num_bitrates += 4;
                range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
                range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
@@ -315,7 +300,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
        }
        range->num_frequency = j;
 
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -326,14 +311,13 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev,
                               char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        size_t len;
 
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
        len =  min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
        memcpy(bcm->nick, extra, len);
        bcm->nick[len] = '\0';
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -344,15 +328,14 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev,
                               char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        size_t len;
 
-       bcm43xx_lock(bcm, flags);
-       len = strlen(bcm->nick) + 1;
+       mutex_lock(&bcm->mutex);
+       len = strlen(bcm->nick);
        memcpy(extra, bcm->nick, len);
        data->data.length = (__u16)len;
        data->data.flags = 1;
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -366,7 +349,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
        unsigned long flags;
        int err = -EINVAL;
 
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (data->rts.disabled) {
                bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
                err = 0;
@@ -377,7 +361,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
                        err = 0;
                }
        }
-       bcm43xx_unlock(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -388,13 +373,12 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev,
                              char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
 
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
        data->rts.value = bcm->rts_threshold;
        data->rts.fixed = 0;
        data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -408,7 +392,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
        unsigned long flags;
        int err = -EINVAL;
 
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        if (data->frag.disabled) {
                bcm->ieee->fts = MAX_FRAG_THRESHOLD;
                err = 0;
@@ -419,7 +404,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
                        err = 0;
                }
        }
-       bcm43xx_unlock(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -430,13 +416,12 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev,
                               char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
 
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
        data->frag.value = bcm->ieee->fts;
        data->frag.fixed = 0;
        data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -458,11 +443,12 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
                return -EOPNOTSUPP;
        }
 
-       bcm43xx_lock_mmio(bcm, flags);
-       if (!bcm->initialized)
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
+       if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
                goto out_unlock;
-       radio = bcm->current_core->radio;
-       phy = bcm->current_core->phy;
+       radio = bcm43xx_current_radio(bcm);
+       phy = bcm43xx_current_phy(bcm);
        if (data->txpower.disabled != (!(radio->enabled))) {
                if (data->txpower.disabled)
                        bcm43xx_radio_turn_off(bcm);
@@ -482,7 +468,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
        err = 0;
 
 out_unlock:
-       bcm43xx_unlock_mmio(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -494,13 +481,12 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
        struct bcm43xx_radioinfo *radio;
-       unsigned long flags;
        int err = -ENODEV;
 
-       bcm43xx_lock(bcm, flags);
-       if (!bcm->initialized)
+       mutex_lock(&bcm->mutex);
+       if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
                goto out_unlock;
-       radio = bcm->current_core->radio;
+       radio = bcm43xx_current_radio(bcm);
        /* desired dBm value is in Q5.2 */
        data->txpower.value = radio->txpower_desired >> 2;
        data->txpower.fixed = 1;
@@ -509,29 +495,11 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
 
        err = 0;
 out_unlock:
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
 
-static int bcm43xx_wx_set_retry(struct net_device *net_dev,
-                               struct iw_request_info *info,
-                               union iwreq_data *data,
-                               char *extra)
-{
-       /*TODO*/
-       return 0;
-}
-
-static int bcm43xx_wx_get_retry(struct net_device *net_dev,
-                               struct iw_request_info *info,
-                               union iwreq_data *data,
-                               char *extra)
-{
-       /*TODO*/
-       return 0;
-}
-
 static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
                                   struct iw_request_info *info,
                                   union iwreq_data *data,
@@ -584,24 +552,6 @@ static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
         return err;
 }
 
-static int bcm43xx_wx_set_power(struct net_device *net_dev,
-                               struct iw_request_info *info,
-                               union iwreq_data *data,
-                               char *extra)
-{
-       /*TODO*/
-       return 0;
-}
-
-static int bcm43xx_wx_get_power(struct net_device *net_dev,
-                               struct iw_request_info *info,
-                               union iwreq_data *data,
-                               char *extra)
-{
-       /*TODO*/
-       return 0;
-}
-
 static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
                                     struct iw_request_info *info,
                                     union iwreq_data *data,
@@ -632,8 +582,9 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
                return -EINVAL;
        }
 
-       bcm43xx_lock_mmio(bcm, flags);
-       if (bcm->initialized) {
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
+       if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
                err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
                if (err) {
                        printk(KERN_ERR PFX "Interference Mitigation not "
@@ -645,9 +596,10 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
                                            "not supported while the interface is down.\n");
                        err = -ENODEV;
                } else
-                       bcm->current_core->radio->interfmode = mode;
+                       bcm43xx_current_radio(bcm)->interfmode = mode;
        }
-       bcm43xx_unlock_mmio(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return err;
 }
@@ -658,12 +610,11 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
                                     char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        int mode;
 
-       bcm43xx_lock(bcm, flags);
-       mode = bcm->current_core->radio->interfmode;
-       bcm43xx_unlock(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       mode = bcm43xx_current_radio(bcm)->interfmode;
+       mutex_unlock(&bcm->mutex);
 
        switch (mode) {
        case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -693,9 +644,11 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
        int on;
 
        on = *((int *)extra);
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        bcm->short_preamble = !!on;
-       bcm43xx_unlock(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -706,12 +659,11 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
                                        char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        int on;
 
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
        on = bcm->short_preamble;
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        if (on)
                strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -733,11 +685,14 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
        
        on = *((int *)extra);
 
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        bcm->ieee->host_encrypt = !!on;
        bcm->ieee->host_decrypt = !!on;
        bcm->ieee->host_build_iv = !on;
-       bcm43xx_unlock(bcm, flags);
+       bcm->ieee->host_strip_iv_icv = !on;
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 
        return 0;
 }
@@ -748,12 +703,11 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
                                       char *extra)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-       unsigned long flags;
        int on;
 
-       bcm43xx_lock(bcm, flags);
+       mutex_lock(&bcm->mutex);
        on = bcm->ieee->host_encrypt;
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
        if (on)
                strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -816,11 +770,13 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
        if (!sprom)
                goto out;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
        err = -ENODEV;
-       if (bcm->initialized)
+       if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
                err = bcm43xx_sprom_read(bcm, sprom);
-       bcm43xx_unlock_mmio(bcm, flags);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
        if (!err)
                data->data.length = sprom2hex(sprom, extra);
        kfree(sprom);
@@ -861,17 +817,80 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
        if (err)
                goto out_kfree;
 
-       bcm43xx_lock_mmio(bcm, flags);
+       mutex_lock(&bcm->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
+       spin_lock(&bcm->leds_lock);
        err = -ENODEV;
-       if (bcm->initialized)
+       if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
                err = bcm43xx_sprom_write(bcm, sprom);
-       bcm43xx_unlock_mmio(bcm, flags);
+       spin_unlock(&bcm->leds_lock);
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
 out_kfree:
        kfree(sprom);
 out:
        return err;
 }
 
+/* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
+
+static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev)
+{
+       struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+       struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
+       struct iw_statistics *wstats;
+       struct ieee80211_network *network = NULL;
+       static int tmp_level = 0;
+       static int tmp_qual = 0;
+       unsigned long flags;
+
+       wstats = &bcm->stats.wstats;
+       if (!mac->associnfo.associated) {
+               wstats->miss.beacon = 0;
+//             bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
+               wstats->discard.retries = 0;
+//             bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question
+               wstats->discard.nwid = 0;
+//             bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto
+               wstats->discard.code = 0;
+//             bcm->ieee->ieee_stats.rx_fragments = 0;  // FIXME: same here
+               wstats->discard.fragment = 0;
+               wstats->discard.misc = 0;
+               wstats->qual.qual = 0;
+               wstats->qual.level = 0;
+               wstats->qual.noise = 0;
+               wstats->qual.updated = 7;
+               wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+               return wstats;
+       }
+       /* fill in the real statistics when iface associated */
+       spin_lock_irqsave(&mac->ieee->lock, flags);
+       list_for_each_entry(network, &mac->ieee->network_list, list) {
+               if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
+                       if (!tmp_level) {       /* get initial values */
+                               tmp_level = network->stats.signal;
+                               tmp_qual = network->stats.rssi;
+                       } else {                /* smooth results */
+                               tmp_level = (15 * tmp_level + network->stats.signal)/16;
+                               tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
+                       }
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&mac->ieee->lock, flags);
+       wstats->qual.level = tmp_level;
+       wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
+       wstats->qual.noise = bcm->stats.noise;
+       wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+       wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
+       wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
+       wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
+       wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments;
+       wstats->discard.misc = 0;       // FIXME
+       wstats->miss.beacon = 0;        // FIXME
+       return wstats;
+}
+
 
 #ifdef WX
 # undef WX
@@ -971,22 +990,22 @@ static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
        {
                .cmd            = PRIV_WX_SET_SHORTPREAMBLE,
                .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-               .name           = "set_shortpreambl",
+               .name           = "set_shortpreamb",
        },
        {
                .cmd            = PRIV_WX_GET_SHORTPREAMBLE,
                .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
-               .name           = "get_shortpreambl",
+               .name           = "get_shortpreamb",
        },
        {
                .cmd            = PRIV_WX_SET_SWENCRYPTION,
                .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-               .name           = "set_swencryption",
+               .name           = "set_swencrypt",
        },
        {
                .cmd            = PRIV_WX_GET_SWENCRYPTION,
                .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
-               .name           = "get_swencryption",
+               .name           = "get_swencrypt",
        },
        {
                .cmd            = PRIV_WX_SPROM_WRITE,
@@ -1007,6 +1026,5 @@ const struct iw_handler_def bcm43xx_wx_handlers_def = {
        .num_private_args       = ARRAY_SIZE(bcm43xx_priv_wx_args),
        .private                = bcm43xx_priv_wx_handlers,
        .private_args           = bcm43xx_priv_wx_args,
+       .get_wireless_stats     = bcm43xx_get_wireless_stats,
 };
-
-/* vim: set ts=8 sw=8 sts=8: */