@@ -103,6 +103,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
@@ -649,14 +649,16 @@ static void vlan_newlink_vlan(const int vlan_id, char *ifname, int *clean,
*clean |= DVLAN_CLEAN_WLAN_PORT;
}
-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);
@@ -697,6 +699,7 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
* vlan entry is freed uplink RTM_DELLINK
*/
vlan->newlink_seen = 1;
+ vlan->ifidx = ifidx;
break;
}
}
@@ -753,7 +756,7 @@ static void vlan_dellink_vlan(int vlan_id, char* ifname, int *clean,
*clean = 0;
}
-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];
@@ -761,7 +764,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)",
@@ -813,7 +817,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))
@@ -827,6 +831,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));
@@ -845,9 +850,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);
@@ -1023,21 +1028,29 @@ static void vlan_dynamic_remove(struct hostapd_data *hapd,
struct hostapd_vlan *vlan)
{
struct hostapd_vlan *next;
+ char buf[IFNAMSIZ+1];
+ vlan_t 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_strncpy(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;
}
}
@@ -1153,6 +1166,8 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
os_free(n);
return NULL;
}
+ // if id_add returned the ifidx, it could be reused here
+ n->ifidx = if_nametoindex(n->ifname);
/* insert into list */
if (!prev) {
@@ -1174,6 +1189,7 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
int vlan_remove_dynamic(struct hostapd_data *hapd, vlan_t vlan_id)
{
struct hostapd_vlan *vlan;
+ char buf[IFNAMSIZ+1];
if (vlan_untagged(&vlan->vlan_id) == VLAN_ID_WILDCARD)
return 1;
@@ -1194,8 +1210,12 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, vlan_t vlan_id)
if (vlan == NULL)
return 1;
- if (vlan->dynamic_vlan == 0)
- hostapd_vlan_if_remove(hapd, vlan->ifname);
+ if (vlan->dynamic_vlan == 0) {
+ os_strncpy(buf, vlan->ifname, sizeof(buf));
+ vlan_dellink(buf, vlan->ifidx, hapd);
+ vlan = NULL; /* freed by vlan_dellink */
+ hostapd_vlan_if_remove(hapd, buf);
+ }
return 0;
}