Commit ea9d807b authored by Vasanthakumar Thiagarajan's avatar Vasanthakumar Thiagarajan Committed by Johannes Berg

wifi: mac80211: add link information in ieee80211_rx_status

In MLO, when the address translation from link to MLD is done
in fw/hw, it is necessary to be able to have some information
on the link on which the frame has been received. Extend the
rx API to include link_id and a valid flag in ieee80211_rx_status.
Also make chanes to mac80211 rx APIs to make use of the reported
link_id after sanity checks.
Signed-off-by: default avatarVasanthakumar Thiagarajan <quic_vthiagar@quicinc.com>
Link: https://lore.kernel.org/r/20220817104213.2531-2-quic_vthiagar@quicinc.comSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent ccdde7c7
......@@ -1480,6 +1480,10 @@ enum mac80211_rx_encoding {
* each A-MPDU but the same for each subframe within one A-MPDU
* @ampdu_delimiter_crc: A-MPDU delimiter CRC
* @zero_length_psdu_type: radiotap type of the 0-length PSDU
* @link_valid: if the link which is identified by @link_id is valid. This flag
* is set only when connection is MLO.
* @link_id: id of the link used to receive the packet. This is used along with
* @link_valid.
*/
struct ieee80211_rx_status {
u64 mactime;
......@@ -1504,6 +1508,7 @@ struct ieee80211_rx_status {
s8 chain_signal[IEEE80211_MAX_CHAINS];
u8 ampdu_delimiter_crc;
u8 zero_length_psdu_type;
u8 link_valid:1, link_id:4;
};
static inline u32
......
......@@ -4506,6 +4506,15 @@ void ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&local->sta_mtx);
}
static bool
ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
{
if (!sta->mlo)
return false;
return !!(sta->valid_links & BIT(link_id));
}
static void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
struct ieee80211_fast_rx *fast_rx,
int orig_len)
......@@ -4835,6 +4844,7 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
struct list_head *list)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_fast_rx *fast_rx;
struct ieee80211_rx_data rx;
......@@ -4855,7 +4865,31 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
rx.sta = container_of(pubsta, struct sta_info, sta);
rx.sdata = rx.sta->sdata;
rx.link = &rx.sdata->deflink;
if (status->link_valid &&
!ieee80211_rx_is_valid_sta_link_id(pubsta, status->link_id))
goto drop;
/*
* TODO: Should the frame be dropped if the right link_id is not
* available? Or may be it is fine in the current form to proceed with
* the frame processing because with frame being in 802.3 format,
* link_id is used only for stats purpose and updating the stats on
* the deflink is fine?
*/
if (status->link_valid)
rx.link_id = status->link_id;
if (rx.link_id >= 0) {
struct ieee80211_link_data *link;
link = rcu_dereference(rx.sdata->link[rx.link_id]);
if (!link)
goto drop;
rx.link = link;
} else {
rx.link = &rx.sdata->deflink;
}
fast_rx = rcu_dereference(rx.sta->fast_rx);
if (!fast_rx)
......@@ -4885,7 +4919,19 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
rx->sta = link_sta->sta;
rx->link_id = link_sta->link_id;
} else {
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
rx->sta = sta_info_get_bss(rx->sdata, hdr->addr2);
if (rx->sta) {
if (status->link_valid &&
!ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta,
status->link_id))
return false;
rx->link_id = status->link_valid ? status->link_id : -1;
} else {
rx->link_id = -1;
}
}
return ieee80211_prepare_and_rx_handle(rx, skb, consume);
......@@ -4901,6 +4947,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
struct list_head *list)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_hdr *hdr;
__le16 fc;
......@@ -4945,10 +4992,39 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
if (ieee80211_is_data(fc)) {
struct sta_info *sta, *prev_sta;
u8 link_id = status->link_id;
if (pubsta) {
rx.sta = container_of(pubsta, struct sta_info, sta);
rx.sdata = rx.sta->sdata;
if (status->link_valid &&
!ieee80211_rx_is_valid_sta_link_id(pubsta, link_id))
goto out;
if (status->link_valid)
rx.link_id = status->link_id;
/*
* In MLO connection, fetch the link_id using addr2
* when the driver does not pass link_id in status.
* When the address translation is already performed by
* driver/hw, the valid link_id must be passed in
* status.
*/
if (!status->link_valid && pubsta->mlo) {
struct ieee80211_hdr *hdr = (void *)skb->data;
struct link_sta_info *link_sta;
link_sta = link_sta_info_get_bss(rx.sdata,
hdr->addr2);
if (!link_sta)
goto out;
rx.link_id = link_sta->link_id;
}
if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
return;
goto out;
......@@ -4962,6 +5038,13 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
continue;
}
if ((status->link_valid &&
!ieee80211_rx_is_valid_sta_link_id(&prev_sta->sta,
link_id)) ||
(!status->link_valid && prev_sta->sta.mlo))
continue;
rx.link_id = status->link_valid ? link_id : -1;
rx.sta = prev_sta;
rx.sdata = prev_sta->sdata;
ieee80211_prepare_and_rx_handle(&rx, skb, false);
......@@ -4970,6 +5053,13 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
}
if (prev_sta) {
if ((status->link_valid &&
!ieee80211_rx_is_valid_sta_link_id(&prev_sta->sta,
link_id)) ||
(!status->link_valid && prev_sta->sta.mlo))
goto out;
rx.link_id = status->link_valid ? link_id : -1;
rx.sta = prev_sta;
rx.sdata = prev_sta->sdata;
......@@ -5112,6 +5202,9 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
}
}
if (WARN_ON_ONCE(status->link_id >= IEEE80211_LINK_UNSPECIFIED))
goto drop;
status->rx_flags = 0;
kcov_remote_start_common(skb_get_kcov_handle(skb));
......
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