Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
chan.c
Go to the documentation of this file.
1 /*
2  * mac80211 - channel management
3  */
4 
5 #include <linux/nl80211.h>
6 #include <net/cfg80211.h>
7 #include "ieee80211_i.h"
8 
9 static enum ieee80211_chan_mode
10 __ieee80211_get_channel_mode(struct ieee80211_local *local,
11  struct ieee80211_sub_if_data *ignore)
12 {
14 
16 
17  list_for_each_entry(sdata, &local->interfaces, list) {
18  if (sdata == ignore)
19  continue;
20 
21  if (!ieee80211_sdata_running(sdata))
22  continue;
23 
24  switch (sdata->vif.type) {
26  continue;
28  if (!sdata->u.mgd.associated)
29  continue;
30  break;
32  if (!sdata->u.ibss.ssid_len)
33  continue;
34  if (!sdata->u.ibss.fixed_channel)
35  return CHAN_MODE_HOPPING;
36  break;
38  /* will also have _AP interface */
39  continue;
40  case NL80211_IFTYPE_AP:
41  if (!sdata->u.ap.beacon)
42  continue;
43  break;
45  if (!sdata->wdev.mesh_id_len)
46  continue;
47  break;
48  default:
49  break;
50  }
51 
52  return CHAN_MODE_FIXED;
53  }
54 
55  return CHAN_MODE_UNDEFINED;
56 }
57 
60  struct ieee80211_sub_if_data *ignore)
61 {
63 
64  mutex_lock(&local->iflist_mtx);
65  mode = __ieee80211_get_channel_mode(local, ignore);
66  mutex_unlock(&local->iflist_mtx);
67 
68  return mode;
69 }
70 
71 static enum nl80211_channel_type
72 ieee80211_get_superchan(struct ieee80211_local *local,
73  struct ieee80211_sub_if_data *sdata)
74 {
76  struct ieee80211_sub_if_data *tmp;
77 
78  mutex_lock(&local->iflist_mtx);
79  list_for_each_entry(tmp, &local->interfaces, list) {
80  if (tmp == sdata)
81  continue;
82 
83  if (!ieee80211_sdata_running(tmp))
84  continue;
85 
86  switch (tmp->vif.bss_conf.channel_type) {
87  case NL80211_CHAN_NO_HT:
88  case NL80211_CHAN_HT20:
89  if (superchan > tmp->vif.bss_conf.channel_type)
90  break;
91 
92  superchan = tmp->vif.bss_conf.channel_type;
93  break;
95  WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
96  superchan = NL80211_CHAN_HT40PLUS;
97  break;
99  WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
100  superchan = NL80211_CHAN_HT40MINUS;
101  break;
102  }
103  }
104  mutex_unlock(&local->iflist_mtx);
105 
106  return superchan;
107 }
108 
109 static bool
110 ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
111  enum nl80211_channel_type chantype2,
112  enum nl80211_channel_type *compat)
113 {
114  /*
115  * start out with chantype1 being the result,
116  * overwriting later if needed
117  */
118  if (compat)
119  *compat = chantype1;
120 
121  switch (chantype1) {
122  case NL80211_CHAN_NO_HT:
123  if (compat)
124  *compat = chantype2;
125  break;
126  case NL80211_CHAN_HT20:
127  /*
128  * allow any change that doesn't go to no-HT
129  * (if it already is no-HT no change is needed)
130  */
131  if (chantype2 == NL80211_CHAN_NO_HT)
132  break;
133  if (compat)
134  *compat = chantype2;
135  break;
138  /* allow smaller bandwidth and same */
139  if (chantype2 == NL80211_CHAN_NO_HT)
140  break;
141  if (chantype2 == NL80211_CHAN_HT20)
142  break;
143  if (chantype2 == chantype1)
144  break;
145  return false;
146  }
147 
148  return true;
149 }
150 
152  struct ieee80211_sub_if_data *sdata,
153  enum nl80211_channel_type chantype)
154 {
155  enum nl80211_channel_type superchan;
156  enum nl80211_channel_type compatchan;
157 
158  superchan = ieee80211_get_superchan(local, sdata);
159  if (!ieee80211_channel_types_are_compatible(superchan, chantype,
160  &compatchan))
161  return false;
162 
163  local->_oper_channel_type = compatchan;
164 
165  if (sdata)
166  sdata->vif.bss_conf.channel_type = chantype;
167 
168  return true;
169 
170 }