summaryrefslogtreecommitdiff
path: root/bridge.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2021-07-23 11:04:45 +0200
committerFelix Fietkau <nbd@nbd.name>2021-07-23 11:04:47 +0200
commit85f01c44a950be8518ce5a7d251b5bba219348cf (patch)
tree5b415838ce2606394aee5a37e61728a8290117ff /bridge.c
parent7f24a063475e1e2be4e0c516a5b62c3fae5ec542 (diff)
downloadnetifd-85f01c44a950be8518ce5a7d251b5bba219348cf.tar.gz
bridge: check bridge port vlan membership on link-up events
When changing to a dfs channel, hostapd can bring down wlan interfaces and reset their bridge membership. If that happens, the port loses its vlan membership settings and needs to be reconfigured by netifd. Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'bridge.c')
-rw-r--r--bridge.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/bridge.c b/bridge.c
index 6c8e79a..32796bf 100644
--- 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
@@ -505,6 +502,22 @@ bridge_check_retry(struct bridge_state *bst)
}
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)
{
struct bridge_member *bm = container_of(dep, struct bridge_member, dev);
@@ -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);