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
39586 views
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
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
error = lhw->ops->get_antenna(hw, txs, rxs);
106
107
out:
108
return (error);
109
}
110
111
int
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
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
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
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
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
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
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
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
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
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
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
error = lhw->ops->config(hw, changed);
440
441
out:
442
return (error);
443
}
444
445
446
int
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
760