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 if (sdata->vif.type == NL80211_IFTYPE_MONITOR) 24 continue; 25 26 if (sdata->vif.type == NL80211_IFTYPE_STATION && 27 !sdata->u.mgd.associated) 28 continue; 29 30 if (sdata->vif.type == 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 } 36 37 if (sdata->vif.type == NL80211_IFTYPE_AP && 38 !sdata->u.ap.beacon) 39 continue; 40 41 return CHAN_MODE_FIXED; 42 } 43 44 return CHAN_MODE_UNDEFINED; 45 } 46 47 enum ieee80211_chan_mode 48 ieee80211_get_channel_mode(struct ieee80211_local *local, 49 struct ieee80211_sub_if_data *ignore) 50 { 51 enum ieee80211_chan_mode mode; 52 53 mutex_lock(&local->iflist_mtx); 54 mode = __ieee80211_get_channel_mode(local, ignore); 55 mutex_unlock(&local->iflist_mtx); 56 57 return mode; 58 } 59 60 bool ieee80211_set_channel_type(struct ieee80211_local *local, 61 struct ieee80211_sub_if_data *sdata, 62 enum nl80211_channel_type chantype) 63 { 64 struct ieee80211_sub_if_data *tmp; 65 enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; 66 bool result; 67 68 mutex_lock(&local->iflist_mtx); 69 70 list_for_each_entry(tmp, &local->interfaces, list) { 71 if (tmp == sdata) 72 continue; 73 74 if (!ieee80211_sdata_running(tmp)) 75 continue; 76 77 switch (tmp->vif.bss_conf.channel_type) { 78 case NL80211_CHAN_NO_HT: 79 case NL80211_CHAN_HT20: 80 if (superchan > tmp->vif.bss_conf.channel_type) 81 break; 82 83 superchan = tmp->vif.bss_conf.channel_type; 84 break; 85 case NL80211_CHAN_HT40PLUS: 86 WARN_ON(superchan == NL80211_CHAN_HT40MINUS); 87 superchan = NL80211_CHAN_HT40PLUS; 88 break; 89 case NL80211_CHAN_HT40MINUS: 90 WARN_ON(superchan == NL80211_CHAN_HT40PLUS); 91 superchan = NL80211_CHAN_HT40MINUS; 92 break; 93 } 94 } 95 96 switch (superchan) { 97 case NL80211_CHAN_NO_HT: 98 case NL80211_CHAN_HT20: 99 /* 100 * allow any change that doesn't go to no-HT 101 * (if it already is no-HT no change is needed) 102 */ 103 if (chantype == NL80211_CHAN_NO_HT) 104 break; 105 superchan = chantype; 106 break; 107 case NL80211_CHAN_HT40PLUS: 108 case NL80211_CHAN_HT40MINUS: 109 /* allow smaller bandwidth and same */ 110 if (chantype == NL80211_CHAN_NO_HT) 111 break; 112 if (chantype == NL80211_CHAN_HT20) 113 break; 114 if (superchan == chantype) 115 break; 116 result = false; 117 goto out; 118 } 119 120 local->_oper_channel_type = superchan; 121 122 if (sdata) 123 sdata->vif.bss_conf.channel_type = chantype; 124 125 result = true; 126 out: 127 mutex_unlock(&local->iflist_mtx); 128 129 return result; 130 } 131