From patchwork Mon Feb 18 17:06:02 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 221422 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from maxx.maxx.shmoo.com (maxx.shmoo.com [205.134.188.171]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "maxx.shmoo.com", Issuer "CA Cert Signing Authority" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 57A542C0367 for ; Tue, 19 Feb 2013 04:06:24 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 598069D302; Mon, 18 Feb 2013 12:06:20 -0500 (EST) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id o0IDylFteB3d; Mon, 18 Feb 2013 12:06:20 -0500 (EST) Received: from maxx.shmoo.com (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id E2BCD9D309; Mon, 18 Feb 2013 12:06:14 -0500 (EST) X-Original-To: mailman-post+hostap@maxx.shmoo.com Delivered-To: mailman-post+hostap@maxx.shmoo.com Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 6DE1E9D302 for ; Mon, 18 Feb 2013 12:06:13 -0500 (EST) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id lhS1qEMPsSId for ; Mon, 18 Feb 2013 12:06:08 -0500 (EST) Received: from sipsolutions.net (he.sipsolutions.net [78.46.109.217]) (using TLSv1 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (Client did not present a certificate) by maxx.maxx.shmoo.com (Postfix) with ESMTPS id 18A629D309 for ; Mon, 18 Feb 2013 12:06:07 -0500 (EST) Received: by sipsolutions.net with esmtpsa (TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256) (Exim 4.80) (envelope-from ) id 1U7UAH-0006xR-G1; Mon, 18 Feb 2013 18:06:05 +0100 From: Johannes Berg To: hostap@lists.shmoo.com Subject: [PATCH v2] hostapd/wpa_s: use driver's extended capabilities Date: Mon, 18 Feb 2013 18:06:02 +0100 Message-Id: <1361207162-5377-1-git-send-email-johannes@sipsolutions.net> X-Mailer: git-send-email 1.8.0 Cc: Johannes Berg X-BeenThere: hostap@lists.shmoo.com X-Mailman-Version: 2.1.9 Precedence: list List-Id: HostAP Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: hostap-bounces@lists.shmoo.com Errors-To: hostap-bounces@lists.shmoo.com From: Johannes Berg 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 --- 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 274eeca..bb373be 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -882,6 +882,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 0803b16..fbdafc5 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; @@ -2477,6 +2479,7 @@ nla_put_failure: struct wiphy_info_data { + struct wpa_driver_nl80211_data *drv; struct wpa_driver_capa *capa; unsigned int error:1; @@ -2509,6 +2512,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct wiphy_info_data *info = arg; + struct wpa_driver_nl80211_data *drv = info->drv; int p2p_go_supported = 0, p2p_client_supported = 0; int p2p_concurrent = 0, p2p_multichan_concurrent = 0; int auth_supported = 0, connect_supported = 0; @@ -2729,6 +2733,30 @@ broken_combination: probe_resp_offload_support(protocols); } + 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; } @@ -2740,6 +2768,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) @@ -3601,6 +3630,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); } @@ -7352,6 +7383,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 82b7e19..fb8d51e 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -486,6 +486,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 ef7a6f0..d32d06e 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; } @@ -2866,6 +2888,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 0f51f8e..63808ab 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;