FT: Clean up wpa_sm_set_ft_params() by using common parse

Instead of parsing the IEs in the callers, use the already existing
parser in wpa_ft.c to handle MDIE and FTIE from initial MD association
response. In addition, this provides more complete access to association
response IEs to FT code which will be needed to fix FT 4-way handshake
message 2/4.
This commit is contained in:
Jouni Malinen 2010-04-10 11:36:35 +03:00
parent 0ae145cde8
commit e7846b6859
6 changed files with 71 additions and 144 deletions

View file

@ -278,9 +278,7 @@ static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
#ifdef CONFIG_IEEE80211R #ifdef CONFIG_IEEE80211R
int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *mobility_domain, int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *r1kh_id);
int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie); int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie);
int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, 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,

View file

@ -24,6 +24,31 @@
#ifdef CONFIG_IEEE80211R #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 *tie;
size_t tie_len;
const u8 *igtk;
size_t igtk_len;
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);
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, const struct wpa_eapol_key *key,
struct wpa_ptk *ptk, size_t ptk_len) struct wpa_ptk *ptk, size_t ptk_len)
@ -62,34 +87,40 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
/** /**
* wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters
* @sm: Pointer to WPA state machine data from wpa_sm_init() * @sm: Pointer to WPA state machine data from wpa_sm_init()
* @mobility_domain: Mobility domain identifier (2 octets + 1 octet) * @ies: Association Response IEs or %NULL to clear FT parameters
* @r0kh_id: PMK-R0 key holder identity (1-48 octets) * @ies_len: Length of ies buffer in octets
* @r0kh_id_len: R0KH-ID length (1-48)
* @r1kh_id: PMK-R1 key holder identity (16 octets)
* Returns: 0 on success, -1 on failure * Returns: 0 on success, -1 on failure
*/ */
int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *mobility_domain, int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *r1kh_id)
{ {
if (sm && mobility_domain) { struct wpa_ft_ies ft;
if (sm == NULL)
return 0;
if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0)
return -1;
if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
return -1;
if (ft.mdie) {
wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
mobility_domain, MOBILITY_DOMAIN_ID_LEN); ft.mdie, MOBILITY_DOMAIN_ID_LEN);
os_memcpy(sm->mobility_domain, mobility_domain, os_memcpy(sm->mobility_domain, ft.mdie,
MOBILITY_DOMAIN_ID_LEN); MOBILITY_DOMAIN_ID_LEN);
sm->mdie_ft_capab = mobility_domain[MOBILITY_DOMAIN_ID_LEN]; sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x", wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
sm->mdie_ft_capab); sm->mdie_ft_capab);
} else if (sm) } else
os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN); os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
if (sm && r0kh_id) { if (ft.r0kh_id) {
if (r0kh_id_len > FT_R0KH_ID_MAX_LEN) wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
return -1; ft.r0kh_id, ft.r0kh_id_len);
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len); os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len);
os_memcpy(sm->r0kh_id, r0kh_id, r0kh_id_len); sm->r0kh_id_len = ft.r0kh_id_len;
sm->r0kh_id_len = r0kh_id_len; } else {
} else if (sm) {
/* FIX: When should R0KH-ID be cleared? We need to keep the /* FIX: When should R0KH-ID be cleared? We need to keep the
* old R0KH-ID in order to be able to use this during FT. */ * old R0KH-ID in order to be able to use this during FT. */
/* /*
@ -98,10 +129,11 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *mobility_domain,
*/ */
} }
if (sm && r1kh_id) { if (ft.r1kh_id) {
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN); wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID",
os_memcpy(sm->r1kh_id, r1kh_id, FT_R1KH_ID_LEN); ft.r1kh_id, FT_R1KH_ID_LEN);
} else if (sm) os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN);
} else
os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN); os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
return 0; return 0;
@ -296,28 +328,6 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
} }
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 *tie;
size_t tie_len;
const u8 *igtk;
size_t igtk_len;
const u8 *ric;
size_t ric_len;
};
static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
struct wpa_ft_ies *parse) struct wpa_ft_ies *parse)
{ {

View file

@ -956,58 +956,11 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_NO_SCAN_PROCESSING */ #endif /* CONFIG_NO_SCAN_PROCESSING */
#ifdef CONFIG_IEEE80211R
static void wpa_assoc_set_ft_params(struct wpa_supplicant *wpa_s,
const u8 *ftie, const u8 *mdie)
{
const u8 *mobility_domain = NULL;
const u8 *r0kh_id = NULL;
size_t r0kh_id_len = 0;
const u8 *r1kh_id = NULL;
struct rsn_ftie *hdr;
const u8 *pos, *end;
if (mdie == NULL || ftie == NULL)
return;
if (mdie[1] >= MOBILITY_DOMAIN_ID_LEN) {
mobility_domain = mdie + 2;
#ifdef CONFIG_SME
wpa_s->sme.ft_used = 1;
os_memcpy(wpa_s->sme.mobility_domain, mobility_domain, 2);
#endif /* CONFIG_SME */
}
if (ftie[1] >= sizeof(struct rsn_ftie)) {
end = ftie + 2 + ftie[1];
hdr = (struct rsn_ftie *) (ftie + 2);
pos = (const u8 *) (hdr + 1);
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
break;
if (pos[0] == FTIE_SUBELEM_R1KH_ID &&
pos[1] == FT_R1KH_ID_LEN)
r1kh_id = pos + 2;
else if (pos[0] == FTIE_SUBELEM_R0KH_ID &&
pos[1] >= 1 && pos[1] <= FT_R0KH_ID_MAX_LEN) {
r0kh_id = pos + 2;
r0kh_id_len = pos[1];
}
pos += 2 + pos[1];
}
}
wpa_sm_set_ft_params(wpa_s->wpa, mobility_domain, r0kh_id,
r0kh_id_len, r1kh_id);
}
#endif /* CONFIG_IEEE80211R */
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data) union wpa_event_data *data)
{ {
int l, len, found = 0, wpa_found, rsn_found; int l, len, found = 0, wpa_found, rsn_found;
const u8 *p; const u8 *p;
#ifdef CONFIG_IEEE80211R
const u8 *mdie = NULL, *ftie = NULL;
#endif /* CONFIG_IEEE80211R */
wpa_printf(MSG_DEBUG, "Association info event"); wpa_printf(MSG_DEBUG, "Association info event");
if (data->assoc_info.req_ies) if (data->assoc_info.req_ies)
@ -1065,12 +1018,11 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
return -1; return -1;
} }
} }
#endif /* CONFIG_SME */
p = data->assoc_info.resp_ies; p = data->assoc_info.resp_ies;
l = data->assoc_info.resp_ies_len; l = data->assoc_info.resp_ies_len;
/* Go through the IEs and make a copy of the FT/MD IE, if present. */ /* Go through the IEs and make a copy of the MDIE, if present. */
while (p && l >= 2) { while (p && l >= 2) {
len = p[1] + 2; len = p[1] + 2;
if (len > l) { if (len > l) {
@ -1078,15 +1030,20 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
p, l); p, l);
break; break;
} }
if (p[0] == WLAN_EID_FAST_BSS_TRANSITION) if (p[0] == WLAN_EID_MOBILITY_DOMAIN &&
ftie = p; p[1] >= MOBILITY_DOMAIN_ID_LEN) {
else if (p[0] == WLAN_EID_MOBILITY_DOMAIN) wpa_s->sme.ft_used = 1;
mdie = p; os_memcpy(wpa_s->sme.mobility_domain, p + 2,
MOBILITY_DOMAIN_ID_LEN);
break;
}
l -= len; l -= len;
p += len; p += len;
} }
#endif /* CONFIG_SME */
wpa_assoc_set_ft_params(wpa_s, ftie, mdie); wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_IEEE80211R */ #endif /* CONFIG_IEEE80211R */
/* WPA/RSN IE from Beacon/ProbeResp */ /* WPA/RSN IE from Beacon/ProbeResp */

