|
@@ -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);
|