#include "wme.h"
#include "ap_list.h"
#include "accounting.h"
-#include "driver.h"
+#include "driver_i.h"
#include "mlme.h"
struct sta_info *sta, u8 *eid)
{
u8 *pos = eid;
- u32 timeout;
+ u32 timeout, tu;
+ struct os_time now, passed;
*pos++ = WLAN_EID_ASSOC_COMEBACK_TIME;
*pos++ = 4;
- timeout = (hapd->conf->assoc_ping_attempts - sta->ping_count + 1) *
- hapd->conf->assoc_ping_timeout;
+ os_get_time(&now);
+ os_time_sub(&now, &sta->sa_query_start, &passed);
+ tu = (passed.sec * 1000000 + passed.usec) / 1024;
+ if (hapd->conf->assoc_sa_query_max_timeout > tu)
+ timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
+ else
+ timeout = 0;
+ if (timeout < hapd->conf->assoc_sa_query_max_timeout)
+ timeout++; /* add some extra time for local timers */
WPA_PUT_LE32(pos, timeout);
pos += 4;
}
+/**
+ * ieee802_11_send_deauth - Send Deauthentication frame
+ * @hapd: hostapd BSS data
+ * @addr: Address of the destination STA
+ * @reason: Reason code for Deauthentication
+ */
void ieee802_11_send_deauth(struct hostapd_data *hapd, u8 *addr, u16 reason)
{
struct ieee80211_mgmt mgmt;
/* save HT capabilities in the sta object */
os_memset(&sta->ht_capabilities, 0, sizeof(sta->ht_capabilities));
if (elems.ht_capabilities &&
- elems.ht_capabilities_len >= sizeof(struct ieee80211_ht_capability)
- && (sta->flags & WLAN_STA_WME)) {
- /* note: without WMM capability, treat the sta as non-HT */
+ elems.ht_capabilities_len >=
+ sizeof(struct ieee80211_ht_capability)) {
sta->flags |= WLAN_STA_HT;
sta->ht_capabilities.id = WLAN_EID_HT_CAP;
sta->ht_capabilities.length =
wpa_ie_len = 0;
}
#ifdef CONFIG_WPS
+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
if (hapd->conf->wps_state && wpa_ie == NULL) {
if (elems.wps_ie) {
wpa_printf(MSG_DEBUG, "STA included WPS IE in "
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
#ifdef CONFIG_IEEE80211W
else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE; /* FIX */
+ resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE; /* FIX */
+ resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
#endif /* CONFIG_IEEE80211W */
else if (res == WPA_INVALID_MDIE)
resp = WLAN_STATUS_INVALID_MDIE;
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
#ifdef CONFIG_IEEE80211W
- if ((sta->flags & WLAN_STA_MFP) && !sta->ping_timed_out) {
+ if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+ if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
/*
- * 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.
+ * STA has already been associated with MFP and SA
+ * Query timeout has not been reached. Reject the
+ * association attempt temporarily and start SA Query,
+ * if one is not pending.
*/
- if (sta->ping_count == 0)
- ap_sta_start_ping(hapd, sta);
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
goto fail;
goto fail;
}
#endif /* CONFIG_IEEE80211R */
- }
+#ifdef CONFIG_IEEE80211N
+ if ((sta->flags & WLAN_STA_HT) &&
+ wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
+ wpa_printf(MSG_DEBUG, "HT: " MACSTR " tried to "
+ "use TKIP with HT association",
+ MAC2STR(sta->addr));
+ resp = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+ goto fail;
+ }
+#endif /* CONFIG_IEEE80211N */
+ } else
+ wpa_auth_sta_no_wpa(sta->wpa_sm);
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
sta->flags |= WLAN_STA_NONERP;
wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities "
"Info: 0x%04x", MAC2STR(sta->addr), ht_capab);
if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) {
- hapd->iface->num_sta_ht_no_gf++;
+ if (!sta->no_ht_gf_set) {
+ sta->no_ht_gf_set = 1;
+ hapd->iface->num_sta_ht_no_gf++;
+ }
wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no "
"greenfield, num of non-gf stations %d",
__func__, MAC2STR(sta->addr),
hapd->iface->num_sta_ht_no_gf);
}
if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) {
- hapd->iface->num_sta_ht_20mhz++;
+ if (!sta->ht_20mhz_set) {
+ sta->ht_20mhz_set = 1;
+ hapd->iface->num_sta_ht_20mhz++;
+ }
wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, "
"num of 20MHz HT STAs %d",
__func__, MAC2STR(sta->addr),
hapd->iface->num_sta_ht_20mhz);
}
} else {
- hapd->iface->num_sta_no_ht++;
+ if (!sta->no_ht_set) {
+ sta->no_ht_set = 1;
+ hapd->iface->num_sta_no_ht++;
+ }
if (hapd->iconf->ieee80211n) {
wpa_printf(MSG_DEBUG, "%s STA " MACSTR
" - no HT, num of non-HT stations %d",
/* Station will be marked associated, after it acknowledges AssocResp
*/
+#ifdef CONFIG_IEEE80211W
+ if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
+ wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
+ "SA Query procedure", reassoc ? "re" : "");
+ /* TODO: Send a protected Disassociate frame to the STA using
+ * the old key and Reason Code "Previous Authentication no
+ * longer valid". Make sure this is only sent protected since
+ * unprotected frame would be received by the STA that is now
+ * trying to associate.
+ */
+ }
+#endif /* CONFIG_IEEE80211W */
+
if (reassoc) {
os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap,
ETH_ALEN);
#ifdef CONFIG_IEEE80211W
-static void hostapd_ping_action(struct hostapd_data *hapd,
- struct ieee80211_mgmt *mgmt, size_t len)
+
+/* MLME-SAQuery.request */
+void ieee802_11_send_sa_query_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_SA_QUERY;
+ mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+ os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+ WLAN_SA_QUERY_TR_ID_LEN);
+ end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+ if (hostapd_send_mgmt_frame(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
+ perror("ieee802_11_send_sa_query_req: send");
+}
+
+
+static void hostapd_sa_query_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;
+ end = mgmt->u.action.u.sa_query_resp.trans_id +
+ WLAN_SA_QUERY_TR_ID_LEN;
if (((u8 *) mgmt) + len < end) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short Ping Action "
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query 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);
+ if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
+ "Action %d", mgmt->u.action.u.sa_query_resp.action);
return;
}
- /* MLME-PING.confirm */
+ /* MLME-SAQuery.confirm */
sta = ap_get_sta(hapd, mgmt->sa);
- if (sta == NULL || sta->ping_trans_id == NULL) {
+ if (sta == NULL || sta->sa_query_trans_id == NULL) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
- "pending ping request found");
+ "pending SA Query 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)
+ for (i = 0; i < sta->sa_query_count; i++) {
+ if (os_memcmp(sta->sa_query_trans_id +
+ i * WLAN_SA_QUERY_TR_ID_LEN,
+ mgmt->u.action.u.sa_query_resp.trans_id,
+ WLAN_SA_QUERY_TR_ID_LEN) == 0)
break;
}
- if (i >= sta->ping_count) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching ping "
+ if (i >= sta->sa_query_count) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
"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);
+ HOSTAPD_LEVEL_DEBUG,
+ "Reply to pending SA Query received");
+ ap_sta_stop_sa_query(hapd, sta);
}
#endif /* CONFIG_IEEE80211W */
hostapd_wme_action(hapd, mgmt, len);
return;
#ifdef CONFIG_IEEE80211W
- case WLAN_ACTION_PING:
- hostapd_ping_action(hapd, mgmt, len);
+ case WLAN_ACTION_SA_QUERY:
+ hostapd_sa_query_action(hapd, mgmt, len);
return;
#endif /* CONFIG_IEEE80211W */
}
* @buf: management frame data (starting from IEEE 802.11 header)
* @len: length of frame data in octets
* @stype: management frame subtype from frame control field
+ * @fi: meta data about received frame (signal level, etc.)
*
* Process all incoming IEEE 802.11 management frames. This will be called for
* each frame received from the kernel driver through wlan#ap interface. In
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211W
- sta->ping_timed_out = 0;
+ sta->sa_query_timed_out = 0;
#endif /* CONFIG_IEEE80211W */
if (hostapd_sta_add(hapd->conf->iface, hapd, sta->addr, sta->aid,
}
+/**
+ * ieee802_11_mgmt_cb - Process management frame TX status callback
+ * @hapd: hostapd BSS data structure (the BSS from which the management frame
+ * was sent from)
+ * @buf: management frame data (starting from IEEE 802.11 header)
+ * @len: length of frame data in octets
+ * @stype: management frame subtype from frame control field
+ * @ok: Whether the frame was ACK'ed
+ */
void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len,
u16 stype, int ok)
{
}
-static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx,
- void *timeout_ctx)
-{
- struct hostapd_data *hapd = eloop_ctx;
- hapd->tkip_countermeasures = 0;
- hostapd_set_countermeasures(hapd, 0);
- hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended");
-}
-
-
-static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
-{
- struct sta_info *sta;
-
- hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "TKIP countermeasures initiated");
-
- wpa_auth_countermeasures_start(hapd->wpa_auth);
- hapd->tkip_countermeasures = 1;
- hostapd_set_countermeasures(hapd, 1);
- wpa_gtk_rekey(hapd->wpa_auth);
- eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
- eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
- hapd, NULL);
- for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
- hostapd_sta_deauth(hapd, sta->addr,
- WLAN_REASON_MICHAEL_MIC_FAILURE);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
- WLAN_STA_AUTHORIZED);
- hostapd_sta_remove(hapd, sta->addr);
- }
-}
-
-
-void ieee80211_michael_mic_failure(struct hostapd_data *hapd, const u8 *addr,
- int local)
-{
- time_t now;
-
- if (addr && local) {
- struct sta_info *sta = ap_get_sta(hapd, addr);
- if (sta != NULL) {
- wpa_auth_sta_local_mic_failure_report(sta->wpa_sm);
- hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO,
- "Michael MIC failure detected in "
- "received frame");
- mlme_michaelmicfailure_indication(hapd, addr);
- } else {
- wpa_printf(MSG_DEBUG,
- "MLME-MICHAELMICFAILURE.indication "
- "for not associated STA (" MACSTR
- ") ignored", MAC2STR(addr));
- return;
- }
- }
-
- time(&now);
- if (now > hapd->michael_mic_failure + 60) {
- hapd->michael_mic_failures = 1;
- } else {
- hapd->michael_mic_failures++;
- if (hapd->michael_mic_failures > 1)
- ieee80211_tkip_countermeasures_start(hapd);
- }
- hapd->michael_mic_failure = now;
-}
-
-
int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
{
/* TODO */