driver_bsd.c: use get_scan_results2
authorMasashi Honma <honma@ictec.co.jp>
Thu, 21 May 2009 08:34:54 +0000 (11:34 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 21 May 2009 08:34:54 +0000 (11:34 +0300)
The attached patch will replace get_scan_results with get_scan_results2.
This is a preparation for WPS on BSD.
And I erased "wpa_scan_result_compar". Because scan result
sorting will be done with "wpa_scan_result_compar" on
"scan_helpers.c".

I have done below tests on NetBSD with an atheros card.
- WPA2-PSK(CCMP)
- WPA-PSK(TKIP)
- PEAP(MSCHAPv2)
- EAP-TLS
- EAP-TTLS(MSCHAPv2)

src/drivers/driver_bsd.c

index e171637..100f4b4 100644 (file)
@@ -904,9 +904,18 @@ static int
 wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
 {
        struct wpa_driver_bsd_data *drv = priv;
+#ifdef __NetBSD__
+       struct ieee80211_bssid bs;
 
+       os_strncpy(bs.i_name, drv->ifname, sizeof(bs.i_name));
+       if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0)
+               return -1;
+       os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid));
+       return 0;
+#else
        return get80211var(drv, IEEE80211_IOC_BSSID,
                bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
+#endif
 }
 
 #if 0
@@ -924,9 +933,22 @@ static int
 wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
 {
        struct wpa_driver_bsd_data *drv = priv;
+#ifdef __NetBSD__
+       struct ieee80211_nwid nwid;
+       struct ifreq ifr;
 
+       os_memset(&ifr, 0, sizeof(ifr));
+       os_strncpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+       ifr.ifr_data = (void *)&nwid;
+       if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
+           nwid.i_len > IEEE80211_NWID_LEN)
+               return -1;
+       os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
+       return nwid.i_len;
+#else
        return get80211var(drv, IEEE80211_IOC_SSID,
                ssid, IEEE80211_NWID_LEN);
+#endif
 }
 
 static int
@@ -934,8 +956,19 @@ wpa_driver_bsd_set_ssid(void *priv, const u8 *ssid,
                             size_t ssid_len)
 {
        struct wpa_driver_bsd_data *drv = priv;
+#ifdef __NetBSD__
+       struct ieee80211_nwid nwid;
+       struct ifreq ifr;
 
+       os_memcpy(nwid.i_nwid, ssid, ssid_len);
+       nwid.i_len = ssid_len;
+       os_memset(&ifr, 0, sizeof(ifr));
+       os_strncpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+       ifr.ifr_data = (void *)&nwid;
+       return ioctl(drv->sock, SIOCS80211NWID, &ifr);
+#else
        return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
+#endif
 }
 
 static int
@@ -1301,135 +1334,94 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
        }
 }
 
-/* Compare function for sorting scan results. Return >0 if @b is consider
- * better. */
-static int
-wpa_scan_result_compar(const void *a, const void *b)
+static void
+wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
+                             struct ieee80211req_scan_result *sr)
 {
-       const struct wpa_scan_result *wa = a;
-       const struct wpa_scan_result *wb = b;
-
-       /* WPA/WPA2 support preferred */
-       if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
-           !(wa->wpa_ie_len || wa->rsn_ie_len))
-               return 1;
-       if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
-           (wa->wpa_ie_len || wa->rsn_ie_len))
-               return -1;
+       struct wpa_scan_res *result, **tmp;
+       size_t extra_len;
+       u8 *pos;
 
-       /* privacy support preferred */
-       if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) &&
-           (wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0)
-               return 1;
-       if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 &&
-           (wb->caps & IEEE80211_CAPINFO_PRIVACY))
-               return -1;
+       extra_len = 2 + sr->isr_ssid_len;
+       extra_len += 2 + sr->isr_nrates;
+       extra_len += 3; /* ERP IE */
+       extra_len += sr->isr_ie_len;
 
-       /* best/max rate preferred if signal level close enough XXX */
-       if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
-               return wb->maxrate - wa->maxrate;
+       result = os_zalloc(sizeof(*result) + extra_len);
+       if (result == NULL)
+               return;
+       os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN);
+       result->freq = sr->isr_freq;
+       result->beacon_int = sr->isr_intval;
+       result->caps = sr->isr_capinfo;
+       result->qual = sr->isr_rssi;
+       result->noise = sr->isr_noise;
 
-       /* use freq for channel preference */
+       pos = (u8 *)(result + 1);
 
-       /* all things being equal, use signal level */
-       return wb->level - wa->level;
-}
+       *pos++ = WLAN_EID_SSID;
+       *pos++ = sr->isr_ssid_len;
+       os_memcpy(pos, sr + 1, sr->isr_ssid_len);
+       pos += sr->isr_ssid_len;
 
-static int
-getmaxrate(uint8_t rates[15], uint8_t nrates)
-{
-       int i, maxrate = -1;
+       /*
+        * Deal all rates as supported rate.
+        * Because net80211 doesn't report extended supported rate or not.
+        */
+       *pos++ = WLAN_EID_SUPP_RATES;
+       *pos++ = sr->isr_nrates;
+       os_memcpy(pos, sr->isr_rates, sr->isr_nrates);
+       pos += sr->isr_nrates;
 
-       for (i = 0; i < nrates; i++) {
-               int rate = rates[i] & IEEE80211_RATE_VAL;
-               if (rate > maxrate)
-                       rate = maxrate;
-       }
-       return maxrate;
-}
+       *pos++ = WLAN_EID_ERP_INFO;
+       *pos++ = 1;
+       *pos++ = sr->isr_erp;
 
