diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog index e249ad73f..a338cdf6e 100644 --- a/hostapd/ChangeLog +++ b/hostapd/ChangeLog @@ -10,6 +10,9 @@ ChangeLog for hostapd * added support for setting VLAN ID for STAs based on local MAC ACL (accept_mac_file) as an alternative for RADIUS server-based configuration + * updated management frame protection to use IEEE 802.11w/D6.0 + (adds a new association ping to protect against unauthenticated + authenticate or (re)associate request frames dropping association) 2008-08-10 - v0.6.4 * added peer identity into EAP-FAST PAC-Opaque and skip Phase 2 diff --git a/hostapd/ap.h b/hostapd/ap.h index 3a008454a..340b97c09 100644 --- a/hostapd/ap.h +++ b/hostapd/ap.h @@ -93,6 +93,14 @@ struct sta_info { #ifdef CONFIG_IEEE80211N struct ht_cap_ie ht_capabilities; /* IEEE 802.11n capabilities */ #endif /* CONFIG_IEEE80211N */ + +#ifdef CONFIG_IEEE80211W + int ping_count; /* number of pending ping requests; + * 0 = no ping in progress */ + int ping_timed_out; + u8 *ping_trans_id; /* buffer of WLAN_PING_TRANS_ID_LEN * ping_count + * octets of pending ping transaction identifiers */ +#endif /* CONFIG_IEEE80211W */ }; diff --git a/hostapd/config.c b/hostapd/config.c index eb247a3f1..0c251a9f5 100644 --- a/hostapd/config.c +++ b/hostapd/config.c @@ -1,6 +1,6 @@ /* * hostapd / Configuration file - * Copyright (c) 2003-2007, Jouni Malinen + * Copyright (c) 2003-2008, Jouni Malinen * Copyright (c) 2007-2008, Intel Corporation * * This program is free software; you can redistribute it and/or modify @@ -181,6 +181,11 @@ static void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->eapol_version = EAPOL_VERSION; bss->max_listen_interval = 65535; + +#ifdef CONFIG_IEEE80211W + bss->assoc_ping_timeout = 1000; + bss->assoc_ping_attempts = 3; +#endif /* CONFIG_IEEE80211W */ } @@ -1965,6 +1970,21 @@ struct hostapd_config * hostapd_config_read(const char *fname) #ifdef CONFIG_IEEE80211W } else if (os_strcmp(buf, "ieee80211w") == 0) { bss->ieee80211w = atoi(pos); + } else if (os_strcmp(buf, "assoc_ping_timeout") == 0) { + bss->assoc_ping_timeout = atoi(pos); + if (bss->assoc_ping_timeout == 0) { + printf("Line %d: invalid assoc_ping_timeout\n", + line); + errors++; + } + } else if (os_strcmp(buf, "assoc_ping_attempts") == 0) { + bss->assoc_ping_timeout = atoi(pos); + if (bss->assoc_ping_timeout == 0) { + printf("Line %d: invalid assoc_ping_attempts " + "(valid range: 1..255)\n", + line); + errors++; + } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211N } else if (os_strcmp(buf, "ieee80211n") == 0) { diff --git a/hostapd/config.h b/hostapd/config.h index f92ea84c4..237dec24a 100644 --- a/hostapd/config.h +++ b/hostapd/config.h @@ -213,6 +213,10 @@ struct hostapd_bss_config { IEEE80211W_OPTIONAL = 1, IEEE80211W_REQUIRED = 2 } ieee80211w; + /* dot11AssociationPingResponseTimeout (in TU) */ + unsigned int assoc_ping_timeout; + /* dot11AssociationMaximumPingAttempts */ + int assoc_ping_attempts; #endif /* CONFIG_IEEE80211W */ int wpa_pairwise; int wpa_group; diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 2e4b71c52..d369c7c6f 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -704,12 +704,21 @@ own_ip_addr=127.0.0.1 # 1 = enabled #peerkey=1 -# ieee80211w: Whether management frame protection is enabled +# ieee80211w: Whether management frame protection (MFP) is enabled # 0 = disabled (default) # 1 = optional # 2 = required #ieee80211w=0 +# Association ping timeout (in TU = 1.024 ms; for MFP) +# dot11AssociationPingResponseTimeout, 1...4294967295 +#assoc_ping_timeout=1000 + +# Maximum number of association pings +# dot11AssociationMaximumPingAttempts , 1...255 +#assoc_ping_attempts=3 + + # okc: Opportunistic Key Caching (aka Proactive Key Caching) # Allow PMK cache to be shared opportunistically among configured interfaces # and BSSes (i.e., all configurations within a single hostapd process). diff --git a/hostapd/ieee802_11.c b/hostapd/ieee802_11.c index c07449fc7..7358c3d67 100644 --- a/hostapd/ieee802_11.c +++ b/hostapd/ieee802_11.c @@ -371,6 +371,25 @@ static int ieee802_11_parse_vendor_specific(struct hostapd_data *hapd, } +#ifdef CONFIG_IEEE80211W +static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, + struct sta_info *sta, u8 *eid) +{ + u8 *pos = eid; + u32 timeout; + + *pos++ = WLAN_EID_ASSOC_COMEBACK_TIME; + *pos++ = 4; + timeout = (hapd->conf->assoc_ping_attempts - sta->ping_count + 1) * + hapd->conf->assoc_ping_timeout; + WPA_PUT_LE32(pos, timeout); + pos += 4; + + return pos; +} +#endif /* CONFIG_IEEE80211W */ + + ParseRes ieee802_11_parse_elems(struct hostapd_data *hapd, u8 *start, size_t len, struct ieee802_11_elems *elems, @@ -514,12 +533,10 @@ void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len) void ieee802_11_send_deauth(struct hostapd_data *hapd, u8 *addr, u16 reason) { struct ieee80211_mgmt mgmt; - char buf[30]; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "deauthenticate - reason %d", reason); - os_snprintf(buf, sizeof(buf), "SEND-DEAUTHENTICATE %d", reason); os_memset(&mgmt, 0, sizeof(mgmt)); mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH); @@ -1160,6 +1177,21 @@ static void handle_assoc(struct hostapd_data *hapd, if (resp != WLAN_STATUS_SUCCESS) goto fail; #ifdef CONFIG_IEEE80211W + if ((sta->flags & WLAN_STA_MFP) && !sta->ping_timed_out) { + /* + * STA has already been associated with MFP and ping + * timeout has not been reached. Reject the + * association attempt temporarily and start ping, if + * one is not pending. + */ + + if (sta->ping_count == 0) + ap_sta_start_ping(hapd, sta); + + resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; + goto fail; + } + if (wpa_auth_uses_mfp(sta->wpa_sm)) sta->flags |= WLAN_STA_MFP; else @@ -1352,6 +1384,11 @@ static void handle_assoc(struct hostapd_data *hapd, } #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + if (resp == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) + p = hostapd_eid_assoc_comeback_time(hapd, sta, p); +#endif /* CONFIG_IEEE80211W */ + send_len += p - reply->u.assoc_resp.variable; /* Request TX callback */ @@ -1553,6 +1590,56 @@ static void handle_beacon(struct hostapd_data *hapd, } +#ifdef CONFIG_IEEE80211W +static void hostapd_ping_action(struct hostapd_data *hapd, + struct ieee80211_mgmt *mgmt, size_t len) +{ + struct sta_info *sta; + u8 *end; + int i; + + end = mgmt->u.action.u.ping_resp.trans_id + WLAN_PING_TRANS_ID_LEN; + if (((u8 *) mgmt) + len < end) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short Ping Action " + "frame (len=%lu)", (unsigned long) len); + return; + } + + if (mgmt->u.action.u.ping_resp.action != WLAN_PING_RESPONSE) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected Ping Action %d", + mgmt->u.action.u.ping_resp.action); + return; + } + + /* MLME-PING.confirm */ + + sta = ap_get_sta(hapd, mgmt->sa); + if (sta == NULL || sta->ping_trans_id == NULL) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with " + "pending ping request found"); + return; + } + + for (i = 0; i < sta->ping_count; i++) { + if (os_memcmp(sta->ping_trans_id + i * WLAN_PING_TRANS_ID_LEN, + mgmt->u.action.u.ping_resp.trans_id, + WLAN_PING_TRANS_ID_LEN) == 0) + break; + } + + if (i >= sta->ping_count) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching ping " + "transaction identifier found"); + return; + } + + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "Reply to pending ping received"); + ap_sta_stop_ping(hapd, sta); +} +#endif /* CONFIG_IEEE80211W */ + + static void handle_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, size_t len) { @@ -1588,6 +1675,11 @@ static void handle_action(struct hostapd_data *hapd, case WME_ACTION_CATEGORY: hostapd_wme_action(hapd, mgmt, len); return; +#ifdef CONFIG_IEEE80211W + case WLAN_ACTION_PING: + hostapd_ping_action(hapd, mgmt, len); + return; +#endif /* CONFIG_IEEE80211W */ } hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -1811,6 +1903,10 @@ static void handle_assoc_cb(struct hostapd_data *hapd, ht_cap = &sta->ht_capabilities; #endif /* CONFIG_IEEE80211N */ +#ifdef CONFIG_IEEE80211W + sta->ping_timed_out = 0; +#endif /* CONFIG_IEEE80211W */ + if (hostapd_sta_add(hapd->conf->iface, hapd, sta->addr, sta->aid, sta->capability, sta->supported_rates, sta->supported_rates_len, 0, sta->listen_interval, @@ -1881,6 +1977,9 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len, case WLAN_FC_STYPE_DEAUTH: /* ignore */ break; + case WLAN_FC_STYPE_ACTION: + wpa_printf(MSG_DEBUG, "mgmt::action cb"); + break; default: printf("unknown mgmt cb frame subtype %d\n", stype); break; diff --git a/hostapd/mlme.c b/hostapd/mlme.c index 318ca8642..d883931cf 100644 --- a/hostapd/mlme.c +++ b/hostapd/mlme.c @@ -58,7 +58,7 @@ void mlme_authenticate_indication(struct hostapd_data *hapd, HOSTAPD_LEVEL_DEBUG, "MLME-AUTHENTICATE.indication(" MACSTR ", %s)", MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg)); - if (sta->auth_alg != WLAN_AUTH_FT) + if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP)) mlme_deletekeys_request(hapd, sta); } diff --git a/hostapd/sta_info.c b/hostapd/sta_info.c index e9c0cc6e1..855c54811 100644 --- a/hostapd/sta_info.c +++ b/hostapd/sta_info.c @@ -1,6 +1,6 @@ /* * hostapd / Station table - * Copyright (c) 2002-2007, Jouni Malinen + * Copyright (c) 2002-2008, Jouni Malinen * Copyright (c) 2007-2008, Intel Corporation * * This program is free software; you can redistribute it and/or modify @@ -34,6 +34,9 @@ static int ap_sta_in_other_bss(struct hostapd_data *hapd, struct sta_info *sta, u32 flags); static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx); +#ifdef CONFIG_IEEE80211W +static void ap_ping_timer(void *eloop_ctx, void *timeout_ctx); +#endif /* CONFIG_IEEE80211W */ int ap_for_each_sta(struct hostapd_data *hapd, int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, @@ -179,6 +182,12 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) os_free(sta->last_assoc_req); os_free(sta->challenge); + +#ifdef CONFIG_IEEE80211W + os_free(sta->ping_trans_id); + eloop_cancel_timeout(ap_ping_timer, hapd, sta); +#endif /* CONFIG_IEEE80211W */ + os_free(sta); } @@ -594,3 +603,87 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, return hostapd_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id); } + + +#ifdef CONFIG_IEEE80211W + +/* MLME-PING.request */ +static void ieee802_11_send_ping_req(struct hostapd_data *hapd, const u8 *addr, + const u8 *trans_id) +{ + struct ieee80211_mgmt mgmt; + u8 *end; + + os_memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memcpy(mgmt.da, addr, ETH_ALEN); + os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); + mgmt.u.action.category = WLAN_ACTION_PING; + mgmt.u.action.u.ping_req.action = WLAN_PING_REQUEST; + os_memcpy(mgmt.u.action.u.ping_req.trans_id, trans_id, + WLAN_PING_TRANS_ID_LEN); + end = mgmt.u.action.u.ping_req.trans_id + WLAN_PING_TRANS_ID_LEN; + if (hostapd_send_mgmt_frame(hapd, &mgmt, IEEE80211_HDRLEN + + end - (u8 *) &mgmt, 0) < 0) + perror("ieee802_11_send_ping_req: send"); +} + + +static void ap_ping_timer(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct sta_info *sta = timeout_ctx; + unsigned int timeout, sec, usec; + u8 *trans_id, *nbuf; + + if (sta->ping_count >= hapd->conf->assoc_ping_attempts) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "association ping timed out"); + sta->ping_timed_out = 1; + os_free(sta->ping_trans_id); + sta->ping_trans_id = NULL; + sta->ping_count = 0; + return; + } + + nbuf = os_realloc(sta->ping_trans_id, + (sta->ping_count + 1) * WLAN_PING_TRANS_ID_LEN); + if (nbuf == NULL) + return; + trans_id = nbuf + sta->ping_count * WLAN_PING_TRANS_ID_LEN; + sta->ping_trans_id = nbuf; + sta->ping_count++; + + os_get_random(trans_id, WLAN_PING_TRANS_ID_LEN); + + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "association ping attempt %d", sta->ping_count); + + ieee802_11_send_ping_req(hapd, sta->addr, trans_id); + + timeout = hapd->conf->assoc_ping_timeout; + sec = ((timeout / 1000) * 1024) / 1000; + usec = (timeout % 1000) * 1024; + eloop_register_timeout(sec, usec, ap_ping_timer, hapd, sta); +} + + +void ap_sta_start_ping(struct hostapd_data *hapd, struct sta_info *sta) +{ + ap_ping_timer(hapd, sta); +} + + +void ap_sta_stop_ping(struct hostapd_data *hapd, struct sta_info *sta) +{ + eloop_cancel_timeout(ap_ping_timer, hapd, sta); + os_free(sta->ping_trans_id); + sta->ping_trans_id = NULL; + sta->ping_count = 0; +} + +#endif /* CONFIG_IEEE80211W */ diff --git a/hostapd/sta_info.h b/hostapd/sta_info.h index 1d9ab9687..51770d9bb 100644 --- a/hostapd/sta_info.h +++ b/hostapd/sta_info.h @@ -36,5 +36,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, u16 reason); int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, int old_vlanid); +void ap_sta_start_ping(struct hostapd_data *hapd, struct sta_info *sta); +void ap_sta_stop_ping(struct hostapd_data *hapd, struct sta_info *sta); #endif /* STA_INFO_H */ diff --git a/hostapd/wpa.c b/hostapd/wpa.c index 450280854..a922ae530 100644 --- a/hostapd/wpa.c +++ b/hostapd/wpa.c @@ -1081,6 +1081,8 @@ void wpa_remove_ptk(struct wpa_state_machine *sm) void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) { + int remove_ptk = 1; + if (sm == NULL) return; @@ -1113,11 +1115,18 @@ void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) sm->ft_completed = 0; #endif /* CONFIG_IEEE80211R */ - sm->PTK_valid = FALSE; - os_memset(&sm->PTK, 0, sizeof(sm->PTK)); +#ifdef CONFIG_IEEE80211W + if (sm->mgmt_frame_prot && event == WPA_AUTH) + remove_ptk = 0; +#endif /* CONFIG_IEEE80211W */ - if (event != WPA_REAUTH_EAPOL) - wpa_remove_ptk(sm); + if (remove_ptk) { + sm->PTK_valid = FALSE; + os_memset(&sm->PTK, 0, sizeof(sm->PTK)); + + if (event != WPA_REAUTH_EAPOL) + wpa_remove_ptk(sm); + } wpa_sm_step(sm); } diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index a42cb1a60..0c7759acb 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -218,6 +218,12 @@ #define WLAN_ACTION_FT 6 #define WLAN_ACTION_PING 8 +/* Ping Action frame (IEEE 802.11w/D6.0, 7.4.9) */ +#define WLAN_PING_REQUEST 0 +#define WLAN_PING_RESPONSE 1 + +#define WLAN_PING_TRANS_ID_LEN 16 + #ifdef _MSC_VER #pragma pack(push, 1) @@ -316,11 +322,11 @@ struct ieee80211_mgmt { } STRUCT_PACKED ft_action_resp; struct { u8 action; - u8 transaction_id[16]; + u8 trans_id[WLAN_PING_TRANS_ID_LEN]; } STRUCT_PACKED ping_req; struct { - u8 action; - u8 transaction_id[16]; + u8 action; /* */ + u8 trans_id[WLAN_PING_TRANS_ID_LEN]; } STRUCT_PACKED ping_resp; } u; } STRUCT_PACKED action; diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog index 07dc0f0bc..a7a843cae 100644 --- a/wpa_supplicant/ChangeLog +++ b/wpa_supplicant/ChangeLog @@ -3,6 +3,7 @@ ChangeLog for wpa_supplicant ????-??-?? - v0.6.5 * added support for SHA-256 as X.509 certificate digest when using the internal X.509/TLSv1 implementation + * updated management frame protection to use IEEE 802.11w/D6.0 2008-08-10 - v0.6.4 * added support for EAP Sequences in EAP-FAST Phase 2 diff --git a/wpa_supplicant/mlme.c b/wpa_supplicant/mlme.c index 6f0fdf127..61fec6c8a 100644 --- a/wpa_supplicant/mlme.c +++ b/wpa_supplicant/mlme.c @@ -1814,6 +1814,7 @@ static void ieee80211_rx_mgmt_probe_req(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_IEEE80211R static void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, @@ -1873,6 +1874,78 @@ static void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s, os_memcpy(wpa_s->bssid, target_ap_addr, ETH_ALEN); ieee80211_associate(wpa_s); } +#endif /* CONFIG_IEEE80211R */ + + +#ifdef CONFIG_IEEE80211W + +/* MLME-PING.response */ +static int ieee80211_sta_send_ping_resp(struct wpa_supplicant *wpa_s, + const u8 *addr, const u8 *trans_id) +{ + struct ieee80211_mgmt *mgmt; + int res; + size_t len; + + mgmt = os_zalloc(sizeof(*mgmt)); + if (mgmt == NULL) { + wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " + "ping action frame"); + return -1; + } + + len = 24; + os_memcpy(mgmt->da, addr, 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_PING; + mgmt->u.action.u.ping_resp.action = WLAN_PING_RESPONSE; + os_memcpy(mgmt->u.action.u.ping_resp.trans_id, trans_id, + WLAN_PING_TRANS_ID_LEN); + len += 1 + sizeof(mgmt->u.action.u.ping_resp); + + res = ieee80211_sta_tx(wpa_s, (u8 *) mgmt, len); + os_free(mgmt); + + return res; +} + + +static void ieee80211_rx_mgmt_ping_action( + struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, + struct ieee80211_rx_status *rx_status) +{ + if (len < 24 + 1 + sizeof(mgmt->u.action.u.ping_req)) { + wpa_printf(MSG_DEBUG, "MLME: Too short Ping Action frame"); + return; + } + + if (mgmt->u.action.u.ping_req.action != WLAN_PING_REQUEST) { + wpa_printf(MSG_DEBUG, "MLME: Unexpected Ping Action %d", + mgmt->u.action.u.ping_req.action); + return; + } + + if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "MLME: Ignore ping from unknown source " + MACSTR, MAC2STR(mgmt->sa)); + return; + } + + if (wpa_s->mlme.state == IEEE80211_ASSOCIATE) { + wpa_printf(MSG_DEBUG, "MLME: Ignore ping request during " + "association process"); + return; + } + + wpa_printf(MSG_DEBUG, "MLME: Replying to ping request"); + ieee80211_sta_send_ping_resp(wpa_s, mgmt->sa, + mgmt->u.action.u.ping_req.trans_id); +} + +#endif /* CONFIG_IEEE80211W */ static void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s, @@ -1885,11 +1958,22 @@ static void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s, if (len < 25) return; - if (mgmt->u.action.category == WLAN_ACTION_FT) + switch (mgmt->u.action.category) { +#ifdef CONFIG_IEEE80211R + case WLAN_ACTION_FT: ieee80211_rx_mgmt_ft_action(wpa_s, mgmt, len, rx_status); - else + break; +#endif /* CONFIG_IEEE80211R */ + case WLAN_ACTION_PING: + ieee80211_rx_mgmt_ping_action(wpa_s, mgmt, len, rx_status); + break; +#ifdef CONFIG_IEEE80211W +#endif /* CONFIG_IEEE80211W */ + default: wpa_printf(MSG_DEBUG, "MLME: unknown Action Category %d", mgmt->u.action.category); + break; + } }