]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FT: Add RIC Request generation and validation (but not processing)
authorJouni Malinen <jouni.malinen@atheros.com>
Mon, 9 Mar 2009 18:45:17 +0000 (20:45 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 9 Mar 2009 18:45:17 +0000 (20:45 +0200)
This adds first part of FT resource request as part of Reassocition
Request frame (i.e., FT Protocol, not FT Resource Request Protocol).
wpa_supplicant can generate a test resource request when driver_test.c
is used with internal MLME code and hostapd can verify the FTIE MIC
properly with the included RIC Request.

The actual RIC Request IEs are not processed yet and hostapd does not
yet reply with RIC Response (nor would wpa_supplicant be able to
validate the FTIE MIC for a frame with RIC Response).

hostapd/wpa_ft.c
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
src/drivers/driver.h
src/rsn_supp/wpa.h
src/rsn_supp/wpa_ft.c
src/utils/wpabuf.h
wpa_supplicant/events.c
wpa_supplicant/mlme.c

index 9cf6713ffd659773eba85a9700ae47529834092d..337c7ebee2b2ab7a4958b47878f0918119570b8b 100644 (file)
@@ -571,6 +571,8 @@ struct wpa_ft_ies {
        const u8 *rsn;
        size_t rsn_len;
        const u8 *rsn_pmkid;
+       const u8 *ric;
+       size_t ric_len;
 };
 
 
@@ -623,6 +625,8 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
        const u8 *end, *pos;
        struct wpa_ie_data data;
        int ret;
+       const struct rsn_ftie *ftie;
+       int prot_ie_count = 0;
 
        os_memset(parse, 0, sizeof(*parse));
        if (ies == NULL)
@@ -651,14 +655,60 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
                        parse->mdie_len = pos[1];
                        break;
                case WLAN_EID_FAST_BSS_TRANSITION:
+                       if (pos[1] < sizeof(*ftie))
+                               return -1;
+                       ftie = (const struct rsn_ftie *) (pos + 2);
+                       prot_ie_count = ftie->mic_control[1];
                        if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
                                return -1;
                        break;
+               case WLAN_EID_RIC_DATA:
+                       if (parse->ric == NULL)
+                               parse->ric = pos;
                }
 
                pos += 2 + pos[1];
        }
 
+       if (prot_ie_count == 0)
+               return 0; /* no MIC */
+
+       /*
+        * Check that the protected IE count matches with IEs included in the
+        * frame.
+        */
+       if (parse->rsn)
+               prot_ie_count--;
+       if (parse->mdie)
+               prot_ie_count--;
+       if (parse->ftie)
+               prot_ie_count--;
+       if (prot_ie_count < 0) {
+               wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
+                          "the protected IE count");
+               return -1;
+       }
+
+       if (prot_ie_count == 0 && parse->ric) {
+               wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
+                          "included in protected IE count");
+               return -1;
+       }
+
+       /* Determine the end of the RIC IE(s) */
+       pos = parse->ric;
+       while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
+              prot_ie_count) {
+               prot_ie_count--;
+               pos += 2 + pos[1];
+       }
+       parse->ric_len = pos - parse->ric;
+       if (prot_ie_count) {
+               wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
+                          "frame", (int) prot_ie_count);
+               return -1;
+       }
+
        return 0;
 }
 
@@ -937,20 +987,11 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
                return WLAN_STATUS_INVALID_FTIE;
        }
 
-       /*
-        * Assume that MDIE, FTIE, and RSN IE are protected and that there is
-        * no RIC, so total of 3 protected IEs.
-        */
-       if (ftie->mic_control[1] != 3) {
-               wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in FTIE (%d)",
-                          ftie->mic_control[1]);
-               return WLAN_STATUS_INVALID_FTIE;
-       }
-
        if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
                       parse.mdie - 2, parse.mdie_len + 2,
                       parse.ftie - 2, parse.ftie_len + 2,
-                      parse.rsn - 2, parse.rsn_len + 2, NULL, 0,
+                      parse.rsn - 2, parse.rsn_len + 2,
+                      parse.ric, parse.ric_len,
                       mic) < 0) {
                wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
index 242f933b03fd4d9c1ccd131b7cf81ce85156a78a..6910b4e63d8711b79d49925032d85e0ea4694d27 100644 (file)
@@ -257,3 +257,25 @@ ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
 
        return unknown ? ParseUnknown : ParseOK;
 }
