Cumulative patch from commit 12c1fdf19a721aaf29e1c77d63445c7f5b8c61c0

12c1fdf P2P: Update peer listen channel from Probe Request frames
a805731 P2P: Abort ongoing scan when p2p_find is stopped
7441698 nl80211: Abort an ongoing scan upon scan timeout indication
1446afc wpa_supplicant: Handle EVENT_SCAN_RESULTS when an interface is disabled
d14e63a WNM: Do not scan based on malformed BSS Transition Management Request
f420577 WNM: Fix candidates count in BSS Transition Management Request
3c58df7 wpa_cli: Support running action script on global control interface
b8f02d8 EAP-PWD peer: Fix possible memory leak on error path
8f38eed Android: Remove superfluous OpenSSL include paths
cbf8d18 HS 2.0R2: Clear fetch_anqp_in_progress if fopen fails
4a6e9e5 Fix CONFIG_WPA_TRACE=y compilation without CONFIG_WPA_TRACE_BFD=y
2bf9a53 Add EAP-AKA' and EAP-pwd to wpa_supplicant README
4196c08 Update notes about OpenSSL versions
5d7b1a3 Fix some typos in wpa_supplicant README files
4194fee README-P2P: Fix a typo
c58eed6 P2P: Add Dev Info attribute to Probe Request frames in 60 GHz
2b6e9f9 wpa_supplicant: Expose wpas_get_bands() and related API
94ad3c3 P2P: Change order of P2P IE and frequencies set up
61697c7 Android: Allow wpa_supplicant to write files to osu-info dir
0147afa FST: Enlarge State Transition Timeout (STT)
e1d00d4 Add error handling for offloaded ACS with vendor command failures
bef5e9a Fix scan rescheduling from wpas_stop_pno to check postponed case
b9ca12a nl80211: Add more address fields into RX frame debug message
debde14 RADIUS: Add Acct-Delay-Time into accounting messages
669b532 RADIUS: Update full message for interim accounting updates
251953b Document nas_identifier requirements for RADIUS accounting
902c07a Replace hostapd_mac_comp_empty() with is_zero_ether_addr()
5aef495 VLAN: Avoid use of libnl cache
732b1d2 nl80211: Clean up ifidx properly if interface in a bridge is removed
170c545 FT: Check destination MAC address on RRB receive
57b2c91 RADIUS: Allow RADIUS server to provide PSK instead of passphrase
d8912fd Cache hashed passphrase in RADIUS-based PSK delivery
f8e09bc Defer passphrase-to-PSK hashing out of 802.11 authentication ACL check
cc9c805 VLAN: Use stack instead of heap allocation for new interface name
d48d1b8 FT: Use BSSID as r1_key_holder if no value is configured
71456db FT: Check hapd->wpa_auth before RRB internal delivery
0270bde FT: Fix R0KH-R1KH protocol data length values
96a26ab P2P: Support dedicated P2P_DEVICE without separate group interface
ba307f8 P2P: Add a separate pointer to the P2P Device instance
e040197 GAS client: Make PMF check on RX more consistent
0645492 WNM: Optimize a single BSS transition management candidate scan
eb20cea nl80211: Add an option to specify the BSSID to scan for
adf0478 AP: Store STA supported operating classes information

Change-Id: If0ce28aae5591be783c38e5b60f7f9ff0fb9f8f2
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5fec430..570dee6 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -181,9 +181,14 @@
 static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
 					       int report);
 
-static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
+#define IFIDX_ANY -1
+
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+		      int ifidx_reason);
+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+		      int ifidx_reason);
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+		      int ifidx_reason);
 
 static int nl80211_set_channel(struct i802_bss *bss,
 			       struct hostapd_freq_params *freq, int set_chan);
@@ -883,7 +888,7 @@
 	dl_list_for_each(drv, &global->interfaces,
 			 struct wpa_driver_nl80211_data, list) {
 		if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
-		    have_ifidx(drv, idx))
+		    have_ifidx(drv, idx, IFIDX_ANY))
 			return drv;
 	}
 	return NULL;
@@ -1062,7 +1067,7 @@
 		}
 		wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
 			   brid, namebuf);
-		add_ifidx(drv, brid);
+		add_ifidx(drv, brid, ifi->ifi_index);
 
 		for (bss = drv->first_bss; bss; bss = bss->next) {
 			if (os_strcmp(ifname, bss->ifname) == 0) {
@@ -1149,7 +1154,7 @@
 				   "nl80211: Remove ifindex %u for bridge %s",
 				   brid, namebuf);
 		}
