bridge: check bridge port vlan membership on link-up events
[project/netifd.git] / bridge.c
index 6c8e79a47399ca88bdb7fa17f6a0fd0d7c008c9a..32796bf9ebb070f9c1c463cc8d427b8078a4cd25 100644 (file)
--- a/bridge.c
+++ b/bridge.c
@@ -122,17 +122,13 @@ struct bridge_member {
        struct vlist_node node;
        struct bridge_state *bst;
        struct device_user dev;
+       struct uloop_timeout check_timer;
        uint16_t pvid;
        bool present;
        bool active;
        char name[];
 };
 
-struct bridge_vlan_hotplug_port {
-       struct list_head list;
-       struct bridge_vlan_port port;
-};
-
 static void
 bridge_reset_primary(struct bridge_state *bst)
 {
@@ -477,6 +473,7 @@ restart:
        device_lock();
 
        device_remove_user(&bm->dev);
+       uloop_timeout_cancel(&bm->check_timer);
 
        /*
         * When reloading the config and moving a device from one bridge to
@@ -504,6 +501,22 @@ bridge_check_retry(struct bridge_state *bst)
        uloop_timeout_set(&bst->retry, 100);
 }
 
+static void
+bridge_member_check_cb(struct uloop_timeout *t)
+{
+       struct bridge_member *bm;
+       struct bridge_state *bst;
+
+       bm = container_of(t, struct bridge_member, check_timer);
+       bst = bm->bst;
+
+       if (!system_bridge_vlan_check(&bst->dev, bm->dev.dev->ifname))
+               return;
+
+       bridge_disable_member(bm, true);
+       bridge_enable_member(bm);
+}
+
 static void
 bridge_member_cb(struct device_user *dep, enum device_event ev)
 {
@@ -521,6 +534,9 @@ bridge_member_cb(struct device_user *dep, enum device_event ev)
                if (bst->n_present == 1)
                        device_set_present(&bst->dev, true);
                fallthrough;
+       case DEV_EVENT_LINK_UP:
+               uloop_timeout_set(&bm->check_timer, 1000);
+               break;
        case DEV_EVENT_AUTH_UP:
                if (!bst->dev.active)
                        break;
@@ -634,6 +650,7 @@ bridge_create_member(struct bridge_state *bst, const char *name,
        bm->bst = bst;
        bm->dev.cb = bridge_member_cb;
        bm->dev.hotplug = hotplug;
+       bm->check_timer.cb = bridge_member_check_cb;
        strcpy(bm->name, name);
        bm->dev.dev = dev;
        vlist_add(&bst->members, &bm->node, bm->name);