net: Kill link between CSUM and SG features.
[pandora-kernel.git] / net / wireless / chan.c
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 }