if (!port)
return;
- if (bridge_member_vlan_is_pvid(bm, port))
+ if (!add && bm->pvid == vlan->vid)
+ bm->pvid = 0;
+ else if (add && bridge_member_vlan_is_pvid(bm, port))
bm->pvid = vlan->vid;
__bridge_set_member_vlan(bm, vlan, port, add);
{
struct bridge_member *bm;
struct bridge_vlan *vlan2;
+ bool clear_pvid = false;
bridge_set_local_vlan(bst, vlan, add);
vlist_for_each_element(&bst->members, bm, node) {
struct bridge_vlan_port *port;
- int new_pvid = -1;
port = bridge_find_vlan_member_port(bm, vlan);
if (!port)
vlan2 = bridge_recalc_member_pvid(bm);
if (vlan2 && vlan2->vid != vlan->vid) {
bridge_set_member_vlan(bm, vlan2, false);
+ bm->pvid = vlan2->vid;
bridge_set_member_vlan(bm, vlan2, true);
+ } else if (!vlan2) {
+ clear_pvid = true;
}
- new_pvid = vlan2 ? vlan2->vid : 0;
}
- if (!bm->present)
- continue;
+ if (bm->present)
+ __bridge_set_member_vlan(bm, vlan, port, add);
- __bridge_set_member_vlan(bm, vlan, port, add);
- if (new_pvid >= 0)
- bm->pvid = new_pvid;
+ if (clear_pvid)
+ bm->pvid = 0;
}
}
bm->extra_vlan[i].end, true, 0);
}
+static void
+bridge_member_enable_vlans(struct bridge_member *bm)
+{
+ struct bridge_state *bst = bm->bst;
+ struct device *dev = bm->dev.dev;
+ struct bridge_vlan *vlan;
+
+ if (dev->settings.auth) {
+ bridge_hotplug_set_member_vlans(bst, dev->config_auth_vlans, bm,
+ !dev->auth_status, true);
+ bridge_hotplug_set_member_vlans(bst, dev->auth_vlans, bm,
+ dev->auth_status, true);
+ }
+
+ if (dev->settings.auth && !dev->auth_status)
+ return;
+
+ bridge_member_add_extra_vlans(bm);
+ vlist_for_each_element(&bst->dev.vlans, vlan, node)
+ bridge_set_member_vlan(bm, vlan, true);
+}
+
static int
bridge_enable_member(struct bridge_member *bm)
{
struct bridge_state *bst = bm->bst;
- struct bridge_vlan *vlan;
struct device *dev;
int ret;
goto error;
dev = bm->dev.dev;
- if (dev->settings.auth && !dev->auth_status)
+ if (dev->settings.auth && !bst->has_vlans && !dev->auth_status)
return -1;
- if (bm->active)
- return 0;
+ if (!bm->active) {
+ ret = system_bridge_addif(&bst->dev, bm->dev.dev);
+ if (ret < 0) {
+ D(DEVICE, "Bridge device %s could not be added", bm->dev.dev->ifname);
+ goto error;
+ }
- ret = system_bridge_addif(&bst->dev, bm->dev.dev);
- if (ret < 0) {
- D(DEVICE, "Bridge device %s could not be added\n", bm->dev.dev->ifname);
- goto error;
+ bm->active = true;
}
- bm->active = true;
if (bst->has_vlans) {
/* delete default VLAN 1 */
system_bridge_vlan(bm->dev.dev->ifname, 1, -1, false, 0);
- bridge_member_add_extra_vlans(bm);
- vlist_for_each_element(&bst->dev.vlans, vlan, node)
- bridge_set_member_vlan(bm, vlan, true);
- if (dev->settings.auth && dev->auth_vlans)
- bridge_hotplug_set_member_vlans(bst, dev->auth_vlans, bm, true, true);
+ bridge_member_enable_vlans(bm);
}
device_set_present(&bst->dev, true);
- device_broadcast_event(&bst->dev, DEV_EVENT_TOPO_CHANGE);
+ if (!dev->settings.auth || dev->auth_status)
+ device_broadcast_event(&bst->dev, DEV_EVENT_TOPO_CHANGE);
return 0;
DEV_OPT_MTU | DEV_OPT_MTU6);
break;
case DEV_EVENT_LINK_UP:
- if (bst->has_vlans)
- uloop_timeout_set(&bm->check_timer, 1000);
+ if (!bst->has_vlans)
+ break;
+
+ if (dev->settings.auth)
+ bridge_enable_member(bm);
+
+ uloop_timeout_set(&bm->check_timer, 1000);
break;
case DEV_EVENT_LINK_DOWN:
if (!dev->settings.auth)
bridge_disable_member(bm, true);
break;
case DEV_EVENT_REMOVE:
- if (dep->hotplug) {
+ if (dep->hotplug && !dev->sys_present) {
vlist_delete(&bst->members, &bm->node);
return;
}
struct blob_attr *tb_br[__BRIDGE_ATTR_MAX];
enum dev_change_type ret = DEV_CONFIG_APPLIED;
struct bridge_state *bst;
- unsigned long diff[2];
+ unsigned long diff[2] = {};
BUILD_BUG_ON(sizeof(diff) < __BRIDGE_ATTR_MAX / BITS_PER_LONG);
BUILD_BUG_ON(sizeof(diff) < __DEV_ATTR_MAX / BITS_PER_LONG);
blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, otb_dev,
blob_data(bst->config_data), blob_len(bst->config_data));
- diff[0] = diff[1] = 0;
uci_blob_diff(tb_dev, otb_dev, &device_attr_list, diff);
if (diff[0] | diff[1]) {
ret = DEV_CONFIG_RESTART;
- D(DEVICE, "Bridge %s device attributes have changed, diff=[%lx %lx]\n",
+ D(DEVICE, "Bridge %s device attributes have changed, diff=[%lx %lx]",
dev->ifname, diff[1], diff[0]);
}
uci_blob_diff(tb_br, otb_br, &bridge_attr_list, diff);
if (diff[0] & ~(1 << BRIDGE_ATTR_PORTS)) {
ret = DEV_CONFIG_RESTART;
- D(DEVICE, "Bridge %s attributes have changed, diff=[%lx %lx]\n",
+ D(DEVICE, "Bridge %s attributes have changed, diff=[%lx %lx]",
dev->ifname, diff[1], diff[0]);
}
struct bridge_state *bst = container_of(tree, struct bridge_state, dev.vlans);
struct bridge_vlan *vlan_new = NULL, *vlan_old = NULL;
- if (!bst->has_vlans || !bst->active)
- goto out;
-
if (node_old)
vlan_old = container_of(node_old, struct bridge_vlan, node);
if (node_new)
vlan_new = container_of(node_new, struct bridge_vlan, node);
+ if (!bst->has_vlans || !bst->active)
+ goto out;
+
if (node_new && node_old && bridge_vlan_equal(vlan_old, vlan_new)) {
list_splice_init(&vlan_old->hotplug_ports, &vlan_new->hotplug_ports);
goto out;
if (node_new)
vlan_new->pending = true;
- bst->dev.config_pending = true;
-
out:
+ bst->dev.config_pending = true;
bridge_vlan_free(vlan_old);
}