+
+
+int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
+{
+       int count = 0;
+       const u8 *pos, *end;
+
+       if (ies == NULL)
+               return 0;
+
+       pos = ies;
+       end = ies + ies_len;
+
+       while (pos + 2 <= end) {
+               if (pos + 2 + pos[1] > end)
+                       break;
+               count++;
+               pos += 2 + pos[1];
+       }
+
+       return count;
+}
index b7e497b6cc6884c9ec90b998553efd4530fe79d5..14599cb4fc41bc47bd88a1a3cb54648135226568 100644 (file)
@@ -70,5 +70,6 @@ typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
 ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
                                struct ieee802_11_elems *elems,
                                int show_errors);
+int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
 
 #endif /* IEEE802_11_COMMON_H */
index 342d032212d9aa971a86152b93a69fc8c6f793e7..39f100018dfee0f3fb0e91cf80b41137faaf896d 100644 (file)
@@ -1342,6 +1342,10 @@ union wpa_event_data {
                size_t ies_len;
                int ft_action;
                u8 target_ap[ETH_ALEN];
+               /** Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request */
+               const u8 *ric_ies;
+               /** Length of ric_ies buffer in octets */
+               size_t ric_ies_len;
        } ft_ies;
 
        /**
index f97d9c5f5083b37b846134d210f785bae073c2e0..29a80afeb2e94b1010ccae7799a6c34f1c27fa50 100644 (file)
@@ -284,7 +284,8 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *mobility_domain,
                         const u8 *r1kh_id);
 int wpa_ft_prepare_auth_request(struct wpa_sm *sm);
 int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
-                           int ft_action, const u8 *target_ap);
+                           int ft_action, const u8 *target_ap,
+                           const u8 *ric_ies, size_t ric_ies_len);
 int wpa_ft_is_completed(struct wpa_sm *sm);
 int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
                                 size_t ies_len, const u8 *src_addr);
index c89b89a772dfbff1abaf76cdb2eef6543d3ebe20..014261c78236dd2599a3fadbd95adde91029ca26 100644 (file)
@@ -20,6 +20,7 @@
 #include "wpa_ie.h"
 #include "aes_wrap.h"
 #include "ieee802_11_defs.h"
+#include "ieee802_11_common.h"
 
 #ifdef CONFIG_IEEE80211R
 
@@ -105,20 +106,23 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *mobility_domain,
 
 
 /**
- * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth Request
+ * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
  * @len: Buffer for returning the length of the IEs
  * @anonce: ANonce or %NULL if not yet available
  * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List
  * @kck: 128-bit KCK for MIC or %NULL if no MIC is used
  * @target_ap: Target AP address
+ * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
+ * @ric_ies_len: Length of ric_ies buffer in octets
  * Returns: Pointer to buffer with IEs or %NULL on failure
  *
  * Caller is responsible for freeing the returned buffer with os_free();
  */
 static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
                               const u8 *anonce, const u8 *pmk_name,
-                              const u8 *kck, const u8 *target_ap)
+                              const u8 *kck, const u8 *target_ap,
+                              const u8 *ric_ies, size_t ric_ies_len)
 {
        size_t buf_len;
        u8 *buf, *pos, *ftie_len, *ftie_pos;
@@ -130,13 +134,13 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
        sm->ft_completed = 0;
 
        buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
-               2 + sm->r0kh_id_len + 100;
+               2 + sm->r0kh_id_len + ric_ies_len + 100;
        buf = os_zalloc(buf_len);
        if (buf == NULL)
                return NULL;
        pos = buf;
 
-       /* RSNIE[PMKR0Name] */
+       /* RSNIE[PMKR0Name/PMKR1Name] */
        rsnie = (struct rsn_ie_hdr *) pos;
        rsnie->elem_id = WLAN_EID_RSN;
        WPA_PUT_LE16(rsnie->version, RSN_VERSION);
@@ -241,6 +245,12 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
        pos += sm->r0kh_id_len;
        *ftie_len = pos - ftie_len - 1;
 
+       if (ric_ies) {
+               /* RIC Request */
+               os_memcpy(pos, ric_ies, ric_ies_len);
+               pos += ric_ies_len;
+       }
+
        if (kck) {
                /*
                 * IEEE Std 802.11r-2008, 11A.8.4
@@ -253,12 +263,14 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
                 * FTIE (with MIC field set to 0)
                 * RIC-Request (if present)
                 */
-               ftie->mic_control[1] = 3; /* Information element count */
+               /* Information element count */
+               ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
+                                                              ric_ies_len);
                if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
                               ((u8 *) mdie) - 2, 2 + sizeof(*mdie),
                               ftie_pos, 2 + *ftie_len,
-                              (u8 *) rsnie, 2 + rsnie->len, NULL, 0,
-                              ftie->mic) < 0) {
+                              (u8 *) rsnie, 2 + rsnie->len, ric_ies,
+                              ric_ies_len, ftie->mic) < 0) {
                        wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
                        os_free(buf);
                        return NULL;
@@ -440,7 +452,7 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm)
        }
 
        ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
