Cumulative patch from commit c06c9099f0d0827feae5622097bd8ac946eca5ea

c06c909 Use stronger PRNG for MS-MPPE-Send/Recv-Key salt
9e1f1bd eloop: Clean up coding style for eloop debug prints
f9982b3 Implement kqueue(2) support via CONFIG_ELOOP_KQUEUE
2e69bdd eloop: Add eloop_sock_requeue()
70f4f05 wpa_ctrl: Retry select() on EINTR
df9e2c2 D-Bus: Don't do <deny send_interface="..." /> in dbus service file
9684c75 mesh: Fix peer link counting when a mesh peer reconnects
83fe38b P2P: Fall back to no VHT when starting AP/P2P GO
360a9d5 P2P: Reduce off channel wait time for some P2P Action frames
1fc63fe RADIUS: Share a single function for generating session IDs
2cbc6ff RADIUS: Redesign Request Authenticator generation
b71a64a Send an Acct-Multi-Session-Id attribute in Access-Request packets
4260e1a Add Acct-Session-Id to Accounting-On/Off
d72a005 RADIUS: Use more likely unique accounting Acct-{,Multi-}Session-Id
d689317 EAPOL auth: Move radius_cui/identity freeing to eapol_auth_free()
0ae86f9 wpa_supplicant: Fix couple of C++ compiler errors with header files
9b6177a Add Event-Timestamp to all Accounting-Request packets
d179089 GAS: Calculate response buffer length of ANQP elements
dda091c OpenSSL: Fix server side PKCS#12 processing with extra certificates
443c8e1 OpenSSL: Fix possible null pointer dereference on an OCSP error path
a3cc64f Remove -w support from wpa_supplicant README
e265838 EAP-FAST: Fix an error path in PAC binary format parsing
f91e11f D-Bus: Fix p2p interface capability message
479f46c Do not send Acct-Authentic in Accounting-On/Off
696544e RADIUS: Do not include Acct-Terminate-Cause in Accounting-On/Off
236053e Make fallback from HT40 to HT20 work
cb22e3b BSD: Zero ifindex on interface removal
a8ef133 Android: Support multiple CA certs when connecting to EAP network
80ce804 WNM: Workaround for broken AP operating class behavior
af06093 BSD: Disable interface on down
dc0ad60 BSD: Use correct ifindex from route messages
5f17b2c BSD: __FUNCTION__ -> __func__
2088ecb OSU: Add debug printing of more LogotypeExtn fields
0b905c8 Add the selector suite into wpa_parse_wpa_ie_rsn() "invalid group cipher"
03a72ea VHT: Add an interoperability workaround for 80+80 and 160 MHz channels

Change-Id: Ief9174bdec380e81025e1467c47bf1656eb39cd9
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 780c19b..99f3504 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -62,6 +62,7 @@
 
 	struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
 	char	ifname[IFNAMSIZ+1];	/* interface name */
+	int	flags;
 	unsigned int ifindex;		/* interface index */
 	void	*ctx;
 	struct wpa_driver_capa capa;	/* driver capability */
@@ -93,6 +94,9 @@
 	struct bsd_driver_data *drv = priv;
 	struct ieee80211req ireq;
 
+	if (drv->ifindex == 0)
+		return -1;
+
 	os_memset(&ireq, 0, sizeof(ireq));
 	os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name));
 	ireq.i_type = op;
@@ -287,6 +291,7 @@
 			   strerror(errno));
 		return -1;
 	}
+	drv->flags = ifr.ifr_flags;
 
 	if (enable) {
 		if (ifr.ifr_flags & IFF_UP)
@@ -304,6 +309,7 @@
 		return -1;
 	}
 
+	drv->flags = ifr.ifr_flags;
 	return 0;
 }
 
@@ -773,12 +779,12 @@
 			   rtm->rtm_version);
 		return;
 	}
-	drv = bsd_get_drvindex(global, rtm->rtm_index);
-	if (drv == NULL)
-		return;
 	switch (rtm->rtm_type) {
 	case RTM_IEEE80211:
 		ifan = (struct if_announcemsghdr *) rtm;
+		drv = bsd_get_drvindex(global, ifan->ifan_index);
+		if (drv == NULL)
+			return;
 		switch (ifan->ifan_what) {
 		case RTM_IEEE80211_ASSOC:
 		case RTM_IEEE80211_REASSOC:
@@ -878,7 +884,8 @@
 {
 	struct bsd_driver_data *drv = priv;
 
-	bsd_ctrl_iface(drv, 0);
+	if (drv->ifindex != 0)
+		bsd_ctrl_iface(drv, 0);
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);
 	os_free(drv);
@@ -966,7 +973,7 @@
 	int ret = 0;
 
 	wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
-		__FUNCTION__, wpa, privacy);
+		__func__, wpa, privacy);
 
 	if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0)
 		ret = -1;
@@ -981,7 +988,7 @@
 static int
 wpa_driver_bsd_set_wpa(void *priv, int enabled)
 {
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
 
 	return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
 }
