aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r--net/mac80211/chan.c152
1 files changed, 27 insertions, 125 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 1a8dee42e546..41e1aa69f7aa 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -7,106 +7,6 @@
7#include "ieee80211_i.h" 7#include "ieee80211_i.h"
8#include "driver-ops.h" 8#include "driver-ops.h"
9 9
10static enum ieee80211_chan_mode
11__ieee80211_get_channel_mode(struct ieee80211_local *local,
12 struct ieee80211_sub_if_data *ignore)
13{
14 struct ieee80211_sub_if_data *sdata;
15
16 lockdep_assert_held(&local->iflist_mtx);
17
18 list_for_each_entry(sdata, &local->interfaces, list) {
19 if (sdata == ignore)
20 continue;
21
22 if (!ieee80211_sdata_running(sdata))
23 continue;
24
25 switch (sdata->vif.type) {
26 case NL80211_IFTYPE_MONITOR:
27 continue;
28 case NL80211_IFTYPE_STATION:
29 if (!sdata->u.mgd.associated)
30 continue;
31 break;
32 case NL80211_IFTYPE_ADHOC:
33 if (!sdata->u.ibss.ssid_len)
34 continue;
35 if (!sdata->u.ibss.fixed_channel)
36 return CHAN_MODE_HOPPING;
37 break;
38 case NL80211_IFTYPE_AP_VLAN:
39 /* will also have _AP interface */
40 continue;
41 case NL80211_IFTYPE_AP:
42 if (!sdata->u.ap.beacon)
43 continue;
44 break;
45 case NL80211_IFTYPE_MESH_POINT:
46 if (!sdata->wdev.mesh_id_len)
47 continue;
48 break;
49 default:
50 break;
51 }
52
53 return CHAN_MODE_FIXED;
54 }
55
56 return CHAN_MODE_UNDEFINED;
57}
58
59enum ieee80211_chan_mode
60ieee80211_get_channel_mode(struct ieee80211_local *local,
61 struct ieee80211_sub_if_data *ignore)
62{
63 enum ieee80211_chan_mode mode;
64
65 mutex_lock(&local->iflist_mtx);
66 mode = __ieee80211_get_channel_mode(local, ignore);
67 mutex_unlock(&local->iflist_mtx);
68
69 return mode;
70}
71
72static enum nl80211_channel_type
73ieee80211_get_superchan(struct ieee80211_local *local,
74 struct ieee80211_sub_if_data *sdata)
75{
76 enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
77 struct ieee80211_sub_if_data *tmp;
78
79 mutex_lock(&local->iflist_mtx);
80 list_for_each_entry(tmp, &local->interfaces, list) {
81 if (tmp == sdata)
82 continue;
83
84 if (!ieee80211_sdata_running(tmp))
85 continue;
86
87 switch (tmp->vif.bss_conf.channel_type) {
88 case NL80211_CHAN_NO_HT:
89 case NL80211_CHAN_HT20:
90 if (superchan > tmp->vif.bss_conf.channel_type)
91 break;
92
93 superchan = tmp->vif.bss_conf.channel_type;
94 break;
95 case NL80211_CHAN_HT40PLUS:
96 WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
97 superchan = NL80211_CHAN_HT40PLUS;
98 break;
99 case NL80211_CHAN_HT40MINUS:
100 WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
101 superchan = NL80211_CHAN_HT40MINUS;
102 break;
103 }
104 }
105 mutex_unlock(&local->iflist_mtx);
106
107 return superchan;
108}
109
110static bool 10static bool
111ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, 11ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
112 enum nl80211_channel_type chantype2, 12 enum nl80211_channel_type chantype2,
@@ -149,26 +49,6 @@ ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
149 return true; 49 return true;
150} 50}
151 51
152bool ieee80211_set_channel_type(struct ieee80211_local *local,
153 struct ieee80211_sub_if_data *sdata,
154 enum nl80211_channel_type chantype)
155{
156 enum nl80211_channel_type superchan;
157 enum nl80211_channel_type compatchan;
158
159 superchan = ieee80211_get_superchan(local, sdata);
160 if (!ieee80211_channel_types_are_compatible(superchan, chantype,
161 &compatchan))
162 return false;
163
164 local->_oper_channel_type = compatchan;
165
166 if (sdata)
167 sdata->vif.bss_conf.channel_type = chantype;
168
169 return true;
170}
171
172static void ieee80211_change_chantype(struct ieee80211_local *local, 52static void ieee80211_change_chantype(struct ieee80211_local *local,
173 struct ieee80211_chanctx *ctx, 53 struct ieee80211_chanctx *ctx,
174 enum nl80211_channel_type chantype) 54 enum nl80211_channel_type chantype)
@@ -178,6 +58,11 @@ static void ieee80211_change_chantype(struct ieee80211_local *local,
178 58
179 ctx->conf.channel_type = chantype; 59 ctx->conf.channel_type = chantype;
180 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); 60 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE);
61
62 if (!local->use_chanctx) {
63 local->_oper_channel_type = chantype;
64 ieee80211_hw_config(local, 0);
65 }
181} 66}
182 67
183static struct ieee80211_chanctx * 68static struct ieee80211_chanctx *
@@ -235,10 +120,16 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
235 ctx->conf.channel_type = channel_type; 120 ctx->conf.channel_type = channel_type;
236 ctx->mode = mode; 121 ctx->mode = mode;
237 122
238 err = drv_add_chanctx(local, ctx); 123 if (!local->use_chanctx) {
239 if (err) { 124 local->_oper_channel_type = channel_type;
240 kfree(ctx); 125 local->_oper_channel = channel;
241 return ERR_PTR(err); 126 ieee80211_hw_config(local, 0);
127 } else {
128 err = drv_add_chanctx(local, ctx);
129 if (err) {
130 kfree(ctx);
131 return ERR_PTR(err);
132 }
242 } 133 }
243 134
244 list_add(&ctx->list, &local->chanctx_list); 135 list_add(&ctx->list, &local->chanctx_list);
@@ -253,7 +144,12 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
253 144
254 WARN_ON_ONCE(ctx->refcount != 0); 145 WARN_ON_ONCE(ctx->refcount != 0);
255 146
256 drv_remove_chanctx(local, ctx); 147 if (!local->use_chanctx) {
148 local->_oper_channel_type = NL80211_CHAN_NO_HT;
149 ieee80211_hw_config(local, 0);
150 } else {
151 drv_remove_chanctx(local, ctx);
152 }
257 153
258 list_del(&ctx->list); 154 list_del(&ctx->list);
259 kfree_rcu(ctx, rcu_head); 155 kfree_rcu(ctx, rcu_head);
@@ -359,6 +255,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
359 struct ieee80211_chanctx *ctx; 255 struct ieee80211_chanctx *ctx;
360 int ret; 256 int ret;
361 257
258 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
259
362 mutex_lock(&local->chanctx_mtx); 260 mutex_lock(&local->chanctx_mtx);
363 __ieee80211_vif_release_channel(sdata); 261 __ieee80211_vif_release_channel(sdata);
364 262
@@ -370,6 +268,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
370 goto out; 268 goto out;
371 } 269 }
372 270
271 sdata->vif.bss_conf.channel_type = channel_type;
272
373 ret = ieee80211_assign_vif_chanctx(sdata, ctx); 273 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
374 if (ret) { 274 if (ret) {
375 /* if assign fails refcount stays the same */ 275 /* if assign fails refcount stays the same */
@@ -385,6 +285,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
385 285
386void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) 286void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
387{ 287{
288 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
289
388 mutex_lock(&sdata->local->chanctx_mtx); 290 mutex_lock(&sdata->local->chanctx_mtx);
389 __ieee80211_vif_release_channel(sdata); 291 __ieee80211_vif_release_channel(sdata);
390 mutex_unlock(&sdata->local->chanctx_mtx); 292 mutex_unlock(&sdata->local->chanctx_mtx);