]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WNM: Add BSS Transition Management Request for ESS Disassoc Imminent
authorJouni Malinen <jouni@qca.qualcomm.com>
Fri, 7 Oct 2011 10:33:04 +0000 (13:33 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 16 Oct 2011 20:55:34 +0000 (23:55 +0300)
"hostapd_cli ess_disassoc (STA addr) (URL)" can now be used to send
an ESS Dissassociation Imminent notification to the STA. This event
is shown in wpa_supplicant ctrl_iface monitors (e.g., wpa_cli):
"WNM: ESS Disassociation Imminent - session_info_url=http://example.com/session/"

hostapd/ctrl_iface.c
hostapd/hostapd_cli.c
src/common/ieee802_11_defs.h
src/drivers/driver_nl80211.c
wpa_supplicant/events.c

index 195b8a73c737ae7a1acf2f345fc302965de52c19..4a6e0112934d26e8a8ee14e3d42c11c5ff294130 100644 (file)
@@ -526,6 +526,57 @@ static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
 #endif /* CONFIG_WPS */
 
 
+static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
+                                          const char *cmd)
+{
+       u8 addr[ETH_ALEN];
+       const char *url;
+       u8 buf[1000], *pos;
+       struct ieee80211_mgmt *mgmt;
+       size_t url_len;
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+       url = cmd + 17;
+       if (*url != ' ')
+               return -1;
+       url++;
+       url_len = os_strlen(url);
+       if (url_len > 255)
+               return -1;
+
+       os_memset(buf, 0, sizeof(buf));
+       mgmt = (struct ieee80211_mgmt *) buf;
+       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                          WLAN_FC_STYPE_ACTION);
+       os_memcpy(mgmt->da, addr, ETH_ALEN);
+       os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+       os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+       mgmt->u.action.category = WLAN_ACTION_WNM;
+       mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+       mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+       mgmt->u.action.u.bss_tm_req.req_mode =
+               WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+       mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
+       mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+       pos = mgmt->u.action.u.bss_tm_req.variable;
+
+       /* Session Information URL */
+       *pos++ = url_len;
+       os_memcpy(pos, url, url_len);
+       pos += url_len;
+
+       if (hostapd_drv_send_mlme(hapd, buf, pos - buf) < 0) {
+               wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+                          "Management Request frame");
+               return -1;
+       }
+
+       return 0;
+}
+
+
 static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
                                         char *buf, size_t buflen)
 {
@@ -879,6 +930,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
                        reply_len = -1;
 #endif /* CONFIG_WPS */
+       } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
+               if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
+                       reply_len = -1;
        } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
                reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
                                                          reply_size);
index 007126103da1c46f9e50199ef8005496aa2c9ddb..527860c3962886d01bbdff9582f7aeef9b128640 100644 (file)
@@ -515,6 +515,26 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
 #endif /* CONFIG_WPS */
 
 
+static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       char buf[300];
+       int res;
+
+       if (argc < 2) {
+               printf("Invalid 'ess_disassoc' command - two arguments (STA "
+                      "addr and URL) are needed\n");
+               return -1;
+       }
+
+       res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
+                         argv[0], argv[1]);
+       if (res < 0 || res >= (int) sizeof(buf))
+               return -1;
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
                                      char *argv[])
 {
@@ -728,6 +748,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
        { "wps_config", hostapd_cli_cmd_wps_config },
 #endif /* CONFIG_WPS */
+       { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
        { "get_config", hostapd_cli_cmd_get_config },
        { "help", hostapd_cli_cmd_help },
        { "interface", hostapd_cli_cmd_interface },
index 3485bd4976f211e7f74f98dc7645da5894216665..07736b3105c446d9d7a10cc6bad0301cb904cc1a 100644 (file)
 #define WLAN_ACTION_FT 6
 #define WLAN_ACTION_HT 7
 #define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_WNM 10
+#define WLAN_ACTION_UNPROTECTED_WNM 11
 #define WLAN_ACTION_TDLS 12
 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
 #define WLAN_ACTION_VENDOR_SPECIFIC 127
@@ -455,6 +457,18 @@ struct ieee80211_mgmt {
                                        /* Vendor-specific content */
                                        u8 variable[0];
                                } STRUCT_PACKED vs_public_action;
+                               struct {
+                                       u8 action; /* 7 */
+                                       u8 dialog_token;
+                                       u8 req_mode;
+                                       le16 disassoc_timer;
+                                       u8 validity_interval;
+                                       /* BSS Termination Duration (optional),
+                                        * Session Information URL (optional),
+                                        * BSS Transition Candidate List
+                                        * Entries */
+                                       u8 variable[0];
+                               } STRUCT_PACKED bss_tm_req;
                        } u;
                } STRUCT_PACKED action;
        } u;
