FT: Add FT AP support for drivers that manage MLME internally
Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
e509167495
commit
88b32a99d3
4 changed files with 215 additions and 15 deletions
|
@ -37,7 +37,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
|||
struct ieee802_11_elems elems;
|
||||
const u8 *ie;
|
||||
size_t ielen;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
|
||||
u8 *p = buf;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
u16 reason = WLAN_REASON_UNSPECIFIED;
|
||||
u16 status = WLAN_STATUS_SUCCESS;
|
||||
|
||||
if (addr == NULL) {
|
||||
/*
|
||||
|
@ -146,27 +151,52 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
|||
return -1;
|
||||
}
|
||||
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
|
||||
ie, ielen, NULL, 0);
|
||||
ie, ielen,
|
||||
elems.mdie, elems.mdie_len);
|
||||
if (res != WPA_IE_OK) {
|
||||
wpa_printf(MSG_DEBUG, "WPA/RSN information element "
|
||||
"rejected? (res %u)", res);
|
||||
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
|
||||
if (res == WPA_INVALID_GROUP)
|
||||
if (res == WPA_INVALID_GROUP) {
|
||||
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
|
||||
else if (res == WPA_INVALID_PAIRWISE)
|
||||
status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
|
||||
} else if (res == WPA_INVALID_PAIRWISE) {
|
||||
reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
|
||||
else if (res == WPA_INVALID_AKMP)
|
||||
status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
|
||||
} else if (res == WPA_INVALID_AKMP) {
|
||||
reason = WLAN_REASON_AKMP_NOT_VALID;
|
||||
status = WLAN_STATUS_AKMP_NOT_VALID;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
|
||||
else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
|
||||
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
|
||||
status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
else
|
||||
else {
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (sta->auth_alg == WLAN_AUTH_FT) {
|
||||
status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
|
||||
req_ies_len);
|
||||
if (status != WLAN_STATUS_SUCCESS) {
|
||||
if (status == WLAN_STATUS_INVALID_PMKID)
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
if (status == WLAN_STATUS_INVALID_MDIE)
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
if (status == WLAN_STATUS_INVALID_FTIE)
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
} else if (hapd->conf->wps_state) {
|
||||
#ifdef CONFIG_WPS
|
||||
struct wpabuf *wps;
|
||||
|
@ -178,6 +208,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
|||
#ifdef CONFIG_WPS_STRICT
|
||||
if (wps && wps_validate_assoc_req(wps) < 0) {
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
wpabuf_free(wps);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -198,8 +229,23 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
|||
skip_wpa_check:
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
|
||||
sta->auth_alg, req_ies, req_ies_len);
|
||||
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
|
||||
#else /* CONFIG_IEEE80211R */
|
||||
/* Keep compiler silent about unused variables */
|
||||
if (status) {
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
|
||||
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
|
||||
|
||||
if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
|
||||
else
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
|
||||
|
||||
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
|
||||
|
@ -216,6 +262,9 @@ skip_wpa_check:
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
|
||||
ap_free_sta(hapd, sta);
|
||||
return -1;
|
||||
|
@ -324,8 +373,93 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
|
|||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
|
||||
const u8 *bssid,
|
||||
u16 auth_transaction, u16 status,
|
||||
const u8 *ies, size_t ies_len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, dst);
|
||||
if (sta == NULL)
|
||||
return;
|
||||
|
||||
hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
|
||||
sta->flags |= WLAN_STA_AUTH;
|
||||
|
||||
hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
|
||||
#ifdef HOSTAPD
|
||||
|
||||
static void hostapd_notif_auth(struct hostapd_data *hapd,
|
||||
struct auth_info *rx_auth)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
u16 status = WLAN_STATUS_SUCCESS;
|
||||
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
|
||||
size_t resp_ies_len = 0;
|
||||
|
||||
sta = ap_get_sta(hapd, rx_auth->peer);
|
||||
if (!sta) {
|
||||
sta = ap_sta_add(hapd, rx_auth->peer);
|
||||
if (sta == NULL) {
|
||||
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
sta->flags &= ~WLAN_STA_PREAUTH;
|
||||
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
|
||||
sta->auth_alg = WLAN_AUTH_FT;
|
||||
if (sta->wpa_sm == NULL)
|
||||
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
|
||||
sta->addr);
|
||||
if (sta->wpa_sm == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
|
||||
"state machine");
|
||||
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
|
||||
rx_auth->auth_transaction, rx_auth->ies,
|
||||
rx_auth->ies_len,
|
||||
hostapd_notify_auth_ft_finish, hapd);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
fail:
|
||||
hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
|
||||
status, resp_ies, resp_ies_len);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
struct rx_action *action)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, action->sa);
|
||||
if (sta == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (action->category == WLAN_ACTION_FT) {
|
||||
wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d",
|
||||
__func__, (int) action->len);
|
||||
wpa_ft_action_rx(sta->wpa_sm, action->data, action->len);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
}
|
||||
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
|
||||
#define HAPD_BROADCAST ((struct hostapd_data *) -1)
|
||||
|
@ -610,14 +744,18 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
|||
break;
|
||||
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
|
||||
break;
|
||||
#ifdef NEED_AP_MLME
|
||||
case EVENT_RX_ACTION:
|
||||
if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
|
||||
data->rx_action.bssid == NULL)
|
||||
break;
|
||||
#ifdef NEED_AP_MLME
|
||||
hostapd_rx_action(hapd, &data->rx_action);
|
||||
break;
|
||||
#endif /* NEED_AP_MLME */
|
||||
hostapd_action_rx(hapd, &data->rx_action);
|
||||
break;
|
||||
case EVENT_AUTH:
|
||||
hostapd_notif_auth(hapd, &data->auth);
|
||||
break;
|
||||
case EVENT_CH_SWITCH:
|
||||
if (!data)
|
||||
break;
|
||||
|
|
|
@ -159,6 +159,7 @@ struct wpa_auth_config {
|
|||
int ft_over_ds;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
int disable_gtk;
|
||||
int ap_mlme;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
@ -197,6 +198,8 @@ struct wpa_auth_callbacks {
|
|||
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
|
||||
int (*send_ft_action)(void *ctx, const u8 *dst,
|
||||
const u8 *data, size_t data_len);
|
||||
int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
|
||||
size_t tspec_ielen);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
};
|
||||
|
||||
|
|
|
@ -52,6 +52,19 @@ wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
|
|||
}
|
||||
|
||||
|
||||
static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *sta_addr,
|
||||
u8 *tspec_ie, size_t tspec_ielen)
|
||||
{
|
||||
if (wpa_auth->cb.add_tspec == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
|
||||
return -1;
|
||||
}
|
||||
return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
|
||||
tspec_ielen);
|
||||
}
|
||||
|
||||
|
||||
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
|
||||
{
|
||||
u8 *pos = buf;
|
||||
|
@ -471,7 +484,8 @@ 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,
|
||||
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
|
||||
u8 *pos, u8 *end, u8 id, u8 descr_count,
|
||||
const u8 *ies, size_t ies_len)
|
||||
{
|
||||
struct ieee802_11_elems parse;
|
||||
|
@ -504,7 +518,7 @@ static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
|
|||
}
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
if (parse.wmm_tspec) {
|
||||
if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
|
||||
struct wmm_tspec_element *tspec;
|
||||
int res;
|
||||
|
||||
|
@ -541,13 +555,35 @@ static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
|
|||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) {
|
||||
struct wmm_tspec_element *tspec;
|
||||
int res;
|
||||
|
||||
tspec = (struct wmm_tspec_element *) pos;
|
||||
os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
|
||||
res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos,
|
||||
sizeof(*tspec));
|
||||
if (res >= 0) {
|
||||
if (res)
|
||||
rdie->status_code = host_to_le16(res);
|
||||
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)
|
||||
static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
|
||||
const u8 *ric, size_t ric_len)
|
||||
{
|
||||
const u8 *rpos, *start;
|
||||
const struct rsn_rdie *rdie;
|
||||
|
@ -569,7 +605,7 @@ static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
|
|||
break;
|
||||
rpos += 2 + rpos[1];
|
||||
}
|
||||
pos = wpa_ft_process_rdie(pos, end, rdie->id,
|
||||
pos = wpa_ft_process_rdie(sm, pos, end, rdie->id,
|
||||
rdie->descr_count,
|
||||
start, rpos - start);
|
||||
}
|
||||
|
@ -678,7 +714,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
|||
|
||||
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);
|
||||
pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
|
||||
parse.ric_len);
|
||||
if (auth_alg == WLAN_AUTH_FT)
|
||||
_ftie->mic_control[1] +=
|
||||
ieee802_11_ie_count(ric_start,
|
||||
|
@ -1061,8 +1098,16 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
|||
|
||||
if (os_memcmp(mic, ftie->mic, 16) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
|
||||
wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
|
||||
MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
|
||||
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
|
||||
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
|
||||
wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
|
||||
parse.mdie - 2, parse.mdie_len + 2);
|
||||
wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
|
||||
parse.ftie - 2, parse.ftie_len + 2);
|
||||
wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
|
||||
parse.rsn - 2, parse.rsn_len + 2);
|
||||
return WLAN_STATUS_INVALID_FTIE;
|
||||
}
|
||||
|
||||
|
|
|
@ -428,6 +428,9 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
|
|||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
|
||||
return NULL;
|
||||
|
||||
sta = ap_sta_add(hapd, sta_addr);
|
||||
if (sta == NULL)
|
||||
return NULL;
|
||||
|
@ -461,6 +464,14 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
|
|||
len - sizeof(*ethhdr));
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
|
||||
u8 *tspec_ie, size_t tspec_ielen)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
|
||||
|
@ -474,6 +485,8 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
|||
hostapd_wpa_auth_conf(hapd->conf, &_conf);
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
|
||||
_conf.tx_status = 1;
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
|
||||
_conf.ap_mlme = 1;
|
||||
os_memset(&cb, 0, sizeof(cb));
|
||||
cb.ctx = hapd;
|
||||
cb.logger = hostapd_wpa_auth_logger;
|
||||
|
@ -492,6 +505,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
|||
#ifdef CONFIG_IEEE80211R
|
||||
cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
|
||||
cb.add_sta = hostapd_wpa_auth_add_sta;
|
||||
cb.add_tspec = hostapd_wpa_auth_add_tspec;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
|
||||
if (hapd->wpa_auth == NULL) {
|
||||
|
|
Loading…
Reference in a new issue