]> Pileus Git - ~andy/linux/blob - net/mac80211/chan.c
xen-netback: coalesce slots in TX path and fix regressions
[~andy/linux] / net / mac80211 / chan.c
1 /*
2  * mac80211 - channel management
3  */
4
5 #include <linux/nl80211.h>
6 #include <linux/export.h>
7 #include <linux/rtnetlink.h>
8 #include <net/cfg80211.h>
9 #include "ieee80211_i.h"
10 #include "driver-ops.h"
11
12 static void ieee80211_change_chanctx(struct ieee80211_local *local,
13                                      struct ieee80211_chanctx *ctx,
14                                      const struct cfg80211_chan_def *chandef)
15 {
16         if (cfg80211_chandef_identical(&ctx->conf.def, chandef))
17                 return;
18
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);
23
24         if (!local->use_chanctx) {
25                 local->_oper_channel_type = cfg80211_get_chandef_type(chandef);
26                 ieee80211_hw_config(local, 0);
27         }
28 }
29
30 static struct ieee80211_chanctx *
31 ieee80211_find_chanctx(struct ieee80211_local *local,
32                        const struct cfg80211_chan_def *chandef,
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;
41
42         list_for_each_entry(ctx, &local->chanctx_list, list) {
43                 const struct cfg80211_chan_def *compat;
44
45                 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
46                         continue;
47
48                 compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
49                 if (!compat)
50                         continue;
51
52                 ieee80211_change_chanctx(local, ctx, compat);
53
54                 return ctx;
55         }
56
57         return NULL;
58 }
59
60 static struct ieee80211_chanctx *
61 ieee80211_new_chanctx(struct ieee80211_local *local,
62                       const struct cfg80211_chan_def *chandef,
63                       enum ieee80211_chanctx_mode mode)
64 {
65         struct ieee80211_chanctx *ctx;
66         u32 changed;
67         int err;
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
75         ctx->conf.def = *chandef;
76         ctx->conf.rx_chains_static = 1;
77         ctx->conf.rx_chains_dynamic = 1;
78         ctx->mode = mode;
79
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
87         if (!local->use_chanctx) {
88                 local->_oper_channel_type =
89                         cfg80211_get_chandef_type(chandef);
90                 local->_oper_channel = chandef->chan;
91                 ieee80211_hw_config(local, 0);
92         } else {
93                 err = drv_add_chanctx(local, ctx);
94                 if (err) {
95                         kfree(ctx);
96                         ctx = ERR_PTR(err);
97
98                         ieee80211_recalc_idle(local);
99                         goto out;
100                 }
101         }
102
103         /* and keep the mutex held until the new chanctx is on the list */
104         list_add_rcu(&ctx->list, &local->chanctx_list);
105
106  out:
107         mutex_unlock(&local->mtx);
108
109         return ctx;
110 }
111
112 static 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
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         }
125
126         list_del_rcu(&ctx->list);
127         kfree_rcu(ctx, rcu_head);
128
129         mutex_lock(&local->mtx);
130         ieee80211_recalc_idle(local);
131         mutex_unlock(&local->mtx);
132 }
133
134 static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
135                                         struct ieee80211_chanctx *ctx)
136 {
137         struct ieee80211_local *local = sdata->local;
138         int ret;
139
140         lockdep_assert_held(&local->chanctx_mtx);
141
142         ret = drv_assign_vif_chanctx(local, sdata, ctx);
143         if (ret)
144                 return ret;
145
146         rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
147         ctx->refcount++;
148
149         ieee80211_recalc_txpower(sdata);
150         sdata->vif.bss_conf.idle = false;
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);
155
156         return 0;
157 }
158
159 static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
160                                               struct ieee80211_chanctx *ctx)
161 {
162         struct ieee80211_chanctx_conf *conf = &ctx->conf;
163         struct ieee80211_sub_if_data *sdata;
164         const struct cfg80211_chan_def *compat = NULL;
165
166         lockdep_assert_held(&local->chanctx_mtx);
167
168         rcu_read_lock();
169         list_for_each_entry_rcu(sdata, &local->interfaces, list) {
170
171                 if (!ieee80211_sdata_running(sdata))
172                         continue;
173                 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
174                         continue;
175
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;
183         }
184         rcu_read_unlock();
185
186         if (WARN_ON_ONCE(!compat))
187                 return;
188
189         ieee80211_change_chanctx(local, ctx, compat);
190 }
191
192 static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
193                                            struct ieee80211_chanctx *ctx)
194 {
195         struct ieee80211_local *local = sdata->local;
196
197         lockdep_assert_held(&local->chanctx_mtx);
198
199         ctx->refcount--;
200         rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
201
202         sdata->vif.bss_conf.idle = true;
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);
207
208         drv_unassign_vif_chanctx(local, sdata, ctx);
209
210         if (ctx->refcount > 0) {
211                 ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
212                 ieee80211_recalc_smps_chanctx(local, ctx);
213                 ieee80211_recalc_radar_chanctx(local, ctx);
214         }
215 }
216
217 static 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
237 void 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
268 void 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
351 int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
352                               const struct cfg80211_chan_def *chandef,
353                               enum ieee80211_chanctx_mode mode)
354 {
355         struct ieee80211_local *local = sdata->local;
356         struct ieee80211_chanctx *ctx;
357         int ret;
358
359         WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
360
361         mutex_lock(&local->chanctx_mtx);
362         __ieee80211_vif_release_channel(sdata);
363
364         ctx = ieee80211_find_chanctx(local, chandef, mode);
365         if (!ctx)
366                 ctx = ieee80211_new_chanctx(local, chandef, mode);
367         if (IS_ERR(ctx)) {
368                 ret = PTR_ERR(ctx);
369                 goto out;
370         }
371
372         sdata->vif.bss_conf.chandef = *chandef;
373
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
382         ieee80211_recalc_smps_chanctx(local, ctx);
383         ieee80211_recalc_radar_chanctx(local, ctx);
384  out:
385         mutex_unlock(&local->chanctx_mtx);
386         return ret;
387 }
388
389 int 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
438 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
439 {
440         WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
441
442         mutex_lock(&sdata->local->chanctx_mtx);
443         __ieee80211_vif_release_channel(sdata);
444         mutex_unlock(&sdata->local->chanctx_mtx);
445 }
446
447 void 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
466 void 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
500 void 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)
512                 if (ctx->driver_present)
513                         iter(hw, &ctx->conf, iter_data);
514         rcu_read_unlock();
515 }
516 EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);