nl80211: Use extended capabilities per interface type
This adds the necessary changes to support extraction and use of the extended capabilities specified per interface type (a recent cfg80211/nl80211 extension). If that information is available, per-interface values will be used to override the global per-radio value. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
c6edea0df6
commit
cc9a2575ca
12 changed files with 197 additions and 1 deletions
|
@ -217,11 +217,20 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
|||
iface->drv_flags = capa.flags;
|
||||
iface->smps_modes = capa.smps_modes;
|
||||
iface->probe_resp_offloads = capa.probe_resp_offloads;
|
||||
/*
|
||||
* Use default extended capa values from per-radio information
|
||||
*/
|
||||
iface->extended_capa = capa.extended_capa;
|
||||
iface->extended_capa_mask = capa.extended_capa_mask;
|
||||
iface->extended_capa_len = capa.extended_capa_len;
|
||||
iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
|
||||
|
||||
/*
|
||||
* Override extended capa with per-interface type (AP), if
|
||||
* available from the driver.
|
||||
*/
|
||||
hostapd_get_ext_capa(iface);
|
||||
|
||||
triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
|
||||
if (triggs && hapd->driver->set_wowlan) {
|
||||
if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
|
||||
|
|
|
@ -750,6 +750,20 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
|
|||
}
|
||||
|
||||
|
||||
void hostapd_get_ext_capa(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
|
||||
if (!hapd->driver || !hapd->driver->get_ext_capab)
|
||||
return;
|
||||
|
||||
hapd->driver->get_ext_capab(hapd->drv_priv, WPA_IF_AP_BSS,
|
||||
&iface->extended_capa,
|
||||
&iface->extended_capa_mask,
|
||||
&iface->extended_capa_len);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
{
|
||||
struct drv_acs_params params;
|
||||
|
|
|
@ -124,6 +124,8 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
|
|||
int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
|
||||
u8 qos_map_set_len);
|
||||
|
||||
void hostapd_get_ext_capa(struct hostapd_iface *iface);
|
||||
|
||||
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
|
||||
int enabled)
|
||||
{
|
||||
|
|
|
@ -3560,6 +3560,19 @@ struct wpa_driver_ops {
|
|||
* Returns: 0 on success or -1 on failure
|
||||
*/
|
||||
int (*configure_data_frame_filters)(void *priv, u32 filter_flags);
|
||||
|
||||
/**
|
||||
* get_ext_capab - Get extended capabilities for the specified interface
|
||||
* @priv: Private driver interface data
|
||||
* @type: Interface type for which to get extended capabilities
|
||||
* @ext_capab: Extended capabilities fetched
|
||||
* @ext_capab_mask: Extended capabilities mask
|
||||
* @ext_capab_len: Length of the extended capabilities
|
||||
* Returns: 0 on success or -1 on failure
|
||||
*/
|
||||
int (*get_ext_capab)(void *priv, enum wpa_driver_if_type type,
|
||||
const u8 **ext_capab, const u8 **ext_capab_mask,
|
||||
unsigned int *ext_capab_len);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2412,6 +2412,7 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
|
|||
static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
|
||||
{
|
||||
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||
unsigned int i;
|
||||
|
||||
wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
|
||||
bss->ifname, drv->disabled_11b_rates);
|
||||
|
@ -2508,6 +2509,10 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
|
|||
|
||||
os_free(drv->extended_capa);
|
||||
os_free(drv->extended_capa_mask);
|
||||
for (i = 0; i < drv->num_iface_ext_capa; i++) {
|
||||
os_free(drv->iface_ext_capa[i].ext_capa);
|
||||
os_free(drv->iface_ext_capa[i].ext_capa_mask);
|
||||
}
|
||||
os_free(drv->first_bss);
|
||||
os_free(drv);
|
||||
}
|
||||
|
@ -4162,7 +4167,7 @@ void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
|
|||
}
|
||||
|
||||
|
||||
static const char * nl80211_iftype_str(enum nl80211_iftype mode)
|
||||
const char * nl80211_iftype_str(enum nl80211_iftype mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
|
@ -9202,6 +9207,39 @@ static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
|
|||
}
|
||||
|
||||
|
||||
static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
|
||||
const u8 **ext_capa, const u8 **ext_capa_mask,
|
||||
unsigned int *ext_capa_len)
|
||||
{
|
||||
struct i802_bss *bss = priv;
|
||||
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||
enum nl80211_iftype nlmode;
|
||||
unsigned int i;
|
||||
|
||||
if (!ext_capa || !ext_capa_mask || !ext_capa_len)
|
||||
return -1;
|
||||
|
||||
nlmode = wpa_driver_nl80211_if_type(type);
|
||||
|
||||
/* By default, use the per-radio values */
|
||||
*ext_capa = drv->extended_capa;
|
||||
*ext_capa_mask = drv->extended_capa_mask;
|
||||
*ext_capa_len = drv->extended_capa_len;
|
||||
|
||||
/* Replace the default value if a per-interface type value exists */
|
||||
for (i = 0; i < drv->num_iface_ext_capa; i++) {
|
||||
if (nlmode == drv->iface_ext_capa[i].iftype) {
|
||||
*ext_capa = drv->iface_ext_capa[i].ext_capa;
|
||||
*ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask;
|
||||
*ext_capa_len = drv->iface_ext_capa[i].ext_capa_len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||
.name = "nl80211",
|
||||
.desc = "Linux nl80211/cfg80211",
|
||||
|
@ -9319,4 +9357,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
|||
.set_prob_oper_freq = nl80211_set_prob_oper_freq,
|
||||
#endif /* CONFIG_DRIVER_NL80211_QCA */
|
||||
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
|
||||
.get_ext_capab = nl80211_get_ext_capab,
|
||||
};
|
||||
|
|
|
@ -96,6 +96,13 @@ struct wpa_driver_nl80211_data {
|
|||
struct wpa_driver_capa capa;
|
||||
u8 *extended_capa, *extended_capa_mask;
|
||||
unsigned int extended_capa_len;
|
||||
struct drv_nl80211_ext_capa {
|
||||
enum nl80211_iftype iftype;
|
||||
u8 *ext_capa, *ext_capa_mask;
|
||||
unsigned int ext_capa_len;
|
||||
} iface_ext_capa[NL80211_IFTYPE_MAX];
|
||||
unsigned int num_iface_ext_capa;
|
||||
|
||||
int has_capability;
|
||||
|
||||
int operstate;
|
||||
|
@ -251,6 +258,8 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags);
|
|||
int process_global_event(struct nl_msg *msg, void *arg);
|
||||
int process_bss_event(struct nl_msg *msg, void *arg);
|
||||
|
||||
const char * nl80211_iftype_str(enum nl80211_iftype mode);
|
||||
|
||||
#ifdef ANDROID
|
||||
int android_nl_socket_set_nonblocking(struct nl_handle *handle);
|
||||
int android_pno_start(struct i802_bss *bss,
|
||||
|
|
|
@ -486,6 +486,74 @@ static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
|
|||
}
|
||||
|
||||
|
||||
static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv,
|
||||
struct nlattr *tb)
|
||||
{
|
||||
int rem = 0, i;
|
||||
struct nlattr *tb1[NL80211_ATTR_MAX + 1], *attr;
|
||||
|
||||
if (!tb || drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
|
||||
return;
|
||||
|
||||
nla_for_each_nested(attr, tb, rem) {
|
||||
unsigned int len;
|
||||
struct drv_nl80211_ext_capa *capa;
|
||||
|
||||
nla_parse(tb1, NL80211_ATTR_MAX, nla_data(attr),
|
||||
nla_len(attr), NULL);
|
||||
|
||||
if (!tb1[NL80211_ATTR_IFTYPE] ||
|
||||
!tb1[NL80211_ATTR_EXT_CAPA] ||
|
||||
!tb1[NL80211_ATTR_EXT_CAPA_MASK])
|
||||
continue;
|
||||
|
||||
capa = &drv->iface_ext_capa[drv->num_iface_ext_capa];
|
||||
capa->iftype = nla_get_u32(tb1[NL80211_ATTR_IFTYPE]);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Driver-advertised extended capabilities for interface type %s",
|
||||
nl80211_iftype_str(capa->iftype));
|
||||
|
||||
len = nla_len(tb1[NL80211_ATTR_EXT_CAPA]);
|
||||
capa->ext_capa = os_malloc(len);
|
||||
if (!capa->ext_capa)
|
||||
goto err;
|
||||
|
||||
os_memcpy(capa->ext_capa, nla_data(tb1[NL80211_ATTR_EXT_CAPA]),
|
||||
len);
|
||||
capa->ext_capa_len = len;
|
||||
wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities",
|
||||
capa->ext_capa, capa->ext_capa_len);
|
||||
|
||||
len = nla_len(tb1[NL80211_ATTR_EXT_CAPA_MASK]);
|
||||
capa->ext_capa_mask = os_malloc(len);
|
||||
if (!capa->ext_capa_mask)
|
||||
goto err;
|
||||
|
||||
os_memcpy(capa->ext_capa_mask,
|
||||
nla_data(tb1[NL80211_ATTR_EXT_CAPA_MASK]), len);
|
||||
wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities mask",
|
||||
capa->ext_capa_mask, capa->ext_capa_len);
|
||||
|
||||
drv->num_iface_ext_capa++;
|
||||
if (drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
/* Cleanup allocated memory on error */
|
||||
for (i = 0; i < NL80211_IFTYPE_MAX; i++) {
|
||||
os_free(drv->iface_ext_capa[i].ext_capa);
|
||||
drv->iface_ext_capa[i].ext_capa = NULL;
|
||||
os_free(drv->iface_ext_capa[i].ext_capa_mask);
|
||||
drv->iface_ext_capa[i].ext_capa_mask = NULL;
|
||||
drv->iface_ext_capa[i].ext_capa_len = 0;
|
||||
}
|
||||
drv->num_iface_ext_capa = 0;
|
||||
}
|
||||
|
||||
|
||||
static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct nlattr *tb[NL80211_ATTR_MAX + 1];
|
||||
|
@ -576,6 +644,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
|||
nla_len(tb[NL80211_ATTR_EXT_CAPA]));
|
||||
drv->extended_capa_len =
|
||||
nla_len(tb[NL80211_ATTR_EXT_CAPA]);
|
||||
wpa_hexdump(MSG_DEBUG,
|
||||
"nl80211: Driver-advertised extended capabilities (default)",
|
||||
drv->extended_capa, drv->extended_capa_len);
|
||||
}
|
||||
drv->extended_capa_mask =
|
||||
os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
|
||||
|
@ -583,6 +654,10 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
|||
os_memcpy(drv->extended_capa_mask,
|
||||
nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]),
|
||||
nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
|
||||
wpa_hexdump(MSG_DEBUG,
|
||||
"nl80211: Driver-advertised extended capabilities mask (default)",
|
||||
drv->extended_capa_mask,
|
||||
drv->extended_capa_len);
|
||||
} else {
|
||||
os_free(drv->extended_capa);
|
||||
drv->extended_capa = NULL;
|
||||
|
@ -590,6 +665,8 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
wiphy_info_extended_capab(drv, tb[NL80211_ATTR_IFTYPE_EXT_CAPA]);
|
||||
|
||||
if (tb[NL80211_ATTR_VENDOR_DATA]) {
|
||||
struct nlattr *nl;
|
||||
int rem;
|
||||
|
|
|
@ -660,6 +660,11 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
|
|||
if (ieee80211_is_dfs(params.freq.freq))
|
||||
params.freq.freq = 0; /* set channel after CAC */
|
||||
|
||||
if (params.p2p)
|
||||
wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_GO);
|
||||
else
|
||||
wpa_drv_get_ext_capa(wpa_s, WPA_IF_AP_BSS);
|
||||
|
||||
if (wpa_drv_associate(wpa_s, ¶ms) < 0) {
|
||||
wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
|
||||
return -1;
|
||||
|
|
|
@ -926,4 +926,15 @@ static inline int wpa_drv_configure_frame_filters(struct wpa_supplicant *wpa_s,
|
|||
filters);
|
||||
}
|
||||
|
||||
static inline int wpa_drv_get_ext_capa(struct wpa_supplicant *wpa_s,
|
||||
enum wpa_driver_if_type type)
|
||||
{
|
||||
if (!wpa_s->driver->get_ext_capab)
|
||||
return -1;
|
||||
return wpa_s->driver->get_ext_capab(wpa_s->drv_priv, type,
|
||||
&wpa_s->extended_capa,
|
||||
&wpa_s->extended_capa_mask,
|
||||
&wpa_s->extended_capa_len);
|
||||
}
|
||||
|
||||
#endif /* DRIVER_I_H */
|
||||
|
|
|
@ -436,6 +436,13 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
|
|||
enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
|
||||
wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
|
||||
else
|
||||
#endif /* CONFIG_P2P */
|
||||
wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
|
||||
|
||||
ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
|
||||
sizeof(ext_capab));
|
||||
if (ext_capab_len > 0 &&
|
||||
|
|
|
@ -455,6 +455,11 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
|||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
if (params.p2p)
|
||||
wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
|
||||
else
|
||||
wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
|
||||
|
||||
ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
|
||||
sizeof(ext_capab));
|
||||
if (ext_capab_len > 0) {
|
||||
|
|
|
@ -2291,6 +2291,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
|
|||
* element in all cases, it is justifiable to skip it to avoid
|
||||
* interoperability issues.
|
||||
*/
|
||||
if (ssid->p2p_group)
|
||||
wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
|
||||
else
|
||||
wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
|
||||
|
||||
if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
|
||||
u8 ext_capab[18];
|
||||
int ext_capab_len;
|
||||
|
|
Loading…
Reference in a new issue