[PATCH] hostapd: Add Operating Mode Notification support
Marek Kwaczynski
marek.kwaczynski
Thu Nov 21 04:21:55 PST 2013
Handling Operating Mode Notification received in Assoc Request.
Signed-off-by: Marek Kwaczynski <marek.kwaczynski at tieto.com>
---
src/ap/ap_drv_ops.c | 4 +++-
src/ap/ap_drv_ops.h | 2 +-
src/ap/ieee802_11.c | 8 +++++++-
src/ap/ieee802_11.h | 2 ++
src/ap/ieee802_11_vht.c | 25 +++++++++++++++++++++++++
src/ap/sta_info.h | 3 ++-
src/common/ieee802_11_common.c | 4 ++++
src/common/ieee802_11_common.h | 2 ++
src/common/ieee802_11_defs.h | 7 +++++++
src/drivers/driver.h | 2 ++
src/drivers/driver_nl80211.c | 6 ++++++
src/drivers/nl80211_copy.h | 5 +++++
12 files changed, 66 insertions(+), 4 deletions(-)
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 0dc0600..3541b82 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -347,7 +347,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u32 flags, u8 qosinfo)
+ u32 flags, u8 qosinfo, u8 vht_opmode)
{
struct hostapd_sta_add_params params;
@@ -365,6 +365,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
params.vht_capabilities = vht_capab;
+ params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
+ params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
return hapd->driver->sta_add(hapd->drv_priv, ¶ms);
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 1eab939..8fa1fb4 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -39,7 +39,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u32 flags, u8 qosinfo);
+ u32 flags, u8 qosinfo, u8 vht_opmode);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index d553caa..bd5ee8e 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -921,6 +921,12 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
elems.vht_capabilities_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+
+ resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif,
+ elems.vht_opmode_notif_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
!(sta->flags & WLAN_STA_VHT)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -1958,7 +1964,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
sta->listen_interval,
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
- sta->flags, sta->qosinfo)) {
+ sta->flags, sta->qosinfo, sta->vht_opmode)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
"Could not add STA to kernel driver");
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 61f1316..0c8cf8b 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -62,6 +62,8 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab, size_t vht_capab_len);
+u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_opmode, size_t vht_opmode_len);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 38590a3..230d821 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -109,6 +109,31 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
}
+u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_oper_notif, size_t vht_oper_notif_len)
+{
+ u8 channel_width;
+
+ if (!vht_oper_notif || vht_oper_notif_len != VHT_OPMODE_LEN) {
+ sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
+ return WLAN_STATUS_SUCCESS;
+ }
+ channel_width = *vht_oper_notif & VHT_OPMODE_CHANNEL_WIDTH_MASK;
+
+ if (channel_width != VHT_CHANWIDTH_USE_HT &&
+ channel_width != VHT_CHANWIDTH_80MHZ &&
+ channel_width != VHT_CHANWIDTH_160MHZ &&
+ channel_width != VHT_CHANWIDTH_80P80MHZ &&
+ (*vht_oper_notif & VHT_OPMODE_CHANNEL_RxNSS_MASK) > VHT_RX_NSS_MAX_STREAMS - 1) {
+ sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
+ sta->vht_opmode = *vht_oper_notif;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap)
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index dc74219..11339f5 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -29,6 +29,7 @@
#define WLAN_STA_WPS2 BIT(16)
#define WLAN_STA_GAS BIT(17)
#define WLAN_STA_VHT BIT(18)
+#define WLAN_STA_VHT_OPMODE_ENABLED BIT(19)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -105,7 +106,7 @@ struct sta_info {
struct ieee80211_ht_capabilities *ht_capabilities;
struct ieee80211_vht_capabilities *vht_capabilities;
-
+ u8 vht_opmode;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 304dfc6..50e692e 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -267,6 +267,10 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->vht_operation = pos;
elems->vht_operation_len = elen;
break;
+ case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
+ elems->vht_opmode_notif = pos;
+ elems->vht_opmode_notif_len = elen;
+ break;
case WLAN_EID_LINK_ID:
if (elen < 18)
break;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index c4618b2..19176af 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -35,6 +35,7 @@ struct ieee802_11_elems {
const u8 *ht_operation;
const u8 *vht_capabilities;
const u8 *vht_operation;
+ const u8 *vht_opmode_notif;
const u8 *vendor_ht_cap;
const u8 *p2p;
const u8 *wfd;
@@ -70,6 +71,7 @@ struct ieee802_11_elems {
u8 ht_operation_len;
u8 vht_capabilities_len;
u8 vht_operation_len;
+ u8 vht_opmode_notif_len;
u8 vendor_ht_cap_len;
u8 p2p_len;
u8 wfd_len;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 9b2d54f..6e939b6 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -748,6 +748,13 @@ struct ieee80211_vht_operation {
#define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28))
#define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29))
+#define VHT_OPMODE_CHANNEL_WIDTH_MASK ((u8) BIT(6) | BIT(7))
+#define VHT_OPMODE_CHANNEL_RxNSS_MASK ((u8) BIT(1) | BIT(2) | BIT(3))
+#define VHT_OPMODE_NOTIF_RX_NSS_SHIFT 4
+#define VHT_OPMODE_LEN 1
+
+#define VHT_RX_NSS_MAX_STREAMS 8
+
/* VHT channel widths */
#define VHT_CHANWIDTH_USE_HT 0
#define VHT_CHANWIDTH_80MHZ 1
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 2a80419..1211e5b 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -983,6 +983,8 @@ struct hostapd_sta_add_params {
u16 listen_interval;
const struct ieee80211_ht_capabilities *ht_capabilities;
const struct ieee80211_vht_capabilities *vht_capabilities;
+ int vht_opmode_enabled;
+ u8 vht_opmode;
u32 flags; /* bitmask of WPA_STA_* flags */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 9b2f81e..b05cc79 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -6948,6 +6948,12 @@ static int wpa_driver_nl80211_sta_add(void *priv,
params->vht_capabilities);
}
+ if (params->vht_opmode_enabled) {
+ wpa_printf(MSG_DEBUG, " * opmode=%u", params->vht_opmode);
+ NLA_PUT_U8(msg, NL80211_ATTR_VHT_OPMODE,
+ params->vht_opmode);
+ }
+
wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability);
NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index f752e98..16f16c8 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -1508,6 +1508,9 @@ enum nl80211_commands {
* to react to radar events, e.g. initiate a channel switch or leave the
* IBSS network.
*
+ * @NL80211_ATTR_VHT_OPMODE: VHT Operating mode information element (from
+ * association request when used with NL80211_CMD_NEW_STATION)
+
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1824,6 +1827,8 @@ enum nl80211_attrs {
NL80211_ATTR_HANDLE_DFS,
+ NL80211_ATTR_VHT_OPMODE,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
--
1.7.9.5
More information about the Hostap
mailing list