-/* unalligned little endian access */     
-#define LE_READ_4(p)                                   \
-       ((u_int32_t)                                    \
-        ((((const u_int8_t *)(p))[0]      ) |          \
-         (((const u_int8_t *)(p))[1] <<  8) |          \
-         (((const u_int8_t *)(p))[2] << 16) |          \
-         (((const u_int8_t *)(p))[3] << 24)))
+       os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len);
+       pos += sr->isr_ie_len;
 
-static int __inline
-iswpaoui(const u_int8_t *frm)
-{
-       return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+       result->ie_len = pos - (u8 *)(result + 1);
+
+       tmp = os_realloc(res->res,
+                        (res->num + 1) * sizeof(struct wpa_scan_res *));
+       if (tmp == NULL) {
+               os_free(result);
+               return;
+       }
+       tmp[res->num++] = result;
+       res->res = tmp;
 }
 
-static int
-wpa_driver_bsd_get_scan_results(void *priv,
-                                    struct wpa_scan_result *results,
-                                    size_t max_size)
+struct wpa_scan_results *
+wpa_driver_bsd_get_scan_results2(void *priv)
 {
-#define        min(a,b)        ((a)>(b)?(b):(a))
        struct wpa_driver_bsd_data *drv = priv;
-       uint8_t buf[24*1024];
-       uint8_t *cp, *vp;
        struct ieee80211req_scan_result *sr;
-       struct wpa_scan_result *wsr;
-       int len, ielen;
+       struct wpa_scan_results *res;
+       int len, rest;
+       uint8_t buf[24*1024], *pos;
 
-       os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
-
-       len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf));
+       len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024);
        if (len < 0)
-               return -1;
-       cp = buf;
-       wsr = results;
-       while (len >= sizeof(struct ieee80211req_scan_result)) {
-               sr = (struct ieee80211req_scan_result *) cp;
-               os_memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN);
-               wsr->ssid_len = sr->isr_ssid_len;
-               wsr->freq = sr->isr_freq;
-               wsr->noise = sr->isr_noise;
-               wsr->qual = sr->isr_rssi;
-               wsr->level = 0;         /* XXX? */
-               wsr->caps = sr->isr_capinfo;
-               wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates);
-               vp = (u_int8_t *)(sr+1);
-               os_memcpy(wsr->ssid, vp, sr->isr_ssid_len);
-               if (sr->isr_ie_len > 0) {
-                       vp += sr->isr_ssid_len;
-                       ielen = sr->isr_ie_len;
-                       while (ielen > 0) {
-                               switch (vp[0]) {
-                               case IEEE80211_ELEMID_VENDOR:
-                                       if (!iswpaoui(vp))
-                                               break;
-                                       wsr->wpa_ie_len =
-                                           min(2+vp[1], SSID_MAX_WPA_IE_LEN);
-                                       os_memcpy(wsr->wpa_ie, vp,
-                                                 wsr->wpa_ie_len);
-                                       break;
-                               case IEEE80211_ELEMID_RSN:
-                                       wsr->rsn_ie_len =
-                                           min(2+vp[1], SSID_MAX_WPA_IE_LEN);
-                                       os_memcpy(wsr->rsn_ie, vp,
-                                                 wsr->rsn_ie_len);
-                                       break;
-                               }
-                               ielen -= 2+vp[1];
-                               vp += 2+vp[1];
-                       }
-               }
+               return NULL;
+
+       res = os_zalloc(sizeof(*res));
+       if (res == NULL)
+               return NULL;
 
-               cp += sr->isr_len, len -= sr->isr_len;
-               wsr++;
+       pos = buf;
+       rest = len;
+       while (rest >= sizeof(struct ieee80211req_scan_result)) {
+               sr = (struct ieee80211req_scan_result *)pos;
+               wpa_driver_bsd_add_scan_entry(res, sr);
+               pos += sr->isr_len;
+               rest -= sr->isr_len;
        }
-       qsort(results, wsr - results, sizeof(struct wpa_scan_result),
-             wpa_scan_result_compar);
 
-       wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
-                  len, wsr - results);
+       wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)",
+                  len, (unsigned long)res->num);
 
-       return wsr - results;
-#undef min
+       return res;
 }
 
 static void *
@@ -1537,7 +1529,7 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = {
        .set_countermeasures    = wpa_driver_bsd_set_countermeasures,
        .set_drop_unencrypted   = wpa_driver_bsd_set_drop_unencrypted,
        .scan                   = wpa_driver_bsd_scan,
-       .get_scan_results       = wpa_driver_bsd_get_scan_results,
+       .get_scan_results2      = wpa_driver_bsd_get_scan_results2,
        .deauthenticate         = wpa_driver_bsd_deauthenticate,
        .disassociate           = wpa_driver_bsd_disassociate,
        .associate              = wpa_driver_bsd_associate,