Commit 9dd19538 authored by Johannes Berg's avatar Johannes Berg

wifi: nl80211/mac80211: clarify link ID in control port TX

Clarify the link ID behaviour in control port TX, we need it
to select the link to transmit on for both MLD and non-MLD
receivers, but select the link address as the SA only if the
receiver is not an MLD.

Fixes: 67207bab ("wifi: cfg80211/mac80211: Support control port TX from specific link")
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent dd820ed6
...@@ -1119,6 +1119,12 @@ ...@@ -1119,6 +1119,12 @@
* has been received. %NL80211_ATTR_FRAME is used to specify the * has been received. %NL80211_ATTR_FRAME is used to specify the
* frame contents. The frame is the raw EAPoL data, without ethernet or * frame contents. The frame is the raw EAPoL data, without ethernet or
* 802.11 headers. * 802.11 headers.
* For an MLD transmitter, the %NL80211_ATTR_MLO_LINK_ID may be given and
* its effect will depend on the destination: If the destination is known
* to be an MLD, this will be used as a hint to select the link to transmit
* the frame on. If the destination is not an MLD, this will select both
* the link to transmit on and the source address will be set to the link
* address of that link.
* When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added
* indicating the protocol type of the received frame; whether the frame * indicating the protocol type of the received frame; whether the frame
......
...@@ -2896,9 +2896,35 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, ...@@ -2896,9 +2896,35 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
info->flags = info_flags; info->flags = info_flags;
info->ack_frame_id = info_id; info->ack_frame_id = info_id;
info->band = band; info->band = band;
info->control.flags = ctrl_flags |
u32_encode_bits(link_id, if (likely(!cookie)) {
ctrl_flags |= u32_encode_bits(link_id,
IEEE80211_TX_CTRL_MLO_LINK); IEEE80211_TX_CTRL_MLO_LINK);
} else {
unsigned int pre_conf_link_id;
/*
* ctrl_flags already have been set by
* ieee80211_tx_control_port(), here
* we just sanity check that
*/
pre_conf_link_id = u32_get_bits(ctrl_flags,
IEEE80211_TX_CTRL_MLO_LINK);
if (pre_conf_link_id != link_id &&
link_id != IEEE80211_LINK_UNSPECIFIED) {
#ifdef CPTCFG_MAC80211_VERBOSE_DEBUG
net_info_ratelimited("%s: dropped frame to %pM with bad link ID request (%d vs. %d)\n",
sdata->name, hdr.addr1,
pre_conf_link_id, link_id);
#endif
ret = -EINVAL;
goto free;
}
}
info->control.flags = ctrl_flags;
return skb; return skb;
free: free:
...@@ -5745,11 +5771,17 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, ...@@ -5745,11 +5771,17 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
ehdr = skb_push(skb, sizeof(struct ethhdr)); ehdr = skb_push(skb, sizeof(struct ethhdr));
memcpy(ehdr->h_dest, dest, ETH_ALEN); memcpy(ehdr->h_dest, dest, ETH_ALEN);
/* we may override the SA for MLO STA later */
if (link_id < 0) { if (link_id < 0) {
ctrl_flags |= u32_encode_bits(IEEE80211_LINK_UNSPECIFIED,
IEEE80211_TX_CTRL_MLO_LINK);
memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
} else { } else {
struct ieee80211_bss_conf *link_conf; struct ieee80211_bss_conf *link_conf;
ctrl_flags |= u32_encode_bits(link_id,
IEEE80211_TX_CTRL_MLO_LINK);
rcu_read_lock(); rcu_read_lock();
link_conf = rcu_dereference(sdata->vif.link_conf[link_id]); link_conf = rcu_dereference(sdata->vif.link_conf[link_id]);
if (!link_conf) { if (!link_conf) {
...@@ -5784,6 +5816,13 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, ...@@ -5784,6 +5816,13 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
skb_set_queue_mapping(skb, queue); skb_set_queue_mapping(skb, queue);
skb_get_hash(skb); skb_get_hash(skb);
/*
* for MLO STA, the SA should be the AP MLD address, but
* the link ID has been selected already
*/
if (sta->sta.mlo)
memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
} }
rcu_read_unlock(); rcu_read_unlock();
......
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