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 superchan = tmp->vif.bss_conf.channel_type; 81 break; 82 case NL80211_CHAN_HT40PLUS: 83 WARN_ON(superchan == NL80211_CHAN_HT40MINUS); 84 superchan = NL80211_CHAN_HT40PLUS; 85 break; 86 case NL80211_CHAN_HT40MINUS: 87 WARN_ON(superchan == NL80211_CHAN_HT40PLUS); 88 superchan = NL80211_CHAN_HT40MINUS; 89 break; 90 } 91 } 92 93 switch (superchan) { 94 case NL80211_CHAN_NO_HT: 95 case NL80211_CHAN_HT20: 96 /* 97 * allow any change that doesn't go to no-HT 98 * (if it already is no-HT no change is needed) 99 */ 100 if (chantype == NL80211_CHAN_NO_HT) 101 break; 102 superchan = chantype; 103 break; 104 case NL80211_CHAN_HT40PLUS: 105 case NL80211_CHAN_HT40MINUS: 106 /* allow smaller bandwidth and same */ 107 if (chantype == NL80211_CHAN_NO_HT) 108 break; 109 if (chantype == NL80211_CHAN_HT20) 110 break; 111 if (superchan == chantype) 112 break; 113 result = false; 114 goto out; 115 } 116 117 local->_oper_channel_type = superchan; 118 119 if (sdata) 120 sdata->vif.bss_conf.channel_type = chantype; 121 122 result = true; 123 out: 124 mutex_unlock(&local->iflist_mtx); 125 126 return result; 127 } 128