Browse Source

FT: Add RIC Request processing and RIC Response generation

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.
Jouni Malinen 16 years ago
parent
commit
f238cf9f42
8 changed files with 252 additions and 62 deletions
  1. 4 3
      hostapd/ieee802_11.c
  2. 30 31
      hostapd/wme.c
  3. 1 0
      hostapd/wme.h
  4. 2 1
      hostapd/wpa.h
  5. 145 20
      hostapd/wpa_ft.c
  6. 4 0
      src/common/ieee802_11_defs.h
  7. 6 0
      src/common/wpa_common.h
  8. 60 7
      src/rsn_supp/wpa_ft.c

+ 4 - 3
hostapd/ieee802_11.c

@@ -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 */
 

+ 30 - 31
hostapd/wme.c

@@ -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);
 }
 
 

+ 1 - 0
hostapd/wme.h

@@ -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 */

+ 2 - 1
hostapd/wpa.h

@@ -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,

+ 145 - 20
hostapd/wpa_ft.c

@@ -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"
@@ -26,6 +27,28 @@
 
 #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)
 {

+ 4 - 0
src/common/ieee802_11_defs.h

@@ -116,9 +116,13 @@
 #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

+ 6 - 0
src/common/wpa_common.h

@@ -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

+ 60 - 7
src/rsn_supp/wpa_ft.c

@@ -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;
 }