xref: /openbmc/linux/net/wireless/chan.c (revision ca79522c)
1 /*
2  * This file contains helper code to handle channel
3  * settings and keeping track of what is possible at
4  * any point in time.
5  *
6  * Copyright 2009	Johannes Berg <johannes@sipsolutions.net>
7  */
8 
9 #include <linux/export.h>
10 #include <net/cfg80211.h>
11 #include "core.h"
12 #include "rdev-ops.h"
13 
14 void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
15 			     struct ieee80211_channel *chan,
16 			     enum nl80211_channel_type chan_type)
17 {
18 	if (WARN_ON(!chan))
19 		return;
20 
21 	chandef->chan = chan;
22 	chandef->center_freq2 = 0;
23 
24 	switch (chan_type) {
25 	case NL80211_CHAN_NO_HT:
26 		chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
27 		chandef->center_freq1 = chan->center_freq;
28 		break;
29 	case NL80211_CHAN_HT20:
30 		chandef->width = NL80211_CHAN_WIDTH_20;
31 		chandef->center_freq1 = chan->center_freq;
32 		break;
33 	case NL80211_CHAN_HT40PLUS:
34 		chandef->width = NL80211_CHAN_WIDTH_40;
35 		chandef->center_freq1 = chan->center_freq + 10;
36 		break;
37 	case NL80211_CHAN_HT40MINUS:
38 		chandef->width = NL80211_CHAN_WIDTH_40;
39 		chandef->center_freq1 = chan->center_freq - 10;
40 		break;
41 	default:
42 		WARN_ON(1);
43 	}
44 }
45 EXPORT_SYMBOL(cfg80211_chandef_create);
46 
47 bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
48 {
49 	u32 control_freq;
50 
51 	if (!chandef->chan)
52 		return false;
53 
54 	control_freq = chandef->chan->center_freq;
55 
56 	switch (chandef->width) {
57 	case NL80211_CHAN_WIDTH_20:
58 	case NL80211_CHAN_WIDTH_20_NOHT:
59 		if (chandef->center_freq1 != control_freq)
60 			return false;
61 		if (chandef->center_freq2)
62 			return false;
63 		break;
64 	case NL80211_CHAN_WIDTH_40:
65 		if (chandef->center_freq1 != control_freq + 10 &&
66 		    chandef->center_freq1 != control_freq - 10)
67 			return false;
68 		if (chandef->center_freq2)
69 			return false;
70 		break;
71 	case NL80211_CHAN_WIDTH_80P80:
72 		if (chandef->center_freq1 != control_freq + 30 &&
73 		    chandef->center_freq1 != control_freq + 10 &&
74 		    chandef->center_freq1 != control_freq - 10 &&
75 		    chandef->center_freq1 != control_freq - 30)
76 			return false;
77 		if (!chandef->center_freq2)
78 			return false;
79 		/* adjacent is not allowed -- that's a 160 MHz channel */
80 		if (chandef->center_freq1 - chandef->center_freq2 == 80 ||
81 		    chandef->center_freq2 - chandef->center_freq1 == 80)
82 			return false;
83 		break;
84 	case NL80211_CHAN_WIDTH_80:
85 		if (chandef->center_freq1 != control_freq + 30 &&
86 		    chandef->center_freq1 != control_freq + 10 &&
87 		    chandef->center_freq1 != control_freq - 10 &&
88 		    chandef->center_freq1 != control_freq - 30)
89 			return false;
90 		if (chandef->center_freq2)
91 			return false;
92 		break;
93 	case NL80211_CHAN_WIDTH_160:
94 		if (chandef->center_freq1 != control_freq + 70 &&
95 		    chandef->center_freq1 != control_freq + 50 &&
96 		    chandef->center_freq1 != control_freq + 30 &&
97 		    chandef->center_freq1 != control_freq + 10 &&
98 		    chandef->center_freq1 != control_freq - 10 &&
99 		    chandef->center_freq1 != control_freq - 30 &&
100 		    chandef->center_freq1 != control_freq - 50 &&
101 		    chandef->center_freq1 != control_freq - 70)
102 			return false;
103 		if (chandef->center_freq2)
104 			return false;
105 		break;
106 	default:
107 		return false;
108 	}
109 
110 	return true;
111 }
112 EXPORT_SYMBOL(cfg80211_chandef_valid);
113 
114 static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
115 				  int *pri40, int *pri80)
116 {
117 	int tmp;
118 
119 	switch (c->width) {
120 	case NL80211_CHAN_WIDTH_40:
121 		*pri40 = c->center_freq1;
122 		*pri80 = 0;
123 		break;
124 	case NL80211_CHAN_WIDTH_80:
125 	case NL80211_CHAN_WIDTH_80P80:
126 		*pri80 = c->center_freq1;
127 		/* n_P20 */
128 		tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
129 		/* n_P40 */
130 		tmp /= 2;
131 		/* freq_P40 */
132 		*pri40 = c->center_freq1 - 20 + 40 * tmp;
133 		break;
134 	case NL80211_CHAN_WIDTH_160:
135 		/* n_P20 */
136 		tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
137 		/* n_P40 */
138 		tmp /= 2;
139 		/* freq_P40 */
140 		*pri40 = c->center_freq1 - 60 + 40 * tmp;
141 		/* n_P80 */
142 		tmp /= 2;
143 		*pri80 = c->center_freq1 - 40 + 80 * tmp;
144 		break;
145 	default:
146 		WARN_ON_ONCE(1);
147 	}
148 }
149 
150 static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
151 {
152 	int width;
153 
154 	switch (c->width) {
155 	case NL80211_CHAN_WIDTH_20:
156 	case NL80211_CHAN_WIDTH_20_NOHT:
157 		width = 20;
158 		break;
159 	case NL80211_CHAN_WIDTH_40:
160 		width = 40;
161 		break;
162 	case NL80211_CHAN_WIDTH_80P80:
163 	case NL80211_CHAN_WIDTH_80:
164 		width = 80;
165 		break;
166 	case NL80211_CHAN_WIDTH_160:
167 		width = 160;
168 		break;
169 	default:
170 		WARN_ON_ONCE(1);
171 		return -1;
172 	}
173 	return width;
174 }
175 
176 const struct cfg80211_chan_def *
177 cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
178 			    const struct cfg80211_chan_def *c2)
179 {
180 	u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
181 
182 	/* If they are identical, return */
183 	if (cfg80211_chandef_identical(c1, c2))
184 		return c1;
185 
186 	/* otherwise, must have same control channel */
187 	if (c1->chan != c2->chan)
188 		return NULL;
189 
190 	/*
191 	 * If they have the same width, but aren't identical,
192 	 * then they can't be compatible.
193 	 */
194 	if (c1->width == c2->width)
195 		return NULL;
196 
197 	if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
198 	    c1->width == NL80211_CHAN_WIDTH_20)
199 		return c2;
200 
201 	if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
202 	    c2->width == NL80211_CHAN_WIDTH_20)
203 		return c1;
204 
205 	chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
206 	chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
207 
208 	if (c1_pri40 != c2_pri40)
209 		return NULL;
210 
211 	WARN_ON(!c1_pri80 && !c2_pri80);
212 	if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
213 		return NULL;
214 
215 	if (c1->width > c2->width)
216 		return c1;
217 	return c2;
218 }
219 EXPORT_SYMBOL(cfg80211_chandef_compatible);
220 
221 static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
222 					 u32 bandwidth,
223 					 enum nl80211_dfs_state dfs_state)
224 {
225 	struct ieee80211_channel *c;
226 	u32 freq;
227 
228 	for (freq = center_freq - bandwidth/2 + 10;
229 	     freq <= center_freq + bandwidth/2 - 10;
230 	     freq += 20) {
231 		c = ieee80211_get_channel(wiphy, freq);
232 		if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
233 			continue;
234 
235 		c->dfs_state = dfs_state;
236 		c->dfs_state_entered = jiffies;
237 	}
238 }
239 
240 void cfg80211_set_dfs_state(struct wiphy *wiphy,
241 			    const struct cfg80211_chan_def *chandef,
242 			    enum nl80211_dfs_state dfs_state)
243 {
244 	int width;
245 
246 	if (WARN_ON(!cfg80211_chandef_valid(chandef)))
247 		return;
248 
249 	width = cfg80211_chandef_get_width(chandef);
250 	if (width < 0)
251 		return;
252 
253 	cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
254 				     width, dfs_state);
255 
256 	if (!chandef->center_freq2)
257 		return;
258 	cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
259 				     width, dfs_state);
260 }
261 
262 static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
263 					    u32 center_freq,
264 					    u32 bandwidth)
265 {
266 	struct ieee80211_channel *c;
267 	u32 freq;
268 
269 	for (freq = center_freq - bandwidth/2 + 10;
270 	     freq <= center_freq + bandwidth/2 - 10;
271 	     freq += 20) {
272 		c = ieee80211_get_channel(wiphy, freq);
273 		if (!c)
274 			return -EINVAL;
275 
276 		if (c->flags & IEEE80211_CHAN_RADAR)
277 			return 1;
278 	}
279 	return 0;
280 }
281 
282 
283 int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
284 				  const struct cfg80211_chan_def *chandef)
285 {
286 	int width;
287 	int r;
288 
289 	if (WARN_ON(!cfg80211_chandef_valid(chandef)))
290 		return -EINVAL;
291 
292 	width = cfg80211_chandef_get_width(chandef);
293 	if (width < 0)
294 		return -EINVAL;
295 
296 	r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1,
297 					    width);
298 	if (r)
299 		return r;
300 
301 	if (!chandef->center_freq2)
302 		return 0;
303 
304 	return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
305 					       width);
306 }
307 
308 static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
309 					u32 center_freq, u32 bandwidth,
310 					u32 prohibited_flags)
311 {
312 	struct ieee80211_channel *c;
313 	u32 freq;
314 
315 	for (freq = center_freq - bandwidth/2 + 10;
316 	     freq <= center_freq + bandwidth/2 - 10;
317 	     freq += 20) {
318 		c = ieee80211_get_channel(wiphy, freq);
319 		if (!c)
320 			return false;
321 
322 		/* check for radar flags */
323 		if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) &&
324 		    (c->dfs_state != NL80211_DFS_AVAILABLE))
325 			return false;
326 
327 		/* check for the other flags */
328 		if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR)
329 			return false;
330 	}
331 
332 	return true;
333 }
334 
335 bool cfg80211_chandef_usable(struct wiphy *wiphy,
336 			     const struct cfg80211_chan_def *chandef,
337 			     u32 prohibited_flags)
338 {
339 	struct ieee80211_sta_ht_cap *ht_cap;
340 	struct ieee80211_sta_vht_cap *vht_cap;
341 	u32 width, control_freq;
342 
343 	if (WARN_ON(!cfg80211_chandef_valid(chandef)))
344 		return false;
345 
346 	ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
347 	vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
348 
349 	control_freq = chandef->chan->center_freq;
350 
351 	switch (chandef->width) {
352 	case NL80211_CHAN_WIDTH_20:
353 		if (!ht_cap->ht_supported)
354 			return false;
355 	case NL80211_CHAN_WIDTH_20_NOHT:
356 		width = 20;
357 		break;
358 	case NL80211_CHAN_WIDTH_40:
359 		width = 40;
360 		if (!ht_cap->ht_supported)
361 			return false;
362 		if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
363 		    ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
364 			return false;
365 		if (chandef->center_freq1 < control_freq &&
366 		    chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
367 			return false;
368 		if (chandef->center_freq1 > control_freq &&
369 		    chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
370 			return false;
371 		break;
372 	case NL80211_CHAN_WIDTH_80P80:
373 		if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
374 			return false;
375 	case NL80211_CHAN_WIDTH_80:
376 		if (!vht_cap->vht_supported)
377 			return false;
378 		prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
379 		width = 80;
380 		break;
381 	case NL80211_CHAN_WIDTH_160:
382 		if (!vht_cap->vht_supported)
383 			return false;
384 		if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ))
385 			return false;
386 		prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
387 		width = 160;
388 		break;
389 	default:
390 		WARN_ON_ONCE(1);
391 		return false;
392 	}
393 
394 	/*
395 	 * TODO: What if there are only certain 80/160/80+80 MHz channels
396 	 *	 allowed by the driver, or only certain combinations?
397 	 *	 For 40 MHz the driver can set the NO_HT40 flags, but for
398 	 *	 80/160 MHz and in particular 80+80 MHz this isn't really
399 	 *	 feasible and we only have NO_80MHZ/NO_160MHZ so far but
400 	 *	 no way to cover 80+80 MHz or more complex restrictions.
401 	 *	 Note that such restrictions also need to be advertised to
402 	 *	 userspace, for example for P2P channel selection.
403 	 */
404 
405 	if (width > 20)
406 		prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
407 
408 	if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
409 					 width, prohibited_flags))
410 		return false;
411 
412 	if (!chandef->center_freq2)
413 		return true;
414 	return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
415 					   width, prohibited_flags);
416 }
417 EXPORT_SYMBOL(cfg80211_chandef_usable);
418 
419 bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
420 			     struct cfg80211_chan_def *chandef)
421 {
422 	bool res;
423 
424 	trace_cfg80211_reg_can_beacon(wiphy, chandef);
425 
426 	res = cfg80211_chandef_usable(wiphy, chandef,
427 				      IEEE80211_CHAN_DISABLED |
428 				      IEEE80211_CHAN_PASSIVE_SCAN |
429 				      IEEE80211_CHAN_NO_IBSS |
430 				      IEEE80211_CHAN_RADAR);
431 
432 	trace_cfg80211_return_bool(res);
433 	return res;
434 }
435 EXPORT_SYMBOL(cfg80211_reg_can_beacon);
436 
437 int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
438 				 struct cfg80211_chan_def *chandef)
439 {
440 	if (!rdev->ops->set_monitor_channel)
441 		return -EOPNOTSUPP;
442 	if (!cfg80211_has_monitors_only(rdev))
443 		return -EBUSY;
444 
445 	return rdev_set_monitor_channel(rdev, chandef);
446 }
447 
448 void
449 cfg80211_get_chan_state(struct wireless_dev *wdev,
450 		        struct ieee80211_channel **chan,
451 		        enum cfg80211_chan_mode *chanmode)
452 {
453 	*chan = NULL;
454 	*chanmode = CHAN_MODE_UNDEFINED;
455 
456 	ASSERT_WDEV_LOCK(wdev);
457 
458 	if (wdev->netdev && !netif_running(wdev->netdev))
459 		return;
460 
461 	switch (wdev->iftype) {
462 	case NL80211_IFTYPE_ADHOC:
463 		if (wdev->current_bss) {
464 			*chan = wdev->current_bss->pub.channel;
465 			*chanmode = wdev->ibss_fixed
466 				  ? CHAN_MODE_SHARED
467 				  : CHAN_MODE_EXCLUSIVE;
468 			return;
469 		}
470 	case NL80211_IFTYPE_STATION:
471 	case NL80211_IFTYPE_P2P_CLIENT:
472 		if (wdev->current_bss) {
473 			*chan = wdev->current_bss->pub.channel;
474 			*chanmode = CHAN_MODE_SHARED;
475 			return;
476 		}
477 		break;
478 	case NL80211_IFTYPE_AP:
479 	case NL80211_IFTYPE_P2P_GO:
480 		if (wdev->cac_started) {
481 			*chan = wdev->channel;
482 			*chanmode = CHAN_MODE_SHARED;
483 		} else if (wdev->beacon_interval) {
484 			*chan = wdev->channel;
485 			*chanmode = CHAN_MODE_SHARED;
486 		}
487 		return;
488 	case NL80211_IFTYPE_MESH_POINT:
489 		if (wdev->mesh_id_len) {
490 			*chan = wdev->channel;
491 			*chanmode = CHAN_MODE_SHARED;
492 		}
493 		return;
494 	case NL80211_IFTYPE_MONITOR:
495 	case NL80211_IFTYPE_AP_VLAN:
496 	case NL80211_IFTYPE_WDS:
497 		/* these interface types don't really have a channel */
498 		return;
499 	case NL80211_IFTYPE_P2P_DEVICE:
500 		if (wdev->wiphy->features &
501 				NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL)
502 			*chanmode = CHAN_MODE_EXCLUSIVE;
503 		return;
504 	case NL80211_IFTYPE_UNSPECIFIED:
505 	case NUM_NL80211_IFTYPES:
506 		WARN_ON(1);
507 	}
508 
509 	return;
510 }
511