]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WNM: Additional BSS Transition Management capability
authorJouni Malinen <j@w1.fi>
Sat, 22 Dec 2012 18:27:30 +0000 (20:27 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 22 Dec 2012 18:27:30 +0000 (20:27 +0200)
Add some more functionality for BSS Transition Management:
- advertise support for BSS Transition Management in extended
  capabilities element
- add hostapd.conf parameter bss_transition=1 for enabling support
  for BSS Transition Management
- add "hostapd_cli disassoc_imminent <STA> <num TBTTs>" for sending
  disassociation imminent notifications for testing purposes
- wpa_supplicant: trigger a new scan to find another BSS if the
  current AP indicates disassociation imminent (TODO: the old AP needs
  to be marked to use lower priority to avoid re-selecting it)

Signed-hostap: Jouni Malinen <j@w1.fi>

hostapd/config_file.c
hostapd/ctrl_iface.c
hostapd/hostapd.conf
hostapd/hostapd_cli.c
src/ap/ap_config.h
src/ap/ieee802_11_shared.c
src/ap/wnm_ap.c
src/common/ieee802_11_defs.h
wpa_supplicant/wnm_sta.c
wpa_supplicant/wpa_supplicant.c

index 4c4d51b482a655ac3b26827c5774c318b0393488..2ba7cc1272599fe338f678f954ebc6e9db84199a 100644 (file)
@@ -2721,8 +2721,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        bss->time_zone = os_strdup(pos);
                        if (bss->time_zone == NULL)
                                errors++;
+#ifdef CONFIG_WNM
                } else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
                        bss->wnm_sleep_mode = atoi(pos);
+               } else if (os_strcmp(buf, "bss_transition") == 0) {
+                       bss->bss_transition = atoi(pos);
+#endif /* CONFIG_WNM */
 #ifdef CONFIG_INTERWORKING
                } else if (os_strcmp(buf, "interworking") == 0) {
                        bss->interworking = atoi(pos);
index bd16b17926bb72b7a8d4c0585154c2c698b23d5c..3c9071caa3aff2d2027d59fa53f06fc376068ce1 100644 (file)
@@ -436,6 +436,50 @@ static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
 #endif /* CONFIG_WPS */
 
 
+#ifdef CONFIG_WNM
+
+static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
+                                               const char *cmd)
+{
+       u8 addr[ETH_ALEN];
+       u8 buf[1000], *pos;
+       struct ieee80211_mgmt *mgmt;
+       int disassoc_timer;
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+       if (cmd[17] != ' ')
+               return -1;
+       disassoc_timer = atoi(cmd + 17);
+
+       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_DISASSOC_IMMINENT;
+       mgmt->u.action.u.bss_tm_req.disassoc_timer =
+               host_to_le16(disassoc_timer);
+       mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+       pos = mgmt->u.action.u.bss_tm_req.variable;
+
+       if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+               wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+                          "Management Request frame");
+               return -1;
+       }
+
+       return 0;
+}
+
+
 static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
                                           const char *cmd)
 {
@@ -486,6 +530,8 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
        return 0;
 }
 
+#endif /* CONFIG_WNM */
+
 
 static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
                                         char *buf, size_t buflen)
@@ -906,9 +952,14 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                        hapd, buf + 14, reply, reply_size);
 #endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_WNM
+       } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
+               if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
+                       reply_len = -1;
        } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
                if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
                        reply_len = -1;
+#endif /* CONFIG_WNM */
        } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
                reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
                                                          reply_size);
index 5a3cdd3dfdfa50985b9f3375a0329fdabb13687d..75b1941653508814c59cadcaf4d2329ba7ee7e15 100644 (file)
@@ -1310,6 +1310,11 @@ own_ip_addr=127.0.0.1
 # 1 = enabled (allow stations to use WNM-Sleep Mode)
 #wnm_sleep_mode=1
 
+# BSS Transition Management
+# 0 = disabled (default)
+# 1 = enabled
+#bss_transition=1
+
 ##### IEEE 802.11u-2011 #######################################################
 
 # Enable Interworking service
index 633c13d2769af87507b45c250d201825bc604774..e8e1bb24a1c583103a6cc121b0f660178d5e843a 100644 (file)
@@ -539,6 +539,26 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
 #endif /* CONFIG_WPS */
 
 
