IEEE 802.11w: Added association ping
authorJouni Malinen <j@w1.fi>
Sun, 31 Aug 2008 08:04:47 +0000 (11:04 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 31 Aug 2008 08:04:47 +0000 (11:04 +0300)
This updates management frame protection to use the assocition ping process
from the latest draft (D6.0) to protect against unauthenticated
authenticate or (re)associate frames dropping association.

13 files changed:
hostapd/ChangeLog
hostapd/ap.h
hostapd/config.c
hostapd/config.h
hostapd/hostapd.conf
hostapd/ieee802_11.c
hostapd/mlme.c
hostapd/sta_info.c
hostapd/sta_info.h
hostapd/wpa.c
src/common/ieee802_11_defs.h
wpa_supplicant/ChangeLog
wpa_supplicant/mlme.c

index e249ad7..a338cdf 100644 (file)
@@ -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
index 3a00845..340b97c 100644 (file)
@@ -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 */
 };
 
 
index eb247a3..0c251a9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration file
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  * 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) {
index f92ea84..237dec2 100644 (file)
@@ -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;
index 2e4b71c..d369c7c 100644 (file)
@@ -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).
index c07449f..7358c3d 100644 (file)
@@ -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;
index 318ca86..d883931 100644 (file)
@@ -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);
 }
 
index e9c0cc6..855c548 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Station table
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
  * 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 */
index 1d9ab96..51770d9 100644 (file)
@@ -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 */
index 4502808..a922ae5 100644 (file)
@@ -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 (remove_ptk) {
+               sm->PTK_valid = FALSE;
+               os_memset(&sm->PTK, 0, sizeof(sm->PTK));
 
-       if (event != WPA_REAUTH_EAPOL)
-               wpa_remove_ptk(sm);
+               if (event != WPA_REAUTH_EAPOL)
+                       wpa_remove_ptk(sm);
+       }
 
        wpa_sm_step(sm);
 }
index a42cb1a..0c7759a 100644 (file)
 #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;
index 07dc0f0..a7a843c 100644 (file)
@@ -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
index 6f0fdf1..61fec6c 100644 (file)
@@ -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;
+       }
 }