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 <linux/export.h> 10 #include <net/cfg80211.h> 11 #include "core.h" 12 13 struct ieee80211_channel * 14 rdev_freq_to_chan(struct cfg80211_registered_device *rdev, 15 int freq, enum nl80211_channel_type channel_type) 16 { 17 struct ieee80211_channel *chan; 18 struct ieee80211_sta_ht_cap *ht_cap; 19 20 chan = ieee80211_get_channel(&rdev->wiphy, freq); 21 22 /* Primary channel not allowed */ 23 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) 24 return NULL; 25 26 if (channel_type == NL80211_CHAN_HT40MINUS && 27 chan->flags & IEEE80211_CHAN_NO_HT40MINUS) 28 return NULL; 29 else if (channel_type == NL80211_CHAN_HT40PLUS && 30 chan->flags & IEEE80211_CHAN_NO_HT40PLUS) 31 return NULL; 32 33 ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; 34 35 if (channel_type != NL80211_CHAN_NO_HT) { 36 if (!ht_cap->ht_supported) 37 return NULL; 38 39 if (channel_type != NL80211_CHAN_HT20 && 40 (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || 41 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) 42 return NULL; 43 } 44 45 return chan; 46 } 47 48 bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, 49 struct ieee80211_channel *chan, 50 enum nl80211_channel_type channel_type) 51 { 52 struct ieee80211_channel *sec_chan; 53 int diff; 54 55 switch (channel_type) { 56 case NL80211_CHAN_HT40PLUS: 57 diff = 20; 58 break; 59 case NL80211_CHAN_HT40MINUS: 60 diff = -20; 61 break; 62 default: 63 return true; 64 } 65 66 sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); 67 if (!sec_chan) 68 return false; 69 70 /* we'll need a DFS capability later */ 71 if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | 72 IEEE80211_CHAN_PASSIVE_SCAN | 73 IEEE80211_CHAN_NO_IBSS | 74 IEEE80211_CHAN_RADAR)) 75 return false; 76 77 return true; 78 } 79 EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan); 80 81 int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, 82 int freq, enum nl80211_channel_type chantype) 83 { 84 struct ieee80211_channel *chan; 85 86 if (!rdev->ops->set_monitor_channel) 87 return -EOPNOTSUPP; 88 if (!cfg80211_has_monitors_only(rdev)) 89 return -EBUSY; 90 91 chan = rdev_freq_to_chan(rdev, freq, chantype); 92 if (!chan) 93 return -EINVAL; 94 95 return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); 96 } 97 98 void 99 cfg80211_get_chan_state(struct wireless_dev *wdev, 100 struct ieee80211_channel **chan, 101 enum cfg80211_chan_mode *chanmode) 102 { 103 *chan = NULL; 104 *chanmode = CHAN_MODE_UNDEFINED; 105 106 ASSERT_WDEV_LOCK(wdev); 107 108 if (wdev->netdev && !netif_running(wdev->netdev)) 109 return; 110 111 switch (wdev->iftype) { 112 case NL80211_IFTYPE_ADHOC: 113 if (wdev->current_bss) { 114 *chan = wdev->current_bss->pub.channel; 115 *chanmode = wdev->ibss_fixed 116 ? CHAN_MODE_SHARED 117 : CHAN_MODE_EXCLUSIVE; 118 return; 119 } 120 case NL80211_IFTYPE_STATION: 121 case NL80211_IFTYPE_P2P_CLIENT: 122 if (wdev->current_bss) { 123 *chan = wdev->current_bss->pub.channel; 124 *chanmode = CHAN_MODE_SHARED; 125 return; 126 } 127 break; 128 case NL80211_IFTYPE_AP: 129 case NL80211_IFTYPE_P2P_GO: 130 if (wdev->beacon_interval) { 131 *chan = wdev->channel; 132 *chanmode = CHAN_MODE_SHARED; 133 } 134 return; 135 case NL80211_IFTYPE_MESH_POINT: 136 if (wdev->mesh_id_len) { 137 *chan = wdev->channel; 138 *chanmode = CHAN_MODE_SHARED; 139 } 140 return; 141 case NL80211_IFTYPE_MONITOR: 142 case NL80211_IFTYPE_AP_VLAN: 143 case NL80211_IFTYPE_WDS: 144 /* these interface types don't really have a channel */ 145 return; 146 case NL80211_IFTYPE_P2P_DEVICE: 147 if (wdev->wiphy->features & 148 NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL) 149 *chanmode = CHAN_MODE_EXCLUSIVE; 150 return; 151 case NL80211_IFTYPE_UNSPECIFIED: 152 case NUM_NL80211_IFTYPES: 153 WARN_ON(1); 154 } 155 156 return; 157 } 158