View file

@ -996,45 +996,6 @@ static void ieee80211_rx_mgmt_disassoc(struct wpa_supplicant *wpa_s,
} }
static int ieee80211_ft_assoc_resp(struct wpa_supplicant *wpa_s,
struct ieee802_11_elems *elems)
{
#ifdef CONFIG_IEEE80211R
const u8 *mobility_domain = NULL;
const u8 *r0kh_id = NULL;
size_t r0kh_id_len = 0;
const u8 *r1kh_id = NULL;
struct rsn_ftie *hdr;
const u8 *pos, *end;
if (elems->mdie && elems->mdie_len >= MOBILITY_DOMAIN_ID_LEN)
mobility_domain = elems->mdie;
if (elems->ftie && elems->ftie_len >= sizeof(struct rsn_ftie)) {
end = elems->ftie + elems->ftie_len;
hdr = (struct rsn_ftie *) elems->ftie;
pos = (const u8 *) (hdr + 1);
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
break;
if (pos[0] == FTIE_SUBELEM_R1KH_ID &&
pos[1] == FT_R1KH_ID_LEN)
r1kh_id = pos + 2;
else if (pos[0] == FTIE_SUBELEM_R0KH_ID &&
pos[1] >= 1 && pos[1] <= FT_R0KH_ID_MAX_LEN) {
r0kh_id = pos + 2;
r0kh_id_len = pos[1];
}
pos += 2 + pos[1];
}
}
return wpa_sm_set_ft_params(wpa_s->wpa, mobility_domain, r0kh_id,
r0kh_id_len, r1kh_id);
#else /* CONFIG_IEEE80211R */
return 0;
#endif /* CONFIG_IEEE80211R */
}
static void ieee80211_build_tspec(struct wpabuf *buf) static void ieee80211_build_tspec(struct wpabuf *buf)
{ {
struct wmm_tspec_element *tspec; struct wmm_tspec_element *tspec;
@ -1194,7 +1155,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
"Resp failed"); "Resp failed");
return; return;
} }
} else if (ieee80211_ft_assoc_resp(wpa_s, &elems) < 0) } else if (wpa_sm_set_ft_params(wpa_s->wpa, pos,
len - (pos - (u8 *) mgmt)) < 0)
return; return;
wpa_printf(MSG_DEBUG, "MLME: associated"); wpa_printf(MSG_DEBUG, "MLME: associated");

View file

@ -160,7 +160,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
md = ie + 2; md = ie + 2;
wpa_sm_set_ft_params(wpa_s->wpa, md, NULL, 0, NULL); wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
if (md) { if (md) {
/* Prepare for the next transition */ /* Prepare for the next transition */
wpa_ft_prepare_auth_request(wpa_s->wpa, ie); wpa_ft_prepare_auth_request(wpa_s->wpa, ie);

View file

@ -1037,7 +1037,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
md = ie + 2; md = ie + 2;
wpa_sm_set_ft_params(wpa_s->wpa, md, NULL, 0, NULL); wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
if (md) { if (md) {
/* Prepare for the next transition */ /* Prepare for the next transition */
wpa_ft_prepare_auth_request(wpa_s->wpa, ie); wpa_ft_prepare_auth_request(wpa_s->wpa, ie);