[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