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 12 struct ieee80211_channel * 13 rdev_freq_to_chan(struct cfg80211_registered_device *rdev, 14 int freq, enum nl80211_channel_type channel_type) 15 { 16 struct ieee80211_channel *chan; 17 struct ieee80211_sta_ht_cap *ht_cap; 18 19 chan = ieee80211_get_channel(&rdev->wiphy, freq); 20 21 /* Primary channel not allowed */ 22 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) 23 return NULL; 24 25 if (channel_type == NL80211_CHAN_HT40MINUS && 26 chan->flags & IEEE80211_CHAN_NO_HT40MINUS) 27 return NULL; 28 else if (channel_type == NL80211_CHAN_HT40PLUS && 29 chan->flags & IEEE80211_CHAN_NO_HT40PLUS) 30 return NULL; 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) 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 47 int 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; 53 54 if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR) 55 wdev = NULL; 56 57 if (wdev) { 58 ASSERT_WDEV_LOCK(wdev); 59 60 if (!netif_running(wdev->netdev)) 61 return -ENETDOWN; 62 } 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 71 result = rdev->ops->set_channel(&rdev->wiphy, 72 wdev ? wdev->netdev : NULL, 73 chan, channel_type); 74 if (result) 75 return result; 76 77 if (wdev) 78 wdev->channel = chan; 79 80 return 0; 81 } 82