Commit 03ecd745 authored by Johannes Berg's avatar Johannes Berg

wifi: mac80211: fix erroneous errors for STA changes

When e.g. wpa_supplicant sets only the MLD "sta" authorized
state, the code actually applies that change, but then returns
an error to userspace anyway because there were no changes to
the link station, and no link ID was given. However, it's not
incorrect to not have a link ID when wanting to change only
the MLD peer ("sta") state, so the code shouldn't require it.

To fix this, separate the "new_link" argument out into a new
three-state enum, because if modify is called on a link STA
only, it should return an error if no link is given or if it
doesn't exist. For modify on the MLD "sta", not having a link
ID is OK, but if there is one it should be validated.

This seems to not have mattered much as wpa_supplicant just
prints a message and continues, and the authorized state was
already set before this error return. However, in the later
code powersave recalculation etc. will be skipped, so that it
may result in never allowing powersave on MLO connections.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarMiri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://msgid.link/20240605135233.48e2b8af07e3.Ib9793c383fcba118c05100e024f4a11a1c3d0e85@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent a7bb6b5d
......@@ -1814,8 +1814,15 @@ static void sta_apply_mesh_params(struct ieee80211_local *local,
#endif
}
enum sta_link_apply_mode {
STA_LINK_MODE_NEW,
STA_LINK_MODE_STA_MODIFY,
STA_LINK_MODE_LINK_MODIFY,
};
static int sta_link_apply_parameters(struct ieee80211_local *local,
struct sta_info *sta, bool new_link,
struct sta_info *sta,
enum sta_link_apply_mode mode,
struct link_station_parameters *params)
{
int ret = 0;
......@@ -1827,18 +1834,29 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
struct link_sta_info *link_sta =
rcu_dereference_protected(sta->link[link_id],
lockdep_is_held(&local->hw.wiphy->mtx));
/*
* If there are no changes, then accept a link that exist,
* unless it's a new link.
*/
if (params->link_id >= 0 && !new_link &&
!params->link_mac && !params->txpwr_set &&
!params->supported_rates_len &&
!params->ht_capa && !params->vht_capa &&
!params->he_capa && !params->eht_capa &&
!params->opmode_notif_used)
return 0;
bool changes = params->link_mac ||
params->txpwr_set ||
params->supported_rates_len ||
params->ht_capa ||
params->vht_capa ||
params->he_capa ||
params->eht_capa ||
params->opmode_notif_used;
switch (mode) {
case STA_LINK_MODE_NEW:
if (!params->link_mac)
return -EINVAL;
break;
case STA_LINK_MODE_LINK_MODIFY:
break;
case STA_LINK_MODE_STA_MODIFY:
if (params->link_id >= 0)
break;
if (!changes)
return 0;
break;
}
if (!link || !link_sta)
return -EINVAL;
......@@ -1848,15 +1866,13 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
return -EINVAL;
if (params->link_mac) {
if (new_link) {
if (mode == STA_LINK_MODE_NEW) {
memcpy(link_sta->addr, params->link_mac, ETH_ALEN);
memcpy(link_sta->pub->addr, params->link_mac, ETH_ALEN);
} else if (!ether_addr_equal(link_sta->addr,
params->link_mac)) {
return -EINVAL;
}
} else if (new_link) {
return -EINVAL;
}
if (params->txpwr_set) {
......@@ -2028,7 +2044,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (params->listen_interval >= 0)
sta->listen_interval = params->listen_interval;
ret = sta_link_apply_parameters(local, sta, false,
ret = sta_link_apply_parameters(local, sta, STA_LINK_MODE_STA_MODIFY,
&params->link_sta_params);
if (ret)
return ret;
......@@ -5005,7 +5021,7 @@ ieee80211_add_link_station(struct wiphy *wiphy, struct net_device *dev,
if (ret)
return ret;
ret = sta_link_apply_parameters(local, sta, true, params);
ret = sta_link_apply_parameters(local, sta, STA_LINK_MODE_NEW, params);
if (ret) {
ieee80211_sta_free_link(sta, params->link_id);
return ret;
......@@ -5032,7 +5048,8 @@ ieee80211_mod_link_station(struct wiphy *wiphy, struct net_device *dev,
if (!(sta->sta.valid_links & BIT(params->link_id)))
return -EINVAL;
return sta_link_apply_parameters(local, sta, false, params);
return sta_link_apply_parameters(local, sta, STA_LINK_MODE_LINK_MODIFY,
params);
}
static int
......
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