Skip to content

Commit

Permalink
wifi: mac80211: isolate driver from inactive links
Browse files Browse the repository at this point in the history
In order to let the driver select active links and properly
make multi-link connections, as a first step isolate the
driver from inactive links, and set the active links to be
only the association link for client-side interfaces. For
AP side nothing changes since APs always have to have all
their links active.

To simplify things, update the for_each_sta_active_link()
API to include the appropriate vif pointer.

This also implies not allocating a chanctx for an inactive
link, which requires a few more changes.

Since we now no longer try to program multiple links to the
driver, remove the check in the MLME code.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
Johannes Berg committed Sep 6, 2022
1 parent 261ce88 commit efe9c2b
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 188 deletions.
30 changes: 16 additions & 14 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,9 @@ struct ieee80211_vif_cfg {
* @link_conf: in case of MLD, the per-link BSS configuration,
* indexed by link ID
* @valid_links: bitmap of valid links, or 0 for non-MLO.
* @active_links: The bitmap of active links, or 0 for non-MLO.
* The driver shouldn't change this directly, but use the
* API calls meant for that purpose.
* @addr: address of this interface
* @p2p: indicates whether this AP or STA interface is a p2p
* interface, i.e. a GO or p2p-sta respectively
Expand Down Expand Up @@ -1834,7 +1837,7 @@ struct ieee80211_vif {
struct ieee80211_vif_cfg cfg;
struct ieee80211_bss_conf bss_conf;
struct ieee80211_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS];
u16 valid_links;
u16 valid_links, active_links;
u8 addr[ETH_ALEN] __aligned(2);
bool p2p;

Expand All @@ -1861,12 +1864,11 @@ struct ieee80211_vif {
u8 drv_priv[] __aligned(sizeof(void *));
};

/* FIXME: for now loop over all the available links; later will be changed
* to loop only over the active links.
*/
#define for_each_vif_active_link(vif, link, link_id) \
for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) \
if ((link = rcu_dereference((vif)->link_conf[link_id])))
#define for_each_vif_active_link(vif, link, link_id) \
for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) \
if ((!(vif)->active_links || \
(vif)->active_links & BIT(link_id)) && \
(link = rcu_dereference((vif)->link_conf[link_id])))

static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
{
Expand Down Expand Up @@ -2264,13 +2266,13 @@ struct ieee80211_sta {
u8 drv_priv[] __aligned(sizeof(void *));
};

/* FIXME: need to loop only over links which are active and check the actual
* lock
*/
#define for_each_sta_active_link(sta, link_sta, link_id) \
for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) \
if (((link_sta) = rcu_dereference_protected((sta)->link[link_id],\
1))) \
/* FIXME: check the locking correctly */
#define for_each_sta_active_link(vif, sta, link_sta, link_id) \
for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) \
if ((!(vif)->active_links || \
(vif)->active_links & BIT(link_id)) && \
((link_sta) = rcu_dereference_protected((sta)->link[link_id],\
1)))

