static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, struct ibss_rsn_peer *peer) { peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr); if (peer->auth == NULL) { wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); return -1; } /* TODO: get peer RSN IE with Probe Request */ if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, (u8 *) "\x30\x14\x01\x00" "\x00\x0f\xac\x04" "\x01\x00\x00\x0f\xac\x04" "\x01\x00\x00\x0f\xac\x02" "\x00\x00", 22, NULL, 0) != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); return -1; } if (wpa_auth_sm_event(peer->auth, WPA_ASSOC)) return -1; if (wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth)) return -1; return 0; }
static struct wpa_state_machine * hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr) { struct hostapd_data *hapd = ctx; struct sta_info *sta; if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0) return NULL; sta = ap_sta_add(hapd, sta_addr); if (sta == NULL) return NULL; if (sta->wpa_sm) { sta->auth_alg = WLAN_AUTH_FT; return sta->wpa_sm; } sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL); if (sta->wpa_sm == NULL) { ap_free_sta(hapd, sta); return NULL; } sta->auth_alg = WLAN_AUTH_FT; return sta->wpa_sm; }
static int bsd_new_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) { struct hostapd_data *hapd = drv->hapd; struct hostapd_bss_config *conf = hapd->conf; struct sta_info *sta; struct ieee80211req_wpaie ie; int new_assoc, ielen, res; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); sta = ap_sta_add(hapd, addr); if (sta == NULL) return -1; /* * Fetch and validate any negotiated WPA/RSN parameters. */ if (conf->wpa) { memset(&ie, 0, sizeof(ie)); memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); if (get80211var(drv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { printf("Failed to get WPA/RSN information element.\n"); return -1; /* XXX not right */ } ielen = ie.wpa_ie[1]; if (ielen == 0) { printf("No WPA/RSN information element for station!\n"); return -1; /* XXX not right */ } ielen += 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"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie.wpa_ie, ielen, NULL, 0); if (res != WPA_IE_OK) { printf("WPA/RSN information element rejected? " "(res %u)\n", res); return -1; } } /* * Now that the internal station state is setup * kick the authenticator into action. */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); return 0; }
static int madwifi_process_wpa_ie(struct madwifi_driver_data *drv, struct sta_info *sta) { struct hostapd_data *hapd = drv->hapd; struct ieee80211req_wpaie ie; int ielen, res; u8 *iebuf; /* * Fetch negotiated WPA/RSN parameters from the system. */ memset(&ie, 0, sizeof(ie)); memcpy(ie.wpa_macaddr, sta->addr, IEEE80211_ADDR_LEN); if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { wpa_printf(MSG_ERROR, "%s: Failed to get WPA/RSN IE", __func__); printf("Failed to get WPA/RSN information element.\n"); return -1; /* XXX not right */ } wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE", ie.wpa_ie, IEEE80211_MAX_OPT_IE); wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE", ie.rsn_ie, IEEE80211_MAX_OPT_IE); iebuf = ie.wpa_ie; /* madwifi seems to return some random data if WPA/RSN IE is not set. * Assume the IE was not included if the IE type is unknown. */ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) iebuf[1] = 0; #ifdef MADWIFI_NG if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not * set. This is needed for WPA2. */ iebuf = ie.rsn_ie; if (iebuf[0] != WLAN_EID_RSN) iebuf[1] = 0; } #endif /* MADWIFI_NG */ ielen = iebuf[1]; if (ielen == 0) { printf("No WPA/RSN information element for station!?\n"); return -1; /* XXX not right */ } ielen += 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"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, iebuf, ielen, NULL, 0); if (res != WPA_IE_OK) { printf("WPA/RSN information element rejected? (res %u)\n", res); return -1; } return 0; }
static int test_driver_new_sta(struct test_driver_data *drv, struct test_driver_bss *bss, const u8 *addr, const u8 *ie, size_t ielen) { struct hostapd_data *hapd; struct sta_info *sta; int new_assoc, res; hapd = test_driver_get_hapd(drv, bss); if (hapd == NULL) return -1; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); sta = ap_get_sta(hapd, addr); if (sta) { accounting_sta_stop(hapd, sta); } else { sta = ap_sta_add(hapd, addr); if (sta == NULL) return -1; } accounting_sta_get_id(hapd, sta); if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { printf("test_driver: no IE from STA\n"); return -1; } if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr); if (sta->wpa_sm == NULL) { printf("test_driver: Failed to initialize WPA state " "machine\n"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen); if (res != WPA_IE_OK) { printf("WPA/RSN information element rejected? " "(res %u)\n", res); return -1; } } new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); return 0; }
static int wext_process_wpa_ie(struct wext_driver_data *drv, struct sta_info *sta) { #define WEXT_WPA_IE_LEN 6 + 256 struct hostapd_data *hapd = drv->hapd; struct iwreq iwr; int ielen, res; static u8 iebuf[WEXT_WPA_IE_LEN]; wpa_printf(MSG_DEBUG, "%s: addr=%s\n", __func__, ether_sprintf(sta->addr)); memset(&iwr, 0, sizeof(iwr)); memset(&iebuf, 0, sizeof(iebuf)); strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ); iwr.u.encoding.pointer = (caddr_t)iebuf; iwr.u.encoding.length = WEXT_WPA_IE_LEN; /** * Some king of hack here: * I set WPA flag, so driver will check iebuf for sta mac address * and will return this station WPA IE * Will work with UBNT atheros driver **/ iwr.u.encoding.flags = IW_AUTH_WPA_ENABLED; memcpy(iebuf, sta->addr, ETH_ALEN); if (ioctl(drv->ioctl_sock, SIOCGIWGENIE, &iwr) < 0) { perror("ioctl[SIOCGIWGENIE]"); return -1; } ielen = iebuf[1]; if (ielen == 0) { printf("No WPA/RSN information element for station!?\n"); return -1; /* XXX not right */ } ielen += 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"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, iebuf, ielen, NULL, 0); if (res != WPA_IE_OK) { printf("WPA/RSN information element rejected? (res %u)\n", res); return -1; } #undef WEXT_WPA_IE_LEN return 0; }
static void hostapd_notif_auth(struct hostapd_data *hapd, struct auth_info *rx_auth) { struct sta_info *sta; u16 status = WLAN_STATUS_SUCCESS; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; size_t resp_ies_len = 0; sta = ap_get_sta(hapd, rx_auth->peer); if (!sta) { sta = ap_sta_add(hapd, rx_auth->peer); if (sta == NULL) { status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; goto fail; } } sta->flags &= ~WLAN_STA_PREAUTH; ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); #ifdef CONFIG_IEEE80211R_AP if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) { sta->auth_alg = WLAN_AUTH_FT; if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL); if (sta->wpa_sm == NULL) { wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA state machine"); status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid, rx_auth->auth_transaction, rx_auth->ies, rx_auth->ies_len, hostapd_notify_auth_ft_finish, hapd); return; } #endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_FILS if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) { sta->auth_alg = WLAN_AUTH_FILS_SK; handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len, rx_auth->auth_type, rx_auth->auth_transaction, rx_auth->status_code, hostapd_notify_auth_fils_finish); return; } #endif /* CONFIG_FILS */ fail: hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1, status, resp_ies, resp_ies_len); }
static void hostapd_notif_auth(struct hostapd_data *hapd, struct auth_info *rx_auth) { struct sta_info *sta; u16 resp = WLAN_STATUS_SUCCESS; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; size_t resp_ies_len = 0; sta = ap_get_sta(hapd, rx_auth->peer); if (!sta) { sta = ap_sta_add(hapd, rx_auth->peer); if (sta == NULL) { resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } } sta->flags &= ~WLAN_STA_PREAUTH; ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); #ifdef CONFIG_IEEE80211R if (rx_auth->auth_type == WLAN_AUTH_FT) { sta->auth_alg = WLAN_AUTH_FT; 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_DEBUG, "FT: Failed to initialize WPA " "state machine"); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid, rx_auth->auth_transaction, rx_auth->ies, rx_auth->ies_len, hostapd_notify_auth_ft_finish, hapd); return; } #endif /* CONFIG_IEEE80211R */ fail: if (resp_ies_len) hostapd_set_auth_ie(hapd, resp_ies, resp_ies_len); hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1, resp); }
static int auth_init(struct wpa *wpa) { wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL); if (wpa->auth == NULL) { wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); return -1; } if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie, wpa->supp_ie_len, NULL, 0) != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); return -1; } wpa_auth_sm_event(wpa->auth, WPA_ASSOC); wpa_auth_sta_associated(wpa->auth_group, wpa->auth); return 0; }
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *req_ies, size_t req_ies_len, int reassoc) { struct sta_info *sta; int new_assoc, res; struct ieee802_11_elems elems; const u8 *ie; size_t ielen; #ifdef CONFIG_IEEE80211R u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; u8 *p = buf; size_t len = 0; #endif /* CONFIG_IEEE80211R */ int resp = WLAN_STATUS_SUCCESS; if (addr == NULL) { /* * This could potentially happen with unexpected event from the * driver wrapper. This was seen at least in one case where the * driver ended up being set to station mode while hostapd was * running, so better make sure we stop processing such an * event here. */ wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " "no address"); return -1; } random_add_randomness(addr, ETH_ALEN); hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); if (elems.wps_ie) { ie = elems.wps_ie - 2; ielen = elems.wps_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); } else if (elems.rsn_ie) { ie = elems.rsn_ie - 2; ielen = elems.rsn_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); } else if (elems.wpa_ie) { ie = elems.wpa_ie - 2; ielen = elems.wpa_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); } else { ie = NULL; ielen = 0; wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " "(Re)AssocReq"); } sta = ap_get_sta(hapd, addr); if (sta) { accounting_sta_stop(hapd, sta); } else { sta = ap_sta_add(hapd, addr); if (sta == NULL) return -1; } sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); #ifdef CONFIG_P2P if (elems.p2p) { wpabuf_free(sta->p2p_ie); sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, P2P_IE_VENDOR_TYPE); } #endif /* CONFIG_P2P */ if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { if (hapd->conf->wps_state) { wpa_printf(MSG_DEBUG, "STA did not include " "WPA/RSN IE in (Re)Association " "Request - possible WPS use"); sta->flags |= WLAN_STA_MAYBE_WPS; goto skip_wpa_check; } wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); return -1; } if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { struct wpabuf *wps; sta->flags |= WLAN_STA_WPS; wps = ieee802_11_vendor_ie_concat(ie, ielen, WPS_IE_VENDOR_TYPE); if (wps) { if (wps_is_20(wps)) { wpa_printf(MSG_DEBUG, "WPS: STA " "supports WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } wpabuf_free(wps); } goto skip_wpa_check; } 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_ERROR, "Failed to initialize WPA state " "machine"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, elems.mdie, elems.mdie_len); if (res != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "WPA/RSN information element " "rejected? (res %u)", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); if (res == WPA_INVALID_GROUP) resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; else if (res == WPA_INVALID_PAIRWISE) resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; else if (res == WPA_INVALID_AKMP) resp = WLAN_REASON_AKMP_NOT_VALID; #ifdef CONFIG_IEEE80211W else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) resp = WLAN_REASON_INVALID_IE; else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; #endif /* CONFIG_IEEE80211W */ else resp = WLAN_REASON_INVALID_IE; goto fail; } #ifdef CONFIG_IEEE80211R if (sta->auth_alg == WLAN_AUTH_FT) { resp = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, req_ies_len); if (resp != WLAN_STATUS_SUCCESS) goto fail; } #endif /* CONFIG_IEEE80211R */ } else if (hapd->conf->wps_state) { struct wpabuf *wps; wps = ieee802_11_vendor_ie_concat(ie, ielen, WPS_IE_VENDOR_TYPE); #ifdef CONFIG_WPS_STRICT if (ie) { if (wps && wps_validate_assoc_req(wps) < 0) { resp = WLAN_REASON_INVALID_IE; wpabuf_free(wps); goto fail; } } #endif /* CONFIG_WPS_STRICT */ if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { sta->flags |= WLAN_STA_WPS; if (wps && wps_is_20(wps)) { wpa_printf(MSG_DEBUG, "WPS: STA supports " "WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } } else sta->flags |= WLAN_STA_MAYBE_WPS; wpabuf_free(wps); } skip_wpa_check: #ifdef CONFIG_IEEE80211R p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), sta->auth_alg, req_ies, req_ies_len); len = p - buf; hostapd_sta_assoc(hapd, addr, reassoc, 0, buf, len); #endif /* CONFIG_IEEE80211R */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); else wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); #ifdef CONFIG_P2P p2p_group_notif_assoc(hapd->p2p_group, sta->addr, req_ies, req_ies_len); #endif /* CONFIG_P2P */ return 0; fail: #ifdef CONFIG_IEEE80211R hostapd_sta_assoc(hapd, addr, reassoc, resp, buf, len); #endif /* CONFIG_IEEE80211R */ hostapd_drv_sta_disassoc(hapd, sta->addr, resp); ap_free_sta(hapd, sta); return -1; }
static int test_driver_new_sta(struct test_driver_data *drv, struct test_driver_bss *bss, const u8 *addr, const u8 *ie, size_t ielen) { struct hostapd_data *hapd; struct sta_info *sta; int new_assoc, res; hapd = test_driver_get_hapd(drv, bss); if (hapd == NULL) return -1; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); sta = ap_get_sta(hapd, addr); if (sta) { accounting_sta_stop(hapd, sta); } else { sta = ap_sta_add(hapd, addr); if (sta == NULL) return -1; } sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { if (hapd->conf->wps_state) { sta->flags |= WLAN_STA_WPS; goto skip_wpa_check; } printf("test_driver: no IE from STA\n"); return -1; } if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { sta->flags |= WLAN_STA_WPS; goto skip_wpa_check; } if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr); if (sta->wpa_sm == NULL) { printf("test_driver: Failed to initialize WPA state " "machine\n"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, NULL, 0); if (res != WPA_IE_OK) { printf("WPA/RSN information element rejected? " "(res %u)\n", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); return -1; } } skip_wpa_check: new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); return 0; }
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *req_ies, size_t req_ies_len, int reassoc) { struct sta_info *sta; int new_assoc, res; struct ieee802_11_elems elems; const u8 *ie; size_t ielen; #ifdef CONFIG_IEEE80211R u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; u8 *p = buf; #endif /* CONFIG_IEEE80211R */ u16 reason = WLAN_REASON_UNSPECIFIED; u16 status = WLAN_STATUS_SUCCESS; const u8 *p2p_dev_addr = NULL; if (addr == NULL) { /* * This could potentially happen with unexpected event from the * driver wrapper. This was seen at least in one case where the * driver ended up being set to station mode while hostapd was * running, so better make sure we stop processing such an * event here. */ wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " "no address"); return -1; } random_add_randomness(addr, ETH_ALEN); hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); if (elems.wps_ie) { ie = elems.wps_ie - 2; ielen = elems.wps_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); } else if (elems.rsn_ie) { ie = elems.rsn_ie - 2; ielen = elems.rsn_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); } else if (elems.wpa_ie) { ie = elems.wpa_ie - 2; ielen = elems.wpa_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); } else { ie = NULL; ielen = 0; wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " "(Re)AssocReq"); } sta = ap_get_sta(hapd, addr); if (sta) { ap_sta_no_session_timeout(hapd, sta); accounting_sta_stop(hapd, sta); /* * Make sure that the previously registered inactivity timer * will not remove the STA immediately. */ sta->timeout_next = STA_NULLFUNC; } else { sta = ap_sta_add(hapd, addr); if (sta == NULL) { hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_AP_BUSY); return -1; } } sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); #ifdef CONFIG_P2P if (elems.p2p) { wpabuf_free(sta->p2p_ie); sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, P2P_IE_VENDOR_TYPE); if (sta->p2p_ie) p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); } #endif /* CONFIG_P2P */ #ifdef CONFIG_INTERWORKING if (elems.ext_capab && elems.ext_capab_len > 4) { if (elems.ext_capab[4] & 0x01) sta->qos_map_enabled = 1; } #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 wpabuf_free(sta->hs20_ie); if (elems.hs20 && elems.hs20_len > 4) { sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, elems.hs20_len - 4); } else sta->hs20_ie = NULL; #endif /* CONFIG_HS20 */ if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { #ifdef CONFIG_WPS if (hapd->conf->wps_state) { wpa_printf(MSG_DEBUG, "STA did not include " "WPA/RSN IE in (Re)Association " "Request - possible WPS use"); sta->flags |= WLAN_STA_MAYBE_WPS; goto skip_wpa_check; } #endif /* CONFIG_WPS */ wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); return -1; } #ifdef CONFIG_WPS if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { struct wpabuf *wps; sta->flags |= WLAN_STA_WPS; wps = ieee802_11_vendor_ie_concat(ie, ielen, WPS_IE_VENDOR_TYPE); if (wps) { if (wps_is_20(wps)) { wpa_printf(MSG_DEBUG, "WPS: STA " "supports WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } wpabuf_free(wps); } goto skip_wpa_check; } #endif /* CONFIG_WPS */ if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, p2p_dev_addr); if (sta->wpa_sm == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize WPA state " "machine"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, elems.mdie, elems.mdie_len); if (res != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "WPA/RSN information element " "rejected? (res %u)", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); if (res == WPA_INVALID_GROUP) { reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; } else if (res == WPA_INVALID_PAIRWISE) { reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; } else if (res == WPA_INVALID_AKMP) { reason = WLAN_REASON_AKMP_NOT_VALID; status = WLAN_STATUS_AKMP_NOT_VALID; } #ifdef CONFIG_IEEE80211W else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) { reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; } #endif /* CONFIG_IEEE80211W */ else { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; } 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 && (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); #ifdef CONFIG_IEEE80211R status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; p = hostapd_eid_assoc_comeback_time(hapd, sta, p); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); #endif /* CONFIG_IEEE80211R */ return 0; } 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) { status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, req_ies_len); if (status != WLAN_STATUS_SUCCESS) { if (status == WLAN_STATUS_INVALID_PMKID) reason = WLAN_REASON_INVALID_IE; if (status == WLAN_STATUS_INVALID_MDIE) reason = WLAN_REASON_INVALID_IE; if (status == WLAN_STATUS_INVALID_FTIE) reason = WLAN_REASON_INVALID_IE; goto fail; } } #endif /* CONFIG_IEEE80211R */ } else if (hapd->conf->wps_state) { #ifdef CONFIG_WPS struct wpabuf *wps; if (req_ies) wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, WPS_IE_VENDOR_TYPE); else wps = NULL; #ifdef CONFIG_WPS_STRICT if (wps && wps_validate_assoc_req(wps) < 0) { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; wpabuf_free(wps); goto fail; } #endif /* CONFIG_WPS_STRICT */ if (wps) { sta->flags |= WLAN_STA_WPS; if (wps_is_20(wps)) { wpa_printf(MSG_DEBUG, "WPS: STA supports " "WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } } else sta->flags |= WLAN_STA_MAYBE_WPS; wpabuf_free(wps); #endif /* CONFIG_WPS */ } #ifdef CONFIG_WPS skip_wpa_check: #endif /* CONFIG_WPS */ #ifdef CONFIG_IEEE80211R p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), sta->auth_alg, req_ies, req_ies_len); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); #else /* CONFIG_IEEE80211R */ /* Keep compiler silent about unused variables */ if (status) { } #endif /* CONFIG_IEEE80211R */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); else wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); #ifdef CONFIG_P2P if (req_ies) { p2p_group_notif_assoc(hapd->p2p_group, sta->addr, req_ies, req_ies_len); } #endif /* CONFIG_P2P */ return 0; fail: #ifdef CONFIG_IEEE80211R hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); #endif /* CONFIG_IEEE80211R */ hostapd_drv_sta_disassoc(hapd, sta->addr, reason); ap_free_sta(hapd, sta); return -1; }
static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, const u8 *ies, size_t ies_len, int reassoc) { struct ieee802_11_elems elems; u16 resp; const 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; #ifdef CONFIG_IEEE80211N resp = copy_sta_ht_capab(sta, elems.ht_capabilities, elems.ht_capabilities_len); if (resp != WLAN_STATUS_SUCCESS) return resp; #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 && 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 = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_IE_VENDOR_TYPE); wpa_ie = NULL; wpa_ie_len = 0; } else if (hapd->conf->wps_state && wpa_ie == NULL) { 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; }
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *ie, size_t ielen) { struct sta_info *sta; int new_assoc, res; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); sta = ap_get_sta(hapd, addr); if (sta) { accounting_sta_stop(hapd, sta); } else { sta = ap_sta_add(hapd, addr); if (sta == NULL) return -1; } sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { if (hapd->conf->wps_state) { wpa_printf(MSG_DEBUG, "STA did not include " "WPA/RSN IE in (Re)Association " "Request - possible WPS use"); sta->flags |= WLAN_STA_MAYBE_WPS; goto skip_wpa_check; } wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); return -1; } if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { sta->flags |= WLAN_STA_WPS; goto skip_wpa_check; } 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_ERROR, "Failed to initialize WPA state " "machine"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, NULL, 0); if (res != WPA_IE_OK) { int resp; wpa_printf(MSG_DEBUG, "WPA/RSN information element " "rejected? (res %u)", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); if (res == WPA_INVALID_GROUP) resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; else if (res == WPA_INVALID_PAIRWISE) resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; else if (res == WPA_INVALID_AKMP) resp = WLAN_REASON_AKMP_NOT_VALID; #ifdef CONFIG_IEEE80211W else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) resp = WLAN_REASON_INVALID_IE; else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; #endif /* CONFIG_IEEE80211W */ else resp = WLAN_REASON_INVALID_IE; hapd->drv.sta_disassoc(hapd, sta->addr, resp); ap_free_sta(hapd, sta); return -1; } } else if (hapd->conf->wps_state) { if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { sta->flags |= WLAN_STA_WPS; } else sta->flags |= WLAN_STA_MAYBE_WPS; } skip_wpa_check: new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); return 0; }
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *req_ies, size_t req_ies_len, int reassoc) { struct sta_info *sta; int new_assoc, res; struct ieee802_11_elems elems; const u8 *ie; size_t ielen; #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; u8 *p = buf; #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ u16 reason = WLAN_REASON_UNSPECIFIED; u16 status = WLAN_STATUS_SUCCESS; const u8 *p2p_dev_addr = NULL; if (addr == NULL) { /* * This could potentially happen with unexpected event from the * driver wrapper. This was seen at least in one case where the * driver ended up being set to station mode while hostapd was * running, so better make sure we stop processing such an * event here. */ wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with no address"); return -1; } random_add_randomness(addr, ETH_ALEN); hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); if (elems.wps_ie) { ie = elems.wps_ie - 2; ielen = elems.wps_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); } else if (elems.rsn_ie) { ie = elems.rsn_ie - 2; ielen = elems.rsn_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); } else if (elems.wpa_ie) { ie = elems.wpa_ie - 2; ielen = elems.wpa_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); #ifdef CONFIG_HS20 } else if (elems.osen) { ie = elems.osen - 2; ielen = elems.osen_len + 2; wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq"); #endif /* CONFIG_HS20 */ } else { ie = NULL; ielen = 0; wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in (Re)AssocReq"); } sta = ap_get_sta(hapd, addr); if (sta) { ap_sta_no_session_timeout(hapd, sta); accounting_sta_stop(hapd, sta); /* * Make sure that the previously registered inactivity timer * will not remove the STA immediately. */ sta->timeout_next = STA_NULLFUNC; } else { sta = ap_sta_add(hapd, addr); if (sta == NULL) { hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_AP_BUSY); return -1; } } sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); /* * ACL configurations to the drivers (implementing AP SME and ACL * offload) without hostapd's knowledge, can result in a disconnection * though the driver accepts the connection. Skip the hostapd check for * ACL if the driver supports ACL offload to avoid potentially * conflicting ACL rules. */ if (hapd->iface->drv_max_acl_mac_addrs == 0 && hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) { wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect", MAC2STR(addr)); reason = WLAN_REASON_UNSPECIFIED; goto fail; } #ifdef CONFIG_P2P if (elems.p2p) { wpabuf_free(sta->p2p_ie); sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, P2P_IE_VENDOR_TYPE); if (sta->p2p_ie) p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); } #endif /* CONFIG_P2P */ #ifdef CONFIG_IEEE80211N #ifdef NEED_AP_MLME if (elems.ht_capabilities && (hapd->iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { struct ieee80211_ht_capabilities *ht_cap = (struct ieee80211_ht_capabilities *) elems.ht_capabilities; if (le_to_host16(ht_cap->ht_capabilities_info) & HT_CAP_INFO_40MHZ_INTOLERANT) ht40_intolerant_add(hapd->iface, sta); } #endif /* NEED_AP_MLME */ #endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_INTERWORKING if (elems.ext_capab && elems.ext_capab_len > 4) { if (elems.ext_capab[4] & 0x01) sta->qos_map_enabled = 1; } #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 wpabuf_free(sta->hs20_ie); if (elems.hs20 && elems.hs20_len > 4) { sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, elems.hs20_len - 4); } else sta->hs20_ie = NULL; #endif /* CONFIG_HS20 */ #ifdef CONFIG_FST wpabuf_free(sta->mb_ies); if (hapd->iface->fst) sta->mb_ies = mb_ies_by_info(&elems.mb_ies); else sta->mb_ies = NULL; #endif /* CONFIG_FST */ mbo_ap_check_sta_assoc(hapd, sta, &elems); ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes, elems.supp_op_classes_len); if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { #ifdef CONFIG_WPS if (hapd->conf->wps_state) { wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use"); sta->flags |= WLAN_STA_MAYBE_WPS; goto skip_wpa_check; } #endif /* CONFIG_WPS */ wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); return -1; } #ifdef CONFIG_WPS if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { struct wpabuf *wps; sta->flags |= WLAN_STA_WPS; wps = ieee802_11_vendor_ie_concat(ie, ielen, WPS_IE_VENDOR_TYPE); if (wps) { if (wps_is_20(wps)) { wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } wpabuf_free(wps); } goto skip_wpa_check; } #endif /* CONFIG_WPS */ if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, p2p_dev_addr); if (sta->wpa_sm == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize WPA state machine"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, elems.mdie, elems.mdie_len); if (res != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "WPA/RSN information element rejected? (res %u)", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); if (res == WPA_INVALID_GROUP) { reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; } else if (res == WPA_INVALID_PAIRWISE) { reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; } else if (res == WPA_INVALID_AKMP) { reason = WLAN_REASON_AKMP_NOT_VALID; status = WLAN_STATUS_AKMP_NOT_VALID; } #ifdef CONFIG_IEEE80211W else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) { reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; } #endif /* CONFIG_IEEE80211W */ else { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; } 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 && (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); status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; p = hostapd_eid_assoc_comeback_time(hapd, sta, p); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); return 0; } 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) { status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, req_ies_len); if (status != WLAN_STATUS_SUCCESS) { if (status == WLAN_STATUS_INVALID_PMKID) reason = WLAN_REASON_INVALID_IE; if (status == WLAN_STATUS_INVALID_MDIE) reason = WLAN_REASON_INVALID_IE; if (status == WLAN_STATUS_INVALID_FTIE) reason = WLAN_REASON_INVALID_IE; goto fail; } } #endif /* CONFIG_IEEE80211R */ } else if (hapd->conf->wps_state) { #ifdef CONFIG_WPS struct wpabuf *wps; if (req_ies) wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, WPS_IE_VENDOR_TYPE); else wps = NULL; #ifdef CONFIG_WPS_STRICT if (wps && wps_validate_assoc_req(wps) < 0) { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; wpabuf_free(wps); goto fail; } #endif /* CONFIG_WPS_STRICT */ if (wps) { sta->flags |= WLAN_STA_WPS; if (wps_is_20(wps)) { wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } } else sta->flags |= WLAN_STA_MAYBE_WPS; wpabuf_free(wps); #endif /* CONFIG_WPS */ #ifdef CONFIG_HS20 } else if (hapd->conf->osen) { if (elems.osen == NULL) { hostapd_logger( hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "No HS 2.0 OSEN element in association request"); return WLAN_STATUS_INVALID_IE; } wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association"); if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL); if (sta->wpa_sm == NULL) { wpa_printf(MSG_WARNING, "Failed to initialize WPA state machine"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, elems.osen - 2, elems.osen_len + 2) < 0) return WLAN_STATUS_INVALID_IE; #endif /* CONFIG_HS20 */ } #ifdef CONFIG_MBO if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) && elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) && hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { wpa_printf(MSG_INFO, "MBO: Reject WPA2 association without PMF"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } #endif /* CONFIG_MBO */ #ifdef CONFIG_WPS skip_wpa_check: #endif /* CONFIG_WPS */ #ifdef CONFIG_IEEE80211R p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), sta->auth_alg, req_ies, req_ies_len); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); if (sta->auth_alg == WLAN_AUTH_FT) ap_sta_set_authorized(hapd, sta, 1); #else /* CONFIG_IEEE80211R */ /* Keep compiler silent about unused variables */ if (status) { } #endif /* CONFIG_IEEE80211R */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; hostapd_set_sta_flags(hapd, sta); if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); else wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); #ifdef CONFIG_P2P if (req_ies) { p2p_group_notif_assoc(hapd->p2p_group, sta->addr, req_ies, req_ies_len); } #endif /* CONFIG_P2P */ return 0; fail: #ifdef CONFIG_IEEE80211R hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); #endif /* CONFIG_IEEE80211R */ hostapd_drv_sta_disassoc(hapd, sta->addr, reason); ap_free_sta(hapd, sta); return -1; }
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *ie, size_t ielen) { struct sta_info *sta; int new_assoc, res; struct ieee802_11_elems elems; if (addr == NULL) { /* * This could potentially happen with unexpected event from the * driver wrapper. This was seen at least in one case where the * driver ended up being set to station mode while hostapd was * running, so better make sure we stop processing such an * event here. */ wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " "no address"); return -1; } hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); ieee802_11_parse_elems(ie, ielen, &elems, 0); if (elems.wps_ie) { ie = elems.wps_ie - 2; ielen = elems.wps_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); } else if (elems.rsn_ie) { ie = elems.rsn_ie - 2; ielen = elems.rsn_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); } else if (elems.wpa_ie) { ie = elems.wpa_ie - 2; ielen = elems.wpa_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); } else { ie = NULL; ielen = 0; wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " "(Re)AssocReq"); } sta = ap_get_sta(hapd, addr); if (sta) { accounting_sta_stop(hapd, sta); } else { sta = ap_sta_add(hapd, addr); if (sta == NULL) return -1; } sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { if (hapd->conf->wps_state) { wpa_printf(MSG_DEBUG, "STA did not include " "WPA/RSN IE in (Re)Association " "Request - possible WPS use"); sta->flags |= WLAN_STA_MAYBE_WPS; goto skip_wpa_check; } wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); return -1; } if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { sta->flags |= WLAN_STA_WPS; goto skip_wpa_check; } 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_ERROR, "Failed to initialize WPA state " "machine"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, NULL, 0); if (res != WPA_IE_OK) { int resp; wpa_printf(MSG_DEBUG, "WPA/RSN information element " "rejected? (res %u)", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); if (res == WPA_INVALID_GROUP) resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; else if (res == WPA_INVALID_PAIRWISE) resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; else if (res == WPA_INVALID_AKMP) resp = WLAN_REASON_AKMP_NOT_VALID; #ifdef CONFIG_IEEE80211W else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) resp = WLAN_REASON_INVALID_IE; else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; #endif /* CONFIG_IEEE80211W */ else resp = WLAN_REASON_INVALID_IE; hapd->drv.sta_disassoc(hapd, sta->addr, resp); ap_free_sta(hapd, sta); return -1; } } else if (hapd->conf->wps_state) { if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { sta->flags |= WLAN_STA_WPS; } else sta->flags |= WLAN_STA_MAYBE_WPS; } skip_wpa_check: new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); return 0; }
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *req_ies, size_t req_ies_len, int reassoc) { struct sta_info *sta; int new_assoc, res; struct ieee802_11_elems elems; const u8 *ie; size_t ielen; #ifdef CONFIG_IEEE80211R u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; u8 *p = buf; #endif /* CONFIG_IEEE80211R */ u16 reason = WLAN_REASON_UNSPECIFIED; u16 status = WLAN_STATUS_SUCCESS; const u8 *p2p_dev_addr = NULL; if (addr == NULL) { /* * This could potentially happen with unexpected event from the * driver wrapper. This was seen at least in one case where the * driver ended up being set to station mode while hostapd was * running, so better make sure we stop processing such an * event here. */ wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " "no address"); return -1; } random_add_randomness(addr, ETH_ALEN); hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); if (elems.wps_ie) { ie = elems.wps_ie - 2; ielen = elems.wps_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); } else if (elems.rsn_ie) { ie = elems.rsn_ie - 2; ielen = elems.rsn_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); } else if (elems.wpa_ie) { ie = elems.wpa_ie - 2; ielen = elems.wpa_ie_len + 2; wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); #ifdef CONFIG_HS20 } else if (elems.osen) { ie = elems.osen - 2; ielen = elems.osen_len + 2; wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq"); #endif /* CONFIG_HS20 */ } else { ie = NULL; ielen = 0; wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " "(Re)AssocReq"); } sta = ap_get_sta(hapd, addr); if (sta) { ap_sta_no_session_timeout(hapd, sta); accounting_sta_stop(hapd, sta); /* * Make sure that the previously registered inactivity timer * will not remove the STA immediately. */ sta->timeout_next = STA_NULLFUNC; } else { sta = ap_sta_add(hapd, addr); if (sta == NULL) { hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_AP_BUSY); return -1; } } sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); #ifdef CONFIG_P2P if (elems.p2p) { wpabuf_free(sta->p2p_ie); sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, P2P_IE_VENDOR_TYPE); if (sta->p2p_ie) p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); } #endif /* CONFIG_P2P */ #ifdef CONFIG_IEEE80211N #ifdef NEED_AP_MLME if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct ieee80211_ht_capabilities) && (hapd->iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { struct ieee80211_ht_capabilities *ht_cap = (struct ieee80211_ht_capabilities *) elems.ht_capabilities; if (le_to_host16(ht_cap->ht_capabilities_info) & HT_CAP_INFO_40MHZ_INTOLERANT) ht40_intolerant_add(hapd->iface, sta); } #endif /* NEED_AP_MLME */ #endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_INTERWORKING if (elems.ext_capab && elems.ext_capab_len > 4) { if (elems.ext_capab[4] & 0x01) sta->qos_map_enabled = 1; } #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 wpabuf_free(sta->hs20_ie); if (elems.hs20 && elems.hs20_len > 4) { sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, elems.hs20_len - 4); } else sta->hs20_ie = NULL; #endif /* CONFIG_HS20 */ #ifdef CONFIG_MTK_P2P if (elems.wfd && (elems.wfd_len > 0)) { struct p2p_message msg; wpabuf_free(sta->wfd_ie); sta->wfd_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, WFD_IE_VENDOR_TYPE); if(p2p_parse_wfd_ie(sta->wfd_ie,&msg)==0) { wpa_printf(MSG_DEBUG, "Change our WFD role and peer wfd_ie"); if(hapd->p2p) { wpa_printf(MSG_DEBUG, "Change our WFD role and peer wfd_ie 2"); wfd_process_request_and_switch_role(hapd->p2p, &msg, 0); } } } #endif /* CONFIG_MTK_P2P */ if (hapd->conf->wpa) { if (ie == NULL || ielen == 0) { #ifdef CONFIG_WPS if (hapd->conf->wps_state) { wpa_printf(MSG_DEBUG, "STA did not include " "WPA/RSN IE in (Re)Association " "Request - possible WPS use"); sta->flags |= WLAN_STA_MAYBE_WPS; goto skip_wpa_check; } #endif /* CONFIG_WPS */ wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); return -1; } #ifdef CONFIG_WPS if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { struct wpabuf *wps; sta->flags |= WLAN_STA_WPS; wps = ieee802_11_vendor_ie_concat(ie, ielen, WPS_IE_VENDOR_TYPE); if (wps) { if (wps_is_20(wps)) { wpa_printf(MSG_DEBUG, "WPS: STA " "supports WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } wpabuf_free(wps); } goto skip_wpa_check; } #endif /* CONFIG_WPS */ if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, p2p_dev_addr); if (sta->wpa_sm == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize WPA state " "machine"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie, ielen, elems.mdie, elems.mdie_len); if (res != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "WPA/RSN information element " "rejected? (res %u)", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); if (res == WPA_INVALID_GROUP) { reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; } else if (res == WPA_INVALID_PAIRWISE) { reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; } else if (res == WPA_INVALID_AKMP) { reason = WLAN_REASON_AKMP_NOT_VALID; status = WLAN_STATUS_AKMP_NOT_VALID; } #ifdef CONFIG_IEEE80211W else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) { reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; } #endif /* CONFIG_IEEE80211W */ else { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; } 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 && (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); #ifdef CONFIG_IEEE80211R status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; p = hostapd_eid_assoc_comeback_time(hapd, sta, p); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); #endif /* CONFIG_IEEE80211R */ return 0; } 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) { status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, req_ies_len); if (status != WLAN_STATUS_SUCCESS) { if (status == WLAN_STATUS_INVALID_PMKID) reason = WLAN_REASON_INVALID_IE; if (status == WLAN_STATUS_INVALID_MDIE) reason = WLAN_REASON_INVALID_IE; if (status == WLAN_STATUS_INVALID_FTIE) reason = WLAN_REASON_INVALID_IE; goto fail; } } #endif /* CONFIG_IEEE80211R */ } else if (hapd->conf->wps_state) { #ifdef CONFIG_WPS struct wpabuf *wps; if (req_ies) wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, WPS_IE_VENDOR_TYPE); else wps = NULL; #ifdef CONFIG_WPS_STRICT if (wps && wps_validate_assoc_req(wps) < 0) { reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; wpabuf_free(wps); goto fail; } #endif /* CONFIG_WPS_STRICT */ if (wps) { sta->flags |= WLAN_STA_WPS; if (wps_is_20(wps)) { wpa_printf(MSG_DEBUG, "WPS: STA supports " "WPS 2.0"); sta->flags |= WLAN_STA_WPS2; } } else sta->flags |= WLAN_STA_MAYBE_WPS; wpabuf_free(wps); #endif /* CONFIG_WPS */ #ifdef CONFIG_HS20 } else if (hapd->conf->osen) { if (elems.osen == NULL) { hostapd_logger( hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "No HS 2.0 OSEN element in association request"); return WLAN_STATUS_INVALID_IE; } wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association"); if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL); if (sta->wpa_sm == NULL) { wpa_printf(MSG_WARNING, "Failed to initialize WPA " "state machine"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, elems.osen - 2, elems.osen_len + 2) < 0) return WLAN_STATUS_INVALID_IE; #endif /* CONFIG_HS20 */ } #ifdef CONFIG_WPS skip_wpa_check: #endif /* CONFIG_WPS */ #ifdef CONFIG_IEEE80211R p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), sta->auth_alg, req_ies, req_ies_len); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); if (sta->auth_alg == WLAN_AUTH_FT) ap_sta_set_authorized(hapd, sta, 1); #else /* CONFIG_IEEE80211R */ /* Keep compiler silent about unused variables */ if (status) { } #endif /* CONFIG_IEEE80211R */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; hostapd_set_sta_flags(hapd, sta); if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); else wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); /* [ALPS00326459][6575JB][BSP Package][6577JB][CTS Verifier 4.1_r2][MT6577_PHONE][changelist 996001] GROUP JOIN 2 cases fail in Wi-Fi Direct Test */ #if defined(CONFIG_MTK_P2P) || defined(CONFIG_HOTSPOT_MGR_SUPPORT) if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || sta->auth_alg == WLAN_AUTH_FT) { /* * Open, static WEP, or FT protocol; no separate authorization * step. */ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); } #endif /* CONFIG_MTK_P2P || CONFIG_HOTSPOT_MGR_SUPPORT */ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); #ifdef CONFIG_P2P if (req_ies) { p2p_group_notif_assoc(hapd->p2p_group, sta->addr, req_ies, req_ies_len); } #endif /* CONFIG_P2P */ return 0; fail: #ifdef CONFIG_IEEE80211R hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); #endif /* CONFIG_IEEE80211R */ hostapd_drv_sta_disassoc(hapd, sta->addr, reason); ap_free_sta(hapd, sta); return -1; }
static void handle_auth(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { u16 auth_alg, auth_transaction, status_code; u16 resp = WLAN_STATUS_SUCCESS; struct sta_info *sta = NULL; int res; u16 fc; const u8 *challenge = NULL; u32 session_timeout, acct_interim_interval; int vlan_id = 0; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; size_t resp_ies_len = 0; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { printf("handle_auth - too short payload (len=%lu)\n", (unsigned long) len); return; } auth_alg = le_to_host16(mgmt->u.auth.auth_alg); auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); status_code = le_to_host16(mgmt->u.auth.status_code); fc = le_to_host16(mgmt->frame_control); if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) + 2 + WLAN_AUTH_CHALLENGE_LEN && mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE && mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN) challenge = &mgmt->u.auth.variable[2]; wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d " "auth_transaction=%d status_code=%d wep=%d%s", MAC2STR(mgmt->sa), auth_alg, auth_transaction, status_code, !!(fc & WLAN_FC_ISWEP), challenge ? " challenge" : ""); if (hapd->tkip_countermeasures) { resp = WLAN_REASON_MICHAEL_MIC_FAILURE; goto fail; } if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) && auth_alg == WLAN_AUTH_OPEN) || #ifdef CONFIG_IEEE80211R (hapd->conf->wpa && (hapd->conf->wpa_key_mgmt & (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) && auth_alg == WLAN_AUTH_FT) || #endif /* CONFIG_IEEE80211R */ ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) && auth_alg == WLAN_AUTH_SHARED_KEY))) { printf("Unsupported authentication algorithm (%d)\n", auth_alg); resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; goto fail; } if (!(auth_transaction == 1 || (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) { printf("Unknown authentication transaction number (%d)\n", auth_transaction); resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; goto fail; } if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) { printf("Station " MACSTR " not allowed to authenticate.\n", MAC2STR(mgmt->sa)); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, &session_timeout, &acct_interim_interval, &vlan_id); if (res == HOSTAPD_ACL_REJECT) { printf("Station " MACSTR " not allowed to authenticate.\n", MAC2STR(mgmt->sa)); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } if (res == HOSTAPD_ACL_PENDING) { wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR " waiting for an external authentication", MAC2STR(mgmt->sa)); /* Authentication code will re-send the authentication frame * after it has received (and cached) information from the * external source. */ return; } sta = ap_sta_add(hapd, mgmt->sa); if (!sta) { resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } if (vlan_id > 0) { if (hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id) == NULL) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "Invalid VLAN ID " "%d received from RADIUS server", vlan_id); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } sta->vlan_id = vlan_id; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); } sta->flags &= ~WLAN_STA_PREAUTH; ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval) sta->acct_interim_interval = acct_interim_interval; if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) ap_sta_session_timeout(hapd, sta, session_timeout); else ap_sta_no_session_timeout(hapd, sta); switch (auth_alg) { case WLAN_AUTH_OPEN: hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication OK (open system)"); #ifdef IEEE80211_REQUIRE_AUTH_ACK /* Station will be marked authenticated if it ACKs the * authentication reply. */ #else sta->flags |= WLAN_STA_AUTH; wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); sta->auth_alg = WLAN_AUTH_OPEN; mlme_authenticate_indication(hapd, sta); #endif break; case WLAN_AUTH_SHARED_KEY: resp = auth_shared_key(hapd, sta, auth_transaction, challenge, fc & WLAN_FC_ISWEP); sta->auth_alg = WLAN_AUTH_SHARED_KEY; mlme_authenticate_indication(hapd, sta); if (sta->challenge && auth_transaction == 1) { resp_ies[0] = WLAN_EID_CHALLENGE; resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN; os_memcpy(resp_ies + 2, sta->challenge, WLAN_AUTH_CHALLENGE_LEN); resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN; } break; #ifdef CONFIG_IEEE80211R case WLAN_AUTH_FT: sta->auth_alg = WLAN_AUTH_FT; 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_DEBUG, "FT: Failed to initialize WPA " "state machine"); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid, auth_transaction, mgmt->u.auth.variable, len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth), handle_auth_ft_finish, hapd); /* handle_auth_ft_finish() callback will complete auth. */ return; #endif /* CONFIG_IEEE80211R */ } fail: send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg, auth_transaction + 1, resp, resp_ies, resp_ies_len); }