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) {
|
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
|
||||||
iface->drv_flags = capa.flags;
|
iface->drv_flags = capa.flags;
|
||||||
iface->probe_resp_offloads = capa.probe_resp_offloads;
|
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;
|
return 0;
|
||||||
|
|
|
@ -229,6 +229,10 @@ struct hostapd_iface {
|
||||||
*/
|
*/
|
||||||
unsigned int probe_resp_offloads;
|
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;
|
struct hostapd_hw_modes *hw_features;
|
||||||
int num_hw_features;
|
int num_hw_features;
|
||||||
struct hostapd_hw_modes *current_mode;
|
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 */
|
#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 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||||
{
|
{
|
||||||
u8 *pos = eid;
|
u8 *pos = eid;
|
||||||
u8 len = 0;
|
u8 len = 0, i;
|
||||||
|
|
||||||
if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
|
if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
|
||||||
len = 5;
|
len = 5;
|
||||||
|
@ -181,53 +223,21 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||||
if (len < 4)
|
if (len < 4)
|
||||||
len = 4;
|
len = 4;
|
||||||
#endif /* CONFIG_WNM */
|
#endif /* CONFIG_WNM */
|
||||||
|
if (len < hapd->iface->extended_capa_len)
|
||||||
|
len = hapd->iface->extended_capa_len;
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return eid;
|
return eid;
|
||||||
|
|
||||||
*pos++ = WLAN_EID_EXT_CAPAB;
|
*pos++ = WLAN_EID_EXT_CAPAB;
|
||||||
*pos++ = len;
|
*pos++ = len;
|
||||||
*pos++ = 0x00;
|
for (i = 0; i < len; i++, pos++) {
|
||||||
*pos++ = 0x00;
|
hostapd_ext_capab_byte(hapd, pos, i);
|
||||||
|
|
||||||
*pos = 0x00;
|
if (i < hapd->iface->extended_capa_len) {
|
||||||
if (hapd->conf->wnm_sleep_mode)
|
*pos &= ~hapd->iface->extended_capa_mask[i];
|
||||||
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
|
*pos |= hapd->iface->extended_capa[i];
|
||||||
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++;
|
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
|
@ -897,6 +897,15 @@ struct wpa_driver_capa {
|
||||||
/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
|
/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
|
||||||
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008
|
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008
|
||||||
unsigned int probe_resp_offloads;
|
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;
|
int ignore_if_down_event;
|
||||||
struct rfkill_data *rfkill;
|
struct rfkill_data *rfkill;
|
||||||
struct wpa_driver_capa capa;
|
struct wpa_driver_capa capa;
|
||||||
|
u8 *extended_capa, *extended_capa_mask;
|
||||||
|
unsigned int extended_capa_len;
|
||||||
int has_capability;
|
int has_capability;
|
||||||
|
|
||||||
int operstate;
|
int operstate;
|
||||||
|
@ -2545,6 +2547,7 @@ nla_put_failure:
|
||||||
|
|
||||||
|
|
||||||
struct wiphy_info_data {
|
struct wiphy_info_data {
|
||||||
|
struct wpa_driver_nl80211_data *drv;
|
||||||
struct wpa_driver_capa *capa;
|
struct wpa_driver_capa *capa;
|
||||||
|
|
||||||
unsigned int error:1;
|
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 genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
||||||
struct wiphy_info_data *info = arg;
|
struct wiphy_info_data *info = arg;
|
||||||
struct wpa_driver_capa *capa = info->capa;
|
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),
|
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
||||||
genlmsg_attrlen(gnlh, 0), NULL);
|
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,
|
wiphy_info_probe_resp_offload(capa,
|
||||||
tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
|
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;
|
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));
|
os_memset(info, 0, sizeof(*info));
|
||||||
info->capa = &drv->capa;
|
info->capa = &drv->capa;
|
||||||
|
info->drv = drv;
|
||||||
|
|
||||||
msg = nlmsg_alloc();
|
msg = nlmsg_alloc();
|
||||||
if (!msg)
|
if (!msg)
|
||||||
|
@ -3733,6 +3762,8 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
|
||||||
if (drv->in_interface_list)
|
if (drv->in_interface_list)
|
||||||
dl_list_del(&drv->list);
|
dl_list_del(&drv->list);
|
||||||
|
|
||||||
|
os_free(drv->extended_capa);
|
||||||
|
os_free(drv->extended_capa_mask);
|
||||||
os_free(drv);
|
os_free(drv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7591,6 +7622,11 @@ static int wpa_driver_nl80211_get_capa(void *priv,
|
||||||
if (!drv->has_capability)
|
if (!drv->has_capability)
|
||||||
return -1;
|
return -1;
|
||||||
os_memcpy(capa, &drv->capa, sizeof(*capa));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -498,6 +498,9 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
|
||||||
hapd_iface->owner = wpa_s;
|
hapd_iface->owner = wpa_s;
|
||||||
hapd_iface->drv_flags = wpa_s->drv_flags;
|
hapd_iface->drv_flags = wpa_s->drv_flags;
|
||||||
hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
|
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();
|
wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
|
||||||
if (conf == NULL) {
|
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)
|
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
|
||||||
{
|
{
|
||||||
u32 ext_capab = 0;
|
|
||||||
u8 *pos = buf;
|
u8 *pos = buf;
|
||||||
|
u8 len = 4, i;
|
||||||
|
|
||||||
#ifdef CONFIG_INTERWORKING
|
if (len < wpa_s->extended_capa_len)
|
||||||
if (wpa_s->conf->interworking)
|
len = wpa_s->extended_capa_len;
|
||||||
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;
|
|
||||||
|
|
||||||
*pos++ = WLAN_EID_EXT_CAPAB;
|
*pos++ = WLAN_EID_EXT_CAPAB;
|
||||||
*pos++ = 4;
|
*pos++ = len;
|
||||||
WPA_PUT_LE32(pos, ext_capab);
|
for (i = 0; i < len; i++, pos++) {
|
||||||
pos += 4;
|
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;
|
return pos - buf;
|
||||||
}
|
}
|
||||||
|
@ -2904,6 +2934,9 @@ next_driver:
|
||||||
wpa_s->max_match_sets = capa.max_match_sets;
|
wpa_s->max_match_sets = capa.max_match_sets;
|
||||||
wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
|
wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
|
||||||
wpa_s->max_stations = capa.max_stations;
|
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)
|
if (wpa_s->max_remain_on_chan == 0)
|
||||||
wpa_s->max_remain_on_chan = 1000;
|
wpa_s->max_remain_on_chan = 1000;
|
||||||
|
|
|
@ -461,6 +461,10 @@ struct wpa_supplicant {
|
||||||
*/
|
*/
|
||||||
unsigned int probe_resp_offloads;
|
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_scan_ssids;
|
||||||
int max_sched_scan_ssids;
|
int max_sched_scan_ssids;
|
||||||
int sched_scan_supported;
|
int sched_scan_supported;
|
||||||
|
|
Loading…
Reference in a new issue