Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[platform/adaptation/renesas_rcar/renesas_kernel.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                         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 }