FT: Add RIC Request processing and RIC Response generation
authorJouni Malinen <jouni.malinen@atheros.com>
Mon, 9 Mar 2009 20:25:58 +0000 (22:25 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 9 Mar 2009 20:25:58 +0000 (22:25 +0200)
hostapd will now go through the RIC Request and process each RDIE. Only
WMM TSPEC requests are currently supported; all other request
descriptors will be declined.

RIC Response is written by hostapd and verified by wpa_supplicant (MIC
validation). wpa_supplicant does not yet have code to notify the driver
about the resource request results.

hostapd/ieee802_11.c
hostapd/wme.c
hostapd/wme.h
hostapd/wpa.h
hostapd/wpa_ft.c
src/common/ieee802_11_defs.h
src/common/wpa_common.h
src/rsn_supp/wpa_ft.c

index 83e4388..72d9f61 100644 (file)
@@ -675,7 +675,7 @@ static void handle_assoc(struct hostapd_data *hapd,
        int send_deauth = 0, send_len, left, i;
        struct sta_info *sta;
        struct ieee802_11_elems elems;
-       u8 buf[sizeof(struct ieee80211_mgmt) + 512];
+       u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
        struct ieee80211_mgmt *reply;
 
        if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
@@ -1133,10 +1133,11 @@ static void handle_assoc(struct hostapd_data *hapd,
 #ifdef CONFIG_IEEE80211R
                if (resp == WLAN_STATUS_SUCCESS) {
                        /* IEEE 802.11r: Mobility Domain Information, Fast BSS
-                        * Transition Information, RSN */
+                        * Transition Information, RSN, [RIC Response] */
                        p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
                                                        buf + sizeof(buf) - p,
-                                                       sta->auth_alg);
+                                                       sta->auth_alg,
+                                                       pos, left);
                }
 #endif /* CONFIG_IEEE80211R */
 
index 700410c..7f92a0a 100644 (file)
@@ -165,25 +165,12 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
 }
 
 
-static void wmm_addts_req(struct hostapd_data *hapd,
-                         struct ieee80211_mgmt *mgmt,
-                         struct wmm_tspec_element *tspec, size_t len)
+int wmm_process_tspec(struct wmm_tspec_element *tspec)
 {
-       u8 *end = ((u8 *) mgmt) + len;
        int medium_time, pps, duration;
        int up, psb, dir, tid;
        u16 val, surplus;
 
-       if ((u8 *) (tspec + 1) > end) {
-               wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
-               return;
-       }
-
-       wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC "
-                  "from " MACSTR,
-                  mgmt->u.action.u.wmm_action.dialog_token,
-                  MAC2STR(mgmt->sa));
-
        up = (tspec->ts_info[1] >> 3) & 0x07;
        psb = (tspec->ts_info[1] >> 2) & 0x01;
        dir = (tspec->ts_info[0] >> 5) & 0x03;
@@ -204,7 +191,7 @@ static void wmm_addts_req(struct hostapd_data *hapd,
        val = le_to_host16(tspec->nominal_msdu_size);
        if (val == 0) {
                wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)");
-               goto invalid;
+               return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
        }
        /* pps = Ceiling((Mean Data Rate / 8) / Nominal MSDU Size) */
        pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val;
@@ -213,7 +200,7 @@ static void wmm_addts_req(struct hostapd_data *hapd,
 
        if (le_to_host32(tspec->minimum_phy_rate) < 1000000) {
                wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate");
-               goto invalid;
+               return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
        }
 
        duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 /
@@ -226,7 +213,7 @@ static void wmm_addts_req(struct hostapd_data *hapd,
        if (surplus <= 0x2000) {
                wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not "
                           "greater than unity");
-               goto invalid;
+               return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
        }
 
        medium_time = surplus * pps * duration / 0x2000;
@@ -241,26 +228,38 @@ static void wmm_addts_req(struct hostapd_data *hapd,
        if (medium_time > 750000) {
                wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over "
                           "75%% of available bandwidth");
-               wmm_send_action(hapd, mgmt->sa, tspec,
-                               WMM_ACTION_CODE_ADDTS_RESP,
-                               mgmt->u.action.u.wmm_action.dialog_token,
-                               WMM_ADDTS_STATUS_REFUSED);
-               return;
+               return WMM_ADDTS_STATUS_REFUSED;
        }
 
        /* Convert to 32 microseconds per second unit */
        tspec->medium_time = host_to_le16(medium_time / 32);
 
+       return WMM_ADDTS_STATUS_ADMISSION_ACCEPTED;
+}
+
+
+static void wmm_addts_req(struct hostapd_data *hapd,
+                         struct ieee80211_mgmt *mgmt,
+                         struct wmm_tspec_element *tspec, size_t len)
+{
+       u8 *end = ((u8 *) mgmt) + len;
+       int res;
+
+       if ((u8 *) (tspec + 1) > end) {
+               wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC "
+                  "from " MACSTR,
+                  mgmt->u.action.u.wmm_action.dialog_token,
+                  MAC2STR(mgmt->sa));
+
+       res = wmm_process_tspec(tspec);
+       wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
+
        wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
-                       mgmt->u.action.u.wmm_action.dialog_token,
-                       WMM_ADDTS_STATUS_ADMISSION_ACCEPTED);
-       return;
-
-invalid:
-       wmm_send_action(hapd, mgmt->sa, tspec,
-                       WMM_ACTION_CODE_ADDTS_RESP,
-                       mgmt->u.action.u.wmm_action.dialog_token,
-                       WMM_ADDTS_STATUS_INVALID_PARAMETERS);
+                       mgmt->u.action.u.wmm_action.dialog_token, res);
 }
 
 
