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
cfg80211_chandef_create(struct cfg80211_chan_def * chandef,struct ieee80211_channel * chan,enum nl80211_channel_type chan_type)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
cfg80211_chandef_valid(const struct cfg80211_chan_def * chandef)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
chandef_primary_freqs(const struct cfg80211_chan_def * c,int * pri40,int * pri80)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
cfg80211_chandef_get_width(const struct cfg80211_chan_def * c)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 *
cfg80211_chandef_compatible(const struct cfg80211_chan_def * c1,const struct cfg80211_chan_def * c2)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
cfg80211_set_chans_dfs_state(struct wiphy * wiphy,u32 center_freq,u32 bandwidth,enum nl80211_dfs_state dfs_state)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
cfg80211_set_dfs_state(struct wiphy * wiphy,const struct cfg80211_chan_def * chandef,enum nl80211_dfs_state dfs_state)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
cfg80211_get_chans_dfs_required(struct wiphy * wiphy,u32 center_freq,u32 bandwidth)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
cfg80211_chandef_dfs_required(struct wiphy * wiphy,const struct cfg80211_chan_def * chandef)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
cfg80211_secondary_chans_ok(struct wiphy * wiphy,u32 center_freq,u32 bandwidth,u32 prohibited_flags)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
cfg80211_chandef_usable(struct wiphy * wiphy,const struct cfg80211_chan_def * chandef,u32 prohibited_flags)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
cfg80211_reg_can_beacon(struct wiphy * wiphy,struct cfg80211_chan_def * chandef)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
cfg80211_set_monitor_channel(struct cfg80211_registered_device * rdev,struct cfg80211_chan_def * chandef)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
cfg80211_get_chan_state(struct wireless_dev * wdev,struct ieee80211_channel ** chan,enum cfg80211_chan_mode * chanmode)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