Commit f7660b3f authored by Ayala Beker's avatar Ayala Beker Committed by Johannes Berg

wifi: mac80211: add support for negotiated TTLM request

Update neg_ttlm and active_links according to the new mapping,
and send a negotiated TID-to-link map request with the new mapping.
Signed-off-by: default avatarAyala Beker <ayala.beker@intel.com>
Reviewed-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Reviewed-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarMiri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://msgid.link/20240102213313.eeb385d771df.I2a5441c14421de884dbd93d1624ce7bb2c944833@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 9362fabc
...@@ -5024,6 +5024,43 @@ static inline u16 ieee80211_mle_get_eml_cap(const u8 *data) ...@@ -5024,6 +5024,43 @@ static inline u16 ieee80211_mle_get_eml_cap(const u8 *data)
return get_unaligned_le16(common); return get_unaligned_le16(common);
} }
/**
* ieee80211_mle_get_mld_capa_op - returns the MLD capabilities and operations.
* @data: pointer to the multi link EHT IE
*
* The element is assumed to be of the correct type (BASIC) and big enough,
* this must be checked using ieee80211_mle_type_ok().
*
* If the MLD capabilities and operations field is not present, 0 will be
* returned.
*/
static inline u16 ieee80211_mle_get_mld_capa_op(const u8 *data)
{
const struct ieee80211_multi_link_elem *mle = (const void *)data;
u16 control = le16_to_cpu(mle->control);
const u8 *common = mle->variable;
/*
* common points now at the beginning of
* ieee80211_mle_basic_common_info
*/
common += sizeof(struct ieee80211_mle_basic_common_info);
if (!(control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP))
return 0;
if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID)
common += 1;
if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)
common += 1;
if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)
common += 2;
if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA)
common += 2;
return get_unaligned_le16(common);
}
/** /**
* ieee80211_mle_size_ok - validate multi-link element size * ieee80211_mle_size_ok - validate multi-link element size
* @data: pointer to the element data * @data: pointer to the element data
......
...@@ -1810,9 +1810,11 @@ enum ieee80211_offload_flags { ...@@ -1810,9 +1810,11 @@ enum ieee80211_offload_flags {
* @ps: power-save mode (STA only). This flag is NOT affected by * @ps: power-save mode (STA only). This flag is NOT affected by
* offchannel/dynamic_ps operations. * offchannel/dynamic_ps operations.
* @aid: association ID number, valid only when @assoc is true * @aid: association ID number, valid only when @assoc is true
* @eml_cap: EML capabilities as described in P802.11be_D2.2 Figure 9-1002k. * @eml_cap: EML capabilities as described in P802.11be_D4.1 Figure 9-1001j.
* @eml_med_sync_delay: Medium Synchronization delay as described in * @eml_med_sync_delay: Medium Synchronization delay as described in
* P802.11be_D2.2 Figure 9-1002j. * P802.11be_D4.1 Figure 9-1001i.
* @mld_capa_op: MLD Capabilities and Operations per P802.11be_D4.1
* Figure 9-1001k
* @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
* may filter ARP queries targeted for other addresses than listed here. * may filter ARP queries targeted for other addresses than listed here.
* The driver must allow ARP queries targeted for all address listed here * The driver must allow ARP queries targeted for all address listed here
...@@ -1837,6 +1839,7 @@ struct ieee80211_vif_cfg { ...@@ -1837,6 +1839,7 @@ struct ieee80211_vif_cfg {
u16 aid; u16 aid;
u16 eml_cap; u16 eml_cap;
u16 eml_med_sync_delay; u16 eml_med_sync_delay;
u16 mld_capa_op;
__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
int arp_addr_cnt; int arp_addr_cnt;
......
...@@ -4966,6 +4966,17 @@ static int ieee80211_set_hw_timestamp(struct wiphy *wiphy, ...@@ -4966,6 +4966,17 @@ static int ieee80211_set_hw_timestamp(struct wiphy *wiphy,
return local->ops->set_hw_timestamp(&local->hw, &sdata->vif, hwts); return local->ops->set_hw_timestamp(&local->hw, &sdata->vif, hwts);
} }
static int
ieee80211_set_ttlm(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ttlm_params *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
lockdep_assert_wiphy(sdata->local->hw.wiphy);
return ieee80211_req_neg_ttlm(sdata, params);
}
const struct cfg80211_ops mac80211_config_ops = { const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface, .add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface, .del_virtual_intf = ieee80211_del_iface,
...@@ -5078,4 +5089,5 @@ const struct cfg80211_ops mac80211_config_ops = { ...@@ -5078,4 +5089,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.mod_link_station = ieee80211_mod_link_station, .mod_link_station = ieee80211_mod_link_station,
.del_link_station = ieee80211_del_link_station, .del_link_station = ieee80211_del_link_station,
.set_hw_timestamp = ieee80211_set_hw_timestamp, .set_hw_timestamp = ieee80211_set_hw_timestamp,
.set_ttlm = ieee80211_set_ttlm,
}; };
...@@ -579,6 +579,10 @@ struct ieee80211_if_managed { ...@@ -579,6 +579,10 @@ struct ieee80211_if_managed {
/* TID-to-link mapping support */ /* TID-to-link mapping support */
struct wiphy_delayed_work ttlm_work; struct wiphy_delayed_work ttlm_work;
struct ieee80211_adv_ttlm_info ttlm_info; struct ieee80211_adv_ttlm_info ttlm_info;
/* dialog token enumerator for neg TTLM request */
u8 dialog_token_alloc;
struct wiphy_delayed_work neg_ttlm_timeout_work;
}; };
struct ieee80211_if_ibss { struct ieee80211_if_ibss {
...@@ -2605,6 +2609,10 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, ...@@ -2605,6 +2609,10 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
struct link_sta_info *link_sta); struct link_sta_info *link_sta);
void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata, void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len); struct ieee80211_mgmt *mgmt, size_t len);
void ieee80211_process_neg_ttlm_res(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len);
int ieee80211_req_neg_ttlm(struct ieee80211_sub_if_data *sdata,
struct cfg80211_ttlm_params *params);
void ieee80211_check_wbrf_support(struct ieee80211_local *local); void ieee80211_check_wbrf_support(struct ieee80211_local *local);
void ieee80211_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef); void ieee80211_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef);
......
...@@ -1554,6 +1554,10 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local, ...@@ -1554,6 +1554,10 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
ieee80211_process_neg_ttlm_req(sdata, mgmt, ieee80211_process_neg_ttlm_req(sdata, mgmt,
skb->len); skb->len);
break; break;
case WLAN_PROTECTED_EHT_ACTION_TTLM_RES:
ieee80211_process_neg_ttlm_res(sdata, mgmt,
skb->len);
break;
default: default:
break; break;
} }
......
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
#define IEEE80211_ADV_TTLM_SAFETY_BUFFER_MS msecs_to_jiffies(100) #define IEEE80211_ADV_TTLM_SAFETY_BUFFER_MS msecs_to_jiffies(100)
#define IEEE80211_ADV_TTLM_ST_UNDERFLOW 0xff00 #define IEEE80211_ADV_TTLM_ST_UNDERFLOW 0xff00
#define IEEE80211_NEG_TTLM_REQ_TIMEOUT (HZ / 5)
static int max_nullfunc_tries = 2; static int max_nullfunc_tries = 2;
module_param(max_nullfunc_tries, int, 0644); module_param(max_nullfunc_tries, int, 0644);
MODULE_PARM_DESC(max_nullfunc_tries, MODULE_PARM_DESC(max_nullfunc_tries,
...@@ -3087,6 +3089,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ...@@ -3087,6 +3089,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
memset(&sdata->u.mgd.ttlm_info, 0, memset(&sdata->u.mgd.ttlm_info, 0,
sizeof(sdata->u.mgd.ttlm_info)); sizeof(sdata->u.mgd.ttlm_info));
wiphy_delayed_work_cancel(sdata->local->hw.wiphy, &ifmgd->ttlm_work); wiphy_delayed_work_cancel(sdata->local->hw.wiphy, &ifmgd->ttlm_work);
wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
&ifmgd->neg_ttlm_timeout_work);
ieee80211_vif_set_links(sdata, 0, 0); ieee80211_vif_set_links(sdata, 0, 0);
} }
...@@ -4984,6 +4988,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, ...@@ -4984,6 +4988,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
ieee80211_mle_get_eml_cap(eht_ml_elem->data + 1); ieee80211_mle_get_eml_cap(eht_ml_elem->data + 1);
sdata->vif.cfg.eml_med_sync_delay = sdata->vif.cfg.eml_med_sync_delay =
ieee80211_mle_get_eml_med_sync_delay(eht_ml_elem->data + 1); ieee80211_mle_get_eml_med_sync_delay(eht_ml_elem->data + 1);
sdata->vif.cfg.mld_capa_op =
ieee80211_mle_get_mld_capa_op(eht_ml_elem->data + 1);
} }
} }
...@@ -6501,6 +6507,19 @@ static void ieee80211_apply_neg_ttlm(struct ieee80211_sub_if_data *sdata, ...@@ -6501,6 +6507,19 @@ static void ieee80211_apply_neg_ttlm(struct ieee80211_sub_if_data *sdata,
sdata->vif.neg_ttlm.valid = true; sdata->vif.neg_ttlm.valid = true;
} }
static void ieee80211_neg_ttlm_timeout_work(struct wiphy *wiphy,
struct wiphy_work *work)
{
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data,
u.mgd.neg_ttlm_timeout_work.work);
sdata_info(sdata,
"No negotiated TTLM response from AP, disconnecting.\n");
__ieee80211_disconnect(sdata);
}
static void static void
ieee80211_neg_ttlm_add_suggested_map(struct sk_buff *skb, ieee80211_neg_ttlm_add_suggested_map(struct sk_buff *skb,
struct ieee80211_neg_ttlm *neg_ttlm) struct ieee80211_neg_ttlm *neg_ttlm)
...@@ -6547,6 +6566,74 @@ ieee80211_neg_ttlm_add_suggested_map(struct sk_buff *skb, ...@@ -6547,6 +6566,74 @@ ieee80211_neg_ttlm_add_suggested_map(struct sk_buff *skb,
} }
} }
static void
ieee80211_send_neg_ttlm_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_neg_ttlm *neg_ttlm,
u8 dialog_token)
{
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_req);
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_req.action_code =
WLAN_PROTECTED_EHT_ACTION_TTLM_REQ;
mgmt->u.action.u.ttlm_req.dialog_token = dialog_token;
ieee80211_neg_ttlm_add_suggested_map(skb, neg_ttlm);
ieee80211_tx_skb(sdata, skb);
}
int ieee80211_req_neg_ttlm(struct ieee80211_sub_if_data *sdata,
struct cfg80211_ttlm_params *params)
{
struct ieee80211_neg_ttlm neg_ttlm = {};
u8 i;
if (!ieee80211_vif_is_mld(&sdata->vif) ||
!(sdata->vif.cfg.mld_capa_op &
IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP))
return -EINVAL;
for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) {
if ((params->dlink[i] & ~sdata->vif.valid_links) ||
(params->ulink[i] & ~sdata->vif.valid_links))
return -EINVAL;
neg_ttlm.downlink[i] = params->dlink[i];
neg_ttlm.uplink[i] = params->ulink[i];
}
if (drv_can_neg_ttlm(sdata->local, sdata, &neg_ttlm) !=
NEG_TTLM_RES_ACCEPT)
return -EINVAL;
ieee80211_apply_neg_ttlm(sdata, neg_ttlm);
sdata->u.mgd.dialog_token_alloc++;
ieee80211_send_neg_ttlm_req(sdata, &sdata->vif.neg_ttlm,
sdata->u.mgd.dialog_token_alloc);
wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
&sdata->u.mgd.neg_ttlm_timeout_work);
wiphy_delayed_work_queue(sdata->local->hw.wiphy,
&sdata->u.mgd.neg_ttlm_timeout_work,
IEEE80211_NEG_TTLM_REQ_TIMEOUT);
return 0;
}
static void static void
ieee80211_send_neg_ttlm_res(struct ieee80211_sub_if_data *sdata, ieee80211_send_neg_ttlm_res(struct ieee80211_sub_if_data *sdata,
enum ieee80211_neg_ttlm_res ttlm_res, enum ieee80211_neg_ttlm_res ttlm_res,
...@@ -6740,6 +6827,29 @@ void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata, ...@@ -6740,6 +6827,29 @@ void ieee80211_process_neg_ttlm_req(struct ieee80211_sub_if_data *sdata,
ieee80211_send_neg_ttlm_res(sdata, ttlm_res, dialog_token, &neg_ttlm); ieee80211_send_neg_ttlm_res(sdata, ttlm_res, dialog_token, &neg_ttlm);
} }
void ieee80211_process_neg_ttlm_res(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len)
{
if (!ieee80211_vif_is_mld(&sdata->vif) ||
mgmt->u.action.u.ttlm_req.dialog_token !=
sdata->u.mgd.dialog_token_alloc)
return;
wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
&sdata->u.mgd.neg_ttlm_timeout_work);
/* MLD station sends a TID to link mapping request, mainly to handle
* BTM (BSS transition management) request, in which case it needs to
* restrict the active links set.
* In this case it's not expected that the MLD AP will reject the
* negotiated TTLM request.
* This can be better implemented in the future, to handle request
* rejections.
*/
if (mgmt->u.action.u.ttlm_res.status_code != WLAN_STATUS_SUCCESS)
__ieee80211_disconnect(sdata);
}
void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -7369,6 +7479,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) ...@@ -7369,6 +7479,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ieee80211_sta_handle_tspec_ac_params_wk); ieee80211_sta_handle_tspec_ac_params_wk);
wiphy_delayed_work_init(&ifmgd->ttlm_work, wiphy_delayed_work_init(&ifmgd->ttlm_work,
ieee80211_tid_to_link_map_work); ieee80211_tid_to_link_map_work);
wiphy_delayed_work_init(&ifmgd->neg_ttlm_timeout_work,
ieee80211_neg_ttlm_timeout_work);
ifmgd->flags = 0; ifmgd->flags = 0;
ifmgd->powersave = sdata->wdev.ps; ifmgd->powersave = sdata->wdev.ps;
...@@ -8459,6 +8571,8 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) ...@@ -8459,6 +8571,8 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
wiphy_delayed_work_cancel(sdata->local->hw.wiphy, wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
&ifmgd->ml_reconf_work); &ifmgd->ml_reconf_work);
wiphy_delayed_work_cancel(sdata->local->hw.wiphy, &ifmgd->ttlm_work); wiphy_delayed_work_cancel(sdata->local->hw.wiphy, &ifmgd->ttlm_work);
wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
&ifmgd->neg_ttlm_timeout_work);
if (ifmgd->assoc_data) if (ifmgd->assoc_data)
ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT); ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT);
......
...@@ -3773,6 +3773,14 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) ...@@ -3773,6 +3773,14 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
u.action.u.ttlm_req)) u.action.u.ttlm_req))
goto invalid; goto invalid;
goto queue; goto queue;
case WLAN_PROTECTED_EHT_ACTION_TTLM_RES:
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
if (len < offsetofend(typeof(*mgmt),
u.action.u.ttlm_res))
goto invalid;
goto queue;
default: default:
break; break;
} }
......
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