1*71e72c9eSCy Schubert /*
2*71e72c9eSCy Schubert * Management of interference due to incumbent signals in 6 GHz band
3*71e72c9eSCy Schubert * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4*71e72c9eSCy Schubert *
5*71e72c9eSCy Schubert * This software may be distributed under the terms of the BSD license.
6*71e72c9eSCy Schubert * See README for more details.
7*71e72c9eSCy Schubert */
8*71e72c9eSCy Schubert
9*71e72c9eSCy Schubert #include "utils/includes.h"
10*71e72c9eSCy Schubert #include "utils/common.h"
11*71e72c9eSCy Schubert #include "common/hw_features_common.h"
12*71e72c9eSCy Schubert #include "common/ieee802_11_common.h"
13*71e72c9eSCy Schubert #include "hostapd.h"
14*71e72c9eSCy Schubert #include "ap_drv_ops.h"
15*71e72c9eSCy Schubert #include "beacon.h"
16*71e72c9eSCy Schubert #include "interference.h"
17*71e72c9eSCy Schubert
18*71e72c9eSCy Schubert
19*71e72c9eSCy Schubert #define BASE_6GHZ_FREQ 5950
20*71e72c9eSCy Schubert /* Channel 2 (op class 136) has a center frequency of 5935 MHz. */
21*71e72c9eSCy Schubert #define BASE_6GHZ_CH2_FREQ 5935
22*71e72c9eSCy Schubert
23*71e72c9eSCy Schubert enum chan_seg {
24*71e72c9eSCy Schubert SEG_PRI20 = 0x1,
25*71e72c9eSCy Schubert SEG_SEC20 = 0x2,
26*71e72c9eSCy Schubert SEG_SEC40_LOW = 0x4,
27*71e72c9eSCy Schubert SEG_SEC40_UP = 0x8,
28*71e72c9eSCy Schubert SEG_SEC40 = 0xC,
29*71e72c9eSCy Schubert SEG_SEC80_LOW = 0x10,
30*71e72c9eSCy Schubert SEG_SEC80_LOW_UP = 0x20,
31*71e72c9eSCy Schubert SEG_SEC80_UP_LOW = 0x40,
32*71e72c9eSCy Schubert SEG_SEC80_UP = 0x80,
33*71e72c9eSCy Schubert SEG_SEC80 = 0xF0,
34*71e72c9eSCy Schubert SEG_SEC160_LOW = 0x0100,
35*71e72c9eSCy Schubert SEG_SEC160_LOW_UP = 0x0200,
36*71e72c9eSCy Schubert SEG_SEC160_LOW_UP_UP = 0x0400,
37*71e72c9eSCy Schubert SEG_SEC160_LOW_UP_UP_UP = 0x0800,
38*71e72c9eSCy Schubert SEG_SEC160_UP_LOW_LOW_LOW = 0x1000,
39*71e72c9eSCy Schubert SEG_SEC160_UP_LOW_LOW = 0x2000,
40*71e72c9eSCy Schubert SEG_SEC160_UP_LOW = 0x4000,
41*71e72c9eSCy Schubert SEG_SEC160_UP = 0x8000,
42*71e72c9eSCy Schubert SEG_SEC160 = 0xFF00,
43*71e72c9eSCy Schubert };
44*71e72c9eSCy Schubert
45*71e72c9eSCy Schubert
is_chan_disabled(struct hostapd_hw_modes * mode,int chan_num)46*71e72c9eSCy Schubert static bool is_chan_disabled(struct hostapd_hw_modes *mode, int chan_num)
47*71e72c9eSCy Schubert {
48*71e72c9eSCy Schubert struct hostapd_channel_data *chan;
49*71e72c9eSCy Schubert int i;
50*71e72c9eSCy Schubert
51*71e72c9eSCy Schubert for (i = 0; i < mode->num_channels; i++) {
52*71e72c9eSCy Schubert chan = &mode->channels[i];
53*71e72c9eSCy Schubert if (chan->chan == chan_num)
54*71e72c9eSCy Schubert return !!(chan->flag & HOSTAPD_CHAN_DISABLED);
55*71e72c9eSCy Schubert }
56*71e72c9eSCy Schubert
57*71e72c9eSCy Schubert return true;
58*71e72c9eSCy Schubert }
59*71e72c9eSCy Schubert
60*71e72c9eSCy Schubert
61*71e72c9eSCy Schubert /*
62*71e72c9eSCy Schubert * chan_range_available - Check whether the channel can operate in the given
63*71e72c9eSCy Schubert * bandwidth in 6 GHz
64*71e72c9eSCy Schubert * @first_chan_idx - Channel index of the first 20 MHz channel in a segment
65*71e72c9eSCy Schubert * @num_chans - Number of 20 MHz channels needed for the operating bandwidth
66*71e72c9eSCy Schubert * @allowed_arr - Range of channels allowed in the given bandwidth
67*71e72c9eSCy Schubert * @allowed_arr_size - Number of channels allowed in the given bandwidth
68*71e72c9eSCy Schubert * Returns: Whether the channel can operation in the given bandwidth
69*71e72c9eSCy Schubert */
chan_range_available(struct hostapd_hw_modes * mode,unsigned int first_chan_idx,unsigned int num_chans,const int * allowed_arr,unsigned int allowed_arr_size)70*71e72c9eSCy Schubert static bool chan_range_available(struct hostapd_hw_modes *mode,
71*71e72c9eSCy Schubert unsigned int first_chan_idx,
72*71e72c9eSCy Schubert unsigned int num_chans,
73*71e72c9eSCy Schubert const int *allowed_arr,
74*71e72c9eSCy Schubert unsigned int allowed_arr_size)
75*71e72c9eSCy Schubert {
76*71e72c9eSCy Schubert struct hostapd_channel_data *first_chan;
77*71e72c9eSCy Schubert unsigned int i;
78*71e72c9eSCy Schubert
79*71e72c9eSCy Schubert first_chan = &mode->channels[first_chan_idx];
80*71e72c9eSCy Schubert
81*71e72c9eSCy Schubert if (!chan_pri_allowed(first_chan)) {
82*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "Intf: Primary channel %d not allowed",
83*71e72c9eSCy Schubert first_chan->chan);
84*71e72c9eSCy Schubert return false;
85*71e72c9eSCy Schubert }
86*71e72c9eSCy Schubert
87*71e72c9eSCy Schubert /* 20 MHz channel, so no need to check the range */
88*71e72c9eSCy Schubert if (num_chans == 1)
89*71e72c9eSCy Schubert return true;
90*71e72c9eSCy Schubert
91*71e72c9eSCy Schubert if (allowed_arr) {
92*71e72c9eSCy Schubert for (i = 0; i < allowed_arr_size; i++) {
93*71e72c9eSCy Schubert if (first_chan->chan == allowed_arr[i])
94*71e72c9eSCy Schubert break;
95*71e72c9eSCy Schubert }
96*71e72c9eSCy Schubert if (i == allowed_arr_size)
97*71e72c9eSCy Schubert return false;
98*71e72c9eSCy Schubert }
99*71e72c9eSCy Schubert
100*71e72c9eSCy Schubert /*
101*71e72c9eSCy Schubert * Check whether all the 20 MHz channels in the given operating range
102*71e72c9eSCy Schubert * are enabled.
103*71e72c9eSCy Schubert */
104*71e72c9eSCy Schubert for (i = 1; i < num_chans; i++) {
105*71e72c9eSCy Schubert if (is_chan_disabled(mode, first_chan->chan + i * 4))
106*71e72c9eSCy Schubert return false;
107*71e72c9eSCy Schubert }
108*71e72c9eSCy Schubert
109*71e72c9eSCy Schubert return true;
110*71e72c9eSCy Schubert }
111*71e72c9eSCy Schubert
112*71e72c9eSCy Schubert
is_in_chanlist(struct hostapd_iface * iface,struct hostapd_channel_data * chan)113*71e72c9eSCy Schubert static bool is_in_chanlist(struct hostapd_iface *iface,
114*71e72c9eSCy Schubert struct hostapd_channel_data *chan)
115*71e72c9eSCy Schubert {
116*71e72c9eSCy Schubert if (!iface->conf->acs_ch_list.num)
117*71e72c9eSCy Schubert return true;
118*71e72c9eSCy Schubert
119*71e72c9eSCy Schubert return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
120*71e72c9eSCy Schubert }
121*71e72c9eSCy Schubert
122*71e72c9eSCy Schubert
get_center_freq_6g(int chan_idx,enum chan_width chan_width,int * center_freq)123*71e72c9eSCy Schubert static int get_center_freq_6g(int chan_idx, enum chan_width chan_width,
124*71e72c9eSCy Schubert int *center_freq)
125*71e72c9eSCy Schubert {
126*71e72c9eSCy Schubert if (!center_freq)
127*71e72c9eSCy Schubert return -1;
128*71e72c9eSCy Schubert
129*71e72c9eSCy Schubert *center_freq = 0;
130*71e72c9eSCy Schubert
131*71e72c9eSCy Schubert switch (chan_width) {
132*71e72c9eSCy Schubert case CHAN_WIDTH_20:
133*71e72c9eSCy Schubert if (chan_idx == 2) {
134*71e72c9eSCy Schubert *center_freq = BASE_6GHZ_CH2_FREQ;
135*71e72c9eSCy Schubert break;
136*71e72c9eSCy Schubert }
137*71e72c9eSCy Schubert if (chan_idx >= 1 && chan_idx <= 233)
138*71e72c9eSCy Schubert *center_freq = ((chan_idx / 4) * 4 + 1) * 5 +
139*71e72c9eSCy Schubert BASE_6GHZ_FREQ;
140*71e72c9eSCy Schubert break;
141*71e72c9eSCy Schubert case CHAN_WIDTH_40:
142*71e72c9eSCy Schubert if (chan_idx >= 1 && chan_idx <= 229)
143*71e72c9eSCy Schubert *center_freq = ((chan_idx / 8) * 8 + 3) * 5 +
144*71e72c9eSCy Schubert BASE_6GHZ_FREQ;
145*71e72c9eSCy Schubert break;
146*71e72c9eSCy Schubert case CHAN_WIDTH_80:
147*71e72c9eSCy Schubert if (chan_idx >= 1 && chan_idx <= 221)
148*71e72c9eSCy Schubert *center_freq = ((chan_idx / 16) * 16 + 7) * 5 +
149*71e72c9eSCy Schubert BASE_6GHZ_FREQ;
150*71e72c9eSCy Schubert break;
151*71e72c9eSCy Schubert case CHAN_WIDTH_160:
152*71e72c9eSCy Schubert if (chan_idx >= 1 && chan_idx <= 221)
153*71e72c9eSCy Schubert *center_freq = ((chan_idx / 32) * 32 + 15) * 5 +
154*71e72c9eSCy Schubert BASE_6GHZ_FREQ;
155*71e72c9eSCy Schubert break;
156*71e72c9eSCy Schubert case CHAN_WIDTH_320:
157*71e72c9eSCy Schubert if (chan_idx >= 1 && chan_idx <= 221)
158*71e72c9eSCy Schubert *center_freq = ((chan_idx / 32) * 32 + 31) * 5 +
159*71e72c9eSCy Schubert BASE_6GHZ_FREQ;
160*71e72c9eSCy Schubert break;
161*71e72c9eSCy Schubert default:
162*71e72c9eSCy Schubert break;
163*71e72c9eSCy Schubert }
164*71e72c9eSCy Schubert
165*71e72c9eSCy Schubert if (*center_freq == 0)
166*71e72c9eSCy Schubert return -1;
167*71e72c9eSCy Schubert
168*71e72c9eSCy Schubert return 0;
169*71e72c9eSCy Schubert }
170*71e72c9eSCy Schubert
171*71e72c9eSCy Schubert
is_interference_in_chanlist(int freq_start,int freq_end,const int * interference_freqs)172*71e72c9eSCy Schubert static bool is_interference_in_chanlist(int freq_start, int freq_end,
173*71e72c9eSCy Schubert const int *interference_freqs)
174*71e72c9eSCy Schubert {
175*71e72c9eSCy Schubert int i;
176*71e72c9eSCy Schubert
177*71e72c9eSCy Schubert for (i = freq_start; i <= freq_end; i += 20) {
178*71e72c9eSCy Schubert if (int_array_includes(interference_freqs, i))
179*71e72c9eSCy Schubert return true;
180*71e72c9eSCy Schubert }
181*71e72c9eSCy Schubert return false;
182*71e72c9eSCy Schubert }
183*71e72c9eSCy Schubert
184*71e72c9eSCy Schubert
185*71e72c9eSCy Schubert
get_allowed_channel_array(int num_chans,unsigned int * size)186*71e72c9eSCy Schubert static const int * get_allowed_channel_array(int num_chans, unsigned int *size)
187*71e72c9eSCy Schubert {
188*71e72c9eSCy Schubert static const int allowed_40_6g[] = { 1, 9, 17, 25, 33, 41, 49, 57, 65,
189*71e72c9eSCy Schubert 73, 81, 89, 97, 105, 113, 121, 129,
190*71e72c9eSCy Schubert 137, 145, 153, 161, 169, 177, 185,
191*71e72c9eSCy Schubert 193, 201, 209, 217, 225, 233 };
192*71e72c9eSCy Schubert static const int allowed_80_6g[] = { 1, 17, 33, 49, 65, 81, 97, 113,
193*71e72c9eSCy Schubert 129, 145, 161, 177,
194*71e72c9eSCy Schubert 193, 209 };
195*71e72c9eSCy Schubert static const int allowed_160_6g[] = { 1, 33, 65, 97, 129, 161, 193 };
196*71e72c9eSCy Schubert static const int allowed_320_6g[] = { 1, 65, 129, 33, 97, 161 };
197*71e72c9eSCy Schubert
198*71e72c9eSCy Schubert switch (num_chans) {
199*71e72c9eSCy Schubert case 2:
200*71e72c9eSCy Schubert *size = ARRAY_SIZE(allowed_40_6g);
201*71e72c9eSCy Schubert return allowed_40_6g;
202*71e72c9eSCy Schubert case 4:
203*71e72c9eSCy Schubert *size = ARRAY_SIZE(allowed_80_6g);
204*71e72c9eSCy Schubert return allowed_80_6g;
205*71e72c9eSCy Schubert case 8:
206*71e72c9eSCy Schubert *size = ARRAY_SIZE(allowed_160_6g);
207*71e72c9eSCy Schubert return allowed_160_6g;
208*71e72c9eSCy Schubert case 16:
209*71e72c9eSCy Schubert *size = ARRAY_SIZE(allowed_320_6g);
210*71e72c9eSCy Schubert return allowed_320_6g;
211*71e72c9eSCy Schubert default:
212*71e72c9eSCy Schubert *size = 0;
213*71e72c9eSCy Schubert return NULL;
214*71e72c9eSCy Schubert }
215*71e72c9eSCy Schubert }
216*71e72c9eSCy Schubert
217*71e72c9eSCy Schubert
218*71e72c9eSCy Schubert /**
219*71e72c9eSCy Schubert * intf_find_channel_list - Find the list of channels that can operate with
220*71e72c9eSCy Schubert * channel width chan_width and not present within the range of current
221*71e72c9eSCy Schubert * operating range.
222*71e72c9eSCy Schubert * @chan_width - Channel width to be checked
223*71e72c9eSCy Schubert * @chandef_list - Pointer array to hold the list of valid available chandef
224*71e72c9eSCy Schubert * Returns: The total number of available chandefs that support the provided
225*71e72c9eSCy Schubert * bandwidth
226*71e72c9eSCy Schubert */
intf_find_channel_list(struct hostapd_iface * iface,int chan_width,struct hostapd_channel_data ** chandef_list,const int * interference_freqs)227*71e72c9eSCy Schubert static int intf_find_channel_list(struct hostapd_iface *iface, int chan_width,
228*71e72c9eSCy Schubert struct hostapd_channel_data **chandef_list,
229*71e72c9eSCy Schubert const int *interference_freqs)
230*71e72c9eSCy Schubert {
231*71e72c9eSCy Schubert struct hostapd_hw_modes *mode = iface->current_mode;
232*71e72c9eSCy Schubert int new_center_freq, new_start_freq, new_end_freq;
233*71e72c9eSCy Schubert const int *allowed_arr = NULL;
234*71e72c9eSCy Schubert unsigned int allowed_arr_size = 0;
235*71e72c9eSCy Schubert struct hostapd_channel_data *chan;
236*71e72c9eSCy Schubert int i;
237*71e72c9eSCy Schubert unsigned int channel_idx = 0, n_chans;
238*71e72c9eSCy Schubert int ret;
239*71e72c9eSCy Schubert
240*71e72c9eSCy Schubert switch (chan_width) {
241*71e72c9eSCy Schubert case CHAN_WIDTH_20_NOHT:
242*71e72c9eSCy Schubert case CHAN_WIDTH_20:
243*71e72c9eSCy Schubert n_chans = 1;
244*71e72c9eSCy Schubert break;
245*71e72c9eSCy Schubert case CHAN_WIDTH_40:
246*71e72c9eSCy Schubert n_chans = 2;
247*71e72c9eSCy Schubert break;
248*71e72c9eSCy Schubert case CHAN_WIDTH_80:
249*71e72c9eSCy Schubert n_chans = 4;
250*71e72c9eSCy Schubert break;
251*71e72c9eSCy Schubert case CHAN_WIDTH_80P80:
252*71e72c9eSCy Schubert case CHAN_WIDTH_160:
253*71e72c9eSCy Schubert n_chans = 8;
254*71e72c9eSCy Schubert break;
255*71e72c9eSCy Schubert case CHAN_WIDTH_320:
256*71e72c9eSCy Schubert n_chans = 16;
257*71e72c9eSCy Schubert break;
258*71e72c9eSCy Schubert default:
259*71e72c9eSCy Schubert n_chans = 1;
260*71e72c9eSCy Schubert break;
261*71e72c9eSCy Schubert }
262*71e72c9eSCy Schubert
263*71e72c9eSCy Schubert allowed_arr = get_allowed_channel_array(n_chans, &allowed_arr_size);
264*71e72c9eSCy Schubert
265*71e72c9eSCy Schubert for (i = 0; i < mode->num_channels; i++) {
266*71e72c9eSCy Schubert chan = &mode->channels[i];
267*71e72c9eSCy Schubert
268*71e72c9eSCy Schubert if (!chan_in_current_hw_info(iface->current_hw_info, chan)) {
269*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
270*71e72c9eSCy Schubert "Intf: Channel %d (%d) is not under current hardware index",
271*71e72c9eSCy Schubert chan->freq, chan->chan);
272*71e72c9eSCy Schubert continue;
273*71e72c9eSCy Schubert }
274*71e72c9eSCy Schubert
275*71e72c9eSCy Schubert /* Skip incompatible chandefs */
276*71e72c9eSCy Schubert if (!chan_range_available(mode, i, n_chans,
277*71e72c9eSCy Schubert allowed_arr, allowed_arr_size)) {
278*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
279*71e72c9eSCy Schubert "Intf: Range not available for chan %d (%d)",
280*71e72c9eSCy Schubert chan->freq, chan->chan);
281*71e72c9eSCy Schubert continue;
282*71e72c9eSCy Schubert }
283*71e72c9eSCy Schubert
284*71e72c9eSCy Schubert if (!is_in_chanlist(iface, chan)) {
285*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
286*71e72c9eSCy Schubert "Intf: Channel %d (%d) not in chanlist",
287*71e72c9eSCy Schubert chan->freq, chan->chan);
288*71e72c9eSCy Schubert continue;
289*71e72c9eSCy Schubert }
290*71e72c9eSCy Schubert
291*71e72c9eSCy Schubert ret = get_center_freq_6g(chan->chan, chan_width,
292*71e72c9eSCy Schubert &new_center_freq);
293*71e72c9eSCy Schubert if (ret) {
294*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
295*71e72c9eSCy Schubert "Intf: Couldn't find center freq for chan %d chan_width %d",
296*71e72c9eSCy Schubert chan->chan, chan_width);
297*71e72c9eSCy Schubert return 0;
298*71e72c9eSCy Schubert }
299*71e72c9eSCy Schubert
300*71e72c9eSCy Schubert new_start_freq = (new_center_freq -
301*71e72c9eSCy Schubert channel_width_to_int(chan_width) / 2) + 10;
302*71e72c9eSCy Schubert new_end_freq = (new_center_freq +
303*71e72c9eSCy Schubert channel_width_to_int(chan_width) / 2) - 10;
304*71e72c9eSCy Schubert
305*71e72c9eSCy Schubert if (is_interference_in_chanlist(new_start_freq, new_end_freq,
306*71e72c9eSCy Schubert interference_freqs)) {
307*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
308*71e72c9eSCy Schubert "Intf: Found frequency which has interference in channel (%d)",
309*71e72c9eSCy Schubert chan->chan);
310*71e72c9eSCy Schubert continue;
311*71e72c9eSCy Schubert }
312*71e72c9eSCy Schubert
313*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
314*71e72c9eSCy Schubert "Intf: Adding channel %d (%d) to valid chandef list",
315*71e72c9eSCy Schubert chan->freq, chan->chan);
316*71e72c9eSCy Schubert chandef_list[channel_idx] = chan;
317*71e72c9eSCy Schubert channel_idx++;
318*71e72c9eSCy Schubert }
319*71e72c9eSCy Schubert
320*71e72c9eSCy Schubert return channel_idx;
321*71e72c9eSCy Schubert }
322*71e72c9eSCy Schubert
323*71e72c9eSCy Schubert
downgrade_bandwidth(enum chan_width chan_width)324*71e72c9eSCy Schubert static enum chan_width downgrade_bandwidth(enum chan_width chan_width)
325*71e72c9eSCy Schubert {
326*71e72c9eSCy Schubert switch (chan_width) {
327*71e72c9eSCy Schubert case CHAN_WIDTH_320:
328*71e72c9eSCy Schubert return CHAN_WIDTH_160;
329*71e72c9eSCy Schubert case CHAN_WIDTH_160:
330*71e72c9eSCy Schubert return CHAN_WIDTH_80;
331*71e72c9eSCy Schubert case CHAN_WIDTH_80:
332*71e72c9eSCy Schubert return CHAN_WIDTH_40;
333*71e72c9eSCy Schubert case CHAN_WIDTH_40:
334*71e72c9eSCy Schubert return CHAN_WIDTH_20;
335*71e72c9eSCy Schubert default:
336*71e72c9eSCy Schubert return CHAN_WIDTH_20_NOHT;
337*71e72c9eSCy Schubert }
338*71e72c9eSCy Schubert }
339*71e72c9eSCy Schubert
340*71e72c9eSCy Schubert
341*71e72c9eSCy Schubert /*
342*71e72c9eSCy Schubert * hostapd_incumbt_sig_intf_detected - Incumbent signal interference is detected
343*71e72c9eSCy Schubert * in the operating channel. The interference channel information is available
344*71e72c9eSCy Schubert * as a bitmap(chan_bw_interference_bitmap). If interference has occurred in
345*71e72c9eSCy Schubert * the primary channel, do a complete channel switch to a different channel;
346*71e72c9eSCy Schubert * otherwise, reduce the operating bandwidth and continue AP operation using
347*71e72c9eSCy Schubert * the same primary channel.
348*71e72c9eSCy Schubert */
hostapd_incumbt_sig_intf_detected(struct hostapd_iface * iface,int freq,int chan_width,int cf1,int cf2,u32 chan_bw_interference_bitmap)349*71e72c9eSCy Schubert int hostapd_incumbt_sig_intf_detected(struct hostapd_iface *iface, int freq,
350*71e72c9eSCy Schubert int chan_width, int cf1, int cf2,
351*71e72c9eSCy Schubert u32 chan_bw_interference_bitmap)
352*71e72c9eSCy Schubert {
353*71e72c9eSCy Schubert struct csa_settings settings;
354*71e72c9eSCy Schubert struct hostapd_channel_data *chan_data = NULL;
355*71e72c9eSCy Schubert struct hostapd_channel_data *chan_temp;
356*71e72c9eSCy Schubert struct hostapd_channel_data **available_chandef_list = NULL;
357*71e72c9eSCy Schubert int ret = 0;
358*71e72c9eSCy Schubert unsigned int i;
359*71e72c9eSCy Schubert u32 _rand;
360*71e72c9eSCy Schubert u32 chan_idx;
361*71e72c9eSCy Schubert int num_available_chandefs = 0;
362*71e72c9eSCy Schubert enum chan_width new_chan_width;
363*71e72c9eSCy Schubert int new_center_freq;
364*71e72c9eSCy Schubert int current_start_freq;
365*71e72c9eSCy Schubert int temp_width;
366*71e72c9eSCy Schubert struct hostapd_hw_modes *mode = iface->current_mode;
367*71e72c9eSCy Schubert int *interference_freqs = NULL;
368*71e72c9eSCy Schubert int primary_chan_bit = -1;
369*71e72c9eSCy Schubert int segment_freq;
370*71e72c9eSCy Schubert int start_freq = (cf1 - channel_width_to_int(chan_width) / 2) + 10;
371*71e72c9eSCy Schubert u8 channel_no;
372*71e72c9eSCy Schubert unsigned int num_segments;
373*71e72c9eSCy Schubert int new_bw;
374*71e72c9eSCy Schubert
375*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
376*71e72c9eSCy Schubert "Intf: input freq=%d, chan_width=%d, cf1=%d, cf2=%d, chan_bw_interference_bitmap=0x%x",
377*71e72c9eSCy Schubert freq, chan_width, cf1, cf2, chan_bw_interference_bitmap);
378*71e72c9eSCy Schubert
379*71e72c9eSCy Schubert num_segments = channel_width_to_int(chan_width) / 20;
380*71e72c9eSCy Schubert if (!num_segments) {
381*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "Intf: Invalid channel width %d",
382*71e72c9eSCy Schubert chan_width);
383*71e72c9eSCy Schubert return -1;
384*71e72c9eSCy Schubert }
385*71e72c9eSCy Schubert
386*71e72c9eSCy Schubert /* Determine which 20 MHz segment contains the primary channel */
387*71e72c9eSCy Schubert for (i = 0; i < num_segments; i++) {
388*71e72c9eSCy Schubert segment_freq = start_freq + i * 20;
389*71e72c9eSCy Schubert if (segment_freq == freq) {
390*71e72c9eSCy Schubert primary_chan_bit = i;
391*71e72c9eSCy Schubert break;
392*71e72c9eSCy Schubert }
393*71e72c9eSCy Schubert }
394*71e72c9eSCy Schubert
395*71e72c9eSCy Schubert /* Check whether interference has occurred in primary 20 MHz channel */
396*71e72c9eSCy Schubert if (primary_chan_bit >= 0 &&
397*71e72c9eSCy Schubert (chan_bw_interference_bitmap & BIT(primary_chan_bit))) {
398*71e72c9eSCy Schubert available_chandef_list = os_calloc(
399*71e72c9eSCy Schubert mode->num_channels,
400*71e72c9eSCy Schubert sizeof(struct hostapd_channel_data *));
401*71e72c9eSCy Schubert if (!available_chandef_list) {
402*71e72c9eSCy Schubert wpa_printf(MSG_ERROR,
403*71e72c9eSCy Schubert "Intf: Failed to allocate available_chandef_list");
404*71e72c9eSCy Schubert return -1;
405*71e72c9eSCy Schubert }
406*71e72c9eSCy Schubert
407*71e72c9eSCy Schubert /* Store frequencies with interference in interference_freqs */
408*71e72c9eSCy Schubert current_start_freq =
409*71e72c9eSCy Schubert (cf1 - channel_width_to_int(chan_width) / 2) + 10;
410*71e72c9eSCy Schubert for (i = 0; i < num_segments; i++) {
411*71e72c9eSCy Schubert if (chan_bw_interference_bitmap & BIT(i)) {
412*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
413*71e72c9eSCy Schubert "Intf: Found incumbent signal interference in frequency %d",
414*71e72c9eSCy Schubert current_start_freq + 20 * i);
415*71e72c9eSCy Schubert int_array_add_unique(&interference_freqs,
416*71e72c9eSCy Schubert current_start_freq +
417*71e72c9eSCy Schubert 20 * i);
418*71e72c9eSCy Schubert if (!interference_freqs) {
419*71e72c9eSCy Schubert wpa_printf(MSG_ERROR,
420*71e72c9eSCy Schubert "Intf: Failed to store interference frequencies");
421*71e72c9eSCy Schubert ret = -1;
422*71e72c9eSCy Schubert goto exit;
423*71e72c9eSCy Schubert }
424*71e72c9eSCy Schubert }
425*71e72c9eSCy Schubert }
426*71e72c9eSCy Schubert
427*71e72c9eSCy Schubert /* Find a random channel to be switched */
428*71e72c9eSCy Schubert temp_width = chan_width;
429*71e72c9eSCy Schubert
430*71e72c9eSCy Schubert while (temp_width > CHAN_WIDTH_20_NOHT) {
431*71e72c9eSCy Schubert num_available_chandefs =
432*71e72c9eSCy Schubert intf_find_channel_list(iface, temp_width,
433*71e72c9eSCy Schubert available_chandef_list,
434*71e72c9eSCy Schubert interference_freqs);
435*71e72c9eSCy Schubert if (num_available_chandefs > 0)
436*71e72c9eSCy Schubert break;
437*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "Intf: Downgrading bandwidth");
438*71e72c9eSCy Schubert temp_width = downgrade_bandwidth(temp_width);
439*71e72c9eSCy Schubert }
440*71e72c9eSCy Schubert
441*71e72c9eSCy Schubert if (num_available_chandefs == 0) {
442*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "Intf: No available_chandefs");
443*71e72c9eSCy Schubert goto exit;
444*71e72c9eSCy Schubert }
445*71e72c9eSCy Schubert
446*71e72c9eSCy Schubert if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
447*71e72c9eSCy Schubert _rand = os_random();
448*71e72c9eSCy Schubert
449*71e72c9eSCy Schubert chan_idx = _rand % num_available_chandefs;
450*71e72c9eSCy Schubert chan_data = available_chandef_list[chan_idx];
451*71e72c9eSCy Schubert new_chan_width = temp_width;
452*71e72c9eSCy Schubert
453*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG, "Intf: Got random channel %d (%d)",
454*71e72c9eSCy Schubert chan_data->freq, chan_data->chan);
455*71e72c9eSCy Schubert } else {
456*71e72c9eSCy Schubert /*
457*71e72c9eSCy Schubert * Interference is not present in the primary 20 MHz, so
458*71e72c9eSCy Schubert * reduce bandwidth.
459*71e72c9eSCy Schubert */
460*71e72c9eSCy Schubert u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
461*71e72c9eSCy Schubert u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
462*71e72c9eSCy Schubert enum oper_chan_width oper_chwidth;
463*71e72c9eSCy Schubert int j;
464*71e72c9eSCy Schubert
465*71e72c9eSCy Schubert for (j = 0; j < mode->num_channels; j++) {
466*71e72c9eSCy Schubert chan_temp = &mode->channels[j];
467*71e72c9eSCy Schubert if (chan_temp->freq == freq)
468*71e72c9eSCy Schubert chan_data = chan_temp;
469*71e72c9eSCy Schubert }
470*71e72c9eSCy Schubert if (!chan_data) {
471*71e72c9eSCy Schubert wpa_printf(MSG_INFO, "Intf: No channel found");
472*71e72c9eSCy Schubert goto exit;
473*71e72c9eSCy Schubert }
474*71e72c9eSCy Schubert
475*71e72c9eSCy Schubert oper_chwidth = chan_width_to_oper_chwidth(chan_width);
476*71e72c9eSCy Schubert
477*71e72c9eSCy Schubert if (chan_width > CHAN_WIDTH_40) {
478*71e72c9eSCy Schubert punct_update_legacy_bw(chan_bw_interference_bitmap,
479*71e72c9eSCy Schubert iface->conf->channel,
480*71e72c9eSCy Schubert &oper_chwidth, &seg0, &seg1);
481*71e72c9eSCy Schubert if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ)
482*71e72c9eSCy Schubert new_chan_width = CHAN_WIDTH_160;
483*71e72c9eSCy Schubert else if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
484*71e72c9eSCy Schubert new_chan_width = CHAN_WIDTH_80;
485*71e72c9eSCy Schubert else if (seg0 == 0)
486*71e72c9eSCy Schubert new_chan_width = CHAN_WIDTH_20;
487*71e72c9eSCy Schubert else
488*71e72c9eSCy Schubert new_chan_width = CHAN_WIDTH_40;
489*71e72c9eSCy Schubert } else {
490*71e72c9eSCy Schubert new_chan_width = CHAN_WIDTH_20;
491*71e72c9eSCy Schubert }
492*71e72c9eSCy Schubert }
493*71e72c9eSCy Schubert
494*71e72c9eSCy Schubert if (new_chan_width > CHAN_WIDTH_20) {
495*71e72c9eSCy Schubert ret = get_center_freq_6g(chan_data->chan, new_chan_width,
496*71e72c9eSCy Schubert &new_center_freq);
497*71e72c9eSCy Schubert if (ret) {
498*71e72c9eSCy Schubert wpa_printf(MSG_ERROR,
499*71e72c9eSCy Schubert "Intf: Couldn't find center freq for chan : %d chan_width : %d",
500*71e72c9eSCy Schubert chan_data->chan, new_chan_width);
501*71e72c9eSCy Schubert goto exit;
502*71e72c9eSCy Schubert }
503*71e72c9eSCy Schubert } else {
504*71e72c9eSCy Schubert new_center_freq = chan_data->freq;
505*71e72c9eSCy Schubert }
506*71e72c9eSCy Schubert
507*71e72c9eSCy Schubert ieee80211_freq_to_chan(chan_data->freq, &channel_no);
508*71e72c9eSCy Schubert
509*71e72c9eSCy Schubert os_memset(&settings, 0, sizeof(settings));
510*71e72c9eSCy Schubert settings.cs_count = 5;
511*71e72c9eSCy Schubert settings.freq_params.freq = chan_data->freq;
512*71e72c9eSCy Schubert
513*71e72c9eSCy Schubert switch (new_chan_width) {
514*71e72c9eSCy Schubert case CHAN_WIDTH_40:
515*71e72c9eSCy Schubert new_bw = 40;
516*71e72c9eSCy Schubert break;
517*71e72c9eSCy Schubert case CHAN_WIDTH_80P80:
518*71e72c9eSCy Schubert case CHAN_WIDTH_80:
519*71e72c9eSCy Schubert new_bw = 80;
520*71e72c9eSCy Schubert break;
521*71e72c9eSCy Schubert case CHAN_WIDTH_160:
522*71e72c9eSCy Schubert new_bw = 160;
523*71e72c9eSCy Schubert break;
524*71e72c9eSCy Schubert case CHAN_WIDTH_320:
525*71e72c9eSCy Schubert new_bw = 320;
526*71e72c9eSCy Schubert break;
527*71e72c9eSCy Schubert default:
528*71e72c9eSCy Schubert new_bw = 20;
529*71e72c9eSCy Schubert break;
530*71e72c9eSCy Schubert }
531*71e72c9eSCy Schubert
532*71e72c9eSCy Schubert settings.freq_params.bandwidth = new_bw;
533*71e72c9eSCy Schubert settings.freq_params.channel = channel_no;
534*71e72c9eSCy Schubert settings.freq_params.center_freq1 = new_center_freq;
535*71e72c9eSCy Schubert settings.freq_params.ht_enabled = iface->conf->ieee80211n;
536*71e72c9eSCy Schubert settings.freq_params.vht_enabled = iface->conf->ieee80211ac;
537*71e72c9eSCy Schubert settings.freq_params.he_enabled = iface->conf->ieee80211ax;
538*71e72c9eSCy Schubert settings.freq_params.eht_enabled = iface->conf->ieee80211be;
539*71e72c9eSCy Schubert wpa_printf(MSG_DEBUG,
540*71e72c9eSCy Schubert "Intf: channel=%u, freq=%d, bw=%d, center_freq1=%d",
541*71e72c9eSCy Schubert settings.freq_params.channel,
542*71e72c9eSCy Schubert settings.freq_params.freq,
543*71e72c9eSCy Schubert settings.freq_params.bandwidth,
544*71e72c9eSCy Schubert settings.freq_params.center_freq1);
545*71e72c9eSCy Schubert
546*71e72c9eSCy Schubert if (chan_data->freq == iface->freq) {
547*71e72c9eSCy Schubert if (hostapd_change_config_freq(iface->bss[0], iface->conf,
548*71e72c9eSCy Schubert &settings.freq_params, NULL)) {
549*71e72c9eSCy Schubert wpa_printf(MSG_INFO,
550*71e72c9eSCy Schubert "Intf: Failed to update bandwidth");
551*71e72c9eSCy Schubert ret = -1;
552*71e72c9eSCy Schubert goto exit;
553*71e72c9eSCy Schubert }
554*71e72c9eSCy Schubert if (hostapd_set_freq(
555*71e72c9eSCy Schubert iface->bss[0], iface->conf->hw_mode, iface->freq,
556*71e72c9eSCy Schubert iface->conf->channel, iface->conf->enable_edmg,
557*71e72c9eSCy Schubert iface->conf->edmg_channel, iface->conf->ieee80211n,
558*71e72c9eSCy Schubert iface->conf->ieee80211ac,
559*71e72c9eSCy Schubert iface->conf->ieee80211ax,
560*71e72c9eSCy Schubert iface->conf->ieee80211be,
561*71e72c9eSCy Schubert iface->conf->secondary_channel,
562*71e72c9eSCy Schubert hostapd_get_oper_chwidth(iface->conf),
563*71e72c9eSCy Schubert hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
564*71e72c9eSCy Schubert hostapd_get_oper_centr_freq_seg1_idx(iface->conf))) {
565*71e72c9eSCy Schubert wpa_printf(MSG_ERROR,
566*71e72c9eSCy Schubert "Intf: Failed to apply bandwidth update");
567*71e72c9eSCy Schubert ret = -1;
568*71e72c9eSCy Schubert goto exit;
569*71e72c9eSCy Schubert }
570*71e72c9eSCy Schubert ieee802_11_set_beacons(iface);
571*71e72c9eSCy Schubert goto exit;
572*71e72c9eSCy Schubert }
573*71e72c9eSCy Schubert
574*71e72c9eSCy Schubert /* Channel and bandwidth have been decided, triggering channel switch */
575*71e72c9eSCy Schubert for (i = 0; i < iface->num_bss; i++) {
576*71e72c9eSCy Schubert /* Save CHAN_SWITCH VHT and HE config */
577*71e72c9eSCy Schubert hostapd_chan_switch_config(iface->bss[i],
578*71e72c9eSCy Schubert &settings.freq_params);
579*71e72c9eSCy Schubert
580*71e72c9eSCy Schubert ret = hostapd_switch_channel(iface->bss[i], &settings);
581*71e72c9eSCy Schubert if (ret) {
582*71e72c9eSCy Schubert wpa_printf(MSG_ERROR,
583*71e72c9eSCy Schubert "Intf: Channel switch failed");
584*71e72c9eSCy Schubert break;
585*71e72c9eSCy Schubert }
586*71e72c9eSCy Schubert }
587*71e72c9eSCy Schubert
588*71e72c9eSCy Schubert exit:
589*71e72c9eSCy Schubert os_free(available_chandef_list);
590*71e72c9eSCy Schubert os_free(interference_freqs);
591*71e72c9eSCy Schubert return ret;
592*71e72c9eSCy Schubert }
593