[PATCH v3 2/3] AP: Add FILS discovery support

Aloka Dixit alokad at codeaurora.org
Mon Dec 14 21:04:27 EST 2020


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 at codeaurora.org>
---
 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,
+						  &params->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, &params);
+#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




More information about the Hostap mailing list