index 2f851ae..1ddb647 100644 (file)
@@ -31,5 +31,6 @@ static inline int hostapd_wmm_sta_config(struct hostapd_data *hapd,
 #endif /* NEED_MLME */
 void hostapd_wmm_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
                        size_t len);
+int wmm_process_tspec(struct wmm_tspec_element *tspec);
 
 #endif /* WME_H */
index 7d9b3d3..873bc42 100644 (file)
@@ -266,7 +266,8 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
 
 #ifdef CONFIG_IEEE80211R
 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
-                                size_t max_len, int auth_alg);
+                                size_t max_len, int auth_alg,
+                                const u8 *req_ies, size_t req_ies_len);
 void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
                         u16 auth_transaction, const u8 *ies, size_t ies_len,
                         void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
index 337c7eb..5a5a443 100644 (file)
@@ -19,6 +19,7 @@
 #include "wpa.h"
 #include "aes_wrap.h"
 #include "ieee802_11.h"
+#include "wme.h"
 #include "defs.h"
 #include "wpa_auth_i.h"
 #include "wpa_auth_ie.h"
 
 #ifdef CONFIG_IEEE80211R
 
+struct wpa_ft_ies {
+       const u8 *mdie;
+       size_t mdie_len;
+       const u8 *ftie;
+       size_t ftie_len;
+       const u8 *r1kh_id;
+       const u8 *gtk;
+       size_t gtk_len;
+       const u8 *r0kh_id;
+       size_t r0kh_id_len;
+       const u8 *rsn;
+       size_t rsn_len;
+       const u8 *rsn_pmkid;
+       const u8 *ric;
+       size_t ric_len;
+};
+
+
+static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
+                           struct wpa_ft_ies *parse);
+
+
 static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
                           const u8 *data, size_t data_len)
 {
@@ -471,14 +494,122 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
 #endif /* CONFIG_IEEE80211W */
 
 
+static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
+                               const u8 *ies, size_t ies_len)
+{
+       struct ieee802_11_elems parse;
+       struct rsn_rdie *rdie;
+
+       wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d",
+                  id, descr_count);
+       wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)",
+                   ies, ies_len);
+
+       if (end - pos < (int) sizeof(*rdie)) {
+               wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE");
+               return pos;
+       }
+
+       *pos++ = WLAN_EID_RIC_DATA;
+       *pos++ = sizeof(*rdie);
+       rdie = (struct rsn_rdie *) pos;
+       rdie->id = id;
+       rdie->descr_count = 0;
+       rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+       pos += sizeof(*rdie);
+
+       if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) ==
+           ParseFailed) {
+               wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs");
+               rdie->status_code =
+                       host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+               return pos;
+       }
+
+       if (parse.wmm_tspec) {
+               struct wmm_tspec_element *tspec;
+               int res;
+
+               if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
+                       wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
+                                  "(%d)", (int) parse.wmm_tspec_len);
+                       rdie->status_code =
+                               host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+                       return pos;
+               }
+               if (end - pos < (int) sizeof(*tspec)) {
+                       wpa_printf(MSG_ERROR, "FT: Not enough room for "
+                                  "response TSPEC");
+                       rdie->status_code =
+                               host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+                       return pos;
+               }
+               tspec = (struct wmm_tspec_element *) pos;
+               os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
+               res = wmm_process_tspec(tspec);
+               wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
+               if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
+                       rdie->status_code =
+                               host_to_le16(WLAN_STATUS_INVALID_PARAMETERS);
+               else if (res == WMM_ADDTS_STATUS_REFUSED)
+                       rdie->status_code =
+                               host_to_le16(WLAN_STATUS_REQUEST_DECLINED);
+               else {
+                       /* TSPEC accepted; include updated TSPEC in response */
+                       rdie->descr_count = 1;
+                       pos += sizeof(*tspec);
+               }
+               return pos;
+       }
+
+       wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
+       rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+       return pos;
+}
+
+
+static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
+{
+       const u8 *rpos, *start;
+       const struct rsn_rdie *rdie;
+
+       wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len);
+
+       rpos = ric;
+       while (rpos + sizeof(*rdie) < ric + ric_len) {
+               if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) ||
+                   rpos + 2 + rpos[1] > ric + ric_len)
+                       break;
+               rdie = (const struct rsn_rdie *) (rpos + 2);
+               rpos += 2 + rpos[1];
+               start = rpos;
+
+               while (rpos + 2 <= ric + ric_len &&
+                      rpos + 2 + rpos[1] <= ric + ric_len) {
+                       if (rpos[0] == WLAN_EID_RIC_DATA)
+                               break;
+                       rpos += 2 + rpos[1];
+               }
+               pos = wpa_ft_process_rdie(pos, end, rdie->id,
+                                         rdie->descr_count,
+                                         start, rpos - start);
+       }
+
+       return pos;
+}
+
+
 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
