[PATCH v3] hostapd/wpa_s: use driver's extended capabilities
Johannes Berg
johannes
Sun Mar 10 12:18:13 PDT 2013
From: Johannes Berg <johannes.berg at intel.com>
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 at intel.com>
---
hostapd/main.c | 3 ++
src/ap/hostapd.h | 4 ++
src/ap/ieee802_11_shared.c | 80 ++++++++++++++++++++-------------------
src/drivers/driver.h | 9 +++++
src/drivers/driver_nl80211.c | 34 +++++++++++++++++
wpa_supplicant/ap.c | 3 ++
wpa_supplicant/wpa_supplicant.c | 53 +++++++++++++++++++-------
wpa_supplicant/wpa_supplicant_i.h | 4 ++
8 files changed, 137 insertions(+), 53 deletions(-)
diff --git a/hostapd/main.c b/hostapd/main.c
index d4256d0..b92637b 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -273,6 +273,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;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 8ab4f3e..669633d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -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;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 76f78a7..657e7ee 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -167,7 +167,7 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
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 +181,55 @@ 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;
-
- *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++;
+ for (i = 0; i < len; i++, pos++) {
+ *pos = 0x00;
- if (len < 4)
- return pos;
- *pos = 0x00;
+ switch (i) {
+ 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 */
+ *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 (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)
+ *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
+ 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;
+ }
- 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;
}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 1a53db3..7fead43 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -895,6 +895,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;
};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 4635d05..eb415a0 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -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;
@@ -2513,6 +2515,7 @@ nla_put_failure:
struct wiphy_info_data {
+ struct wpa_driver_nl80211_data *drv;
struct wpa_driver_capa *capa;
unsigned int error:1;
@@ -2751,6 +2754,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);
@@ -2798,6 +2802,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;
}
@@ -2810,6 +2838,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)
@@ -3698,6 +3727,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);
}
@@ -7543,6 +7574,9 @@ static int wpa_driver_nl80211_get_capa(void *priv,
if (!drv->has_capability)
return -1;
os_memcpy(capa, &drv->capa, sizeof(*capa));
+ capa->extended_capa = drv->extended_capa;
+ capa->extended_capa_mask = drv->extended_capa_mask;
+ capa->extended_capa_len = drv->extended_capa_len;
return 0;
}
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 720ff7b..f7ab6f1 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -493,6 +493,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) {
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 42a475f..8d64d23 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1189,26 +1189,48 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
{
- u32 ext_capab = 0;
u8 *pos = buf;
+ u8 len = 4, i;
-#ifdef CONFIG_INTERWORKING
- if (wpa_s->conf->interworking)
- ext_capab |= BIT(31); /* Interworking */
-#endif /* CONFIG_INTERWORKING */
+ if (len < wpa_s->extended_capa_len)
+ len = wpa_s->extended_capa_len;
+ *pos++ = WLAN_EID_EXT_CAPAB;
+ *pos++ = len;
+ for (i = 0; i < len; i++, pos++) {
+ *pos = 0x00;
+
+ switch (i) {
+ case 0: /* Bits 0-7 */
+ break;
+ case 1: /* Bits 8-15 */
+ break;
+ case 2: /* Bits 16-23 */
#ifdef CONFIG_WNM
- ext_capab |= BIT(17); /* WNM-Sleep Mode */
- ext_capab |= BIT(19); /* BSS Transition */
+ *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
+#endif
+ break;
+ case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 25 - SSID List */
#endif /* CONFIG_WNM */
+ if (wpa_s->conf->interworking)
+ *pos |= 0x80; /* Bit 31 - Interworking */
+ break;
+ case 4: /* Bits 32-39 */
+ break;
+ case 5: /* Bits 40-47 */
+ break;
+ case 6: /* Bits 48-55 */
+ break;
+ }
- if (!ext_capab)
- return 0;
-
- *pos++ = WLAN_EID_EXT_CAPAB;
- *pos++ = 4;
- WPA_PUT_LE32(pos, ext_capab);
- pos += 4;
+ if (i < wpa_s->extended_capa_len) {
+ *pos &= ~wpa_s->extended_capa_mask[i];
+ *pos |= wpa_s->extended_capa[i];
+ }
+ }
return pos - buf;
}
@@ -2914,6 +2936,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;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 4ec15c1..9f278de 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -459,6 +459,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;
--
1.8.0
More information about the Hostap
mailing list