Split handle_assoc() into number of helper functions
This commit is contained in:
parent
9294bfefc7
commit
5586f500a0
1 changed files with 446 additions and 337 deletions
|
@ -700,18 +700,440 @@ static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
|
|||
}
|
||||
|
||||
|
||||
static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ssid_ie, size_t ssid_ie_len)
|
||||
{
|
||||
if (ssid_ie == NULL)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
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 (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,
|
||||
"invalid WMM element in association "
|
||||
"request");
|
||||
else
|
||||
sta->flags |= WLAN_STA_WMM;
|
||||
}
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
if (elems->ext_supp_rates) {
|
||||
if (elems->supp_rates_len + elems->ext_supp_rates_len >
|
||||
sizeof(sta->supported_rates)) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
|
||||
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;
|
||||
} else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
|
||||
elems.wpa_ie) {
|
||||
wpa_ie = elems.wpa_ie;
|
||||
wpa_ie_len = elems.wpa_ie_len;
|
||||
} else {
|
||||
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) {
|
||||
if (elems.wps_ie) {
|
||||
wpa_printf(MSG_DEBUG, "STA included WPS IE in "
|
||||
"(Re)Association Request - assume WPS is "
|
||||
"used");
|
||||
sta->flags |= WLAN_STA_WPS;
|
||||
wpabuf_free(sta->wps_ie);
|
||||
sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4,
|
||||
elems.wps_ie_len - 4);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE "
|
||||
"in (Re)Association Request - possible WPS "
|
||||
"use");
|
||||
sta->flags |= WLAN_STA_MAYBE_WPS;
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_WPS */
|
||||
if (hapd->conf->wpa && wpa_ie == NULL) {
|
||||
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) {
|
||||
int res;
|
||||
wpa_ie -= 2;
|
||||
wpa_ie_len += 2;
|
||||
if (sta->wpa_sm == NULL)
|
||||
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
|
||||
sta->addr);
|
||||
if (sta->wpa_sm == NULL) {
|
||||
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,
|
||||
elems.mdie, elems.mdie_len);
|
||||
if (res == WPA_INVALID_GROUP)
|
||||
resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
|
||||
else if (res == WPA_INVALID_PAIRWISE)
|
||||
resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
|
||||
else if (res == WPA_INVALID_AKMP)
|
||||
resp = WLAN_STATUS_AKMP_NOT_VALID;
|
||||
else if (res == WPA_ALLOC_FAIL)
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
|
||||
resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
|
||||
else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
|
||||
resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
else if (res == WPA_INVALID_MDIE)
|
||||
resp = WLAN_STATUS_INVALID_MDIE;
|
||||
else if (res != WPA_IE_OK)
|
||||
resp = WLAN_STATUS_INVALID_IE;
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
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 SA
|
||||
* Query timeout has not been reached. Reject the
|
||||
* association attempt temporarily and start SA Query,
|
||||
* if one is not pending.
|
||||
*/
|
||||
|
||||
if (sta->sa_query_count == 0)
|
||||
ap_sta_start_sa_query(hapd, sta);
|
||||
|
||||
return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
|
||||
}
|
||||
|
||||
if (wpa_auth_uses_mfp(sta->wpa_sm))
|
||||
sta->flags |= WLAN_STA_MFP;
|
||||
else
|
||||
sta->flags &= ~WLAN_STA_MFP;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (sta->auth_alg == WLAN_AUTH_FT) {
|
||||
if (!reassoc) {
|
||||
wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
|
||||
"to use association (not "
|
||||
"re-association) with FT auth_alg",
|
||||
MAC2STR(sta->addr));
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
|
||||
ies_len);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if ((sta->flags & WLAN_STA_HT) &&
|
||||
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
|
||||
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, *wpa_ie;
|
||||
size_t wpa_ie_len;
|
||||
int send_deauth = 0, send_len, left, i;
|
||||
u8 *pos;
|
||||
int 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))) {
|
||||
|
@ -752,15 +1174,15 @@ static void handle_assoc(struct hostapd_data *hapd,
|
|||
} 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;
|
||||
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) {
|
||||
|
@ -777,234 +1199,21 @@ static void handle_assoc(struct hostapd_data *hapd,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 WMM element in association "
|
||||
"request");
|
||||
else
|
||||
sta->flags |= WLAN_STA_WMM;
|
||||
}
|
||||
|
||||
if (!elems.supp_rates) {
|
||||
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"No supported rates element in AssocReq");
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (elems.supp_rates_len > sizeof(sta->supported_rates)) {
|
||||
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Invalid supported rates element length %d",
|
||||
elems.supp_rates_len);
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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 {
|
||||
sta->flags &= ~WLAN_STA_HT;
|
||||
os_free(sta->ht_capabilities);
|
||||
sta->ht_capabilities = NULL;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
|
||||
wpa_ie = elems.rsn_ie;
|
||||
wpa_ie_len = elems.rsn_ie_len;
|
||||
} else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
|
||||
elems.wpa_ie) {
|
||||
wpa_ie = elems.wpa_ie;
|
||||
wpa_ie_len = elems.wpa_ie_len;
|
||||
} else {
|
||||
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) {
|
||||
if (elems.wps_ie) {
|
||||
wpa_printf(MSG_DEBUG, "STA included WPS IE in "
|
||||
"(Re)Association Request - assume WPS is "
|
||||
"used");
|
||||
sta->flags |= WLAN_STA_WPS;
|
||||
wpabuf_free(sta->wps_ie);
|
||||
sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4,
|
||||
elems.wps_ie_len - 4);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE "
|
||||
"in (Re)Association Request - possible WPS "
|
||||
"use");
|
||||
sta->flags |= WLAN_STA_MAYBE_WPS;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
if (hapd->conf->wpa && wpa_ie) {
|
||||
int res;
|
||||
wpa_ie -= 2;
|
||||
wpa_ie_len += 2;
|
||||
if (sta->wpa_sm == NULL)
|
||||
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;
|
||||
}
|
||||
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
|
||||
wpa_ie, wpa_ie_len,
|
||||
elems.mdie, elems.mdie_len);
|
||||
if (res == WPA_INVALID_GROUP)
|
||||
resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
|
||||
else if (res == WPA_INVALID_PAIRWISE)
|
||||
resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
|
||||
else if (res == WPA_INVALID_AKMP)
|
||||
resp = WLAN_STATUS_AKMP_NOT_VALID;
|
||||
else if (res == WPA_ALLOC_FAIL)
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
|
||||
resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
|
||||
else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
|
||||
resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
else if (res == WPA_INVALID_MDIE)
|
||||
resp = WLAN_STATUS_INVALID_MDIE;
|
||||
else if (res != WPA_IE_OK)
|
||||
resp = WLAN_STATUS_INVALID_IE;
|
||||
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
goto fail;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
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 SA
|
||||
* Query timeout has not been reached. Reject the
|
||||
* association attempt temporarily and start SA Query,
|
||||
* if one is not pending.
|
||||
*/
|
||||
|
||||
if (sta->sa_query_count == 0)
|
||||
ap_sta_start_sa_query(hapd, sta);
|
||||
|
||||
resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
|
||||
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;
|
||||
}
|
||||
|
||||
if (wpa_auth_uses_mfp(sta->wpa_sm))
|
||||
sta->flags |= WLAN_STA_MFP;
|
||||
else
|
||||
sta->flags &= ~WLAN_STA_MFP;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (sta->auth_alg == WLAN_AUTH_FT) {
|
||||
if (!reassoc) {
|
||||
wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
|
||||
"to use association (not "
|
||||
"re-association) with FT auth_alg",
|
||||
MAC2STR(sta->addr));
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
resp = wpa_ft_validate_reassoc(sta->wpa_sm, pos, left);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
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);
|
||||
sta->capability = capab_info;
|
||||
sta->listen_interval = listen_interval;
|
||||
|
||||
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
|
||||
sta->flags |= WLAN_STA_NONERP;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue