Cumulative patch from commit fcd85d9a3f2d9d63d0fa57e93446ad467db75b23

fcd85d9 Add QCA vendor commands/attributes for indoor location
d1723c5 wpa_supplicant: Allow FTM functionality to be published
faecb39 hostapd: Allow FTM functionality to be published
fc72a48 hostapd: Use stations nsts capability in (Re)Association Response frame
22950d0 QCA vendor subcommand for LL_STATS extension
b44d9c7 D-Bus: Add ConfigFile parameter into the interface properties
7dcec24 mka: Clean up key allocation
95e9460 mka: Get rid of struct ieee802_1x_cp_conf
07a6bfe mka: Store cipher suite ID in a u64 instead of u8 pointer
535a8b8 mka: Make csindex unsigned
343eb3b mka: Reorganize live peer creation and key server election
34dbe90 mka: Share a single delete mka implementation
0dabf79 mka: Introduce compare_priorities()
53080f7 mka: Clean up ieee802_1x_kay_mkpdu_sanity_check()
05283e7 mka: Simplify ieee802_1x_mka_dist_sak_body_present()
87b19c8 mka: Replace participant->kay with a local kay variable
f9ea083 mka: Fix typos in grammar in variable names and comments
921171f mka: Use named initializers for mka_body_handler[]
86bef17 mka: Remove unused enum mka_created_mode values
ec958ae mka: Remove cs_len argument from the set_current_cipher_suite functions
46bbda2 mka: Clean up ieee802_1x_mka_decode_potential_peer_body()
cf375eb mka: Simplify ieee802_1x_mka_encode_icv_body() memory copying
8b4a148 mka: Simplify ieee802_1x_mka_sak_use_body_present()
b3df783 mka: Reorganize loops in number of KaY functions
de7f533 mka: Remove unused body_peer incrementation
2b13bca mka: Add reset_participant_mi() helper
3ceb458 mka: Clean up printf formats
8fab9e1 mka: Use named initializers for static structs
d4f668f mka: Add MKA_ALIGN_LENGTH macro
1de7a9f mka: Add helper functions for dumping and creating peer
d9639d1 mka: Clean up ieee802_1x_kay_get_cipher_suite() lookup function
7c547cf mka: Refactor the get_*_peer() functions
515bc1a mka: Fix a typo in mka_body_handler (mak to mka)
a33e3c3 mka: Add a helper function, sci_equal(), for sci comparison
cefeb8e mka: Use less bitfields in the IEEE 802.1X-2010 structs
2e94489 mka: Fix a typo in macsec_capbility
f2f8616 Initialize hapd->nr_db in hostapd_alloc_bss_data()
30e0745 Fix TRACK_STA_LIST before BSS enabled
1f3b8b4 Check for driver initialization before doing driver operations
833d0d4 radius: Sanity check for NULL pointer segfault

Change-Id: I500fe4f62e1a0010ea82c277f73becd2ac2dfa43
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 64daf4c..8c8f7e2 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -582,6 +582,7 @@
 	u8 radio_measurements[RRM_CAPABILITIES_IE_LEN];
 
 	int vendor_vht;
+	int use_sta_nsts;
 
 	char *no_probe_resp_if_seen_on;
 	char *no_auth_if_seen_on;
@@ -591,6 +592,9 @@
 #ifdef CONFIG_MBO
 	int mbo_enabled;
 #endif /* CONFIG_MBO */
+
+	int ftm_responder;
+	int ftm_initiator;
 };
 
 
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 532b72f..f139465 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -623,7 +623,7 @@
 int hostapd_drv_send_mlme(struct hostapd_data *hapd,
 			  const void *msg, size_t len, int noack)
 {
-	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
+	if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
 		return 0;
 	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
 				       NULL, 0);
@@ -644,7 +644,7 @@
 int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
 			   const u8 *addr, int reason)
 {
-	if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+	if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv)
 		return 0;
 	return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
 					reason);
@@ -654,7 +654,7 @@
 int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
 			     const u8 *addr, int reason)
 {
-	if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
+	if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv)
 		return 0;
 	return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
 					  reason);
@@ -680,7 +680,7 @@
 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 	};
 
-	if (hapd->driver == NULL || hapd->driver->send_action == NULL)
+	if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv)
 		return 0;
 	bssid = hapd->own_addr;
 	if (!is_multicast_ether_addr(dst) &&
@@ -754,7 +754,7 @@
 int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
 			    const u8 *qos_map_set, u8 qos_map_set_len)
 {
-	if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL)
+	if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
 		return 0;
 	return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
 					 qos_map_set_len);
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 6406d13..0bb7954 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -160,7 +160,7 @@
 static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
 					 const u8 *addr)
 {
-	if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+	if (!hapd->driver || !hapd->driver->sta_remove || !hapd->drv_priv)
 		return 0;
 	return hapd->driver->sta_remove(hapd->drv_priv, addr);
 }
@@ -283,7 +283,7 @@
 static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
 				     size_t buflen)
 {
-	if (hapd->driver == NULL || hapd->driver->status == NULL)
+	if (!hapd->driver || !hapd->driver->status || !hapd->drv_priv)
 		return -1;
 	return hapd->driver->status(hapd->drv_priv, buf, buflen);
 }
