mac80211: reconfigure tx on device reconfiguration
[linux-2.6.git] / net / mac80211 / chan.c
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 }