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