#include "wme.h"
#include "ap_list.h"
#include "accounting.h"
-#include "driver.h"
+#include "driver_i.h"
#include "mlme.h"
u32 timeout, tu;
struct os_time now, passed;
- *pos++ = WLAN_EID_ASSOC_COMEBACK_TIME;
- *pos++ = 4;
+ *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+ *pos++ = 5;
+ *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
os_get_time(&now);
os_time_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
}
+/**
+ * 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;
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
if (hostapd_send_mgmt_frame(hapd, &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth), 0) < 0)
+ sizeof(mgmt.u.deauth)) < 0)
perror("ieee802_11_send_deauth: send");
}
" auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
MAC2STR(dst), auth_alg, auth_transaction,
resp, (unsigned long) ies_len);
- if (hostapd_send_mgmt_frame(hapd, reply, rlen, 0) < 0)
+ if (hostapd_send_mgmt_frame(hapd, reply, rlen) < 0)
perror("send_auth_reply: send");
os_free(buf);
}
+static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ int i, j = 32, aid;
+
+ /* get a unique AID */
+ if (sta->aid > 0) {
+ wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
+ return 0;
+ }
+
+ for (i = 0; i < AID_WORDS; i++) {
+ if (hapd->sta_aid[i] == (u32) -1)
+ continue;
+ for (j = 0; j < 32; j++) {
+ if (!(hapd->sta_aid[i] & BIT(j)))
+ break;
+ }
+ if (j < 32)
+ break;
+ }
+ if (j == 32)
+ return -1;
+ aid = i * 32 + j + 1;
+ if (aid > 2007)
+ return -1;
+
+ sta->aid = aid;
+ hapd->sta_aid[i] |= BIT(j);
+ wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
+ return 0;
+}
+
+
static void handle_assoc(struct hostapd_data *hapd,
struct ieee80211_mgmt *mgmt, size_t len, int reassoc)
{
int send_deauth = 0, send_len, left, i;
struct sta_info *sta;
struct ieee802_11_elems elems;
- u8 buf[sizeof(struct ieee80211_mgmt) + 512];
+ u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
struct ieee80211_mgmt *reply;
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
goto fail;
}
- sta->flags &= ~WLAN_STA_WME;
- if (elems.wme && hapd->conf->wme_enabled) {
- if (hostapd_eid_wme_valid(hapd, elems.wme, elems.wme_len))
+ sta->flags &= ~WLAN_STA_WMM;
+ if (elems.wmm && hapd->conf->wmm_enabled) {
+ if (hostapd_eid_wmm_valid(hapd, elems.wmm, elems.wmm_len))
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
- "invalid WME element in association "
+ "invalid WMM element in association "
"request");
else
- sta->flags |= WLAN_STA_WME;
+ sta->flags |= WLAN_STA_WMM;
}
if (!elems.supp_rates) {
ieee802_11_set_beacons(hapd->iface);
#endif /* CONFIG_IEEE80211N */
- /* get a unique AID */
- if (sta->aid > 0) {
- wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
- } else {
- for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++)
- if (hapd->sta_aid[sta->aid - 1] == NULL)
- break;
- if (sta->aid > MAX_AID_TABLE_SIZE) {
- sta->aid = 0;
- resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
- wpa_printf(MSG_ERROR, " no room for more AIDs");
- goto fail;
- } else {
- hapd->sta_aid[sta->aid - 1] = sta;
- wpa_printf(MSG_DEBUG, " new AID %d", sta->aid);
- }
+ if (hostapd_get_aid(hapd, sta) < 0) {
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ wpa_printf(MSG_ERROR, " no room for more AIDs");
+ goto fail;
}
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
/* Extended supported rates */
p = hostapd_eid_ext_supp_rates(hapd, p);
- if (sta->flags & WLAN_STA_WME)
- p = hostapd_eid_wme(hapd, p);
+ if (sta->flags & WLAN_STA_WMM)
+ p = hostapd_eid_wmm(hapd, p);
p = hostapd_eid_ht_capabilities_info(hapd, p);
p = hostapd_eid_ht_operation(hapd, p);
#ifdef CONFIG_IEEE80211R
if (resp == WLAN_STATUS_SUCCESS) {
/* IEEE 802.11r: Mobility Domain Information, Fast BSS
- * Transition Information, RSN */
+ * Transition Information, RSN, [RIC Response] */
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
buf + sizeof(buf) - p,
- sta->auth_alg);
+ sta->auth_alg,
+ pos, left);
}
#endif /* CONFIG_IEEE80211R */
send_len += p - reply->u.assoc_resp.variable;
}
- if (hostapd_send_mgmt_frame(hapd, reply, send_len, 0) < 0)
+ if (hostapd_send_mgmt_frame(hapd, reply, send_len) < 0)
perror("handle_assoc: send");
}
#ifdef CONFIG_IEEE80211W
+
+/* 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;
+
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
+ MACSTR, MAC2STR(addr));
+ wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+ trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+ 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)
+ 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)
{
return;
}
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
+ MACSTR, MAC2STR(mgmt->sa));
+ wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+ mgmt->u.action.u.sa_query_resp.trans_id,
+ WLAN_SA_QUERY_TR_ID_LEN);
+
/* MLME-SAQuery.confirm */
sta = ap_get_sta(hapd, mgmt->sa);
"Reply to pending SA Query received");
ap_sta_stop_sa_query(hapd, sta);
}
+
+
+static int robust_action_frame(u8 category)
+{
+ return category != WLAN_ACTION_PUBLIC &&
+ category != WLAN_ACTION_HT;
+}
#endif /* CONFIG_IEEE80211W */
static void handle_action(struct hostapd_data *hapd,
struct ieee80211_mgmt *mgmt, size_t len)
{
+ struct sta_info *sta;
+
if (len < IEEE80211_HDRLEN + 1) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
return;
}
+ sta = ap_get_sta(hapd, mgmt->sa);
+#ifdef CONFIG_IEEE80211W
+ if (sta && (sta->flags & WLAN_STA_MFP) &&
+ !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
+ robust_action_frame(mgmt->u.action.category))) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Dropped unprotected Robust Action frame from "
+ "an MFP STA");
+ return;
+ }
+#endif /* CONFIG_IEEE80211W */
+
switch (mgmt->u.action.category) {
#ifdef CONFIG_IEEE80211R
case WLAN_ACTION_FT:
{
- struct sta_info *sta;
-
- sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action "
"frame from unassociated STA " MACSTR,
}
#endif /* CONFIG_IEEE80211R */
case WLAN_ACTION_WMM:
- hostapd_wme_action(hapd, mgmt, len);
+ hostapd_wmm_action(hapd, mgmt, len);
return;
#ifdef CONFIG_IEEE80211W
case WLAN_ACTION_SA_QUERY:
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
mgmt->u.action.category |= 0x80;
- hostapd_send_mgmt_frame(hapd, mgmt, len, 0);
+ hostapd_send_mgmt_frame(hapd, mgmt, len);
}
}
* @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
return;
}
- if (fi && fi->passive_scan)
- return;
-
broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff &&
mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
}
+#ifdef CONFIG_IEEE80211N
+static void
+hostapd_get_ht_capab(struct hostapd_data *hapd,
+ struct ht_cap_ie *ht_cap_ie,
+ struct ht_cap_ie *neg_ht_cap_ie)
+{
+
+ os_memcpy(neg_ht_cap_ie, ht_cap_ie, sizeof(struct ht_cap_ie));
+ neg_ht_cap_ie->data.capabilities_info =
+ ht_cap_ie->data.capabilities_info & hapd->iconf->ht_capab;
+
+ neg_ht_cap_ie->data.capabilities_info &= ~HT_CAP_INFO_SMPS_DISABLED;
+ if ((ht_cap_ie->data.capabilities_info & HT_CAP_INFO_SMPS_DISABLED) ==
+ (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED))
+ neg_ht_cap_ie->data.capabilities_info |=
+ hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED;
+ else
+ neg_ht_cap_ie->data.capabilities_info |=
+ HT_CAP_INFO_SMPS_DISABLED;
+
+ /* FIXME: Rx STBC needs to be handled specially */
+ neg_ht_cap_ie->data.capabilities_info &= ~HT_CAP_INFO_RX_STBC_MASK;
+ neg_ht_cap_ie->data.capabilities_info |=
+ hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
static void handle_assoc_cb(struct hostapd_data *hapd,
struct ieee80211_mgmt *mgmt,
size_t len, int reassoc, int ok)
u16 status;
struct sta_info *sta;
int new_assoc = 1;
- struct ht_cap_ie *ht_cap = NULL;
+#ifdef CONFIG_IEEE80211N
+ struct ht_cap_ie ht_cap;
+#endif /* CONFIG_IEEE80211N */
+ struct ht_cap_ie *ht_cap_ptr = NULL;
+ int set_flags, flags_and, flags_or;
if (!ok) {
hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
if (sta->flags & WLAN_STA_ASSOC)
new_assoc = 0;
sta->flags |= WLAN_STA_ASSOC;
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
+ /* Open or static WEP; no separate authorization */
+ sta->flags |= WLAN_STA_AUTHORIZED;
+ }
if (reassoc)
mlme_reassociate_indication(hapd, sta);
mlme_associate_indication(hapd, sta);
#ifdef CONFIG_IEEE80211N
- if (sta->flags & WLAN_STA_HT)
- ht_cap = &sta->ht_capabilities;
+ if (sta->flags & WLAN_STA_HT) {
+ ht_cap_ptr = &ht_cap;
+ hostapd_get_ht_capab(hapd, &sta->ht_capabilities, ht_cap_ptr);
+ }
#endif /* CONFIG_IEEE80211N */
#ifdef 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,
- ht_cap))
+ ht_cap_ptr))
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
ap_sta_bind_vlan(hapd, sta, 0);
}
- if (sta->flags & WLAN_STA_SHORT_PREAMBLE) {
- hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
- WLAN_STA_SHORT_PREAMBLE, ~0);
- } else {
- hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
- 0, ~WLAN_STA_SHORT_PREAMBLE);
- }
+
+ set_flags = WLAN_STA_SHORT_PREAMBLE | WLAN_STA_WMM | WLAN_STA_MFP;
+ flags_or = sta->flags & set_flags;
+ flags_and = sta->flags | ~set_flags;
+ hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
+ flags_or, flags_and);
if (sta->auth_alg == WLAN_AUTH_FT)
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
}
+/**
+ * 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 */