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