Merge remote-tracking branch 'regulator/topic/max8952' into v3.9-rc8
[linux-2.6-block.git] / net / mac80211 / chan.c
CommitLineData
f444de05
JB
1/*
2 * mac80211 - channel management
3 */
4
0aaffa9b 5#include <linux/nl80211.h>
3448c005 6#include <linux/export.h>
4d76d21b 7#include <linux/rtnetlink.h>
3117bbdb 8#include <net/cfg80211.h>
f444de05 9#include "ieee80211_i.h"
35f2fce9 10#include "driver-ops.h"
f444de05 11
18942d3b 12static void ieee80211_change_chanctx(struct ieee80211_local *local,
4bf88530
JB
13 struct ieee80211_chanctx *ctx,
14 const struct cfg80211_chan_def *chandef)
23a85b45 15{
4bf88530 16 if (cfg80211_chandef_identical(&ctx->conf.def, chandef))
e89a96f5 17 return;
0aaffa9b 18
4bf88530
JB
19 WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
20
21 ctx->conf.def = *chandef;
22 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
55de908a
JB
23
24 if (!local->use_chanctx) {
4bf88530 25 local->_oper_channel_type = cfg80211_get_chandef_type(chandef);
55de908a
JB
26 ieee80211_hw_config(local, 0);
27 }
0aaffa9b 28}
d01a1e65
MK
29
30static struct ieee80211_chanctx *
31ieee80211_find_chanctx(struct ieee80211_local *local,
4bf88530 32 const struct cfg80211_chan_def *chandef,
d01a1e65
MK
33 enum ieee80211_chanctx_mode mode)
34{
35 struct ieee80211_chanctx *ctx;
36
37 lockdep_assert_held(&local->chanctx_mtx);
38
39 if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
40 return NULL;
d01a1e65
MK
41
42 list_for_each_entry(ctx, &local->chanctx_list, list) {
4bf88530 43 const struct cfg80211_chan_def *compat;
e89a96f5 44
d01a1e65
MK
45 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
46 continue;
4bf88530
JB
47
48 compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
49 if (!compat)
d01a1e65
MK
50 continue;
51
18942d3b 52 ieee80211_change_chanctx(local, ctx, compat);
e89a96f5 53
d01a1e65
MK
54 return ctx;
55 }
56
57 return NULL;
58}
59
60static struct ieee80211_chanctx *
61ieee80211_new_chanctx(struct ieee80211_local *local,
4bf88530 62 const struct cfg80211_chan_def *chandef,
d01a1e65
MK
63 enum ieee80211_chanctx_mode mode)
64{
65 struct ieee80211_chanctx *ctx;
382a103b 66 u32 changed;
35f2fce9 67 int err;
d01a1e65
MK
68
69 lockdep_assert_held(&local->chanctx_mtx);
70
71 ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
72 if (!ctx)
73 return ERR_PTR(-ENOMEM);
74
4bf88530 75 ctx->conf.def = *chandef;
04ecd257
JB
76 ctx->conf.rx_chains_static = 1;
77 ctx->conf.rx_chains_dynamic = 1;
d01a1e65
MK
78 ctx->mode = mode;
79
382a103b
JB
80 /* acquire mutex to prevent idle from changing */
81 mutex_lock(&local->mtx);
82 /* turn idle off *before* setting channel -- some drivers need that */
83 changed = ieee80211_idle_off(local);
84 if (changed)
85 ieee80211_hw_config(local, changed);
86
55de908a 87 if (!local->use_chanctx) {
4bf88530
JB
88 local->_oper_channel_type =
89 cfg80211_get_chandef_type(chandef);
90 local->_oper_channel = chandef->chan;
55de908a
JB
91 ieee80211_hw_config(local, 0);
92 } else {
93 err = drv_add_chanctx(local, ctx);
94 if (err) {
95 kfree(ctx);
382a103b
JB
96 ctx = ERR_PTR(err);
97
98 ieee80211_recalc_idle(local);
99 goto out;
55de908a 100 }
35f2fce9
MK
101 }
102
382a103b 103 /* and keep the mutex held until the new chanctx is on the list */
3448c005 104 list_add_rcu(&ctx->list, &local->chanctx_list);
d01a1e65 105
382a103b 106 out:
fd0f979a
JB
107 mutex_unlock(&local->mtx);
108
d01a1e65
MK
109 return ctx;
110}
111
112static void ieee80211_free_chanctx(struct ieee80211_local *local,
113 struct ieee80211_chanctx *ctx)
114{
115 lockdep_assert_held(&local->chanctx_mtx);
116
117 WARN_ON_ONCE(ctx->refcount != 0);
118
55de908a
JB
119 if (!local->use_chanctx) {
120 local->_oper_channel_type = NL80211_CHAN_NO_HT;
121 ieee80211_hw_config(local, 0);
122 } else {
123 drv_remove_chanctx(local, ctx);
124 }
35f2fce9 125
3448c005 126 list_del_rcu(&ctx->list);
d01a1e65 127 kfree_rcu(ctx, rcu_head);
fd0f979a
JB
128
129 mutex_lock(&local->mtx);
130 ieee80211_recalc_idle(local);
131 mutex_unlock(&local->mtx);
d01a1e65
MK
132}
133
134static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
135 struct ieee80211_chanctx *ctx)
136{
35f2fce9
MK
137 struct ieee80211_local *local = sdata->local;
138 int ret;
d01a1e65
MK
139
140 lockdep_assert_held(&local->chanctx_mtx);
141
35f2fce9
MK
142 ret = drv_assign_vif_chanctx(local, sdata, ctx);
143 if (ret)
144 return ret;
145
d01a1e65
MK
146 rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
147 ctx->refcount++;
148
1ea6f9c0 149 ieee80211_recalc_txpower(sdata);
fd0f979a 150 sdata->vif.bss_conf.idle = false;
5bbe754d
JB
151
152 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
153 sdata->vif.type != NL80211_IFTYPE_MONITOR)
154 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
1ea6f9c0 155
d01a1e65
MK
156 return 0;
157}
158
4bf88530
JB
159static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
160 struct ieee80211_chanctx *ctx)
e89a96f5
MK
161{
162 struct ieee80211_chanctx_conf *conf = &ctx->conf;
163 struct ieee80211_sub_if_data *sdata;
4bf88530 164 const struct cfg80211_chan_def *compat = NULL;
e89a96f5
MK
165
166 lockdep_assert_held(&local->chanctx_mtx);
167
168 rcu_read_lock();
169 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
4bf88530 170
e89a96f5
MK
171 if (!ieee80211_sdata_running(sdata))
172 continue;
173 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
174 continue;
175
4bf88530
JB
176 if (!compat)
177 compat = &sdata->vif.bss_conf.chandef;
178
179 compat = cfg80211_chandef_compatible(
180 &sdata->vif.bss_conf.chandef, compat);
181 if (!compat)
182 break;
e89a96f5
MK
183 }
184 rcu_read_unlock();
185
4bf88530
JB
186 if (WARN_ON_ONCE(!compat))
187 return;
e89a96f5 188
18942d3b 189 ieee80211_change_chanctx(local, ctx, compat);
e89a96f5
MK
190}
191
d01a1e65
MK
192static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
193 struct ieee80211_chanctx *ctx)
194{
35f2fce9 195 struct ieee80211_local *local = sdata->local;
d01a1e65
MK
196
197 lockdep_assert_held(&local->chanctx_mtx);
198
199 ctx->refcount--;
200 rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
35f2fce9 201
fd0f979a 202 sdata->vif.bss_conf.idle = true;
5bbe754d
JB
203
204 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
205 sdata->vif.type != NL80211_IFTYPE_MONITOR)
206 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
fd0f979a 207
35f2fce9 208 drv_unassign_vif_chanctx(local, sdata, ctx);
e89a96f5 209
04ecd257 210 if (ctx->refcount > 0) {
e89a96f5 211 ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
04ecd257 212 ieee80211_recalc_smps_chanctx(local, ctx);
164eb02d 213 ieee80211_recalc_radar_chanctx(local, ctx);
04ecd257 214 }
d01a1e65
MK
215}
216
217static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
218{
219 struct ieee80211_local *local = sdata->local;
220 struct ieee80211_chanctx_conf *conf;
221 struct ieee80211_chanctx *ctx;
222
223 lockdep_assert_held(&local->chanctx_mtx);
224
225 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
226 lockdep_is_held(&local->chanctx_mtx));
227 if (!conf)
228 return;
229
230 ctx = container_of(conf, struct ieee80211_chanctx, conf);
231
232 ieee80211_unassign_vif_chanctx(sdata, ctx);
233 if (ctx->refcount == 0)
234 ieee80211_free_chanctx(local, ctx);
235}
236
164eb02d
SW
237void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
238 struct ieee80211_chanctx *chanctx)
239{
240 struct ieee80211_sub_if_data *sdata;
241 bool radar_enabled = false;
242
243 lockdep_assert_held(&local->chanctx_mtx);
244
245 rcu_read_lock();
246 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
247 if (sdata->radar_required) {
248 radar_enabled = true;
249 break;
250 }
251 }
252 rcu_read_unlock();
253
254 if (radar_enabled == chanctx->conf.radar_enabled)
255 return;
256
257 chanctx->conf.radar_enabled = radar_enabled;
258 local->radar_detect_enabled = chanctx->conf.radar_enabled;
259
260 if (!local->use_chanctx) {
261 local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
262 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
263 }
264
265 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
266}
267
04ecd257
JB
268void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
269 struct ieee80211_chanctx *chanctx)
270{
271 struct ieee80211_sub_if_data *sdata;
272 u8 rx_chains_static, rx_chains_dynamic;
273
274 lockdep_assert_held(&local->chanctx_mtx);
275
276 rx_chains_static = 1;
277 rx_chains_dynamic = 1;
278
279 rcu_read_lock();
280 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
281 u8 needed_static, needed_dynamic;
282
283 if (!ieee80211_sdata_running(sdata))
284 continue;
285
286 if (rcu_access_pointer(sdata->vif.chanctx_conf) !=
287 &chanctx->conf)
288 continue;
289
290 switch (sdata->vif.type) {
291 case NL80211_IFTYPE_P2P_DEVICE:
292 continue;
293 case NL80211_IFTYPE_STATION:
294 if (!sdata->u.mgd.associated)
295 continue;
296 break;
297 case NL80211_IFTYPE_AP_VLAN:
298 continue;
299 case NL80211_IFTYPE_AP:
300 case NL80211_IFTYPE_ADHOC:
301 case NL80211_IFTYPE_WDS:
302 case NL80211_IFTYPE_MESH_POINT:
303 break;
304 default:
305 WARN_ON_ONCE(1);
306 }
307
308 switch (sdata->smps_mode) {
309 default:
310 WARN_ONCE(1, "Invalid SMPS mode %d\n",
311 sdata->smps_mode);
312 /* fall through */
313 case IEEE80211_SMPS_OFF:
314 needed_static = sdata->needed_rx_chains;
315 needed_dynamic = sdata->needed_rx_chains;
316 break;
317 case IEEE80211_SMPS_DYNAMIC:
318 needed_static = 1;
319 needed_dynamic = sdata->needed_rx_chains;
320 break;
321 case IEEE80211_SMPS_STATIC:
322 needed_static = 1;
323 needed_dynamic = 1;
324 break;
325 }
326
327 rx_chains_static = max(rx_chains_static, needed_static);
328 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
329 }
330 rcu_read_unlock();
331
332 if (!local->use_chanctx) {
333 if (rx_chains_static > 1)
334 local->smps_mode = IEEE80211_SMPS_OFF;
335 else if (rx_chains_dynamic > 1)
336 local->smps_mode = IEEE80211_SMPS_DYNAMIC;
337 else
338 local->smps_mode = IEEE80211_SMPS_STATIC;
339 ieee80211_hw_config(local, 0);
340 }
341
342 if (rx_chains_static == chanctx->conf.rx_chains_static &&
343 rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
344 return;
345
346 chanctx->conf.rx_chains_static = rx_chains_static;
347 chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
348 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
349}
350
d01a1e65 351int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
4bf88530 352 const struct cfg80211_chan_def *chandef,
d01a1e65
MK
353 enum ieee80211_chanctx_mode mode)
354{
355 struct ieee80211_local *local = sdata->local;
356 struct ieee80211_chanctx *ctx;
357 int ret;
358
55de908a
JB
359 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
360
d01a1e65
MK
361 mutex_lock(&local->chanctx_mtx);
362 __ieee80211_vif_release_channel(sdata);
363
4bf88530 364 ctx = ieee80211_find_chanctx(local, chandef, mode);
d01a1e65 365 if (!ctx)
4bf88530 366 ctx = ieee80211_new_chanctx(local, chandef, mode);
d01a1e65
MK
367 if (IS_ERR(ctx)) {
368 ret = PTR_ERR(ctx);
369 goto out;
370 }
371
4bf88530 372 sdata->vif.bss_conf.chandef = *chandef;
55de908a 373
d01a1e65
MK
374 ret = ieee80211_assign_vif_chanctx(sdata, ctx);
375 if (ret) {
376 /* if assign fails refcount stays the same */
377 if (ctx->refcount == 0)
378 ieee80211_free_chanctx(local, ctx);
379 goto out;
380 }
381
04ecd257 382 ieee80211_recalc_smps_chanctx(local, ctx);
164eb02d 383 ieee80211_recalc_radar_chanctx(local, ctx);
d01a1e65
MK
384 out:
385 mutex_unlock(&local->chanctx_mtx);
386 return ret;
387}
388
2c9b7359
JB
389int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
390 const struct cfg80211_chan_def *chandef,
391 u32 *changed)
392{
393 struct ieee80211_local *local = sdata->local;
394 struct ieee80211_chanctx_conf *conf;
395 struct ieee80211_chanctx *ctx;
396 int ret;
397
398 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
399 IEEE80211_CHAN_DISABLED))
400 return -EINVAL;
401
402 mutex_lock(&local->chanctx_mtx);
403 if (cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) {
404 ret = 0;
405 goto out;
406 }
407
408 if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT ||
409 sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) {
410 ret = -EINVAL;
411 goto out;
412 }
413
414 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
415 lockdep_is_held(&local->chanctx_mtx));
416 if (!conf) {
417 ret = -EINVAL;
418 goto out;
419 }
420
421 ctx = container_of(conf, struct ieee80211_chanctx, conf);
422 if (!cfg80211_chandef_compatible(&conf->def, chandef)) {
423 ret = -EINVAL;
424 goto out;
425 }
426
427 sdata->vif.bss_conf.chandef = *chandef;
428
429 ieee80211_recalc_chanctx_chantype(local, ctx);
430
431 *changed |= BSS_CHANGED_BANDWIDTH;
432 ret = 0;
433 out:
434 mutex_unlock(&local->chanctx_mtx);
435 return ret;
436}
437
d01a1e65
MK
438void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
439{
55de908a
JB
440 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
441
d01a1e65
MK
442 mutex_lock(&sdata->local->chanctx_mtx);
443 __ieee80211_vif_release_channel(sdata);
444 mutex_unlock(&sdata->local->chanctx_mtx);
445}
3448c005 446
4d76d21b
JB
447void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
448{
449 struct ieee80211_local *local = sdata->local;
450 struct ieee80211_sub_if_data *ap;
451 struct ieee80211_chanctx_conf *conf;
452
453 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
454 return;
455
456 ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
457
458 mutex_lock(&local->chanctx_mtx);
459
460 conf = rcu_dereference_protected(ap->vif.chanctx_conf,
461 lockdep_is_held(&local->chanctx_mtx));
462 rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
463 mutex_unlock(&local->chanctx_mtx);
464}
465
1f4ac5a6
JB
466void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
467 bool clear)
468{
469 struct ieee80211_local *local = sdata->local;
470 struct ieee80211_sub_if_data *vlan;
471 struct ieee80211_chanctx_conf *conf;
472
473 ASSERT_RTNL();
474
475 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
476 return;
477
478 mutex_lock(&local->chanctx_mtx);
479
480 /*
481 * Check that conf exists, even when clearing this function
482 * must be called with the AP's channel context still there
483 * as it would otherwise cause VLANs to have an invalid
484 * channel context pointer for a while, possibly pointing
485 * to a channel context that has already been freed.
486 */
487 conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
488 lockdep_is_held(&local->chanctx_mtx));
489 WARN_ON(!conf);
490
491 if (clear)
492 conf = NULL;
493
494 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
495 rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
496
497 mutex_unlock(&local->chanctx_mtx);
498}
499
3448c005
JB
500void ieee80211_iter_chan_contexts_atomic(
501 struct ieee80211_hw *hw,
502 void (*iter)(struct ieee80211_hw *hw,
503 struct ieee80211_chanctx_conf *chanctx_conf,
504 void *data),
505 void *iter_data)
506{
507 struct ieee80211_local *local = hw_to_local(hw);
508 struct ieee80211_chanctx *ctx;
509
510 rcu_read_lock();
511 list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
8a61af65
JB
512 if (ctx->driver_present)
513 iter(hw, &ctx->conf, iter_data);
3448c005
JB
514 rcu_read_unlock();
515}
516EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);