aboutsummaryrefslogtreecommitdiffstats
path: root/hostapd
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2008-08-31 11:04:47 +0300
committerJouni Malinen <j@w1.fi>2008-08-31 11:04:47 +0300
commit5d22a1d5aaa7bafdbb3180c3cfec4868b347a86a (patch)
tree7b32a6411c0176f141c45d922004b9d9236184af /hostapd
parent1e858f69d9c4386467e57452c3ada245a00fd172 (diff)
downloadexternal_wpa_supplicant_8_ti-5d22a1d5aaa7bafdbb3180c3cfec4868b347a86a.zip
external_wpa_supplicant_8_ti-5d22a1d5aaa7bafdbb3180c3cfec4868b347a86a.tar.gz
external_wpa_supplicant_8_ti-5d22a1d5aaa7bafdbb3180c3cfec4868b347a86a.tar.bz2
IEEE 802.11w: Added association ping
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.
Diffstat (limited to 'hostapd')
-rw-r--r--hostapd/ChangeLog3
-rw-r--r--hostapd/ap.h8
-rw-r--r--hostapd/config.c22
-rw-r--r--hostapd/config.h4
-rw-r--r--hostapd/hostapd.conf11
-rw-r--r--hostapd/ieee802_11.c103
-rw-r--r--hostapd/mlme.c2
-rw-r--r--hostapd/sta_info.c95
-rw-r--r--hostapd/sta_info.h2
-rw-r--r--hostapd/wpa.c17
10 files changed, 257 insertions, 10 deletions
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index e249ad7..a338cdf 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 3a00845..340b97c 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 eb247a3..0c251a9 100644
--- a/hostapd/config.c
+++ b/hostapd/config.c
@@ -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) {
diff --git a/hostapd/config.h b/hostapd/config.h
index f92ea84..237dec2 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 2e4b71c..d369c7c 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 c07449f..7358c3d 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 318ca86..d883931 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 e9c0cc6..855c548 100644
--- a/hostapd/sta_info.c
+++ b/hostapd/sta_info.c
@@ -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 */
diff --git a/hostapd/sta_info.h b/hostapd/sta_info.h
index 1d9ab96..51770d9 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 4502808..a922ae5 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 (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);
}