diff options
| author | Bjoern A. Zeeb <bz@FreeBSD.org> | 2026-03-10 11:16:12 +0000 |
|---|---|---|
| committer | Bjoern A. Zeeb <bz@FreeBSD.org> | 2026-04-18 01:12:09 +0000 |
| commit | 166a7344df582f98a88f2b37b7aa3dc4558c9438 (patch) | |
| tree | fccac055f2b73b3c379b513f4ae4e3e9079bd58a /sys | |
| parent | 491f5876bfb40a4f70f523b5d14bccf6b53d2b0c (diff) | |
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/compat/linuxkpi/common/include/net/mac80211.h | 72 | ||||
| -rw-r--r-- | sys/compat/linuxkpi/common/src/linux_80211.c | 208 | ||||
| -rw-r--r-- | sys/compat/linuxkpi/common/src/linux_80211.h | 1 |
3 files changed, 218 insertions, 63 deletions
diff --git a/sys/compat/linuxkpi/common/include/net/mac80211.h b/sys/compat/linuxkpi/common/include/net/mac80211.h index 4f3aad532810..c637e13a496d 100644 --- a/sys/compat/linuxkpi/common/include/net/mac80211.h +++ b/sys/compat/linuxkpi/common/include/net/mac80211.h @@ -1196,6 +1196,22 @@ void linuxkpi_ieee80211_handle_wake_tx_queue(struct ieee80211_hw *, /* -------------------------------------------------------------------------- */ +/* + * Emulate chanctx operations. We cannot rename/prefix the functions + * as we rely on the (function)pointers being the same everywhere. + */ +int ieee80211_emulate_add_chanctx(struct ieee80211_hw *, + struct ieee80211_chanctx_conf *); +void ieee80211_emulate_remove_chanctx(struct ieee80211_hw *, + struct ieee80211_chanctx_conf *); +void ieee80211_emulate_change_chanctx(struct ieee80211_hw *, + struct ieee80211_chanctx_conf *, uint32_t); +int ieee80211_emulate_switch_vif_chanctx(struct ieee80211_hw *, + struct ieee80211_vif_chanctx_switch *, int, + enum ieee80211_chanctx_switch_mode); + +/* -------------------------------------------------------------------------- */ + static __inline void _ieee80211_hw_set(struct ieee80211_hw *hw, enum ieee80211_hw_flags flag) { @@ -2634,60 +2650,4 @@ ieee80211_cqm_beacon_loss_notify(struct ieee80211_vif *vif, gfp_t gfp __unused) /* -------------------------------------------------------------------------- */ -int lkpi_80211_update_chandef(struct ieee80211_hw *, - struct ieee80211_chanctx_conf *); - -static inline int -ieee80211_emulate_add_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *chanctx_conf) -{ - int error; - - hw->conf.radar_enabled = chanctx_conf->radar_enabled; - error = lkpi_80211_update_chandef(hw, chanctx_conf); - return (error); -} - -static inline void -ieee80211_emulate_remove_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *chanctx_conf __unused) -{ - hw->conf.radar_enabled = false; - lkpi_80211_update_chandef(hw, NULL); -} - -static inline void -ieee80211_emulate_change_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed __unused) -{ - hw->conf.radar_enabled = chanctx_conf->radar_enabled; - lkpi_80211_update_chandef(hw, chanctx_conf); -} - -static inline int -ieee80211_emulate_switch_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif_chanctx_switch *vifs, int n_vifs, - enum ieee80211_chanctx_switch_mode mode __unused) -{ - struct ieee80211_chanctx_conf *chanctx_conf; - int error; - - /* Sanity check. */ - if (n_vifs <= 0) - return (-EINVAL); - if (vifs == NULL || vifs[0].new_ctx == NULL) - return (-EINVAL); - - /* - * What to do if n_vifs > 1? - * Does that make sense for drivers not supporting chanctx? - */ - hw->conf.radar_enabled = vifs[0].new_ctx->radar_enabled; - chanctx_conf = vifs[0].new_ctx; - error = lkpi_80211_update_chandef(hw, chanctx_conf); - return (error); -} - -/* -------------------------------------------------------------------------- */ - #endif /* _LINUXKPI_NET_MAC80211_H */ diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c index e839867bea58..c2f2adfc7053 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.c +++ b/sys/compat/linuxkpi/common/src/linux_80211.c @@ -181,6 +181,8 @@ static void lkpi_ieee80211_free_skb_mbuf(void *); #ifdef LKPI_80211_WME static int lkpi_wme_update(struct lkpi_hw *, struct ieee80211vap *, bool); #endif +static int lkpi_80211_update_chandef(struct ieee80211_hw *, + struct ieee80211_chanctx_conf *); static void lkpi_ieee80211_wake_queues_locked(struct ieee80211_hw *); static const char * @@ -5218,7 +5220,7 @@ lkpi_ic_set_channel(struct ieee80211com *ic) IMPROVE("max power for scanning; TODO in lkpi_80211_update_chandef"); - } else if (lhw->ops->change_chanctx == ieee80211_emulate_change_chanctx) { + } else if (lhw->emulate_chanctx) { /* * We do not set the channel here for normal chanctx operation. * That's just a setup to fail. scan_to_auth will setup all the @@ -6593,6 +6595,53 @@ linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops) struct lkpi_hw *lhw; struct wiphy *wiphy; int ac; + bool emuchanctx; + + /* + * Do certain checks before starting to allocate resources. + * Store results in temporary variables. + */ + + /* ac1d519c01ca introduced emulating chanctx changes. */ + emuchanctx = false; + if (ops->add_chanctx == ieee80211_emulate_add_chanctx && + ops->change_chanctx == ieee80211_emulate_change_chanctx && + ops->remove_chanctx == ieee80211_emulate_remove_chanctx) { + /* + * If we emulate the chanctx ops, we must not have + * assign_vif_chanctx and unassign_vif_chanctx. + */ + if (ops->assign_vif_chanctx != NULL || + ops->unassign_vif_chanctx != NULL) { + /* Fail gracefully. */ + printf("%s: emulate_chanctx but " + "assign_vif_chanctx %p != NULL || " + "unassign_vif_chanctx %p != NULL\n", __func__, + ops->assign_vif_chanctx, ops->unassign_vif_chanctx); + return (NULL); + } + emuchanctx = true; + } + if (!emuchanctx && (ops->add_chanctx == ieee80211_emulate_add_chanctx || + ops->change_chanctx == ieee80211_emulate_change_chanctx || + ops->remove_chanctx == ieee80211_emulate_remove_chanctx)) { + printf("%s: not emulating chanctx changes but emulating " + "function set: %d/%d/%d\n", __func__, + ops->add_chanctx == ieee80211_emulate_add_chanctx, + ops->change_chanctx == ieee80211_emulate_change_chanctx, + ops->remove_chanctx == ieee80211_emulate_remove_chanctx); + return (NULL); + } + if (!emuchanctx && (ops->add_chanctx == NULL || ops->change_chanctx == NULL || + ops->remove_chanctx == NULL || ops->assign_vif_chanctx == NULL || + ops->unassign_vif_chanctx == NULL)) { + printf("%s: not all functions set for chanctx operations " + "(emulating chanctx %d): %p/%p/%p %p/%p\n", + __func__, emuchanctx, + ops->add_chanctx, ops->change_chanctx, ops->remove_chanctx, + ops->assign_vif_chanctx, ops->unassign_vif_chanctx); + return (NULL); + } /* Get us and the driver data also allocated. */ wiphy = wiphy_new(&linuxkpi_mac80211cfgops, sizeof(*lhw) + priv_len); @@ -6618,6 +6667,7 @@ linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops) /* Chanctx_conf */ INIT_LIST_HEAD(&lhw->lchanctx_list); INIT_LIST_HEAD(&lhw->lchanctx_list_reserved); + lhw->emulate_chanctx = emuchanctx; /* Deferred RX path. */ LKPI_80211_LHW_RXQ_LOCK_INIT(lhw); @@ -6637,6 +6687,8 @@ linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops) /* BSD Specific. */ lhw->ic = lkpi_ieee80211_ifalloc(); + if (lhw->emulate_chanctx) + ic_printf(lhw->ic, "Using chanctx emulation.\n"); IMPROVE(); return (hw); @@ -9220,6 +9272,35 @@ linuxkpi_cfg80211_bss_flush(struct wiphy *wiphy) /* -------------------------------------------------------------------------- */ +static bool +cfg80211_chan_def_are_same(struct cfg80211_chan_def *cd1, + struct cfg80211_chan_def *cd2) +{ + + if (cd1 == cd2) + return (true); + + if (cd1 == NULL || cd2 == NULL) + return (false); + + if (cd1->chan != cd2->chan) + return (false); + + if (cd1->width != cd2->width) + return (false); + + if (cd1->center_freq1 != cd2->center_freq1) + return (false); + + if (cd1->center_freq2 != cd2->center_freq2) + return (false); + + if (cd1->punctured != cd2->punctured) + return (false); + + return (true); +} + /* * hw->conf get initialized/set in various places for us: * - linuxkpi_ieee80211_alloc_hw(): flags @@ -9228,20 +9309,42 @@ linuxkpi_cfg80211_bss_flush(struct wiphy *wiphy) * - lkpi_ic_set_channel(): chandef, flags */ -int lkpi_80211_update_chandef(struct ieee80211_hw *hw, +static int +lkpi_80211_update_chandef(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *new) { + struct lkpi_hw *lhw; struct cfg80211_chan_def *cd; uint32_t changed; int error; + bool same; - changed = 0; - if (new == NULL || new->def.chan == NULL) - cd = NULL; - else + lockdep_assert_wiphy(hw->wiphy); + + lhw = HW_TO_LHW(hw); + if (!lhw->emulate_chanctx) + return (0); + + if (new == NULL || new->def.chan == NULL) { + /* + * In case of remove "new" is NULL, we need to get us to some + * basic channel width but we'd also need to set the channel + * accordingly somewhere. + * The same is true if we are scanning in which case the + * scan_chandef should have a channel set. + */ + if (lhw->scan_chandef.chan != NULL) { + cd = &lhw->scan_chandef; + } else { + cd = &lhw->dflt_chandef; + } + } else { cd = &new->def; + } - if (cd && cd->chan != hw->conf.chandef.chan) { + changed = 0; + same = cfg80211_chan_def_are_same(cd, &hw->conf.chandef); + if (!same) { /* Copy; the chan pointer is fine and will stay valid. */ hw->conf.chandef = *cd; changed |= IEEE80211_CONF_CHANGE_CHANNEL; @@ -9255,6 +9358,97 @@ int lkpi_80211_update_chandef(struct ieee80211_hw *hw, return (error); } +int +ieee80211_emulate_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *chanctx_conf) +{ + int error; + + lockdep_assert_wiphy(hw->wiphy); + +#ifdef LINUXKPI_DEBUG_80211 + if ((linuxkpi_debug_80211 & D80211_TRACE) != 0) { + struct lkpi_hw *lhw; + + lhw = HW_TO_LHW(hw); + ic_printf(lhw->ic, "%s:%d: chanctx_conf %p\n", + __func__, __LINE__, chanctx_conf); + } +#endif + + hw->conf.radar_enabled = chanctx_conf->radar_enabled; + error = lkpi_80211_update_chandef(hw, chanctx_conf); + return (error); +} + +void +ieee80211_emulate_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *chanctx_conf __unused) +{ + + lockdep_assert_wiphy(hw->wiphy); + +#ifdef LINUXKPI_DEBUG_80211 + if ((linuxkpi_debug_80211 & D80211_TRACE) != 0) { + struct lkpi_hw *lhw; + + lhw = HW_TO_LHW(hw); + ic_printf(lhw->ic, "%s:%d: chanctx_conf %p\n", + __func__, __LINE__, chanctx_conf); + } +#endif + + hw->conf.radar_enabled = false; + lkpi_80211_update_chandef(hw, NULL); +} + +void +ieee80211_emulate_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed __unused) +{ + + lockdep_assert_wiphy(hw->wiphy); + +#ifdef LINUXKPI_DEBUG_80211 + if ((linuxkpi_debug_80211 & D80211_TRACE) != 0) { + struct lkpi_hw *lhw; + + lhw = HW_TO_LHW(hw); + ic_printf(lhw->ic, "%s:%d: chanctx_conf %p\n", + __func__, __LINE__, chanctx_conf); + } +#endif + + hw->conf.radar_enabled = chanctx_conf->radar_enabled; + lkpi_80211_update_chandef(hw, chanctx_conf); +} + +int +ieee80211_emulate_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, int n_vifs, + enum ieee80211_chanctx_switch_mode mode __unused) +{ + struct ieee80211_chanctx_conf *chanctx_conf; + int error; + + lockdep_assert_wiphy(hw->wiphy); + + /* Sanity check. */ + if (n_vifs <= 0) + return (-EINVAL); + if (vifs == NULL || vifs[0].new_ctx == NULL) + return (-EINVAL); + + /* + * What to do if n_vifs > 1? + * Does that make sense for drivers not supporting chanctx? + */ + hw->conf.radar_enabled = vifs[0].new_ctx->radar_enabled; + chanctx_conf = vifs[0].new_ctx; + error = lkpi_80211_update_chandef(hw, chanctx_conf); + return (error); +} + /* -------------------------------------------------------------------------- */ MODULE_VERSION(linuxkpi_wlan, 1); diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h index 07816cdfe166..235597ea7a94 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.h +++ b/sys/compat/linuxkpi/common/src/linux_80211.h @@ -318,6 +318,7 @@ struct lkpi_hw { /* name it mac80211_sc? */ bool mc_all_multi; bool update_wme; bool rxq_stopped; + bool emulate_chanctx; /* Must be last! */ struct ieee80211_hw hw __aligned(CACHE_LINE_SIZE); |
