Commit efe9c2bf authored by Johannes Berg's avatar Johannes Berg
Browse files

wifi: mac80211: isolate driver from inactive links



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: default avatarJohannes Berg <johannes.berg@intel.com>
parent 261ce887
Loading
Loading
Loading
Loading
+16 −14
Original line number Diff line number Diff line
@@ -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
@@ -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;

@@ -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])))
		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)
{
@@ -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)		         \
/* 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 (((link_sta) = rcu_dereference_protected((sta)->link[link_id],\
							    1)))	         \
		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
+6 −0
Original line number Diff line number Diff line
@@ -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,
+172 −0
Original line number Diff line number Diff line
@@ -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
@@ -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)
@@ -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;
}
+25 −140
Original line number Diff line number Diff line
@@ -165,40 +165,10 @@ static inline void drv_vif_cfg_changed(struct ieee80211_local *local,
	trace_drv_return_void(local);
}

static inline void drv_link_info_changed(struct ieee80211_local *local,
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;

	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 link_id, u64 changed);

static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
					struct netdev_hw_addr_list *mc_list)
@@ -256,25 +226,11 @@ static inline int drv_set_tim(struct ieee80211_local *local,
	return ret;
}

static inline int drv_set_key(struct ieee80211_local *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;

	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;
}
		struct ieee80211_key_conf *key);

static inline void drv_update_tkip_key(struct ieee80211_local *local,
				       struct ieee80211_sub_if_data *sdata,
@@ -945,52 +901,14 @@ static inline void drv_verify_link_exists(struct ieee80211_sub_if_data *sdata,
		sdata_assert_lock(sdata);
}

static inline int drv_assign_vif_chanctx(struct ieee80211_local *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;

	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;
}

static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
			   struct ieee80211_chanctx *ctx);
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;

	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);
}

			      struct ieee80211_chanctx *ctx);
int drv_switch_vif_chanctx(struct ieee80211_local *local,
			   struct ieee80211_vif_chanctx_switch *vifs,
			   int n_vifs, enum ieee80211_chanctx_switch_mode mode);
@@ -1552,46 +1470,13 @@ static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
	return ret;
}

static inline int drv_change_vif_links(struct ieee80211_local *local,
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;

	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;
}

static inline int drv_change_sta_links(struct ieee80211_local *local,
			 struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]);
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;

	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;
}
			 u16 old_links, u16 new_links);

#endif /* __MAC80211_DRIVER_OPS */
+8 −0
Original line number Diff line number Diff line
@@ -177,6 +177,10 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
		}
	}

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

	ret = drv_set_key(key->local, SET_KEY, sdata,
			  sta ? &sta->sta : NULL, &key->conf);

@@ -246,6 +250,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
	sta = key->sta;
	sdata = key->sdata;

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

	if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
				 IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
				 IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
Loading