summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2012-10-19 15:49:46 +0200
committerFelix Fietkau <nbd@openwrt.org>2012-10-19 15:49:46 +0200
commita9fd870450e82f31cba681651656276dfc1c39ac (patch)
treece680992d8a466a7610021c4bcd42c9431db9bf0
parent8125e561e33276cf80c5146c5fa3020b6f1425b8 (diff)
downloadnetifd-a9fd870450e82f31cba681651656276dfc1c39ac.tar.gz
bridge: toggle device present state after freeing a bridge member to ensure that it can be reassigned to a different bridge
-rw-r--r--bridge.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/bridge.c b/bridge.c
index d29c3c0..1d02f83 100644
--- a/bridge.c
+++ b/bridge.c
@@ -189,6 +189,29 @@ bridge_remove_member(struct bridge_member *bm)
}
static void
+bridge_free_member(struct bridge_member *bm)
+{
+ struct device *dev = bm->dev.dev;
+
+ bridge_remove_member(bm);
+ device_remove_user(&bm->dev);
+
+ /*
+ * When reloading the config and moving a device from one bridge to
+ * another, the other bridge may have tried to claim this device
+ * before it was removed here.
+ * Ensure that claiming the device is retried by toggling its present
+ * state
+ */
+ if (dev->present) {
+ device_set_present(dev, false);
+ device_set_present(dev, true);
+ }
+
+ free(bm);
+}
+
+static void
bridge_member_cb(struct device_user *dev, enum device_event ev)
{
struct bridge_member *bm = container_of(dev, struct bridge_member, dev);
@@ -323,9 +346,7 @@ bridge_member_update(struct vlist_tree *tree, struct vlist_node *node_new,
if (node_old) {
bm = container_of(node_old, struct bridge_member, node);
- bridge_remove_member(bm);
- device_remove_user(&bm->dev);
- free(bm);
+ bridge_free_member(bm);
}
}