[PATCH 38/44] nl80211: cleanup ifidx properly

michael-dev at fami-braun.de michael-dev at fami-braun.de
Wed Feb 24 03:53:44 PST 2016


From: Michael Braun <michael-dev at fami-braun.de>

When an interface is removed while it was in a bridge, the bridge was not
removed from ifidx list.

Signed-off-by: Michael Braun <michael-dev at fami-braun.de>
---
 src/drivers/driver_nl80211.c | 100 ++++++++++++++++++++++++++++++++-----------
 src/drivers/driver_nl80211.h |   3 ++
 2 files changed, 79 insertions(+), 24 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 3e6ee3b..2d1bf18 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -182,9 +182,12 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
 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);
+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);
@@ -893,7 +896,7 @@ nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
 	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, -1))
 			return drv;
 	}
 	return NULL;
@@ -1072,7 +1075,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 		}
 		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) {
@@ -1159,7 +1162,7 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
 				   "nl80211: Remove ifindex %u for bridge %s",
 				   brid, namebuf);
 		}
-		del_ifidx(drv, brid);
+		del_ifidx(drv, brid, ifi->ifi_index);
 	}
 }
 
@@ -1726,6 +1729,7 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
 
 	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) {
@@ -2400,6 +2404,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 	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);
 
@@ -4079,7 +4086,11 @@ void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
 	/* 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, -1);
+		/* remove all bridges learned for this iface */
+		del_ifidx(drv2, -1, ifidx);
+	}
 
 	msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
 	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
@@ -4187,7 +4198,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 	    iftype == NL80211_IFTYPE_WDS ||
 	    iftype == NL80211_IFTYPE_MONITOR) {
 		/* start listening for EAPOL on this interface */
-		add_ifidx(drv, ifidx);
+		add_ifidx(drv, ifidx, -1);
 	}
 
 	if (addr && iftype != NL80211_IFTYPE_MONITOR &&
@@ -5649,6 +5660,11 @@ static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
 		if (os_snprintf_error(end - pos, res))
 			break;
 		pos += res;
+		res = os_snprintf(pos, end - pos, "(%d)",
+				  drv->if_indices_reason[i]);
+		if (os_snprintf_error(end - pos, res))
+			break;
+		pos += res;
 	}
 	*pos = '\0';
 
@@ -5657,14 +5673,15 @@ static void dump_ifidx(struct wpa_driver_nl80211_data *drv)
 }
 
 
-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)) {
+	if (have_ifidx(drv, ifidx, ifidx_reason)) {
 		wpa_printf(MSG_DEBUG, "nl80211: ifindex %d already in the list",
 			   ifidx);
 		return;
@@ -5672,6 +5689,7 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 	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;
 		}
@@ -5682,32 +5700,57 @@ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 	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 == -1) &&
+		    (drv->if_indices_reason[i] == ifidx_reason
+		     || ifidx_reason == -1)) {
 			drv->if_indices[i] = 0;
 			break;
 		}
@@ -5716,12 +5759,15 @@ static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 }
 
 
-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 == -1))
 			return 1;
 
 	return 0;
@@ -5776,6 +5822,7 @@ static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
 	struct sockaddr_ll lladdr;
 	unsigned char buf[3000];
 	int len;
+	char namebuf[IFNAMSIZ];
 	socklen_t fromlen = sizeof(lladdr);
 
 	len = recvfrom(sock, buf, sizeof(buf), 0,
@@ -5785,8 +5832,10 @@ static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
 			   strerror(errno));
 		return;
 	}
+	os_memset(namebuf, 0, sizeof(namebuf));
+	if_indextoname(lladdr.sll_ifindex, namebuf);
 
-	if (have_ifidx(drv, lladdr.sll_ifindex))
+	if (have_ifidx(drv, lladdr.sll_ifindex, -1))
 		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
 }
 
@@ -5813,7 +5862,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
 		}
 		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;
 
@@ -5875,7 +5924,7 @@ static void *i802_init(struct hostapd_data *hapd,
 		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';
 	}
@@ -5886,14 +5935,14 @@ static void *i802_init(struct hostapd_data *hapd,
 		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, -1);
 
 	if (params->num_bridge && params->bridge[0]) {
 		if (i802_check_bridge(drv, bss, params->bridge[0],
@@ -5905,7 +5954,7 @@ static void *i802_init(struct hostapd_data *hapd,
 
 	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) {
@@ -6191,7 +6240,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
 	     nlmode == NL80211_IFTYPE_AP_VLAN ||
 	     nlmode == NL80211_IFTYPE_WDS ||
 	     nlmode == NL80211_IFTYPE_MONITOR))
-		add_ifidx(drv, ifidx);
+		add_ifidx(drv, ifidx, -1);
 
 	return 0;
 }
@@ -6212,7 +6261,10 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
 		struct wpa_driver_nl80211_data *drv2;
 		dl_list_for_each(drv2, &drv->global->interfaces,
 				 struct wpa_driver_nl80211_data, list)
-			del_ifidx(drv2, ifindex);
+		{
+			del_ifidx(drv2, ifindex, -1);
+			del_ifidx(drv2, -1, ifindex);
+		}
 	}
 
 	if (type != WPA_IF_AP_BSS)
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 4fa7d5f..430369f 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -172,7 +172,10 @@ struct wpa_driver_nl80211_data {
 	struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
 
 	int default_if_indices[16];
+	/* the AP/AP_VLAN iface that is in this bridge */
+	int default_if_indices_reason[16];
 	int *if_indices;
+	int *if_indices_reason;
 	int num_if_indices;
 
 	/* From failed authentication command */
-- 
1.9.1




More information about the Hostap mailing list