wireless: dynamically enable/disable virtual interfaces base on network interface...
authorFelix Fietkau <nbd@nbd.name>
Fri, 15 Sep 2023 18:30:04 +0000 (20:30 +0200)
committerFelix Fietkau <nbd@nbd.name>
Fri, 15 Sep 2023 18:30:05 +0000 (20:30 +0200)
This allows disabling individual interfaces with ifup/ifdown calls

Signed-off-by: Felix Fietkau <nbd@nbd.name>
config.c
interface.c
wireless.c
wireless.h

index 8f4a383157d8881e41f9d259c94e0b28270dfb23..dbf44257cce205189666fb2b7b682acfc12a7691 100644 (file)
--- a/config.c
+++ b/config.c
@@ -784,7 +784,7 @@ config_init_all(void)
        vlist_flush(&interfaces);
        interface_refresh_assignments(false);
        interface_start_pending();
-       wireless_start_pending();
+       wireless_start_pending(0);
 
        return ret;
 }
index 66e0e80d72ba027f194210b3610c486709c80b7a..a18e872c832b538a7bd27f9607b7a02732567613 100644 (file)
@@ -25,6 +25,7 @@
 #include "ubus.h"
 #include "config.h"
 #include "system.h"
+#include "wireless.h"
 
 struct vlist_tree interfaces;
 static LIST_HEAD(iface_all_users);
@@ -1125,6 +1126,7 @@ interface_set_up(struct interface *iface)
        const char *error = NULL;
 
        iface->autostart = true;
+       wireless_check_network_enabled();
 
        if (iface->state != IFS_DOWN)
                return;
@@ -1157,6 +1159,7 @@ interface_set_down(struct interface *iface)
                        __interface_set_down(iface, false);
        } else {
                iface->autostart = false;
+               wireless_check_network_enabled();
                __interface_set_down(iface, false);
        }
 }
index 958080eca2a56bbfe3dd765a30408f5caa57da8d..a21bf54d6f5dbfe20bf2686f3e9f72445bdac5c3 100644 (file)
@@ -198,6 +198,9 @@ prepare_config(struct wireless_device *wdev, struct blob_buf *buf, bool up)
 
        l = blobmsg_open_table(&b, "interfaces");
        vlist_for_each_element(&wdev->interfaces, vif, node) {
+               if (vif->disabled)
+                       continue;
+
                i = blobmsg_open_table(&b, vif->name);
                vif_config_add_bridge(&b, vif->network, up);
                put_container(&b, vif->config, "config");
@@ -1522,19 +1525,78 @@ wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data,
        return 0;
 }
 
-/* called on startup and by netifd reload() */
-void
-wireless_start_pending(void)
+static void
+wdev_check_network_enabled(struct wireless_device *wdev)
+{
+       struct wireless_interface *vif;
+       struct interface *iface;
+       struct blob_attr *cur;
+       int rem;
+
+       vlist_for_each_element(&wdev->interfaces, vif, node) {
+               int enabled = -1;
+
+               blobmsg_for_each_attr(cur, vif->network, rem) {
+                       iface = vlist_find(&interfaces, blobmsg_get_string(cur), iface, node);
+                       if (!iface)
+                               continue;
+
+                       if (iface->autostart) {
+                               enabled = 1;
+                               break;
+                       }
+                       if (enabled != 1)
+                               enabled = 0;
+               }
+
+               if (vif->disabled == !enabled)
+                       continue;
+
+               vif->disabled = !enabled;
+               wdev->config_update = true;
+       }
+}
+
+static void
+__wireless_start_pending(struct uloop_timeout *t)
 {
        struct wireless_device *wdev;
 
        vlist_for_each_element(&wireless_devices, wdev, node) {
+               wdev_check_network_enabled(wdev);
                if (wdev->config_update)
                        wdev_set_config_state(wdev, IFC_RELOAD);
                __wireless_device_set_up(wdev, 0);
        }
 }
 
+void wireless_start_pending(int timeout)
+{
+       static struct uloop_timeout timer = {
+               .cb = __wireless_start_pending
+       };
+
+       if (timeout) {
+               uloop_timeout_set(&timer, timeout);
+               return;
+       }
+
+       uloop_timeout_cancel(&timer);
+       timer.cb(&timer);
+}
+
+void wireless_check_network_enabled(void)
+{
+       struct wireless_device *wdev;
+
+       vlist_for_each_element(&wireless_devices, wdev, node) {
+               wdev_check_network_enabled(wdev);
+
+               if (wdev->config_update)
+                       wireless_start_pending(1000);
+       }
+}
+
 void wireless_device_hotplug_event(const char *name, bool add)
 {
        struct wireless_interface *vif;
index eaf75f72e2cff084ee9400e527fca66629c9079b..f8bbd2fbcb04d60b0de64b57fd9feac4c2f9868c 100644 (file)
@@ -94,6 +94,7 @@ struct wireless_interface {
        int multicast_to_unicast;
        int vlan_idx;
        int sta_idx;
+       bool disabled;
 };
 
 struct wireless_vlan {
@@ -142,7 +143,8 @@ void wireless_station_create(struct wireless_interface *vif, struct blob_attr *d
 int wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data,
                           struct ubus_request_data *req);
 
-void wireless_start_pending(void);
+void wireless_check_network_enabled(void);
+void wireless_start_pending(int timeout);
 void wireless_init(void);
 void wireless_device_hotplug_event(const char *name, bool add);