-                                   NULL, sm->bssid);
+                                   NULL, sm->bssid, NULL, 0);
        if (ft_ies) {
                wpa_sm_update_ft_ies(sm, sm->mobility_domain,
                                     ft_ies, ft_ies_len);
@@ -452,7 +464,8 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm)
 
 
 int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
-                           int ft_action, const u8 *target_ap)
+                           int ft_action, const u8 *target_ap,
+                           const u8 *ric_ies, size_t ric_ies_len)
 {
        u8 *ft_ies;
        size_t ft_ies_len;
@@ -464,6 +477,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
        const u8 *bssid;
 
        wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
+       wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);
 
        if (ft_action) {
                if (!sm->over_the_ds_in_progress) {
@@ -553,7 +567,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
        wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
 
        ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
-                                   sm->pmk_r1_name, sm->ptk.kck, bssid);
+                                   sm->pmk_r1_name, sm->ptk.kck, bssid,
+                                   ric_ies, ric_ies_len);
        if (ft_ies) {
                wpa_sm_update_ft_ies(sm, sm->mobility_domain,
                                     ft_ies, ft_ies_len);
@@ -857,7 +872,7 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap)
        }
 
        ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
-                                   NULL, target_ap);
+                                   NULL, target_ap, NULL, 0);
        if (ft_ies) {
                sm->over_the_ds_in_progress = 1;
                os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
index bd8f09e94f84079c28344f0dac51f422da95261e..a150455a5a65bfd1c657f422f32ebfd4f87b1166 100644 (file)
@@ -111,6 +111,12 @@ static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
        *pos = data;
 }
 
+static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
+{
+       u8 *pos = wpabuf_put(buf, 2);
+       WPA_PUT_LE16(pos, data);
+}
+
 static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
 {
        u8 *pos = wpabuf_put(buf, 2);
index e6f3a4aedce044ee08b46a8da64fe3d92b6f4526..b47ea9d1d1badb68652e3588f834ffb7a4de5fc5 100644 (file)
@@ -1087,7 +1087,9 @@ wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
        if (wpa_ft_process_response(wpa_s->wpa, data->ft_ies.ies,
                                    data->ft_ies.ies_len,
                                    data->ft_ies.ft_action,
-                                   data->ft_ies.target_ap) < 0) {
+                                   data->ft_ies.target_ap,
+                                   data->ft_ies.ric_ies,
+                                   data->ft_ies.ric_ies_len) < 0) {
                /* TODO: prevent MLME/driver from trying to associate? */
        }
 }
index fd1fa5581d01eb2005fdc5d555ae25f62f29adc4..3576365d6572a2128dac45573c09ed04ad8cd746 100644 (file)
@@ -94,6 +94,7 @@ static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s);
 static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s);
 static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx);
 static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx);
+static void ieee80211_build_tspec(struct wpabuf *buf);
 
 
 static int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s,
@@ -876,12 +877,36 @@ static void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s,
        case WLAN_AUTH_FT:
        {
                union wpa_event_data data;
+               struct wpabuf *ric = NULL;
                os_memset(&data, 0, sizeof(data));
                data.ft_ies.ies = mgmt->u.auth.variable;
                data.ft_ies.ies_len = len -
                        (mgmt->u.auth.variable - (u8 *) mgmt);
                os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN);
