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