ipv6: avoid unregistering inet6_dev for loopback
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / wireless / chan.c
CommitLineData
59bbb6f7
JB
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
54858ee5 9#include <linux/export.h>
59bbb6f7
JB
10#include <net/cfg80211.h>
11#include "core.h"
e35e4d28 12#include "rdev-ops.h"
59bbb6f7 13
3d9d1d66
JB
14void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
15 struct ieee80211_channel *chan,
16 enum nl80211_channel_type chan_type)
9236d838 17{
3d9d1d66
JB
18 if (WARN_ON(!chan))
19 return;
9236d838 20
3d9d1d66
JB
21 chandef->chan = chan;
22 chandef->center_freq2 = 0;
4ee3e063 23
3d9d1d66
JB
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;
9236d838 33 case NL80211_CHAN_HT40PLUS:
3d9d1d66
JB
34 chandef->width = NL80211_CHAN_WIDTH_40;
35 chandef->center_freq1 = chan->center_freq + 10;
09a02fdb 36 break;
9236d838 37 case NL80211_CHAN_HT40MINUS:
3d9d1d66
JB
38 chandef->width = NL80211_CHAN_WIDTH_40;
39 chandef->center_freq1 = chan->center_freq - 10;
09a02fdb 40 break;
9236d838 41 default:
3d9d1d66
JB
42 WARN_ON(1);
43 }
44}
45EXPORT_SYMBOL(cfg80211_chandef_create);
46
9f5e8f6e 47bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
3d9d1d66
JB
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;
9cab3151
JB
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;
3d9d1d66
JB
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}
9f5e8f6e 112EXPORT_SYMBOL(cfg80211_chandef_valid);
3d9d1d66
JB
113
114static 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
04f39047
SW
150static 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
3d9d1d66
JB
176const struct cfg80211_chan_def *
177cfg80211_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}
219EXPORT_SYMBOL(cfg80211_chandef_compatible);
220
04f39047
SW
221static 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
240void 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
262static 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
283int 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
9f5e8f6e
JB
308static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
309 u32 center_freq, u32 bandwidth,
310 u32 prohibited_flags)
3d9d1d66
JB
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);
04f39047
SW
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)
3d9d1d66 329 return false;
9236d838
LR
330 }
331
3d9d1d66
JB
332 return true;
333}
334
9f5e8f6e
JB
335bool cfg80211_chandef_usable(struct wiphy *wiphy,
336 const struct cfg80211_chan_def *chandef,
337 u32 prohibited_flags)
3d9d1d66 338{
9f5e8f6e
JB
339 struct ieee80211_sta_ht_cap *ht_cap;
340 struct ieee80211_sta_vht_cap *vht_cap;
b1039f72 341 u32 width, control_freq, cap;
3d9d1d66 342
9f5e8f6e
JB
343 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
344 return false;
3d9d1d66 345
9f5e8f6e
JB
346 ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
347 vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
3d9d1d66 348
9f5e8f6e 349 control_freq = chandef->chan->center_freq;
9236d838 350
3d9d1d66 351 switch (chandef->width) {
3d9d1d66 352 case NL80211_CHAN_WIDTH_20:
9f5e8f6e
JB
353 if (!ht_cap->ht_supported)
354 return false;
355 case NL80211_CHAN_WIDTH_20_NOHT:
3d9d1d66
JB
356 width = 20;
357 break;
358 case NL80211_CHAN_WIDTH_40:
359 width = 40;
9f5e8f6e
JB
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;
3d9d1d66 371 break;
3d9d1d66 372 case NL80211_CHAN_WIDTH_80P80:
b1039f72
JM
373 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
374 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
9f5e8f6e
JB
375 return false;
376 case NL80211_CHAN_WIDTH_80:
377 if (!vht_cap->vht_supported)
378 return false;
c7a6ee27 379 prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
3d9d1d66
JB
380 width = 80;
381 break;
382 case NL80211_CHAN_WIDTH_160:
9f5e8f6e
JB
383 if (!vht_cap->vht_supported)
384 return false;
b1039f72
JM
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)
9f5e8f6e 388 return false;
c7a6ee27 389 prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
3d9d1d66
JB
390 width = 160;
391 break;
392 default:
393 WARN_ON_ONCE(1);
9236d838 394 return false;
4ee3e063 395 }
3d9d1d66 396
c7a6ee27
JB
397 /*
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.
406 */
9f5e8f6e 407
a6662dba
JB
408 if (width > 20)
409 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
410
9f5e8f6e
JB
411 if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
412 width, prohibited_flags))
413 return false;
414
415 if (!chandef->center_freq2)
416 return true;
417 return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
418 width, prohibited_flags);
419}
420EXPORT_SYMBOL(cfg80211_chandef_usable);
421
422bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
423 struct cfg80211_chan_def *chandef)
424{
425 bool res;
426
427 trace_cfg80211_reg_can_beacon(wiphy, chandef);
3d9d1d66 428
9f5e8f6e
JB
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);
3d9d1d66
JB
434
435 trace_cfg80211_return_bool(res);
436 return res;
9236d838 437}
683b6d3b 438EXPORT_SYMBOL(cfg80211_reg_can_beacon);
9236d838 439
e8c9bd5b 440int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
683b6d3b 441 struct cfg80211_chan_def *chandef)
9588bbd5 442{
e8c9bd5b 443 if (!rdev->ops->set_monitor_channel)
9588bbd5 444 return -EOPNOTSUPP;
4f03c1ed
MK
445 if (!cfg80211_has_monitors_only(rdev))
446 return -EBUSY;
9588bbd5 447
683b6d3b 448 return rdev_set_monitor_channel(rdev, chandef);
59bbb6f7 449}
26ab9a0c
MK
450
451void
8e95ea49 452cfg80211_get_chan_state(struct wireless_dev *wdev,
26ab9a0c
MK
453 struct ieee80211_channel **chan,
454 enum cfg80211_chan_mode *chanmode)
455{
456 *chan = NULL;
457 *chanmode = CHAN_MODE_UNDEFINED;
458
26ab9a0c
MK
459 ASSERT_WDEV_LOCK(wdev);
460
98104fde 461 if (wdev->netdev && !netif_running(wdev->netdev))
26ab9a0c
MK
462 return;
463
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;
472 }
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;
479 }
480 break;
481 case NL80211_IFTYPE_AP:
482 case NL80211_IFTYPE_P2P_GO:
04f39047
SW
483 if (wdev->cac_started) {
484 *chan = wdev->channel;
485 *chanmode = CHAN_MODE_SHARED;
486 } else if (wdev->beacon_interval) {
f53594a0
FF
487 *chan = wdev->channel;
488 *chanmode = CHAN_MODE_SHARED;
489 }
490 return;
26ab9a0c 491 case NL80211_IFTYPE_MESH_POINT:
f53594a0
FF
492 if (wdev->mesh_id_len) {
493 *chan = wdev->channel;
494 *chanmode = CHAN_MODE_SHARED;
495 }
26ab9a0c
MK
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;
98104fde
JB
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;
26ab9a0c
MK
507 case NL80211_IFTYPE_UNSPECIFIED:
508 case NUM_NL80211_IFTYPES:
509 WARN_ON(1);
510 }
511
512 return;
513}