mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 20:32:22 +00:00
wifi: mac80211: process and save negotiated TID to Link mapping request
An MLD may send TID-to-Link mapping request frame to negotiate TID to link mapping with a peer MLD. Support handling negotiated TID-to-Link mapping request frame by parsing the frame, asking the driver whether it supports the received mapping or not, and sending a TID-to-Link mapping response to the AP MLD. Theoretically, links that became inactive due to the received TID-to-Link mapping request, can be selected to be activated but this would require tearing down the negotiated TID-to-Link mapping, which is still not supported. Signed-off-by: Ayala Beker <ayala.beker@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Reviewed-by: Gregory Greenman <gregory.greenman@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://msgid.link/20240102213313.0bc1a24fcc9d.Ie72e47dc6f8c77d4a2f0947b775ef6367fe0edac@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
83e897a961
commit
8f500fbc6c
@ -342,6 +342,7 @@ struct ieee80211_vif_chanctx_switch {
|
||||
* status changed.
|
||||
* @BSS_CHANGED_EHT_PUNCTURING: The channel puncturing bitmap changed.
|
||||
* @BSS_CHANGED_MLD_VALID_LINKS: MLD valid links status changed.
|
||||
* @BSS_CHANGED_MLD_TTLM: TID to link mapping was changed
|
||||
*/
|
||||
enum ieee80211_bss_change {
|
||||
BSS_CHANGED_ASSOC = 1<<0,
|
||||
@ -378,6 +379,7 @@ enum ieee80211_bss_change {
|
||||
BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = 1<<31,
|
||||
BSS_CHANGED_EHT_PUNCTURING = BIT_ULL(32),
|
||||
BSS_CHANGED_MLD_VALID_LINKS = BIT_ULL(33),
|
||||
BSS_CHANGED_MLD_TTLM = BIT_ULL(34),
|
||||
|
||||
/* when adding here, make sure to change ieee80211_reconfig */
|
||||
};
|
||||
@ -1845,6 +1847,35 @@ struct ieee80211_vif_cfg {
|
||||
u8 ap_addr[ETH_ALEN] __aligned(2);
|
||||
};
|
||||
|
||||
#define IEEE80211_TTLM_NUM_TIDS 8
|
||||
|
||||
/**
|
||||
* struct ieee80211_neg_ttlm - negotiated TID to link map info
|
||||
*
|
||||
* @downlink: bitmap of active links per TID for downlink, or 0 if mapping for
|
||||
* this TID is not included.
|
||||
* @uplink: bitmap of active links per TID for uplink, or 0 if mapping for this
|
||||
* TID is not included.
|
||||
* @valid: info is valid or not.
|
||||
*/
|
||||
struct ieee80211_neg_ttlm {
|
||||
u16 downlink[IEEE80211_TTLM_NUM_TIDS];
|
||||
u16 uplink[IEEE80211_TTLM_NUM_TIDS];
|
||||
bool valid;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_neg_ttlm_res - return value for negotiated TTLM handling
|
||||
* @NEG_TTLM_RES_ACCEPT: accept the request
|
||||
* @NEG_TTLM_RES_REJECT: reject the request
|
||||
* @NEG_TTLM_RES_SUGGEST_PREFERRED: reject and suggest a new mapping
|
||||
*/
|
||||
enum ieee80211_neg_ttlm_res {
|
||||
NEG_TTLM_RES_ACCEPT,
|
||||
NEG_TTLM_RES_REJECT,
|
||||
NEG_TTLM_RES_SUGGEST_PREFERRED
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_vif - per-interface data
|
||||
*
|
||||
@ -1863,6 +1894,11 @@ struct ieee80211_vif_cfg {
|
||||
* API calls meant for that purpose.
|
||||
* @dormant_links: bitmap of valid but disabled links, or 0 for non-MLO.
|
||||
* Must be a subset of valid_links.
|
||||
* @suspended_links: subset of dormant_links representing links that are
|
||||
* suspended.
|
||||
* 0 for non-MLO.
|
||||
* @neg_ttlm: negotiated TID to link mapping info.
|
||||
* see &struct ieee80211_neg_ttlm.
|
||||
* @addr: address of this interface
|
||||
* @p2p: indicates whether this AP or STA interface is a p2p
|
||||
* interface, i.e. a GO or p2p-sta respectively
|
||||
@ -1900,7 +1936,8 @@ struct ieee80211_vif {
|
||||
struct ieee80211_vif_cfg cfg;
|
||||
struct ieee80211_bss_conf bss_conf;
|
||||
struct ieee80211_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||
u16 valid_links, active_links, dormant_links;
|
||||
u16 valid_links, active_links, dormant_links, suspended_links;
|
||||
struct ieee80211_neg_ttlm neg_ttlm;
|
||||
u8 addr[ETH_ALEN] __aligned(2);
|
||||
bool p2p;
|
||||
|
||||
@ -4293,6 +4330,10 @@ struct ieee80211_prep_tx_info {
|
||||
* flow offloading for flows originating from the vif.
|
||||
* Note that the driver must not assume that the vif driver_data is valid
|
||||
* at this point, since the callback can be called during netdev teardown.
|
||||
* @can_neg_ttlm: for managed interface, requests the driver to determine
|
||||
* if the requested TID-To-Link mapping can be accepted or not.
|
||||
* If it's not accepted the driver may suggest a preferred mapping and
|
||||
* modify @ttlm parameter with the suggested TID-to-Link mapping.
|
||||
*/
|
||||
struct ieee80211_ops {
|
||||
void (*tx)(struct ieee80211_hw *hw,
|
||||
@ -4673,6 +4714,9 @@ struct ieee80211_ops {
|
||||
struct net_device *dev,
|
||||
enum tc_setup_type type,
|
||||
void *type_data);
|
||||
enum ieee80211_neg_ttlm_res
|
||||
(*can_neg_ttlm)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_neg_ttlm *ttlm);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1695,4 +1695,23 @@ int drv_change_sta_links(struct ieee80211_local *local,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 old_links, u16 new_links);
|
||||
|
||||
static inline enum ieee80211_neg_ttlm_res
|
||||
drv_can_neg_ttlm(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_neg_ttlm *neg_ttlm)
|
||||
{
|
||||
enum ieee80211_neg_ttlm_res res = NEG_TTLM_RES_REJECT;
|
||||
|
||||
might_sleep();
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return -EIO;
|
||||
|
||||
trace_drv_can_neg_ttlm(local, sdata, neg_ttlm);
|
||||
if (local->ops->can_neg_ttlm)
|
||||
res = local->ops->can_neg_ttlm(&local->hw, &sdata->vif,
|
||||
neg_ttlm);
|
||||
trace_drv_neg_ttlm_res(local, sdata, res, neg_ttlm);
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
|
@ -2603,6 +2603,8 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
const struct ieee80211_eht_cap_elem *eht_cap_ie_elem,
|
||||
u8 eht_cap_len,
|
||||
struct link_sta_info *link_sta);
|
||||
void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len);
|
||||
|
||||
void ieee80211_check_wbrf_support(struct ieee80211_local *local);
|
||||
void ieee80211_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef);
|
||||
|
@ -1546,6 +1546,18 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (ieee80211_is_action(mgmt->frame_control) &&
|
||||
mgmt->u.action.category == WLAN_CATEGORY_PROTECTED_EHT) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
switch (mgmt->u.action.u.ttlm_req.action_code) {
|
||||
case WLAN_PROTECTED_EHT_ACTION_TTLM_REQ:
|
||||
ieee80211_process_neg_ttlm_req(sdata, mgmt,
|
||||
skb->len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (ieee80211_is_ext(mgmt->frame_control)) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_sta_rx_queued_ext(sdata, skb);
|
||||
|
@ -208,7 +208,8 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
|
||||
BSS_CHANGED_IBSS |\
|
||||
BSS_CHANGED_ARP_FILTER |\
|
||||
BSS_CHANGED_SSID |\
|
||||
BSS_CHANGED_MLD_VALID_LINKS)
|
||||
BSS_CHANGED_MLD_VALID_LINKS |\
|
||||
BSS_CHANGED_MLD_TTLM)
|
||||
|
||||
void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
u64 changed)
|
||||
|
@ -1318,8 +1318,6 @@ static void ieee80211_assoc_add_ml_elem(struct ieee80211_sub_if_data *sdata,
|
||||
cpu_to_le16(IEEE80211_MLC_BASIC_PRES_EML_CAPA);
|
||||
skb_put_data(skb, &eml_capa, sizeof(eml_capa));
|
||||
}
|
||||
/* need indication from userspace to support this */
|
||||
mld_capa_ops &= ~cpu_to_le16(IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP);
|
||||
skb_put_data(skb, &mld_capa_ops, sizeof(mld_capa_ops));
|
||||
|
||||
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
|
||||
@ -5890,6 +5888,56 @@ static void ieee80211_ml_reconfiguration(struct ieee80211_sub_if_data *sdata,
|
||||
TU_TO_JIFFIES(delay));
|
||||
}
|
||||
|
||||
static int ieee80211_ttlm_set_links(struct ieee80211_sub_if_data *sdata,
|
||||
u16 active_links, u16 dormant_links,
|
||||
u16 suspended_links)
|
||||
{
|
||||
u64 changed = 0;
|
||||
int ret;
|
||||
|
||||
if (!active_links) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If there is an active negotiated TTLM, it should be discarded by
|
||||
* the new negotiated/advertised TTLM.
|
||||
*/
|
||||
if (sdata->vif.neg_ttlm.valid) {
|
||||
memset(&sdata->vif.neg_ttlm, 0, sizeof(sdata->vif.neg_ttlm));
|
||||
sdata->vif.suspended_links = 0;
|
||||
changed = BSS_CHANGED_MLD_TTLM;
|
||||
}
|
||||
|
||||
if (sdata->vif.active_links != active_links) {
|
||||
ret = ieee80211_set_active_links(&sdata->vif, active_links);
|
||||
if (ret) {
|
||||
sdata_info(sdata, "Failed to set TTLM active links\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ieee80211_vif_set_links(sdata, sdata->vif.valid_links,
|
||||
dormant_links);
|
||||
if (ret) {
|
||||
sdata_info(sdata, "Failed to set TTLM dormant links\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
changed |= BSS_CHANGED_MLD_VALID_LINKS;
|
||||
sdata->vif.suspended_links = suspended_links;
|
||||
if (sdata->vif.suspended_links)
|
||||
changed |= BSS_CHANGED_MLD_TTLM;
|
||||
|
||||
ieee80211_vif_cfg_change_notify(sdata, changed);
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
ieee80211_disconnect(&sdata->vif, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ieee80211_tid_to_link_map_work(struct wiphy *wiphy,
|
||||
struct wiphy_work *work)
|
||||
{
|
||||
@ -5897,30 +5945,19 @@ static void ieee80211_tid_to_link_map_work(struct wiphy *wiphy,
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
container_of(work, struct ieee80211_sub_if_data,
|
||||
u.mgd.ttlm_work.work);
|
||||
int ret;
|
||||
|
||||
new_active_links = sdata->u.mgd.ttlm_info.map &
|
||||
sdata->vif.valid_links;
|
||||
new_dormant_links = ~sdata->u.mgd.ttlm_info.map &
|
||||
sdata->vif.valid_links;
|
||||
if (!new_active_links) {
|
||||
ieee80211_disconnect(&sdata->vif, false);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_vif_set_links(sdata, sdata->vif.valid_links, 0);
|
||||
new_active_links = BIT(ffs(new_active_links) - 1);
|
||||
ieee80211_set_active_links(&sdata->vif, new_active_links);
|
||||
|
||||
ret = ieee80211_vif_set_links(sdata, sdata->vif.valid_links,
|
||||
new_dormant_links);
|
||||
if (ieee80211_ttlm_set_links(sdata, new_active_links, new_dormant_links,
|
||||
0))
|
||||
return;
|
||||
|
||||
sdata->u.mgd.ttlm_info.active = true;
|
||||
sdata->u.mgd.ttlm_info.switch_time = 0;
|
||||
|
||||
if (!ret)
|
||||
ieee80211_vif_cfg_change_notify(sdata,
|
||||
BSS_CHANGED_MLD_VALID_LINKS);
|
||||
}
|
||||
|
||||
static u16 ieee80211_get_ttlm(u8 bm_size, u8 *data)
|
||||
@ -6437,6 +6474,272 @@ free:
|
||||
kfree(elems);
|
||||
}
|
||||
|
||||
static void ieee80211_apply_neg_ttlm(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_neg_ttlm neg_ttlm)
|
||||
{
|
||||
u16 new_active_links, new_dormant_links, new_suspended_links, map = 0;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++)
|
||||
map |= neg_ttlm.downlink[i] | neg_ttlm.uplink[i];
|
||||
|
||||
/* If there is an active TTLM, unset previously suspended links */
|
||||
if (sdata->vif.neg_ttlm.valid)
|
||||
sdata->vif.dormant_links &= ~sdata->vif.suspended_links;
|
||||
|
||||
/* exclude links that are already disabled by advertised TTLM */
|
||||
new_active_links =
|
||||
map & sdata->vif.valid_links & ~sdata->vif.dormant_links;
|
||||
new_suspended_links =
|
||||
(~map & sdata->vif.valid_links) & ~sdata->vif.dormant_links;
|
||||
new_dormant_links = sdata->vif.dormant_links | new_suspended_links;
|
||||
if (ieee80211_ttlm_set_links(sdata, new_active_links,
|
||||
new_dormant_links, new_suspended_links))
|
||||
return;
|
||||
|
||||
sdata->vif.neg_ttlm = neg_ttlm;
|
||||
sdata->vif.neg_ttlm.valid = true;
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_neg_ttlm_add_suggested_map(struct sk_buff *skb,
|
||||
struct ieee80211_neg_ttlm *neg_ttlm)
|
||||
{
|
||||
u8 i, direction[IEEE80211_TTLM_MAX_CNT];
|
||||
|
||||
if (memcmp(neg_ttlm->downlink, neg_ttlm->uplink,
|
||||
sizeof(neg_ttlm->downlink))) {
|
||||
direction[0] = IEEE80211_TTLM_DIRECTION_DOWN;
|
||||
direction[1] = IEEE80211_TTLM_DIRECTION_UP;
|
||||
} else {
|
||||
direction[0] = IEEE80211_TTLM_DIRECTION_BOTH;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(direction); i++) {
|
||||
u8 tid, len, map_ind = 0, *len_pos, *map_ind_pos, *pos;
|
||||
__le16 map;
|
||||
|
||||
len = sizeof(struct ieee80211_ttlm_elem) + 1 + 1;
|
||||
|
||||
pos = skb_put(skb, len + 2);
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
len_pos = pos++;
|
||||
*pos++ = WLAN_EID_EXT_TID_TO_LINK_MAPPING;
|
||||
*pos++ = direction[i];
|
||||
map_ind_pos = pos++;
|
||||
for (tid = 0; tid < IEEE80211_TTLM_NUM_TIDS; tid++) {
|
||||
map = direction[i] == IEEE80211_TTLM_DIRECTION_UP ?
|
||||
cpu_to_le16(neg_ttlm->uplink[tid]) :
|
||||
cpu_to_le16(neg_ttlm->downlink[tid]);
|
||||
if (!map)
|
||||
continue;
|
||||
|
||||
len += 2;
|
||||
map_ind |= BIT(tid);
|
||||
skb_put_data(skb, &map, sizeof(map));
|
||||
}
|
||||
|
||||
*map_ind_pos = map_ind;
|
||||
*len_pos = len;
|
||||
|
||||
if (direction[i] == IEEE80211_TTLM_DIRECTION_BOTH)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_send_neg_ttlm_res(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_neg_ttlm_res ttlm_res,
|
||||
u8 dialog_token,
|
||||
struct ieee80211_neg_ttlm *neg_ttlm)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
struct sk_buff *skb;
|
||||
int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.ttlm_res);
|
||||
int ttlm_max_len = 2 + 1 + sizeof(struct ieee80211_ttlm_elem) + 1 +
|
||||
2 * 2 * IEEE80211_TTLM_NUM_TIDS;
|
||||
|
||||
skb = dev_alloc_skb(local->tx_headroom + hdr_len + ttlm_max_len);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
skb_reserve(skb, local->tx_headroom);
|
||||
mgmt = skb_put_zero(skb, hdr_len);
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
memcpy(mgmt->da, sdata->vif.cfg.ap_addr, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, sdata->vif.cfg.ap_addr, ETH_ALEN);
|
||||
|
||||
mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT;
|
||||
mgmt->u.action.u.ttlm_res.action_code =
|
||||
WLAN_PROTECTED_EHT_ACTION_TTLM_RES;
|
||||
mgmt->u.action.u.ttlm_res.dialog_token = dialog_token;
|
||||
switch (ttlm_res) {
|
||||
default:
|
||||
WARN_ON(1);
|
||||
fallthrough;
|
||||
case NEG_TTLM_RES_REJECT:
|
||||
mgmt->u.action.u.ttlm_res.status_code =
|
||||
WLAN_STATUS_DENIED_TID_TO_LINK_MAPPING;
|
||||
break;
|
||||
case NEG_TTLM_RES_ACCEPT:
|
||||
mgmt->u.action.u.ttlm_res.status_code = WLAN_STATUS_SUCCESS;
|
||||
break;
|
||||
case NEG_TTLM_RES_SUGGEST_PREFERRED:
|
||||
mgmt->u.action.u.ttlm_res.status_code =
|
||||
WLAN_STATUS_PREF_TID_TO_LINK_MAPPING_SUGGESTED;
|
||||
ieee80211_neg_ttlm_add_suggested_map(skb, neg_ttlm);
|
||||
break;
|
||||
}
|
||||
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
static int
|
||||
ieee80211_parse_neg_ttlm(struct ieee80211_sub_if_data *sdata,
|
||||
const struct ieee80211_ttlm_elem *ttlm,
|
||||
struct ieee80211_neg_ttlm *neg_ttlm,
|
||||
u8 *direction)
|
||||
{
|
||||
u8 control, link_map_presence, map_size, tid;
|
||||
u8 *pos;
|
||||
|
||||
/* The element size was already validated in
|
||||
* ieee80211_tid_to_link_map_size_ok()
|
||||
*/
|
||||
pos = (void *)ttlm->optional;
|
||||
|
||||
control = ttlm->control;
|
||||
|
||||
/* mapping switch time and expected duration fields are not expected
|
||||
* in case of negotiated TTLM
|
||||
*/
|
||||
if (control & (IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT |
|
||||
IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT)) {
|
||||
mlme_dbg(sdata,
|
||||
"Invalid TTLM element in negotiated TTLM request\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP) {
|
||||
for (tid = 0; tid < IEEE80211_TTLM_NUM_TIDS; tid++) {
|
||||
neg_ttlm->downlink[tid] = sdata->vif.valid_links;
|
||||
neg_ttlm->uplink[tid] = sdata->vif.valid_links;
|
||||
}
|
||||
*direction = IEEE80211_TTLM_DIRECTION_BOTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*direction = u8_get_bits(control, IEEE80211_TTLM_CONTROL_DIRECTION);
|
||||
if (*direction != IEEE80211_TTLM_DIRECTION_DOWN &&
|
||||
*direction != IEEE80211_TTLM_DIRECTION_UP &&
|
||||
*direction != IEEE80211_TTLM_DIRECTION_BOTH)
|
||||
return -EINVAL;
|
||||
|
||||
link_map_presence = *pos;
|
||||
pos++;
|
||||
|
||||
if (control & IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE)
|
||||
map_size = 1;
|
||||
else
|
||||
map_size = 2;
|
||||
|
||||
for (tid = 0; tid < IEEE80211_TTLM_NUM_TIDS; tid++) {
|
||||
u16 map;
|
||||
|
||||
if (link_map_presence & BIT(tid)) {
|
||||
map = ieee80211_get_ttlm(map_size, pos);
|
||||
if (!map) {
|
||||
mlme_dbg(sdata,
|
||||
"No active links for TID %d", tid);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
map = 0;
|
||||
}
|
||||
|
||||
switch (*direction) {
|
||||
case IEEE80211_TTLM_DIRECTION_BOTH:
|
||||
neg_ttlm->downlink[tid] = map;
|
||||
neg_ttlm->uplink[tid] = map;
|
||||
break;
|
||||
case IEEE80211_TTLM_DIRECTION_DOWN:
|
||||
neg_ttlm->downlink[tid] = map;
|
||||
break;
|
||||
case IEEE80211_TTLM_DIRECTION_UP:
|
||||
neg_ttlm->uplink[tid] = map;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
pos += map_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
u8 dialog_token, direction[IEEE80211_TTLM_MAX_CNT] = {}, i;
|
||||
size_t ies_len;
|
||||
enum ieee80211_neg_ttlm_res ttlm_res = NEG_TTLM_RES_ACCEPT;
|
||||
struct ieee802_11_elems *elems = NULL;
|
||||
struct ieee80211_neg_ttlm neg_ttlm = {};
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(direction) != ARRAY_SIZE(elems->ttlm));
|
||||
|
||||
if (!ieee80211_vif_is_mld(&sdata->vif))
|
||||
return;
|
||||
|
||||
dialog_token = mgmt->u.action.u.ttlm_req.dialog_token;
|
||||
ies_len = len - offsetof(struct ieee80211_mgmt,
|
||||
u.action.u.ttlm_req.variable);
|
||||
elems = ieee802_11_parse_elems(mgmt->u.action.u.ttlm_req.variable,
|
||||
ies_len, true, NULL);
|
||||
if (!elems) {
|
||||
ttlm_res = NEG_TTLM_RES_REJECT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < elems->ttlm_num; i++) {
|
||||
if (ieee80211_parse_neg_ttlm(sdata, elems->ttlm[i],
|
||||
&neg_ttlm, &direction[i]) ||
|
||||
(direction[i] == IEEE80211_TTLM_DIRECTION_BOTH &&
|
||||
elems->ttlm_num != 1)) {
|
||||
ttlm_res = NEG_TTLM_RES_REJECT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!elems->ttlm_num ||
|
||||
(elems->ttlm_num == 2 && direction[0] == direction[1])) {
|
||||
ttlm_res = NEG_TTLM_RES_REJECT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) {
|
||||
if ((neg_ttlm.downlink[i] &&
|
||||
(neg_ttlm.downlink[i] & ~sdata->vif.valid_links)) ||
|
||||
(neg_ttlm.uplink[i] &&
|
||||
(neg_ttlm.uplink[i] & ~sdata->vif.valid_links))) {
|
||||
ttlm_res = NEG_TTLM_RES_REJECT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ttlm_res = drv_can_neg_ttlm(sdata->local, sdata, &neg_ttlm);
|
||||
|
||||
if (ttlm_res != NEG_TTLM_RES_ACCEPT)
|
||||
goto out;
|
||||
|
||||
ieee80211_apply_neg_ttlm(sdata, neg_ttlm);
|
||||
out:
|
||||
kfree(elems);
|
||||
ieee80211_send_neg_ttlm_res(sdata, ttlm_res, dialog_token, &neg_ttlm);
|
||||
}
|
||||
|
||||
void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -3763,6 +3763,20 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WLAN_CATEGORY_PROTECTED_EHT:
|
||||
switch (mgmt->u.action.u.ttlm_req.action_code) {
|
||||
case WLAN_PROTECTED_EHT_ACTION_TTLM_REQ:
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
break;
|
||||
|
||||
if (len < offsetofend(typeof(*mgmt),
|
||||
u.action.u.ttlm_req))
|
||||
goto invalid;
|
||||
goto queue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return RX_CONTINUE;
|
||||
|
@ -3088,6 +3088,58 @@ TRACE_EVENT(stop_queue,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_can_neg_ttlm,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_neg_ttlm *neg_ttlm),
|
||||
|
||||
TP_ARGS(local, sdata, neg_ttlm),
|
||||
|
||||
TP_STRUCT__entry(LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__array(u16, downlink, sizeof(u16) * 8)
|
||||
__array(u16, uplink, sizeof(u16) * 8)
|
||||
),
|
||||
|
||||
TP_fast_assign(LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
memcpy(__entry->downlink, neg_ttlm->downlink,
|
||||
sizeof(neg_ttlm->downlink));
|
||||
memcpy(__entry->uplink, neg_ttlm->uplink,
|
||||
sizeof(neg_ttlm->uplink));
|
||||
),
|
||||
|
||||
TP_printk(LOCAL_PR_FMT ", " VIF_PR_FMT, LOCAL_PR_ARG, VIF_PR_ARG)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_neg_ttlm_res,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_neg_ttlm_res res,
|
||||
struct ieee80211_neg_ttlm *neg_ttlm),
|
||||
|
||||
TP_ARGS(local, sdata, res, neg_ttlm),
|
||||
|
||||
TP_STRUCT__entry(LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(u32, res)
|
||||
__array(u16, downlink, sizeof(u16) * 8)
|
||||
__array(u16, uplink, sizeof(u16) * 8)
|
||||
),
|
||||
|
||||
TP_fast_assign(LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->res = res;
|
||||
memcpy(__entry->downlink, neg_ttlm->downlink,
|
||||
sizeof(neg_ttlm->downlink));
|
||||
memcpy(__entry->uplink, neg_ttlm->uplink,
|
||||
sizeof(neg_ttlm->uplink));
|
||||
),
|
||||
|
||||
TP_printk(LOCAL_PR_FMT VIF_PR_FMT " response: %d\n ",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, __entry->res
|
||||
)
|
||||
);
|
||||
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
|
Loading…
Reference in New Issue
Block a user