1 // SPDX-License-Identifier: ISC
2 /*
3 * Copyright (C) 2024 Felix Fietkau <[email protected]>
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 cancel_delayed_work_sync(&phy->mac_work);
92
93 mutex_lock(&dev->mutex);
94 mt76_phy_update_channel(phy, conf);
95 mutex_unlock(&dev->mutex);
96 }
97 EXPORT_SYMBOL_GPL(mt76_change_chanctx);
98
99
mt76_assign_vif_chanctx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf,struct ieee80211_chanctx_conf * conf)100 int mt76_assign_vif_chanctx(struct ieee80211_hw *hw,
101 struct ieee80211_vif *vif,
102 struct ieee80211_bss_conf *link_conf,
103 struct ieee80211_chanctx_conf *conf)
104 {
105 struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
106 struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
107 struct mt76_vif_data *mvif = mlink->mvif;
108 int link_id = link_conf->link_id;
109 struct mt76_phy *phy = ctx->phy;
110 struct mt76_dev *dev = phy->dev;
111 bool mlink_alloc = false;
112 int ret = 0;
113
114 if (dev->scan.vif == vif)
115 mt76_abort_scan(dev);
116
117 mutex_lock(&dev->mutex);
118
119 if (vif->type == NL80211_IFTYPE_MONITOR &&
120 is_zero_ether_addr(vif->addr))
121 goto out;
122
123 mlink = mt76_vif_conf_link(dev, vif, link_conf);
124 if (!mlink) {
125 mlink = mt76_alloc_mlink(dev, mvif);
126 if (!mlink) {
127 ret = -ENOMEM;
128 goto out;
129 }
130 mlink_alloc = true;
131 }
132
133 mlink->ctx = conf;
134 ret = dev->drv->vif_link_add(phy, vif, link_conf, mlink);
135 if (ret) {
136 if (mlink_alloc)
137 kfree(mlink);
138 goto out;
139 }
140
141 if (link_conf != &vif->bss_conf)
142 rcu_assign_pointer(mvif->link[link_id], mlink);
143
144 out:
145 mutex_unlock(&dev->mutex);
146
147 return ret;
148 }
149 EXPORT_SYMBOL_GPL(mt76_assign_vif_chanctx);
150
mt76_unassign_vif_chanctx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf,struct ieee80211_chanctx_conf * conf)151 void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw,
152 struct ieee80211_vif *vif,
153 struct ieee80211_bss_conf *link_conf,
154 struct ieee80211_chanctx_conf *conf)
155 {
156 struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv;
157 struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
158 struct mt76_vif_data *mvif = mlink->mvif;
159 int link_id = link_conf->link_id;
160 struct mt76_phy *phy = ctx->phy;
161 struct mt76_dev *dev = phy->dev;
162
163 if (dev->scan.vif == vif)
164 mt76_abort_scan(dev);
165
166 mutex_lock(&dev->mutex);
167
168 if (vif->type == NL80211_IFTYPE_MONITOR &&
169 is_zero_ether_addr(vif->addr))
170 goto out;
171
172 mlink = mt76_vif_conf_link(dev, vif, link_conf);
173 if (!mlink)
174 goto out;
175
176 if (link_conf != &vif->bss_conf)
177 rcu_assign_pointer(mvif->link[link_id], NULL);
178
179 dev->drv->vif_link_remove(phy, vif, link_conf, mlink);
180 mlink->ctx = NULL;
181
182 if (link_conf != &vif->bss_conf)
183 kfree_rcu(mlink, rcu_head);
184
185 out:
186 mutex_unlock(&dev->mutex);
187 }
188 EXPORT_SYMBOL_GPL(mt76_unassign_vif_chanctx);
189
mt76_switch_vif_chanctx(struct ieee80211_hw * hw,struct ieee80211_vif_chanctx_switch * vifs,int n_vifs,enum ieee80211_chanctx_switch_mode mode)190 int mt76_switch_vif_chanctx(struct ieee80211_hw *hw,
191 struct ieee80211_vif_chanctx_switch *vifs,
192 int n_vifs,
193 enum ieee80211_chanctx_switch_mode mode)
194 {
195 struct mt76_chanctx *old_ctx = (struct mt76_chanctx *)vifs->old_ctx->drv_priv;
196 struct mt76_chanctx *new_ctx = (struct mt76_chanctx *)vifs->new_ctx->drv_priv;
197 struct ieee80211_chanctx_conf *conf = vifs->new_ctx;
198 struct mt76_phy *old_phy = old_ctx->phy;
199 struct mt76_phy *phy = hw->priv;
200 struct mt76_dev *dev = phy->dev;
201 struct mt76_vif_link *mlink;
202 bool update_chan;
203 int i, ret = 0;
204
205 if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS)
206 phy = new_ctx->phy = dev->band_phys[conf->def.chan->band];
207 else
208 phy = new_ctx->phy;
209 if (!phy)
210 return -EINVAL;
211
212 update_chan = phy->chanctx != new_ctx;
213 if (update_chan) {
214 if (dev->scan.phy == phy)
215 mt76_abort_scan(dev);
216
217 cancel_delayed_work_sync(&phy->mac_work);
218 }
219
220 mutex_lock(&dev->mutex);
221
222 if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
223 phy != old_phy && old_phy->chanctx == old_ctx)
224 old_phy->chanctx = NULL;
225
226 if (update_chan)
227 ret = mt76_phy_update_channel(phy, vifs->new_ctx);
228
229 if (ret)
230 goto out;
231
232 if (old_phy == phy)
233 goto skip_link_replace;
234
235 for (i = 0; i < n_vifs; i++) {
236 mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
237 if (!mlink)
238 continue;
239
240 dev->drv->vif_link_remove(old_phy, vifs[i].vif,
241 vifs[i].link_conf, mlink);
242
243 ret = dev->drv->vif_link_add(phy, vifs[i].vif,
244 vifs[i].link_conf, mlink);
245 if (ret)
246 goto out;
247
248 }
249
250 skip_link_replace:
251 for (i = 0; i < n_vifs; i++) {
252 mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf);
253 if (!mlink)
254 continue;
255
256 mlink->ctx = vifs->new_ctx;
257 }
258
259 out:
260 mutex_unlock(&dev->mutex);
261
262 return ret;
263 }
264 EXPORT_SYMBOL_GPL(mt76_switch_vif_chanctx);
265
mt76_get_vif_phy_link(struct mt76_phy * phy,struct ieee80211_vif * vif)266 struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy,
267 struct ieee80211_vif *vif)
268 {
269 struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
270 struct mt76_vif_data *mvif = mlink->mvif;
271 struct mt76_dev *dev = phy->dev;
272 int i, ret;
273
274 for (i = 0; i < ARRAY_SIZE(mvif->link); i++) {
275 mlink = mt76_dereference(mvif->link[i], dev);
276 if (!mlink)
277 continue;
278
279 if (mt76_vif_link_phy(mlink) == phy)
280 return mlink;
281 }
282
283 if (!dev->drv->vif_link_add)
284 return ERR_PTR(-EINVAL);
285
286 mlink = mt76_alloc_mlink(dev, mvif);
287 if (!mlink)
288 return ERR_PTR(-ENOMEM);
289
290 mlink->offchannel = true;
291 ret = dev->drv->vif_link_add(phy, vif, &vif->bss_conf, mlink);
292 if (ret) {
293 kfree(mlink);
294 return ERR_PTR(ret);
295 }
296
297 return mlink;
298 }
299
mt76_put_vif_phy_link(struct mt76_phy * phy,struct ieee80211_vif * vif,struct mt76_vif_link * mlink)300 void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
301 struct mt76_vif_link *mlink)
302 {
303 struct mt76_dev *dev = phy->dev;
304
305 if (IS_ERR_OR_NULL(mlink) || !mlink->offchannel)
306 return;
307
308 dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink);
309 kfree(mlink);
310 }
311
mt76_roc_complete(struct mt76_phy * phy)312 static void mt76_roc_complete(struct mt76_phy *phy)
313 {
314 struct mt76_vif_link *mlink = phy->roc_link;
315
316 if (!phy->roc_vif)
317 return;
318
319 if (mlink)
320 mlink->mvif->roc_phy = NULL;
321 if (phy->main_chandef.chan)
322 mt76_set_channel(phy, &phy->main_chandef, false);
323 mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link);
324 phy->roc_vif = NULL;
325 phy->roc_link = NULL;
326 ieee80211_remain_on_channel_expired(phy->hw);
327 }
328
mt76_roc_complete_work(struct work_struct * work)329 void mt76_roc_complete_work(struct work_struct *work)
330 {
331 struct mt76_phy *phy = container_of(work, struct mt76_phy, roc_work.work);
332 struct mt76_dev *dev = phy->dev;
333
334 mutex_lock(&dev->mutex);
335 mt76_roc_complete(phy);
336 mutex_unlock(&dev->mutex);
337 }
338
mt76_abort_roc(struct mt76_phy * phy)339 void mt76_abort_roc(struct mt76_phy *phy)
340 {
341 struct mt76_dev *dev = phy->dev;
342
343 cancel_delayed_work_sync(&phy->roc_work);
344
345 mutex_lock(&dev->mutex);
346 mt76_roc_complete(phy);
347 mutex_unlock(&dev->mutex);
348 }
349
mt76_remain_on_channel(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_channel * chan,int duration,enum ieee80211_roc_type type)350 int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
351 struct ieee80211_channel *chan, int duration,
352 enum ieee80211_roc_type type)
353 {
354 struct cfg80211_chan_def chandef = {};
355 struct mt76_phy *phy = hw->priv;
356 struct mt76_dev *dev = phy->dev;
357 struct mt76_vif_link *mlink;
358 int ret = 0;
359
360 phy = dev->band_phys[chan->band];
361 if (!phy)
362 return -EINVAL;
363
364 mutex_lock(&dev->mutex);
365
366 if (phy->roc_vif || dev->scan.phy == phy) {
367 ret = -EBUSY;
368 goto out;
369 }
370
371 mlink = mt76_get_vif_phy_link(phy, vif);
372 if (IS_ERR(mlink)) {
373 ret = PTR_ERR(mlink);
374 goto out;
375 }
376
377 mlink->mvif->roc_phy = phy;
378 phy->roc_vif = vif;
379 phy->roc_link = mlink;
380 cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
381 mt76_set_channel(phy, &chandef, true);
382 ieee80211_ready_on_channel(hw);
383 ieee80211_queue_delayed_work(phy->hw, &phy->roc_work,
384 msecs_to_jiffies(duration));
385
386 out:
387 mutex_unlock(&dev->mutex);
388 return ret;
389 }
390 EXPORT_SYMBOL_GPL(mt76_remain_on_channel);
391
mt76_cancel_remain_on_channel(struct ieee80211_hw * hw,struct ieee80211_vif * vif)392 int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw,
393 struct ieee80211_vif *vif)
394 {
395 struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
396 struct mt76_vif_data *mvif = mlink->mvif;
397 struct mt76_phy *phy = mvif->roc_phy;
398
399 if (!phy)
400 return 0;
401
402 mt76_abort_roc(phy);
403
404 return 0;
405 }
406 EXPORT_SYMBOL_GPL(mt76_cancel_remain_on_channel);
407