From e15147c272201eb17320c10ec95919e641bd03c5 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 25 Oct 2019 14:06:30 +0200 Subject: [PATCH] wireless: make reconf opt-in and allow serializing configuration 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 --- wireless.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++------ wireless.h | 7 +++++ 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/wireless.c b/wireless.c index 9986e9a..c8e196f 100644 --- a/wireless.c +++ b/wireless.c @@ -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); diff --git a/wireless.h b/wireless.h index bade738..f734770 100644 --- a/wireless.h +++ b/wireless.h @@ -15,6 +15,7 @@ #define __NETIFD_WIRELESS_H #include +#include #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; -- 2.25.1