nl80211: Add preliminary implementation of FT Action send
authorJouni Malinen <j@w1.fi>
Sun, 7 Mar 2010 20:47:39 +0000 (22:47 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 7 Mar 2010 20:47:39 +0000 (22:47 +0200)
This is a step in adding FT support with nl80211-based drivers.
driver_nl80211.c is now registering to handle the FT Action frames
and is able to transmit FT Request frame. Received FT Action frames
are not yet indicated as driver events.

src/drivers/driver_nl80211.c

index edbe69b..d4679b9 100644 (file)
@@ -1338,6 +1338,14 @@ static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
                /* Public Action frames */
                return nl80211_register_action_frame(drv, (u8 *) "\x04", 1);
        }
+
+       /* FT Action frames */
+       if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0)
+               return -1;
+       else
+               drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
+                       WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+
        return 0;
 }
 
@@ -1369,8 +1377,15 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
                               1, IF_OPER_DORMANT);
 #endif /* HOSTAPD */
 
-       if (nl80211_register_action_frames(drv) < 0)
-               return -1;
+       if (nl80211_register_action_frames(drv) < 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
+                          "frame processing - ignore for now");
+               /*
+                * Older kernel versions did not support this, so ignore the
+                * error for now. Some functionality may not be available
+                * because of this.
+                */
+       }
 
        return 0;
 }
@@ -5083,6 +5098,56 @@ static void wpa_driver_nl80211_resume(void *priv)
 }
 
 
+static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
+                                 const u8 *ies, size_t ies_len)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       int ret;
+       u8 *data, *pos;
+       size_t data_len;
+       u8 own_addr[ETH_ALEN];
+
+       if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0)
+               return -1;
+
+       if (action != 1) {
+               wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
+                          "action %d", action);
+               return -1;
+       }
+
+       /*
+        * Action frame payload:
+        * Category[1] = 6 (Fast BSS Transition)
+        * Action[1] = 1 (Fast BSS Transition Request)
+        * STA Address
+        * Target AP Address
+        * FT IEs
+        */
+
+       data_len = ies_len;
+       data = os_malloc(2 + 2 * ETH_ALEN + data_len);
+       if (data == NULL)
+               return -1;
+       pos = data;
+       *pos++ = 0x06; /* FT Action category */
+       *pos++ = action;
+       os_memcpy(pos, own_addr, ETH_ALEN);
+       pos += ETH_ALEN;
+       os_memcpy(pos, target_ap, ETH_ALEN);
+       pos += ETH_ALEN;
+       os_memcpy(pos, ies, ies_len);
+
+       ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, drv->bssid,
+                                            own_addr, drv->bssid,
+                                            data, data_len);
+       os_free(data);
+
+       return ret;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -5141,4 +5206,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
        .deinit_ap = wpa_driver_nl80211_deinit_ap,
        .resume = wpa_driver_nl80211_resume,
+       .send_ft_action = nl80211_send_ft_action,
 };