wireless: make reconf opt-in and allow serializing configuration
authorJohn Crispin <john@phrozen.org>
Fri, 25 Oct 2019 12:06:30 +0000 (14:06 +0200)
committerDaniel Golle <daniel@makrotopia.org>
Tue, 12 Nov 2019 10:27:24 +0000 (11:27 +0100)
Add option 'reconf' to make dynamic re-configuration opt-in.
Also add option 'serialize' to 'wifi-device' section and if set
configure interfaces of wireless devices one-by-one.
Both options are disabled by default.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
wireless.c
wireless.h

index 9986e9a4455f7081a451c0d2ca2d03c30c168513..c8e196f9bd5753d465499533ef8ec1b4b0c8088d 100644 (file)
@@ -23,13 +23,25 @@ struct vlist_tree wireless_devices;
 struct avl_tree wireless_drivers;
 static struct blob_buf b;
 static int drv_fd;
+static LIST_HEAD(handlers);
+static bool handler_pending;
 
-static const struct blobmsg_policy wdev_policy =
-       { .name = "disabled", .type = BLOBMSG_TYPE_BOOL };
+enum {
+       WDEV_ATTR_DISABLED,
+       WDEV_ATTR_RECONF,
+       WDEV_ATTR_SERIALIZE,
+       __WDEV_ATTR_MAX,
+};
+
+static const struct blobmsg_policy wdev_policy[__WDEV_ATTR_MAX] = {
+       [WDEV_ATTR_DISABLED] = { .name = "disabled", .type = BLOBMSG_TYPE_BOOL },
+       [WDEV_ATTR_RECONF] = { .name = "reconf", .type = BLOBMSG_TYPE_BOOL },
+       [WDEV_ATTR_SERIALIZE] = { .name = "serialize", .type = BLOBMSG_TYPE_BOOL },
+};
 
 static const struct uci_blob_param_list wdev_param = {
-       .n_params = 1,
-       .params = &wdev_policy,
+       .n_params = ARRAY_SIZE(wdev_policy),
+       .params = wdev_policy,
 };
 
 enum {
@@ -52,6 +64,15 @@ static const struct uci_blob_param_list vif_param = {
        .params = vif_policy,
 };
 
+static void
+wireless_handler_stop(struct wireless_device *wdev)
+{
+       if (wdev->handler_pending) {
+               wdev->handler_pending = false;
+               list_del(&wdev->handler);
+       }
+}
+
 static void
 put_container(struct blob_buf *buf, struct blob_attr *attr, const char *name)
 {
@@ -188,6 +209,7 @@ wireless_device_free_state(struct wireless_device *wdev)
 {
        struct wireless_interface *vif;
 
+       wireless_handler_stop(wdev);
        uloop_timeout_cancel(&wdev->script_check);
        uloop_timeout_cancel(&wdev->timeout);
        wireless_complete_kill_request(wdev);
@@ -236,6 +258,7 @@ wireless_device_setup_cancel(struct wireless_device *wdev)
        if (wdev->cancel)
                return;
 
+       wireless_handler_stop(wdev);
        D(WIRELESS, "Cancel wireless device '%s' setup\n", wdev->name);
        wdev->cancel = true;
        uloop_timeout_set(&wdev->timeout, 10 * 1000);
@@ -250,6 +273,17 @@ wireless_device_run_handler(struct wireless_device *wdev, bool up)
        int i = 0;
        int fds[2] = { -1, -1 };
 
+       wireless_handler_stop(wdev);
+
+       if (handler_pending && wdev->serialize) {
+               wdev->handler_action = up;
+               wdev->handler_pending = true;
+               list_add_tail(&wdev->handler, &handlers);
+               return;
+       }
+       if (wdev->serialize)
+               handler_pending = true;
+
        D(WIRELESS, "Wireless device '%s' run %s handler\n", wdev->name, action);
        if (!up && wdev->prev_config) {
                config = blobmsg_format_json(wdev->prev_config, true);
@@ -281,6 +315,21 @@ wireless_device_run_handler(struct wireless_device *wdev, bool up)
        free(config);
 }
 
+static void
+wireless_handler_next(void)
+{
+       struct wireless_device *wdev;
+
+       if (handler_pending)
+               return;
+       if (list_empty(&handlers))
+               return;
+       wdev = list_first_entry(&handlers, struct wireless_device, handler);
+       list_del(&wdev->handler);
+       wdev->handler_pending = false;
+       wireless_device_run_handler(wdev, wdev->handler_action);
+}
+
 static void
 __wireless_device_set_up(struct wireless_device *wdev, int force)
 {
@@ -305,6 +354,7 @@ __wireless_device_set_up(struct wireless_device *wdev, int force)
 static void
 wireless_device_free(struct wireless_device *wdev)
 {
+       wireless_handler_stop(wdev);
        vlist_flush_all(&wdev->interfaces);
        avl_delete(&wireless_devices.avl, &wdev->node.avl);
        free(wdev->config);
@@ -353,6 +403,10 @@ wireless_device_setup_timeout(struct uloop_timeout *timeout)
 {
        struct wireless_device *wdev = container_of(timeout, struct wireless_device, timeout);
 
+       if (wdev->handler_pending) {
+               wdev->handler_pending = false;
+               list_del(&wdev->handler);
+       }
        netifd_kill_process(&wdev->script_task);
        wdev->script_task.cb(&wdev->script_task, -1);
        wireless_device_mark_down(wdev);
@@ -371,7 +425,7 @@ wireless_device_reconf(struct wireless_device *wdev)
 {
        wdev->retry = WIRELESS_SETUP_RETRY;
        wdev->autostart = true;
-       __wireless_device_set_up(wdev, 1);
+       __wireless_device_set_up(wdev, wdev->reconf && (wdev->state == IFS_UP));
 }
 
 static void
@@ -433,6 +487,11 @@ wireless_device_script_task_cb(struct netifd_process *proc, int ret)
        default:
                break;
        }
+
+       if (wdev->serialize) {
+               handler_pending = false;
+               wireless_handler_next();
+       }
 }
 
 void
@@ -452,7 +511,7 @@ wdev_set_config_state(struct wireless_device *wdev, enum interface_config_state
        wdev->config_state = s;
        if (wdev->state == IFS_DOWN)
                wdev_handle_config_change(wdev);
-       else
+       else if (!wdev->reconf || wdev->state != IFS_UP)
                __wireless_device_set_down(wdev);
 }
 
@@ -501,6 +560,7 @@ wdev_update(struct vlist_tree *tree, struct vlist_node *node_new,
        struct wireless_device *wd_new = container_of(node_new, struct wireless_device, node);
 
        if (wd_old && wd_new) {
+               D(WIRELESS, "Update wireless device '%s'\n", wd_old->name);
                wdev_change_config(wd_old, wd_new);
        } else if (wd_old) {
                D(WIRELESS, "Delete wireless device '%s'\n", wd_old->name);
@@ -686,18 +746,29 @@ wireless_device_create(struct wireless_driver *drv, const char *name, struct blo
 {
        struct wireless_device *wdev;
        char *name_buf;
-       struct blob_attr *disabled;
+       struct blob_attr *tb[__WDEV_ATTR_MAX];
+       struct blob_attr *cur;
 
-       blobmsg_parse(&wdev_policy, 1, &disabled, blob_data(data), blob_len(data));
+       blobmsg_parse(wdev_policy, __WDEV_ATTR_MAX, tb, blob_data(data), blob_len(data));
 
        wdev = calloc_a(sizeof(*wdev), &name_buf, strlen(name) + 1);
-       if (disabled && blobmsg_get_bool(disabled))
-               wdev->disabled = true;
+
+       cur = tb[WDEV_ATTR_DISABLED];
+       wdev->disabled = cur && blobmsg_get_bool(cur);
+
        wdev->drv = drv;
        wdev->state = IFS_DOWN;
        wdev->config_state = IFC_NORMAL;
        wdev->name = strcpy(name_buf, name);
        wdev->config = data;
+       wdev->handler_pending = false;
+
+       cur = tb[WDEV_ATTR_SERIALIZE];
+       wdev->serialize = cur && blobmsg_get_bool(cur);
+
+       cur = tb[WDEV_ATTR_RECONF];
+       wdev->reconf = cur && blobmsg_get_bool(cur);
+
        wdev->retry_setup_failed = false;
        wdev->autostart = true;
        INIT_LIST_HEAD(&wdev->script_proc);
index bade738d9a8c59bc5991eceafcea638a34fd63c2..f734770fdb92421b5ed89fd45e33d59b39276be0 100644 (file)
@@ -15,6 +15,7 @@
 #define __NETIFD_WIRELESS_H
 
 #include <libubox/utils.h>
+#include <libubox/list.h>
 #include "interface.h"
 
 extern struct vlist_tree wireless_devices;
@@ -35,6 +36,11 @@ struct wireless_driver {
 struct wireless_device {
        struct vlist_node node;
 
+       struct list_head handler;
+       bool handler_action;
+       bool handler_pending;
+       bool serialize;
+
        struct wireless_driver *drv;
        struct vlist_tree interfaces;
        char *name;
@@ -59,6 +65,7 @@ struct wireless_device {
 
        enum interface_state state;
        enum interface_config_state config_state;
+       bool reconf;
        bool cancel;
        int retry;