-		del_ifidx(drv, brid);
+		del_ifidx(drv, brid, ifi->ifi_index);
 	}
 }
 
@@ -1716,6 +1721,7 @@
 
 	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
 	drv->if_indices = drv->default_if_indices;
+	drv->if_indices_reason = drv->default_if_indices_reason;
 
 	drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
 	if (!drv->first_bss) {
@@ -2390,6 +2396,9 @@
 	if (drv->if_indices != drv->default_if_indices)
 		os_free(drv->if_indices);
 
+	if (drv->if_indices_reason != drv->default_if_indices_reason)
+		os_free(drv->if_indices_reason);
+
 	if (drv->disabled_11b_rates)
 		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
@@ -4069,7 +4078,11 @@
 	/* stop listening for EAPOL on this interface */
 	dl_list_for_each(drv2, &drv->global->interfaces,
 			 struct wpa_driver_nl80211_data, list)
-		del_ifidx(drv2, ifidx);
+	{
+		del_ifidx(drv2, ifidx, IFIDX_ANY);
+		/* Remove all bridges learned for this iface */
+		del_ifidx(drv2, IFIDX_ANY, ifidx);
+	}
 
 	msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
 	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
@@ -4177,7 +4190,7 @@
 	    iftype == NL80211_IFTYPE_WDS ||
 	    iftype == NL80211_IFTYPE_MONITOR) {
 		/* start listening for EAPOL on this interface */
-		add_ifidx(drv, ifidx);
+		add_ifidx(drv, ifidx, IFIDX_ANY);
 	}
 
 	if (addr && iftype != NL80211_IFTYPE_MONITOR &&
@@ -5635,7 +5648,9 @@
 	for (i = 0; i < drv->num_if_indices; i++) {
 		if (!drv->if_indices[i])
 			continue;
-		res = os_snprintf(pos, end - pos, " %d", drv->if_indices[i]);
+		res = os_snprintf(pos, end - pos, " %d(%d)",
+				  drv->if_indices[i],
+				  drv->if_indices_reason[i]);
 		if (os_snprintf_error(end - pos, res))
 			break;
 		pos += res;
@@ -5647,14 +5662,16 @@
 }
 
 
-static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+		      int ifidx_reason)
 {
 	int i;
-	int *old;
+	int *old, *old_reason;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
-		   ifidx);
-	if (have_ifidx(drv, ifidx)) {
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: Add own interface ifindex %d (ifidx_reason %d)",
+		   ifidx, ifidx_reason);
+	if (have_ifidx(drv, ifidx, ifidx_reason)) {
 		wpa_printf(MSG_DEBUG, "nl80211: ifindex %d already in the list",
 			   ifidx);
 		return;
@@ -5662,6 +5679,7 @@
 	for (i = 0; i < drv->num_if_indices; i++) {
 		if (drv->if_indices[i] == 0) {
 			drv->if_indices[i] = ifidx;
+			drv->if_indices_reason[i] = ifidx_reason;
 			dump_ifidx(drv);
 			return;
 		}
@@ -5672,32 +5690,57 @@
 	else
 		old = NULL;
 
+	if (drv->if_indices_reason != drv->default_if_indices_reason)
+		old_reason = drv->if_indices_reason;
+	else
+		old_reason = NULL;
+
 	drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
 					   sizeof(int));
+	drv->if_indices_reason = os_realloc_array(old_reason,
+						  drv->num_if_indices + 1,
+						  sizeof(int));
 	if (!drv->if_indices) {
 		if (!old)
 			drv->if_indices = drv->default_if_indices;
 		else
 			drv->if_indices = old;
+	}
+	if (!drv->if_indices_reason) {
+		if (!old_reason)
+			drv->if_indices_reason = drv->default_if_indices_reason;
+		else
+			drv->if_indices = old_reason;
+	}
+	if (!drv->if_indices || !drv->if_indices_reason) {
 		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
 			   "interfaces");
 		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
 		return;
-	} else if (!old)
+	}
+	if (!old)
 		os_memcpy(drv->if_indices, drv->default_if_indices,
 			  sizeof(drv->default_if_indices));
