]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd/wpa_s: Use driver's extended capabilities
authorJohannes Berg <johannes.berg@intel.com>
Sun, 31 Mar 2013 18:51:44 +0000 (21:51 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 31 Mar 2013 18:51:44 +0000 (21:51 +0300)
Some extended capabilities (I'm currently interested in "Operating Mode
Notification" for VHT) are implemented by the kernel driver and exported
in nl80211. Use these in hostapd/wpa_supplicant.

Signed-hostap: Johannes Berg <johannes.berg@intel.com>

hostapd/main.c
src/ap/hostapd.h
src/ap/ieee802_11_shared.c
src/drivers/driver.h
src/drivers/driver_nl80211.c
wpa_supplicant/ap.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 4b0da3c10b0e32a3fb5fc90dd363a7fb90dccd7f..881a053e9177d4202a9cb6e8619d2c22ff08dfd3 100644 (file)
@@ -274,6 +274,9 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
            hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
                iface->drv_flags = capa.flags;
                iface->probe_resp_offloads = capa.probe_resp_offloads;
+               iface->extended_capa = capa.extended_capa;
+               iface->extended_capa_mask = capa.extended_capa_mask;
+               iface->extended_capa_len = capa.extended_capa_len;
        }
 
        return 0;
index 89591c705e2917ed3dcce23cf44b98de4b2ec81a..9a3bb6862f0b962ab40172a87aca08c913a8ead9 100644 (file)
@@ -229,6 +229,10 @@ struct hostapd_iface {
         */
        unsigned int probe_resp_offloads;
 
+       /* extended capabilities supported by the driver */
+       const u8 *extended_capa, *extended_capa_mask;
+       unsigned int extended_capa_len;
+
        struct hostapd_hw_modes *hw_features;
        int num_hw_features;
        struct hostapd_hw_modes *current_mode;
index 76f78a7dbd9c1fde8f1eac7bfa2acadb42aef97d..e59ac1322280d976fddb4fc258a50abe1a826b06 100644 (file)
@@ -164,10 +164,52 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
 #endif /* CONFIG_IEEE80211W */
 
 
+static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
+{
+       *pos = 0x00;
+
+       switch (idx) {
+       case 0: /* Bits 0-7 */
+               break;
+       case 1: /* Bits 8-15 */
+               break;
+       case 2: /* Bits 16-23 */
+               if (hapd->conf->wnm_sleep_mode)
+                       *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+               if (hapd->conf->bss_transition)
+                       *pos |= 0x08; /* Bit 19 - BSS Transition */
+               break;
+       case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+               *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+               if (hapd->conf->time_advertisement == 2)
+                       *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+               if (hapd->conf->interworking)
+                       *pos |= 0x80; /* Bit 31 - Interworking */
+               break;
+       case 4: /* Bits 32-39 */
+               if (hapd->conf->tdls & TDLS_PROHIBIT)
+                       *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+               if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
+                       /* Bit 39 - TDLS Channel Switching Prohibited */
+                       *pos |= 0x80;
+               }
+               break;
+       case 5: /* Bits 40-47 */
+               break;
+       case 6: /* Bits 48-55 */
+               if (hapd->conf->ssid.utf8_ssid)
+                       *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+               break;
+       }
+}
+
+
 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
 {
        u8 *pos = eid;
-       u8 len = 0;
+       u8 len = 0, i;
 
        if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
                len = 5;
@@ -181,53 +223,21 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
        if (len < 4)
                len = 4;
 #endif /* CONFIG_WNM */
+       if (len < hapd->iface->extended_capa_len)
+               len = hapd->iface->extended_capa_len;
        if (len == 0)
                return eid;
 
        *pos++ = WLAN_EID_EXT_CAPAB;
        *pos++ = len;
-       *pos++ = 0x00;
-       *pos++ = 0x00;
+       for (i = 0; i < len; i++, pos++) {
+               hostapd_ext_capab_byte(hapd, pos, i);
 
-       *pos = 0x00;
-       if (hapd->conf->wnm_sleep_mode)
-               *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
-       if (hapd->conf->bss_transition)
-               *pos |= 0x08; /* Bit 19 - BSS Transition */
-       pos++;
-
-       if (len < 4)
-               return pos;
-       *pos = 0x00;
-#ifdef CONFIG_WNM
-       *pos |= 0x02; /* Bit 25 - SSID List */
-#endif /* CONFIG_WNM */
-       if (hapd->conf->time_advertisement == 2)
-               *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
-       if (hapd->conf->interworking)
-               *pos |= 0x80; /* Bit 31 - Interworking */
-       pos++;
-
-       if (len < 5)
-               return pos;
-       *pos = 0x00;
-       if (hapd->conf->tdls & TDLS_PROHIBIT)
-               *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
-       if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
-               *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
-       pos++;
-
-       if (len < 6)
-               return pos;
-       *pos = 0x00;
-       pos++;
-
-       if (len < 7)
-               return pos;
-       *pos = 0x00;
-       if (hapd->conf->ssid.utf8_ssid)
-               *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
-       pos++;
+               if (i < hapd->iface->extended_capa_len) {
+                       *pos &= ~hapd->iface->extended_capa_mask[i];
+                       *pos |= hapd->iface->extended_capa[i];
+               }
+       }
 
        return pos;
 }
index ab6907d9a1b6447ac7188ca03dd469062faf3671..699a56f186787ed0935a9d8d915d8774a3ad3c29 100644 (file)
@@ -897,6 +897,15 @@ struct wpa_driver_capa {
 /* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING     0x00000008
        unsigned int probe_resp_offloads;
+
+       /**
+        * extended_capa - extended capabilities in driver/device
+        *
+        * Must be allocated and freed by driver and the pointers must be
+        * valid for the lifetime of the driver, i.e., freed in deinit()
+        */
+       const u8 *extended_capa, *extended_capa_mask;
+       unsigned int extended_capa_len;
 };
 
 
index e8896f3a4bce2f6253a589284a6f5b7f40fb9a6f..b53e7066ae893308a272a19d035be48a5f7b6e5e 100644 (file)
@@ -220,6 +220,8 @@ struct wpa_driver_nl80211_data {
        int ignore_if_down_event;
        struct rfkill_data *rfkill;
        struct wpa_driver_capa capa;
+       u8 *extended_capa, *extended_capa_mask;
+       unsigned int extended_capa_len;
        int has_capability;
 
        int operstate;
@@ -2545,6 +2547,7 @@ nla_put_failure:
 
 
 struct wiphy_info_data {
+       struct wpa_driver_nl80211_data *drv;
        struct wpa_driver_capa *capa;
 
        unsigned int error:1;
@@ -2786,6 +2789,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
        struct wiphy_info_data *info = arg;
        struct wpa_driver_capa *capa = info->capa;
+       struct wpa_driver_nl80211_data *drv = info->drv;
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
@@ -2833,6 +2837,30 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
        wiphy_info_probe_resp_offload(capa,
                                      tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
 
+       if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+           drv->extended_capa == NULL) {
+               drv->extended_capa =
+                       os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               if (drv->extended_capa) {
+                       os_memcpy(drv->extended_capa,
+                                 nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+                                 nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+                       drv->extended_capa_len =
+                               nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+               }
+               drv->extended_capa_mask =
+                       os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               if (drv->extended_capa_mask) {
+                       os_memcpy(drv->extended_capa_mask,
+                                 nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+                                 nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               } else {
+                       os_free(drv->extended_capa);
+                       drv->extended_capa = NULL;
+                       drv->extended_capa_len = 0;
+               }
+       }
+
        return NL_SKIP;
 }
 
@@ -2845,6 +2873,7 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
 
        os_memset(info, 0, sizeof(*info));
        info->capa = &drv->capa;
+       info->drv = drv;
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -3733,6 +3762,8 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
        if (drv->in_interface_list)
                dl_list_del(&drv->list);
 
+       os_free(drv->extended_capa);
+       os_free(drv->extended_capa_mask);
        os_free(drv);
 }
 
@@ -7591,6 +7622,11 @@ static int wpa_driver_nl80211_get_capa(void *priv,
        if (!drv->has_capability)
                return -1;
        os_memcpy(capa, &drv->capa, sizeof(*capa));
+       if (drv->extended_capa && drv->extended_capa_mask) {
+               capa->extended_capa = drv->extended_capa;
+               capa->extended_capa_mask = drv->extended_capa_mask;
+               capa->extended_capa_len = drv->extended_capa_len;
+       }
        return 0;
 }
 
index 8a996f9008cbe66a257d8912a45660d10447e710..3ba44964d92eec7d9ead85c5be3ef0153d798bf0 100644 (file)
@@ -498,6 +498,9 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
        hapd_iface->owner = wpa_s;
        hapd_iface->drv_flags = wpa_s->drv_flags;
        hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
+       hapd_iface->extended_capa = wpa_s->extended_capa;
+       hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
+       hapd_iface->extended_capa_len = wpa_s->extended_capa_len;
 
        wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
        if (conf == NULL) {
index 24cc8b602d4a1e874439f246ac482b50e27a6249..cac824426e33b0d334ab138f753cd9587deb729d 100644 (file)
@@ -1178,28 +1178,58 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 }
 
 
-int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
+static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
 {
-       u32 ext_capab = 0;
-       u8 *pos = buf;
+       *pos = 0x00;
 
+       switch (idx) {
+       case 0: /* Bits 0-7 */
+               break;
+       case 1: /* Bits 8-15 */
+               break;
+       case 2: /* Bits 16-23 */
+#ifdef CONFIG_WNM
+               *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+               *pos |= 0x08; /* Bit 19 - BSS Transition */
+#endif /* CONFIG_WNM */
+               break;
+       case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+               *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
 #ifdef CONFIG_INTERWORKING
-       if (wpa_s->conf->interworking)
-               ext_capab |= BIT(31); /* Interworking */
+               if (wpa_s->conf->interworking)
+                       *pos |= 0x80; /* Bit 31 - Interworking */
 #endif /* CONFIG_INTERWORKING */
+               break;
+       case 4: /* Bits 32-39 */
+               break;
+       case 5: /* Bits 40-47 */
+               break;
+       case 6: /* Bits 48-55 */
+               break;
+       }
+}
 
-#ifdef CONFIG_WNM
-       ext_capab |= BIT(17); /* WNM-Sleep Mode */
-       ext_capab |= BIT(19); /* BSS Transition */
-#endif /* CONFIG_WNM */
 
-       if (!ext_capab)
-               return 0;
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
+{
+       u8 *pos = buf;
+       u8 len = 4, i;
+
+       if (len < wpa_s->extended_capa_len)
+               len = wpa_s->extended_capa_len;
 
        *pos++ = WLAN_EID_EXT_CAPAB;
-       *pos++ = 4;
-       WPA_PUT_LE32(pos, ext_capab);
-       pos += 4;
+       *pos++ = len;
+       for (i = 0; i < len; i++, pos++) {
+               wpas_ext_capab_byte(wpa_s, pos, i);
+
+               if (i < wpa_s->extended_capa_len) {
+                       *pos &= ~wpa_s->extended_capa_mask[i];
+                       *pos |= wpa_s->extended_capa[i];
+               }
+       }
 
        return pos - buf;
 }
@@ -2904,6 +2934,9 @@ next_driver:
                wpa_s->max_match_sets = capa.max_match_sets;
                wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
                wpa_s->max_stations = capa.max_stations;
+               wpa_s->extended_capa = capa.extended_capa;
+               wpa_s->extended_capa_mask = capa.extended_capa_mask;
+               wpa_s->extended_capa_len = capa.extended_capa_len;
        }
        if (wpa_s->max_remain_on_chan == 0)
                wpa_s->max_remain_on_chan = 1000;
index 1a35a89271f64167344a48cc8091230be1ca762a..982fb655bf943a90d367dfd1139e6155d7bc5d57 100644 (file)
@@ -461,6 +461,10 @@ struct wpa_supplicant {
         */
        unsigned int probe_resp_offloads;
 
+       /* extended capabilities supported by the driver */
+       const u8 *extended_capa, *extended_capa_mask;
+       unsigned int extended_capa_len;
+
        int max_scan_ssids;
        int max_sched_scan_ssids;
        int sched_scan_supported;