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; }
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) { return hw_get_freq(hapd->iface->current_mode, chan); }
int check_40mhz_5g(struct hostapd_hw_modes *mode, struct wpa_scan_results *scan_res, int pri_chan, int sec_chan) { int pri_freq, sec_freq, pri_bss, sec_bss; int bss_pri_chan, bss_sec_chan; size_t i; int match; 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); /* * Switch PRI/SEC channels if Beacons were detected on selected SEC * channel, but not on selected PRI channel. */ pri_bss = sec_bss = 0; for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *bss = scan_res->res[i]; if (bss->freq == pri_freq) pri_bss++; else if (bss->freq == sec_freq) sec_bss++; } if (sec_bss && !pri_bss) { wpa_printf(MSG_INFO, "Switch own primary and secondary channel to get secondary channel with no Beacons from other BSSes"); return 2; } /* * Match PRI/SEC channel with any existing HT40 BSS on the same * channels that we are about to use (if already mixed order in * existing BSSes, use own preference). */ match = 0; for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *bss = scan_res->res[i]; get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); if (pri_chan == bss_pri_chan && sec_chan == bss_sec_chan) { match = 1; break; } } if (!match) { for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *bss = scan_res->res[i]; get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); if (pri_chan == bss_sec_chan && sec_chan == bss_pri_chan) { wpa_printf(MSG_INFO, "Switch own primary and " "secondary channel due to BSS " "overlap with " MACSTR, MAC2STR(bss->bssid)); return 2; } } } return 1; }