FT: Add RIC Request generation and validation (but not processing)

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).
This commit is contained in:
Jouni Malinen 2009-03-09 20:45:17 +02:00 committed by Jouni Malinen
parent 143a4bf632
commit babfbf15cc
9 changed files with 173 additions and 48 deletions

View 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;

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

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

View 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;
/**

View 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);

View 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);

View 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);

View 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? */
}
}

View 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);