Commit e993af2e authored by Miri Korenblit's avatar Miri Korenblit Committed by Johannes Berg

wifi: mac80211: add a driver callback to check active_links

During ieee80211_set_active_links() we do (among the others):
1. Call drv_change_vif_links() with both old_active and new_active
2. Unassign the chanctx for the removed link(s) (if any)
3. Assign chanctx to the added link(s) (if any)
4. Call drv_change_vif_links() with the new_active links bitmap

The problem here is that during step #1 the driver doesn't know whether
we will activate multiple links simultaneously or are just doing a link
switch, so it can't check there if multiple links are supported/enabled.
(Some of the drivers might enable/disable this option dynamically)

And during step #3, in which the driver already knows that,
returning an error code (for example when multiple links are not
supported or disabled), will cause a warning, and we will still complete
the transition to the new_active links.
(It is hard to undo things in that stage, since we released channels etc.)

Therefore add a driver callback to check if the desired new_active links
will be supported by the driver or not. This callback will be called
in the beginning of ieee80211_set_active_links() so we won't do anything
before we are sure it is supported.
Signed-off-by: default avatarMiri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Reviewed-by: default avatarJohannes Berg <johannes.berg@intel.com>
Link: https://msgid.link/20231220133549.64c4d70b33b8.I79708619be76b8ecd4ef3975205b8f903e24a2cd@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent b1a23f8a
...@@ -4272,6 +4272,8 @@ struct ieee80211_prep_tx_info { ...@@ -4272,6 +4272,8 @@ struct ieee80211_prep_tx_info {
* disable background CAC/radar detection. * disable background CAC/radar detection.
* @net_fill_forward_path: Called from .ndo_fill_forward_path in order to * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to
* resolve a path for hardware flow offloading * resolve a path for hardware flow offloading
* @can_activate_links: Checks if a specific active_links bitmap is
* supported by the driver.
* @change_vif_links: Change the valid links on an interface, note that while * @change_vif_links: Change the valid links on an interface, note that while
* removing the old link information is still valid (link_conf pointer), * removing the old link information is still valid (link_conf pointer),
* but may immediately disappear after the function returns. The old or * but may immediately disappear after the function returns. The old or
...@@ -4652,6 +4654,9 @@ struct ieee80211_ops { ...@@ -4652,6 +4654,9 @@ struct ieee80211_ops {
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct net_device_path_ctx *ctx, struct net_device_path_ctx *ctx,
struct net_device_path *path); struct net_device_path *path);
bool (*can_activate_links)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u16 active_links);
int (*change_vif_links)(struct ieee80211_hw *hw, int (*change_vif_links)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
u16 old_links, u16 new_links, u16 old_links, u16 new_links,
......
...@@ -1666,6 +1666,26 @@ static inline int drv_net_setup_tc(struct ieee80211_local *local, ...@@ -1666,6 +1666,26 @@ static inline int drv_net_setup_tc(struct ieee80211_local *local,
return ret; return ret;
} }
static inline bool drv_can_activate_links(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
u16 active_links)
{
bool ret = true;
lockdep_assert_wiphy(local->hw.wiphy);
if (!check_sdata_in_driver(sdata))
return false;
trace_drv_can_activate_links(local, sdata, active_links);
if (local->ops->can_activate_links)
ret = local->ops->can_activate_links(&local->hw, &sdata->vif,
active_links);
trace_drv_return_bool(local, ret);
return ret;
}
int drv_change_vif_links(struct ieee80211_local *local, int drv_change_vif_links(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
u16 old_links, u16 new_links, u16 old_links, u16 new_links,
......
...@@ -444,6 +444,9 @@ int ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links) ...@@ -444,6 +444,9 @@ int ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links)
lockdep_assert_wiphy(local->hw.wiphy); lockdep_assert_wiphy(local->hw.wiphy);
if (!drv_can_activate_links(local, sdata, active_links))
return -EINVAL;
old_active = sdata->vif.active_links; old_active = sdata->vif.active_links;
if (old_active & active_links) { if (old_active & active_links) {
/* /*
......
...@@ -2512,6 +2512,31 @@ TRACE_EVENT(drv_net_setup_tc, ...@@ -2512,6 +2512,31 @@ TRACE_EVENT(drv_net_setup_tc,
) )
); );
TRACE_EVENT(drv_can_activate_links,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
u16 active_links),
TP_ARGS(local, sdata, active_links),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
__field(u16, active_links)
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
__entry->active_links = active_links;
),
TP_printk(
LOCAL_PR_FMT VIF_PR_FMT " requested active_links:0x%04x\n",
LOCAL_PR_ARG, VIF_PR_ARG, __entry->active_links
)
);
TRACE_EVENT(drv_change_vif_links, TRACE_EVENT(drv_change_vif_links,
TP_PROTO(struct ieee80211_local *local, TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment