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.
This commit is contained in:
Jouni Malinen 2009-03-09 22:25:58 +02:00 committed by Jouni Malinen
parent babfbf15cc
commit f238cf9f42
8 changed files with 252 additions and 62 deletions

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

View 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);
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;
return WMM_ADDTS_STATUS_ADMISSION_ACCEPTED;
}
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);
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, res);
}

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

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

View 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"
@ -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)
{

View file

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

View 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

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