aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2009-11-29 20:14:57 (GMT)
committerJouni Malinen <j@w1.fi>2009-11-29 20:14:57 (GMT)
commit5586f500a0c58b457e512ac01a2a316657474a15 (patch)
treef21be6840ea1e5bd5df82e1eacdc4d3c82c6886b
parent9294bfefc749c617463720153417135f49e82441 (diff)
downloadhostap-5586f500a0c58b457e512ac01a2a316657474a15.zip
hostap-5586f500a0c58b457e512ac01a2a316657474a15.tar.gz
hostap-5586f500a0c58b457e512ac01a2a316657474a15.tar.bz2
Split handle_assoc() into number of helper functions
-rw-r--r--hostapd/ieee802_11.c627
1 files changed, 368 insertions, 259 deletions
diff --git a/hostapd/ieee802_11.c b/hostapd/ieee802_11.c
index ed0bdd3..b92065e 100644
--- a/hostapd/ieee802_11.c
+++ b/hostapd/ieee802_11.c
@@ -700,110 +700,33 @@ static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
}
-static void handle_assoc(struct hostapd_data *hapd,
- struct ieee80211_mgmt *mgmt, size_t len, int reassoc)
+static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ssid_ie, size_t ssid_ie_len)
{
- u16 capab_info, listen_interval;
- u16 resp = WLAN_STATUS_SUCCESS;
- u8 *pos, *wpa_ie;
- size_t wpa_ie_len;
- int send_deauth = 0, send_len, left, i;
- struct sta_info *sta;
- struct ieee802_11_elems elems;
- u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
- struct ieee80211_mgmt *reply;
-
- if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
- sizeof(mgmt->u.assoc_req))) {
- printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
- "\n", reassoc, (unsigned long) len);
- return;
- }
-
- if (reassoc) {
- capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
- listen_interval = le_to_host16(
- mgmt->u.reassoc_req.listen_interval);
- wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
- " capab_info=0x%02x listen_interval=%d current_ap="
- MACSTR,
- MAC2STR(mgmt->sa), capab_info, listen_interval,
- MAC2STR(mgmt->u.reassoc_req.current_ap));
- left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
- pos = mgmt->u.reassoc_req.variable;
- } else {
- capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
- listen_interval = le_to_host16(
- mgmt->u.assoc_req.listen_interval);
- wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
- " capab_info=0x%02x listen_interval=%d",
- MAC2STR(mgmt->sa), capab_info, listen_interval);
- left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
- pos = mgmt->u.assoc_req.variable;
- }
-
- sta = ap_get_sta(hapd, mgmt->sa);
-#ifdef CONFIG_IEEE80211R
- if (sta && sta->auth_alg == WLAN_AUTH_FT &&
- (sta->flags & WLAN_STA_AUTH) == 0) {
- wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
- "prior to authentication since it is using "
- "over-the-DS FT", MAC2STR(mgmt->sa));
- } else
-#endif /* CONFIG_IEEE80211R */
- if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
- printf("STA " MACSTR " trying to associate before "
- "authentication\n", MAC2STR(mgmt->sa));
- if (sta) {
- printf(" sta: addr=" MACSTR " aid=%d flags=0x%04x\n",
- MAC2STR(sta->addr), sta->aid, sta->flags);
- }
- send_deauth = 1;
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- if (hapd->tkip_countermeasures) {
- resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
- goto fail;
- }
+ if (ssid_ie == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (listen_interval > hapd->conf->max_listen_interval) {
- hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG,
- "Too large Listen Interval (%d)",
- listen_interval);
- resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
- goto fail;
+ if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
+ os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
+ char ssid_txt[33];
+ ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len);
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Station tried to associate with unknown SSID "
+ "'%s'", ssid_txt);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- sta->capability = capab_info;
- sta->listen_interval = listen_interval;
-
- /* followed by SSID and Supported rates; and HT capabilities if 802.11n
- * is used */
- if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed ||
- !elems.ssid) {
- printf("STA " MACSTR " sent invalid association request\n",
- MAC2STR(sta->addr));
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
+ return WLAN_STATUS_SUCCESS;
+}
- if (elems.ssid_len != hapd->conf->ssid.ssid_len ||
- os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) != 0)
- {
- char ssid_txt[33];
- ieee802_11_print_ssid(ssid_txt, elems.ssid, elems.ssid_len);
- printf("Station " MACSTR " tried to associate with "
- "unknown SSID '%s'\n", MAC2STR(sta->addr), ssid_txt);
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
+static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *wmm_ie, size_t wmm_ie_len)
+{
sta->flags &= ~WLAN_STA_WMM;
- if (elems.wmm && hapd->conf->wmm_enabled) {
- if (hostapd_eid_wmm_valid(hapd, elems.wmm, elems.wmm_len))
+ if (wmm_ie && hapd->conf->wmm_enabled) {
+ if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len))
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
@@ -812,73 +735,183 @@ static void handle_assoc(struct hostapd_data *hapd,
else
sta->flags |= WLAN_STA_WMM;
}
+ return WLAN_STATUS_SUCCESS;
+}
- if (!elems.supp_rates) {
- hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+
+static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
+ struct ieee802_11_elems *elems)
+{
+ if (!elems->supp_rates) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"No supported rates element in AssocReq");
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (elems.supp_rates_len > sizeof(sta->supported_rates)) {
- hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ if (elems->supp_rates_len > sizeof(sta->supported_rates)) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"Invalid supported rates element length %d",
- elems.supp_rates_len);
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
+ elems->supp_rates_len);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
os_memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
- os_memcpy(sta->supported_rates, elems.supp_rates,
- elems.supp_rates_len);
- sta->supported_rates_len = elems.supp_rates_len;
+ os_memcpy(sta->supported_rates, elems->supp_rates,
+ elems->supp_rates_len);
+ sta->supported_rates_len = elems->supp_rates_len;
- if (elems.ext_supp_rates) {
- if (elems.supp_rates_len + elems.ext_supp_rates_len >
+ if (elems->ext_supp_rates) {
+ if (elems->supp_rates_len + elems->ext_supp_rates_len >
sizeof(sta->supported_rates)) {
- hostapd_logger(hapd, mgmt->sa,
+ hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"Invalid supported rates element length"
- " %d+%d", elems.supp_rates_len,
- elems.ext_supp_rates_len);
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
+ " %d+%d", elems->supp_rates_len,
+ elems->ext_supp_rates_len);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- os_memcpy(sta->supported_rates + elems.supp_rates_len,
- elems.ext_supp_rates, elems.ext_supp_rates_len);
- sta->supported_rates_len += elems.ext_supp_rates_len;
+ os_memcpy(sta->supported_rates + elems->supp_rates_len,
+ elems->ext_supp_rates, elems->ext_supp_rates_len);
+ sta->supported_rates_len += elems->ext_supp_rates_len;
}
+ return WLAN_STATUS_SUCCESS;
+}
+
+
#ifdef CONFIG_IEEE80211N
- /* save HT capabilities in the sta object */
- if (elems.ht_capabilities &&
- elems.ht_capabilities_len >=
- sizeof(struct ieee80211_ht_capabilities)) {
- if (sta->ht_capabilities) {
- os_memset(sta->ht_capabilities, 0,
- sizeof(*sta->ht_capabilities));
- } else {
- sta->ht_capabilities =
- os_zalloc(sizeof(*sta->ht_capabilities));
- if (sta->ht_capabilities == NULL) {
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
- }
- sta->flags |= WLAN_STA_HT;
- os_memcpy(sta->ht_capabilities, elems.ht_capabilities,
- sizeof(struct ieee80211_ht_capabilities));
- } else {
+
+static u16 copy_sta_ht_capab(struct sta_info *sta, const u8 *ht_capab,
+ size_t ht_capab_len)
+{
+ if (!ht_capab ||
+ ht_capab_len < sizeof(struct ieee80211_ht_capabilities)) {
sta->flags &= ~WLAN_STA_HT;
os_free(sta->ht_capabilities);
sta->ht_capabilities = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (sta->ht_capabilities == NULL) {
+ sta->ht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_ht_capabilities));
+ if (sta->ht_capabilities == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
+
+ sta->flags |= WLAN_STA_HT;
+ os_memcpy(sta->ht_capabilities, ht_capab,
+ sizeof(struct ieee80211_ht_capabilities));
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ u16 ht_capab;
+
+ ht_capab = le_to_host16(sta->ht_capabilities->ht_capabilities_info);
+ 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) {
+ 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) {
+ 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);
+ }
+}
+
+
+static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ 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",
+ __func__, MAC2STR(sta->addr),
+ hapd->iface->num_sta_no_ht);
+ }
+}
+
+
+static void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities)
+ update_sta_ht(hapd, sta);
+ else
+ update_sta_no_ht(hapd, sta);
+
+ if (hostapd_ht_operation_update(hapd->iface) > 0)
+ ieee802_11_set_beacons(hapd->iface);
+}
+
+#else /* CONFIG_IEEE80211N */
+
+static u16 copy_sta_ht_capab(struct sta_info *sta, const u8 *ht_capab,
+ size_t ht_capab_len)
+{
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
+{
+}
+
#endif /* CONFIG_IEEE80211N */
+
+static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
+ u8 *ies, size_t ies_len, int reassoc)
+{
+ struct ieee802_11_elems elems;
+ u16 resp;
+ u8 *wpa_ie;
+ size_t wpa_ie_len;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "Station sent an invalid "
+ "association request");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ resp = copy_supp_rates(hapd, sta, &elems);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ resp = copy_sta_ht_capab(sta, elems.ht_capabilities,
+ elems.ht_capabilities_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+
if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
wpa_ie = elems.rsn_ie;
wpa_ie_len = elems.rsn_ie_len;
@@ -890,6 +923,7 @@ static void handle_assoc(struct hostapd_data *hapd,
wpa_ie = NULL;
wpa_ie_len = 0;
}
+
#ifdef CONFIG_WPS
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
if (hapd->conf->wps_state && wpa_ie == NULL) {
@@ -910,10 +944,10 @@ static void handle_assoc(struct hostapd_data *hapd,
} else
#endif /* CONFIG_WPS */
if (hapd->conf->wpa && wpa_ie == NULL) {
- printf("STA " MACSTR ": No WPA/RSN IE in association "
- "request\n", MAC2STR(sta->addr));
- resp = WLAN_STATUS_INVALID_IE;
- goto fail;
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "No WPA/RSN IE in association request");
+ return WLAN_STATUS_INVALID_IE;
}
if (hapd->conf->wpa && wpa_ie) {
@@ -924,9 +958,9 @@ static void handle_assoc(struct hostapd_data *hapd,
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr);
if (sta->wpa_sm == NULL) {
- printf("Failed to initialize WPA state machine\n");
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
+ wpa_printf(MSG_WARNING, "Failed to initialize WPA "
+ "state machine");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
wpa_ie, wpa_ie_len,
@@ -950,7 +984,7 @@ static void handle_assoc(struct hostapd_data *hapd,
else if (res != WPA_IE_OK)
resp = WLAN_STATUS_INVALID_IE;
if (resp != WLAN_STATUS_SUCCESS)
- goto fail;
+ return resp;
#ifdef CONFIG_IEEE80211W
if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
sta->sa_query_count > 0)
@@ -967,8 +1001,7 @@ static void handle_assoc(struct hostapd_data *hapd,
if (sta->sa_query_count == 0)
ap_sta_start_sa_query(hapd, sta);
- resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
- goto fail;
+ return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
}
if (wpa_auth_uses_mfp(sta->wpa_sm))
@@ -984,28 +1017,204 @@ static void handle_assoc(struct hostapd_data *hapd,
"to use association (not "
"re-association) with FT auth_alg",
MAC2STR(sta->addr));
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- resp = wpa_ft_validate_reassoc(sta->wpa_sm, pos, left);
+ resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
+ ies_len);
if (resp != WLAN_STATUS_SUCCESS)
- goto fail;
+ return resp;
}
#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;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Station tried to use TKIP with HT "
+ "association");
+ return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
}
#endif /* CONFIG_IEEE80211N */
} else
wpa_auth_sta_no_wpa(sta->wpa_sm);
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
+ u16 reason_code)
+{
+ int send_len;
+ struct ieee80211_mgmt reply;
+
+ os_memset(&reply, 0, sizeof(reply));
+ reply.frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
+ os_memcpy(reply.da, addr, ETH_ALEN);
+ os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
+
+ send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
+ reply.u.deauth.reason_code = host_to_le16(reason_code);
+
+ if (hostapd_send_mgmt_frame(hapd, &reply, send_len) < 0)
+ wpa_printf(MSG_INFO, "Failed to send deauth: %s",
+ strerror(errno));
+}
+
+
+static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
+ u16 status_code, int reassoc, u8 *ies,
+ size_t ies_len)
+{
+ int send_len;
+ u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+ struct ieee80211_mgmt *reply;
+ u8 *p;
+
+ os_memset(buf, 0, sizeof(buf));
+ reply = (struct ieee80211_mgmt *) buf;
+ reply->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
+ WLAN_FC_STYPE_ASSOC_RESP));
+ os_memcpy(reply->da, sta->addr, ETH_ALEN);
+ os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
+
+ send_len = IEEE80211_HDRLEN;
+ send_len += sizeof(reply->u.assoc_resp);
+ reply->u.assoc_resp.capab_info =
+ host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
+ reply->u.assoc_resp.status_code = host_to_le16(status_code);
+ reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
+ | BIT(14) | BIT(15));
+ /* Supported rates */
+ 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_WMM)
+ p = hostapd_eid_wmm(hapd, p);
+
+ p = hostapd_eid_ht_capabilities(hapd, p);
+ p = hostapd_eid_ht_operation(hapd, p);
+
+#ifdef CONFIG_IEEE80211R
+ if (status_code == WLAN_STATUS_SUCCESS) {
+ /* IEEE 802.11r: Mobility Domain Information, Fast BSS
+ * Transition Information, RSN, [RIC Response] */
+ p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
+ buf + sizeof(buf) - p,
+ sta->auth_alg, ies, ies_len);
+ }
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+ if (status_code == 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;
+
+ if (hostapd_send_mgmt_frame(hapd, reply, send_len) < 0)
+ wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
+ strerror(errno));
+}
+
+
+static void handle_assoc(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt, size_t len, int reassoc)
+{
+ u16 capab_info, listen_interval;
+ u16 resp = WLAN_STATUS_SUCCESS;
+ u8 *pos;
+ int left, i;
+ struct sta_info *sta;
+
+ if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
+ sizeof(mgmt->u.assoc_req))) {
+ printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
+ "\n", reassoc, (unsigned long) len);
+ return;
+ }
+
+ if (reassoc) {
+ capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
+ listen_interval = le_to_host16(
+ mgmt->u.reassoc_req.listen_interval);
+ wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
+ " capab_info=0x%02x listen_interval=%d current_ap="
+ MACSTR,
+ MAC2STR(mgmt->sa), capab_info, listen_interval,
+ MAC2STR(mgmt->u.reassoc_req.current_ap));
+ left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
+ pos = mgmt->u.reassoc_req.variable;
+ } else {
+ capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
+ listen_interval = le_to_host16(
+ mgmt->u.assoc_req.listen_interval);
+ wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
+ " capab_info=0x%02x listen_interval=%d",
+ MAC2STR(mgmt->sa), capab_info, listen_interval);
+ left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
+ pos = mgmt->u.assoc_req.variable;
+ }
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+#ifdef CONFIG_IEEE80211R
+ if (sta && sta->auth_alg == WLAN_AUTH_FT &&
+ (sta->flags & WLAN_STA_AUTH) == 0) {
+ wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
+ "prior to authentication since it is using "
+ "over-the-DS FT", MAC2STR(mgmt->sa));
+ } else
+#endif /* CONFIG_IEEE80211R */
+ if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "Station tried to "
+ "associate before authentication "
+ "(aid=%d flags=0x%x)",
+ sta ? sta->aid : -1,
+ sta ? sta->flags : 0);
+ send_deauth(hapd, mgmt->sa,
+ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+ return;
+ }
+
+ if (hapd->tkip_countermeasures) {
+ resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+ goto fail;
+ }
+
+ if (listen_interval > hapd->conf->max_listen_interval) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Too large Listen Interval (%d)",
+ listen_interval);
+ resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
+ goto fail;
+ }
+
+ /* followed by SSID and Supported rates; and HT capabilities if 802.11n
+ * is used */
+ resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
+ if (resp != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+ if (hostapd_get_aid(hapd, sta) < 0) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "No room for more AIDs");
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
+
+ sta->capability = capab_info;
+ sta->listen_interval = listen_interval;
+
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
sta->flags |= WLAN_STA_NONERP;
for (i = 0; i < sta->supported_rates_len; i++) {
@@ -1045,54 +1254,7 @@ static void handle_assoc(struct hostapd_data *hapd,
ieee802_11_set_beacons(hapd->iface);
}
- 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;
- }
-
-#ifdef CONFIG_IEEE80211N
- if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
- u16 ht_capab = le_to_host16(
- sta->ht_capabilities->ht_capabilities_info);
- 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) {
- 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) {
- 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 {
- 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",
- __func__, MAC2STR(sta->addr),
- hapd->iface->num_sta_no_ht);
- }
- }
-
- if (hostapd_ht_operation_update(hapd->iface) > 0)
- ieee802_11_set_beacons(hapd->iface);
-#endif /* CONFIG_IEEE80211N */
+ update_ht_state(hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -1129,60 +1291,7 @@ static void handle_assoc(struct hostapd_data *hapd,
sta->timeout_next = STA_NULLFUNC;
fail:
- os_memset(buf, 0, sizeof(buf));
- reply = (struct ieee80211_mgmt *) buf;
- reply->frame_control =
- IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- (send_deauth ? WLAN_FC_STYPE_DEAUTH :
- (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
- WLAN_FC_STYPE_ASSOC_RESP)));
- os_memcpy(reply->da, mgmt->sa, ETH_ALEN);
- os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(reply->bssid, mgmt->bssid, ETH_ALEN);
-
- send_len = IEEE80211_HDRLEN;
- if (send_deauth) {
- send_len += sizeof(reply->u.deauth);
- reply->u.deauth.reason_code = host_to_le16(resp);
- } else {
- u8 *p;
- send_len += sizeof(reply->u.assoc_resp);
- reply->u.assoc_resp.capab_info =
- host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
- reply->u.assoc_resp.status_code = host_to_le16(resp);
- reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
- | BIT(14) | BIT(15));
- /* Supported rates */
- 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_WMM)
- p = hostapd_eid_wmm(hapd, p);
-
- p = hostapd_eid_ht_capabilities(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, [RIC Response] */
- p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
- buf + sizeof(buf) - p,
- sta->auth_alg,
- pos, left);
- }
-#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;
- }
-
- if (hostapd_send_mgmt_frame(hapd, reply, send_len) < 0)
- perror("handle_assoc: send");
+ send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
}