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

wifi: mac80211: add sta link addition/removal



Add the necessary infrastructure, including a new driver
method, to add/remove links to/from a station. To do this,
refactor the link alloc/free a bit, splitting that so we
can do it without linking them, to handle failures better.

Note that a station entry must be created representing an
MLD or a non-MLD STA, it cannot change between the two.
When representing an MLD, the 'deflink' is used for the
first link, which might be removed later, in which case
the memory isn't reused.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 69d41b5a
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -2150,7 +2150,6 @@ struct ieee80211_link_sta {
 * @max_tid_amsdu_len: Maximum A-MSDU size in bytes for this TID
 * @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that
 *	the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames
 * @multi_link_sta: Identifies if this sta is a MLD STA
 * @deflink: This holds the default link STA information, for non MLO STA all link
 *	specific STA information is accessed through @deflink or through
 *	link[0] which points to address of @deflink. For MLO Link STA
@@ -2162,6 +2161,7 @@ struct ieee80211_link_sta {
 *	@deflink address and remaining would be allocated and the address
 *	would be assigned to link[link_id] where link_id is the id assigned
 *	by the AP.
 * @valid_links: bitmap of valid links, or 0 for non-MLO
 */
struct ieee80211_sta {
	u8 addr[ETH_ALEN];
@@ -2199,7 +2199,7 @@ struct ieee80211_sta {

	struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1];

	bool multi_link_sta;
	u16 valid_links;
	struct ieee80211_link_sta deflink;
	struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS];

@@ -4048,6 +4048,11 @@ struct ieee80211_prep_tx_info {
 *	The @old[] array contains pointers to the old bss_conf structures
 *	that were already removed, in case they're needed.
 *	This callback can sleep.
 * @change_sta_links: Change the valid links of a station, similar to
 *	@change_vif_links. This callback can sleep.
 *	Note that a sta can also be inserted or removed with valid links,
 *	i.e. passed to @sta_add/@sta_state with sta->valid_links not zero.
 *	In fact, cannot change from having valid_links and not having them.
 */
struct ieee80211_ops {
	void (*tx)(struct ieee80211_hw *hw,
@@ -4395,6 +4400,10 @@ struct ieee80211_ops {
				struct ieee80211_vif *vif,
				u16 old_links, u16 new_links,
				struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]);
	int (*change_sta_links)(struct ieee80211_hw *hw,
				struct ieee80211_vif *vif,
				struct ieee80211_sta *sta,
				u16 old_links, u16 new_links);
};

/**
+1 −1
Original line number Diff line number Diff line
@@ -1839,7 +1839,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
	    !sdata->u.mgd.associated)
		return -EINVAL;

	sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
	sta = sta_info_alloc(sdata, mac, -1, GFP_KERNEL);
	if (!sta)
		return -ENOMEM;

+21 −0
Original line number Diff line number Diff line
@@ -1554,4 +1554,25 @@ static inline int drv_change_vif_links(struct ieee80211_local *local,
	return ret;
}

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

#endif /* __MAC80211_DRIVER_OPS */
+2 −2
Original line number Diff line number Diff line
@@ -629,7 +629,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
	scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
	rcu_read_unlock();

	sta = sta_info_alloc(sdata, addr, GFP_KERNEL);
	sta = sta_info_alloc(sdata, addr, -1, GFP_KERNEL);
	if (!sta) {
		rcu_read_lock();
		return NULL;
@@ -1229,7 +1229,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
	scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
	rcu_read_unlock();

	sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
	sta = sta_info_alloc(sdata, addr, -1, GFP_ATOMIC);
	if (!sta)
		return;

+1 −1
Original line number Diff line number Diff line
@@ -510,7 +510,7 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
	if (aid < 0)
		return NULL;

	sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
	sta = sta_info_alloc(sdata, hw_addr, -1, GFP_KERNEL);
	if (!sta)
		return NULL;

Loading