+               if (os_strcmp(wpa_s->driver->name, "test") == 0 &&
+                   wpa_s->mlme.wmm_enabled) {
+                       ric = wpabuf_alloc(200);
+                       if (ric) {
+                               /* Build simple RIC-Request: RDIE | TSPEC */
+
+                               /* RIC Data (RDIE) */
+                               wpabuf_put_u8(ric, WLAN_EID_RIC_DATA);
+                               wpabuf_put_u8(ric, 4);
+                               wpabuf_put_u8(ric, 0); /* RDIE Identifier */
+                               wpabuf_put_u8(ric, 1); /* Resource Descriptor
+                                                       * Count */
+                               wpabuf_put_le16(ric, 0); /* Status Code */
+
+                               /* WMM TSPEC */
+                               ieee80211_build_tspec(ric);
+
+                               data.ft_ies.ric_ies = wpabuf_head(ric);
+                               data.ft_ies.ric_ies_len = wpabuf_len(ric);
+                       }
+               }
+
                wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
+               wpabuf_free(ric);
                ieee80211_auth_completed(wpa_s);
                break;
        }
@@ -1012,33 +1037,11 @@ static int ieee80211_ft_assoc_resp(struct wpa_supplicant *wpa_s,
 }
 
 
-static void ieee80211_tx_addts(struct wpa_supplicant *wpa_s)
+static void ieee80211_build_tspec(struct wpabuf *buf)
 {
-       struct wpabuf *buf;
-       struct ieee80211_mgmt *mgmt;
        struct wmm_tspec_element *tspec;
-       size_t alen;
        int tid, up;
 
-       wpa_printf(MSG_DEBUG, "MLME: Send ADDTS Request for Voice TSPEC");
-       mgmt = NULL;
-       alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
-
-       buf = wpabuf_alloc(alen + sizeof(*tspec));
-       if (buf == NULL)
-               return;
-
-       mgmt = wpabuf_put(buf, alen);
-       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_WMM;
-       mgmt->u.action.u.wmm_action.action_code = WMM_ACTION_CODE_ADDTS_REQ;
-       mgmt->u.action.u.wmm_action.dialog_token = 1;
-       mgmt->u.action.u.wmm_action.status_code = 0;
-
        tspec = wpabuf_put(buf, sizeof(*tspec));
        tspec->eid = WLAN_EID_VENDOR_SPECIFIC;
        tspec->length = sizeof(*tspec) - 2;
@@ -1059,6 +1062,35 @@ static void ieee80211_tx_addts(struct wpa_supplicant *wpa_s)
        tspec->mean_data_rate = host_to_le32(128000); /* bits per second */
        tspec->minimum_phy_rate = host_to_le32(6000000);
        tspec->surplus_bandwidth_allowance = host_to_le16(0x3000); /* 150% */
+}
+
+
+static void ieee80211_tx_addts(struct wpa_supplicant *wpa_s)
+{
+       struct wpabuf *buf;
+       struct ieee80211_mgmt *mgmt;
+       size_t alen;
+
+       wpa_printf(MSG_DEBUG, "MLME: Send ADDTS Request for Voice TSPEC");
+       mgmt = NULL;
+       alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
+
+       buf = wpabuf_alloc(alen + sizeof(struct wmm_tspec_element));
+       if (buf == NULL)
+               return;
+
+       mgmt = wpabuf_put(buf, alen);
+       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_WMM;
+       mgmt->u.action.u.wmm_action.action_code = WMM_ACTION_CODE_ADDTS_REQ;
+       mgmt->u.action.u.wmm_action.dialog_token = 1;
+       mgmt->u.action.u.wmm_action.status_code = 0;
+
+       ieee80211_build_tspec(buf);
 
        ieee80211_sta_tx(wpa_s, wpabuf_head(buf), wpabuf_len(buf));
        wpabuf_free(buf);
@@ -1216,7 +1248,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
 
        ieee80211_associated(wpa_s);
 
-       if (os_strcmp(wpa_s->driver->name, "test") == 0 &&
+       if (wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
+           os_strcmp(wpa_s->driver->name, "test") == 0 &&
            elems.wmm && wpa_s->mlme.wmm_enabled) {
                /* Test WMM-AC - send ADDTS for WMM TSPEC */
                ieee80211_tx_addts(wpa_s);