Attached is a patch for bcm43xx/softmac that enables /proc/net/wireless and SIOCGIWSTATS to obtain the wireless statistics, which are also used by desktop tools such as the Wireless Network Applet in KDE. In the present implementation, I added the iw_statistics struct to bcm43xx_private. If there is a better location, please let me know.

At present, the Link Quality is 0 if the interface is not associated, and 100/100 if it is. This behavior is that of the Windows driver when it is run under ndiswrapper.

The Signal Level is derived from the noise measurement algorithm listed by the clean-room team and lies in the range 0-3/3. We will probably want to increase the granularity of this quantity. In the present form, it would be sufficient for lighting LED's, but for the bar graphs used in the KDE applet, this scheme is probably a little crude.

The noise value comes directly from the averaged noise and is given on a scale of 100. Using various means of signal attenuation, the maximum value I have found for this quantity is 14.

The output values also include a number of kinds of tx/rx errors. Some are not yet implemented as shown in the FIXME's.

Larry
Index: bcm43xx_wx.c
===================================================================
--- bcm43xx_wx.c        (revision 1053)
+++ bcm43xx_wx.c        (working copy)
@@ -262,13 +262,13 @@
 
        range->max_qual.qual = 100;
        /* TODO: Real max RSSI */
-       range->max_qual.level = 0;
-       range->max_qual.noise = 0;
+       range->max_qual.level = 3;
+       range->max_qual.noise = 100;
        range->max_qual.updated = 7;
 
        range->avg_qual.qual = 70;
-       range->avg_qual.level = 0;
-       range->avg_qual.noise = 0;
+       range->avg_qual.level = 2;
+       range->avg_qual.noise = 40;
        range->avg_qual.updated = 7;
 
        range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
@@ -961,7 +961,51 @@
        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 ieee80211_device *net = ieee80211_priv(net_dev);
+       struct iw_statistics *wstats;
+
+               wstats = &bcm->wstats;
+               if (!mac->associated) {
+                       wstats->miss.beacon = 0;
+                       net->ieee_stats.tx_retry_limit_exceeded = 0;
+                       wstats->discard.retries = 0;
+                       net->ieee_stats.tx_discards_wrong_sa = 0;
+                       wstats->discard.nwid = 0;
+                       bcm->ieee->ieee_stats.rx_discards_undecryptable = 0;
+                       wstats->discard.code = 0;
+                       net->ieee_stats.rx_fragments = 0;
+                       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_NOISE_INVALID |
+                               IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+                       return wstats;
+               }
+               /* fill in the real statistics when iface associated */
+               wstats->qual.qual = 100;     // TODO: get the real signal 
quality
+               wstats->qual.level = 3 - bcm->stats.link_quality;
+               wstats->qual.noise = bcm->stats.noise;
+               wstats->qual.updated = IW_QUAL_QUAL_UPDATED | 
IW_QUAL_LEVEL_UPDATED |
+                               IW_QUAL_NOISE_UPDATED;
+               wstats->discard.code = 
bcm->ieee->ieee_stats.rx_discards_undecryptable;
+               wstats->discard.retries = 
net->ieee_stats.tx_retry_limit_exceeded;
+               wstats->discard.nwid = net->ieee_stats.tx_discards_wrong_sa;
+               wstats->discard.fragment = net->ieee_stats.rx_fragments;
+               wstats->discard.misc = 0;       // FIXME
+               wstats->miss.beacon = 0;        // FIXME
+               return wstats;
+       }
+
+
 #ifdef WX
 # undef WX
 #endif
@@ -1096,6 +1140,7 @@
        .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: */
Index: bcm43xx_main.c
===================================================================
--- bcm43xx_main.c      (revision 1053)
+++ bcm43xx_main.c      (working copy)
@@ -1919,6 +1919,16 @@
                average *= 125;
                average += 64;
                average /= 128;
+
+/* In early tests, 'average' has values that ranged from 3 - 14.
+ * As a first approximation, set the noise value to 'average' with a range of 
0 to 100.
+ */
+               bcm->stats.noise = average;
+
+/* The following algorithm comes from the clean-room reverse engineers. It 
results
+ * in a link quality from 0 to 3 (higher is better). The granularity should 
probably be
+ * increased before the driver goes "mainstream".
+ */
                tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
                tmp = (tmp / 128) & 0x1F;
                if (tmp >= 8)
Index: bcm43xx.h
===================================================================
--- bcm43xx.h   (revision 1053)
+++ bcm43xx.h   (working copy)
@@ -627,6 +627,7 @@
 
 struct bcm43xx_stats {
        u8 link_quality;
+       u8 noise;
 };
 
 struct bcm43xx_key {
@@ -659,6 +660,7 @@
            firmware_norelease:1;       /* Do not release the firmware. Used on 
suspend. */
 
        struct bcm43xx_stats stats;
+       struct iw_statistics wstats;
 
        /* Bus type we are connected to.
         * This is currently always BCM43xx_BUSTYPE_PCI

Reply via email to