@@ -816,4 +830,44 @@ enum p2p_sd_status {
 #define WLAN_AKM_SUITE_8021X           0x000FAC01
 #define WLAN_AKM_SUITE_PSK             0x000FAC02
 
+
+/* IEEE 802.11v - WNM Action field values */
+enum wnm_action {
+       WNM_EVENT_REQ = 0,
+       WNM_EVENT_REPORT = 1,
+       WNM_DIAGNOSTIC_REQ = 2,
+       WNM_DIAGNOSTIC_REPORT = 3,
+       WNM_LOCATION_CFG_REQ = 4,
+       WNM_LOCATION_CFG_RESP = 5,
+       WNM_BSS_TRANS_MGMT_QUERY = 6,
+       WNM_BSS_TRANS_MGMT_REQ = 7,
+       WNM_BSS_TRANS_MGMT_RESP = 8,
+       WNM_FMS_REQ = 9,
+       WNM_FMS_RESP = 10,
+       WNM_COLLOCATED_INTERFERENCE_REQ = 11,
+       WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
+       WNM_TFS_REQ = 13,
+       WNM_TFS_RESP = 14,
+       WNM_TFS_NOTIFY = 15,
+       WNM_SLEEP_MODE_REQ = 16,
+       WNM_SLEEP_MODE_RESP = 17,
+       WNM_TIM_BROADCAST_REQ = 18,
+       WNM_TIM_BROADCAST_RESP = 19,
+       WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
+       WNM_CHANNEL_USAGE_REQ = 21,
+       WNM_CHANNEL_USAGE_RESP = 22,
+       WNM_DMS_REQ = 23,
+       WNM_DMS_RESP = 24,
+       WNM_TIMING_MEASUREMENT_REQ = 25,
+       WNM_NOTIFICATION_REQ = 26,
+       WNM_NOTIFICATION_RESP = 27
+};
+
+/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
+#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
+#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
+#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
+#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
+#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+
 #endif /* IEEE802_11_DEFS_H */
index f754a46e79efb041c22d76f8bde51429e2dfcbd2..bb2b7974d0c3bfca24a22ca5972541791e8bc421 100644 (file)
@@ -2312,6 +2312,10 @@ static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
                drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
                        WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
 
+       /* WNM - BSS Transition Management Request */
+       if (nl80211_register_action_frame(drv, (u8 *) "\x0a\x07", 2) < 0)
+               return -1;
+
        return 0;
 }
 
index b00e308bf17db8dee763d864f2c73fcb33a91850..43b22ab54396e9d9bc1065cb64a45910c866f611 100644 (file)
@@ -1774,6 +1774,50 @@ static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wnm_action_rx(struct wpa_supplicant *wpa_s, struct rx_action *rx)
+{
+       u8 action, mode;
+       const u8 *pos, *end;
+
+       if (rx->data == NULL || rx->len == 0)
+               return;
+
+       pos = rx->data;
+       end = pos + rx->len;
+       action = *pos++;
+
+       wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
+                  action, MAC2STR(rx->sa));
+       switch (action) {
+       case WNM_BSS_TRANS_MGMT_REQ:
+               if (pos + 5 > end)
+                       break;
+               wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
+                          "Request: dialog_token=%u request_mode=0x%x "
+                          "disassoc_timer=%u validity_interval=%u",
+                          pos[0], pos[1], WPA_GET_LE16(pos + 2), pos[4]);
+               mode = pos[1];
+               pos += 5;
+               if (mode & 0x08)
+                       pos += 12; /* BSS Termination Duration */
+               if (mode & 0x10) {
+                       char url[256];
+                       if (pos + 1 > end || pos + 1 + pos[0] > end) {
+                               wpa_printf(MSG_DEBUG, "WNM: Invalid BSS "
+                                          "Transition Management Request "
+                                          "(URL)");
+                               break;
+                       }
+                       os_memcpy(url, pos + 1, pos[0]);
+                       url[pos[0]] = '\0';
+                       wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation "
+                               "Imminent - session_info_url=%s", url);
+               }
+               break;
+       }
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                          union wpa_event_data *data)
 {
@@ -2048,6 +2092,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                 data->rx_action.freq) == 0)
                        break;
 #endif /* CONFIG_GAS */
+               if (data->rx_action.category == WLAN_ACTION_WNM) {
+                       wnm_action_rx(wpa_s, &data->rx_action);
+                       break;
+               }
 #ifdef CONFIG_P2P
                wpas_p2p_rx_action(wpa_s, data->rx_action.da,
                                   data->rx_action.sa,