|
@@ -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,9 +229,24 @@ 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;
|
|
|
- wpa_auth_sm_event(sta->wpa_sm, WPA_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;
|