summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h2
-rw-r--r--net/mac80211/cfg.c4
-rw-r--r--net/mac80211/tx.c19
3 files changed, 23 insertions, 2 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 6fc4253b5644..6f856da28d71 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2147,6 +2147,7 @@ struct ieee80211_link_sta {
* @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only
* valid if the STA is a TDLS peer in the first place.
* @mfp: indicates whether the STA uses management frame protection or not.
+ * @mlo: indicates whether the STA is MLO station.
* @max_amsdu_subframes: indicates the maximal number of MSDUs in a single
* A-MSDU. Taken from the Extended Capabilities element. 0 means
* unlimited.
@@ -2180,6 +2181,7 @@ struct ieee80211_sta {
bool tdls;
bool tdls_initiator;
bool mfp;
+ bool mlo;
u8 max_amsdu_subframes;
/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1cacd1e0fc85..fe6500b36953 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1818,6 +1818,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
return ret;
}
+ /* Mark the STA as MLO if MLD MAC address is available */
+ if (params->link_sta_params.mld_mac)
+ sta->sta.mlo = true;
+
return 0;
}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 5dd29288c009..1d60eab8308a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2570,6 +2570,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx_conf *chanctx_conf = NULL;
enum nl80211_band band;
int ret;
+ u8 link_id = IEEE80211_LINK_UNSPECIFIED;
if (IS_ERR(sta))
sta = NULL;
@@ -2618,7 +2619,21 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
/* DA BSSID SA */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
- memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
+
+ if (sdata->vif.valid_links && sta && !sta->sta.mlo) {
+ struct ieee80211_link_data *link;
+
+ link_id = sta->deflink.link_id;
+ link = rcu_dereference(sdata->link[link_id]);
+ if (WARN_ON(!link)) {
+ ret = -ENOLINK;
+ goto free;
+ }
+ memcpy(hdr.addr2, link->conf->addr, ETH_ALEN);
+ } else {
+ memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
+ }
+
memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
hdrlen = 24;
break;
@@ -2882,7 +2897,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
info->ack_frame_id = info_id;
info->band = band;
info->control.flags = ctrl_flags |
- u32_encode_bits(IEEE80211_LINK_UNSPECIFIED,
+ u32_encode_bits(link_id,
IEEE80211_TX_CTRL_MLO_LINK);
return skb;