@@ -1189,6 +1196,7 @@
 	struct bsd_driver_global *global = sock_ctx;
 	struct bsd_driver_data *drv;
 	struct if_announcemsghdr *ifan;
+	struct if_msghdr *ifm;
 	struct rt_msghdr *rtm;
 	union wpa_event_data event;
 	struct ieee80211_michael_event *mic;
@@ -1210,19 +1218,20 @@
 			   rtm->rtm_version);
 		return;
 	}
-	drv = bsd_get_drvindex(global, rtm->rtm_index);
-	if (drv == NULL)
-		return;
-	ctx = drv->ctx;
 	os_memset(&event, 0, sizeof(event));
 	switch (rtm->rtm_type) {
 	case RTM_IFANNOUNCE:
 		ifan = (struct if_announcemsghdr *) rtm;
+		drv = bsd_get_drvindex(global, ifan->ifan_index);
+		if (drv == NULL)
+			return;
 		os_strlcpy(event.interface_status.ifname, drv->ifname,
 			   sizeof(event.interface_status.ifname));
 		switch (ifan->ifan_what) {
 		case IFAN_DEPARTURE:
 			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+			drv->ifindex = 0;
+			break;
 		default:
 			return;
 		}
@@ -1230,37 +1239,41 @@
 			   event.interface_status.ifname,
 			   ifan->ifan_what == IFAN_DEPARTURE ?
 				"removed" : "added");
-		wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
 		break;
 	case RTM_IEEE80211:
 		ifan = (struct if_announcemsghdr *) rtm;
+		drv = bsd_get_drvindex(global, ifan->ifan_index);
+		if (drv == NULL)
+			return;
 		switch (ifan->ifan_what) {
 		case RTM_IEEE80211_ASSOC:
 		case RTM_IEEE80211_REASSOC:
 			if (drv->is_ap)
 				break;
-			wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+			wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
 			break;
 		case RTM_IEEE80211_DISASSOC:
 			if (drv->is_ap)
 				break;
-			wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
+			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
 			break;
 		case RTM_IEEE80211_SCAN:
 			if (drv->is_ap)
 				break;
-			wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+			wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+					     NULL);
 			break;
 		case RTM_IEEE80211_LEAVE:
 			leave = (struct ieee80211_leave_event *) &ifan[1];
-			drv_event_disassoc(ctx, leave->iev_addr);
+			drv_event_disassoc(drv->ctx, leave->iev_addr);
 			break;
 		case RTM_IEEE80211_JOIN:
 #ifdef RTM_IEEE80211_REJOIN
 		case RTM_IEEE80211_REJOIN:
 #endif
 			join = (struct ieee80211_join_event *) &ifan[1];
-			bsd_new_sta(drv, ctx, join->iev_addr);
+			bsd_new_sta(drv, drv->ctx, join->iev_addr);
 			break;
 		case RTM_IEEE80211_REPLAY:
 			/* ignore */
@@ -1275,20 +1288,30 @@
 			os_memset(&event, 0, sizeof(event));
 			event.michael_mic_failure.unicast =
 				!IEEE80211_IS_MULTICAST(mic->iev_dst);
-			wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
-				&event);
+			wpa_supplicant_event(drv->ctx,
+					     EVENT_MICHAEL_MIC_FAILURE, &event);
 			break;
 		}
 		break;
 	case RTM_IFINFO:
-		if ((rtm->rtm_flags & RTF_UP) == 0) {
-			os_strlcpy(event.interface_status.ifname, drv->ifname,
-				   sizeof(event.interface_status.ifname));
-			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+		ifm = (struct if_msghdr *) rtm;
+		drv = bsd_get_drvindex(global, ifm->ifm_index);
+		if (drv == NULL)
+			return;
+		if ((ifm->ifm_flags & IFF_UP) == 0 &&
+		    (drv->flags & IFF_UP) != 0) {
 			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
-				   event.interface_status.ifname);
-			wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+				   drv->ifname);
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+					     NULL);
+		} else if ((ifm->ifm_flags & IFF_UP) != 0 &&
+		    (drv->flags & IFF_UP) == 0) {
+			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+				   drv->ifname);
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+					     NULL);
 		}
+		drv->flags = ifm->ifm_flags;
 		break;
 	}
 }
@@ -1559,16 +1582,21 @@
 {
 	struct bsd_driver_data *drv = priv;
 
-	wpa_driver_bsd_set_wpa(drv, 0);
+	if (drv->ifindex != 0) {
+		wpa_driver_bsd_set_wpa(drv, 0);
 
-	/* NB: mark interface down */
-	bsd_ctrl_iface(drv, 0);
+		/* NB: mark interface down */
+		bsd_ctrl_iface(drv, 0);
 
-	wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
+		wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa,
+						drv->prev_privacy);
 
-	if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
-		wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
-			__func__);
+		if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)
+		    < 0)
+			wpa_printf(MSG_DEBUG,
+				   "%s: failed to restore roaming state",
+				   __func__);
+	}
 
 	if (drv->sock_xmit != NULL)
 		l2_packet_deinit(drv->sock_xmit);