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