-                                size_t max_len, int auth_alg)
+                                size_t max_len, int auth_alg,
+                                const u8 *req_ies, size_t req_ies_len)
 {
        u8 *end, *mdie, *ftie, *rsnie, *r0kh_id, *subelem = NULL;
        size_t mdie_len, ftie_len, rsnie_len, r0kh_id_len, subelem_len = 0;
        int res;
        struct wpa_auth_config *conf;
        struct rsn_ftie *_ftie;
+       struct wpa_ft_ies parse;
+       u8 *ric_start;
 
        if (sm == NULL)
                return pos;
@@ -549,33 +680,27 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 
        _ftie = (struct rsn_ftie *) (ftie + 2);
        _ftie->mic_control[1] = 3; /* Information element count */
+
+       ric_start = pos;
+       if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
+               pos = wpa_ft_process_ric(pos, end, parse.ric, parse.ric_len);
+               _ftie->mic_control[1] += ieee802_11_ie_count(ric_start,
+                                                            pos - ric_start);
+       }
+       if (ric_start == pos)
+               ric_start = NULL;
+
        if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
                       mdie, mdie_len, ftie, ftie_len,
-                      rsnie, rsnie_len, NULL, 0, _ftie->mic) < 0)
+                      rsnie, rsnie_len,
+                      ric_start, ric_start ? pos - ric_start : 0,
+                      _ftie->mic) < 0)
                wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
 
        return pos;
 }
 
 
-struct wpa_ft_ies {
-       const u8 *mdie;
-       size_t mdie_len;
-       const u8 *ftie;
-       size_t ftie_len;
-       const u8 *r1kh_id;
-       const u8 *gtk;
-       size_t gtk_len;
-       const u8 *r0kh_id;
-       size_t r0kh_id_len;
-       const u8 *rsn;
-       size_t rsn_len;
-       const u8 *rsn_pmkid;
-       const u8 *ric;
-       size_t ric_len;
-};
-
-
 static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
                             struct wpa_ft_ies *parse)
 {
index 67c704d..e04b285 100644 (file)
 #define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
 #define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
 #define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
+#define WLAN_STATUS_R0KH_UNREACHABLE 28
 /* IEEE 802.11w */
 #define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
 #define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
+#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
+#define WLAN_STATUS_REQUEST_DECLINED 37
+#define WLAN_STATUS_INVALID_PARAMETERS 38
 /* IEEE 802.11i */
 #define WLAN_STATUS_INVALID_IE 40
 #define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
index 2fcb9f2..2853156 100644 (file)
@@ -282,6 +282,12 @@ struct rsn_ftie {
 #define FTIE_SUBELEM_R0KH_ID 3
 #define FTIE_SUBELEM_IGTK 4
 
+struct rsn_rdie {
+       u8 id;
+       u8 descr_count;
+       le16 status_code;
+} STRUCT_PACKED;
+
 #endif /* CONFIG_IEEE80211R */
 
 #ifdef _MSC_VER
index 014261c..aa77a3d 100644 (file)
@@ -300,6 +300,8 @@ struct wpa_ft_ies {
        size_t tie_len;
        const u8 *igtk;
        size_t igtk_len;
+       const u8 *ric;
+       size_t ric_len;
 };
 
 
@@ -358,6 +360,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)
@@ -386,6 +390,10 @@ 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;
@@ -393,11 +401,55 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
                        parse->tie = pos + 2;
                        parse->tie_len = pos[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 (parse->tie)
+               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;
 }
 
@@ -818,16 +870,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
        if (parse.tie)
                count++;
 
-       if (ftie->mic_control[1] != count) {
-               wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in FTIE (%d)",
-                          ftie->mic_control[1]);
-               return -1;
-       }
-
        if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
                       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 -1;
@@ -848,6 +895,12 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
                return -1;
 #endif /* CONFIG_IEEE80211W */
 
+       if (parse.ric) {
+               wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response",
+                           parse.ric, parse.ric_len);
+               /* TODO: parse response and inform driver about results */
+       }
+
        return 0;
 }