+static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
+                                            char *argv[])
+{
+       char buf[300];
+       int res;
+
+       if (argc < 2) {
+               printf("Invalid 'disassoc_imminent' command - two arguments "
+                      "(STA addr and Disassociation Timer) are needed\n");
+               return -1;
+       }
+
+       res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %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_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
                                        char *argv[])
 {
@@ -775,6 +795,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 */
+       { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
        { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
        { "get_config", hostapd_cli_cmd_get_config },
        { "help", hostapd_cli_cmd_help },
index bc04307ddd7b63465d37026edb2e544b8ff581fb..a1d2b048b513104dc79066ef07d93011b48b3ea2 100644 (file)
@@ -392,6 +392,7 @@ struct hostapd_bss_config {
        int time_advertisement;
        char *time_zone;
        int wnm_sleep_mode;
+       int bss_transition;
 
        /* IEEE 802.11u - Interworking */
        int interworking;
index 7d87379de1ae78c3ca7be75acb7d8a419620a49f..76f78a7dbd9c1fde8f1eac7bfa2acadb42aef97d 100644 (file)
@@ -192,6 +192,8 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
        *pos = 0x00;
        if (hapd->conf->wnm_sleep_mode)
                *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+       if (hapd->conf->bss_transition)
+               *pos |= 0x08; /* Bit 19 - BSS Transition */
        pos++;
 
        if (len < 4)
index 13961e06134b43e37acf5e7314f79d30ec13d4df..54a6b857d7845a94bd31c38b086d1a1affded890 100644 (file)
@@ -250,6 +250,15 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
                return -1;
 
        switch (action->data[0]) {
+       case WNM_BSS_TRANS_MGMT_QUERY:
+               wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query");
+               /* TODO */
+               return -1;
+       case WNM_BSS_TRANS_MGMT_RESP:
+               wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
+                          "Response");
+               /* TODO */
+               return -1;
        case WNM_SLEEP_MODE_REQ:
                ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
                                           action->len - 1);
index 1a9ad1a7d2cfd40aa0a9d5703ea6d39d084bb51f..e873545f6fa183838a01a0970ed7398b52741d19 100644 (file)
@@ -538,6 +538,16 @@ struct ieee80211_mgmt {
                                         * Entries */
                                        u8 variable[0];
                                } STRUCT_PACKED bss_tm_req;
+                               struct {
+                                       u8 action; /* 8 */
+                                       u8 dialog_token;
+                                       u8 status_code;
+                                       u8 bss_termination_delay;
+                                       /* Target BSSID (optional),
+                                        * BSS Transition Candidate List
+                                        * Entries (optional) */
+                                       u8 variable[0];
+                               } STRUCT_PACKED bss_tm_resp;
                        } u;
                } STRUCT_PACKED action;
        } u;
index 45c0aa84e3b94502df37afc1855a578562af1b75..4d9e4533e64ef2738fe91aa6c4a6590d662e8016 100644 (file)
@@ -13,6 +13,7 @@
 #include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
+#include "scan.h"
 
 #define MAX_TFS_IE_LEN  1024
 
@@ -293,11 +294,104 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
+                                             u8 dialog_token, u8 status,
+                                             u8 delay, const u8 *target_bssid)
+{
+       u8 buf[1000], *pos;
+       struct ieee80211_mgmt *mgmt;
+       size_t len;
+
+       wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
+                  "to " MACSTR " dialog_token=%u status=%u delay=%d",
+                  MAC2STR(wpa_s->bssid), dialog_token, status, delay);
+
+       mgmt = (struct ieee80211_mgmt *) buf;
+       os_memset(&buf, 0, sizeof(buf));
+       os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+       os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+       os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                          WLAN_FC_STYPE_ACTION);
+       mgmt->u.action.category = WLAN_ACTION_WNM;
+       mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP;
+       mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token;
+       mgmt->u.action.u.bss_tm_resp.status_code = status;
+       mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay;
+       pos = mgmt->u.action.u.bss_tm_resp.variable;
+       if (target_bssid) {
+               os_memcpy(pos, target_bssid, ETH_ALEN);
+               pos += ETH_ALEN;
+       }
+
+       len = pos - (u8 *) &mgmt->u.action.category;
+
+       wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+                           wpa_s->own_addr, wpa_s->bssid,
+                           &mgmt->u.action.category, len, 0);
+}
+
+
+static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
+                                            const u8 *pos, const u8 *end,
+                                            int reply)
+{
+       u8 dialog_token;
+       u8 mode;
+       u16 disassoc_timer;
+
+       if (pos + 5 > end)
+               return;
+
+       dialog_token = pos[0];
+       mode = pos[1];
+       disassoc_timer = WPA_GET_LE16(pos + 2);
+
+       wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
+                  "dialog_token=%u request_mode=0x%x "
+                  "disassoc_timer=%u validity_interval=%u",
+                  dialog_token, mode, disassoc_timer, pos[4]);
+       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)");
+                       return;
+               }
+               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);
+       }
+
+       if (mode & 0x04) {
+               wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
+                       "Disassociation Timer %u", disassoc_timer);
+               if (disassoc_timer && !wpa_s->scanning) {
+                       /* TODO: mark current BSS less preferred for
+                        * selection */
+                       wpa_printf(MSG_DEBUG, "Trying to find another BSS");
+                       wpa_supplicant_req_scan(wpa_s, 0, 0);
+               }
+       }
+
+       if (reply) {
+               /* TODO: add support for reporting Accept */
+               wnm_send_bss_transition_mgmt_resp(wpa_s, dialog_token,
+                                                 1 /* Reject - unspecified */,
+                                                 0, NULL);
+       }
+}
+
+
 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
                              struct rx_action *action)
 {
        const u8 *pos, *end;
-       u8 act, mode;
+       u8 act;
 
        if (action->data == NULL || action->len == 0)
                return;
@@ -308,32 +402,17 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
 
        wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
                   act, MAC2STR(action->sa));
+       if (wpa_s->wpa_state < WPA_ASSOCIATED ||
+           os_memcmp(action->sa, wpa_s->bssid, ETH_ALEN) != 0) {
+               wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
+                          "frame");
+               return;
+       }
 
        switch (act) {
        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);
-               }
+               ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
+                                                !(action->da[0] & 0x01));
                break;
        case WNM_SLEEP_MODE_RESP:
                ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
index 3e4304494eb4de1a2616c1b83634ba2af9af856e..d76f958e362fa4f2ef805bb5fe9781af61d5f229 100644 (file)
@@ -1242,6 +1242,7 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
 
 #ifdef CONFIG_WNM
        ext_capab |= BIT(17); /* WNM-Sleep Mode */
+       ext_capab |= BIT(19); /* BSS Transition */
 #endif /* CONFIG_WNM */
 
        if (!ext_capab)