aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/chan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/chan.c')
-rw-r--r--net/wireless/chan.c90
1 files changed, 41 insertions, 49 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index a46ac6c9b365..d0c92dddb26b 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -10,80 +10,72 @@
10#include "core.h" 10#include "core.h"
11 11
12struct ieee80211_channel * 12struct ieee80211_channel *
13rdev_fixed_channel(struct cfg80211_registered_device *rdev, 13rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
14 struct wireless_dev *for_wdev)
15{
16 struct wireless_dev *wdev;
17 struct ieee80211_channel *result = NULL;
18
19 WARN_ON(!mutex_is_locked(&rdev->devlist_mtx));
20
21 list_for_each_entry(wdev, &rdev->netdev_list, list) {
22 if (wdev == for_wdev)
23 continue;
24
25 /*
26 * Lock manually to tell lockdep about allowed
27 * nesting here if for_wdev->mtx is held already.
28 * This is ok as it's all under the rdev devlist
29 * mutex and as such can only be done once at any
30 * given time.
31 */
32 mutex_lock_nested(&wdev->mtx, SINGLE_DEPTH_NESTING);
33 if (wdev->current_bss)
34 result = wdev->current_bss->pub.channel;
35 wdev_unlock(wdev);
36
37 if (result)
38 break;
39 }
40
41 return result;
42}
43
44int rdev_set_freq(struct cfg80211_registered_device *rdev,
45 struct wireless_dev *for_wdev,
46 int freq, enum nl80211_channel_type channel_type) 14 int freq, enum nl80211_channel_type channel_type)
47{ 15{
48 struct ieee80211_channel *chan; 16 struct ieee80211_channel *chan;
49 struct ieee80211_sta_ht_cap *ht_cap; 17 struct ieee80211_sta_ht_cap *ht_cap;
50 int result;
51
52 if (rdev_fixed_channel(rdev, for_wdev))
53 return -EBUSY;
54
55 if (!rdev->ops->set_channel)
56 return -EOPNOTSUPP;
57 18
58 chan = ieee80211_get_channel(&rdev->wiphy, freq); 19 chan = ieee80211_get_channel(&rdev->wiphy, freq);
59 20
60 /* Primary channel not allowed */ 21 /* Primary channel not allowed */
61 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) 22 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
62 return -EINVAL; 23 return NULL;
63 24
64 if (channel_type == NL80211_CHAN_HT40MINUS && 25 if (channel_type == NL80211_CHAN_HT40MINUS &&
65 chan->flags & IEEE80211_CHAN_NO_HT40MINUS) 26 chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
66 return -EINVAL; 27 return NULL;
67 else if (channel_type == NL80211_CHAN_HT40PLUS && 28 else if (channel_type == NL80211_CHAN_HT40PLUS &&
68 chan->flags & IEEE80211_CHAN_NO_HT40PLUS) 29 chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
69 return -EINVAL; 30 return NULL;
70 31
71 ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; 32 ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
72 33
73 if (channel_type != NL80211_CHAN_NO_HT) { 34 if (channel_type != NL80211_CHAN_NO_HT) {
74 if (!ht_cap->ht_supported) 35 if (!ht_cap->ht_supported)
75 return -EINVAL; 36 return NULL;
37
38 if (channel_type != NL80211_CHAN_HT20 &&
39 (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
40 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
41 return NULL;
42 }
43
44 return chan;
45}
46
47int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
48 struct wireless_dev *wdev, int freq,
49 enum nl80211_channel_type channel_type)
50{
51 struct ieee80211_channel *chan;
52 int result;
76 53
77 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || 54 if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR)
78 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) 55 wdev = NULL;
79 return -EINVAL; 56
57 if (wdev) {
58 ASSERT_WDEV_LOCK(wdev);
59
60 if (!netif_running(wdev->netdev))
61 return -ENETDOWN;
80 } 62 }
81 63
82 result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); 64 if (!rdev->ops->set_channel)
65 return -EOPNOTSUPP;
66
67 chan = rdev_freq_to_chan(rdev, freq, channel_type);
68 if (!chan)
69 return -EINVAL;
70
71 result = rdev->ops->set_channel(&rdev->wiphy,
72 wdev ? wdev->netdev : NULL,
73 chan, channel_type);
83 if (result) 74 if (result)
84 return result; 75 return result;
85 76
86 rdev->channel = chan; 77 if (wdev)
78 wdev->channel = chan;
87 79
88 return 0; 80 return 0;
89} 81}