]>
Commit | Line | Data |
---|---|---|
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 | ||
9 | #include <net/cfg80211.h> | |
10 | #include "core.h" | |
11 | ||
9588bbd5 JM |
12 | struct ieee80211_channel * |
13 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | |
59bbb6f7 JB |
14 | int freq, enum nl80211_channel_type channel_type) |
15 | { | |
16 | struct ieee80211_channel *chan; | |
17 | struct ieee80211_sta_ht_cap *ht_cap; | |
59bbb6f7 JB |
18 | |
19 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | |
20 | ||
21 | /* Primary channel not allowed */ | |
22 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | |
9588bbd5 | 23 | return NULL; |
59bbb6f7 JB |
24 | |
25 | if (channel_type == NL80211_CHAN_HT40MINUS && | |
26 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | |
9588bbd5 | 27 | return NULL; |
59bbb6f7 JB |
28 | else if (channel_type == NL80211_CHAN_HT40PLUS && |
29 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | |
9588bbd5 | 30 | return NULL; |
59bbb6f7 JB |
31 | |
32 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | |
33 | ||
34 | if (channel_type != NL80211_CHAN_NO_HT) { | |
35 | if (!ht_cap->ht_supported) | |
9588bbd5 | 36 | return NULL; |
59bbb6f7 | 37 | |
aed8e1f9 HS |
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)) | |
9588bbd5 | 41 | return NULL; |
59bbb6f7 JB |
42 | } |
43 | ||
9588bbd5 JM |
44 | return chan; |
45 | } | |
46 | ||
f444de05 JB |
47 | int cfg80211_set_freq(struct cfg80211_registered_device *rdev, |
48 | struct wireless_dev *wdev, int freq, | |
49 | enum nl80211_channel_type channel_type) | |
9588bbd5 JM |
50 | { |
51 | struct ieee80211_channel *chan; | |
52 | int result; | |
53 | ||
9fbc630c | 54 | if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR) |
f444de05 JB |
55 | wdev = NULL; |
56 | ||
57 | if (wdev) { | |
58 | ASSERT_WDEV_LOCK(wdev); | |
59 | ||
60 | if (!netif_running(wdev->netdev)) | |
61 | return -ENETDOWN; | |
62 | } | |
9588bbd5 JM |
63 | |
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 | ||
f444de05 JB |
71 | result = rdev->ops->set_channel(&rdev->wiphy, |
72 | wdev ? wdev->netdev : NULL, | |
73 | chan, channel_type); | |
59bbb6f7 JB |
74 | if (result) |
75 | return result; | |
76 | ||
f444de05 JB |
77 | if (wdev) |
78 | wdev->channel = chan; | |
59bbb6f7 JB |
79 | |
80 | return 0; | |
81 | } |