Blame view
net/wireless/chan.c
3.21 KB
59bbb6f75 cfg80211: validat... |
1 2 3 4 5 6 7 |
/* * This file contains helper code to handle channel * settings and keeping track of what is possible at * any point in time. * * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> */ |
54858ee5b nl80211: Parse ch... |
8 |
#include <linux/export.h> |
59bbb6f75 cfg80211: validat... |
9 10 11 12 |
#include <net/cfg80211.h> #include "core.h" struct ieee80211_channel * |
9588bbd55 cfg80211: add rem... |
13 |
rdev_freq_to_chan(struct cfg80211_registered_device *rdev, |
59bbb6f75 cfg80211: validat... |
14 15 16 17 |
int freq, enum nl80211_channel_type channel_type) { struct ieee80211_channel *chan; struct ieee80211_sta_ht_cap *ht_cap; |
59bbb6f75 cfg80211: validat... |
18 19 20 21 22 |
chan = ieee80211_get_channel(&rdev->wiphy, freq); /* Primary channel not allowed */ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) |
9588bbd55 cfg80211: add rem... |
23 |
return NULL; |
59bbb6f75 cfg80211: validat... |
24 25 26 |
if (channel_type == NL80211_CHAN_HT40MINUS && chan->flags & IEEE80211_CHAN_NO_HT40MINUS) |
9588bbd55 cfg80211: add rem... |
27 |
return NULL; |
59bbb6f75 cfg80211: validat... |
28 29 |
else if (channel_type == NL80211_CHAN_HT40PLUS && chan->flags & IEEE80211_CHAN_NO_HT40PLUS) |
9588bbd55 cfg80211: add rem... |
30 |
return NULL; |
59bbb6f75 cfg80211: validat... |
31 32 33 34 35 |
ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; if (channel_type != NL80211_CHAN_NO_HT) { if (!ht_cap->ht_supported) |
9588bbd55 cfg80211: add rem... |
36 |
return NULL; |
59bbb6f75 cfg80211: validat... |
37 |
|
aed8e1f99 cfg80211: don't r... |
38 39 40 |
if (channel_type != NL80211_CHAN_HT20 && (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) |
9588bbd55 cfg80211: add rem... |
41 |
return NULL; |
59bbb6f75 cfg80211: validat... |
42 |
} |
9588bbd55 cfg80211: add rem... |
43 44 |
return chan; } |
54858ee5b nl80211: Parse ch... |
45 46 47 |
int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) |
9236d838c cfg80211: fix ext... |
48 49 50 51 52 53 54 |
{ struct ieee80211_channel *sec_chan; int diff; switch (channel_type) { case NL80211_CHAN_HT40PLUS: diff = 20; |
09a02fdb9 cfg80211: fix can... |
55 |
break; |
9236d838c cfg80211: fix ext... |
56 57 |
case NL80211_CHAN_HT40MINUS: diff = -20; |
09a02fdb9 cfg80211: fix can... |
58 |
break; |
9236d838c cfg80211: fix ext... |
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
default: return false; } sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); if (!sec_chan) return false; /* we'll need a DFS capability later */ if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR)) return false; return true; } |
54858ee5b nl80211: Parse ch... |
76 |
EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan); |
9236d838c cfg80211: fix ext... |
77 |
|
f444de05d cfg80211/mac80211... |
78 79 80 |
int cfg80211_set_freq(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, int freq, enum nl80211_channel_type channel_type) |
9588bbd55 cfg80211: add rem... |
81 82 83 |
{ struct ieee80211_channel *chan; int result; |
9fbc630c8 cfg80211: fix cra... |
84 |
if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR) |
f444de05d cfg80211/mac80211... |
85 86 87 88 89 90 91 92 |
wdev = NULL; if (wdev) { ASSERT_WDEV_LOCK(wdev); if (!netif_running(wdev->netdev)) return -ENETDOWN; } |
9588bbd55 cfg80211: add rem... |
93 94 95 96 97 98 99 |
if (!rdev->ops->set_channel) return -EOPNOTSUPP; chan = rdev_freq_to_chan(rdev, freq, channel_type); if (!chan) return -EINVAL; |
9236d838c cfg80211: fix ext... |
100 101 102 103 104 105 106 107 108 |
/* Both channels should be able to initiate communication */ if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC || wdev->iftype == NL80211_IFTYPE_AP || wdev->iftype == NL80211_IFTYPE_AP_VLAN || wdev->iftype == NL80211_IFTYPE_MESH_POINT || wdev->iftype == NL80211_IFTYPE_P2P_GO)) { switch (channel_type) { case NL80211_CHAN_HT40PLUS: case NL80211_CHAN_HT40MINUS: |
54858ee5b nl80211: Parse ch... |
109 110 |
if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan, channel_type)) { |
9236d838c cfg80211: fix ext... |
111 112 113 114 115 116 117 118 119 120 121 |
printk(KERN_DEBUG "cfg80211: Secondary channel not " "allowed to initiate communication "); return -EINVAL; } break; default: break; } } |
f444de05d cfg80211/mac80211... |
122 123 124 |
result = rdev->ops->set_channel(&rdev->wiphy, wdev ? wdev->netdev : NULL, chan, channel_type); |
59bbb6f75 cfg80211: validat... |
125 126 |
if (result) return result; |
f444de05d cfg80211/mac80211... |
127 128 |
if (wdev) wdev->channel = chan; |
59bbb6f75 cfg80211: validat... |
129 130 131 |
return 0; } |