1 /*-
2 * Copyright (c) 2021-2022 The FreeBSD Foundation
3 *
4 * This software was developed by Björn Zeeb under sponsorship from
5 * the FreeBSD Foundation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/kernel.h>
32 #include <sys/errno.h>
33
34 #define LINUXKPI_NET80211
35 #include <net/mac80211.h>
36
37 #include "linux_80211.h"
38
39 /* Could be a different tracing framework later. */
40 #ifdef LINUXKPI_DEBUG_80211
41 #define LKPI_80211_TRACE_MO(fmt, ...) \
42 if (linuxkpi_debug_80211 & D80211_TRACE_MO) \
43 printf("LKPI_80211_TRACE_MO %s:%d: %d %d %lu: " fmt "\n", \
44 __func__, __LINE__, curcpu, curthread->td_tid, \
45 jiffies, __VA_ARGS__)
46 #else
47 #define LKPI_80211_TRACE_MO(...) do { } while(0)
48 #endif
49
50 int
lkpi_80211_mo_start(struct ieee80211_hw * hw)51 lkpi_80211_mo_start(struct ieee80211_hw *hw)
52 {
53 struct lkpi_hw *lhw;
54 int error;
55
56 lockdep_assert_wiphy(hw->wiphy);
57
58 lhw = HW_TO_LHW(hw);
59 if (lhw->ops->start == NULL) {
60 error = EOPNOTSUPP;
61 goto out;
62 }
63
64 if ((lhw->sc_flags & LKPI_MAC80211_DRV_STARTED)) {
65 /* Trying to start twice is an error. */
66 error = EEXIST;
67 goto out;
68 }
69 LKPI_80211_TRACE_MO("hw %p", hw);
70 error = lhw->ops->start(hw);
71 if (error == 0)
72 lhw->sc_flags |= LKPI_MAC80211_DRV_STARTED;
73
74 out:
75 return (error);
76 }
77
78 void
lkpi_80211_mo_stop(struct ieee80211_hw * hw,bool suspend)79 lkpi_80211_mo_stop(struct ieee80211_hw *hw, bool suspend)
80 {
81 struct lkpi_hw *lhw;
82
83 lhw = HW_TO_LHW(hw);
84 if (lhw->ops->stop == NULL)
85 return;
86
87 LKPI_80211_TRACE_MO("hw %p suspend %d", hw, suspend);
88 lhw->ops->stop(hw, suspend);
89 lhw->sc_flags &= ~LKPI_MAC80211_DRV_STARTED;
90 }
91
92 int
lkpi_80211_mo_get_antenna(struct ieee80211_hw * hw,u32 * txs,u32 * rxs)93 lkpi_80211_mo_get_antenna(struct ieee80211_hw *hw, u32 *txs, u32 *rxs)
94 {
95 struct lkpi_hw *lhw;
96 int error;
97
98 lhw = HW_TO_LHW(hw);
99 if (lhw->ops->get_antenna == NULL) {
100 error = EOPNOTSUPP;
101 goto out;
102 }
103
104 LKPI_80211_TRACE_MO("hw %p", hw);
105 error = lhw->ops->get_antenna(hw, txs, rxs);
106
107 out:
108 return (error);
109 }
110
111 int
lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw * hw,uint32_t frag_th)112 lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *hw, uint32_t frag_th)
113 {
114 struct lkpi_hw *lhw;
115 int error;
116
117 lhw = HW_TO_LHW(hw);
118 if (lhw->ops->set_frag_threshold == NULL) {
119 error = EOPNOTSUPP;
120 goto out;
121 }
122
123 LKPI_80211_TRACE_MO("hw %p frag_th %u", hw, frag_th);
124 error = lhw->ops->set_frag_threshold(hw, frag_th);
125
126 out:
127 return (error);
128 }
129
130 int
lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw * hw,uint32_t rts_th)131 lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *hw, uint32_t rts_th)
132 {
133 struct lkpi_hw *lhw;
134 int error;
135
136 lhw = HW_TO_LHW(hw);
137 if (lhw->ops->set_rts_threshold == NULL) {
138 error = EOPNOTSUPP;
139 goto out;
140 }
141
142 LKPI_80211_TRACE_MO("hw %p rts_th %u", hw, rts_th);
143 error = lhw->ops->set_rts_threshold(hw, rts_th);
144
145 out:
146 return (error);
147 }
148
149
150 int
lkpi_80211_mo_add_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)151 lkpi_80211_mo_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
152 {
153 struct lkpi_hw *lhw;
154 struct lkpi_vif *lvif;
155 int error;
156
157 lhw = HW_TO_LHW(hw);
158 if (lhw->ops->add_interface == NULL) {
159 error = EOPNOTSUPP;
160 goto out;
161 }
162
163 lvif = VIF_TO_LVIF(vif);
164 LKPI_80211_LVIF_LOCK(lvif);
165 if (lvif->added_to_drv) {
166 LKPI_80211_LVIF_UNLOCK(lvif);
167 /* Trying to add twice is an error. */
168 error = EEXIST;
169 goto out;
170 }
171 LKPI_80211_LVIF_UNLOCK(lvif);
172
173 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
174 error = lhw->ops->add_interface(hw, vif);
175 if (error == 0) {
176 LKPI_80211_LVIF_LOCK(lvif);
177 lvif->added_to_drv = true;
178 LKPI_80211_LVIF_UNLOCK(lvif);
179 }
180
181 out:
182 return (error);
183 }
184
185 void
lkpi_80211_mo_remove_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)186 lkpi_80211_mo_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
187 {
188 struct lkpi_hw *lhw;
189 struct lkpi_vif *lvif;
190
191 lhw = HW_TO_LHW(hw);
192 if (lhw->ops->remove_interface == NULL)
193 return;
194
195 lvif = VIF_TO_LVIF(vif);
196 LKPI_80211_LVIF_LOCK(lvif);
197 if (!lvif->added_to_drv) {
198 LKPI_80211_LVIF_UNLOCK(lvif);
199 return;
200 }
201 LKPI_80211_LVIF_UNLOCK(lvif);
202
203 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
204 lhw->ops->remove_interface(hw, vif);
205 LKPI_80211_LVIF_LOCK(lvif);
206 lvif->added_to_drv = false;
207 LKPI_80211_LVIF_UNLOCK(lvif);
208 }
209
210
211 int
lkpi_80211_mo_hw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_scan_request * sr)212 lkpi_80211_mo_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
213 struct ieee80211_scan_request *sr)
214 {
215 struct lkpi_hw *lhw;
216 int error;
217
218 /*
219 * MUST NOT return EPERM as that is a "magic number 1" based on rtw88
220 * driver indicating hw_scan is not supported despite the ops call
221 * being available.
222 */
223
224 lhw = HW_TO_LHW(hw);
225 if (lhw->ops->hw_scan == NULL) {
226 /* Return magic number to use sw scan. */
227 error = 1;
228 goto out;
229 }
230
231 LKPI_80211_TRACE_MO("CALLING hw %p vif %p sr %p", hw, vif, sr);
232 error = lhw->ops->hw_scan(hw, vif, sr);
233 LKPI_80211_TRACE_MO("RETURNING hw %p vif %p sr %p error %d", hw, vif, sr, error);
234
235 out:
236 return (error);
237 }
238
239 void
lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif)240 lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
241 {
242 struct lkpi_hw *lhw;
243
244 lhw = HW_TO_LHW(hw);
245 if (lhw->ops->cancel_hw_scan == NULL)
246 return;
247
248 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
249 lhw->ops->cancel_hw_scan(hw, vif);
250 }
251
252 void
lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw * hw,struct ieee80211_vif * vif)253 lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
254 {
255 struct lkpi_hw *lhw;
256
257 lhw = HW_TO_LHW(hw);
258 if (lhw->ops->sw_scan_complete == NULL)
259 return;
260
261 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
262 lhw->ops->sw_scan_complete(hw, vif);
263 lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
264 }
265
266 void
lkpi_80211_mo_sw_scan_start(struct ieee80211_hw * hw,struct ieee80211_vif * vif,const u8 * addr)267 lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
268 const u8 *addr)
269 {
270 struct lkpi_hw *lhw;
271
272 lhw = HW_TO_LHW(hw);
273 if (lhw->ops->sw_scan_start == NULL)
274 return;
275
276 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
277 lhw->ops->sw_scan_start(hw, vif, addr);
278 }
279
280
281 /*
282 * We keep the Linux type here; it really is an uintptr_t.
283 */
284 u64
lkpi_80211_mo_prepare_multicast(struct ieee80211_hw * hw,struct netdev_hw_addr_list * mc_list)285 lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw,
286 struct netdev_hw_addr_list *mc_list)
287 {
288 struct lkpi_hw *lhw;
289 u64 ptr;
290
291 lhw = HW_TO_LHW(hw);
292 if (lhw->ops->prepare_multicast == NULL)
293 return (0);
294
295 LKPI_80211_TRACE_MO("hw %p mc_list %p", hw, mc_list);
296 ptr = lhw->ops->prepare_multicast(hw, mc_list);
297 return (ptr);
298 }
299
300 void
lkpi_80211_mo_configure_filter(struct ieee80211_hw * hw,unsigned int changed_flags,unsigned int * total_flags,u64 mc_ptr)301 lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
302 unsigned int *total_flags, u64 mc_ptr)
303 {
304 struct lkpi_hw *lhw;
305
306 lhw = HW_TO_LHW(hw);
307 if (lhw->ops->configure_filter == NULL)
308 return;
309
310 if (mc_ptr == 0)
311 return;
312
313 LKPI_80211_TRACE_MO("hw %p changed_flags %#x total_flags %p mc_ptr %ju", hw, changed_flags, total_flags, (uintmax_t)mc_ptr);
314 lhw->ops->configure_filter(hw, changed_flags, total_flags, mc_ptr);
315 }
316
317
318 /*
319 * So far we only called sta_{add,remove} as an alternative to sta_state.
320 * Let's keep the implementation simpler and hide sta_{add,remove} under the
321 * hood here calling them if state_state is not available from mo_sta_state.
322 */
323 static int
lkpi_80211_mo_sta_add(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)324 lkpi_80211_mo_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
325 struct ieee80211_sta *sta)
326 {
327 struct lkpi_hw *lhw;
328 struct lkpi_sta *lsta;
329 int error;
330
331 lhw = HW_TO_LHW(hw);
332 if (lhw->ops->sta_add == NULL) {
333 error = EOPNOTSUPP;
334 goto out;
335 }
336
337 lsta = STA_TO_LSTA(sta);
338 if (lsta->added_to_drv) {
339 error = EEXIST;
340 goto out;
341 }
342
343 LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
344 error = lhw->ops->sta_add(hw, vif, sta);
345 if (error == 0)
346 lsta->added_to_drv = true;
347
348 out:
349 return error;
350 }
351
352 static int
lkpi_80211_mo_sta_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)353 lkpi_80211_mo_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
354 struct ieee80211_sta *sta)
355 {
356 struct lkpi_hw *lhw;
357 struct lkpi_sta *lsta;
358 int error;
359
360 lhw = HW_TO_LHW(hw);
361 if (lhw->ops->sta_remove == NULL) {
362 error = EOPNOTSUPP;
363 goto out;
364 }
365
366 lsta = STA_TO_LSTA(sta);
367 if (!lsta->added_to_drv) {
368 /* If we never added the sta, do not complain on cleanup. */
369 error = 0;
370 goto out;
371 }
372
373 LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
374 error = lhw->ops->sta_remove(hw, vif, sta);
375 if (error == 0)
376 lsta->added_to_drv = false;
377
378 out:
379 return error;
380 }
381
382 int
lkpi_80211_mo_sta_state(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct lkpi_sta * lsta,enum ieee80211_sta_state nstate)383 lkpi_80211_mo_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
384 struct lkpi_sta *lsta, enum ieee80211_sta_state nstate)
385 {
386 struct lkpi_hw *lhw;
387 struct ieee80211_sta *sta;
388 int error;
389
390 lhw = HW_TO_LHW(hw);
391 sta = LSTA_TO_STA(lsta);
392 if (lhw->ops->sta_state != NULL) {
393 LKPI_80211_TRACE_MO("hw %p vif %p sta %p nstate %d", hw, vif, sta, nstate);
394 error = lhw->ops->sta_state(hw, vif, sta, lsta->state, nstate);
395 if (error == 0) {
396 if (nstate == IEEE80211_STA_NOTEXIST)
397 lsta->added_to_drv = false;
398 else
399 lsta->added_to_drv = true;
400 lsta->state = nstate;
401 }
402 goto out;
403 }
404
405 /* XXX-BZ is the change state AUTH or ASSOC here? */
406 if (lsta->state < IEEE80211_STA_ASSOC && nstate == IEEE80211_STA_ASSOC) {
407 error = lkpi_80211_mo_sta_add(hw, vif, sta);
408 if (error == 0)
409 lsta->added_to_drv = true;
410 } else if (lsta->state >= IEEE80211_STA_ASSOC &&
411 nstate < IEEE80211_STA_ASSOC) {
412 error = lkpi_80211_mo_sta_remove(hw, vif, sta);
413 if (error == 0)
414 lsta->added_to_drv = false;
415 } else
416 /* Nothing to do. */
417 error = 0;
418 if (error == 0)
419 lsta->state = nstate;
420
421 out:
422 /* XXX-BZ should we manage state in here? */
423 return (error);
424 }
425
426 int
lkpi_80211_mo_config(struct ieee80211_hw * hw,uint32_t changed)427 lkpi_80211_mo_config(struct ieee80211_hw *hw, uint32_t changed)
428 {
429 struct lkpi_hw *lhw;
430 int error;
431
432 lhw = HW_TO_LHW(hw);
433 if (lhw->ops->config == NULL) {
434 error = EOPNOTSUPP;
435 goto out;
436 }
437
438 LKPI_80211_TRACE_MO("hw %p changed %u", hw, changed);
439 error = lhw->ops->config(hw, changed);
440
441 out:
442 return (error);
443 }
444
445
446 int
lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * conf,struct ieee80211_chanctx_conf * chanctx_conf)447 lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
448 struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)
449 {
450 struct lkpi_hw *lhw;
451 int error;
452
453 lhw = HW_TO_LHW(hw);
454 if (lhw->ops->assign_vif_chanctx == NULL) {
455 error = EOPNOTSUPP;
456 goto out;
457 }
458
459 LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",
460 hw, vif, conf, chanctx_conf);
461 error = lhw->ops->assign_vif_chanctx(hw, vif, conf, chanctx_conf);
462 if (error == 0)
463 vif->bss_conf.chanctx_conf = chanctx_conf;
464
465 out:
466 return (error);
467 }
468
469 void
lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * conf,struct ieee80211_chanctx_conf * chanctx_conf)470 lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
471 struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)
472 {
473 struct lkpi_hw *lhw;
474
475 might_sleep();
476 lockdep_assert_wiphy(hw->wiphy);
477
478 lhw = HW_TO_LHW(hw);
479 if (lhw->ops->unassign_vif_chanctx == NULL)
480 return;
481
482 if (chanctx_conf == NULL)
483 return;
484
485 LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",
486 hw, vif, conf, chanctx_conf);
487 lhw->ops->unassign_vif_chanctx(hw, vif, conf, chanctx_conf);
488 }
489
490
491 int
lkpi_80211_mo_add_chanctx(struct ieee80211_hw * hw,struct ieee80211_chanctx_conf * chanctx_conf)492 lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw,
493 struct ieee80211_chanctx_conf *chanctx_conf)
494 {
495 struct lkpi_hw *lhw;
496 struct lkpi_chanctx *lchanctx;
497 int error;
498
499 lhw = HW_TO_LHW(hw);
500 if (lhw->ops->add_chanctx == NULL) {
501 error = EOPNOTSUPP;
502 goto out;
503 }
504
505 LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
506 error = lhw->ops->add_chanctx(hw, chanctx_conf);
507 if (error == 0) {
508 lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
509 lchanctx->added_to_drv = true;
510 }
511
512 out:
513 return (error);
514 }
515
516 void
lkpi_80211_mo_change_chanctx(struct ieee80211_hw * hw,struct ieee80211_chanctx_conf * chanctx_conf,uint32_t changed)517 lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw,
518 struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed)
519 {
520 struct lkpi_hw *lhw;
521
522 lhw = HW_TO_LHW(hw);
523 if (lhw->ops->change_chanctx == NULL)
524 return;
525
526 LKPI_80211_TRACE_MO("hw %p chanctx_conf %p changed %u", hw, chanctx_conf, changed);
527 lhw->ops->change_chanctx(hw, chanctx_conf, changed);
528 }
529
530 void
lkpi_80211_mo_remove_chanctx(struct ieee80211_hw * hw,struct ieee80211_chanctx_conf * chanctx_conf)531 lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw,
532 struct ieee80211_chanctx_conf *chanctx_conf)
533 {
534 struct lkpi_hw *lhw;
535 struct lkpi_chanctx *lchanctx;
536
537 lhw = HW_TO_LHW(hw);
538 if (lhw->ops->remove_chanctx == NULL)
539 return;
540
541 LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
542 lhw->ops->remove_chanctx(hw, chanctx_conf);
543 lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
544 lchanctx->added_to_drv = false;
545 }
546
547 void
lkpi_80211_mo_bss_info_changed(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * conf,uint64_t changed)548 lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
549 struct ieee80211_bss_conf *conf, uint64_t changed)
550 {
551 struct lkpi_hw *lhw;
552
553 lhw = HW_TO_LHW(hw);
554 if (lhw->ops->link_info_changed == NULL &&
555 lhw->ops->bss_info_changed == NULL)
556 return;
557
558 if (changed == 0)
559 return;
560
561 LKPI_80211_TRACE_MO("hw %p vif %p conf %p changed %#jx", hw, vif, conf, (uintmax_t)changed);
562 if (lhw->ops->link_info_changed != NULL)
563 lhw->ops->link_info_changed(hw, vif, conf, changed);
564 else
565 lhw->ops->bss_info_changed(hw, vif, conf, changed);
566 }
567
568 int
lkpi_80211_mo_conf_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,uint32_t link_id,uint16_t ac,const struct ieee80211_tx_queue_params * txqp)569 lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
570 uint32_t link_id, uint16_t ac, const struct ieee80211_tx_queue_params *txqp)
571 {
572 struct lkpi_hw *lhw;
573 int error;
574
575 lhw = HW_TO_LHW(hw);
576 if (lhw->ops->conf_tx == NULL) {
577 error = EOPNOTSUPP;
578 goto out;
579 }
580
581 LKPI_80211_TRACE_MO("hw %p vif %p link_id %u ac %u txpq %p",
582 hw, vif, link_id, ac, txqp);
583 error = lhw->ops->conf_tx(hw, vif, link_id, ac, txqp);
584
585 out:
586 return (error);
587 }
588
589 void
lkpi_80211_mo_flush(struct ieee80211_hw * hw,struct ieee80211_vif * vif,uint32_t nqueues,bool drop)590 lkpi_80211_mo_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
591 uint32_t nqueues, bool drop)
592 {
593 struct lkpi_hw *lhw;
594
595 lhw = HW_TO_LHW(hw);
596 if (lhw->ops->flush == NULL)
597 return;
598
599 LKPI_80211_TRACE_MO("hw %p vif %p nqueues %u drop %d", hw, vif, nqueues, drop);
600 lhw->ops->flush(hw, vif, nqueues, drop);
601 }
602
603 void
lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_prep_tx_info * txinfo)604 lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
605 struct ieee80211_prep_tx_info *txinfo)
606 {
607 struct lkpi_hw *lhw;
608
609 lhw = HW_TO_LHW(hw);
610 if (lhw->ops->mgd_prepare_tx == NULL)
611 return;
612
613 LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
614 lhw->ops->mgd_prepare_tx(hw, vif, txinfo);
615 }
616
617 void
lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_prep_tx_info * txinfo)618 lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
619 struct ieee80211_prep_tx_info *txinfo)
620 {
621 struct lkpi_hw *lhw;
622
623 lhw = HW_TO_LHW(hw);
624 if (lhw->ops->mgd_complete_tx == NULL)
625 return;
626
627 LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
628 lhw->ops->mgd_complete_tx(hw, vif, txinfo);
629 }
630
631 void
lkpi_80211_mo_tx(struct ieee80211_hw * hw,struct ieee80211_tx_control * txctrl,struct sk_buff * skb)632 lkpi_80211_mo_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *txctrl,
633 struct sk_buff *skb)
634 {
635 struct lkpi_hw *lhw;
636
637 lhw = HW_TO_LHW(hw);
638 if (lhw->ops->tx == NULL)
639 return;
640
641 LKPI_80211_TRACE_MO("hw %p txctrl %p skb %p", hw, txctrl, skb);
642 lhw->ops->tx(hw, txctrl, skb);
643 }
644
645 void
lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw * hw,struct ieee80211_txq * txq)646 lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
647 {
648 struct lkpi_hw *lhw;
649
650 lhw = HW_TO_LHW(hw);
651 if (lhw->ops->wake_tx_queue == NULL)
652 return;
653
654 LKPI_80211_TRACE_MO("hw %p txq %p", hw, txq);
655 lhw->ops->wake_tx_queue(hw, txq);
656 }
657
658 void
lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw * hw)659 lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *hw)
660 {
661 struct lkpi_hw *lhw;
662
663 lhw = HW_TO_LHW(hw);
664 if (lhw->ops->sync_rx_queues == NULL)
665 return;
666
667 LKPI_80211_TRACE_MO("hw %p", hw);
668 lhw->ops->sync_rx_queues(hw);
669 }
670
671 void
lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)672 lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *hw,
673 struct ieee80211_vif *vif, struct ieee80211_sta *sta)
674 {
675 struct lkpi_hw *lhw;
676
677 lhw = HW_TO_LHW(hw);
678 if (lhw->ops->sta_pre_rcu_remove == NULL)
679 return;
680
681 LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
682 lhw->ops->sta_pre_rcu_remove(hw, vif, sta);
683 }
684
685 int
lkpi_80211_mo_set_key(struct ieee80211_hw * hw,enum set_key_cmd cmd,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * kc)686 lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
687 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
688 struct ieee80211_key_conf *kc)
689 {
690 struct lkpi_hw *lhw;
691 int error;
692
693 lockdep_assert_wiphy(hw->wiphy);
694
695 lhw = HW_TO_LHW(hw);
696 if (lhw->ops->set_key == NULL) {
697 error = EOPNOTSUPP;
698 goto out;
699 }
700
701 LKPI_80211_TRACE_MO("hw %p cmd %d vif %p sta %p kc %p", hw, cmd, vif, sta, kc);
702 error = lhw->ops->set_key(hw, cmd, vif, sta, kc);
703
704 out:
705 return (error);
706 }
707
708 int
lkpi_80211_mo_ampdu_action(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_ampdu_params * params)709 lkpi_80211_mo_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
710 struct ieee80211_ampdu_params *params)
711 {
712 struct lkpi_hw *lhw;
713 int error;
714
715 lhw = HW_TO_LHW(hw);
716 if (lhw->ops->ampdu_action == NULL) {
717 error = EOPNOTSUPP;
718 goto out;
719 }
720
721 LKPI_80211_TRACE_MO("hw %p vif %p params %p { %p, %d, %u, %u, %u, %u, %d }",
722 hw, vif, params, params->sta, params->action, params->buf_size,
723 params->timeout, params->ssn, params->tid, params->amsdu);
724 error = lhw->ops->ampdu_action(hw, vif, params);
725
726 out:
727 return (error);
728 }
729
730 int
lkpi_80211_mo_sta_statistics(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct station_info * sinfo)731 lkpi_80211_mo_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
732 struct ieee80211_sta *sta, struct station_info *sinfo)
733 {
734 struct lkpi_hw *lhw;
735 struct lkpi_sta *lsta;
736 int error;
737
738 lhw = HW_TO_LHW(hw);
739 if (lhw->ops->sta_statistics == NULL) {
740 error = EOPNOTSUPP;
741 goto out;
742 }
743
744 lsta = STA_TO_LSTA(sta);
745 if (!lsta->added_to_drv) {
746 error = EEXIST;
747 goto out;
748 }
749
750 lockdep_assert_wiphy(hw->wiphy);
751
752 LKPI_80211_TRACE_MO("hw %p vif %p sta %p sinfo %p", hw, vif, sta, sinfo);
753 lhw->ops->sta_statistics(hw, vif, sta, sinfo);
754 error = 0;
755
756 out:
757 return (error);
758 }
759