[PATCH v5 21/22] VLAN: ensure destroying interfaces goes reverse as creating
Michael Braun
michael-dev
Tue Nov 19 11:48:25 PST 2013
This fixes a race condition:
1. STA removal triggers dynamic interface removal
2. STA reconnects, finds VLAN still present but fails to set key
(detecting the VLAN has been removed here would generate
a NEWLINK messages after 3. but that would be pointless,
due to 3. removing the vlan from hapd->conf->vlan, which
is required for manual vlan interface removal)
3. DELLINK is processed, removes the VLAN although in use
Signed-hostap: Michael Braun <michael-dev at fami-braun.de>
---
src/ap/ap_config.h | 3 +++
src/ap/vlan_init.c | 57 ++++++++++++++++++++++++++++++++++++----------------
2 files changed, 43 insertions(+), 17 deletions(-)
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index f51b6a8..df30423 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -97,6 +97,9 @@ struct hostapd_vlan {
* freed.
*/
int newlink_seen;
+ /* Make sure DELLINK processing does not affect newly created
+ * interfaces. */
+ int ifidx;
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index ab6ac97..a6c21e2 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -653,14 +653,16 @@ static void vlan_newlink_vlan(const int vlan_id, char *ifname, int *clean,
}
-static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
+static void vlan_newlink(char *ifname, int ifidx, struct hostapd_data *hapd)
{
struct hostapd_vlan *vlan;
char vlan_ifname[IFNAMSIZ+1];
int i, ret;
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
- if (os_strcmp(ifname, vlan->ifname) != 0 || vlan->newlink_seen)
+ if (os_strcmp(ifname, vlan->ifname) != 0 ||
+ vlan->newlink_seen ||
+ (vlan->ifidx > 0 && ifidx > 0 && vlan->ifidx != ifidx))
continue;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
@@ -698,7 +700,7 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
}
vlan->newlink_seen = 1;
-
+ vlan->ifidx = ifidx;
break;
}
}
@@ -760,7 +762,7 @@ static void vlan_dellink_vlan(int vlan_id, char* ifname, int *clean,
}
-static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
+static void vlan_dellink(char *ifname, int ifidx, struct hostapd_data *hapd)
{
struct hostapd_vlan *first, *prev, *vlan;
char vlan_ifname[IFNAMSIZ];
@@ -768,7 +770,8 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
for (first = prev = vlan = hapd->conf->vlan; vlan;
prev = vlan, vlan = vlan->next) {
- if (os_strcmp(ifname, vlan->ifname) != 0)
+ if (os_strcmp(ifname, vlan->ifname) != 0 ||
+ (vlan->ifidx > 0 && ifidx > 0 && vlan->ifidx != ifidx))
continue;
wpa_printf(MSG_DEBUG, "VLAN:%s: vlan_dellink(%s)",
@@ -820,7 +823,7 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
struct hostapd_data *hapd)
{
struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
+ int attrlen, nlmsg_len, rta_len, ifidx;
struct rtattr *attr;
if (len < sizeof(*ifi))
@@ -834,6 +837,7 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
if (attrlen < 0)
return;
+ ifidx = ifi->ifi_index;
attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
rta_len = RTA_ALIGN(sizeof(struct rtattr));
@@ -852,9 +856,9 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
os_memcpy(ifname, ((char *) attr) + rta_len, n);
if (del)
- vlan_dellink(ifname, hapd);
+ vlan_dellink(ifname, ifidx, hapd);
else
- vlan_newlink(ifname, hapd);
+ vlan_newlink(ifname, ifidx, hapd);
}
attr = RTA_NEXT(attr, attrlen);
@@ -1030,21 +1034,29 @@ static void vlan_dynamic_remove(struct hostapd_data *hapd,
struct hostapd_vlan *vlan)
{
struct hostapd_vlan *next;
+ char buf[IFNAMSIZ+1];
+ struct vlan_description vlan_id = VLAN_NULL;
while (vlan) {
next = vlan->next;
- if (vlan_untagged(&vlan->vlan_id) != VLAN_ID_WILDCARD &&
- hostapd_vlan_if_remove(hapd, vlan->ifname)) {
- wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
- "iface: %s: %s",
- vlan->ifname, strerror(errno));
- }
+ vlan_alloc_copy(&vlan_id, &vlan->vlan_id);
+ os_strlcpy(buf, vlan->ifname, sizeof(buf));
+
#ifdef CONFIG_FULL_DYNAMIC_VLAN
if (vlan->clean)
- vlan_dellink(vlan->ifname, hapd);
+ vlan_dellink(buf, vlan->ifidx, hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+ if (vlan_untagged(&vlan_id) != VLAN_ID_WILDCARD &&
+ hostapd_vlan_if_remove(hapd, buf)) {
+ wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
+ "iface: %s: %s",
+ buf, strerror(errno));
+ }
+
+ vlan_free(&vlan_id);
+
vlan = next;
}
}
@@ -1161,6 +1173,10 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
os_free(n);
return NULL;
}
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ // if id_add returned the ifidx, it could be reused here
+ n->ifidx = if_nametoindex(n->ifname);
+#endif
/* insert into list */
if (!prev) {
@@ -1183,6 +1199,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd,
struct vlan_description vlan_id)
{
struct hostapd_vlan *vlan;
+ char buf[IFNAMSIZ+1];
if (vlan_untagged(&vlan_id) == VLAN_ID_WILDCARD)
return 1;
@@ -1203,8 +1220,14 @@ int vlan_remove_dynamic(struct hostapd_data *hapd,
if (vlan == NULL)
return 1;
- if (vlan->dynamic_vlan == 0)
- hostapd_vlan_if_remove(hapd, vlan->ifname);
+ if (vlan->dynamic_vlan == 0) {
+ os_strlcpy(buf, vlan->ifname, sizeof(buf));
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ vlan_dellink(buf, vlan->ifidx, hapd);
+#endif
+ vlan = NULL; /* freed by vlan_dellink */
+ hostapd_vlan_if_remove(hapd, buf);
+ }
return 0;
}
More information about the Hostap
mailing list