00001 /* 00002 * mac80211 - channel management 00003 */ 00004 00005 #include <linux/nl80211.h> 00006 #include "ieee80211_i.h" 00007 00008 static enum ieee80211_chan_mode 00009 __ieee80211_get_channel_mode(struct ieee80211_local *local, 00010 struct ieee80211_sub_if_data *ignore) 00011 { 00012 struct ieee80211_sub_if_data *sdata; 00013 00014 lockdep_assert_held(&local->iflist_mtx); 00015 00016 list_for_each_entry(sdata, &local->interfaces, list) { 00017 if (sdata == ignore) 00018 continue; 00019 00020 if (!ieee80211_sdata_running(sdata)) 00021 continue; 00022 00023 if (sdata->vif.type == NL80211_IFTYPE_MONITOR) 00024 continue; 00025 00026 if (sdata->vif.type == NL80211_IFTYPE_STATION && 00027 !sdata->u.mgd.associated) 00028 continue; 00029 00030 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { 00031 if (!sdata->u.ibss.ssid_len) 00032 continue; 00033 if (!sdata->u.ibss.fixed_channel) 00034 return CHAN_MODE_HOPPING; 00035 } 00036 00037 if (sdata->vif.type == NL80211_IFTYPE_AP && 00038 !sdata->u.ap.beacon) 00039 continue; 00040 00041 return CHAN_MODE_FIXED; 00042 } 00043 00044 return CHAN_MODE_UNDEFINED; 00045 } 00046 00047 enum ieee80211_chan_mode 00048 ieee80211_get_channel_mode(struct ieee80211_local *local, 00049 struct ieee80211_sub_if_data *ignore) 00050 { 00051 enum ieee80211_chan_mode mode; 00052 00053 mutex_lock(&local->iflist_mtx); 00054 mode = __ieee80211_get_channel_mode(local, ignore); 00055 mutex_unlock(&local->iflist_mtx); 00056 00057 return mode; 00058 } 00059 00060 bool ieee80211_set_channel_type(struct ieee80211_local *local, 00061 struct ieee80211_sub_if_data *sdata, 00062 enum nl80211_channel_type chantype) 00063 { 00064 struct ieee80211_sub_if_data *tmp; 00065 enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; 00066 bool result; 00067 00068 mutex_lock(&local->iflist_mtx); 00069 00070 list_for_each_entry(tmp, &local->interfaces, list) { 00071 if (tmp == sdata) 00072 continue; 00073 00074 if (!ieee80211_sdata_running(tmp)) 00075 continue; 00076 00077 switch (tmp->vif.bss_conf.channel_type) { 00078 case NL80211_CHAN_NO_HT: 00079 case NL80211_CHAN_HT20: 00080 if (superchan > tmp->vif.bss_conf.channel_type) 00081 break; 00082 00083 superchan = tmp->vif.bss_conf.channel_type; 00084 break; 00085 case NL80211_CHAN_HT40PLUS: 00086 WARN_ON(superchan == NL80211_CHAN_HT40MINUS); 00087 superchan = NL80211_CHAN_HT40PLUS; 00088 break; 00089 case NL80211_CHAN_HT40MINUS: 00090 WARN_ON(superchan == NL80211_CHAN_HT40PLUS); 00091 superchan = NL80211_CHAN_HT40MINUS; 00092 break; 00093 } 00094 } 00095 00096 switch (superchan) { 00097 case NL80211_CHAN_NO_HT: 00098 case NL80211_CHAN_HT20: 00099 /* 00100 * allow any change that doesn't go to no-HT 00101 * (if it already is no-HT no change is needed) 00102 */ 00103 if (chantype == NL80211_CHAN_NO_HT) 00104 break; 00105 superchan = chantype; 00106 break; 00107 case NL80211_CHAN_HT40PLUS: 00108 case NL80211_CHAN_HT40MINUS: 00109 /* allow smaller bandwidth and same */ 00110 if (chantype == NL80211_CHAN_NO_HT) 00111 break; 00112 if (chantype == NL80211_CHAN_HT20) 00113 break; 00114 if (superchan == chantype) 00115 break; 00116 result = false; 00117 goto out; 00118 } 00119 00120 local->_oper_channel_type = superchan; 00121 00122 if (sdata) 00123 sdata->vif.bss_conf.channel_type = chantype; 00124 00125 result = true; 00126 out: 00127 mutex_unlock(&local->iflist_mtx); 00128 00129 return result; 00130 }