1ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt/* 2ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * Common hostapd/wpa_supplicant HW features 3ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> 4ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * Copyright (c) 2015, Qualcomm Atheros, Inc. 5ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * 6ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * This software may be distributed under the terms of the BSD license. 7ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * See README for more details. 8ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt */ 9ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 10ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#include "includes.h" 11ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 12ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#include "common.h" 13ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#include "defs.h" 14ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#include "ieee802_11_defs.h" 15ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#include "ieee802_11_common.h" 16ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#include "hw_features_common.h" 17ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 18ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 19ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstruct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode, 20ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int chan, int *freq) 21ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{ 22ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int i; 23ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 24ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (freq) 25ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt *freq = 0; 26ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 27ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (!mode) 28ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return NULL; 29ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 30ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 31ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct hostapd_channel_data *ch = &mode->channels[i]; 32ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (ch->chan == chan) { 33ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (freq) 34ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt *freq = ch->freq; 35ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return ch; 36ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 37ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 38ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 39ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return NULL; 40ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt} 41ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 42ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 43ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstruct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode, 44ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int freq, int *chan) 45ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{ 46ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int i; 47ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 48ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (chan) 49ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt *chan = 0; 50ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 51ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (!mode) 52ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return NULL; 53ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 54ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 55ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct hostapd_channel_data *ch = &mode->channels[i]; 56ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (ch->freq == freq) { 57ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (chan) 58ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt *chan = ch->chan; 59ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return ch; 60ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 61ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 62ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 63ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return NULL; 64ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt} 65ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 66ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 67ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtint hw_get_freq(struct hostapd_hw_modes *mode, int chan) 68ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{ 69ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int freq; 70ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 71ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt hw_get_channel_chan(mode, chan, &freq); 72ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 73ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return freq; 74ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt} 75ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 76ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 77ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtint hw_get_chan(struct hostapd_hw_modes *mode, int freq) 78ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{ 79ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int chan; 80ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 81ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt hw_get_channel_freq(mode, freq, &chan); 82ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 83ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return chan; 84ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt} 85ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 86ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 87ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtint allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan, 88ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int sec_chan) 89ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{ 90ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int ok, j, first; 91f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140, 92f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt 149, 157, 184, 192 }; 93ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt size_t k; 94ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 95ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (pri_chan == sec_chan || !sec_chan) 96ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 1; /* HT40 not used */ 97ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 98ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_DEBUG, 99ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt "HT40: control channel: %d secondary channel: %d", 100ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt pri_chan, sec_chan); 101ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 102ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt /* Verify that HT40 secondary channel is an allowed 20 MHz 103ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * channel */ 104ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt ok = 0; 105ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt for (j = 0; j < mode->num_channels; j++) { 106ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[j]; 107ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 108ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt chan->chan == sec_chan) { 109ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt ok = 1; 110ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt break; 111ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 112ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 113ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (!ok) { 114ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed", 115ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec_chan); 116ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 0; 117ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 118ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 119ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt /* 120ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * Verify that HT40 primary,secondary channel pair is allowed per 121ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * IEEE 802.11n Annex J. This is only needed for 5 GHz band since 122ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * 2.4 GHz rules allow all cases where the secondary channel fits into 123ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * the list of allowed channels (already checked above). 124ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt */ 125ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) 126ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 1; 127ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 128ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt first = pri_chan < sec_chan ? pri_chan : sec_chan; 129ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 130ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt ok = 0; 131ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt for (k = 0; k < ARRAY_SIZE(allowed); k++) { 132ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (first == allowed[k]) { 133ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt ok = 1; 134ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt break; 135ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 136ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 137ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (!ok) { 138ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed", 139ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt pri_chan, sec_chan); 140ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 0; 141ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 142ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 143ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 1; 144ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt} 145ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 146ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 147ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtvoid get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan) 148ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{ 149ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct ieee80211_ht_operation *oper; 150ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct ieee802_11_elems elems; 151ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 152ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt *pri_chan = *sec_chan = 0; 153ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 154ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 1559d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt if (elems.ht_operation) { 156ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt oper = (struct ieee80211_ht_operation *) elems.ht_operation; 157ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt *pri_chan = oper->primary_chan; 158ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) { 159ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int sec = oper->ht_param & 160ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 161ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 162ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt *sec_chan = *pri_chan + 4; 163ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 164ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt *sec_chan = *pri_chan - 4; 165ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 166ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 167ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt} 168ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 169ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 170ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtint check_40mhz_5g(struct hostapd_hw_modes *mode, 171ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct wpa_scan_results *scan_res, int pri_chan, 172ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int sec_chan) 173ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{ 174ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int pri_freq, sec_freq, pri_bss, sec_bss; 175ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int bss_pri_chan, bss_sec_chan; 176ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt size_t i; 177ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int match; 178ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 1794171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt if (!mode || !scan_res || !pri_chan || !sec_chan || 1804171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt pri_chan == sec_chan) 181ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 0; 182ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 183ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt pri_freq = hw_get_freq(mode, pri_chan); 184ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec_freq = hw_get_freq(mode, sec_chan); 185ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 186ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt /* 187ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * Switch PRI/SEC channels if Beacons were detected on selected SEC 188ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * channel, but not on selected PRI channel. 189ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt */ 190ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt pri_bss = sec_bss = 0; 191ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt for (i = 0; i < scan_res->num; i++) { 192ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 193ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (bss->freq == pri_freq) 194ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt pri_bss++; 195ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt else if (bss->freq == sec_freq) 196ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec_bss++; 197ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 198ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (sec_bss && !pri_bss) { 199ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_INFO, 200ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt "Switch own primary and secondary channel to get secondary channel with no Beacons from other BSSes"); 201ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 2; 202ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 203ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 204ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt /* 205ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * Match PRI/SEC channel with any existing HT40 BSS on the same 206ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * channels that we are about to use (if already mixed order in 207ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt * existing BSSes, use own preference). 208ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt */ 209ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt match = 0; 210ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt for (i = 0; i < scan_res->num; i++) { 211ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 212ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 213ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (pri_chan == bss_pri_chan && 214ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec_chan == bss_sec_chan) { 215ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt match = 1; 216ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt break; 217ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 218ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 219ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (!match) { 220ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt for (i = 0; i < scan_res->num; i++) { 221ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 222ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 223ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (pri_chan == bss_sec_chan && 224ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec_chan == bss_pri_chan) { 225ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_INFO, "Switch own primary and " 226ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt "secondary channel due to BSS " 227ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt "overlap with " MACSTR, 228ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt MAC2STR(bss->bssid)); 229ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 2; 230ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 231ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 232ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 233ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 234ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 1; 235ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt} 236ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 237ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 2384171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidtstatic int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, 2394171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt int end) 240ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{ 241ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct ieee802_11_elems elems; 242ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct ieee80211_ht_operation *oper; 243ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 244ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (bss->freq < start || bss->freq > end || bss->freq == pri_freq) 245ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 0; 246ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 247ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 248ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (!elems.ht_capabilities) { 249ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: " 250ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq); 251ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 1; 252ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 253ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 2549d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt if (elems.ht_operation) { 255ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt oper = (struct ieee80211_ht_operation *) elems.ht_operation; 256ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK) 257ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 0; 258ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 259ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: " 260ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq); 261ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 1; 262ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 263ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 0; 264ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt} 265ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 266ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 267ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtint check_40mhz_2g4(struct hostapd_hw_modes *mode, 268ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct wpa_scan_results *scan_res, int pri_chan, 269ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int sec_chan) 270ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{ 271ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int pri_freq, sec_freq; 272ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int affected_start, affected_end; 273ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt size_t i; 274ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 275d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (!mode || !scan_res || !pri_chan || !sec_chan || 276d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt pri_chan == sec_chan) 277ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 0; 278ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 279ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt pri_freq = hw_get_freq(mode, pri_chan); 280ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec_freq = hw_get_freq(mode, sec_chan); 281ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 282ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 283ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 284ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 285ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt affected_start, affected_end); 286ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt for (i = 0; i < scan_res->num; i++) { 287ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 288ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int pri = bss->freq; 289ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int sec = pri; 290ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct ieee802_11_elems elems; 291ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 292ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt /* Check for overlapping 20 MHz BSS */ 293ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (check_20mhz_bss(bss, pri_freq, affected_start, 294ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt affected_end)) { 295ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_DEBUG, 296ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt "Overlapping 20 MHz BSS is found"); 297ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 0; 298ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 299ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 300ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt get_pri_sec_chan(bss, &pri_chan, &sec_chan); 301ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 302ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (sec_chan) { 303ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (sec_chan < pri_chan) 304ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec = pri - 20; 305ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt else 306ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec = pri + 20; 307ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 308ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 309ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if ((pri < affected_start || pri > affected_end) && 310ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt (sec < affected_start || sec > affected_end)) 311ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt continue; /* not within affected channel range */ 312ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 313ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR 314ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt " freq=%d pri=%d sec=%d", 315ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); 316ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 317ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (sec_chan) { 318ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (pri_freq != pri || sec_freq != sec) { 319ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_DEBUG, 320ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt "40 MHz pri/sec mismatch with BSS " 321ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt MACSTR 322ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt " <%d,%d> (chan=%d%c) vs. <%d,%d>", 323ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt MAC2STR(bss->bssid), 324ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt pri, sec, pri_chan, 325ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec > pri ? '+' : '-', 326ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt pri_freq, sec_freq); 327ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 0; 328ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 329ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 330ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 331ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 332ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 0); 3339d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt if (elems.ht_capabilities) { 334ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt struct ieee80211_ht_capabilities *ht_cap = 335ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt (struct ieee80211_ht_capabilities *) 336ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt elems.ht_capabilities; 337ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 338ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (le_to_host16(ht_cap->ht_capabilities_info) & 339ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt HT_CAP_INFO_40MHZ_INTOLERANT) { 340ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt wpa_printf(MSG_DEBUG, 341ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt "40 MHz Intolerant is set on channel %d in BSS " 342ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt MACSTR, pri, MAC2STR(bss->bssid)); 343ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 0; 344ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 345ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 346ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt } 347ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 348ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return 1; 349ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt} 3507f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt 3517f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt 3527f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidtint hostapd_set_freq_params(struct hostapd_freq_params *data, 3537f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt enum hostapd_hw_mode mode, 3547f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt int freq, int channel, int ht_enabled, 3557f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt int vht_enabled, int sec_channel_offset, 3567f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt int vht_oper_chwidth, int center_segment0, 3577f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt int center_segment1, u32 vht_caps) 3587f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt{ 3597f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt os_memset(data, 0, sizeof(*data)); 3607f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->mode = mode; 3617f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->freq = freq; 3627f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->channel = channel; 3637f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->ht_enabled = ht_enabled; 3647f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->vht_enabled = vht_enabled; 3657f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->sec_channel_offset = sec_channel_offset; 3667f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->center_freq1 = freq + sec_channel_offset * 10; 3677f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->center_freq2 = 0; 3687f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->bandwidth = sec_channel_offset ? 40 : 20; 3697f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt 3707f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt if (data->vht_enabled) switch (vht_oper_chwidth) { 3717f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 3724171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt if (center_segment1 || 3734171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt (center_segment0 != 0 && 3744171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt 5000 + center_segment0 * 5 != data->center_freq1 && 3754171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt 2407 + center_segment0 * 5 != data->center_freq1)) 3767f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return -1; 3777f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt break; 3787f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt case VHT_CHANWIDTH_80P80MHZ: 3797f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) { 3807f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt wpa_printf(MSG_ERROR, 3817f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt "80+80 channel width is not supported!"); 3827f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return -1; 3837f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt } 3847f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt if (center_segment1 == center_segment0 + 4 || 3857f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt center_segment1 == center_segment0 - 4) 3867f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return -1; 3877f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->center_freq2 = 5000 + center_segment1 * 5; 3887f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt /* fall through */ 3897f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 3907f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->bandwidth = 80; 391ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if ((vht_oper_chwidth == VHT_CHANWIDTH_80MHZ && 392ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt center_segment1) || 393ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt (vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ && 394ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt !center_segment1) || 3954171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt !sec_channel_offset) 3967f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return -1; 397dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt if (!center_segment0) { 398dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt if (channel <= 48) 399dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 = 42; 400dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt else if (channel <= 64) 401dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 = 58; 402dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt else if (channel <= 112) 403dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 = 106; 404dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt else if (channel <= 128) 405dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 = 122; 406dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt else if (channel <= 144) 407dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 = 138; 408dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt else if (channel <= 161) 409dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 = 155; 410dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt data->center_freq1 = 5000 + center_segment0 * 5; 411dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt } else { 412dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt /* 413dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt * Note: HT/VHT config and params are coupled. Check if 414dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt * HT40 channel band is in VHT80 Pri channel band 415dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt * configuration. 416dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt */ 417dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt if (center_segment0 == channel + 6 || 418dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 == channel + 2 || 419dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 == channel - 2 || 420dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 == channel - 6) 421dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt data->center_freq1 = 5000 + center_segment0 * 5; 422dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt else 423dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt return -1; 424dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt } 4257f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt break; 4267f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 4277f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt data->bandwidth = 160; 4287f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | 4297f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { 4307f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt wpa_printf(MSG_ERROR, 4317f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt "160MHZ channel width is not supported!"); 4327f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return -1; 4337f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt } 4347f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt if (center_segment1) 4357f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return -1; 4367f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt if (!sec_channel_offset) 4377f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return -1; 438dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt /* 439dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt * Note: HT/VHT config and params are coupled. Check if 440dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt * HT40 channel band is in VHT160 channel band configuration. 441dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt */ 442dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt if (center_segment0 == channel + 14 || 443dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 == channel + 10 || 444dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 == channel + 6 || 445dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 == channel + 2 || 446dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 == channel - 2 || 447dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 == channel - 6 || 448dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 == channel - 10 || 449dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt center_segment0 == channel - 14) 450dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt data->center_freq1 = 5000 + center_segment0 * 5; 451dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt else 4527f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return -1; 4537f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt break; 4547f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt } 4557f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt 4567f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt return 0; 4577f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt} 458092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart 459092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart 460092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewartvoid set_disable_ht40(struct ieee80211_ht_capabilities *htcaps, 461092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart int disabled) 462092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart{ 463092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart /* Masking these out disables HT40 */ 464092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET | 465092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart HT_CAP_INFO_SHORT_GI40MHZ); 466092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart 467092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart if (disabled) 468092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart htcaps->ht_capabilities_info &= ~msk; 469092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart else 470092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart htcaps->ht_capabilities_info |= msk; 471092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart} 472ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 473ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 474ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt#ifdef CONFIG_IEEE80211AC 475ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 476ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidtstatic int _ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, 477ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt const char *name) 478ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt{ 479ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt u32 req_cap = conf & cap; 480ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 481ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt /* 482ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt * Make sure we support all requested capabilities. 483ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt * NOTE: We assume that 'cap' represents a capability mask, 484ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt * not a discrete value. 485ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt */ 486ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if ((hw & req_cap) != req_cap) { 487ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt wpa_printf(MSG_ERROR, 488ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt "Driver does not support configured VHT capability [%s]", 489ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt name); 490ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return 0; 491ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt } 492ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return 1; 493ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt} 494ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 495ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 496ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidtstatic int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask, 497ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt unsigned int shift, 498ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt const char *name) 499ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt{ 500ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt u32 hw_max = hw & mask; 501ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt u32 conf_val = conf & mask; 502ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 503ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (conf_val > hw_max) { 504ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt wpa_printf(MSG_ERROR, 505ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)", 506ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt name, conf_val >> shift, hw_max >> shift); 507ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return 0; 508ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt } 509ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return 1; 510ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt} 511ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 512ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 513ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidtint ieee80211ac_cap_check(u32 hw, u32 conf) 514ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt{ 515ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt#define VHT_CAP_CHECK(cap) \ 516ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt do { \ 517ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (!_ieee80211ac_cap_check(hw, conf, cap, #cap)) \ 518ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return 0; \ 519ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt } while (0) 520ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 521ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt#define VHT_CAP_CHECK_MAX(cap) \ 522ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt do { \ 523ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \ 524ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt #cap)) \ 525ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return 0; \ 526ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt } while (0) 527ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 528ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK); 529ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ); 530ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); 531ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_RXLDPC); 532ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80); 533ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160); 534ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_TXSTBC); 535ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK); 536ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE); 537ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE); 538ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX); 539ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX); 540ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE); 541ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE); 542ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS); 543ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_HTC_VHT); 544ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX); 545ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB); 546ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB); 547ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN); 548ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN); 549ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 550ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt#undef VHT_CAP_CHECK 551ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt#undef VHT_CAP_CHECK_MAX 552ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 553ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return 1; 554ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt} 555ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 556ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt#endif /* CONFIG_IEEE80211AC */ 557