diff options
Diffstat (limited to 'bridge.c')
-rw-r--r-- | bridge.c | 54 |
1 files changed, 50 insertions, 4 deletions
@@ -706,8 +706,21 @@ bridge_hotplug_get_vlan(struct bridge_state *bst, unsigned int vid) return vlan; } +static struct bridge_vlan_hotplug_port * +bridge_hotplug_get_vlan_port(struct bridge_vlan *vlan, const char *ifname) +{ + struct bridge_vlan_hotplug_port *port; + + list_for_each_entry(port, &vlan->hotplug_ports, list) + if (!strcmp(port->port.ifname, ifname)) + return port; + + return NULL; +} + static void -bridge_hotplug_create_member_vlans(struct bridge_state *bst, struct blob_attr *vlans, const char *ifname) +bridge_hotplug_set_member_vlans(struct bridge_state *bst, struct blob_attr *vlans, + const char *ifname, struct bridge_member *bm, bool add) { struct bridge_vlan *vlan; struct blob_attr *cur; @@ -750,6 +763,27 @@ bridge_hotplug_create_member_vlans(struct bridge_state *bst, struct blob_attr *v } } + port = bridge_hotplug_get_vlan_port(vlan, ifname); + if (!add) { + if (!port) + continue; + + __bridge_set_member_vlan(bm, vlan, &port->port, false); + list_del(&port->list); + free(port); + continue; + } + + if (port) { + if (port->port.flags == flags) + continue; + + __bridge_set_member_vlan(bm, vlan, &port->port, false); + port->port.flags = flags; + __bridge_set_member_vlan(bm, vlan, &port->port, true); + continue; + } + port = calloc_a(sizeof(*port), &name_buf, strlen(ifname) + 1); if (!port) continue; @@ -757,6 +791,11 @@ bridge_hotplug_create_member_vlans(struct bridge_state *bst, struct blob_attr *v port->port.flags = flags; port->port.ifname = strcpy(name_buf, ifname); list_add_tail(&port->list, &vlan->hotplug_ports); + + if (!bm) + continue; + + __bridge_set_member_vlan(bm, vlan, &port->port, true); } } @@ -764,15 +803,18 @@ static int bridge_hotplug_add(struct device *dev, struct device *member, struct blob_attr *vlan) { struct bridge_state *bst = container_of(dev, struct bridge_state, dev); + struct bridge_member *bm; - bridge_hotplug_create_member_vlans(bst, vlan, member->ifname); - bridge_create_member(bst, member->ifname, member, true); + bm = vlist_find(&bst->members, member->ifname, bm, node); + bridge_hotplug_set_member_vlans(bst, vlan, member->ifname, bm, true); + if (!bm) + bridge_create_member(bst, member->ifname, member, true); return 0; } static int -bridge_hotplug_del(struct device *dev, struct device *member) +bridge_hotplug_del(struct device *dev, struct device *member, struct blob_attr *vlan) { struct bridge_state *bst = container_of(dev, struct bridge_state, dev); struct bridge_member *bm; @@ -781,6 +823,10 @@ bridge_hotplug_del(struct device *dev, struct device *member) if (!bm) return UBUS_STATUS_NOT_FOUND; + bridge_hotplug_set_member_vlans(bst, vlan, member->ifname, bm, false); + if (!bm->dev.hotplug) + return 0; + vlist_delete(&bst->members, &bm->node); return 0; } |