]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Add support for STA opmode change events
authorTamizh chelvam <tamizhr@codeaurora.org>
Fri, 9 Mar 2018 12:49:08 +0000 (18:19 +0530)
committerJouni Malinen <j@w1.fi>
Mon, 19 Mar 2018 17:57:25 +0000 (19:57 +0200)
The nl80211 driver can report STA_OPMODE notification event as soon as
it receives an HT/VHT Action frame about modification of station's SMPS
mode/bandwidth/RX NSS. Add support to parse such events.

Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
src/drivers/driver.h
src/drivers/driver_common.c
src/drivers/driver_nl80211_event.c

index 01204bed2bcfcd4742edf8572fec01d280f518df..338a56eebf6ba23d81f6fb73d6e7c3b1ad42e342 100644 (file)
@@ -1877,6 +1877,17 @@ enum wnm_oper {
        WNM_SLEEP_TFS_IE_DEL        /* AP delete the TFS IE */
 };
 
+/* enum smps_mode - SMPS mode definitions */
+enum smps_mode {
+       SMPS_AUTOMATIC,
+       SMPS_OFF,
+       SMPS_DYNAMIC,
+       SMPS_STATIC,
+
+       /* Keep last */
+       SMPS_INVALID,
+};
+
 /* enum chan_width - Channel width definitions */
 enum chan_width {
        CHAN_WIDTH_20_NOHT,
@@ -4568,6 +4579,12 @@ enum wpa_event_type {
         * indicates the completion of IEEE 802.11 association.
         */
        EVENT_PORT_AUTHORIZED,
+
+       /**
+        * EVENT_STATION_OPMODE_CHANGED - Notify STA's HT/VHT operation mode
+        * change event.
+        */
+       EVENT_STATION_OPMODE_CHANGED,
 };
 
 
@@ -5373,6 +5390,22 @@ union wpa_event_data {
 
        /* For EVENT_EXTERNAL_AUTH */
        struct external_auth external_auth;
+
+       /**
+        * struct sta_opmode - Station's operation mode change event
+        * @addr: The station MAC address
+        * @smps_mode: SMPS mode of the station
+        * @chan_width: Channel width of the station
+        * @rx_nss: RX_NSS of the station
+        *
+        * This is used as data with EVENT_STATION_OPMODE_CHANGED.
+        */
+       struct sta_opmode {
+               const u8 *addr;
+               enum smps_mode smps_mode;
+               enum chan_width chan_width;
+               u8 rx_nss;
+       } sta_opmode;
 };
 
 /**
index e4806ad5e2807e94e643f59945d733557c089250..9de9693f5e086fa89e0ba366ddb8ceed52a4c19f 100644 (file)
@@ -84,6 +84,7 @@ const char * event_to_string(enum wpa_event_type event)
        E2S(DFS_PRE_CAC_EXPIRED);
        E2S(EXTERNAL_AUTH);
        E2S(PORT_AUTHORIZED);
+       E2S(STATION_OPMODE_CHANGED);
        }
 
        return "UNKNOWN";
index dd9b001e4fd6422fabe5224718ff37d200f20a49..fd9eac97029ed1955322e3ae00068fecd0aaaba8 100644 (file)
@@ -132,6 +132,7 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
        C2S(NL80211_CMD_ADD_TX_TS)
        C2S(NL80211_CMD_DEL_TX_TS)
        C2S(NL80211_CMD_EXTERNAL_AUTH)
+       C2S(NL80211_CMD_STA_OPMODE_CHANGED)
        default:
                return "NL80211_CMD_UNKNOWN";
        }
@@ -2246,6 +2247,76 @@ static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv,
+                                           struct nlattr **tb)
+{
+       union wpa_event_data ed;
+       u8 smps_mode, max_bw;
+
+       if (!tb[NL80211_ATTR_MAC] ||
+           (!tb[NL80211_ATTR_CHANNEL_WIDTH] &&
+            !tb[NL80211_ATTR_SMPS_MODE] &&
+            !tb[NL80211_ATTR_NSS]))
+               return;
+
+       ed.sta_opmode.smps_mode = SMPS_INVALID;
+       ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
+       ed.sta_opmode.rx_nss = 0xff;
+       ed.sta_opmode.addr = nla_data(tb[NL80211_ATTR_MAC]);
+
+       if (tb[NL80211_ATTR_SMPS_MODE]) {
+               smps_mode = nla_get_u32(tb[NL80211_ATTR_SMPS_MODE]);
+               switch (smps_mode) {
+               case NL80211_SMPS_OFF:
+                       ed.sta_opmode.smps_mode = SMPS_OFF;
+                       break;
+               case NL80211_SMPS_STATIC:
+                       ed.sta_opmode.smps_mode = SMPS_STATIC;
+                       break;
+               case NL80211_SMPS_DYNAMIC:
+                       ed.sta_opmode.smps_mode = SMPS_DYNAMIC;
+                       break;
+               default:
+                       ed.sta_opmode.smps_mode = SMPS_INVALID;
+                       break;
+               }
+       }
+
+       if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+               max_bw = nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]);
+               switch (max_bw) {
+               case NL80211_CHAN_WIDTH_20_NOHT:
+                       ed.sta_opmode.chan_width = CHAN_WIDTH_20_NOHT;
+                       break;
+               case NL80211_CHAN_WIDTH_20:
+                       ed.sta_opmode.chan_width = CHAN_WIDTH_20;
+                       break;
+               case NL80211_CHAN_WIDTH_40:
+                       ed.sta_opmode.chan_width = CHAN_WIDTH_40;
+                       break;
+               case NL80211_CHAN_WIDTH_80:
+                       ed.sta_opmode.chan_width = CHAN_WIDTH_80;
+                       break;
+               case NL80211_CHAN_WIDTH_80P80:
+                       ed.sta_opmode.chan_width = CHAN_WIDTH_80P80;
+                       break;
+               case NL80211_CHAN_WIDTH_160:
+                       ed.sta_opmode.chan_width = CHAN_WIDTH_160;
+                       break;
+               default:
+                       ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
+                       break;
+
+               }
+       }
+
+       if (tb[NL80211_ATTR_NSS])
+               ed.sta_opmode.rx_nss = nla_get_u8(tb[NL80211_ATTR_NSS]);
+
+       wpa_supplicant_event(drv->ctx, EVENT_STATION_OPMODE_CHANGED, &ed);
+}
+
+
 static void do_process_drv_event(struct i802_bss *bss, int cmd,
                                 struct nlattr **tb)
 {
@@ -2447,6 +2518,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        case NL80211_CMD_PORT_AUTHORIZED:
                nl80211_port_authorized(drv, tb);
                break;
+       case NL80211_CMD_STA_OPMODE_CHANGED:
+               nl80211_sta_opmode_change_event(drv, tb);
+               break;
        default:
                wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
                        "(cmd=%d)", cmd);