2 * Copyright (c) 2021-2022 The FreeBSD Foundation
4 * This software was developed by Björn Zeeb under sponsorship from
5 * the FreeBSD Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/kernel.h>
35 #include <sys/errno.h>
37 #define LINUXKPI_NET80211
38 #include <net/mac80211.h>
40 #include "linux_80211.h"
42 /* Could be a different tracing framework later. */
43 #ifdef LINUXKPI_DEBUG_80211
44 #define LKPI_80211_TRACE_MO(fmt, ...) \
45 if (linuxkpi_debug_80211 & D80211_TRACE_MO) \
46 printf("LKPI_80211_TRACE_MO %s:%d: %d %d %u_" fmt "\n", \
47 __func__, __LINE__, curcpu, curthread->td_tid, \
48 (unsigned int)ticks, __VA_ARGS__)
50 #define LKPI_80211_TRACE_MO(...) do { } while(0)
54 lkpi_80211_mo_start(struct ieee80211_hw *hw)
60 if (lhw->ops->start == NULL) {
65 if ((lhw->sc_flags & LKPI_MAC80211_DRV_STARTED)) {
66 /* Trying to start twice is an error. */
70 LKPI_80211_TRACE_MO("hw %p", hw);
71 error = lhw->ops->start(hw);
73 lhw->sc_flags |= LKPI_MAC80211_DRV_STARTED;
80 lkpi_80211_mo_stop(struct ieee80211_hw *hw)
85 if (lhw->ops->stop == NULL)
88 LKPI_80211_TRACE_MO("hw %p", hw);
90 lhw->sc_flags &= ~LKPI_MAC80211_DRV_STARTED;
94 lkpi_80211_mo_get_antenna(struct ieee80211_hw *hw, u32 *txs, u32 *rxs)
100 if (lhw->ops->get_antenna == NULL) {
105 LKPI_80211_TRACE_MO("hw %p", hw);
106 error = lhw->ops->get_antenna(hw, txs, rxs);
113 lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *hw, uint32_t frag_th)
119 if (lhw->ops->set_frag_threshold == NULL) {
124 LKPI_80211_TRACE_MO("hw %p frag_th %u", hw, frag_th);
125 error = lhw->ops->set_frag_threshold(hw, frag_th);
132 lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *hw, uint32_t rts_th)
138 if (lhw->ops->set_rts_threshold == NULL) {
143 LKPI_80211_TRACE_MO("hw %p rts_th %u", hw, rts_th);
144 error = lhw->ops->set_rts_threshold(hw, rts_th);
152 lkpi_80211_mo_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
155 struct lkpi_vif *lvif;
159 if (lhw->ops->add_interface == NULL) {
164 lvif = VIF_TO_LVIF(vif);
165 LKPI_80211_LVIF_LOCK(lvif);
166 if (lvif->added_to_drv) {
167 LKPI_80211_LVIF_UNLOCK(lvif);
168 /* Trying to add twice is an error. */
172 LKPI_80211_LVIF_UNLOCK(lvif);
174 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
175 error = lhw->ops->add_interface(hw, vif);
177 LKPI_80211_LVIF_LOCK(lvif);
178 lvif->added_to_drv = true;
179 LKPI_80211_LVIF_UNLOCK(lvif);
187 lkpi_80211_mo_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
190 struct lkpi_vif *lvif;
193 if (lhw->ops->remove_interface == NULL)
196 lvif = VIF_TO_LVIF(vif);
197 LKPI_80211_LVIF_LOCK(lvif);
198 if (!lvif->added_to_drv) {
199 LKPI_80211_LVIF_UNLOCK(lvif);
202 LKPI_80211_LVIF_UNLOCK(lvif);
204 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
205 lhw->ops->remove_interface(hw, vif);
206 LKPI_80211_LVIF_LOCK(lvif);
207 lvif->added_to_drv = false;
208 LKPI_80211_LVIF_UNLOCK(lvif);
213 lkpi_80211_mo_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
214 struct ieee80211_scan_request *sr)
220 * MUST NOT return EPERM as that is a "magic number 1" based on rtw88
221 * driver indicating hw_scan is not supported despite the ops call
226 if (lhw->ops->hw_scan == NULL) {
227 /* Return magic number to use sw scan. */
232 LKPI_80211_TRACE_MO("CALLING hw %p vif %p sr %p", hw, vif, sr);
233 error = lhw->ops->hw_scan(hw, vif, sr);
234 LKPI_80211_TRACE_MO("RETURNING hw %p vif %p sr %p error %d", hw, vif, sr, error);
241 lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
246 if (lhw->ops->cancel_hw_scan == NULL)
249 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
250 lhw->ops->cancel_hw_scan(hw, vif);
254 lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
259 if (lhw->ops->sw_scan_complete == NULL)
262 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
263 lhw->ops->sw_scan_complete(hw, vif);
264 lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
268 lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
274 if (lhw->ops->sw_scan_start == NULL)
277 LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
278 lhw->ops->sw_scan_start(hw, vif, addr);
283 * We keep the Linux type here; it really is an uintptr_t.
286 lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw,
287 struct netdev_hw_addr_list *mc_list)
293 if (lhw->ops->prepare_multicast == NULL)
296 LKPI_80211_TRACE_MO("hw %p mc_list %p", hw, mc_list);
297 ptr = lhw->ops->prepare_multicast(hw, mc_list);
302 lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
303 unsigned int *total_flags, u64 mc_ptr)
308 if (lhw->ops->configure_filter == NULL)
314 LKPI_80211_TRACE_MO("hw %p changed_flags %#x total_flags %p mc_ptr %ju", hw, changed_flags, total_flags, (uintmax_t)mc_ptr);
315 lhw->ops->configure_filter(hw, changed_flags, total_flags, mc_ptr);
320 * So far we only called sta_{add,remove} as an alternative to sta_state.
321 * Let's keep the implementation simpler and hide sta_{add,remove} under the
322 * hood here calling them if state_state is not available from mo_sta_state.
325 lkpi_80211_mo_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
326 struct ieee80211_sta *sta)
329 struct lkpi_sta *lsta;
333 if (lhw->ops->sta_add == NULL) {
338 lsta = STA_TO_LSTA(sta);
339 if (lsta->added_to_drv) {
344 LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
345 error = lhw->ops->sta_add(hw, vif, sta);
347 lsta->added_to_drv = true;
354 lkpi_80211_mo_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
355 struct ieee80211_sta *sta)
358 struct lkpi_sta *lsta;
362 if (lhw->ops->sta_remove == NULL) {
367 lsta = STA_TO_LSTA(sta);
368 if (!lsta->added_to_drv) {
369 /* If we never added the sta, do not complain on cleanup. */
374 LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
375 error = lhw->ops->sta_remove(hw, vif, sta);
377 lsta->added_to_drv = false;
384 lkpi_80211_mo_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
385 struct lkpi_sta *lsta, enum ieee80211_sta_state nstate)
388 struct ieee80211_sta *sta;
392 sta = LSTA_TO_STA(lsta);
393 if (lhw->ops->sta_state != NULL) {
394 LKPI_80211_TRACE_MO("hw %p vif %p sta %p nstate %d", hw, vif, sta, nstate);
395 error = lhw->ops->sta_state(hw, vif, sta, lsta->state, nstate);
397 if (nstate == IEEE80211_STA_NOTEXIST)
398 lsta->added_to_drv = false;
400 lsta->added_to_drv = true;
401 lsta->state = nstate;
406 /* XXX-BZ is the change state AUTH or ASSOC here? */
407 if (lsta->state < IEEE80211_STA_ASSOC && nstate == IEEE80211_STA_ASSOC) {
408 error = lkpi_80211_mo_sta_add(hw, vif, sta);
410 lsta->added_to_drv = true;
411 } else if (lsta->state >= IEEE80211_STA_ASSOC &&
412 nstate < IEEE80211_STA_ASSOC) {
413 error = lkpi_80211_mo_sta_remove(hw, vif, sta);
415 lsta->added_to_drv = false;
420 lsta->state = nstate;
423 /* XXX-BZ should we manage state in here? */
428 lkpi_80211_mo_config(struct ieee80211_hw *hw, uint32_t changed)
434 if (lhw->ops->config == NULL) {
439 LKPI_80211_TRACE_MO("hw %p changed %u", hw, changed);
440 error = lhw->ops->config(hw, changed);
448 lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
449 struct ieee80211_chanctx_conf *chanctx_conf)
455 if (lhw->ops->assign_vif_chanctx == NULL) {
460 LKPI_80211_TRACE_MO("hw %p vif %p chanctx_conf %p", hw, vif, chanctx_conf);
461 error = lhw->ops->assign_vif_chanctx(hw, vif, NULL, chanctx_conf);
463 vif->chanctx_conf = chanctx_conf;
470 lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
471 struct ieee80211_chanctx_conf **chanctx_conf)
476 if (lhw->ops->unassign_vif_chanctx == NULL)
479 if (*chanctx_conf == NULL)
482 LKPI_80211_TRACE_MO("hw %p vif %p chanctx_conf %p", hw, vif, *chanctx_conf);
483 lhw->ops->unassign_vif_chanctx(hw, vif, NULL, *chanctx_conf);
484 *chanctx_conf = NULL;
489 lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw,
490 struct ieee80211_chanctx_conf *chanctx_conf)
496 if (lhw->ops->add_chanctx == NULL) {
501 LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
502 error = lhw->ops->add_chanctx(hw, chanctx_conf);
509 lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw,
510 struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed)
515 if (lhw->ops->change_chanctx == NULL)
518 LKPI_80211_TRACE_MO("hw %p chanctx_conf %p changed %u", hw, chanctx_conf, changed);
519 lhw->ops->change_chanctx(hw, chanctx_conf, changed);
523 lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw,
524 struct ieee80211_chanctx_conf *chanctx_conf)
529 if (lhw->ops->remove_chanctx == NULL)
532 LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
533 lhw->ops->remove_chanctx(hw, chanctx_conf);
537 lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
538 struct ieee80211_bss_conf *conf, uint64_t changed)
543 if (lhw->ops->bss_info_changed == NULL)
546 LKPI_80211_TRACE_MO("hw %p vif %p conf %p changed %#jx", hw, vif, conf, (uintmax_t)changed);
547 lhw->ops->bss_info_changed(hw, vif, conf, changed);
552 lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
553 uint16_t ac, const struct ieee80211_tx_queue_params *txqp)
559 if (lhw->ops->conf_tx == NULL) {
564 LKPI_80211_TRACE_MO("hw %p vif %p ac %u txpq %p", hw, vif, ac, txqp);
565 error = lhw->ops->conf_tx(hw, vif, 0, ac, txqp);
572 lkpi_80211_mo_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
573 uint32_t nqueues, bool drop)
578 if (lhw->ops->flush == NULL)
581 LKPI_80211_TRACE_MO("hw %p vif %p nqueues %u drop %d", hw, vif, nqueues, drop);
582 lhw->ops->flush(hw, vif, nqueues, drop);
586 lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
587 struct ieee80211_prep_tx_info *txinfo)
592 if (lhw->ops->mgd_prepare_tx == NULL)
595 LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
596 lhw->ops->mgd_prepare_tx(hw, vif, txinfo);
600 lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
601 struct ieee80211_prep_tx_info *txinfo)
606 if (lhw->ops->mgd_complete_tx == NULL)
609 LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
610 lhw->ops->mgd_complete_tx(hw, vif, txinfo);
614 lkpi_80211_mo_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *txctrl,
620 if (lhw->ops->tx == NULL)
623 LKPI_80211_TRACE_MO("hw %p txctrl %p skb %p", hw, txctrl, skb);
624 lhw->ops->tx(hw, txctrl, skb);
628 lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
633 if (lhw->ops->wake_tx_queue == NULL)
636 LKPI_80211_TRACE_MO("hw %p txq %p", hw, txq);
637 lhw->ops->wake_tx_queue(hw, txq);
641 lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *hw)
646 if (lhw->ops->sync_rx_queues == NULL)
649 LKPI_80211_TRACE_MO("hw %p", hw);
650 lhw->ops->sync_rx_queues(hw);
654 lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *hw,
655 struct ieee80211_vif *vif, struct ieee80211_sta *sta)
660 if (lhw->ops->sta_pre_rcu_remove == NULL)
663 LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
664 lhw->ops->sta_pre_rcu_remove(hw, vif, sta);
668 lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
669 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
670 struct ieee80211_key_conf *kc)
676 if (lhw->ops->set_key == NULL) {
681 LKPI_80211_TRACE_MO("hw %p cmd %d vif %p sta %p kc %p", hw, cmd, vif, sta, kc);
682 error = lhw->ops->set_key(hw, cmd, vif, sta, kc);