add a simplified vlist type
[project/netifd.git] / bridge.c
index 54526f7..5337e3a 100644 (file)
--- a/bridge.c
+++ b/bridge.c
@@ -65,6 +65,7 @@ struct bridge_state {
        struct bridge_config config;
        struct blob_attr *ifnames;
        bool active;
+       bool force_active;
 
        struct list_head members;
        int n_present;
@@ -119,6 +120,24 @@ error:
 }
 
 static void
+bridge_remove_member(struct bridge_member *bm)
+{
+       struct bridge_state *bst = bm->bst;
+
+       if (!bm->present)
+               return;
+
+       bm->present = false;
+       bm->bst->n_present--;
+       if (bst->dev.active)
+               bridge_disable_member(bm);
+
+       bst->force_active = false;
+       if (bst->n_present == 0)
+               device_set_present(&bst->dev, false);
+}
+
+static void
 bridge_member_cb(struct device_user *dev, enum device_event ev)
 {
        struct bridge_member *bm = container_of(dev, struct bridge_member, dev);
@@ -141,16 +160,11 @@ bridge_member_cb(struct device_user *dev, enum device_event ev)
                if (!bm->present)
                        return;
 
-               if (bst->dev.active)
-                       bridge_disable_member(bm);
-
-               bm->present = false;
-               bm->bst->n_present--;
-               if (bst->n_present == 0)
-                       device_set_present(&bst->dev, false);
-
                if (dev->hotplug)
                        bridge_free_member(bm);
+               else
+                       bridge_remove_member(bm);
+
                break;
        default:
                return;
@@ -178,7 +192,7 @@ bridge_set_up(struct bridge_state *bst)
        struct bridge_member *bm;
        int ret;
 
-       if (!bst->n_present)
+       if (!bst->force_active && !bst->n_present)
                return -ENOENT;
 
        ret = system_bridge_addbr(&bst->dev, &bst->config);
@@ -188,7 +202,7 @@ bridge_set_up(struct bridge_state *bst)
        list_for_each_entry(bm, &bst->members, list)
                bridge_enable_member(bm);
 
-       if (!bst->n_present) {
+       if (!bst->force_active && !bst->n_present) {
                /* initialization of all member interfaces failed */
                system_bridge_delbr(&bst->dev);
                device_set_present(&bst->dev, false);
@@ -235,15 +249,9 @@ bridge_create_member(struct bridge_state *bst, struct device *dev, bool hotplug)
 static void
 bridge_free_member(struct bridge_member *bm)
 {
-       if (bm->present) {
-               bridge_member_cb(&bm->dev, DEV_EVENT_REMOVE);
-               bm->bst->n_present--;
-               if (bm->bst->dev.active)
-                       bridge_disable_member(bm);
-       }
-
-       list_del(&bm->list);
+       bridge_remove_member(bm);
        device_remove_user(&bm->dev);
+       list_del(&bm->list);
        free(bm);
 }
 
@@ -283,10 +291,23 @@ bridge_hotplug_del(struct device *dev, struct device *member)
                return 0;
        }
 
-       return -ENOENT;
+       return UBUS_STATUS_NOT_FOUND;
+}
+
+static int
+bridge_hotplug_prepare(struct device *dev)
+{
+       struct bridge_state *bst;
+
+       bst = container_of(dev, struct bridge_state, dev);
+       bst->force_active = true;
+       device_set_present(&bst->dev, true);
+
+       return 0;
 }
 
 static const struct device_hotplug_ops bridge_ops = {
+       .prepare = bridge_hotplug_prepare,
        .add = bridge_hotplug_add,
        .del = bridge_hotplug_del
 };