static void rx_data_tdls_teardown(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr, const u8 *dst, const u8 *src, const u8 *data, size_t len) { u16 reason; struct ieee802_11_elems elems; struct wlantest_tdls *tdls; if (len < 2) return; reason = WPA_GET_LE16(data); wpa_printf(MSG_DEBUG, "TDLS Teardown " MACSTR " -> " MACSTR " (reason %d)", MAC2STR(src), MAC2STR(dst), reason); if (ieee802_11_parse_elems(data + 2, len - 2, &elems, 1) == ParseFailed || elems.link_id == NULL) return; wpa_printf(MSG_DEBUG, "TDLS Link Identifier: BSSID " MACSTR " initiator STA " MACSTR " responder STA " MACSTR, MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN), MAC2STR(elems.link_id + 2 * ETH_ALEN)); tdls = get_tdls(wt, elems.link_id, 1, bssid); if (tdls) { if (tdls->link_up) add_note(wt, MSG_DEBUG, "TDLS: Link down"); tdls->link_up = 0; tdls->counters[WLANTEST_TDLS_COUNTER_TEARDOWN]++; tdls_verify_mic_teardown(wt, tdls, 4, data, &elems); } }
static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, struct os_reltime *fetch_time) { struct ieee80211_ht_capabilities *capab; struct ieee80211_ht_operation *oper; struct ieee802_11_elems elems; dst->flags = src->flags; os_memcpy(dst->bssid, src->bssid, ETH_ALEN); dst->freq = src->freq; dst->beacon_int = src->beacon_int; dst->caps = src->caps; dst->qual = src->qual; dst->noise = src->noise; dst->level = src->level; dst->tsf = src->tsf; dst->est_throughput = src->est_throughput; dst->snr = src->snr; memset(&elems, 0, sizeof(elems)); ieee802_11_parse_elems((u8 *) (src + 1), src->ie_len, &elems, 0); capab = (struct ieee80211_ht_capabilities *) elems.ht_capabilities; oper = (struct ieee80211_ht_operation *) elems.ht_operation; if (capab) dst->ht_capab = le_to_host16(capab->ht_capabilities_info); if (oper) dst->ht_param = oper->ht_param; calculate_update_time(fetch_time, src->age, &dst->last_update); }
/** * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE) * @data: IEs from the message * @len: Length of data buffer in octets * @msg: Buffer for returning parsed attributes * Returns: 0 on success, -1 on failure * * Note: Caller is responsible for clearing the msg data structure before * calling this function. * * Note: Caller must free temporary memory allocations by calling * p2p_parse_free() when the parsed data is not needed anymore. */ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg) { struct ieee802_11_elems elems; ieee802_11_parse_elems(data, len, &elems, 0); if (elems.ds_params && elems.ds_params_len >= 1) msg->ds_params = elems.ds_params; if (elems.ssid) msg->ssid = elems.ssid - 2; msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len, WPS_DEV_OUI_WFA); if (msg->wps_attributes && p2p_parse_wps_ie(msg->wps_attributes, msg)) { p2p_parse_free(msg); return -1; } msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len, P2P_IE_VENDOR_TYPE); if (msg->p2p_attributes && p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); if (msg->p2p_attributes) wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", msg->p2p_attributes); p2p_parse_free(msg); return -1; } return 0; }
static int ieee802_11_parse_tests(void) { int i, ret = 0; wpa_printf(MSG_INFO, "ieee802_11_parse tests"); for (i = 0; parse_tests[i].data; i++) { const struct ieee802_11_parse_test_data *test; struct ieee802_11_elems elems; ParseRes res; test = &parse_tests[i]; res = ieee802_11_parse_elems(test->data, test->len, &elems, 1); if (res != test->result || ieee802_11_ie_count(test->data, test->len) != test->count) { wpa_printf(MSG_ERROR, "ieee802_11_parse test %d failed", i); ret = -1; } } if (ieee802_11_vendor_ie_concat((const u8 *) "\x00\x01", 2, 0) != NULL) { wpa_printf(MSG_ERROR, "ieee802_11_vendor_ie_concat test failed"); ret = -1; } return ret; }
static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end) { struct ieee802_11_elems elems; struct ieee80211_ht_operation *oper; if (bss->freq < start || bss->freq > end || bss->freq == pri_freq) return 0; ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); if (!elems.ht_capabilities) { wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: " MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq); return 1; } if (elems.ht_operation) { oper = (struct ieee80211_ht_operation *) elems.ht_operation; if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK) return 0; wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: " MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq); return 1; } return 0; }
void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, const u8 *bssid, u16 auth_type) { struct wpa_driver_associate_params params; struct ieee802_11_elems elems; os_memset(¶ms, 0, sizeof(params)); params.bssid = bssid; params.ssid = wpa_s->sme.ssid; params.ssid_len = wpa_s->sme.ssid_len; params.freq = wpa_s->sme.freq; params.wpa_ie = wpa_s->sme.assoc_req_ie_len ? wpa_s->sme.assoc_req_ie : NULL; params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; #ifdef CONFIG_IEEE80211R if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { params.wpa_ie = wpa_s->sme.ft_ies; params.wpa_ie_len = wpa_s->sme.ft_ies_len; } #endif /* CONFIG_IEEE80211R */ params.mode = mode; params.mgmt_frame_protection = wpa_s->sme.mfp; if (wpa_s->sme.prev_bssid_set) params.prev_bssid = wpa_s->sme.prev_bssid; wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid), params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "", params.freq); wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING); if (params.wpa_ie == NULL || ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0) < 0) { wpa_printf(MSG_DEBUG, "SME: Could not parse own IEs?!"); os_memset(&elems, 0, sizeof(elems)); } if (elems.rsn_ie) wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2, elems.rsn_ie_len + 2); else if (elems.wpa_ie) wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2, elems.wpa_ie_len + 2); else wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); if (wpa_drv_associate(wpa_s, ¶ms) < 0) { wpa_msg(wpa_s, MSG_INFO, "Association request to the driver " "failed"); //wpa_supplicant_req_scan(wpa_s, 5, 0); ros_assoc_failed(wpa_s, bssid, "Driver request to associate failed"); return; } /* TODO: add timeout on association */ }
void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd, struct sta_info *sta) { u16 reply_res = WLAN_STATUS_SUCCESS; struct ieee802_11_elems elems; u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf; int new_assoc; wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR, __func__, MAC2STR(sta->addr)); eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); if (!sta->fils_pending_assoc_req) return; ieee802_11_parse_elems(sta->fils_pending_assoc_req, sta->fils_pending_assoc_req_len, &elems, 0); if (!elems.fils_session) { wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element", __func__); return; } p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p, elems.fils_session, sta->fils_hlp_resp); reply_res = hostapd_sta_assoc(hapd, sta->addr, sta->fils_pending_assoc_is_reassoc, WLAN_STATUS_SUCCESS, buf, p - buf); ap_sta_set_authorized(hapd, sta, 1); 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); wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); hostapd_new_assoc_sta(hapd, sta, !new_assoc); os_free(sta->fils_pending_assoc_req); sta->fils_pending_assoc_req = NULL; sta->fils_pending_assoc_req_len = 0; wpabuf_free(sta->fils_hlp_resp); sta->fils_hlp_resp = NULL; wpabuf_free(sta->hlp_dhcp_discover); sta->hlp_dhcp_discover = NULL; fils_hlp_deinit(hapd); /* * Remove the station in case transmission of a success response fails * (the STA was added associated to the driver) or if the station was * previously added unassociated. */ if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) { hostapd_drv_sta_remove(hapd, sta->addr); sta->added_unassoc = 0; } }
static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da, const u8 *bssid, const u8 *ie, size_t ie_len, int ssi_signal) { struct hostapd_data *hapd = ctx; struct wpabuf *wps_ie; struct ieee802_11_elems elems; if (hapd->wps == NULL) return 0; if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from " MACSTR, MAC2STR(addr)); return 0; } if (elems.ssid && elems.ssid_len > 0 && (elems.ssid_len != hapd->conf->ssid.ssid_len || os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) != 0)) return 0; /* Not for us */ wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); if (wps_ie == NULL) return 0; if (wps_validate_probe_req(wps_ie, addr) < 0) { wpabuf_free(wps_ie); return 0; } if (wpabuf_len(wps_ie) > 0) { int p2p_wildcard = 0; #ifdef CONFIG_P2P if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN && os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) p2p_wildcard = 1; #endif /* CONFIG_P2P */ wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie, p2p_wildcard); #ifdef CONFIG_WPS_UPNP /* FIX: what exactly should be included in the WLANEvent? * WPS attributes? Full ProbeReq frame? */ if (!p2p_wildcard) upnp_wps_device_send_wlan_event( hapd->wps_upnp, addr, UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie); #endif /* CONFIG_WPS_UPNP */ } wpabuf_free(wps_ie); return 0; }
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { struct ieee802_11_elems elems; size_t baselen; u32 last_hop_metric; struct sta_info *sta; /* need action_code */ if (len < IEEE80211_MIN_ACTION_SIZE + 1) return; rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); if (!sta || sta->plink_state != NL80211_PLINK_ESTAB) { rcu_read_unlock(); return; } rcu_read_unlock(); baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, len - baselen, &elems); if (elems.preq) { if (elems.preq_len != 37) /* Right now we support just 1 destination and no AE */ return; last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq, MPATH_PREQ); if (last_hop_metric) hwmp_preq_frame_process(sdata, mgmt, elems.preq, last_hop_metric); } if (elems.prep) { if (elems.prep_len != 31) /* Right now we support no AE */ return; last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep, MPATH_PREP); if (last_hop_metric) hwmp_prep_frame_process(sdata, mgmt, elems.prep, last_hop_metric); } if (elems.perr) { if (elems.perr_len != 15) /* Right now we support only one destination per PERR */ return; hwmp_perr_frame_process(sdata, mgmt, elems.perr); } if (elems.rann) hwmp_rann_frame_process(sdata, mgmt, elems.rann); }
void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *ies, size_t ie_len) { struct ieee802_11_elems elems; wpa_msg(wpa_s, MSG_INFO, "new peer notification for " MACSTR, MAC2STR(addr)); if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) { wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR, MAC2STR(addr)); return; } wpa_mesh_new_mesh_peer(wpa_s, addr, &elems); }
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { struct ieee802_11_elems elems; size_t baselen; u32 last_hop_metric; /* need action_code */ if (len < IEEE80211_MIN_ACTION_SIZE + 1) return; baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, len - baselen, &elems); switch (mgmt->u.action.u.mesh_action.action_code) { case MPATH_PREQ: if (!elems.preq || elems.preq_len != 37) /* Right now we support just 1 destination and no AE */ return; last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq); if (!last_hop_metric) return; hwmp_preq_frame_process(sdata, mgmt, elems.preq, last_hop_metric); break; case MPATH_PREP: if (!elems.prep || elems.prep_len != 31) /* Right now we support no AE */ return; last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep); if (!last_hop_metric) return; hwmp_prep_frame_process(sdata, mgmt, elems.prep, last_hop_metric); break; case MPATH_PERR: if (!elems.perr || elems.perr_len != 12) /* Right now we support only one destination per PERR */ return; hwmp_perr_frame_process(sdata, mgmt, elems.perr); default: return; } }
static struct wmm_ac_assoc_data * wmm_ac_process_param_elem(struct wpa_supplicant *wpa_s, const u8 *ies, size_t ies_len) { struct ieee802_11_elems elems; struct wmm_parameter_element *wmm_params; struct wmm_ac_assoc_data *assoc_data; int i; /* Parsing WMM Parameter Element */ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) != ParseOK) { wpa_printf(MSG_DEBUG, "WMM AC: could not parse assoc ies"); return NULL; } if (!elems.wmm) { wpa_printf(MSG_DEBUG, "WMM AC: No WMM IE"); return NULL; } if (elems.wmm_len != sizeof(*wmm_params)) { wpa_printf(MSG_WARNING, "WMM AC: Invalid WMM ie length"); return NULL; } wmm_params = (struct wmm_parameter_element *)(elems.wmm); assoc_data = os_zalloc(sizeof(*assoc_data)); if (!assoc_data) return NULL; for (i = 0; i < WMM_AC_NUM; i++) assoc_data->ac_params[i].acm = !!(wmm_params->ac[i].aci_aifsn & WMM_AC_ACM); wpa_printf(MSG_DEBUG, "WMM AC: AC mandatory: AC_BE=%u AC_BK=%u AC_VI=%u AC_VO=%u", assoc_data->ac_params[WMM_AC_BE].acm, assoc_data->ac_params[WMM_AC_BK].acm, assoc_data->ac_params[WMM_AC_VI].acm, assoc_data->ac_params[WMM_AC_VO].acm); return assoc_data; }
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { struct ieee802_11_elems elems; size_t baselen; u8 *orig_addr;//ymj u32 last_hop_metric; struct sta_info *sta; /* need action_code */ if (len < IEEE80211_MIN_ACTION_SIZE + 1) return; rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); if (!sta || sta->plink_state != NL80211_PLINK_ESTAB) { rcu_read_unlock(); return; } rcu_read_unlock(); baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, len - baselen, &elems); if (elems.preq) { if (elems.preq_len != 37)//ymj /* Right now we support just 1 destination and no AE */ return; orig_addr=PREQ_IE_ORIG_ADDR(elems.preq); if(/*blank*/)//调用mesh_flood_detect函数,判断是否是SUPPRESSED的节点 { last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq, MPATH_PREQ); if (last_hop_metric) hwmp_preq_frame_process(sdata, mgmt, elems.preq, last_hop_metric); }else{ //to be modified //是SUPPRESSED节点,在debug信息中提示该节点MAC } }
static void rx_data_tdls_setup_request(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr, const u8 *dst, const u8 *src, const u8 *data, size_t len) { struct ieee802_11_elems elems; struct wlantest_tdls *tdls; u8 linkid[3 * ETH_ALEN]; if (len < 3) { add_note(wt, MSG_INFO, "Too short TDLS Setup Request " MACSTR " -> " MACSTR, MAC2STR(src), MAC2STR(dst)); return; } wpa_printf(MSG_DEBUG, "TDLS Setup Request " MACSTR " -> " MACSTR, MAC2STR(src), MAC2STR(dst)); if (ieee802_11_parse_elems(data + 3, len - 3, &elems, 1) == ParseFailed || elems.link_id == NULL) return; wpa_printf(MSG_DEBUG, "TDLS Link Identifier: BSSID " MACSTR " initiator STA " MACSTR " responder STA " MACSTR, MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN), MAC2STR(elems.link_id + 2 * ETH_ALEN)); tdls = get_tdls(wt, elems.link_id, 1, bssid); if (tdls) { tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_REQ]++; tdls->dialog_token = data[0]; if (elems.ftie && elems.ftie_len >= sizeof(struct rsn_ftie)) { const struct rsn_ftie *f; f = (const struct rsn_ftie *) elems.ftie; os_memcpy(tdls->inonce, f->snonce, WPA_NONCE_LEN); } } /* Check whether reverse direction context exists already */ os_memcpy(linkid, bssid, ETH_ALEN); os_memcpy(linkid + ETH_ALEN, dst, ETH_ALEN); os_memcpy(linkid + 2 * ETH_ALEN, src, ETH_ALEN); tdls = get_tdls(wt, linkid, 0, bssid); if (tdls) add_note(wt, MSG_INFO, "Reverse direction TDLS context exists"); }
static void handle_beacon(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, struct hostapd_frame_info *fi) { struct ieee802_11_elems elems; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) { printf("handle_beacon - too short payload (len=%lu)\n", (unsigned long) len); return; } (void) ieee802_11_parse_elems(mgmt->u.beacon.variable, len - (IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)), &elems, 0); ap_list_process_beacon(hapd->iface, mgmt, &elems, fi); }
/** * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE) * @data: IEs from the message * @len: Length of data buffer in octets * @msg: Buffer for returning parsed attributes * Returns: 0 on success, -1 on failure * * Note: Caller is responsible for clearing the msg data structure before * calling this function. * * Note: Caller must free temporary memory allocations by calling * p2p_parse_free() when the parsed data is not needed anymore. */ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg) { struct ieee802_11_elems elems; ieee802_11_parse_elems(data, len, &elems, 0); if (elems.ds_params) msg->ds_params = elems.ds_params; if (elems.ssid) msg->ssid = elems.ssid - 2; msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len, WPS_DEV_OUI_WFA); if (msg->wps_attributes && p2p_parse_wps_ie(msg->wps_attributes, msg)) { p2p_parse_free(msg); return -1; } msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len, P2P_IE_VENDOR_TYPE); if (msg->p2p_attributes && p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); if (msg->p2p_attributes) wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", msg->p2p_attributes); p2p_parse_free(msg); return -1; } #ifdef CONFIG_WIFI_DISPLAY if (elems.wfd) { msg->wfd_subelems = ieee802_11_vendor_ie_concat( data, len, WFD_IE_VENDOR_TYPE); } #endif /* CONFIG_WIFI_DISPLAY */ msg->pref_freq_list = elems.pref_freq_list; msg->pref_freq_list_len = elems.pref_freq_list_len; return 0; }
void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan) { struct ieee80211_ht_operation *oper; struct ieee802_11_elems elems; *pri_chan = *sec_chan = 0; ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); if (elems.ht_operation) { oper = (struct ieee80211_ht_operation *) elems.ht_operation; *pri_chan = oper->primary_chan; if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) { int sec = oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) *sec_chan = *pri_chan + 4; else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) *sec_chan = *pri_chan - 4; } } }
static void handle_beacon(hostapd *hapd, struct ieee80211_mgmt *mgmt, size_t len) { struct ieee802_11_elems elems; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) { printf("handle_beacon - too short payload (len=%lu)\n", (unsigned long) len); return; } (void) ieee802_11_parse_elems(hapd, mgmt->u.beacon.variable, len - (IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)), &elems, 0); if (hapd->assoc_ap_state == WAIT_BEACON && memcmp(mgmt->sa, hapd->conf->assoc_ap_addr, ETH_ALEN) == 0) { if (elems.ssid && elems.ssid_len <= 32) { memcpy(hapd->assoc_ap_ssid, elems.ssid, elems.ssid_len); hapd->assoc_ap_ssid[elems.ssid_len] = '\0'; hapd->assoc_ap_ssid_len = elems.ssid_len; } ieee802_11_sta_authenticate(hapd, NULL); } if (!HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_EXCESSIVE)) return; printf("Beacon from " MACSTR, MAC2STR(mgmt->sa)); if (elems.ssid) { printf(" SSID='"); ieee802_11_print_ssid(elems.ssid, elems.ssid_len); printf("'"); } if (elems.ds_params && elems.ds_params_len == 1) printf(" CHAN=%d", elems.ds_params[0]); printf("\n"); }
static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan) { struct ieee80211_ht_operation *oper; struct ieee802_11_elems elems; *pri_chan = *sec_chan = 0; ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); if (elems.ht_operation && elems.ht_operation_len >= sizeof(*oper)) { oper = (struct ieee80211_ht_operation *) elems.ht_operation; *pri_chan = oper->control_chan; if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) *sec_chan = *pri_chan + 4; else if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) *sec_chan = *pri_chan - 4; } } }
void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { struct ieee80211_local *local = sdata->local; struct ieee802_11_elems elems; struct sta_info *sta; enum plink_event event; enum plink_frame_type ftype; size_t baselen; u8 ie_len; u8 *baseaddr; __le16 plid, llid, reason; #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG static const char *mplstates[] = { [PLINK_LISTEN] = "LISTEN", [PLINK_OPN_SNT] = "OPN-SNT", [PLINK_OPN_RCVD] = "OPN-RCVD", [PLINK_CNF_RCVD] = "CNF_RCVD", [PLINK_ESTAB] = "ESTAB", [PLINK_HOLDING] = "HOLDING", [PLINK_BLOCKED] = "BLOCKED" }; #endif /* need action_code, aux */ if (len < IEEE80211_MIN_ACTION_SIZE + 3) return; if (is_multicast_ether_addr(mgmt->da)) { mpl_dbg("Mesh plink: ignore frame from multicast address"); return; } baseaddr = mgmt->u.action.u.plink_action.variable; baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) { baseaddr += 4; baselen += 4; } ieee802_11_parse_elems(baseaddr, len - baselen, &elems); if (!elems.peer_link) { mpl_dbg("Mesh plink: missing necessary peer link ie\n"); return; } ftype = mgmt->u.action.u.plink_action.action_code; ie_len = elems.peer_link_len; if ((ftype == PLINK_OPEN && ie_len != 6) || (ftype == PLINK_CONFIRM && ie_len != 8) || (ftype == PLINK_CLOSE && ie_len != 8 && ie_len != 10)) { mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", ftype, ie_len); return; } if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) { mpl_dbg("Mesh plink: missing necessary ie\n"); return; } /* Note the lines below are correct, the llid in the frame is the plid * from the point of view of this host. */ memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 10)) memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); if (!sta && ftype != PLINK_OPEN) { mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); rcu_read_unlock(); return; } if (sta && sta->plink_state == PLINK_BLOCKED) { rcu_read_unlock(); return; } /* Now we will figure out the appropriate event... */ event = PLINK_UNDEFINED; if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, sdata))) { switch (ftype) { case PLINK_OPEN: event = OPN_RJCT; break; case PLINK_CONFIRM: event = CNF_RJCT; break; case PLINK_CLOSE: /* avoid warning */ break; } spin_lock_bh(&sta->lock); } else if (!sta) { /* ftype == PLINK_OPEN */ u32 rates; rcu_read_unlock(); if (!mesh_plink_free_count(sdata)) { mpl_dbg("Mesh plink error: no more free plinks\n"); return; } rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); sta = mesh_plink_alloc(sdata, mgmt->sa, rates); if (!sta) { mpl_dbg("Mesh plink error: plink table full\n"); return; } if (sta_info_insert_rcu(sta)) { rcu_read_unlock(); return; } event = OPN_ACPT; spin_lock_bh(&sta->lock); } else { spin_lock_bh(&sta->lock); switch (ftype) { case PLINK_OPEN: if (!mesh_plink_free_count(sdata) || (sta->plid && sta->plid != plid)) event = OPN_IGNR; else event = OPN_ACPT; break; case PLINK_CONFIRM: if (!mesh_plink_free_count(sdata) || (sta->llid != llid || sta->plid != plid)) event = CNF_IGNR; else event = CNF_ACPT; break; case PLINK_CLOSE: if (sta->plink_state == PLINK_ESTAB) /* Do not check for llid or plid. This does not * follow the standard but since multiple plinks * per sta are not supported, it is necessary in * order to avoid a livelock when MP A sees an * establish peer link to MP B but MP B does not * see it. This can be caused by a timeout in * B's peer link establishment or B beign * restarted. */ event = CLS_ACPT; else if (sta->plid != plid) event = CLS_IGNR; else if (ie_len == 7 && sta->llid != llid) event = CLS_IGNR; else event = CLS_ACPT; break; default: mpl_dbg("Mesh plink: unknown frame subtype\n"); spin_unlock_bh(&sta->lock); rcu_read_unlock(); return; } } mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", mgmt->sa, mplstates[sta->plink_state], le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), event); reason = 0; switch (sta->plink_state) { /* spin_unlock as soon as state is updated at each case */ case PLINK_LISTEN: switch (event) { case CLS_ACPT: mesh_plink_fsm_restart(sta); spin_unlock_bh(&sta->lock); break; case OPN_ACPT: sta->plink_state = PLINK_OPN_RCVD; sta->plid = plid; get_random_bytes(&llid, 2); sta->llid = llid; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid, 0, 0); mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, plid, 0); break; default: spin_unlock_bh(&sta->lock); break; } break; case PLINK_OPN_SNT: switch (event) { case OPN_RJCT: case CNF_RJCT: reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); case CLS_ACPT: if (!reason) reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; sta->plink_state = PLINK_HOLDING; if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; llid = sta->llid; spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, reason); break; case OPN_ACPT: /* retry timer is left untouched */ sta->plink_state = PLINK_OPN_RCVD; sta->plid = plid; llid = sta->llid; spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, plid, 0); break; case CNF_ACPT: sta->plink_state = PLINK_CNF_RCVD; if (!mod_plink_timer(sta, dot11MeshConfirmTimeout(sdata))) sta->ignore_plink_timer = true; spin_unlock_bh(&sta->lock); break; default: spin_unlock_bh(&sta->lock); break; } break; case PLINK_OPN_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); case CLS_ACPT: if (!reason) reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; sta->plink_state = PLINK_HOLDING; if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; llid = sta->llid; spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, reason); break; case OPN_ACPT: llid = sta->llid; spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, plid, 0); break; case CNF_ACPT: del_timer(&sta->plink_timer); sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); break; default: spin_unlock_bh(&sta->lock); break; } break; case PLINK_CNF_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); case CLS_ACPT: if (!reason) reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; sta->plink_state = PLINK_HOLDING; if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; llid = sta->llid; spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, reason); break; case OPN_ACPT: del_timer(&sta->plink_timer); sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, plid, 0); break; default: spin_unlock_bh(&sta->lock); break; } break; case PLINK_ESTAB: switch (event) { case CLS_ACPT: reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; __mesh_plink_deactivate(sta); sta->plink_state = PLINK_HOLDING; llid = sta->llid; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, reason); break; case OPN_ACPT: llid = sta->llid; spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, plid, 0); break; default: spin_unlock_bh(&sta->lock); break; } break; case PLINK_HOLDING: switch (event) { case CLS_ACPT: if (del_timer(&sta->plink_timer)) sta->ignore_plink_timer = 1; mesh_plink_fsm_restart(sta); spin_unlock_bh(&sta->lock); break; case OPN_ACPT: case CNF_ACPT: case OPN_RJCT: case CNF_RJCT: llid = sta->llid; reason = sta->reason; spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, reason); break; default: spin_unlock_bh(&sta->lock); } break; default: /* should not get here, PLINK_BLOCKED is dealt with at the * beggining of the function */ spin_unlock_bh(&sta->lock); break; } rcu_read_unlock(); }
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; }
void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, const u8 *bssid, u16 auth_type) { struct wpa_driver_associate_params params; struct ieee802_11_elems elems; #ifdef CONFIG_HT_OVERRIDES struct ieee80211_ht_capabilities htcaps; struct ieee80211_ht_capabilities htcaps_mask; #endif /* CONFIG_HT_OVERRIDES */ os_memset(¶ms, 0, sizeof(params)); params.bssid = bssid; params.ssid = wpa_s->sme.ssid; params.ssid_len = wpa_s->sme.ssid_len; params.freq = wpa_s->sme.freq; params.bg_scan_period = wpa_s->current_ssid ? wpa_s->current_ssid->bg_scan_period : -1; params.wpa_ie = wpa_s->sme.assoc_req_ie_len ? wpa_s->sme.assoc_req_ie : NULL; params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher); params.group_suite = cipher_suite2driver(wpa_s->group_cipher); #ifdef CONFIG_HT_OVERRIDES os_memset(&htcaps, 0, sizeof(htcaps)); os_memset(&htcaps_mask, 0, sizeof(htcaps_mask)); params.htcaps = (u8 *) &htcaps; params.htcaps_mask = (u8 *) &htcaps_mask; wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, ¶ms); #endif /* CONFIG_HT_OVERRIDES */ #ifdef CONFIG_IEEE80211R if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { params.wpa_ie = wpa_s->sme.ft_ies; params.wpa_ie_len = wpa_s->sme.ft_ies_len; } #endif /* CONFIG_IEEE80211R */ params.mode = mode; params.mgmt_frame_protection = wpa_s->sme.mfp; if (wpa_s->sme.prev_bssid_set) params.prev_bssid = wpa_s->sme.prev_bssid; wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid), params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "", params.freq); wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING); if (params.wpa_ie == NULL || ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0) < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Could not parse own IEs?!"); os_memset(&elems, 0, sizeof(elems)); } if (elems.rsn_ie) { params.wpa_proto = WPA_PROTO_RSN; wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2, elems.rsn_ie_len + 2); } else if (elems.wpa_ie) { params.wpa_proto = WPA_PROTO_WPA; wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2, elems.wpa_ie_len + 2); } else wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group) params.p2p = 1; if (wpa_s->parent->set_sta_uapsd) params.uapsd = wpa_s->parent->sta_uapsd; else params.uapsd = -1; if (wpa_drv_associate(wpa_s, ¶ms) < 0) { wpa_msg(wpa_s, MSG_INFO, "SME: Association request to the " "driver failed"); wpas_connection_failed(wpa_s, wpa_s->pending_bssid); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); return; } eloop_register_timeout(SME_ASSOC_TIMEOUT, 0, sme_assoc_timer, wpa_s, NULL); }
void wmm_ac_rx_action(struct wpa_supplicant *wpa_s, const u8 *da, const u8 *sa, const u8 *data, size_t len) { u8 action; u8 dialog_token; u8 status_code; struct ieee802_11_elems elems; struct wmm_tspec_element *tspec; if (wpa_s->wmm_ac_assoc_info == NULL) { wpa_printf(MSG_WARNING, "WMM AC: WMM AC is disabled, ignoring action frame"); return; } action = data[0]; if (action != WMM_ACTION_CODE_ADDTS_RESP && action != WMM_ACTION_CODE_DELTS) { wpa_printf(MSG_WARNING, "WMM AC: Unknown action (%d), ignoring action frame", action); return; } /* WMM AC action frame */ if (os_memcmp(da, wpa_s->own_addr, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "WMM AC: frame destination addr="MACSTR " is other than ours, ignoring frame", MAC2STR(da)); return; } if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "WMM AC: ignore frame with sa " MACSTR " different other than our bssid", MAC2STR(da)); return; } if (len < 2 + sizeof(struct wmm_tspec_element)) { wpa_printf(MSG_DEBUG, "WMM AC: Short ADDTS response ignored (len=%lu)", (unsigned long) len); return; } data++; len--; dialog_token = data[0]; status_code = data[1]; if (ieee802_11_parse_elems(data + 2, len - 2, &elems, 1) != ParseOK) { wpa_printf(MSG_DEBUG, "WMM AC: Could not parse WMM AC action from " MACSTR, MAC2STR(sa)); return; } /* the struct also contains the type and value, so decrease it */ if (elems.wmm_tspec_len != sizeof(struct wmm_tspec_element) - 2) { wpa_printf(MSG_DEBUG, "WMM AC: missing or wrong length TSPEC"); return; } tspec = (struct wmm_tspec_element *)(elems.wmm_tspec - 2); wpa_printf(MSG_DEBUG, "WMM AC: RX WMM AC Action from " MACSTR, MAC2STR(sa)); wpa_hexdump(MSG_MSGDUMP, "WMM AC: WMM AC Action content", data, len); switch (action) { case WMM_ACTION_CODE_ADDTS_RESP: wmm_ac_handle_addts_resp(wpa_s, sa, dialog_token, status_code, tspec); break; case WMM_ACTION_CODE_DELTS: wmm_ac_handle_delts(wpa_s, sa, tspec); break; default: break; } }
static void rx_data_tdls_setup_confirm(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr, const u8 *dst, const u8 *src, const u8 *data, size_t len) { u16 status; struct ieee802_11_elems elems; struct wlantest_tdls *tdls; u8 link_id[3 * ETH_ALEN]; if (len < 3) { add_note(wt, MSG_INFO, "Too short TDLS Setup Confirm " MACSTR " -> " MACSTR, MAC2STR(src), MAC2STR(dst)); return; } status = WPA_GET_LE16(data); wpa_printf(MSG_DEBUG, "TDLS Setup Confirm " MACSTR " -> " MACSTR " (status %d)", MAC2STR(src), MAC2STR(dst), status); if (ieee802_11_parse_elems(data + 3, len - 3, &elems, 1) == ParseFailed || elems.link_id == NULL) { /* Need to match TDLS link based on Dialog Token */ rx_data_tdls_setup_confirm_failure(wt, bssid, src, data[2], status); return; } wpa_printf(MSG_DEBUG, "TDLS Link Identifier: BSSID " MACSTR " initiator STA " MACSTR " responder STA " MACSTR, MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN), MAC2STR(elems.link_id + 2 * ETH_ALEN)); tdls = get_tdls(wt, elems.link_id, 1, bssid); if (tdls == NULL) return; if (status) tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_CONF_FAIL]++; else tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_CONF_OK]++; if (status != WLAN_STATUS_SUCCESS) return; if (elems.ftie && elems.ftie_len >= sizeof(struct rsn_ftie)) { const struct rsn_ftie *f; f = (const struct rsn_ftie *) elems.ftie; if (os_memcmp(tdls->inonce, f->snonce, WPA_NONCE_LEN) != 0) { add_note(wt, MSG_INFO, "Mismatch in TDLS initiator " "nonce"); } if (os_memcmp(tdls->rnonce, f->anonce, WPA_NONCE_LEN) != 0) { add_note(wt, MSG_INFO, "Mismatch in TDLS responder " "nonce"); } } tdls->link_up = 1; if (tdls_derive_tpk(tdls, bssid, elems.ftie, elems.ftie_len) < 1) { if (elems.ftie == NULL) goto remove_reverse; return; } if (tdls_verify_mic(wt, tdls, 3, &elems) == 0) { tdls->dialog_token = data[2]; add_note(wt, MSG_DEBUG, "TDLS: Link up - Dialog Token: %u", tdls->dialog_token); } remove_reverse: /* * The TDLS link itself is bidirectional, but there is explicit * initiator/responder roles. Remove the other direction of the link * (if it exists) to make sure that the link counters are stored for * the current TDLS entery. */ os_memcpy(link_id, elems.link_id, ETH_ALEN); os_memcpy(link_id + ETH_ALEN, elems.link_id + 2 * ETH_ALEN, ETH_ALEN); os_memcpy(link_id + 2 * ETH_ALEN, elems.link_id + ETH_ALEN, ETH_ALEN); tdls = get_tdls(wt, link_id, 0, bssid); if (tdls) { add_note(wt, MSG_DEBUG, "TDLS: Remove reverse link entry"); tdls_deinit(tdls); } }
void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_mgmt *resp; struct ieee802_11_elems elems; char *ssid; u8 *pos, *epos; const u8 *ie; size_t ssid_len, ie_len; struct sta_info *sta = NULL; size_t buflen; size_t i; ie = mgmt->u.probe_req.variable; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) return; ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, mgmt->sa, mgmt->da, mgmt->bssid, ie, ie_len) > 0) return; if (!hapd->iconf->send_probe_response) return; if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR, MAC2STR(mgmt->sa)); return; } ssid = NULL; ssid_len = 0; if ((!elems.ssid || !elems.supp_rates)) { wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " "without SSID or supported rates element", MAC2STR(mgmt->sa)); return; } #ifdef CONFIG_P2P if (hapd->p2p && elems.wps_ie) { struct wpabuf *wps; wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) { wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " "due to mismatch with Requested Device " "Type"); wpabuf_free(wps); return; } wpabuf_free(wps); } if (hapd->p2p && elems.p2p) { struct wpabuf *p2p; p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE); if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) { wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " "due to mismatch with Device ID"); wpabuf_free(p2p); return; } wpabuf_free(p2p); } #endif /* CONFIG_P2P */ if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for " "broadcast SSID ignored", MAC2STR(mgmt->sa)); return; } sta = ap_get_sta(hapd, mgmt->sa); #ifdef CONFIG_P2P if ((hapd->conf->p2p & P2P_GROUP_OWNER) && elems.ssid_len == P2P_WILDCARD_SSID_LEN && os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) { /* Process P2P Wildcard SSID like Wildcard SSID */ elems.ssid_len = 0; } #endif /* CONFIG_P2P */ if (elems.ssid_len == 0 || (elems.ssid_len == hapd->conf->ssid.ssid_len && os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) == 0)) { ssid = hapd->conf->ssid.ssid; ssid_len = hapd->conf->ssid.ssid_len; if (sta) sta->ssid_probe = &hapd->conf->ssid; } if (!ssid) { if (!(mgmt->da[0] & 0x01)) { char ssid_txt[33]; ieee802_11_print_ssid(ssid_txt, elems.ssid, elems.ssid_len); wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for foreign SSID '%s' (DA " MACSTR ")", MAC2STR(mgmt->sa), ssid_txt, MAC2STR(mgmt->da)); } return; } #ifdef CONFIG_INTERWORKING if (elems.interworking && elems.interworking_len >= 1) { u8 ant = elems.interworking[0] & 0x0f; if (ant != INTERWORKING_ANT_WILDCARD && ant != hapd->conf->access_network_type) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for mismatching ANT %u ignored", MAC2STR(mgmt->sa), ant); return; } } if (elems.interworking && (elems.interworking_len == 7 || elems.interworking_len == 9)) { const u8 *hessid; if (elems.interworking_len == 7) hessid = elems.interworking + 1; else hessid = elems.interworking + 1 + 2; if (!is_broadcast_ether_addr(hessid) && os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for mismatching HESSID " MACSTR " ignored", MAC2STR(mgmt->sa), MAC2STR(hessid)); return; } } #endif /* CONFIG_INTERWORKING */ /* TODO: verify that supp_rates contains at least one matching rate * with AP configuration */ #define MAX_PROBERESP_LEN 768 buflen = MAX_PROBERESP_LEN; #ifdef CONFIG_WPS if (hapd->wps_probe_resp_ie) buflen += wpabuf_len(hapd->wps_probe_resp_ie); #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P if (hapd->p2p_probe_resp_ie) buflen += wpabuf_len(hapd->p2p_probe_resp_ie); #endif /* CONFIG_P2P */ resp = os_zalloc(buflen); if (resp == NULL) return; epos = ((u8 *) resp) + MAX_PROBERESP_LEN; resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_PROBE_RESP); os_memcpy(resp->da, mgmt->sa, ETH_ALEN); os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); resp->u.probe_resp.beacon_int = host_to_le16(hapd->iconf->beacon_int); /* hardware or low-level driver will setup seq_ctrl and timestamp */ resp->u.probe_resp.capab_info = host_to_le16(hostapd_own_capab_info(hapd, sta, 1)); pos = resp->u.probe_resp.variable; *pos++ = WLAN_EID_SSID; *pos++ = ssid_len; os_memcpy(pos, ssid, ssid_len); pos += ssid_len; /* Supported rates */ pos = hostapd_eid_supp_rates(hapd, pos); /* DS Params */ pos = hostapd_eid_ds_params(hapd, pos); pos = hostapd_eid_country(hapd, pos, epos - pos); /* ERP Information element */ pos = hostapd_eid_erp_info(hapd, pos); /* Extended supported rates */ pos = hostapd_eid_ext_supp_rates(hapd, pos); /* RSN, MDIE, WPA */ pos = hostapd_eid_wpa(hapd, pos, epos - pos); #ifdef CONFIG_IEEE80211N pos = hostapd_eid_ht_capabilities(hapd, pos); pos = hostapd_eid_ht_operation(hapd, pos); #endif /* CONFIG_IEEE80211N */ pos = hostapd_eid_ext_capab(hapd, pos); pos = hostapd_eid_time_adv(hapd, pos); pos = hostapd_eid_time_zone(hapd, pos); pos = hostapd_eid_interworking(hapd, pos); pos = hostapd_eid_adv_proto(hapd, pos); pos = hostapd_eid_roaming_consortium(hapd, pos); /* Wi-Fi Alliance WMM */ pos = hostapd_eid_wmm(hapd, pos); #ifdef CONFIG_WPS if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), wpabuf_len(hapd->wps_probe_resp_ie)); pos += wpabuf_len(hapd->wps_probe_resp_ie); } #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P if ((hapd->conf->p2p & P2P_ENABLED) && elems.p2p && hapd->p2p_probe_resp_ie) { os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), wpabuf_len(hapd->p2p_probe_resp_ie)); pos += wpabuf_len(hapd->p2p_probe_resp_ie); } #endif /* CONFIG_P2P */ #ifdef CONFIG_P2P_MANAGER if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == P2P_MANAGE) pos = hostapd_eid_p2p_manage(hapd, pos); #endif /* CONFIG_P2P_MANAGER */ if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0) perror("handle_probe_req: send"); os_free(resp); wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s " "SSID", MAC2STR(mgmt->sa), elems.ssid_len == 0 ? "broadcast" : "our"); }
static void handle_assoc(hostapd *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; struct sta_info *sta; struct ieee802_11_elems elems; 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); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "reassociation request: STA=" MACSTR " capab_info=0x%02x " "listen_interval=%d current_ap=" MACSTR "\n", 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); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "association request: STA=" MACSTR " capab_info=0x%02x listen_interval=%d\n", 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); 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; } sta->capability = capab_info; /* followed by SSID and Supported rates */ if (ieee802_11_parse_elems(hapd, 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_len || memcmp(elems.ssid, hapd->conf->ssid, elems.ssid_len) != 0) { printf("Station " MACSTR " tried to associate with " "unknown SSID '", MAC2STR(sta->addr)); ieee802_11_print_ssid(elems.ssid, elems.ssid_len); printf("'\n"); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } if (elems.supp_rates) { if (elems.supp_rates_len > sizeof(sta->supported_rates)) { printf("STA " MACSTR ": Invalid supported rates " "element length %d\n", MAC2STR(sta->addr), elems.supp_rates_len); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); memcpy(sta->supported_rates, elems.supp_rates, elems.supp_rates_len); sta->tx_supp_rates = 0; for (i = 0; i < elems.supp_rates_len; i++) { if ((sta->supported_rates[i] & 0x7f) == 2) sta->tx_supp_rates |= WLAN_RATE_1M; if ((sta->supported_rates[i] & 0x7f) == 4) sta->tx_supp_rates |= WLAN_RATE_2M; if ((sta->supported_rates[i] & 0x7f) == 11) sta->tx_supp_rates |= WLAN_RATE_5M5; if ((sta->supported_rates[i] & 0x7f) == 22) sta->tx_supp_rates |= WLAN_RATE_11M; } } else sta->tx_supp_rates = 0xff; if ((hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA2) && elems.rsn_ie) { wpa_ie = elems.rsn_ie; wpa_ie_len = elems.rsn_ie_len; } else if ((hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA) && elems.wpa_ie) { wpa_ie = elems.wpa_ie; wpa_ie_len = elems.wpa_ie_len; } else { wpa_ie = NULL; wpa_ie_len = 0; } 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) { int res; wpa_ie -= 2; wpa_ie_len += 2; res = wpa_validate_wpa_ie(hapd, sta, wpa_ie, wpa_ie_len, elems.rsn_ie ? HOSTAPD_WPA_VERSION_WPA2 : HOSTAPD_WPA_VERSION_WPA); 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_IE_OK) resp = WLAN_STATUS_INVALID_IE; if (resp != WLAN_STATUS_SUCCESS) goto fail; free(sta->wpa_ie); sta->wpa_ie = malloc(wpa_ie_len); if (sta->wpa_ie == NULL) { resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } sta->wpa_ie_len = wpa_ie_len; memcpy(sta->wpa_ie, wpa_ie, wpa_ie_len); } /* get a unique AID */ if (sta->aid > 0) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " old AID %d\n", sta->aid); } else { for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) if (hapd->sta_aid[sta->aid - 1] == NULL) break; if (sta->aid > MAX_AID_TABLE_SIZE) { sta->aid = 0; resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; printf(" no room for more AIDs\n"); goto fail; } else { hapd->sta_aid[sta->aid - 1] = sta; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " new AID %d\n", sta->aid); } } hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "association OK (aid %d)", sta->aid); /* Station will be marked associated, after it acknowledges AssocResp */ if (sta->last_assoc_req) free(sta->last_assoc_req); sta->last_assoc_req = (struct ieee80211_mgmt *) malloc(len); if (sta->last_assoc_req) memcpy(sta->last_assoc_req, mgmt, len); /* Make sure that the previously registered inactivity timer will not * remove the STA immediately. */ sta->timeout_next = STA_NULLFUNC; fail: /* use the queued buffer for transmission because it is large enough * and not needed anymore */ mgmt->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))); memcpy(mgmt->da, mgmt->sa, ETH_ALEN); memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); /* Addr3 = BSSID - already set */ send_len = IEEE80211_HDRLEN; if (send_deauth) { send_len += sizeof(mgmt->u.deauth); mgmt->u.deauth.reason_code = host_to_le16(resp); } else { u8 *p; send_len += sizeof(mgmt->u.assoc_resp); mgmt->u.assoc_resp.capab_info = host_to_le16(hostapd_own_capab_info(hapd)); mgmt->u.assoc_resp.status_code = host_to_le16(resp); mgmt->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) | BIT(14) | BIT(15)); /* Supported rates */ p = hostapd_eid_supp_rates(hapd, mgmt->u.assoc_resp.variable); send_len += p - mgmt->u.assoc_resp.variable; /* Request TX callback */ mgmt->frame_control |= host_to_le16(BIT(1)); } if (hostapd_send_mgmt_frame(hapd, mgmt, send_len, 0) < 0) perror("handle_assoc: send"); }
void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int ssi_signal) { u8 *resp; struct ieee802_11_elems elems; const u8 *ie; size_t ie_len; size_t i, resp_len; int noack; enum ssid_match_result res; int ret; u16 csa_offs[2]; size_t csa_offs_len; ie = mgmt->u.probe_req.variable; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) return; if (hapd->iconf->track_sta_max_num) sta_track_add(hapd->iface, mgmt->sa); ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, mgmt->sa, mgmt->da, mgmt->bssid, ie, ie_len, ssi_signal) > 0) return; if (!hapd->iconf->send_probe_response) return; if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR, MAC2STR(mgmt->sa)); return; } if ((!elems.ssid || !elems.supp_rates)) { wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " "without SSID or supported rates element", MAC2STR(mgmt->sa)); return; } /* * No need to reply if the Probe Request frame was sent on an adjacent * channel. IEEE Std 802.11-2012 describes this as a requirement for an * AP with dot11RadioMeasurementActivated set to true, but strictly * speaking does not allow such ignoring of Probe Request frames if * dot11RadioMeasurementActivated is false. Anyway, this can help reduce * number of unnecessary Probe Response frames for cases where the STA * is less likely to see them (Probe Request frame sent on a * neighboring, but partially overlapping, channel). */ if (elems.ds_params && hapd->iface->current_mode && (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G || hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) && hapd->iconf->channel != elems.ds_params[0]) { wpa_printf(MSG_DEBUG, "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u", hapd->iconf->channel, elems.ds_params[0]); return; } #ifdef CONFIG_P2P if (hapd->p2p && hapd->p2p_group && elems.wps_ie) { struct wpabuf *wps; wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) { wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " "due to mismatch with Requested Device " "Type"); wpabuf_free(wps); return; } wpabuf_free(wps); } if (hapd->p2p && hapd->p2p_group && elems.p2p) { struct wpabuf *p2p; p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE); if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) { wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " "due to mismatch with Device ID"); wpabuf_free(p2p); return; } wpabuf_free(p2p); } #endif /* CONFIG_P2P */ if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 && elems.ssid_list_len == 0) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for " "broadcast SSID ignored", MAC2STR(mgmt->sa)); return; } #ifdef CONFIG_P2P if ((hapd->conf->p2p & P2P_GROUP_OWNER) && elems.ssid_len == P2P_WILDCARD_SSID_LEN && os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) { /* Process P2P Wildcard SSID like Wildcard SSID */ elems.ssid_len = 0; } #endif /* CONFIG_P2P */ res = ssid_match(hapd, elems.ssid, elems.ssid_len, elems.ssid_list, elems.ssid_list_len); if (res == NO_SSID_MATCH) { if (!(mgmt->da[0] & 0x01)) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for foreign SSID '%s' (DA " MACSTR ")%s", MAC2STR(mgmt->sa), wpa_ssid_txt(elems.ssid, elems.ssid_len), MAC2STR(mgmt->da), elems.ssid_list ? " (SSID list)" : ""); } return; } #ifdef CONFIG_INTERWORKING if (hapd->conf->interworking && elems.interworking && elems.interworking_len >= 1) { u8 ant = elems.interworking[0] & 0x0f; if (ant != INTERWORKING_ANT_WILDCARD && ant != hapd->conf->access_network_type) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for mismatching ANT %u ignored", MAC2STR(mgmt->sa), ant); return; } } if (hapd->conf->interworking && elems.interworking && (elems.interworking_len == 7 || elems.interworking_len == 9)) { const u8 *hessid; if (elems.interworking_len == 7) hessid = elems.interworking + 1; else hessid = elems.interworking + 1 + 2; if (!is_broadcast_ether_addr(hessid) && os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for mismatching HESSID " MACSTR " ignored", MAC2STR(mgmt->sa), MAC2STR(hessid)); return; } } #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_P2P if ((hapd->conf->p2p & P2P_GROUP_OWNER) && supp_rates_11b_only(&elems)) { /* Indicates support for 11b rates only */ wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from " MACSTR " with only 802.11b rates", MAC2STR(mgmt->sa)); return; } #endif /* CONFIG_P2P */ /* TODO: verify that supp_rates contains at least one matching rate * with AP configuration */ if (hapd->conf->no_probe_resp_if_seen_on && is_multicast_ether_addr(mgmt->da) && is_multicast_ether_addr(mgmt->bssid) && sta_track_seen_on(hapd->iface, mgmt->sa, hapd->conf->no_probe_resp_if_seen_on)) { wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR " since STA has been seen on %s", hapd->conf->iface, MAC2STR(mgmt->sa), hapd->conf->no_probe_resp_if_seen_on); return; } if (hapd->conf->no_probe_resp_if_max_sta && is_multicast_ether_addr(mgmt->da) && is_multicast_ether_addr(mgmt->bssid) && hapd->num_sta >= hapd->conf->max_num_sta && !ap_get_sta(hapd, mgmt->sa)) { wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR " since no room for additional STA", hapd->conf->iface, MAC2STR(mgmt->sa)); return; } #ifdef CONFIG_TESTING_OPTIONS if (hapd->iconf->ignore_probe_probability > 0.0 && drand48() < hapd->iconf->ignore_probe_probability) { wpa_printf(MSG_INFO, "TESTING: ignoring probe request from " MACSTR, MAC2STR(mgmt->sa)); return; } #endif /* CONFIG_TESTING_OPTIONS */ resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL, &resp_len); if (resp == NULL) return; /* * If this is a broadcast probe request, apply no ack policy to avoid * excessive retries. */ noack = !!(res == WILDCARD_SSID_MATCH && is_broadcast_ether_addr(mgmt->da)); csa_offs_len = 0; if (hapd->csa_in_progress) { if (hapd->cs_c_off_proberesp) csa_offs[csa_offs_len++] = hapd->cs_c_off_proberesp; if (hapd->cs_c_off_ecsa_proberesp) csa_offs[csa_offs_len++] = hapd->cs_c_off_ecsa_proberesp; } ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack, csa_offs_len ? csa_offs : NULL, csa_offs_len); if (ret < 0) wpa_printf(MSG_INFO, "handle_probe_req: send failed"); os_free(resp); wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s " "SSID", MAC2STR(mgmt->sa), elems.ssid_len == 0 ? "broadcast" : "our"); }
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; }
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; }
int check_40mhz_2g4(struct hostapd_hw_modes *mode, struct wpa_scan_results *scan_res, int pri_chan, int sec_chan) { int pri_freq, sec_freq; int affected_start, affected_end; size_t i; if (!mode || !scan_res || !pri_chan || !sec_chan || pri_chan == sec_chan) return 0; pri_freq = hw_get_freq(mode, pri_chan); sec_freq = hw_get_freq(mode, sec_chan); affected_start = (pri_freq + sec_freq) / 2 - 25; affected_end = (pri_freq + sec_freq) / 2 + 25; wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", affected_start, affected_end); for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *bss = scan_res->res[i]; int pri = bss->freq; int sec = pri; struct ieee802_11_elems elems; /* Check for overlapping 20 MHz BSS */ if (check_20mhz_bss(bss, pri_freq, affected_start, affected_end)) { wpa_printf(MSG_DEBUG, "Overlapping 20 MHz BSS is found"); return 0; } get_pri_sec_chan(bss, &pri_chan, &sec_chan); if (sec_chan) { if (sec_chan < pri_chan) sec = pri - 20; else sec = pri + 20; } if ((pri < affected_start || pri > affected_end) && (sec < affected_start || sec > affected_end)) continue; /* not within affected channel range */ wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR " freq=%d pri=%d sec=%d", MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); if (sec_chan) { if (pri_freq != pri || sec_freq != sec) { wpa_printf(MSG_DEBUG, "40 MHz pri/sec mismatch with BSS " MACSTR " <%d,%d> (chan=%d%c) vs. <%d,%d>", MAC2STR(bss->bssid), pri, sec, pri_chan, sec > pri ? '+' : '-', pri_freq, sec_freq); return 0; } } ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); if (elems.ht_capabilities) { 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) { wpa_printf(MSG_DEBUG, "40 MHz Intolerant is set on channel %d in BSS " MACSTR, pri, MAC2STR(bss->bssid)); return 0; } } } return 1; }