@@ -342,7 +342,7 @@
 
 static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
 {
-	if (hapd->driver == NULL || hapd->driver->stop_ap == NULL)
+	if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv)
 		return 0;
 	return hapd->driver->stop_ap(hapd->drv_priv);
 }
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 0570ab7..202abe6 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -485,7 +485,7 @@
 
 #ifdef CONFIG_IEEE80211AC
 	if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
-		pos = hostapd_eid_vht_capabilities(hapd, pos);
+		pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
 		pos = hostapd_eid_vht_operation(hapd, pos);
 		pos = hostapd_eid_txpower_envelope(hapd, pos);
 		pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
@@ -1105,7 +1105,7 @@
 
 #ifdef CONFIG_IEEE80211AC
 	if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
-		tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+		tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
 		tailpos = hostapd_eid_vht_operation(hapd, tailpos);
 		tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
 		tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 17a3ea4..23c8c60 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -258,7 +258,7 @@
 	int ret;
 	u8 *pos;
 
-	if (hapd->driver->send_frame == NULL)
+	if (!hapd->drv_priv || !hapd->driver->send_frame)
 		return -1;
 
 	mgmt = os_zalloc(sizeof(*mgmt) + 100);
@@ -325,7 +325,7 @@
 	if (pos) {
 		struct ieee80211_mgmt mgmt;
 		int encrypt;
-		if (hapd->driver->send_frame == NULL)
+		if (!hapd->drv_priv || !hapd->driver->send_frame)
 			return -1;
 		pos += 6;
 		encrypt = atoi(pos);
@@ -388,7 +388,7 @@
 	if (pos) {
 		struct ieee80211_mgmt mgmt;
 		int encrypt;
-		if (hapd->driver->send_frame == NULL)
+		if (!hapd->drv_priv || !hapd->driver->send_frame)
 			return -1;
 		pos += 6;
 		encrypt = atoi(pos);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 65f513d..a09d423 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -912,7 +912,6 @@
 		return -1;
 	}
 	hapd->started = 1;
-	dl_list_init(&hapd->nr_db);
 
 	if (!first || first == -1) {
 		u8 *addr = hapd->own_addr;
@@ -2002,6 +2001,7 @@
 	hapd->driver = hapd->iconf->driver;
 	hapd->ctrl_sock = -1;
 	dl_list_init(&hapd->ctrl_dst);
+	dl_list_init(&hapd->nr_db);
 
 	return hapd;
 }
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index eed5483..2ecd78f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1944,7 +1944,23 @@
 
 #ifdef CONFIG_IEEE80211AC
 	if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
-		p = hostapd_eid_vht_capabilities(hapd, p);
+		u32 nsts = 0, sta_nsts;
+
+		if (hapd->conf->use_sta_nsts && sta->vht_capabilities) {
+			struct ieee80211_vht_capabilities *capa;
+
+			nsts = (hapd->iface->conf->vht_capab >>
+				VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+			capa = sta->vht_capabilities;
+			sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
+				    VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+
+			if (nsts < sta_nsts)
+				nsts = 0;
+			else
+				nsts = sta_nsts;
+		}
+		p = hostapd_eid_vht_capabilities(hapd, p, nsts);
 		p = hostapd_eid_vht_operation(hapd, p);
 	}
 #endif /* CONFIG_IEEE80211AC */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 71b3b49..0327dec 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -50,7 +50,7 @@
 u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
 u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index af858f0..259413b 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -218,6 +218,12 @@
 		if (hapd->conf->ssid.utf8_ssid)
 			*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
 		break;
+	case 8: /* Bits 64-71 */
+		if (hapd->conf->ftm_responder)
+			*pos |= 0x40; /* Bit 70 - FTM responder */
+		if (hapd->conf->ftm_initiator)
+			*pos |= 0x80; /* Bit 71 - FTM initiator */
+		break;
 	}
 }
 
@@ -237,6 +243,9 @@
 		len = 1;
 	if (len < 7 && hapd->conf->ssid.utf8_ssid)
 		len = 7;
+	if (len < 9 &&
+	    (hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
+		len = 9;
 #ifdef CONFIG_WNM
 	if (len < 4)
 		len = 4;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 0841898..f30f63b 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -20,7 +20,7 @@
 #include "dfs.h"
 
 
-u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
 {
 	struct ieee80211_vht_capabilities *cap;
 	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
@@ -50,6 +50,18 @@
 	cap->vht_capabilities_info = host_to_le32(
 		hapd->iface->conf->vht_capab);
 
+	if (nsts != 0) {
+		u32 hapd_nsts;
+
+		hapd_nsts = le_to_host32(cap->vht_capabilities_info);
+		hapd_nsts = (hapd_nsts >> VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+		cap->vht_capabilities_info &=
+			~(host_to_le32(hapd_nsts <<
+				       VHT_CAP_BEAMFORMEE_STS_OFFSET));
+		cap->vht_capabilities_info |=
+			host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+	}
+
 	/* Supported MCS set comes from hw */
 	os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
 
@@ -398,7 +410,7 @@
 	WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
 	pos += 4;
 	*pos++ = VENDOR_VHT_SUBTYPE;
-	pos = hostapd_eid_vht_capabilities(hapd, pos);
+	pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
 	pos = hostapd_eid_vht_operation(hapd, pos);
 
 	return pos;