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