void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta, struct ieee802_11_elems *elems) { const u8 *pos, *attr, *end; size_t len; if (!hapd->conf->mbo_enabled || !elems->mbo) return; pos = elems->mbo + 4; len = elems->mbo_len - 4; wpa_hexdump(MSG_DEBUG, "MBO: Association Request attributes", pos, len); attr = get_ie(pos, len, MBO_ATTR_ID_CELL_DATA_CAPA); if (attr && attr[1] >= 1) sta->cell_capa = attr[2]; mbo_ap_sta_free(sta); end = pos + len; while (end - pos > 1) { u8 ie_len = pos[1]; if (2 + ie_len > end - pos) break; if (pos[0] == MBO_ATTR_ID_NON_PREF_CHAN_REPORT) mbo_ap_parse_non_pref_chan(sta, pos + 2, ie_len); pos += 2 + pos[1]; } }
unsigned char *get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit) { int len; u16 val16; unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; u8 *pbuf = pie; while(1) { pbuf = get_ie(pbuf, _WPA_IE_ID_, &len, limit); if (pbuf) { //check if oui matches... if (_memcmp((pbuf + 2), wpa_oui_type, sizeof (wpa_oui_type)) == _FALSE) { goto check_next_ie; } //check version... _memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16)); val16 = le16_to_cpu(val16); if (val16 != 0x0001) goto check_next_ie; *wpa_ie_len = *(pbuf + 1); return pbuf; } else { *wpa_ie_len = 0; return NULL; } check_next_ie: limit = limit - (pbuf - pie) - 2 - len; if (limit <= 0) break; pbuf += (2 + len); } *wpa_ie_len = 0; return NULL; }
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr) { const u8 *mbo, *end; if (!bss) return NULL; mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); if (!mbo) return NULL; end = mbo + 2 + mbo[1]; mbo += MBO_IE_HEADER; return get_ie(mbo, end - mbo, attr); }
unsigned char *get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit) { return get_ie(pie, _WPA2_IE_ID_,rsn_ie_len, limit); }
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, const u8 *pos, const u8 *end, int reply) { unsigned int beacon_int; u8 valid_int; #ifdef CONFIG_MBO const u8 *vendor; #endif /* CONFIG_MBO */ if (end - pos < 5) return; #ifdef CONFIG_MBO wpa_s->wnm_mbo_trans_reason_present = 0; wpa_s->wnm_mbo_transition_reason = 0; #endif /* CONFIG_MBO */ if (wpa_s->current_bss) beacon_int = wpa_s->current_bss->beacon_int; else beacon_int = 100; /* best guess */ wpa_s->wnm_dialog_token = pos[0]; wpa_s->wnm_mode = pos[1]; wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); valid_int = pos[4]; wpa_s->wnm_reply = reply; wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " "dialog_token=%u request_mode=0x%x " "disassoc_timer=%u validity_interval=%u", wpa_s->wnm_dialog_token, wpa_s->wnm_mode, wpa_s->wnm_dissoc_timer, valid_int); #if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS) if (wpa_s->reject_btm_req_reason) { wpa_printf(MSG_INFO, "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", wpa_s->reject_btm_req_reason); wnm_send_bss_transition_mgmt_resp( wpa_s, wpa_s->wnm_dialog_token, wpa_s->reject_btm_req_reason, MBO_TRANSITION_REASON_UNSPECIFIED, 0, NULL); return; } #endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ pos += 5; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { if (end - pos < 12) { wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); return; } os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); pos += 12; /* BSS Termination Duration */ } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { char url[256]; if (end - pos < 1 || 1 + pos[0] > end - pos) { wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " "Management Request (URL)"); return; } os_memcpy(url, pos + 1, pos[0]); url[pos[0]] = '\0'; pos += 1 + pos[0]; wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", wpa_sm_pmf_enabled(wpa_s->wpa), wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { /* TODO: mark current BSS less preferred for * selection */ wpa_printf(MSG_DEBUG, "Trying to find another BSS"); wpa_supplicant_req_scan(wpa_s, 0, 0); } } #ifdef CONFIG_MBO vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC); if (vendor) wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]); #endif /* CONFIG_MBO */ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { unsigned int valid_ms; wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); wnm_deallocate_memory(wpa_s); wpa_s->wnm_neighbor_report_elements = os_calloc( WNM_MAX_NEIGHBOR_REPORT, sizeof(struct neighbor_report)); if (wpa_s->wnm_neighbor_report_elements == NULL) return; while (end - pos >= 2 && wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) { u8 tag = *pos++; u8 len = *pos++; wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", tag); if (len > end - pos) { wpa_printf(MSG_DEBUG, "WNM: Truncated request"); return; } if (tag == WLAN_EID_NEIGHBOR_REPORT) { struct neighbor_report *rep; rep = &wpa_s->wnm_neighbor_report_elements[ wpa_s->wnm_num_neighbor_report]; wnm_parse_neighbor_report(wpa_s, pos, len, rep); wpa_s->wnm_num_neighbor_report++; #ifdef CONFIG_MBO if (wpa_s->wnm_mbo_trans_reason_present && wpa_s->wnm_num_neighbor_report == 1) { rep->is_first = 1; wpa_printf(MSG_DEBUG, "WNM: First transition candidate is " MACSTR, MAC2STR(rep->bssid)); } #endif /* CONFIG_MBO */ } pos += len; } if (!wpa_s->wnm_num_neighbor_report) { wpa_printf(MSG_DEBUG, "WNM: Candidate list included bit is set, but no candidates found"); wnm_send_bss_transition_mgmt_resp( wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, MBO_TRANSITION_REASON_UNSPECIFIED, 0, NULL); return; } wnm_sort_cand_list(wpa_s); wnm_dump_cand_list(wpa_s); valid_ms = valid_int * beacon_int * 128 / 125; wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", valid_ms); os_get_reltime(&wpa_s->wnm_cand_valid_until); wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; wpa_s->wnm_cand_valid_until.sec += wpa_s->wnm_cand_valid_until.usec / 1000000; wpa_s->wnm_cand_valid_until.usec %= 1000000; os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); /* * Fetch the latest scan results from the kernel and check for * candidates based on those results first. This can help in * finding more up-to-date information should the driver has * done some internal scanning operations after the last scan * result update in wpa_supplicant. */ if (wnm_fetch_scan_results(wpa_s) > 0) return; /* * Try to use previously received scan results, if they are * recent enough to use for a connection. */ if (wpa_s->last_scan_res_used > 0) { struct os_reltime now; os_get_reltime(&now); if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { wpa_printf(MSG_DEBUG, "WNM: Try to use recent scan results"); if (wnm_scan_process(wpa_s, 0) > 0) return; wpa_printf(MSG_DEBUG, "WNM: No match in previous scan results - try a new scan"); } } wnm_set_scan_freqs(wpa_s); if (wpa_s->wnm_num_neighbor_report == 1) { os_memcpy(wpa_s->next_scan_bssid, wpa_s->wnm_neighbor_report_elements[0].bssid, ETH_ALEN); wpa_printf(MSG_DEBUG, "WNM: Scan only for a specific BSSID since there is only a single candidate " MACSTR, MAC2STR(wpa_s->next_scan_bssid)); } wpa_supplicant_req_scan(wpa_s, 0, 0); } else if (reply) { enum bss_trans_mgmt_status_code status; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) status = WNM_BSS_TM_ACCEPT; else { wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); status = WNM_BSS_TM_REJECT_UNSPECIFIED; } wnm_send_bss_transition_mgmt_resp( wpa_s, wpa_s->wnm_dialog_token, status, MBO_TRANSITION_REASON_UNSPECIFIED, 0, NULL); } }
static int rtl871x_set_beacon_ops(void *priv, struct wpa_driver_ap_params *params) { int ret; size_t sz; ieee_param *pparam; struct rtl871x_driver_data *drv = priv; struct hostapd_data *hapd = drv->hapd; u8 *ssid_ie; u8 ssid_len; u8 expend_len = 0; if ((params->head_len<24) ||(!params->head)) return -1; printf("%s\n", __func__); #ifdef RTL871X_HIDDEN_SSID_SUPPORT rtl871x_set_hidden_ssid_ops(drv->iface, priv, hapd->conf->ignore_broadcast_ssid); ssid_ie = get_ie((params->head+24+12), (params->head_len-24-12), WLAN_EID_SSID); if (hapd->conf->ignore_broadcast_ssid == 2) { ssid_len = ssid_ie[1]; /* confirm the ssid_len */ if (ssid_len != hapd->conf->ssid.ssid_len) { printf("%s ssid_len(%u) != hapd->conf->ssid.ssid_len(%u)!!\n", __func__ , ssid_len, hapd->conf->ssid.ssid_len ); } memcpy(ssid_ie+2, hapd->conf->ssid.ssid, ssid_len); } else if (hapd->conf->ignore_broadcast_ssid == 1) { expend_len = hapd->conf->ssid.ssid_len; printf("%s ignore_broadcast_ssid:%d, %s,%d, expend_len:%u\n", __func__ , hapd->conf->ignore_broadcast_ssid , hapd->conf->ssid.ssid , hapd->conf->ssid.ssid_len , expend_len ); } #endif /* RTL871X_HIDDEN_SSID_SUPPORT */ sz = params->head_len+params->tail_len+12-24 + 2 + expend_len; // 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed pparam = os_zalloc(sz); if (pparam == NULL) { return -ENOMEM; } pparam->cmd = RTL871X_HOSTAPD_SET_BEACON; memcpy(pparam->u.bcn_ie.reserved, &hapd->conf->max_num_sta, 2); // for set max_num_sta #ifdef RTL871X_HIDDEN_SSID_SUPPORT if (hapd->conf->ignore_broadcast_ssid == 1) { u8 *ssid_ie_next = params->head+24+12+2; size_t head_remain_len = params->head_len-24-12-2; memcpy(pparam->u.bcn_ie.buf, (params->head+24), 12); pparam->u.bcn_ie.buf[12] = WLAN_EID_SSID; pparam->u.bcn_ie.buf[13] = expend_len; memcpy(pparam->u.bcn_ie.buf+12+2, hapd->conf->ssid.ssid, expend_len); memcpy(pparam->u.bcn_ie.buf+12+2+expend_len, ssid_ie_next, head_remain_len); // 24=beacon header len. memcpy(&pparam->u.bcn_ie.buf[params->head_len-24+expend_len], params->tail, params->tail_len); } else #endif /* RTL871X_HIDDEN_SSID_SUPPORT */ { memcpy(pparam->u.bcn_ie.buf, (params->head+24), (params->head_len-24)); // 24=beacon header len. memcpy(&pparam->u.bcn_ie.buf[params->head_len-24], params->tail, params->tail_len); } ret = rtl871x_hostapd_ioctl(drv, pparam, sz); os_free(pparam); return ret; }