hostapd/wpa_s: Use driver's extended capabilities
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>
This commit is contained in:
parent
62d58f7ae3
commit
8cd6b7bce8
8 changed files with 160 additions and 58 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1178,28 +1178,58 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
|
|||
}
|
||||
|
||||
|
||||
static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, 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 */
|
||||
#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)
|
||||
*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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
|
||||
#ifdef CONFIG_WNM
|
||||
ext_capab |= BIT(17); /* WNM-Sleep Mode */
|
||||
ext_capab |= BIT(19); /* BSS Transition */
|
||||
#endif /* CONFIG_WNM */
|
||||
|
||||
if (!ext_capab)
|
||||
return 0;
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue