This patch adds following hostapd configuration options for FILS discovery transmission from IEEE Std 802.11ai-2016, Annex C.3 MIB detail: (1) Minimum interval - default 20 TUs (2) Maximum interval - default 0 TUs (FILS discovery disabled) Signed-off-by: Aloka Dixit <alokad@xxxxxxxxxxxxxx> --- hostapd/config_file.c | 4 + hostapd/hostapd.conf | 5 + src/ap/ap_config.c | 1 + src/ap/ap_config.h | 2 + src/ap/beacon.c | 288 ++++++++++++++++++++++++++++++++++++++++++ src/drivers/driver.h | 20 +++ 6 files changed, 320 insertions(+) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index b3dc8f81a999..bedd0b5826e4 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4359,6 +4359,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->dhcp_server_port = atoi(pos); } else if (os_strcmp(buf, "dhcp_relay_port") == 0) { bss->dhcp_relay_port = atoi(pos); + } else if (os_strcmp(buf, "fils_discovery_min_interval") == 0) { + bss->fils_discovery_min_int = atoi(pos); + } else if (os_strcmp(buf, "fils_discovery_max_interval") == 0) { + bss->fils_discovery_max_int = atoi(pos); #endif /* CONFIG_FILS */ } else if (os_strcmp(buf, "multicast_to_unicast") == 0) { bss->multicast_to_unicast = atoi(pos); diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 3ac64a75e963..73a57d900864 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1930,6 +1930,11 @@ own_ip_addr=127.0.0.1 # default: 30 TUs (= 30.72 milliseconds) #fils_hlp_wait_time=30 +# FILS discovery transmission minimum and maximum packet interval settings. +# If maximum interval is non-zero, the AP schedules FILS discovery transmission +#fils_discovery_max_interval=0 to 10000 (in TUs). +#fils_discovery_min_interval=0 to 10000 (in TUs). + # Transition Disable indication # The AP can notify authenticated stations to disable transition mode in their # network profiles when the network has completed transition steps, i.e., once diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index f82468ac802c..c7e09353df94 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -131,6 +131,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->fils_hlp_wait_time = 30; bss->dhcp_server_port = DHCP_SERVER_PORT; bss->dhcp_relay_port = DHCP_SERVER_PORT; + bss->fils_discovery_min_int = 20; #endif /* CONFIG_FILS */ bss->broadcast_deauth = 1; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index f7a344e0ea4d..025b729c39ea 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -730,6 +730,8 @@ struct hostapd_bss_config { unsigned int fils_hlp_wait_time; u16 dhcp_server_port; u16 dhcp_relay_port; + u32 fils_discovery_min_int; + u32 fils_discovery_max_int; #endif /* CONFIG_FILS */ int multicast_to_unicast; diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 47b260e810e8..462dc2ab0c8a 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -1128,6 +1128,286 @@ void sta_track_del(struct hostapd_sta_info *info) } +#ifdef CONFIG_FILS +static u8 hostapd_fils_discovery_rsn(struct hostapd_data *hapd, u16 *cap, + u32 *suite_selector_ptr) +{ + const u8 *ie, *start; + u8 len; + u16 cnt; + u32 suite_selector = 0; + + ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN); + if (!ie || ie[1] < 6) + return 0; + + len = ie[1]; + start = &ie[2]; + ie += 4; + do { + /* Group Data Cipher Suite Selector */ + suite_selector = ie[3]; + ie += 4; + + /* Pairwise Cipher Suite Selector */ + if ((ie - start) >= len) + break; + os_memcpy((u8 *) &cnt, ie, 2); + ie += 2; + if (cnt) { + suite_selector |= (((u32) ie[3]) << 12); + ie += (4 * cnt); + } + + /* AKM Cipher Suite Selector */ + if ((ie - start) >= len) + break; + os_memcpy((u8 *) &cnt, ie, 2); + ie += 2; + if (cnt) { + suite_selector |= (((u32) ie[3]) << 18); + ie += (4 * cnt); + } + + /* RSN capabilities */ + if ((ie - start) >= len) + break; + os_memcpy((u8 *) cap, ie, 2); + ie += 2; + + /* Group Management Cipher Suite Selector */ + if ((ie - start) < len) + suite_selector |= (((u32) ie[3]) << 6); + } while (0); + + *suite_selector_ptr = suite_selector; + return 1; +} + + +u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd) +{ + u16 cap_info = 0, nss_mask = 0x0003, *mcs; + u8 nss = 0, chwidth = 0, mcs_nss_size = 4; + int i; + + cap_info = FILS_DISCOVERY_CAP_ESS | + (hapd->conf->wpa ? FILS_DISCOVERY_CAP_PRIVACY : 0); + + if (is_6ghz_op_class(hapd->iconf->op_class)) { + cap_info |= (FILS_DISCOVERY_CAP_PHY_INDEX_HE << + FILS_DISCOVERY_CAP_PHY_INDEX_SHIFT); + + switch (hapd->iconf->op_class) { + case 135: + mcs_nss_size += 4; + /* fallthrough */ + case 134: + mcs_nss_size += 4; + chwidth = FILS_DISCOVERY_CAP_BSS_CHWIDTH_160_8080; + break; + case 133: + chwidth = FILS_DISCOVERY_CAP_BSS_CHWIDTH_80; + break; + case 132: + chwidth = FILS_DISCOVERY_CAP_BSS_CHWIDTH_40; + break; + } + } else { + switch (hostapd_get_oper_chwidth(hapd->iconf)) { + case CHANWIDTH_80P80MHZ: + mcs_nss_size += 4; + /* fallthrough */ + case CHANWIDTH_160MHZ: + mcs_nss_size += 4; + chwidth = FILS_DISCOVERY_CAP_BSS_CHWIDTH_160_8080; + break; + case CHANWIDTH_80MHZ: + chwidth = FILS_DISCOVERY_CAP_BSS_CHWIDTH_80; + break; + case CHANWIDTH_USE_HT: + if (hapd->iconf->secondary_channel) + chwidth = FILS_DISCOVERY_CAP_BSS_CHWIDTH_40; + break; + } + + if (hapd->iconf->ieee80211ax) { +#ifdef CONFIG_IEEE80211AX + cap_info |= (FILS_DISCOVERY_CAP_PHY_INDEX_HE << + FILS_DISCOVERY_CAP_PHY_INDEX_SHIFT); +#endif /* CONFIG_IEEE80211AX */ + } else if (hapd->conf->vendor_vht) { +#ifdef CONFIG_IEEE80211AC + cap_info |= (FILS_DISCOVERY_CAP_PHY_INDEX_VHT << + FILS_DISCOVERY_CAP_PHY_INDEX_SHIFT); +#endif /* CONFIG_IEEE80211AC */ + } else if (hapd->iconf->ieee80211n && + !hapd->conf->disable_11n) { + cap_info |= (FILS_DISCOVERY_CAP_PHY_INDEX_HT << + FILS_DISCOVERY_CAP_PHY_INDEX_SHIFT); + } + } + + cap_info |= (chwidth << FILS_DISCOVERY_CAP_BSS_CHWIDTH_SHIFT); + + if (hapd->iface->current_mode) { + mcs = (u16 *)hapd->iface->current_mode->he_capab[IEEE80211_MODE_AP].mcs; + + for (i = 0; i < HE_NSS_MAX_STREAMS; i++) { + do { + if ((mcs_nss_size == 4) && + (((mcs[0] & nss_mask) == nss_mask) || + ((mcs[1] & nss_mask) == nss_mask))) + break; + + if ((mcs_nss_size == 8) && + (((mcs[2] & nss_mask) == nss_mask) || + ((mcs[3] & nss_mask) == nss_mask))) + break; + + if ((mcs_nss_size == 12) && + (((mcs[4] & nss_mask) == nss_mask) || + ((mcs[5] & nss_mask) == nss_mask))) + break; + + nss++; + } while (0); + + nss_mask <<= 2; + } + + if (nss > 4) + cap_info |= (4 << FILS_DISCOVERY_CAP_NSS_SHIFT); + else if (nss) + cap_info |= ((nss - 1) << FILS_DISCOVERY_CAP_NSS_SHIFT); + } + return cap_info; +} + + +static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, u32 *len) +{ + struct ieee80211_mgmt *head; + const u8 *mobility_domain; + u8 *pos, *length_pos, rsn = 0, buf[200], buf_len; + u16 frm_cntl = 0, rsn_cap = 0; + u32 suite_selectors = 0, total_len; + +#define FILS_DISOVERY_TMPL_HEAD_LEN 26 +#define FILS_DISOVERY_TMPL_MIN_LEN 19 + + total_len = FILS_DISOVERY_TMPL_HEAD_LEN + FILS_DISOVERY_TMPL_MIN_LEN; + + /* FILS discovery frame control: 2 bytes */ + frm_cntl = (sizeof(hapd->conf->ssid.short_ssid) - 1) | + FILS_DISCOVERY_FRM_CNTL_CAP_PRESENT | + FILS_DISCOVERY_FRM_CNTL_SHORT_SSID_PRESENT | + FILS_DISCOVERY_FRM_CNTL_LENGTH_PRESENT; + + /* Check for optional subfields and calculate length */ + rsn = hostapd_fils_discovery_rsn(hapd, &rsn_cap, &suite_selectors); + if (rsn) { + frm_cntl |= FILS_DISCOVERY_FRM_CNTL_RSN_INFO_PRESENT; + total_len += 5; + } + + mobility_domain = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN); + if (mobility_domain) { + frm_cntl |= FILS_DISCOVERY_FRM_CNTL_MOBILITY_DOMAIN_PRESENT; + total_len += 3; + } + + pos = hostapd_eid_fils_indic(hapd, buf, 0); + buf_len = pos - buf; + total_len += buf_len; + + head = os_zalloc(total_len); + if (!head) + return NULL; + + head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memset(head->da, 0xff, ETH_ALEN); + os_memcpy(head->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN); + + head->u.action.category = WLAN_ACTION_PUBLIC; + head->u.action.u.public_action.action = WLAN_PA_FILS_DISCOVERY; + + pos = &head->u.action.u.public_action.variable[0]; + *((u16 *) pos) = host_to_le16(frm_cntl); + pos += 2; + + /* hardware or low-level driver will setup timestamp */ + pos += 8; + + /* Beacon interval */ + *((u16 *) pos) = host_to_le16(hapd->iconf->beacon_int); + pos += 2; + + /* Short SSID */ + *((u32 *) pos) = host_to_le32(hapd->conf->ssid.short_ssid); + pos += sizeof(hapd->conf->ssid.short_ssid); + + /* Store position of FILS discovery information element length field */ + length_pos = pos++; + + /* FD Capability : total 2 bytes */ + *((u16 *) pos) = host_to_le16(hostapd_fils_discovery_cap(hapd)); + pos += 2; + + /* RSN */ + if (frm_cntl & FILS_DISCOVERY_FRM_CNTL_RSN_INFO_PRESENT) { + os_memcpy(pos, &rsn_cap, 2); + os_memcpy(&pos[2], &suite_selectors, 3); + pos += 5; + } + + /* Mobility Domain */ + if (frm_cntl & FILS_DISCOVERY_FRM_CNTL_MOBILITY_DOMAIN_PRESENT) { + os_memcpy(pos, &mobility_domain[2], 3); + pos += 3; + } + + /* Fill the FILS discovery information element length */ + *length_pos = pos - (length_pos + 1); + + /* FILS indication element */ + if (buf_len) { + os_memcpy(pos, buf, buf_len); + pos += buf_len; + } + + *len = pos - (u8 *) head; + return ((u8 *) head); +} + + +/* Configure FILS discovery transmission */ +static u8 * hostapd_fils_discovery(struct hostapd_data *hapd, + struct wpa_driver_ap_params *params) +{ +#define VALID_INTERVAL(x,y) { x = (x > y) ? y : x; } + + params->fils_discovery_max_int = hapd->conf->fils_discovery_max_int; + if (is_6ghz_op_class(hapd->iconf->op_class)) + VALID_INTERVAL(params->fils_discovery_max_int, + FILS_DISCOVERY_MAX_INTERVAL_6GHZ); + + params->fils_discovery_min_int = hapd->conf->fils_discovery_min_int; + VALID_INTERVAL(params->fils_discovery_min_int, + params->fils_discovery_max_int); +#undef VALID_INTERVAL + + if (params->fils_discovery_max_int) + return hostapd_gen_fils_discovery(hapd, + ¶ms->fils_discovery_tmpl_len); + + return NULL; +} +#endif /* CONFIG_FILS */ + + int ieee802_11_build_ap_params(struct hostapd_data *hapd, struct wpa_driver_ap_params *params) { @@ -1465,6 +1745,10 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) params->head = NULL; os_free(params->proberesp); params->proberesp = NULL; +#ifdef CONFIG_FILS + os_free(params->fils_discovery_tmpl); + params->fils_discovery_tmpl = NULL; +#endif /* CONFIG_FILS */ } @@ -1515,6 +1799,10 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) params.sae_pwe = hapd->conf->sae_pwe; #endif /* CONFIG_SAE */ +#ifdef CONFIG_FILS + params.fils_discovery_tmpl = hostapd_fils_discovery(hapd, ¶ms); +#endif /* CONFIG_FILS */ + if (cmode && hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq, iconf->channel, iconf->enable_edmg, diff --git a/src/drivers/driver.h b/src/drivers/driver.h index b0543e7b42be..1a3bcaf546f3 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1524,6 +1524,26 @@ struct wpa_driver_ap_params { * 2 = both hunting-and-pecking loop and hash-to-element enabled */ int sae_pwe; + + /** + * FILS discovery minimum interval + */ + u32 fils_discovery_min_int; + + /** + * FILS discovery maximum interval + */ + u32 fils_discovery_max_int; + + /** + * FILS discovery template data + */ + u8 *fils_discovery_tmpl; + + /** + * FILS discovery template length + */ + size_t fils_discovery_tmpl_len; }; struct wpa_driver_mesh_bss_params { -- 2.25.0 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap