interface-ip: mask out host bits in IPv4 route targets
[project/netifd.git] / wireless.c
index 1e7d757e01d7b9de26b1e9cd5c99869a893a209f..7ad2fcf0aa484f97fc25d47177f0db3850b8d388 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");
@@ -438,6 +441,8 @@ wireless_device_run_handler(struct wireless_device *wdev, bool up)
                wdev->prev_config = NULL;
        } else {
                prepare_config(wdev, &b, up);
+               free(wdev->prev_config);
+               wdev->prev_config = up ? blob_memdup(b.head) : NULL;
                config = blobmsg_format_json(b.head, true);
        }
 
@@ -495,8 +500,6 @@ __wireless_device_set_up(struct wireless_device *wdev, int force)
        if ((!force && wdev->state != IFS_DOWN) || config_init)
                return;
 
-       free(wdev->prev_config);
-       wdev->prev_config = NULL;
        wdev->state = IFS_SETUP;
        wireless_device_run_handler(wdev, true);
 }
@@ -692,10 +695,8 @@ wdev_set_config_state(struct wireless_device *wdev, enum interface_config_state
 static void
 wdev_prepare_prev_config(struct wireless_device *wdev)
 {
-       if (wdev->prev_config)
-               return;
-
        prepare_config(wdev, &b, false);
+       free(wdev->prev_config);
        wdev->prev_config = blob_memdup(b.head);
 }
 
@@ -709,7 +710,6 @@ wdev_change_config(struct wireless_device *wdev, struct wireless_device *wd_new)
        wdev->serialize = wd_new->serialize;
        free(wd_new);
 
-       wdev_prepare_prev_config(wdev);
        if (blob_attr_equal(wdev->config, new_config) && wdev->disabled == disabled)
                return;
 
@@ -1519,6 +1519,7 @@ wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data,
                        wireless_vlan_set_data(vlan);
                else if (vif)
                        wireless_interface_set_data(vif);
+               wdev_prepare_prev_config(wdev);
                break;
        case NOTIFY_CMD_PROCESS_ADD:
                return wireless_device_add_process(wdev, cur);
@@ -1533,19 +1534,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;