wext: Fix scan result signal levels when driver reports in dBm
authorDavid A Benjamin <davidben@MIT.EDU>
Sun, 5 Sep 2010 16:04:10 +0000 (19:04 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 4 Oct 2010 05:25:00 +0000 (08:25 +0300)
wpa_supplicant showed signal levels incorrectly with some drivers:
Jun  6 16:29:36 rupert wpa_supplicant[18945]: Current BSS: 00:0d:97:11:40:d6
level=190
Jun  6 16:29:36 rupert wpa_supplicant[18945]: Selected BSS: 00:0d:97:11:50:09
level=192

Judging from output from other tools (iwlist) and the min_diff block
at the end of wpa_supplicant_need_to_roam, it seems these values
should actually be negative. Specifically, if one treats that number
as a signed char instead of unsigned, everything matches up.

To be honest, I've little to no understanding of wireless, but looking
at the source code for wireless-tools (iw_print_stats in iwlib.c), it
seems that the fields of the iw_quality struct need to be decoded
differently depending on various flags. I guess
src/drivers/driver_wext.c should have similar logic in
wext_get_scan_qual.

I wrote a patch that attempts to replicate some of that logic,
although it may be more complicated than is necessary; I think some of
the complexity is for backwards-compatibility, which might not be
necessary depending on wpa_supplicant's dependencies? In any case, it
is attached. Again, I don't know how any of this works, so it's likely
the patch is a bit off. But I think at least the logic to determine
min_diff in wpa_supplicant_need_to_roam would be more accurate if
level were determined correctly.

src/drivers/driver_wext.c
src/drivers/driver_wext.h

index d3629dd..f0de6aa 100644 (file)
@@ -1117,7 +1117,8 @@ static void wext_get_scan_freq(struct iw_event *iwe,
 }
 
 
-static void wext_get_scan_qual(struct iw_event *iwe,
+static void wext_get_scan_qual(struct wpa_driver_wext_data *drv,
+                              struct iw_event *iwe,
                               struct wext_scan_data *res)
 {
        res->res.qual = iwe->u.qual.qual;
@@ -1131,6 +1132,14 @@ static void wext_get_scan_qual(struct iw_event *iwe,
                res->res.flags |= WPA_SCAN_NOISE_INVALID;
        if (iwe->u.qual.updated & IW_QUAL_DBM)
                res->res.flags |= WPA_SCAN_LEVEL_DBM;
+       if ((iwe->u.qual.updated & IW_QUAL_DBM) ||
+           ((iwe->u.qual.level != 0) &&
+            (iwe->u.qual.level > drv->max_level))) {
+               if (iwe->u.qual.level >= 64)
+                       res->res.level -= 0x100;
+               if (iwe->u.qual.noise >= 64)
+                       res->res.noise -= 0x100;
+       }
 }
 
 
@@ -1406,7 +1415,7 @@ struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
                        wext_get_scan_freq(iwe, &data);
                        break;
                case IWEVQUAL:
-                       wext_get_scan_qual(iwe, &data);
+                       wext_get_scan_qual(drv, iwe, &data);
                        break;
                case SIOCGIWENCODE:
                        wext_get_scan_encode(iwe, &data);
@@ -1504,6 +1513,8 @@ static int wpa_driver_wext_get_range(void *priv)
                           "assuming WPA is not supported");
        }
 
+       drv->max_level = range->max_qual.level;
+
        os_free(range);
        return 0;
 }
index 9176dd8..6382bbb 100644 (file)
@@ -47,6 +47,8 @@ struct wpa_driver_wext_data {
        int scan_complete_events;
 
        int cfg80211; /* whether driver is using cfg80211 */
+
+       u8 max_level;
 };
 
 int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);