/**
* enum sta_notify_cmd - sta notify command
Expand Down
6 changes: 6 additions & 0 deletions net/mac80211/chan.c
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,12 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link,

lockdep_assert_held(&local->mtx);

if (sdata->vif.active_links &&
!(sdata->vif.active_links & BIT(link->link_id))) {
ieee80211_link_update_chandef(link, chandef);
return 0;
}

mutex_lock(&local->chanctx_mtx);

ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
Expand Down
172 changes: 172 additions & 0 deletions net/mac80211/driver-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ int drv_conf_tx(struct ieee80211_local *local,
if (!check_sdata_in_driver(sdata))
return -EIO;

if (sdata->vif.active_links &&
!(sdata->vif.active_links & BIT(link->link_id)))
return 0;

if (params->cw_min == 0 || params->cw_min > params->cw_max) {
/*
* If we can't configure hardware anyway, don't warn. We may
Expand Down Expand Up @@ -272,6 +276,60 @@ void drv_reset_tsf(struct ieee80211_local *local,
trace_drv_return_void(local);
}

int drv_assign_vif_chanctx(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx *ctx)
{
int ret = 0;

drv_verify_link_exists(sdata, link_conf);
if (!check_sdata_in_driver(sdata))
return -EIO;

if (sdata->vif.active_links &&
!(sdata->vif.active_links & BIT(link_conf->link_id)))
return 0;

trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx);
if (local->ops->assign_vif_chanctx) {
WARN_ON_ONCE(!ctx->driver_present);
ret = local->ops->assign_vif_chanctx(&local->hw,
&sdata->vif,
link_conf,
&ctx->conf);
}
trace_drv_return_int(local, ret);

return ret;
}

void drv_unassign_vif_chanctx(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx *ctx)
{
might_sleep();

drv_verify_link_exists(sdata, link_conf);
if (!check_sdata_in_driver(sdata))
return;

if (sdata->vif.active_links &&
!(sdata->vif.active_links & BIT(link_conf->link_id)))
return;

trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx);
if (local->ops->unassign_vif_chanctx) {
WARN_ON_ONCE(!ctx->driver_present);
local->ops->unassign_vif_chanctx(&local->hw,
&sdata->vif,
link_conf,
&ctx->conf);
}
trace_drv_return_void(local);
}

int drv_switch_vif_chanctx(struct ieee80211_local *local,
struct ieee80211_vif_chanctx_switch *vifs,
int n_vifs, enum ieee80211_chanctx_switch_mode mode)
Expand Down Expand Up @@ -346,3 +404,117 @@ int drv_ampdu_action(struct ieee80211_local *local,

return ret;
}

void drv_link_info_changed(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *info,
int link_id, u64 changed)
{
might_sleep();

if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED) &&
sdata->vif.type != NL80211_IFTYPE_AP &&
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
sdata->vif.type != NL80211_IFTYPE_OCB))
return;

if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
sdata->vif.type == NL80211_IFTYPE_NAN ||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!sdata->vif.bss_conf.mu_mimo_owner &&
!(changed & BSS_CHANGED_TXPOWER))))
return;

if (!check_sdata_in_driver(sdata))
return;

if (sdata->vif.active_links &&
!(sdata->vif.active_links & BIT(link_id)))
return;

trace_drv_link_info_changed(local, sdata, info, changed);
if (local->ops->link_info_changed)
local->ops->link_info_changed(&local->hw, &sdata->vif,
info, changed);
else if (local->ops->bss_info_changed)
local->ops->bss_info_changed(&local->hw, &sdata->vif,
info, changed);
trace_drv_return_void(local);
}

int drv_set_key(struct ieee80211_local *local,
enum set_key_cmd cmd,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
int ret;

might_sleep();

sdata = get_bss_sdata(sdata);
if (!check_sdata_in_driver(sdata))
return -EIO;

if (WARN_ON(key->link_id >= 0 && sdata->vif.active_links &&
!(sdata->vif.active_links & BIT(key->link_id))))
return -ENOLINK;

trace_drv_set_key(local, cmd, sdata, sta, key);
ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
trace_drv_return_int(local, ret);
return ret;
}

int drv_change_vif_links(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
u16 old_links, u16 new_links,
struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
{
int ret = -EOPNOTSUPP;

might_sleep();

if (!check_sdata_in_driver(sdata))
return -EIO;

if (old_links == new_links)
return 0;

trace_drv_change_vif_links(local, sdata, old_links, new_links);
if (local->ops->change_vif_links)
ret = local->ops->change_vif_links(&local->hw, &sdata->vif,
old_links, new_links, old);
trace_drv_return_int(local, ret);

return ret;
}

int drv_change_sta_links(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta,
u16 old_links, u16 new_links)
{
int ret = -EOPNOTSUPP;

might_sleep();

if (!check_sdata_in_driver(sdata))
return -EIO;

old_links &= sdata->vif.active_links;
new_links &= sdata->vif.active_links;

if (old_links == new_links)
return 0;

trace_drv_change_sta_links(local, sdata, sta, old_links, new_links);
if (local->ops->change_sta_links)
ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta,
old_links, new_links);
trace_drv_return_int(local, ret);

return ret;
}
Loading

0 comments on commit efe9c2b

Please sign in to comment.