Path: blob/main/sys/compat/linuxkpi/common/src/linux_80211_macops.c
39586 views
/*-1* Copyright (c) 2021-2022 The FreeBSD Foundation2*3* This software was developed by Björn Zeeb under sponsorship from4* the FreeBSD Foundation.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/param.h>29#include <sys/types.h>30#include <sys/kernel.h>31#include <sys/errno.h>3233#define LINUXKPI_NET8021134#include <net/mac80211.h>3536#include "linux_80211.h"3738/* Could be a different tracing framework later. */39#ifdef LINUXKPI_DEBUG_8021140#define LKPI_80211_TRACE_MO(fmt, ...) \41if (linuxkpi_debug_80211 & D80211_TRACE_MO) \42printf("LKPI_80211_TRACE_MO %s:%d: %d %d %lu: " fmt "\n", \43__func__, __LINE__, curcpu, curthread->td_tid, \44jiffies, __VA_ARGS__)45#else46#define LKPI_80211_TRACE_MO(...) do { } while(0)47#endif4849int50lkpi_80211_mo_start(struct ieee80211_hw *hw)51{52struct lkpi_hw *lhw;53int error;5455lockdep_assert_wiphy(hw->wiphy);5657lhw = HW_TO_LHW(hw);58if (lhw->ops->start == NULL) {59error = EOPNOTSUPP;60goto out;61}6263if ((lhw->sc_flags & LKPI_MAC80211_DRV_STARTED)) {64/* Trying to start twice is an error. */65error = EEXIST;66goto out;67}68LKPI_80211_TRACE_MO("hw %p", hw);69error = lhw->ops->start(hw);70if (error == 0)71lhw->sc_flags |= LKPI_MAC80211_DRV_STARTED;7273out:74return (error);75}7677void78lkpi_80211_mo_stop(struct ieee80211_hw *hw, bool suspend)79{80struct lkpi_hw *lhw;8182lhw = HW_TO_LHW(hw);83if (lhw->ops->stop == NULL)84return;8586LKPI_80211_TRACE_MO("hw %p suspend %d", hw, suspend);87lhw->ops->stop(hw, suspend);88lhw->sc_flags &= ~LKPI_MAC80211_DRV_STARTED;89}9091int92lkpi_80211_mo_get_antenna(struct ieee80211_hw *hw, u32 *txs, u32 *rxs)93{94struct lkpi_hw *lhw;95int error;9697lhw = HW_TO_LHW(hw);98if (lhw->ops->get_antenna == NULL) {99error = EOPNOTSUPP;100goto out;101}102103LKPI_80211_TRACE_MO("hw %p", hw);104error = lhw->ops->get_antenna(hw, txs, rxs);105106out:107return (error);108}109110int111lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *hw, uint32_t frag_th)112{113struct lkpi_hw *lhw;114int error;115116lhw = HW_TO_LHW(hw);117if (lhw->ops->set_frag_threshold == NULL) {118error = EOPNOTSUPP;119goto out;120}121122LKPI_80211_TRACE_MO("hw %p frag_th %u", hw, frag_th);123error = lhw->ops->set_frag_threshold(hw, frag_th);124125out:126return (error);127}128129int130lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *hw, uint32_t rts_th)131{132struct lkpi_hw *lhw;133int error;134135lhw = HW_TO_LHW(hw);136if (lhw->ops->set_rts_threshold == NULL) {137error = EOPNOTSUPP;138goto out;139}140141LKPI_80211_TRACE_MO("hw %p rts_th %u", hw, rts_th);142error = lhw->ops->set_rts_threshold(hw, rts_th);143144out:145return (error);146}147148149int150lkpi_80211_mo_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)151{152struct lkpi_hw *lhw;153struct lkpi_vif *lvif;154int error;155156lhw = HW_TO_LHW(hw);157if (lhw->ops->add_interface == NULL) {158error = EOPNOTSUPP;159goto out;160}161162lvif = VIF_TO_LVIF(vif);163LKPI_80211_LVIF_LOCK(lvif);164if (lvif->added_to_drv) {165LKPI_80211_LVIF_UNLOCK(lvif);166/* Trying to add twice is an error. */167error = EEXIST;168goto out;169}170LKPI_80211_LVIF_UNLOCK(lvif);171172LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);173error = lhw->ops->add_interface(hw, vif);174if (error == 0) {175LKPI_80211_LVIF_LOCK(lvif);176lvif->added_to_drv = true;177LKPI_80211_LVIF_UNLOCK(lvif);178}179180out:181return (error);182}183184void185lkpi_80211_mo_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)186{187struct lkpi_hw *lhw;188struct lkpi_vif *lvif;189190lhw = HW_TO_LHW(hw);191if (lhw->ops->remove_interface == NULL)192return;193194lvif = VIF_TO_LVIF(vif);195LKPI_80211_LVIF_LOCK(lvif);196if (!lvif->added_to_drv) {197LKPI_80211_LVIF_UNLOCK(lvif);198return;199}200LKPI_80211_LVIF_UNLOCK(lvif);201202LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);203lhw->ops->remove_interface(hw, vif);204LKPI_80211_LVIF_LOCK(lvif);205lvif->added_to_drv = false;206LKPI_80211_LVIF_UNLOCK(lvif);207}208209210int211lkpi_80211_mo_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,212struct ieee80211_scan_request *sr)213{214struct lkpi_hw *lhw;215int error;216217/*218* MUST NOT return EPERM as that is a "magic number 1" based on rtw88219* driver indicating hw_scan is not supported despite the ops call220* being available.221*/222223lhw = HW_TO_LHW(hw);224if (lhw->ops->hw_scan == NULL) {225/* Return magic number to use sw scan. */226error = 1;227goto out;228}229230LKPI_80211_TRACE_MO("CALLING hw %p vif %p sr %p", hw, vif, sr);231error = lhw->ops->hw_scan(hw, vif, sr);232LKPI_80211_TRACE_MO("RETURNING hw %p vif %p sr %p error %d", hw, vif, sr, error);233234out:235return (error);236}237238void239lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)240{241struct lkpi_hw *lhw;242243lhw = HW_TO_LHW(hw);244if (lhw->ops->cancel_hw_scan == NULL)245return;246247LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);248lhw->ops->cancel_hw_scan(hw, vif);249}250251void252lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)253{254struct lkpi_hw *lhw;255256lhw = HW_TO_LHW(hw);257if (lhw->ops->sw_scan_complete == NULL)258return;259260LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);261lhw->ops->sw_scan_complete(hw, vif);262lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;263}264265void266lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,267const u8 *addr)268{269struct lkpi_hw *lhw;270271lhw = HW_TO_LHW(hw);272if (lhw->ops->sw_scan_start == NULL)273return;274275LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);276lhw->ops->sw_scan_start(hw, vif, addr);277}278279280/*281* We keep the Linux type here; it really is an uintptr_t.282*/283u64284lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw,285struct netdev_hw_addr_list *mc_list)286{287struct lkpi_hw *lhw;288u64 ptr;289290lhw = HW_TO_LHW(hw);291if (lhw->ops->prepare_multicast == NULL)292return (0);293294LKPI_80211_TRACE_MO("hw %p mc_list %p", hw, mc_list);295ptr = lhw->ops->prepare_multicast(hw, mc_list);296return (ptr);297}298299void300lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,301unsigned int *total_flags, u64 mc_ptr)302{303struct lkpi_hw *lhw;304305lhw = HW_TO_LHW(hw);306if (lhw->ops->configure_filter == NULL)307return;308309if (mc_ptr == 0)310return;311312LKPI_80211_TRACE_MO("hw %p changed_flags %#x total_flags %p mc_ptr %ju", hw, changed_flags, total_flags, (uintmax_t)mc_ptr);313lhw->ops->configure_filter(hw, changed_flags, total_flags, mc_ptr);314}315316317/*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 the320* hood here calling them if state_state is not available from mo_sta_state.321*/322static int323lkpi_80211_mo_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,324struct ieee80211_sta *sta)325{326struct lkpi_hw *lhw;327struct lkpi_sta *lsta;328int error;329330lhw = HW_TO_LHW(hw);331if (lhw->ops->sta_add == NULL) {332error = EOPNOTSUPP;333goto out;334}335336lsta = STA_TO_LSTA(sta);337if (lsta->added_to_drv) {338error = EEXIST;339goto out;340}341342LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);343error = lhw->ops->sta_add(hw, vif, sta);344if (error == 0)345lsta->added_to_drv = true;346347out:348return error;349}350351static int352lkpi_80211_mo_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,353struct ieee80211_sta *sta)354{355struct lkpi_hw *lhw;356struct lkpi_sta *lsta;357int error;358359lhw = HW_TO_LHW(hw);360if (lhw->ops->sta_remove == NULL) {361error = EOPNOTSUPP;362goto out;363}364365lsta = STA_TO_LSTA(sta);366if (!lsta->added_to_drv) {367/* If we never added the sta, do not complain on cleanup. */368error = 0;369goto out;370}371372LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);373error = lhw->ops->sta_remove(hw, vif, sta);374if (error == 0)375lsta->added_to_drv = false;376377out:378return error;379}380381int382lkpi_80211_mo_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,383struct lkpi_sta *lsta, enum ieee80211_sta_state nstate)384{385struct lkpi_hw *lhw;386struct ieee80211_sta *sta;387int error;388389lhw = HW_TO_LHW(hw);390sta = LSTA_TO_STA(lsta);391if (lhw->ops->sta_state != NULL) {392LKPI_80211_TRACE_MO("hw %p vif %p sta %p nstate %d", hw, vif, sta, nstate);393error = lhw->ops->sta_state(hw, vif, sta, lsta->state, nstate);394if (error == 0) {395if (nstate == IEEE80211_STA_NOTEXIST)396lsta->added_to_drv = false;397else398lsta->added_to_drv = true;399lsta->state = nstate;400}401goto out;402}403404/* XXX-BZ is the change state AUTH or ASSOC here? */405if (lsta->state < IEEE80211_STA_ASSOC && nstate == IEEE80211_STA_ASSOC) {406error = lkpi_80211_mo_sta_add(hw, vif, sta);407if (error == 0)408lsta->added_to_drv = true;409} else if (lsta->state >= IEEE80211_STA_ASSOC &&410nstate < IEEE80211_STA_ASSOC) {411error = lkpi_80211_mo_sta_remove(hw, vif, sta);412if (error == 0)413lsta->added_to_drv = false;414} else415/* Nothing to do. */416error = 0;417if (error == 0)418lsta->state = nstate;419420out:421/* XXX-BZ should we manage state in here? */422return (error);423}424425int426lkpi_80211_mo_config(struct ieee80211_hw *hw, uint32_t changed)427{428struct lkpi_hw *lhw;429int error;430431lhw = HW_TO_LHW(hw);432if (lhw->ops->config == NULL) {433error = EOPNOTSUPP;434goto out;435}436437LKPI_80211_TRACE_MO("hw %p changed %u", hw, changed);438error = lhw->ops->config(hw, changed);439440out:441return (error);442}443444445int446lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,447struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)448{449struct lkpi_hw *lhw;450int error;451452lhw = HW_TO_LHW(hw);453if (lhw->ops->assign_vif_chanctx == NULL) {454error = EOPNOTSUPP;455goto out;456}457458LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",459hw, vif, conf, chanctx_conf);460error = lhw->ops->assign_vif_chanctx(hw, vif, conf, chanctx_conf);461if (error == 0)462vif->bss_conf.chanctx_conf = chanctx_conf;463464out:465return (error);466}467468void469lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,470struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)471{472struct lkpi_hw *lhw;473474might_sleep();475lockdep_assert_wiphy(hw->wiphy);476477lhw = HW_TO_LHW(hw);478if (lhw->ops->unassign_vif_chanctx == NULL)479return;480481if (chanctx_conf == NULL)482return;483484LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",485hw, vif, conf, chanctx_conf);486lhw->ops->unassign_vif_chanctx(hw, vif, conf, chanctx_conf);487}488489490int491lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw,492struct ieee80211_chanctx_conf *chanctx_conf)493{494struct lkpi_hw *lhw;495struct lkpi_chanctx *lchanctx;496int error;497498lhw = HW_TO_LHW(hw);499if (lhw->ops->add_chanctx == NULL) {500error = EOPNOTSUPP;501goto out;502}503504LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);505error = lhw->ops->add_chanctx(hw, chanctx_conf);506if (error == 0) {507lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);508lchanctx->added_to_drv = true;509}510511out:512return (error);513}514515void516lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw,517struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed)518{519struct lkpi_hw *lhw;520521lhw = HW_TO_LHW(hw);522if (lhw->ops->change_chanctx == NULL)523return;524525LKPI_80211_TRACE_MO("hw %p chanctx_conf %p changed %u", hw, chanctx_conf, changed);526lhw->ops->change_chanctx(hw, chanctx_conf, changed);527}528529void530lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw,531struct ieee80211_chanctx_conf *chanctx_conf)532{533struct lkpi_hw *lhw;534struct lkpi_chanctx *lchanctx;535536lhw = HW_TO_LHW(hw);537if (lhw->ops->remove_chanctx == NULL)538return;539540LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);541lhw->ops->remove_chanctx(hw, chanctx_conf);542lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);543lchanctx->added_to_drv = false;544}545546void547lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,548struct ieee80211_bss_conf *conf, uint64_t changed)549{550struct lkpi_hw *lhw;551552lhw = HW_TO_LHW(hw);553if (lhw->ops->link_info_changed == NULL &&554lhw->ops->bss_info_changed == NULL)555return;556557if (changed == 0)558return;559560LKPI_80211_TRACE_MO("hw %p vif %p conf %p changed %#jx", hw, vif, conf, (uintmax_t)changed);561if (lhw->ops->link_info_changed != NULL)562lhw->ops->link_info_changed(hw, vif, conf, changed);563else564lhw->ops->bss_info_changed(hw, vif, conf, changed);565}566567int568lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,569uint32_t link_id, uint16_t ac, const struct ieee80211_tx_queue_params *txqp)570{571struct lkpi_hw *lhw;572int error;573574lhw = HW_TO_LHW(hw);575if (lhw->ops->conf_tx == NULL) {576error = EOPNOTSUPP;577goto out;578}579580LKPI_80211_TRACE_MO("hw %p vif %p link_id %u ac %u txpq %p",581hw, vif, link_id, ac, txqp);582error = lhw->ops->conf_tx(hw, vif, link_id, ac, txqp);583584out:585return (error);586}587588void589lkpi_80211_mo_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,590uint32_t nqueues, bool drop)591{592struct lkpi_hw *lhw;593594lhw = HW_TO_LHW(hw);595if (lhw->ops->flush == NULL)596return;597598LKPI_80211_TRACE_MO("hw %p vif %p nqueues %u drop %d", hw, vif, nqueues, drop);599lhw->ops->flush(hw, vif, nqueues, drop);600}601602void603lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,604struct ieee80211_prep_tx_info *txinfo)605{606struct lkpi_hw *lhw;607608lhw = HW_TO_LHW(hw);609if (lhw->ops->mgd_prepare_tx == NULL)610return;611612LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);613lhw->ops->mgd_prepare_tx(hw, vif, txinfo);614}615616void617lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,618struct ieee80211_prep_tx_info *txinfo)619{620struct lkpi_hw *lhw;621622lhw = HW_TO_LHW(hw);623if (lhw->ops->mgd_complete_tx == NULL)624return;625626LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);627lhw->ops->mgd_complete_tx(hw, vif, txinfo);628}629630void631lkpi_80211_mo_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *txctrl,632struct sk_buff *skb)633{634struct lkpi_hw *lhw;635636lhw = HW_TO_LHW(hw);637if (lhw->ops->tx == NULL)638return;639640LKPI_80211_TRACE_MO("hw %p txctrl %p skb %p", hw, txctrl, skb);641lhw->ops->tx(hw, txctrl, skb);642}643644void645lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)646{647struct lkpi_hw *lhw;648649lhw = HW_TO_LHW(hw);650if (lhw->ops->wake_tx_queue == NULL)651return;652653LKPI_80211_TRACE_MO("hw %p txq %p", hw, txq);654lhw->ops->wake_tx_queue(hw, txq);655}656657void658lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *hw)659{660struct lkpi_hw *lhw;661662lhw = HW_TO_LHW(hw);663if (lhw->ops->sync_rx_queues == NULL)664return;665666LKPI_80211_TRACE_MO("hw %p", hw);667lhw->ops->sync_rx_queues(hw);668}669670void671lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *hw,672struct ieee80211_vif *vif, struct ieee80211_sta *sta)673{674struct lkpi_hw *lhw;675676lhw = HW_TO_LHW(hw);677if (lhw->ops->sta_pre_rcu_remove == NULL)678return;679680LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);681lhw->ops->sta_pre_rcu_remove(hw, vif, sta);682}683684int685lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,686struct ieee80211_vif *vif, struct ieee80211_sta *sta,687struct ieee80211_key_conf *kc)688{689struct lkpi_hw *lhw;690int error;691692lockdep_assert_wiphy(hw->wiphy);693694lhw = HW_TO_LHW(hw);695if (lhw->ops->set_key == NULL) {696error = EOPNOTSUPP;697goto out;698}699700LKPI_80211_TRACE_MO("hw %p cmd %d vif %p sta %p kc %p", hw, cmd, vif, sta, kc);701error = lhw->ops->set_key(hw, cmd, vif, sta, kc);702703out:704return (error);705}706707int708lkpi_80211_mo_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,709struct ieee80211_ampdu_params *params)710{711struct lkpi_hw *lhw;712int error;713714lhw = HW_TO_LHW(hw);715if (lhw->ops->ampdu_action == NULL) {716error = EOPNOTSUPP;717goto out;718}719720LKPI_80211_TRACE_MO("hw %p vif %p params %p { %p, %d, %u, %u, %u, %u, %d }",721hw, vif, params, params->sta, params->action, params->buf_size,722params->timeout, params->ssn, params->tid, params->amsdu);723error = lhw->ops->ampdu_action(hw, vif, params);724725out:726return (error);727}728729int730lkpi_80211_mo_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,731struct ieee80211_sta *sta, struct station_info *sinfo)732{733struct lkpi_hw *lhw;734struct lkpi_sta *lsta;735int error;736737lhw = HW_TO_LHW(hw);738if (lhw->ops->sta_statistics == NULL) {739error = EOPNOTSUPP;740goto out;741}742743lsta = STA_TO_LSTA(sta);744if (!lsta->added_to_drv) {745error = EEXIST;746goto out;747}748749lockdep_assert_wiphy(hw->wiphy);750751LKPI_80211_TRACE_MO("hw %p vif %p sta %p sinfo %p", hw, vif, sta, sinfo);752lhw->ops->sta_statistics(hw, vif, sta, sinfo);753error = 0;754755out:756return (error);757}758759760