1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /*
3 * Copyright (C) 2024 Felix Fietkau <nbd@nbd.name>
4 */
5 #include "mt76.h"
6
7 static struct mt76_vif_link *
mt76_alloc_mlink(struct mt76_dev * dev,struct mt76_vif_data * mvif)8 mt76_alloc_mlink(struct mt76_dev *dev, struct mt76_vif_data *mvif)
9 {
10 struct mt76_vif_link *mlink;
11
12 mlink = kzalloc(dev->drv->link_data_size, GFP_KERNEL);
13 if (!mlink)
14 return NULL;
15
16 mlink->mvif = mvif;
17
18 return mlink;
19 }
20
21 static int
mt76_phy_update_channel(struct mt76_phy * phy,struct ieee80211_chanctx_conf * conf)22 mt76_phy_update_channel(struct mt76_phy *phy,
23 struct ieee80211_chanctx_conf *conf)
24 {
25 phy->radar_enabled = conf->radar_enabled;
26 phy->main_chandef = conf->def;
27 phy->chanctx = (struct mt76_chanctx *)conf->drv_priv;
28
29 return __mt76_set_channel(phy, &phy->main_chandef, false);
30 }
31
mt76_add_chanctx(struct ieee80211_hw * hw,struct ieee80211_chanctx_conf * conf)32 int mt76_add_chanctx(struct ieee80211_hw *hw,
33 struct ieee80211_chanctx_conf *conf)
34 {
35 struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
36 struct mt76_phy *phy = hw->priv;
37 struct mt76_dev *dev = phy->dev;
38 int ret = -EINVAL;
39
40 phy = ctx->phy = dev->band_phys[conf->def.chan->band];
41 if (WARN_ON_ONCE(!phy))
42 return ret;
43
44 if (dev->scan.phy == phy)
45 mt76_abort_scan(dev);
46
47 mutex_lock(&dev->mutex);
48 if (!phy->chanctx)
49 ret = mt76_phy_update_channel(phy, conf);
50 else
51 ret = 0;
52 mutex_unlock(&dev->mutex);
53
54 return ret;
55 }
56 EXPORT_SYMBOL_GPL(mt76_add_chanctx);
57
mt76_remove_chanctx(struct ieee80211_hw * hw,struct ieee80211_chanctx_conf * conf)58 void mt76_remove_chanctx(struct ieee80211_hw *hw,
59 struct ieee80211_chanctx_conf *conf)
60 {
61 struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
62 struct mt76_phy *phy = hw->priv;
63 struct mt76_dev *dev = phy->dev;
64
65 phy = ctx->phy;
66 if (WARN_ON_ONCE(!phy))
67 return;
68
69 if (dev->scan.phy == phy)
70 mt76_abort_scan(dev);
71
72 mutex_lock(&dev->mutex);
73 if (phy->chanctx == ctx)
74 phy->chanctx = NULL;
75 mutex_unlock(&dev->mutex);
76 }
77 EXPORT_SYMBOL_GPL(mt76_remove_chanctx);
78
mt76_change_chanctx(struct ieee80211_hw * hw,struct ieee80211_chanctx_conf * conf,u32 changed)79 void mt76_change_chanctx(struct ieee80211_hw *hw,
80 struct ieee80211_chanctx_conf *conf,
81 u32 changed)
82 {
83 struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
84 struct mt76_phy *phy = ctx->phy;
85 struct mt76_dev *dev = phy->dev;
86
87 if (!(changed & (IEEE80211_CHANCTX_CHANGE_WIDTH |
88 IEEE80211_CHANCTX_CHANGE_RADAR)))
89 return;
90
91 if (phy->roc_vif)
92 mt76_abort_roc(phy);
93
94 cancel_delayed_work_sync(&phy->mac_work);
95
96 mutex_lock(&dev->mutex);
97 mt76_phy_update_channel(phy, conf);
98 mutex_unlock(&dev->mutex);
99 }
100 EXPORT_SYMBOL_GPL(mt76_change_chanctx);
101
102
mt76_assign_vif_chanctx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf,struct ieee80211_chanctx_conf * conf)103 int mt76_assign_vif_chanctx(struct ieee80211_hw *hw,
104 struct ieee80211_vif *vif,
105 struct ieee80211_bss_conf *link_conf,
106 struct ieee80211_chanctx_conf *conf)
107 {
108 struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
109 struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
110 struct mt76_vif_data *mvif = mlink->mvif;
111 int link_id = link_conf->link_id;
112 struct mt76_phy *phy = ctx->phy;
113 struct mt76_dev *dev = phy->dev;
114 bool mlink_alloc = false;
115 int ret = 0;
116
117 if (dev->scan.vif == vif)
118 mt76_abort_scan(dev);
119
120 mutex_lock(&dev->mutex);
121
122 if (vif->type == NL80211_IFTYPE_MONITOR &&
123 is_zero_ether_addr(vif->addr))
124 goto out;
125
126 mlink = mt76_vif_conf_link(dev, vif, link_conf);
127 if (!mlink) {
128 mlink = mt76_alloc_mlink(dev, mvif);
129 if (!mlink) {
130 ret = -ENOMEM;
131 goto out;
132 }
133 mlink_alloc = true;
134 }
135
136 mlink->ctx = conf;
137 ret = dev->drv->vif_link_add(phy, vif, link_conf, mlink);
138 if (ret) {
139 if (mlink_alloc)
140 kfree(mlink);
141 goto out;
142 }
143
144 if (link_conf != &vif->bss_conf)
145 rcu_assign_pointer(mvif->link[link_id], mlink);
146
147 out:
148 mutex_unlock(&dev->mutex);
149
150 return ret;
151 }
152 EXPORT_SYMBOL_GPL(mt76_assign_vif_chanctx);
153
mt76_unassign_vif_chanctx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf,struct ieee80211_chanctx_conf * conf)154 void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw,
155 struct ieee80211_vif *vif,
156 struct ieee80211_bss_conf *link_conf,
157 struct ieee80211_chanctx_conf *conf)
158 {
159 struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
160 struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
161 struct mt76_phy *phy = ctx->phy;
162 struct mt76_dev *dev = phy->dev;
163
164 if (dev->scan.vif == vif)
165 mt76_abort_scan(dev);
166
167 mutex_lock(&dev->mutex);
168
169 if (vif->type == NL80211_IFTYPE_MONITOR &&
170 is_zero_ether_addr(vif->addr))
171 goto out;
172
173 mlink = mt76_vif_conf_link(dev, vif, link_conf);
174 if (!mlink)
175 goto out;
176
177 dev->drv->vif_link_remove(phy, vif, link_conf, mlink);
178 mlink->ctx = NULL;
179 out:
180 mutex_unlock(&dev->mutex);
181 }
182 EXPORT_SYMBOL_GPL(mt76_unassign_vif_chanctx);
183
mt76_switch_vif_chanctx(struct ieee80211_hw * hw,struct ieee80211_vif_chanctx_switch * vifs,int n_vifs,enum ieee80211_chanctx_switch_mode mode)184 int mt76_switch_vif_chanctx(struct ieee80211_hw *hw,
185 struct ieee80211_vif_chanctx_switch *vifs,
186 int n_vifs,
187 enum ieee80211_chanctx_switch_mode mode)
188 {
189 struct ieee80211_vif_chanctx_switch *v;
190 struct mt76_chanctx *old_ctx, *new_ctx;
191 struct mt76_phy *old_phy, *phy = hw->priv;
192 struct mt76_dev *dev = phy->dev;
193 struct mt76_vif_link *mlink;
194 bool need_update[__MT_MAX_BAND] = {};
195 int i, ret = 0;
196
197 for (i = 0; i < n_vifs; i++) {
198 v = &vifs[i];
199 new_ctx = (struct mt76_chanctx *)v->new_ctx->drv_priv;
200 if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS)
201 phy = new_ctx->phy = dev->band_phys[v->new_ctx->def.chan->band];
202 else
203 phy = new_ctx->phy;
204
205 if (!phy)
206 return -EINVAL;
207
208 if (need_update[phy->band_idx])
209 continue;
210
211 if (phy->chanctx != new_ctx) {
212 if (dev->scan.phy == phy)
213 mt76_abort_scan(dev);
214
215 cancel_delayed_work_sync(&phy->mac_work);
216 need_update[phy->band_idx] = true;
217 }
218 }
219
220 mutex_lock(&dev->mutex);
221
222 for (i = 0; i < n_vifs; i++) {
223 v = &vifs[i];
224 old_ctx = (struct mt76_chanctx *)v->old_ctx->drv_priv;
225 old_phy = old_ctx->phy;
226
227 new_ctx = (struct mt76_chanctx *)v->new_ctx->drv_priv;
228 phy = new_ctx->phy;
229
230 if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS && old_phy->chanctx &&
231 old_phy->chanctx == old_ctx && phy != old_phy)
232 old_phy->chanctx = NULL;
233
234 if (need_update[phy->band_idx]) {
235 ret = mt76_phy_update_channel(phy, v->new_ctx);
236 if (ret)
237 goto out;
238
239 need_update[phy->band_idx] = false;
240 }
241
242 mlink = mt76_vif_conf_link(dev, v->vif, v->link_conf);
243 if (!mlink)
244 continue;
245
246 if (old_phy != phy) {
247 dev->drv->vif_link_remove(old_phy, v->vif, v->link_conf,
248 mlink);
249
250 ret = dev->drv->vif_link_add(phy, v->vif, v->link_conf,
251 mlink);
252 if (ret)
253 goto out;
254 }
255
256 mlink->ctx = v->new_ctx;
257 if (mlink->beacon_mon_interval)
258 WRITE_ONCE(mlink->beacon_mon_last, jiffies);
259 }
260
261 out:
262 mutex_unlock(&dev->mutex);
263
264 return ret;
265 }
266 EXPORT_SYMBOL_GPL(mt76_switch_vif_chanctx);
267
mt76_get_vif_phy_link(struct mt76_phy * phy,struct ieee80211_vif * vif)268 struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy,
269 struct ieee80211_vif *vif)
270 {
271 struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
272 struct mt76_vif_data *mvif = mlink->mvif;
273 struct mt76_dev *dev = phy->dev;
274 int i, ret;
275
276 for (i = 0; i < ARRAY_SIZE(mvif->link); i++) {
277 mlink = mt76_dereference(mvif->link[i], dev);
278 if (!mlink)
279 continue;
280
281 if (mt76_vif_link_phy(mlink) == phy)
282 return mlink;
283 }
284
285 if (!dev->drv->vif_link_add)
286 return ERR_PTR(-EINVAL);
287
288 mlink = mt76_alloc_mlink(dev, mvif);
289 if (!mlink)
290 return ERR_PTR(-ENOMEM);
291
292 mlink->offchannel = true;
293 ret = dev->drv->vif_link_add(phy, vif, &vif->bss_conf, mlink);
294 if (ret) {
295 kfree(mlink);
296 return ERR_PTR(ret);
297 }
298 rcu_assign_pointer(mvif->offchannel_link, mlink);
299
300 return mlink;
301 }
302
mt76_put_vif_phy_link(struct mt76_phy * phy,struct ieee80211_vif * vif,struct mt76_vif_link * mlink)303 void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
304 struct mt76_vif_link *mlink)
305 {
306 struct mt76_dev *dev = phy->dev;
307 struct mt76_vif_data *mvif;
308
309 if (IS_ERR_OR_NULL(mlink) || !mlink->offchannel)
310 return;
311
312 mvif = mlink->mvif;
313
314 rcu_assign_pointer(mvif->offchannel_link, NULL);
315 dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink);
316 kfree_rcu(mlink, rcu_head);
317 }
318
mt76_roc_complete(struct mt76_phy * phy)319 void mt76_roc_complete(struct mt76_phy *phy)
320 {
321 struct mt76_vif_link *mlink = phy->roc_link;
322 struct mt76_dev *dev = phy->dev;
323
324 if (!phy->roc_vif)
325 return;
326
327 if (mlink)
328 mlink->mvif->roc_phy = NULL;
329 if (phy->chanctx && phy->main_chandef.chan && phy->offchannel &&
330 !test_bit(MT76_MCU_RESET, &dev->phy.state)) {
331 __mt76_set_channel(phy, &phy->main_chandef, false);
332 mt76_offchannel_notify(phy, false);
333 }
334 mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link);
335 phy->roc_vif = NULL;
336 phy->roc_link = NULL;
337 if (!test_bit(MT76_MCU_RESET, &dev->phy.state))
338 ieee80211_remain_on_channel_expired(phy->hw);
339 }
340
mt76_roc_complete_work(struct work_struct * work)341 void mt76_roc_complete_work(struct work_struct *work)
342 {
343 struct mt76_phy *phy = container_of(work, struct mt76_phy, roc_work.work);
344 struct mt76_dev *dev = phy->dev;
345
346 mutex_lock(&dev->mutex);
347 mt76_roc_complete(phy);
348 mutex_unlock(&dev->mutex);
349 }
350
mt76_abort_roc(struct mt76_phy * phy)351 void mt76_abort_roc(struct mt76_phy *phy)
352 {
353 struct mt76_dev *dev = phy->dev;
354
355 cancel_delayed_work_sync(&phy->roc_work);
356
357 mutex_lock(&dev->mutex);
358 mt76_roc_complete(phy);
359 mutex_unlock(&dev->mutex);
360 }
361 EXPORT_SYMBOL_GPL(mt76_abort_roc);
362
mt76_remain_on_channel(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_channel * chan,int duration,enum ieee80211_roc_type type)363 int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
364 struct ieee80211_channel *chan, int duration,
365 enum ieee80211_roc_type type)
366 {
367 struct cfg80211_chan_def chandef = {};
368 struct mt76_phy *phy = hw->priv;
369 struct mt76_dev *dev = phy->dev;
370 struct mt76_vif_link *mlink;
371 bool offchannel;
372 int ret = 0;
373
374 phy = dev->band_phys[chan->band];
375 if (!phy)
376 return -EINVAL;
377
378 cancel_delayed_work_sync(&phy->mac_work);
379
380 mutex_lock(&dev->mutex);
381
382 if (phy->roc_vif || dev->scan.phy == phy ||
383 test_bit(MT76_MCU_RESET, &dev->phy.state)) {
384 ret = -EBUSY;
385 goto out;
386 }
387
388 mlink = mt76_get_vif_phy_link(phy, vif);
389 if (IS_ERR(mlink)) {
390 ret = PTR_ERR(mlink);
391 goto out;
392 }
393
394 mlink->mvif->roc_phy = phy;
395 phy->roc_vif = vif;
396 phy->roc_link = mlink;
397
398 offchannel = mt76_offchannel_chandef(phy, chan, &chandef);
399 if (offchannel)
400 mt76_offchannel_notify(phy, true);
401 ret = __mt76_set_channel(phy, &chandef, offchannel);
402 if (ret) {
403 mlink->mvif->roc_phy = NULL;
404 phy->roc_vif = NULL;
405 phy->roc_link = NULL;
406 mt76_put_vif_phy_link(phy, vif, mlink);
407 goto out;
408 }
409 ieee80211_ready_on_channel(hw);
410 ieee80211_queue_delayed_work(phy->hw, &phy->roc_work,
411 msecs_to_jiffies(duration));
412
413 out:
414 mutex_unlock(&dev->mutex);
415 return ret;
416 }
417 EXPORT_SYMBOL_GPL(mt76_remain_on_channel);
418
mt76_cancel_remain_on_channel(struct ieee80211_hw * hw,struct ieee80211_vif * vif)419 int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw,
420 struct ieee80211_vif *vif)
421 {
422 struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
423 struct mt76_vif_data *mvif = mlink->mvif;
424 struct mt76_phy *phy = mvif->roc_phy;
425
426 if (!phy)
427 return 0;
428
429 mt76_abort_roc(phy);
430
431 return 0;
432 }
433 EXPORT_SYMBOL_GPL(mt76_cancel_remain_on_channel);
434