+	if (!old_reason)
+		os_memcpy(drv->if_indices_reason,
+			  drv->default_if_indices_reason,
+			  sizeof(drv->default_if_indices_reason));
 	drv->if_indices[drv->num_if_indices] = ifidx;
+	drv->if_indices_reason[drv->num_if_indices] = ifidx_reason;
 	drv->num_if_indices++;
 	dump_ifidx(drv);
 }
 
 
-static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+		      int ifidx_reason)
 {
 	int i;
 
 	for (i = 0; i < drv->num_if_indices; i++) {
-		if (drv->if_indices[i] == ifidx) {
+		if ((drv->if_indices[i] == ifidx || ifidx == IFIDX_ANY) &&
+		    (drv->if_indices_reason[i] == ifidx_reason ||
+		     ifidx_reason == IFIDX_ANY)) {
 			drv->if_indices[i] = 0;
 			break;
 		}
@@ -5706,12 +5749,15 @@
 }
 
 
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx,
+		      int ifidx_reason)
 {
 	int i;
 
 	for (i = 0; i < drv->num_if_indices; i++)
-		if (drv->if_indices[i] == ifidx)
+		if (drv->if_indices[i] == ifidx &&
+		    (drv->if_indices_reason[i] == ifidx_reason ||
+		     ifidx_reason == IFIDX_ANY))
 			return 1;
 
 	return 0;
@@ -5776,7 +5822,7 @@
 		return;
 	}
 
-	if (have_ifidx(drv, lladdr.sll_ifindex))
+	if (have_ifidx(drv, lladdr.sll_ifindex, IFIDX_ANY))
 		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
 }
 
@@ -5803,7 +5849,7 @@
 		}
 		bss->added_bridge = 1;
 		br_ifindex = if_nametoindex(brname);
-		add_ifidx(drv, br_ifindex);
+		add_ifidx(drv, br_ifindex, drv->ifindex);
 	}
 	bss->br_ifindex = br_ifindex;
 
@@ -5865,7 +5911,7 @@
 		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s",
 			params->ifname, master_ifname);
 		/* start listening for EAPOL on the master interface */
-		add_ifidx(drv, if_nametoindex(master_ifname));
+		add_ifidx(drv, if_nametoindex(master_ifname), drv->ifindex);
 	} else {
 		master_ifname[0] = '\0';
 	}
@@ -5876,14 +5922,14 @@
 		if (params->bridge[i]) {
 			ifindex = if_nametoindex(params->bridge[i]);
 			if (ifindex)
-				add_ifidx(drv, ifindex);
+				add_ifidx(drv, ifindex, drv->ifindex);
 			if (ifindex == br_ifindex)
 				br_added = 1;
 		}
 	}
 
 	/* start listening for EAPOL on the default AP interface */
-	add_ifidx(drv, drv->ifindex);
+	add_ifidx(drv, drv->ifindex, IFIDX_ANY);
 
 	if (params->num_bridge && params->bridge[0]) {
 		if (i802_check_bridge(drv, bss, params->bridge[0],
@@ -5895,7 +5941,7 @@
 
 	if (!br_added && br_ifindex &&
 	    (params->num_bridge == 0 || !params->bridge[0]))
-		add_ifidx(drv, br_ifindex);
+		add_ifidx(drv, br_ifindex, drv->ifindex);
 
 #ifdef CONFIG_LIBNL3_ROUTE
 	if (bss->added_if_into_bridge) {
@@ -6181,7 +6227,7 @@
 	     nlmode == NL80211_IFTYPE_AP_VLAN ||
 	     nlmode == NL80211_IFTYPE_WDS ||
 	     nlmode == NL80211_IFTYPE_MONITOR))
-		add_ifidx(drv, ifidx);
+		add_ifidx(drv, ifidx, IFIDX_ANY);
 
 	return 0;
 }
@@ -6201,8 +6247,10 @@
 	else if (ifindex > 0 && !bss->added_if) {
 		struct wpa_driver_nl80211_data *drv2;
 		dl_list_for_each(drv2, &drv->global->interfaces,
-				 struct wpa_driver_nl80211_data, list)
-			del_ifidx(drv2, ifindex);
+				 struct wpa_driver_nl80211_data, list) {
+			del_ifidx(drv2, ifindex, IFIDX_ANY);
+			del_ifidx(drv2, IFIDX_ANY, ifindex);
+		}
 	}
 
 	if (type != WPA_IF_AP_BSS)