parisc iommu: fix panic due to trying to allocate too large region
[linux/fpc-iii.git] / net / wireless / chan.c
blobe69a17da1e8483e10a9c7ef8b488454e3ae4ec32
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.
6 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
7 */
9 #include <linux/export.h>
10 #include <net/cfg80211.h>
11 #include "core.h"
12 #include "rdev-ops.h"
14 void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
15 struct ieee80211_channel *chan,
16 enum nl80211_channel_type chan_type)
18 if (WARN_ON(!chan))
19 return;
21 chandef->chan = chan;
22 chandef->center_freq2 = 0;
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);
45 EXPORT_SYMBOL(cfg80211_chandef_create);
47 bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
49 u32 control_freq;
51 if (!chandef->chan)
52 return false;
54 control_freq = chandef->chan->center_freq;
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;
110 return true;
112 EXPORT_SYMBOL(cfg80211_chandef_valid);
114 static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
115 int *pri40, int *pri80)
117 int tmp;
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);
150 static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
152 int width;
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;
173 return width;
176 const struct cfg80211_chan_def *
177 cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
178 const struct cfg80211_chan_def *c2)
180 u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
182 /* If they are identical, return */
183 if (cfg80211_chandef_identical(c1, c2))
184 return c1;
186 /* otherwise, must have same control channel */
187 if (c1->chan != c2->chan)
188 return NULL;
191 * If they have the same width, but aren't identical,
192 * then they can't be compatible.
194 if (c1->width == c2->width)
195 return NULL;
197 if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
198 c1->width == NL80211_CHAN_WIDTH_20)
199 return c2;
201 if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
202 c2->width == NL80211_CHAN_WIDTH_20)
203 return c1;
205 chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
206 chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
208 if (c1_pri40 != c2_pri40)
209 return NULL;
211 WARN_ON(!c1_pri80 && !c2_pri80);
212 if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
213 return NULL;
215 if (c1->width > c2->width)
216 return c1;
217 return c2;
219 EXPORT_SYMBOL(cfg80211_chandef_compatible);
221 static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
222 u32 bandwidth,
223 enum nl80211_dfs_state dfs_state)
225 struct ieee80211_channel *c;
226 u32 freq;
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;
235 c->dfs_state = dfs_state;
236 c->dfs_state_entered = jiffies;
240 void cfg80211_set_dfs_state(struct wiphy *wiphy,
241 const struct cfg80211_chan_def *chandef,
242 enum nl80211_dfs_state dfs_state)
244 int width;
246 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
247 return;
249 width = cfg80211_chandef_get_width(chandef);
250 if (width < 0)
251 return;
253 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
254 width, dfs_state);
256 if (!chandef->center_freq2)
257 return;
258 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
259 width, dfs_state);
262 static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
263 u32 center_freq,
264 u32 bandwidth)
266 struct ieee80211_channel *c;
267 u32 freq;
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;
276 if (c->flags & IEEE80211_CHAN_RADAR)
277 return 1;
279 return 0;
283 int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
284 const struct cfg80211_chan_def *chandef)
286 int width;
287 int r;
289 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
290 return -EINVAL;
292 width = cfg80211_chandef_get_width(chandef);
293 if (width < 0)
294 return -EINVAL;
296 r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1,
297 width);
298 if (r)
299 return r;
301 if (!chandef->center_freq2)
302 return 0;
304 return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
305 width);
308 static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
309 u32 center_freq, u32 bandwidth,
310 u32 prohibited_flags)
312 struct ieee80211_channel *c;
313 u32 freq;
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;
322 /* check for radar flags */
323 if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) &&
324 (c->dfs_state != NL80211_DFS_AVAILABLE))
325 return false;
327 /* check for the other flags */
328 if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR)
329 return false;
332 return true;
335 bool cfg80211_chandef_usable(struct wiphy *wiphy,
336 const struct cfg80211_chan_def *chandef,
337 u32 prohibited_flags)
339 struct ieee80211_sta_ht_cap *ht_cap;
340 struct ieee80211_sta_vht_cap *vht_cap;
341 u32 width, control_freq, cap;
343 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
344 return false;
346 ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
347 vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
349 control_freq = chandef->chan->center_freq;
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 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
374 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
375 return false;
376 case NL80211_CHAN_WIDTH_80:
377 if (!vht_cap->vht_supported)
378 return false;
379 prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
380 width = 80;
381 break;
382 case NL80211_CHAN_WIDTH_160:
383 if (!vht_cap->vht_supported)
384 return false;
385 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
386 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
387 cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
388 return false;
389 prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
390 width = 160;
391 break;
392 default:
393 WARN_ON_ONCE(1);
394 return false;
398 * TODO: What if there are only certain 80/160/80+80 MHz channels
399 * allowed by the driver, or only certain combinations?
400 * For 40 MHz the driver can set the NO_HT40 flags, but for
401 * 80/160 MHz and in particular 80+80 MHz this isn't really
402 * feasible and we only have NO_80MHZ/NO_160MHZ so far but
403 * no way to cover 80+80 MHz or more complex restrictions.
404 * Note that such restrictions also need to be advertised to
405 * userspace, for example for P2P channel selection.
408 if (width > 20)
409 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
411 if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
412 width, prohibited_flags))
413 return false;
415 if (!chandef->center_freq2)
416 return true;
417 return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
418 width, prohibited_flags);
420 EXPORT_SYMBOL(cfg80211_chandef_usable);
422 bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
423 struct cfg80211_chan_def *chandef)
425 bool res;
427 trace_cfg80211_reg_can_beacon(wiphy, chandef);
429 res = cfg80211_chandef_usable(wiphy, chandef,
430 IEEE80211_CHAN_DISABLED |
431 IEEE80211_CHAN_PASSIVE_SCAN |
432 IEEE80211_CHAN_NO_IBSS |
433 IEEE80211_CHAN_RADAR);
435 trace_cfg80211_return_bool(res);
436 return res;
438 EXPORT_SYMBOL(cfg80211_reg_can_beacon);
440 int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
441 struct cfg80211_chan_def *chandef)
443 if (!rdev->ops->set_monitor_channel)
444 return -EOPNOTSUPP;
445 if (!cfg80211_has_monitors_only(rdev))
446 return -EBUSY;
448 return rdev_set_monitor_channel(rdev, chandef);
451 void
452 cfg80211_get_chan_state(struct wireless_dev *wdev,
453 struct ieee80211_channel **chan,
454 enum cfg80211_chan_mode *chanmode)
456 *chan = NULL;
457 *chanmode = CHAN_MODE_UNDEFINED;
459 ASSERT_WDEV_LOCK(wdev);
461 if (wdev->netdev && !netif_running(wdev->netdev))
462 return;
464 switch (wdev->iftype) {
465 case NL80211_IFTYPE_ADHOC:
466 if (wdev->current_bss) {
467 *chan = wdev->current_bss->pub.channel;
468 *chanmode = wdev->ibss_fixed
469 ? CHAN_MODE_SHARED
470 : CHAN_MODE_EXCLUSIVE;
471 return;
473 case NL80211_IFTYPE_STATION:
474 case NL80211_IFTYPE_P2P_CLIENT:
475 if (wdev->current_bss) {
476 *chan = wdev->current_bss->pub.channel;
477 *chanmode = CHAN_MODE_SHARED;
478 return;
480 break;
481 case NL80211_IFTYPE_AP:
482 case NL80211_IFTYPE_P2P_GO:
483 if (wdev->cac_started) {
484 *chan = wdev->channel;
485 *chanmode = CHAN_MODE_SHARED;
486 } else if (wdev->beacon_interval) {
487 *chan = wdev->channel;
488 *chanmode = CHAN_MODE_SHARED;
490 return;
491 case NL80211_IFTYPE_MESH_POINT:
492 if (wdev->mesh_id_len) {
493 *chan = wdev->channel;
494 *chanmode = CHAN_MODE_SHARED;
496 return;
497 case NL80211_IFTYPE_MONITOR:
498 case NL80211_IFTYPE_AP_VLAN:
499 case NL80211_IFTYPE_WDS:
500 /* these interface types don't really have a channel */
501 return;
502 case NL80211_IFTYPE_P2P_DEVICE:
503 if (wdev->wiphy->features &
504 NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL)
505 *chanmode = CHAN_MODE_EXCLUSIVE;
506 return;
507 case NL80211_IFTYPE_UNSPECIFIED:
508 case NUM_NL80211_IFTYPES:
509 WARN_ON(1);
512 return;