]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd: Add Operating Mode Notification support
authorMarek Kwaczynski <marek.kwaczynski@tieto.com>
Mon, 10 Feb 2014 12:43:05 +0000 (13:43 +0100)
committerJouni Malinen <j@w1.fi>
Fri, 14 Feb 2014 17:30:05 +0000 (19:30 +0200)
Handle Operating Mode Notification received in (Re)Association Request
frames.

Signed-hostap: Marek Kwaczynski <marek.kwaczynski@tieto.com>

src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/ieee802_11_vht.c
src/ap/sta_info.h
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
src/common/ieee802_11_defs.h
src/drivers/driver.h
src/drivers/driver_nl80211.c

index 893e6d9eee8bcc77e7ec77dc3fb96b9f06b0372e..e998fc620510bb1efd3eefea6958b47a120c510d 100644 (file)
@@ -346,7 +346,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;
 
@@ -364,6 +364,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, &params);
index 15a4b2678202ee842135b109fa10d792fa8f0e30..9edaf7d741c0d4ebbe649635685c6493fe36eb3a 100644 (file)
@@ -40,7 +40,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);
index c755265c8af574700f513b96252de57f6d0de2d6..9251ac3a548a884d16975fefe89b5374465f71d9 100644 (file)
@@ -895,6 +895,11 @@ 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);
+       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,
@@ -1937,7 +1942,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");
index 566a65ad695b2650ba489f827f0cc1ad8b759a3a..809b4ca6c088ab8e2b9bf62cb7bac05f2107eaea 100644 (file)
@@ -61,6 +61,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);
 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,
index f2ab182db3949db193595d9fa43de982bfcd2ef8..221d9c207d014564fa5e574e63ae6bc405ecdbfa 100644 (file)
@@ -108,6 +108,35 @@ 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)
+{
+       u8 channel_width;
+
+       if (!vht_oper_notif) {
+               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_OPMODE_NOTIF_RX_NSS_SHIFT) > 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)
index 9b77e0609132d850f69d7293cb14d607cfe1d878..240b92634a39e036580b0a395ed6821d0c6472ca 100644 (file)
@@ -27,6 +27,7 @@
 #define WLAN_STA_GAS BIT(17)
 #define WLAN_STA_VHT BIT(18)
 #define WLAN_STA_WNM_SLEEP_MODE BIT(19)
+#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
 #define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
 #define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
@@ -103,6 +104,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;
index 809089faca53de6c1476a0fb2aba9a8eb4e8566f..50bdc0147a18280b73481455b04cea0485777906 100644 (file)
@@ -252,6 +252,11 @@ 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:
+                       if (elen != 1)
+                               break;
+                       elems->vht_opmode_notif = pos;
+                       break;
                case WLAN_EID_LINK_ID:
                        if (elen < 18)
                                break;
index b84dd9e75741bd37c4f754bacf1b1be3bf3eae25..4fb2e842a3ceaabaae56030e0c40246e5c11eb25 100644 (file)
@@ -30,6 +30,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;
index 6f7f7779da67b31c2762a13f011dbb5c3220c0d8..0e39caf563a1c8e5e3e32b4908dfce9c3fe4dc2a 100644 (file)
@@ -764,6 +764,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(0) | BIT(1))
+#define VHT_OPMODE_CHANNEL_RxNSS_MASK              ((u8) BIT(4) | BIT(5) | \
+                                                    BIT(6))
+#define VHT_OPMODE_NOTIF_RX_NSS_SHIFT              4
+
+#define VHT_RX_NSS_MAX_STREAMS                     8
+
 /* VHT channel widths */
 #define VHT_CHANWIDTH_USE_HT   0
 #define VHT_CHANWIDTH_80MHZ    1
index d4136d7f867deae28c7c2bb6c9539e3a91a6f93c..632ae3a7763f9324bc4c142ba4c7e12a8ca5b276 100644 (file)
@@ -1028,6 +1028,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;
index f4bb31c6b74ed1093a0685db93dcf2fcf9cfe5f1..e96c0c22a6a68a18f4def9fde6ba22912286f86e 100644 (file)
@@ -7351,6 +7351,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_OPMODE_NOTIF,
+                          params->vht_opmode);
+       }
+
        wpa_printf(MSG_DEBUG, "  * capability=0x%x", params->capability);
        NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);