Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/compat/linuxkpi/common/src/linux_80211_macops.c
102493 views
1
/*-
2
* Copyright (c) 2021-2026 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
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
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
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
LKPI_80211_TRACE_MO("TODO link/radio_idx");
106
error = lhw->ops->get_antenna(hw, 0, txs, rxs);
107
108
out:
109
return (error);
110
}
111
112
int
113
lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *hw, uint32_t frag_th)
114
{
115
struct lkpi_hw *lhw;
116
int error;
117
118
lhw = HW_TO_LHW(hw);
119
if (lhw->ops->set_frag_threshold == NULL) {
120
error = EOPNOTSUPP;
121
goto out;
122
}
123
124
LKPI_80211_TRACE_MO("hw %p frag_th %u", hw, frag_th);
125
LKPI_80211_TRACE_MO("TODO link/radio_idx");
126
error = lhw->ops->set_frag_threshold(hw, 0, frag_th);
127
128
out:
129
return (error);
130
}
131
132
int
133
lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *hw, uint32_t rts_th)
134
{
135
struct lkpi_hw *lhw;
136
int error;
137
138
lhw = HW_TO_LHW(hw);
139
if (lhw->ops->set_rts_threshold == NULL) {
140
error = EOPNOTSUPP;
141
goto out;
142
}
143
144
LKPI_80211_TRACE_MO("hw %p rts_th %u", hw, rts_th);
145
LKPI_80211_TRACE_MO("TODO link/radio_idx");
146
error = lhw->ops->set_rts_threshold(hw, 0, rts_th);
147
148
out:
149
return (error);
150
}
151
152
153
int
154
lkpi_80211_mo_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
155
{
156
struct lkpi_hw *lhw;
157
struct lkpi_vif *lvif;
158
int error;
159
160
lhw = HW_TO_LHW(hw);
161
if (lhw->ops->add_interface == NULL) {
162
error = EOPNOTSUPP;
163
goto out;
164
}
165
166
lvif = VIF_TO_LVIF(vif);
167
LKPI_80211_LVIF_LOCK(lvif);
168
if (lvif->added_to_drv) {
169
LKPI_80211_LVIF_UNLOCK(lvif);
170
/* Trying to add twice is an error. */
171
error = EEXIST;
172
goto out;
173
}
174
LKPI_80211_LVIF_UNLOCK(lvif);
175
176
LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
177
error = lhw->ops->add_interface(hw, vif);
178
if (error == 0) {
179
LKPI_80211_LVIF_LOCK(lvif);
180
lvif->added_to_drv = true;
181
LKPI_80211_LVIF_UNLOCK(lvif);
182
}
183
184
out:
185
return (error);
186
}
187
188
void
189
lkpi_80211_mo_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
190
{
191
struct lkpi_hw *lhw;
192
struct lkpi_vif *lvif;
193
194
lhw = HW_TO_LHW(hw);
195
if (lhw->ops->remove_interface == NULL)
196
return;
197
198
lvif = VIF_TO_LVIF(vif);
199
LKPI_80211_LVIF_LOCK(lvif);
200
if (!lvif->added_to_drv) {
201
LKPI_80211_LVIF_UNLOCK(lvif);
202
return;
203
}
204
LKPI_80211_LVIF_UNLOCK(lvif);
205
206
LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
207
lhw->ops->remove_interface(hw, vif);
208
LKPI_80211_LVIF_LOCK(lvif);
209
lvif->added_to_drv = false;
210
LKPI_80211_LVIF_UNLOCK(lvif);
211
}
212
213
214
int
215
lkpi_80211_mo_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
216
struct ieee80211_scan_request *sr)
217
{
218
struct lkpi_hw *lhw;
219
int error;
220
221
/*
222
* MUST NOT return EPERM as that is a "magic number 1" based on rtw88
223
* driver indicating hw_scan is not supported despite the ops call
224
* being available.
225
*/
226
227
lhw = HW_TO_LHW(hw);
228
if (lhw->ops->hw_scan == NULL) {
229
/* Return magic number to use sw scan. */
230
error = 1;
231
goto out;
232
}
233
234
LKPI_80211_TRACE_MO("CALLING hw %p vif %p sr %p", hw, vif, sr);
235
error = lhw->ops->hw_scan(hw, vif, sr);
236
LKPI_80211_TRACE_MO("RETURNING hw %p vif %p sr %p error %d", hw, vif, sr, error);
237
238
out:
239
return (error);
240
}
241
242
void
243
lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
244
{
245
struct lkpi_hw *lhw;
246
247
lhw = HW_TO_LHW(hw);
248
if (lhw->ops->cancel_hw_scan == NULL)
249
return;
250
251
LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
252
lhw->ops->cancel_hw_scan(hw, vif);
253
}
254
255
void
256
lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
257
{
258
struct lkpi_hw *lhw;
259
260
lhw = HW_TO_LHW(hw);
261
if (lhw->ops->sw_scan_complete == NULL)
262
return;
263
264
LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
265
lhw->ops->sw_scan_complete(hw, vif);
266
lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
267
}
268
269
void
270
lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
271
const u8 *addr)
272
{
273
struct lkpi_hw *lhw;
274
275
lhw = HW_TO_LHW(hw);
276
if (lhw->ops->sw_scan_start == NULL)
277
return;
278
279
LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
280
lhw->ops->sw_scan_start(hw, vif, addr);
281
}
282
283
284
/*
285
* We keep the Linux type here; it really is an uintptr_t.
286
*/
287
u64
288
lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw,
289
struct netdev_hw_addr_list *mc_list)
290
{
291
struct lkpi_hw *lhw;
292
u64 ptr;
293
294
lhw = HW_TO_LHW(hw);
295
if (lhw->ops->prepare_multicast == NULL)
296
return (0);
297
298
LKPI_80211_TRACE_MO("hw %p mc_list %p", hw, mc_list);
299
ptr = lhw->ops->prepare_multicast(hw, mc_list);
300
return (ptr);
301
}
302
303
void
304
lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
305
unsigned int *total_flags, u64 mc_ptr)
306
{
307
struct lkpi_hw *lhw;
308
309
lhw = HW_TO_LHW(hw);
310
if (lhw->ops->configure_filter == NULL)
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
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
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
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
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
LKPI_80211_TRACE_MO("TODO link/radio_idx");
440
error = lhw->ops->config(hw, 0, changed);
441
442
out:
443
return (error);
444
}
445
446
447
int
448
lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
449
struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)
450
{
451
struct lkpi_hw *lhw;
452
int error;
453
454
lhw = HW_TO_LHW(hw);
455
if (lhw->ops->assign_vif_chanctx == NULL) {
456
error = EOPNOTSUPP;
457
goto out;
458
}
459
460
LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",
461
hw, vif, conf, chanctx_conf);
462
error = lhw->ops->assign_vif_chanctx(hw, vif, conf, chanctx_conf);
463
if (error == 0)
464
vif->bss_conf.chanctx_conf = chanctx_conf;
465
466
out:
467
return (error);
468
}
469
470
void
471
lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
472
struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)
473
{
474
struct lkpi_hw *lhw;
475
476
might_sleep();
477
lockdep_assert_wiphy(hw->wiphy);
478
479
lhw = HW_TO_LHW(hw);
480
if (lhw->ops->unassign_vif_chanctx == NULL)
481
return;
482
483
if (chanctx_conf == NULL)
484
return;
485
486
LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",
487
hw, vif, conf, chanctx_conf);
488
lhw->ops->unassign_vif_chanctx(hw, vif, conf, chanctx_conf);
489
}
490
491
492
int
493
lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw,
494
struct ieee80211_chanctx_conf *chanctx_conf)
495
{
496
struct lkpi_hw *lhw;
497
struct lkpi_chanctx *lchanctx;
498
int error;
499
500
lhw = HW_TO_LHW(hw);
501
if (lhw->ops->add_chanctx == NULL) {
502
error = EOPNOTSUPP;
503
goto out;
504
}
505
506
LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
507
error = lhw->ops->add_chanctx(hw, chanctx_conf);
508
if (error == 0) {
509
lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
510
lchanctx->added_to_drv = true;
511
}
512
513
out:
514
return (error);
515
}
516
517
void
518
lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw,
519
struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed)
520
{
521
struct lkpi_hw *lhw;
522
523
lhw = HW_TO_LHW(hw);
524
if (lhw->ops->change_chanctx == NULL)
525
return;
526
527
LKPI_80211_TRACE_MO("hw %p chanctx_conf %p changed %u", hw, chanctx_conf, changed);
528
lhw->ops->change_chanctx(hw, chanctx_conf, changed);
529
}
530
531
void
532
lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw,
533
struct ieee80211_chanctx_conf *chanctx_conf)
534
{
535
struct lkpi_hw *lhw;
536
struct lkpi_chanctx *lchanctx;
537
538
lhw = HW_TO_LHW(hw);
539
if (lhw->ops->remove_chanctx == NULL)
540
return;
541
542
LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
543
lhw->ops->remove_chanctx(hw, chanctx_conf);
544
lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
545
lchanctx->added_to_drv = false;
546
}
547
548
void
549
lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
550
struct ieee80211_bss_conf *conf, uint64_t changed)
551
{
552
struct lkpi_hw *lhw;
553
554
lhw = HW_TO_LHW(hw);
555
if (lhw->ops->link_info_changed == NULL &&
556
lhw->ops->bss_info_changed == NULL)
557
return;
558
559
if (changed == 0)
560
return;
561
562
LKPI_80211_TRACE_MO("hw %p vif %p conf %p changed %#jx", hw, vif, conf, (uintmax_t)changed);
563
if (lhw->ops->link_info_changed != NULL)
564
lhw->ops->link_info_changed(hw, vif, conf, changed);
565
else
566
lhw->ops->bss_info_changed(hw, vif, conf, changed);
567
}
568
569
int
570
lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
571
uint32_t link_id, uint16_t ac, const struct ieee80211_tx_queue_params *txqp)
572
{
573
struct lkpi_hw *lhw;
574
int error;
575
576
lhw = HW_TO_LHW(hw);
577
if (lhw->ops->conf_tx == NULL) {
578
error = EOPNOTSUPP;
579
goto out;
580
}
581
582
LKPI_80211_TRACE_MO("hw %p vif %p link_id %u ac %u txpq %p",
583
hw, vif, link_id, ac, txqp);
584
error = lhw->ops->conf_tx(hw, vif, link_id, ac, txqp);
585
586
out:
587
return (error);
588
}
589
590
void
591
lkpi_80211_mo_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
592
uint32_t nqueues, bool drop)
593
{
594
struct lkpi_hw *lhw;
595
596
lhw = HW_TO_LHW(hw);
597
if (lhw->ops->flush == NULL)
598
return;
599
600
LKPI_80211_TRACE_MO("hw %p vif %p nqueues %u drop %d", hw, vif, nqueues, drop);
601
lhw->ops->flush(hw, vif, nqueues, drop);
602
}
603
604
void
605
lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
606
struct ieee80211_prep_tx_info *txinfo)
607
{
608
struct lkpi_hw *lhw;
609
610
lhw = HW_TO_LHW(hw);
611
if (lhw->ops->mgd_prepare_tx == NULL)
612
return;
613
614
LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
615
lhw->ops->mgd_prepare_tx(hw, vif, txinfo);
616
}
617
618
void
619
lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
620
struct ieee80211_prep_tx_info *txinfo)
621
{
622
struct lkpi_hw *lhw;
623
624
lhw = HW_TO_LHW(hw);
625
if (lhw->ops->mgd_complete_tx == NULL)
626
return;
627
628
LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
629
lhw->ops->mgd_complete_tx(hw, vif, txinfo);
630
}
631
632
void
633
lkpi_80211_mo_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *txctrl,
634
struct sk_buff *skb)
635
{
636
struct lkpi_hw *lhw;
637
638
lhw = HW_TO_LHW(hw);
639
if (lhw->ops->tx == NULL)
640
return;
641
642
LKPI_80211_TRACE_MO("hw %p txctrl %p skb %p", hw, txctrl, skb);
643
lhw->ops->tx(hw, txctrl, skb);
644
}
645
646
void
647
lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
648
bool schedule)
649
{
650
struct lkpi_hw *lhw;
651
652
lhw = HW_TO_LHW(hw);
653
654
/* Do the schedule before the check for wake_tx_queue supported! */
655
if (schedule)
656
ieee80211_schedule_txq(hw, txq);
657
658
if (lhw->ops->wake_tx_queue == NULL)
659
return;
660
661
LKPI_80211_TRACE_MO("hw %p txq %p", hw, txq);
662
lhw->ops->wake_tx_queue(hw, txq);
663
}
664
665
void
666
lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *hw)
667
{
668
struct lkpi_hw *lhw;
669
670
lhw = HW_TO_LHW(hw);
671
if (lhw->ops->sync_rx_queues == NULL)
672
return;
673
674
LKPI_80211_TRACE_MO("hw %p", hw);
675
lhw->ops->sync_rx_queues(hw);
676
}
677
678
void
679
lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *hw,
680
struct ieee80211_vif *vif, struct ieee80211_sta *sta)
681
{
682
struct lkpi_hw *lhw;
683
684
lhw = HW_TO_LHW(hw);
685
if (lhw->ops->sta_pre_rcu_remove == NULL)
686
return;
687
688
LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
689
lhw->ops->sta_pre_rcu_remove(hw, vif, sta);
690
}
691
692
int
693
lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
694
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
695
struct ieee80211_key_conf *kc)
696
{
697
struct lkpi_hw *lhw;
698
int error;
699
700
lockdep_assert_wiphy(hw->wiphy);
701
702
lhw = HW_TO_LHW(hw);
703
if (lhw->ops->set_key == NULL) {
704
error = EOPNOTSUPP;
705
goto out;
706
}
707
708
LKPI_80211_TRACE_MO("hw %p cmd %d vif %p sta %p kc %p", hw, cmd, vif, sta, kc);
709
error = lhw->ops->set_key(hw, cmd, vif, sta, kc);
710
711
out:
712
return (error);
713
}
714
715
int
716
lkpi_80211_mo_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
717
struct ieee80211_ampdu_params *params)
718
{
719
struct lkpi_hw *lhw;
720
int error;
721
722
lhw = HW_TO_LHW(hw);
723
if (lhw->ops->ampdu_action == NULL) {
724
error = EOPNOTSUPP;
725
goto out;
726
}
727
728
LKPI_80211_TRACE_MO("hw %p vif %p params %p { %p, %d, %u, %u, %u, %u, %d }",
729
hw, vif, params, params->sta, params->action, params->buf_size,
730
params->timeout, params->ssn, params->tid, params->amsdu);
731
error = lhw->ops->ampdu_action(hw, vif, params);
732
733
out:
734
return (error);
735
}
736
737
int
738
lkpi_80211_mo_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
739
struct ieee80211_sta *sta, struct station_info *sinfo)
740
{
741
struct lkpi_hw *lhw;
742
struct lkpi_sta *lsta;
743
int error;
744
745
lhw = HW_TO_LHW(hw);
746
if (lhw->ops->sta_statistics == NULL) {
747
error = EOPNOTSUPP;
748
goto out;
749
}
750
751
lsta = STA_TO_LSTA(sta);
752
if (!lsta->added_to_drv) {
753
error = EEXIST;
754
goto out;
755
}
756
757
lockdep_assert_wiphy(hw->wiphy);
758
759
LKPI_80211_TRACE_MO("hw %p vif %p sta %p sinfo %p", hw, vif, sta, sinfo);
760
lhw->ops->sta_statistics(hw, vif, sta, sinfo);
761
error = 0;
762
763
out:
764
return (error);
765
}
766
767