AP: Support building Basic Multi-Link element
Define a struct to hold MLD station info and implement publishing of the Basic Multi-Link element. Add it into Beacon and Probe Response frames. Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
This commit is contained in:
parent
79a9df6e88
commit
f540d078c9
7 changed files with 296 additions and 0 deletions
|
@ -605,6 +605,14 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||||
buflen += 3 + sizeof(struct ieee80211_eht_operation);
|
buflen += 3 + sizeof(struct ieee80211_eht_operation);
|
||||||
if (hapd->iconf->punct_bitmap)
|
if (hapd->iconf->punct_bitmap)
|
||||||
buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
|
buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Multi-Link element has variable length and can be
|
||||||
|
* long based on the common info and number of per
|
||||||
|
* station profiles. For now use 256.
|
||||||
|
*/
|
||||||
|
if (hapd->conf->mld_ap)
|
||||||
|
buflen += 256;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_IEEE80211BE */
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
|
@ -755,6 +763,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211BE
|
#ifdef CONFIG_IEEE80211BE
|
||||||
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
|
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
|
||||||
|
if (hapd->conf->mld_ap)
|
||||||
|
pos = hostapd_eid_eht_basic_ml(hapd, pos, NULL, true);
|
||||||
pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP);
|
pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP);
|
||||||
pos = hostapd_eid_eht_operation(hapd, pos);
|
pos = hostapd_eid_eht_operation(hapd, pos);
|
||||||
}
|
}
|
||||||
|
@ -1711,6 +1721,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||||
tail_len += 3 + sizeof(struct ieee80211_eht_operation);
|
tail_len += 3 + sizeof(struct ieee80211_eht_operation);
|
||||||
if (hapd->iconf->punct_bitmap)
|
if (hapd->iconf->punct_bitmap)
|
||||||
tail_len += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
|
tail_len += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Multi-Link element has variable length and can be
|
||||||
|
* long based on the common info and number of per
|
||||||
|
* station profiles. For now use 256.
|
||||||
|
*/
|
||||||
|
if (hapd->conf->mld_ap)
|
||||||
|
tail_len += 256;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_IEEE80211BE */
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
|
@ -1881,6 +1899,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211BE
|
#ifdef CONFIG_IEEE80211BE
|
||||||
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
|
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
|
||||||
|
if (hapd->conf->mld_ap)
|
||||||
|
tailpos = hostapd_eid_eht_basic_ml(hapd, tailpos, NULL,
|
||||||
|
true);
|
||||||
tailpos = hostapd_eid_eht_capab(hapd, tailpos,
|
tailpos = hostapd_eid_eht_capab(hapd, tailpos,
|
||||||
IEEE80211_MODE_AP);
|
IEEE80211_MODE_AP);
|
||||||
tailpos = hostapd_eid_eht_operation(hapd, tailpos);
|
tailpos = hostapd_eid_eht_operation(hapd, tailpos);
|
||||||
|
|
|
@ -4260,3 +4260,26 @@ void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_OCV */
|
#endif /* CONFIG_OCV */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211BE
|
||||||
|
struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
|
||||||
|
u8 link_id)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < hapd->iface->interfaces->count; i++) {
|
||||||
|
struct hostapd_iface *h = hapd->iface->interfaces->iface[i];
|
||||||
|
struct hostapd_data *h_hapd = h->bss[0];
|
||||||
|
struct hostapd_bss_config *hconf = h_hapd->conf;
|
||||||
|
|
||||||
|
if (!hconf->mld_ap || hconf->mld_id != hapd->conf->mld_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (h_hapd->mld_link_id == link_id)
|
||||||
|
return h_hapd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
|
@ -764,5 +764,7 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
|
||||||
int hostapd_set_acl(struct hostapd_data *hapd);
|
int hostapd_set_acl(struct hostapd_data *hapd);
|
||||||
struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd);
|
struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd);
|
||||||
int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd);
|
int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd);
|
||||||
|
struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
|
||||||
|
u8 link_id);
|
||||||
|
|
||||||
#endif /* HOSTAPD_H */
|
#endif /* HOSTAPD_H */
|
||||||
|
|
|
@ -84,6 +84,8 @@ void hostapd_get_eht_capab(struct hostapd_data *hapd,
|
||||||
const struct ieee80211_eht_capabilities *src,
|
const struct ieee80211_eht_capabilities *src,
|
||||||
struct ieee80211_eht_capabilities *dest,
|
struct ieee80211_eht_capabilities *dest,
|
||||||
size_t len);
|
size_t len);
|
||||||
|
u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid,
|
||||||
|
struct sta_info *info, bool include_mld_id);
|
||||||
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
|
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
const u8 *ht_capab);
|
const u8 *ht_capab);
|
||||||
|
|
|
@ -417,3 +417,207 @@ void hostapd_get_eht_capab(struct hostapd_data *hapd,
|
||||||
os_memset(dest, 0, sizeof(*dest));
|
os_memset(dest, 0, sizeof(*dest));
|
||||||
os_memcpy(dest, src, len);
|
os_memcpy(dest, src, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid,
|
||||||
|
struct sta_info *info, bool include_mld_id)
|
||||||
|
{
|
||||||
|
struct wpabuf *buf;
|
||||||
|
u16 control;
|
||||||
|
u8 *pos = eid;
|
||||||
|
const u8 *ptr;
|
||||||
|
size_t len, slice_len;
|
||||||
|
u8 link_id;
|
||||||
|
u8 common_info_len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As the Multi-Link element can exceed the size of 255 bytes need to
|
||||||
|
* first build it and then handle fragmentation.
|
||||||
|
*/
|
||||||
|
buf = wpabuf_alloc(1024);
|
||||||
|
if (!buf)
|
||||||
|
return pos;
|
||||||
|
|
||||||
|
/* Multi-Link Control field */
|
||||||
|
control = MULTI_LINK_CONTROL_TYPE_BASIC |
|
||||||
|
BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
|
||||||
|
BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
|
||||||
|
BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA |
|
||||||
|
BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the basic Multi-Link common information. Hard code the common
|
||||||
|
* info length to 13 based on the length of the present fields:
|
||||||
|
* Length (1) + MLD address (6) + Link ID (1) +
|
||||||
|
* BSS Parameters Change Count (1) + EML Capabilities (2) +
|
||||||
|
* MLD Capabilities and Operations (2)
|
||||||
|
*/
|
||||||
|
common_info_len = 13;
|
||||||
|
|
||||||
|
if (include_mld_id) {
|
||||||
|
/* AP MLD ID */
|
||||||
|
control |= BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID;
|
||||||
|
common_info_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpabuf_put_le16(buf, control);
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, common_info_len);
|
||||||
|
|
||||||
|
/* Own MLD MAC Address */
|
||||||
|
wpabuf_put_data(buf, hapd->mld_addr, ETH_ALEN);
|
||||||
|
|
||||||
|
/* Own Link ID */
|
||||||
|
wpabuf_put_u8(buf, hapd->mld_link_id);
|
||||||
|
|
||||||
|
/* Currently hard code the BSS Parameters Change Count to 0x1 */
|
||||||
|
wpabuf_put_u8(buf, 0x1);
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "MLD: EML Capabilities=0x%x",
|
||||||
|
hapd->iface->mld_eml_capa);
|
||||||
|
wpabuf_put_le16(buf, hapd->iface->mld_eml_capa);
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "MLD: MLD Capabilities and Operations=0x%x",
|
||||||
|
hapd->iface->mld_mld_capa);
|
||||||
|
wpabuf_put_le16(buf, hapd->iface->mld_mld_capa);
|
||||||
|
|
||||||
|
if (include_mld_id) {
|
||||||
|
wpa_printf(MSG_DEBUG, "MLD: AP MLD ID=0x%x",
|
||||||
|
hapd->conf->mld_id);
|
||||||
|
wpabuf_put_u8(buf, hapd->conf->mld_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Add link info for the other links */
|
||||||
|
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
|
||||||
|
struct mld_link_info *link = &info->mld_info.links[link_id];
|
||||||
|
struct hostapd_data *link_bss;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* control (2) + station info length (1) + MAC address (6) +
|
||||||
|
* beacon interval (2) + TSF offset (8) + DTIM info (2) + BSS
|
||||||
|
* parameters change counter (1) + station profile length.
|
||||||
|
*/
|
||||||
|
const size_t fixed_len = 22;
|
||||||
|
size_t total_len = fixed_len + link->resp_sta_profile_len;
|
||||||
|
|
||||||
|
/* Skip the local one */
|
||||||
|
if (link_id == hapd->mld_link_id || !link->valid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
link_bss = hostapd_mld_get_link_bss(hapd, link_id);
|
||||||
|
if (!link_bss) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"MLD: Couldn't find link BSS - skip it");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Per-STA Profile subelement */
|
||||||
|
wpabuf_put_u8(buf, EHT_ML_SUB_ELEM_PER_STA_PROFILE);
|
||||||
|
|
||||||
|
if (total_len <= 255)
|
||||||
|
wpabuf_put_u8(buf, total_len);
|
||||||
|
else
|
||||||
|
wpabuf_put_u8(buf, 255);
|
||||||
|
|
||||||
|
/* STA Control */
|
||||||
|
control = (link_id & 0xf) |
|
||||||
|
EHT_PER_STA_CTRL_MAC_ADDR_PRESENT_MSK |
|
||||||
|
EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK |
|
||||||
|
EHT_PER_STA_CTRL_TSF_OFFSET_PRESENT_MSK |
|
||||||
|
EHT_PER_STA_CTRL_BEACON_INTERVAL_PRESENT_MSK |
|
||||||
|
EHT_PER_STA_CTRL_DTIM_INFO_PRESENT_MSK |
|
||||||
|
EHT_PER_STA_CTRL_BSS_PARAM_CNT_PRESENT_MSK;
|
||||||
|
wpabuf_put_le16(buf, control);
|
||||||
|
|
||||||
|
/* STA Info */
|
||||||
|
|
||||||
|
/* STA Info Length */
|
||||||
|
wpabuf_put_u8(buf, fixed_len - 2);
|
||||||
|
wpabuf_put_data(buf, link->local_addr, ETH_ALEN);
|
||||||
|
wpabuf_put_le16(buf, link_bss->iconf->beacon_int);
|
||||||
|
|
||||||
|
/* TSF Offset */
|
||||||
|
/*
|
||||||
|
* TODO: Currently setting TSF offset to zero. However, this
|
||||||
|
* information needs to come from the driver.
|
||||||
|
*/
|
||||||
|
wpabuf_put_le64(buf, 0);
|
||||||
|
|
||||||
|
/* DTIM Info */
|
||||||
|
wpabuf_put_le16(buf, link_bss->conf->dtim_period);
|
||||||
|
|
||||||
|
/* BSS Parameters Change Count */
|
||||||
|
/* TODO: Currently hard code the BSS Parameters Change Count to
|
||||||
|
* 0x1 */
|
||||||
|
wpabuf_put_u8(buf, 0x1);
|
||||||
|
|
||||||
|
/* Fragment the sub element if needed */
|
||||||
|
if (total_len <= 255) {
|
||||||
|
wpabuf_put_data(buf, link->resp_sta_profile,
|
||||||
|
link->resp_sta_profile_len);
|
||||||
|
} else {
|
||||||
|
ptr = link->resp_sta_profile;
|
||||||
|
len = link->resp_sta_profile_len;
|
||||||
|
|
||||||
|
slice_len = 255 - fixed_len;
|
||||||
|
|
||||||
|
wpabuf_put_data(buf, ptr, slice_len);
|
||||||
|
len -= slice_len;
|
||||||
|
ptr += slice_len;
|
||||||
|
|
||||||
|
while (len) {
|
||||||
|
if (len <= 255)
|
||||||
|
slice_len = len;
|
||||||
|
else
|
||||||
|
slice_len = 255;
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, EHT_ML_SUB_ELEM_FRAGMENT);
|
||||||
|
wpabuf_put_u8(buf, slice_len);
|
||||||
|
wpabuf_put_data(buf, ptr, slice_len);
|
||||||
|
|
||||||
|
len -= slice_len;
|
||||||
|
ptr += slice_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
/* Fragment the Multi-Link element, if needed */
|
||||||
|
len = wpabuf_len(buf);
|
||||||
|
ptr = wpabuf_head(buf);
|
||||||
|
|
||||||
|
if (len <= 254)
|
||||||
|
slice_len = len;
|
||||||
|
else
|
||||||
|
slice_len = 254;
|
||||||
|
|
||||||
|
*pos++ = WLAN_EID_EXTENSION;
|
||||||
|
*pos++ = slice_len + 1;
|
||||||
|
*pos++ = WLAN_EID_EXT_MULTI_LINK;
|
||||||
|
os_memcpy(pos, ptr, slice_len);
|
||||||
|
|
||||||
|
ptr += slice_len;
|
||||||
|
pos += slice_len;
|
||||||
|
len -= slice_len;
|
||||||
|
|
||||||
|
while (len) {
|
||||||
|
if (len <= 255)
|
||||||
|
slice_len = len;
|
||||||
|
else
|
||||||
|
slice_len = 255;
|
||||||
|
|
||||||
|
*pos++ = WLAN_EID_FRAGMENT;
|
||||||
|
*pos++ = slice_len;
|
||||||
|
os_memcpy(pos, ptr, slice_len);
|
||||||
|
|
||||||
|
ptr += slice_len;
|
||||||
|
pos += slice_len;
|
||||||
|
len -= slice_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpabuf_free(buf);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
|
@ -69,6 +69,35 @@ struct pending_eapol_rx {
|
||||||
enum frame_encryption encrypted;
|
enum frame_encryption encrypted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define EHT_ML_MAX_STA_PROF_LEN 1024
|
||||||
|
struct mld_info {
|
||||||
|
bool mld_sta;
|
||||||
|
|
||||||
|
struct ml_common_info {
|
||||||
|
u8 mld_addr[ETH_ALEN];
|
||||||
|
u16 medium_sync_delay;
|
||||||
|
u16 eml_capa;
|
||||||
|
u16 mld_capa;
|
||||||
|
} common_info;
|
||||||
|
|
||||||
|
struct mld_link_info {
|
||||||
|
u8 valid;
|
||||||
|
u8 local_addr[ETH_ALEN];
|
||||||
|
u8 peer_addr[ETH_ALEN];
|
||||||
|
|
||||||
|
size_t nstr_bitmap_len;
|
||||||
|
u8 nstr_bitmap[2];
|
||||||
|
|
||||||
|
u16 capability;
|
||||||
|
|
||||||
|
u16 status;
|
||||||
|
size_t resp_sta_profile_len;
|
||||||
|
u8 resp_sta_profile[EHT_ML_MAX_STA_PROF_LEN];
|
||||||
|
|
||||||
|
const u8 *rsne, *rsnxe;
|
||||||
|
} links[MAX_NUM_MLD_LINKS];
|
||||||
|
};
|
||||||
|
|
||||||
struct sta_info {
|
struct sta_info {
|
||||||
struct sta_info *next; /* next entry in sta list */
|
struct sta_info *next; /* next entry in sta list */
|
||||||
struct sta_info *hnext; /* next entry in hash table list */
|
struct sta_info *hnext; /* next entry in hash table list */
|
||||||
|
@ -299,6 +328,11 @@ struct sta_info {
|
||||||
#ifdef CONFIG_PASN
|
#ifdef CONFIG_PASN
|
||||||
struct pasn_data *pasn;
|
struct pasn_data *pasn;
|
||||||
#endif /* CONFIG_PASN */
|
#endif /* CONFIG_PASN */
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211BE
|
||||||
|
struct mld_info mld_info;
|
||||||
|
u8 mld_assoc_link_id;
|
||||||
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2660,6 +2660,16 @@ struct eht_ml_basic_common_info {
|
||||||
#define EHT_ML_MLD_CAPA_FREQ_SEP_FOR_STR_MASK 0x0f80
|
#define EHT_ML_MLD_CAPA_FREQ_SEP_FOR_STR_MASK 0x0f80
|
||||||
#define EHT_ML_MLD_CAPA_AAR_SUPP 0x1000
|
#define EHT_ML_MLD_CAPA_AAR_SUPP 0x1000
|
||||||
|
|
||||||
|
#define EHT_PER_STA_CTRL_LINK_ID_MSK 0x000f
|
||||||
|
#define EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK 0x0010
|
||||||
|
#define EHT_PER_STA_CTRL_MAC_ADDR_PRESENT_MSK 0x0020
|
||||||
|
#define EHT_PER_STA_CTRL_BEACON_INTERVAL_PRESENT_MSK 0x0040
|
||||||
|
#define EHT_PER_STA_CTRL_TSF_OFFSET_PRESENT_MSK 0x0080
|
||||||
|
#define EHT_PER_STA_CTRL_DTIM_INFO_PRESENT_MSK 0x0100
|
||||||
|
#define EHT_PER_STA_CTRL_NSTR_LINK_PAIR_PRESENT_MSK 0x0200
|
||||||
|
#define EHT_PER_STA_CTRL_NSTR_BM_SIZE_MSK 0x0400
|
||||||
|
#define EHT_PER_STA_CTRL_BSS_PARAM_CNT_PRESENT_MSK 0x0800
|
||||||
|
|
||||||
/* IEEE P802.11be/D2.0, 9.4.2.312.2.4 - Per-STA Profile subelement format */
|
/* IEEE P802.11be/D2.0, 9.4.2.312.2.4 - Per-STA Profile subelement format */
|
||||||
struct ieee80211_eht_per_sta_profile {
|
struct ieee80211_eht_per_sta_profile {
|
||||||
le16 sta_control;
|
le16 sta_control;
|
||||||
|
|
Loading…
Reference in a new issue