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 (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || 39 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) 40 return NULL; 41 } 42 43 return chan; 44 } 45 46 int cfg80211_set_freq(struct cfg80211_registered_device *rdev, 47 struct wireless_dev *wdev, int freq, 48 enum nl80211_channel_type channel_type) 49 { 50 struct ieee80211_channel *chan; 51 int result; 52 53 if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR) 54 wdev = NULL; 55 56 if (wdev) { 57 ASSERT_WDEV_LOCK(wdev); 58 59 if (!netif_running(wdev->netdev)) 60 return -ENETDOWN; 61 } 62 63 if (!rdev->ops->set_channel) 64 return -EOPNOTSUPP; 65 66 chan = rdev_freq_to_chan(rdev, freq, channel_type); 67 if (!chan) 68 return -EINVAL; 69 70 result = rdev->ops->set_channel(&rdev->wiphy, 71 wdev ? wdev->netdev : NULL, 72 chan, channel_type); 73 if (result) 74 return result; 75 76 if (wdev) 77 wdev->channel = chan; 78 79 return 0; 80 } 81