xref: /freebsd/contrib/wpa/src/ap/interference.c (revision 71e72c9e91c4b8007a4292e09669e8b549c29e97)
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