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: Vasanthakumar Thiagarajan <quic_vthiagar@quicinc.com> Link: https://lore.kernel.org/r/20220817104213.2531-2-quic_vthiagar@quicinc.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
ccdde7c74f
commit
ea9d807b56
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue