aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKanchanapally, Vidyullatha <vkanchan@qti.qualcomm.com>2016-04-12 13:31:42 +0530
committerLinux Build Service Account <lnxbuild@localhost>2016-08-24 08:07:45 -0600
commitd0f59302dc1780530a62add349bb75a349876851 (patch)
tree6c5131f2128e35dd72a158a8bd400a723ee99bc7
parentade78076f83d16282ffc2588fa6f307653711bcc (diff)
downloadandroid_external_wpa_supplicant_8-d0f59302dc1780530a62add349bb75a349876851.tar.gz
android_external_wpa_supplicant_8-d0f59302dc1780530a62add349bb75a349876851.tar.bz2
android_external_wpa_supplicant_8-d0f59302dc1780530a62add349bb75a349876851.zip
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. CRs-Fixed: 1030694 Git-commit: cc9a2575cabd2adb975df3677c6df5829f4279ad Git-repo : git://w1.fi/srv/git/hostap.git Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com> Change-Id: Ia192693d606ebf9b7028ecc58be01cbf37cb4620
-rw-r--r--hostapd/main.c9
-rw-r--r--src/ap/ap_drv_ops.c14
-rw-r--r--src/ap/ap_drv_ops.h2
-rw-r--r--src/drivers/driver.h13
-rw-r--r--src/drivers/driver_nl80211.c41
-rw-r--r--src/drivers/driver_nl80211.h9
-rw-r--r--src/drivers/driver_nl80211_capa.c77
-rw-r--r--wpa_supplicant/ap.c5
-rw-r--r--wpa_supplicant/driver_i.h11
-rw-r--r--wpa_supplicant/scan.c7
-rw-r--r--wpa_supplicant/sme.c5
-rw-r--r--wpa_supplicant/wpa_supplicant.c5
12 files changed, 197 insertions, 1 deletions
diff --git a/hostapd/main.c b/hostapd/main.c
index 1d9e63e3..5f3f83bf 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -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))
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index b89f60e1..a9d12ce9 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -747,6 +747,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;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 757a706c..8e87c7dd 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -123,6 +123,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)
{
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 40d95bf6..c33db9fe 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -3541,6 +3541,19 @@ struct wpa_driver_ops {
int (*abort_scan)(void *priv);
/**
+ * 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);
+
+ /**
* p2p_lo_start - Start offloading P2P listen to device
* @priv: Private driver interface data
* @freq: Listening frequency (MHz) for P2P listen
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index f9837776..0ca6ccdc 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2366,6 +2366,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);
@@ -2462,6 +2463,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);
}
@@ -4109,7 +4114,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:
@@ -9134,6 +9139,39 @@ static int nl80211_p2p_lo_stop(void *priv)
}
#endif /* CONFIG_DRIVER_NL80211_QCA */
+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",
@@ -9252,4 +9290,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.p2p_lo_start = nl80211_p2p_lo_start,
.p2p_lo_stop = nl80211_p2p_lo_stop,
#endif /* CONFIG_DRIVER_NL80211_QCA */
+ .get_ext_capab = nl80211_get_ext_capab,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index b0d2b6d7..283dfd99 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -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,
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index cc37deee..a5515fff 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -479,6 +479,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];
@@ -569,6 +637,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]));
@@ -576,6 +647,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;
@@ -583,6 +658,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;
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 4f895f34..f6abd706 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -654,6 +654,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, &params) < 0) {
wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
return -1;
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index fd56c0cd..82e9a5a3 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -917,6 +917,17 @@ static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s)
return wpa_s->driver->abort_scan(wpa_s->drv_priv);
}
+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);
+}
+
static inline int wpa_drv_p2p_lo_start(struct wpa_supplicant *wpa_s,
unsigned int channel,
unsigned int period,
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 7a528262..53bdf860 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -438,6 +438,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 &&
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index a6ace1ad..dc52d027 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -451,6 +451,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) {
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 3f1d08b8..6a978667 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -2286,6 +2286,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;