1 /* 2 * mac80211 - channel management 3 */ 4 5 #include <linux/nl80211.h> 6 #include <net/cfg80211.h> 7 #include "ieee80211_i.h" 8 9 static enum ieee80211_chan_mode 10 __ieee80211_get_channel_mode(struct ieee80211_local *local, 11 struct ieee80211_sub_if_data *ignore) 12 { 13 struct ieee80211_sub_if_data *sdata; 14 15 lockdep_assert_held(&local->iflist_mtx); 16 17 list_for_each_entry(sdata, &local->interfaces, list) { 18 if (sdata == ignore) 19 continue; 20 21 if (!ieee80211_sdata_running(sdata)) 22 continue; 23 24 switch (sdata->vif.type) { 25 case NL80211_IFTYPE_MONITOR: 26 continue; 27 case NL80211_IFTYPE_STATION: 28 if (!sdata->u.mgd.associated) 29 continue; 30 break; 31 case NL80211_IFTYPE_ADHOC: 32 if (!sdata->u.ibss.ssid_len) 33 continue; 34 if (!sdata->u.ibss.fixed_channel) 35 return CHAN_MODE_HOPPING; 36 break; 37 case NL80211_IFTYPE_AP_VLAN: 38 /* will also have _AP interface */ 39 continue; 40 case NL80211_IFTYPE_AP: 41 if (!sdata->u.ap.beacon) 42 continue; 43 break; 44 default: 45 break; 46 } 47 48 return CHAN_MODE_FIXED; 49 } 50 51 return CHAN_MODE_UNDEFINED; 52 } 53 54 enum ieee80211_chan_mode 55 ieee80211_get_channel_mode(struct ieee80211_local *local, 56 struct ieee80211_sub_if_data *ignore) 57 { 58 enum ieee80211_chan_mode mode; 59 60 mutex_lock(&local->iflist_mtx); 61 mode = __ieee80211_get_channel_mode(local, ignore); 62 mutex_unlock(&local->iflist_mtx); 63 64 return mode; 65 } 66 67 bool ieee80211_set_channel_type(struct ieee80211_local *local, 68 struct ieee80211_sub_if_data *sdata, 69 enum nl80211_channel_type chantype) 70 { 71 struct ieee80211_sub_if_data *tmp; 72 enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; 73 bool result; 74 75 mutex_lock(&local->iflist_mtx); 76 77 list_for_each_entry(tmp, &local->interfaces, list) { 78 if (tmp == sdata) 79 continue; 80 81 if (!ieee80211_sdata_running(tmp)) 82 continue; 83 84 switch (tmp->vif.bss_conf.channel_type) { 85 case NL80211_CHAN_NO_HT: 86 case NL80211_CHAN_HT20: 87 if (superchan > tmp->vif.bss_conf.channel_type) 88 break; 89 90 superchan = tmp->vif.bss_conf.channel_type; 91 break; 92 case NL80211_CHAN_HT40PLUS: 93 WARN_ON(superchan == NL80211_CHAN_HT40MINUS); 94 superchan = NL80211_CHAN_HT40PLUS; 95 break; 96 case NL80211_CHAN_HT40MINUS: 97 WARN_ON(superchan == NL80211_CHAN_HT40PLUS); 98 superchan = NL80211_CHAN_HT40MINUS; 99 break; 100 } 101 } 102 103 switch (superchan) { 104 case NL80211_CHAN_NO_HT: 105 case NL80211_CHAN_HT20: 106 /* 107 * allow any change that doesn't go to no-HT 108 * (if it already is no-HT no change is needed) 109 */ 110 if (chantype == NL80211_CHAN_NO_HT) 111 break; 112 superchan = chantype; 113 break; 114 case NL80211_CHAN_HT40PLUS: 115 case NL80211_CHAN_HT40MINUS: 116 /* allow smaller bandwidth and same */ 117 if (chantype == NL80211_CHAN_NO_HT) 118 break; 119 if (chantype == NL80211_CHAN_HT20) 120 break; 121 if (superchan == chantype) 122 break; 123 result = false; 124 goto out; 125 } 126 127 local->_oper_channel_type = superchan; 128 129 if (sdata) 130 sdata->vif.bss_conf.channel_type = chantype; 131 132 result = true; 133 out: 134 mutex_unlock(&local->iflist_mtx); 135 136 return result; 137 } 138 139 /* 140 * ieee80211_get_tx_channel_type returns the channel type we should 141 * use for packet transmission, given the channel capability and 142 * whatever regulatory flags we have been given. 143 */ 144 enum nl80211_channel_type ieee80211_get_tx_channel_type( 145 struct ieee80211_local *local, 146 enum nl80211_channel_type channel_type) 147 { 148 switch (channel_type) { 149 case NL80211_CHAN_HT40PLUS: 150 if (local->hw.conf.channel->flags & 151 IEEE80211_CHAN_NO_HT40PLUS) 152 return NL80211_CHAN_HT20; 153 break; 154 case NL80211_CHAN_HT40MINUS: 155 if (local->hw.conf.channel->flags & 156 IEEE80211_CHAN_NO_HT40MINUS) 157 return NL80211_CHAN_HT20; 158 break; 159 default: 160 break; 161 } 162 return channel_type; 163 } 164