From f5e2764d23b0f7273b5a25490e67cdbaaeded8af Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 20 Jun 2020 16:27:12 +0200 Subject: [PATCH 01/40] netifd: several backports required by ipq807x IPQ807x uses the mac80211.sh/hostapd.sh from owrt HEAD, which require these patches. Signed-off-by: John Crispin --- ...add-support-for-tracking-wifi-vlan-s.patch | 703 ++++++++++++++++++ ...add-support-for-tracking-wifi-statio.patch | 427 +++++++++++ ...s-method-for-reloading-configuration.patch | 123 +++ ...conf-opt-in-and-allow-serializing-co.patch | 249 +++++++ .../0005-netifd-fix-wdev-data-lifetime.patch | 42 ++ 5 files changed, 1544 insertions(+) create mode 100644 package/network/config/netifd/patches/0001-netifd-wireless-add-support-for-tracking-wifi-vlan-s.patch create mode 100644 package/network/config/netifd/patches/0002-netifd-wireless-add-support-for-tracking-wifi-statio.patch create mode 100644 package/network/config/netifd/patches/0003-wireless-add-ubus-method-for-reloading-configuration.patch create mode 100644 package/network/config/netifd/patches/0004-wireless-make-reconf-opt-in-and-allow-serializing-co.patch create mode 100644 package/network/config/netifd/patches/0005-netifd-fix-wdev-data-lifetime.patch diff --git a/package/network/config/netifd/patches/0001-netifd-wireless-add-support-for-tracking-wifi-vlan-s.patch b/package/network/config/netifd/patches/0001-netifd-wireless-add-support-for-tracking-wifi-vlan-s.patch new file mode 100644 index 0000000000..48185fc16c --- /dev/null +++ b/package/network/config/netifd/patches/0001-netifd-wireless-add-support-for-tracking-wifi-vlan-s.patch @@ -0,0 +1,703 @@ +From 4ce33cee34e413f69082a80a833f3ed1baf8a761 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 25 May 2020 11:49:18 +0200 +Subject: [PATCH 1/2] netifd: wireless: add support for tracking wifi-vlan + sections + +This new section allows us to create apvlan settings for hostapd. + +Signed-off-by: John Crispin +--- + config.c | 42 ++++++- + scripts/netifd-wireless.sh | 42 ++++++- + wireless.c | 247 +++++++++++++++++++++++++++++++++++-- + wireless.h | 23 +++- + 4 files changed, 337 insertions(+), 17 deletions(-) + +diff --git a/config.c b/config.c +index 843c53f..1bb3737 100644 +--- a/config.c ++++ b/config.c +@@ -338,7 +338,7 @@ config_parse_wireless_device(struct uci_section *s) + wireless_device_create(drv, s->e.name, b.head); + } + +-static void ++static struct wireless_interface* + config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s) + { + char *name; +@@ -348,7 +348,20 @@ config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section + + blob_buf_init(&b, 0); + uci_to_blob(&b, s, wdev->drv->interface.config); +- wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name); ++ return wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name); ++} ++ ++static void ++config_parse_wireless_vlan(struct wireless_device *wdev, char *vif, struct uci_section *s) ++{ ++ char *name; ++ ++ name = alloca(strlen(s->type) + 16); ++ sprintf(name, "@%s[%d]", s->type, config_section_idx(s)); ++ ++ blob_buf_init(&b, 0); ++ uci_to_blob(&b, s, wdev->drv->vlan.config); ++ wireless_vlan_create(wdev, vif, b.head, s->anonymous ? name : s->e.name); + } + + static void +@@ -378,10 +391,14 @@ config_init_wireless(void) + vlist_for_each_element(&wireless_devices, wdev, node) { + wdev->vif_idx = 0; + vlist_update(&wdev->interfaces); ++ wdev->vlan_idx = 0; ++ vlist_update(&wdev->vlans); + } + + uci_foreach_element(&uci_wireless->sections, e) { + struct uci_section *s = uci_to_section(e); ++ struct wireless_interface *vif; ++ struct uci_element *f; + + if (strcmp(s->type, "wifi-iface") != 0) + continue; +@@ -396,11 +413,28 @@ config_init_wireless(void) + continue; + } + +- config_parse_wireless_interface(wdev, s); ++ vif = config_parse_wireless_interface(wdev, s); ++ ++ if (!vif || s->anonymous) ++ continue; ++ uci_foreach_element(&uci_wireless->sections, f) { ++ struct uci_section *s = uci_to_section(f); ++ const char *vif_name; ++ ++ if (strcmp(s->type, "wifi-vlan") != 0) ++ continue; ++ ++ vif_name = uci_lookup_option_string(uci_ctx, s, "iface"); ++ if (vif_name && strcmp(e->name, vif_name)) ++ continue; ++ config_parse_wireless_vlan(wdev, vif->name, s); ++ } + } + +- vlist_for_each_element(&wireless_devices, wdev, node) ++ vlist_for_each_element(&wireless_devices, wdev, node) { + vlist_flush(&wdev->interfaces); ++ vlist_flush(&wdev->vlans); ++ } + } + + int +diff --git a/scripts/netifd-wireless.sh b/scripts/netifd-wireless.sh +index 6bc48c6..41e380f 100644 +--- a/scripts/netifd-wireless.sh ++++ b/scripts/netifd-wireless.sh +@@ -108,12 +108,13 @@ _wdev_wrapper() { + + _wdev_notify_init() { + local command="$1" +- local interface="$2" ++ local name="$2" ++ local value="$3" + + json_init + json_add_int "command" "$command" + json_add_string "device" "$__netifd_device" +- [ -n "$interface" ] && json_add_string "interface" "$interface" ++ [ -n "$name" -a -n "$value" ] && json_add_string "$name" "$value" + json_add_object "data" + } + +@@ -139,7 +140,17 @@ _wireless_add_vif() { + local name="$1"; shift + local ifname="$1"; shift + +- _wdev_notify_init $CMD_SET_DATA "$name" ++ _wdev_notify_init $CMD_SET_DATA "interface" "$name" ++ json_add_string "ifname" "$ifname" ++ _wdev_add_variables "$@" ++ _wdev_notify ++} ++ ++_wireless_add_vlan() { ++ local name="$1"; shift ++ local ifname="$1"; shift ++ ++ _wdev_notify_init $CMD_SET_DATA "vlan" "$name" + json_add_string "ifname" "$ifname" + _wdev_add_variables "$@" + _wdev_notify +@@ -182,6 +193,7 @@ _wireless_set_retry() { + + _wdev_wrapper \ + wireless_add_vif \ ++ wireless_add_vlan \ + wireless_set_up \ + wireless_set_data \ + wireless_add_process \ +@@ -306,6 +318,21 @@ for_each_interface() { + json_select .. + } + ++for_each_vlan() { ++ local _w_vlans _w_vlan ++ ++ json_get_keys _w_vlans vlans ++ json_select vlans ++ for _w_vlan in $_w_vlans; do ++ json_select "$_w_vlan" ++ json_select config ++ "$@" "$_w_vlan" ++ json_select .. ++ json_select .. ++ done ++ json_select .. ++} ++ + _wdev_common_device_config() { + config_add_string channel hwmode htmode noscan + } +@@ -314,6 +341,10 @@ _wdev_common_iface_config() { + config_add_string mode ssid encryption 'key:wpakey' + } + ++_wdev_common_vlan_config() { ++ config_add_string name vid iface ++} ++ + init_wireless_driver() { + name="$1"; shift + cmd="$1"; shift +@@ -336,6 +367,11 @@ init_wireless_driver() { + eval "drv_$1_init_iface_config" + json_close_array + ++ json_add_array vlan ++ _wdev_common_vlan_config ++ eval "drv_$1_init_vlan_config" ++ json_close_array ++ + json_dump + } + ;; +diff --git a/wireless.c b/wireless.c +index c8e196f..b0b35a1 100644 +--- a/wireless.c ++++ b/wireless.c +@@ -64,6 +64,24 @@ static const struct uci_blob_param_list vif_param = { + .params = vif_policy, + }; + ++enum { ++ VLAN_ATTR_DISABLED, ++ VLAN_ATTR_NETWORK, ++ VLAN_ATTR_ISOLATE, ++ __VLAN_ATTR_MAX, ++}; ++ ++static const struct blobmsg_policy vlan_policy[__VLAN_ATTR_MAX] = { ++ [VLAN_ATTR_DISABLED] = { .name = "disabled", .type = BLOBMSG_TYPE_BOOL }, ++ [VLAN_ATTR_NETWORK] = { .name = "network", .type = BLOBMSG_TYPE_ARRAY }, ++ [VLAN_ATTR_ISOLATE] = { .name = "isolate", .type = BLOBMSG_TYPE_BOOL }, ++}; ++ ++static const struct uci_blob_param_list vlan_param = { ++ .n_params = ARRAY_SIZE(vlan_policy), ++ .params = vlan_policy, ++}; ++ + static void + wireless_handler_stop(struct wireless_device *wdev) + { +@@ -125,7 +143,8 @@ static void + prepare_config(struct wireless_device *wdev, struct blob_buf *buf, bool up) + { + struct wireless_interface *vif; +- void *l, *i; ++ struct wireless_vlan *vlan; ++ void *l, *i, *j, *k; + + blob_buf_init(&b, 0); + put_container(&b, wdev->config, "config"); +@@ -139,9 +158,23 @@ prepare_config(struct wireless_device *wdev, struct blob_buf *buf, bool up) + put_container(&b, vif->config, "config"); + if (vif->data) + blobmsg_add_blob(&b, vif->data); ++ ++ j = blobmsg_open_table(&b, "vlans"); ++ vlist_for_each_element(&wdev->vlans, vlan, node) { ++ if (strcmp(vlan->vif, vif->name)) ++ continue; ++ k = blobmsg_open_table(&b, vlan->name); ++ vif_config_add_bridge(&b, vlan->network, up); ++ put_container(&b, vlan->config, "config"); ++ if (vlan->data) ++ blobmsg_add_blob(&b, vlan->data); ++ blobmsg_close_table(&b, k); ++ } ++ blobmsg_close_table(&b, j); + blobmsg_close_table(&b, i); + } + blobmsg_close_table(&b, l); ++ + } + + static bool +@@ -208,6 +241,7 @@ static void + wireless_device_free_state(struct wireless_device *wdev) + { + struct wireless_interface *vif; ++ struct wireless_vlan *vlan; + + wireless_handler_stop(wdev); + uloop_timeout_cancel(&wdev->script_check); +@@ -220,6 +254,11 @@ wireless_device_free_state(struct wireless_device *wdev) + vif->data = NULL; + vif->ifname = NULL; + } ++ vlist_for_each_element(&wdev->vlans, vlan, node) { ++ free(vlan->data); ++ vlan->data = NULL; ++ vlan->ifname = NULL; ++ } + } + + static void wireless_interface_handle_link(struct wireless_interface *vif, bool up) +@@ -252,6 +291,36 @@ static void wireless_interface_handle_link(struct wireless_interface *vif, bool + } + } + ++static void wireless_vlan_handle_link(struct wireless_vlan *vlan, bool up) ++{ ++ struct interface *iface; ++ struct blob_attr *cur; ++ const char *network; ++ int rem; ++ ++ if (!vlan->network || !vlan->ifname) ++ return; ++ ++ if (up) { ++ struct device *dev = device_get(vlan->ifname, 2); ++ if (dev) { ++ dev->wireless_isolate = vlan->isolate; ++ dev->wireless = true; ++ dev->wireless_ap = true; ++ } ++ } ++ ++ blobmsg_for_each_attr(cur, vlan->network, rem) { ++ network = blobmsg_data(cur); ++ ++ iface = vlist_find(&interfaces, network, iface, node); ++ if (!iface) ++ continue; ++ ++ interface_handle_link(iface, vlan->ifname, up, true); ++ } ++} ++ + static void + wireless_device_setup_cancel(struct wireless_device *wdev) + { +@@ -356,6 +425,7 @@ wireless_device_free(struct wireless_device *wdev) + { + wireless_handler_stop(wdev); + vlist_flush_all(&wdev->interfaces); ++ vlist_flush_all(&wdev->vlans); + avl_delete(&wireless_devices.avl, &wdev->node.avl); + free(wdev->config); + free(wdev->prev_config); +@@ -384,9 +454,13 @@ static void + wireless_device_mark_down(struct wireless_device *wdev) + { + struct wireless_interface *vif; ++ struct wireless_vlan *vlan; + + D(WIRELESS, "Wireless device '%s' is now down\n", wdev->name); + ++ vlist_for_each_element(&wdev->vlans, vlan, node) ++ wireless_vlan_handle_link(vlan, false); ++ + vlist_for_each_element(&wdev->interfaces, vif, node) + wireless_interface_handle_link(vif, false); + +@@ -447,6 +521,7 @@ static void + wireless_device_mark_up(struct wireless_device *wdev) + { + struct wireless_interface *vif; ++ struct wireless_vlan *vlan; + + if (wdev->cancel) { + wdev->cancel = false; +@@ -458,6 +533,8 @@ wireless_device_mark_up(struct wireless_device *wdev) + wdev->state = IFS_UP; + vlist_for_each_element(&wdev->interfaces, vif, node) + wireless_interface_handle_link(vif, true); ++ vlist_for_each_element(&wdev->vlans, vlan, node) ++ wireless_vlan_handle_link(vlan, true); + } + + static void +@@ -576,18 +653,20 @@ wireless_add_handler(const char *script, const char *name, json_object *obj) + { + struct wireless_driver *drv; + char *name_str, *script_str; +- json_object *dev_config_obj, *iface_config_obj; +- struct uci_blob_param_list *dev_config, *iface_config; ++ json_object *dev_config_obj, *iface_config_obj, *vlan_config_obj; ++ struct uci_blob_param_list *dev_config, *iface_config, *vlan_config; + + dev_config_obj = json_get_field(obj, "device", json_type_array); + iface_config_obj = json_get_field(obj, "iface", json_type_array); ++ vlan_config_obj = json_get_field(obj, "vlan", json_type_array); + +- if (!dev_config_obj || !iface_config_obj) ++ if (!dev_config_obj || !iface_config_obj || !vlan_config_obj) + return; + + drv = calloc_a(sizeof(*drv), + &dev_config, sizeof(*dev_config) + sizeof(void *), + &iface_config, sizeof(*iface_config) + sizeof(void *), ++ &vlan_config, sizeof(*vlan_config) + sizeof(void *), + &name_str, strlen(name) + 1, + &script_str, strlen(script) + 1); + +@@ -602,8 +681,13 @@ wireless_add_handler(const char *script, const char *name, json_object *obj) + iface_config->next[0] = &vif_param; + drv->interface.config = iface_config; + ++ vlan_config->n_next = 1; ++ vlan_config->next[0] = &vlan_param; ++ drv->vlan.config = vlan_config; ++ + drv->device.buf = netifd_handler_parse_config(drv->device.config, dev_config_obj); + drv->interface.buf = netifd_handler_parse_config(drv->interface.config, iface_config_obj); ++ drv->vlan.buf = netifd_handler_parse_config(drv->vlan.config, vlan_config_obj); + + drv->node.key = drv->name; + avl_insert(&wireless_drivers, &drv->node); +@@ -690,6 +774,67 @@ vif_update(struct vlist_tree *tree, struct vlist_node *node_new, + wdev_set_config_state(wdev, IFC_RELOAD); + } + ++static void ++wireless_vlan_init_config(struct wireless_vlan *vlan) ++{ ++ struct blob_attr *tb[__VLAN_ATTR_MAX]; ++ struct blob_attr *cur; ++ ++ vlan->network = NULL; ++ blobmsg_parse(vlan_policy, __VLAN_ATTR_MAX, tb, blob_data(vlan->config), blob_len(vlan->config)); ++ ++ if ((cur = tb[VLAN_ATTR_NETWORK])) ++ vlan->network = cur; ++ ++ cur = tb[VLAN_ATTR_ISOLATE]; ++ if (cur) ++ vlan->isolate = blobmsg_get_bool(cur); ++} ++ ++static void ++vlan_update(struct vlist_tree *tree, struct vlist_node *node_new, ++ struct vlist_node *node_old) ++{ ++ struct wireless_vlan *vlan_old = container_of(node_old, struct wireless_vlan, node); ++ struct wireless_vlan *vlan_new = container_of(node_new, struct wireless_vlan, node); ++ struct wireless_device *wdev; ++ ++ if (vlan_old) ++ wdev = vlan_old->wdev; ++ else ++ wdev = vlan_new->wdev; ++ ++ if (vlan_old && vlan_new) { ++ free((void *) vlan_old->section); ++ vlan_old->section = strdup(vlan_new->section); ++ if (blob_attr_equal(vlan_old->config, vlan_new->config)) { ++ free(vlan_new); ++ return; ++ } ++ ++ D(WIRELESS, "Update wireless vlan %s on device %s\n", vlan_new->name, wdev->name); ++ wireless_vlan_handle_link(vlan_old, false); ++ free(vlan_old->config); ++ vlan_old->config = blob_memdup(vlan_new->config); ++ vlan_old->isolate = vlan_new->isolate; ++ wireless_vlan_init_config(vlan_old); ++ free(vlan_new); ++ } else if (vlan_new) { ++ D(WIRELESS, "Create new wireless vlan %s on device %s\n", vlan_new->name, wdev->name); ++ vlan_new->section = strdup(vlan_new->section); ++ vlan_new->config = blob_memdup(vlan_new->config); ++ wireless_vlan_init_config(vlan_new); ++ } else if (vlan_old) { ++ D(WIRELESS, "Delete wireless interface %s on device %s\n", vlan_old->name, wdev->name); ++ wireless_vlan_handle_link(vlan_old, false); ++ free((void *) vlan_old->section); ++ free(vlan_old->config); ++ free(vlan_old); ++ } ++ ++ wdev_set_config_state(wdev, IFC_RELOAD); ++} ++ + static void + wireless_proc_poll_fd(struct uloop_fd *fd, unsigned int events) + { +@@ -774,6 +919,8 @@ wireless_device_create(struct wireless_driver *drv, const char *name, struct blo + INIT_LIST_HEAD(&wdev->script_proc); + vlist_init(&wdev->interfaces, avl_strcmp, vif_update); + wdev->interfaces.keep_old = true; ++ vlist_init(&wdev->vlans, avl_strcmp, vlan_update); ++ wdev->vlans.keep_old = true; + + wdev->timeout.cb = wireless_device_setup_timeout; + wdev->script_task.cb = wireless_device_script_task_cb; +@@ -788,7 +935,51 @@ wireless_device_create(struct wireless_driver *drv, const char *name, struct blo + vlist_add(&wireless_devices, &wdev->node, wdev->name); + } + +-void wireless_interface_create(struct wireless_device *wdev, struct blob_attr *data, const char *section) ++void ++wireless_vlan_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section) ++{ ++ struct wireless_vlan *vlan; ++ struct blob_attr *tb[__VLAN_ATTR_MAX]; ++ struct blob_attr *cur; ++ char *name_buf, *vif_buf; ++ char name[8]; ++ ++ blobmsg_parse(vlan_policy, __VLAN_ATTR_MAX, tb, blob_data(data), blob_len(data)); ++ ++ cur = tb[VLAN_ATTR_DISABLED]; ++ if (cur && blobmsg_get_bool(cur)) ++ return; ++ ++ sprintf(name, "%d", wdev->vlan_idx++); ++ ++ vlan = calloc_a(sizeof(*vlan), ++ &name_buf, strlen(name) + 1, ++ &vif_buf, strlen(vif) + 1); ++ vlan->name = strcpy(name_buf, name); ++ vlan->vif = strcpy(vif_buf, vif); ++ vlan->wdev = wdev; ++ vlan->config = data; ++ vlan->section = section; ++ vlan->isolate = false; ++ ++ vlist_add(&wdev->vlans, &vlan->node, vlan->name); ++} ++ ++static void ++wireless_vlan_status(struct wireless_vlan *vlan, struct blob_buf *b) ++{ ++ void *i; ++ ++ i = blobmsg_open_table(b, NULL); ++ if (vlan->section) ++ blobmsg_add_string(b, "section", vlan->section); ++ if (vlan->ifname) ++ blobmsg_add_string(b, "ifname", vlan->ifname); ++ put_container(b, vlan->config, "config"); ++ blobmsg_close_table(b, i); ++} ++ ++struct wireless_interface* wireless_interface_create(struct wireless_device *wdev, struct blob_attr *data, const char *section) + { + struct wireless_interface *vif; + struct blob_attr *tb[__VIF_ATTR_MAX]; +@@ -800,7 +991,7 @@ void wireless_interface_create(struct wireless_device *wdev, struct blob_attr *d + + cur = tb[VIF_ATTR_DISABLED]; + if (cur && blobmsg_get_bool(cur)) +- return; ++ return NULL; + + sprintf(name, "%d", wdev->vif_idx++); + +@@ -813,12 +1004,14 @@ void wireless_interface_create(struct wireless_device *wdev, struct blob_attr *d + vif->isolate = false; + + vlist_add(&wdev->interfaces, &vif->node, vif->name); ++ return vif; + } + + static void + wireless_interface_status(struct wireless_interface *iface, struct blob_buf *b) + { +- void *i; ++ struct wireless_vlan *vlan; ++ void *i, *j; + + i = blobmsg_open_table(b, NULL); + if (iface->section) +@@ -826,6 +1019,11 @@ wireless_interface_status(struct wireless_interface *iface, struct blob_buf *b) + if (iface->ifname) + blobmsg_add_string(b, "ifname", iface->ifname); + put_container(b, iface->config, "config"); ++ j = blobmsg_open_array(b, "vlans"); ++ vlist_for_each_element(&iface->wdev->vlans, vlan, node) ++ if (!strcmp(iface->name, vlan->vif)) ++ wireless_vlan_status(vlan, b); ++ blobmsg_close_array(b, j); + blobmsg_close_table(b, i); + } + +@@ -894,6 +1092,26 @@ wireless_interface_set_data(struct wireless_interface *vif) + vif->ifname = blobmsg_data(cur); + } + ++static void ++wireless_vlan_set_data(struct wireless_vlan *vlan) ++{ ++ enum { ++ VLAN_DATA_IFNAME, ++ __VLAN_DATA_MAX, ++ }; ++ static const struct blobmsg_policy data_policy[__VLAN_DATA_MAX] = { ++ [VLAN_DATA_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, ++ }; ++ struct blob_attr *tb[__VLAN_DATA_MAX]; ++ struct blob_attr *cur; ++ ++ blobmsg_parse(data_policy, __VLAN_DATA_MAX, tb, ++ blobmsg_data(vlan->data), blobmsg_data_len(vlan->data)); ++ ++ if ((cur = tb[VLAN_DATA_IFNAME])) ++ vlan->ifname = blobmsg_data(cur); ++} ++ + static int + wireless_device_add_process(struct wireless_device *wdev, struct blob_attr *data) + { +@@ -1011,15 +1229,18 @@ wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data, + enum { + NOTIFY_ATTR_COMMAND, + NOTIFY_ATTR_VIF, ++ NOTIFY_ATTR_VLAN, + NOTIFY_ATTR_DATA, + __NOTIFY_MAX, + }; + static const struct blobmsg_policy notify_policy[__NOTIFY_MAX] = { + [NOTIFY_ATTR_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_INT32 }, + [NOTIFY_ATTR_VIF] = { .name = "interface", .type = BLOBMSG_TYPE_STRING }, ++ [NOTIFY_ATTR_VLAN] = { .name = "vlan", .type = BLOBMSG_TYPE_STRING }, + [NOTIFY_ATTR_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, + }; + struct wireless_interface *vif = NULL; ++ struct wireless_vlan *vlan = NULL; + struct blob_attr *tb[__NOTIFY_MAX]; + struct blob_attr *cur, **pdata; + +@@ -1034,13 +1255,19 @@ wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data, + return UBUS_STATUS_NOT_FOUND; + } + ++ if ((cur = tb[NOTIFY_ATTR_VLAN]) != NULL) { ++ vlan = vlist_find(&wdev->vlans, blobmsg_data(cur), vlan, node); ++ if (!vlan) ++ return UBUS_STATUS_NOT_FOUND; ++ } ++ + cur = tb[NOTIFY_ATTR_DATA]; + if (!cur) + return UBUS_STATUS_INVALID_ARGUMENT; + + switch (blobmsg_get_u32(tb[NOTIFY_ATTR_COMMAND])) { + case NOTIFY_CMD_UP: +- if (vif) ++ if (vif || vlan) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (wdev->state != IFS_SETUP) +@@ -1051,6 +1278,8 @@ wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data, + case NOTIFY_CMD_SET_DATA: + if (vif) + pdata = &vif->data; ++ else if (vlan) ++ pdata = &vlan->data; + else + pdata = &wdev->data; + +@@ -1060,6 +1289,8 @@ wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data, + *pdata = blob_memdup(cur); + if (vif) + wireless_interface_set_data(vif); ++ else if (vlan) ++ wireless_vlan_set_data(vlan); + break; + case NOTIFY_CMD_PROCESS_ADD: + return wireless_device_add_process(wdev, cur); +diff --git a/wireless.h b/wireless.h +index f734770..8d0a1f0 100644 +--- a/wireless.h ++++ b/wireless.h +@@ -30,7 +30,7 @@ struct wireless_driver { + struct { + char *buf; + struct uci_blob_param_list *config; +- } device, interface; ++ } device, interface, vlan; + }; + + struct wireless_device { +@@ -43,6 +43,7 @@ struct wireless_device { + + struct wireless_driver *drv; + struct vlist_tree interfaces; ++ struct vlist_tree vlans; + char *name; + + struct netifd_process script_task; +@@ -70,6 +71,7 @@ struct wireless_device { + int retry; + + int vif_idx; ++ int vlan_idx; + }; + + struct wireless_interface { +@@ -88,6 +90,22 @@ struct wireless_interface { + bool ap_mode; + }; + ++struct wireless_vlan { ++ struct vlist_node node; ++ const char *section; ++ char *name; ++ ++ struct wireless_device *wdev; ++ char *vif; ++ ++ struct blob_attr *config; ++ struct blob_attr *data; ++ ++ const char *ifname; ++ struct blob_attr *network; ++ bool isolate; ++}; ++ + struct wireless_process { + struct list_head list; + +@@ -103,7 +121,8 @@ void wireless_device_set_down(struct wireless_device *wdev); + void wireless_device_reconf(struct wireless_device *wdev); + void wireless_device_status(struct wireless_device *wdev, struct blob_buf *b); + void wireless_device_get_validate(struct wireless_device *wdev, struct blob_buf *b); +-void wireless_interface_create(struct wireless_device *wdev, struct blob_attr *data, const char *section); ++struct wireless_interface* wireless_interface_create(struct wireless_device *wdev, struct blob_attr *data, const char *section); ++void wireless_vlan_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section); + int wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data, + struct ubus_request_data *req); + +-- +2.20.1 + diff --git a/package/network/config/netifd/patches/0002-netifd-wireless-add-support-for-tracking-wifi-statio.patch b/package/network/config/netifd/patches/0002-netifd-wireless-add-support-for-tracking-wifi-statio.patch new file mode 100644 index 0000000000..d849fb09e0 --- /dev/null +++ b/package/network/config/netifd/patches/0002-netifd-wireless-add-support-for-tracking-wifi-statio.patch @@ -0,0 +1,427 @@ +From a56b457656218e5b6142b6238286ea54801ac4b2 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 25 May 2020 11:49:19 +0200 +Subject: [PATCH 2/2] netifd: wireless: add support for tracking wifi-station + sections + +This new section allows us to assign mac specific key/vid settings to a +station. + +Signed-off-by: John Crispin +--- + config.c | 29 ++++++++ + scripts/netifd-wireless.sh | 24 +++++++ + wireless.c | 134 ++++++++++++++++++++++++++++++++++++- + wireless.h | 17 ++++- + 4 files changed, 200 insertions(+), 4 deletions(-) + +diff --git a/config.c b/config.c +index 1bb3737..b1b4bf3 100644 +--- a/config.c ++++ b/config.c +@@ -364,6 +364,19 @@ config_parse_wireless_vlan(struct wireless_device *wdev, char *vif, struct uci_s + wireless_vlan_create(wdev, vif, b.head, s->anonymous ? name : s->e.name); + } + ++static void ++config_parse_wireless_station(struct wireless_device *wdev, char *vif, struct uci_section *s) ++{ ++ char *name; ++ ++ name = alloca(strlen(s->type) + 16); ++ sprintf(name, "@%s[%d]", s->type, config_section_idx(s)); ++ ++ blob_buf_init(&b, 0); ++ uci_to_blob(&b, s, wdev->drv->station.config); ++ wireless_station_create(wdev, vif, b.head, s->anonymous ? name : s->e.name); ++} ++ + static void + config_init_wireless(void) + { +@@ -393,6 +406,8 @@ config_init_wireless(void) + vlist_update(&wdev->interfaces); + wdev->vlan_idx = 0; + vlist_update(&wdev->vlans); ++ wdev->sta_idx = 0; ++ vlist_update(&wdev->stations); + } + + uci_foreach_element(&uci_wireless->sections, e) { +@@ -429,11 +444,25 @@ config_init_wireless(void) + continue; + config_parse_wireless_vlan(wdev, vif->name, s); + } ++ ++ uci_foreach_element(&uci_wireless->sections, f) { ++ struct uci_section *s = uci_to_section(f); ++ const char *vif_name; ++ ++ if (strcmp(s->type, "wifi-station") != 0) ++ continue; ++ ++ vif_name = uci_lookup_option_string(uci_ctx, s, "iface"); ++ if (vif_name && strcmp(e->name, vif_name)) ++ continue; ++ config_parse_wireless_station(wdev, vif->name, s); ++ } + } + + vlist_for_each_element(&wireless_devices, wdev, node) { + vlist_flush(&wdev->interfaces); + vlist_flush(&wdev->vlans); ++ vlist_flush(&wdev->stations); + } + } + +diff --git a/scripts/netifd-wireless.sh b/scripts/netifd-wireless.sh +index 41e380f..d51380d 100644 +--- a/scripts/netifd-wireless.sh ++++ b/scripts/netifd-wireless.sh +@@ -333,6 +333,21 @@ for_each_vlan() { + json_select .. + } + ++for_each_station() { ++ local _w_stas _w_sta ++ ++ json_get_keys _w_stas stas ++ json_select stas ++ for _w_sta in $_w_stas; do ++ json_select "$_w_sta" ++ json_select config ++ "$@" "$_w_sta" ++ json_select .. ++ json_select .. ++ done ++ json_select .. ++} ++ + _wdev_common_device_config() { + config_add_string channel hwmode htmode noscan + } +@@ -345,6 +360,10 @@ _wdev_common_vlan_config() { + config_add_string name vid iface + } + ++_wdev_common_station_config() { ++ config_add_string mac key vid iface ++} ++ + init_wireless_driver() { + name="$1"; shift + cmd="$1"; shift +@@ -372,6 +391,11 @@ init_wireless_driver() { + eval "drv_$1_init_vlan_config" + json_close_array + ++ json_add_array station ++ _wdev_common_station_config ++ eval "drv_$1_init_station_config" ++ json_close_array ++ + json_dump + } + ;; +diff --git a/wireless.c b/wireless.c +index b0b35a1..efb7992 100644 +--- a/wireless.c ++++ b/wireless.c +@@ -82,6 +82,20 @@ static const struct uci_blob_param_list vlan_param = { + .params = vlan_policy, + }; + ++enum { ++ STA_ATTR_DISABLED, ++ __STA_ATTR_MAX, ++}; ++ ++static const struct blobmsg_policy sta_policy[__STA_ATTR_MAX] = { ++ [STA_ATTR_DISABLED] = { .name = "disabled", .type = BLOBMSG_TYPE_BOOL }, ++}; ++ ++static const struct uci_blob_param_list station_param = { ++ .n_params = ARRAY_SIZE(sta_policy), ++ .params = sta_policy, ++}; ++ + static void + wireless_handler_stop(struct wireless_device *wdev) + { +@@ -144,6 +158,7 @@ prepare_config(struct wireless_device *wdev, struct blob_buf *buf, bool up) + { + struct wireless_interface *vif; + struct wireless_vlan *vlan; ++ struct wireless_station *sta; + void *l, *i, *j, *k; + + blob_buf_init(&b, 0); +@@ -171,6 +186,18 @@ prepare_config(struct wireless_device *wdev, struct blob_buf *buf, bool up) + blobmsg_close_table(&b, k); + } + blobmsg_close_table(&b, j); ++ ++ j = blobmsg_open_table(&b, "stas"); ++ vlist_for_each_element(&wdev->stations, sta, node) { ++ if (strcmp(sta->vif, vif->name)) ++ continue; ++ k = blobmsg_open_table(&b, sta->name); ++ put_container(&b, sta->config, "config"); ++ if (sta->data) ++ blobmsg_add_blob(&b, sta->data); ++ blobmsg_close_table(&b, k); ++ } ++ blobmsg_close_table(&b, j); + blobmsg_close_table(&b, i); + } + blobmsg_close_table(&b, l); +@@ -242,6 +269,7 @@ wireless_device_free_state(struct wireless_device *wdev) + { + struct wireless_interface *vif; + struct wireless_vlan *vlan; ++ struct wireless_station *sta; + + wireless_handler_stop(wdev); + uloop_timeout_cancel(&wdev->script_check); +@@ -259,6 +287,10 @@ wireless_device_free_state(struct wireless_device *wdev) + vlan->data = NULL; + vlan->ifname = NULL; + } ++ vlist_for_each_element(&wdev->stations, sta, node) { ++ free(sta->data); ++ sta->data = NULL; ++ } + } + + static void wireless_interface_handle_link(struct wireless_interface *vif, bool up) +@@ -426,6 +458,7 @@ wireless_device_free(struct wireless_device *wdev) + wireless_handler_stop(wdev); + vlist_flush_all(&wdev->interfaces); + vlist_flush_all(&wdev->vlans); ++ vlist_flush_all(&wdev->stations); + avl_delete(&wireless_devices.avl, &wdev->node.avl); + free(wdev->config); + free(wdev->prev_config); +@@ -653,20 +686,22 @@ wireless_add_handler(const char *script, const char *name, json_object *obj) + { + struct wireless_driver *drv; + char *name_str, *script_str; +- json_object *dev_config_obj, *iface_config_obj, *vlan_config_obj; +- struct uci_blob_param_list *dev_config, *iface_config, *vlan_config; ++ json_object *dev_config_obj, *iface_config_obj, *vlan_config_obj, *station_config_obj; ++ struct uci_blob_param_list *dev_config, *iface_config, *vlan_config, *station_config; + + dev_config_obj = json_get_field(obj, "device", json_type_array); + iface_config_obj = json_get_field(obj, "iface", json_type_array); + vlan_config_obj = json_get_field(obj, "vlan", json_type_array); ++ station_config_obj = json_get_field(obj, "station", json_type_array); + +- if (!dev_config_obj || !iface_config_obj || !vlan_config_obj) ++ if (!dev_config_obj || !iface_config_obj || !vlan_config_obj || !station_config_obj) + return; + + drv = calloc_a(sizeof(*drv), + &dev_config, sizeof(*dev_config) + sizeof(void *), + &iface_config, sizeof(*iface_config) + sizeof(void *), + &vlan_config, sizeof(*vlan_config) + sizeof(void *), ++ &station_config, sizeof(*station_config) + sizeof(void *), + &name_str, strlen(name) + 1, + &script_str, strlen(script) + 1); + +@@ -685,9 +720,14 @@ wireless_add_handler(const char *script, const char *name, json_object *obj) + vlan_config->next[0] = &vlan_param; + drv->vlan.config = vlan_config; + ++ station_config->n_next = 1; ++ station_config->next[0] = &station_param; ++ drv->station.config = station_config; ++ + drv->device.buf = netifd_handler_parse_config(drv->device.config, dev_config_obj); + drv->interface.buf = netifd_handler_parse_config(drv->interface.config, iface_config_obj); + drv->vlan.buf = netifd_handler_parse_config(drv->vlan.config, vlan_config_obj); ++ drv->station.buf = netifd_handler_parse_config(drv->station.config, station_config_obj); + + drv->node.key = drv->name; + avl_insert(&wireless_drivers, &drv->node); +@@ -835,6 +875,45 @@ vlan_update(struct vlist_tree *tree, struct vlist_node *node_new, + wdev_set_config_state(wdev, IFC_RELOAD); + } + ++static void ++station_update(struct vlist_tree *tree, struct vlist_node *node_new, ++ struct vlist_node *node_old) ++{ ++ struct wireless_station *sta_old = container_of(node_old, struct wireless_station, node); ++ struct wireless_station *sta_new = container_of(node_new, struct wireless_station, node); ++ struct wireless_device *wdev; ++ ++ if (sta_old) ++ wdev = sta_old->wdev; ++ else ++ wdev = sta_new->wdev; ++ ++ if (sta_old && sta_new) { ++ free((void *) sta_old->section); ++ sta_old->section = strdup(sta_new->section); ++ if (blob_attr_equal(sta_old->config, sta_new->config)) { ++ free(sta_new); ++ return; ++ } ++ ++ D(WIRELESS, "Update wireless station %s on device %s\n", sta_new->name, wdev->name); ++ free(sta_old->config); ++ sta_old->config = blob_memdup(sta_new->config); ++ free(sta_new); ++ } else if (sta_new) { ++ D(WIRELESS, "Create new wireless station %s on device %s\n", sta_new->name, wdev->name); ++ sta_new->section = strdup(sta_new->section); ++ sta_new->config = blob_memdup(sta_new->config); ++ } else if (sta_old) { ++ D(WIRELESS, "Delete wireless station %s on device %s\n", sta_old->name, wdev->name); ++ free((void *) sta_old->section); ++ free(sta_old->config); ++ free(sta_old); ++ } ++ ++ wdev_set_config_state(wdev, IFC_RELOAD); ++} ++ + static void + wireless_proc_poll_fd(struct uloop_fd *fd, unsigned int events) + { +@@ -921,6 +1000,8 @@ wireless_device_create(struct wireless_driver *drv, const char *name, struct blo + wdev->interfaces.keep_old = true; + vlist_init(&wdev->vlans, avl_strcmp, vlan_update); + wdev->vlans.keep_old = true; ++ vlist_init(&wdev->stations, avl_strcmp, station_update); ++ wdev->stations.keep_old = true; + + wdev->timeout.cb = wireless_device_setup_timeout; + wdev->script_task.cb = wireless_device_script_task_cb; +@@ -935,6 +1016,47 @@ wireless_device_create(struct wireless_driver *drv, const char *name, struct blo + vlist_add(&wireless_devices, &wdev->node, wdev->name); + } + ++void ++wireless_station_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section) ++{ ++ struct wireless_station *sta; ++ struct blob_attr *tb[__STA_ATTR_MAX]; ++ struct blob_attr *cur; ++ char *name_buf, *vif_buf; ++ char name[8]; ++ ++ blobmsg_parse(sta_policy, __STA_ATTR_MAX, tb, blob_data(data), blob_len(data)); ++ ++ cur = tb[STA_ATTR_DISABLED]; ++ if (cur && blobmsg_get_bool(cur)) ++ return; ++ ++ sprintf(name, "%d", wdev->vlan_idx++); ++ ++ sta = calloc_a(sizeof(*sta), ++ &name_buf, strlen(name) + 1, ++ &vif_buf, strlen(vif) + 1); ++ sta->name = strcpy(name_buf, name); ++ sta->vif = strcpy(vif_buf, vif); ++ sta->wdev = wdev; ++ sta->config = data; ++ sta->section = section; ++ ++ vlist_add(&wdev->stations, &sta->node, sta->name); ++} ++ ++static void ++wireless_station_status(struct wireless_station *sta, struct blob_buf *b) ++{ ++ void *i; ++ ++ i = blobmsg_open_table(b, NULL); ++ if (sta->section) ++ blobmsg_add_string(b, "section", sta->section); ++ put_container(b, sta->config, "config"); ++ blobmsg_close_table(b, i); ++} ++ + void + wireless_vlan_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section) + { +@@ -1011,6 +1133,7 @@ static void + wireless_interface_status(struct wireless_interface *iface, struct blob_buf *b) + { + struct wireless_vlan *vlan; ++ struct wireless_station *sta; + void *i, *j; + + i = blobmsg_open_table(b, NULL); +@@ -1024,6 +1147,11 @@ wireless_interface_status(struct wireless_interface *iface, struct blob_buf *b) + if (!strcmp(iface->name, vlan->vif)) + wireless_vlan_status(vlan, b); + blobmsg_close_array(b, j); ++ j = blobmsg_open_array(b, "stations"); ++ vlist_for_each_element(&iface->wdev->stations, sta, node) ++ if (!strcmp(iface->name, sta->vif)) ++ wireless_station_status(sta, b); ++ blobmsg_close_array(b, j); + blobmsg_close_table(b, i); + } + +diff --git a/wireless.h b/wireless.h +index 8d0a1f0..5fedd20 100644 +--- a/wireless.h ++++ b/wireless.h +@@ -30,7 +30,7 @@ struct wireless_driver { + struct { + char *buf; + struct uci_blob_param_list *config; +- } device, interface, vlan; ++ } device, interface, vlan, station; + }; + + struct wireless_device { +@@ -44,6 +44,7 @@ struct wireless_device { + struct wireless_driver *drv; + struct vlist_tree interfaces; + struct vlist_tree vlans; ++ struct vlist_tree stations; + char *name; + + struct netifd_process script_task; +@@ -72,6 +73,7 @@ struct wireless_device { + + int vif_idx; + int vlan_idx; ++ int sta_idx; + }; + + struct wireless_interface { +@@ -106,6 +108,18 @@ struct wireless_vlan { + bool isolate; + }; + ++struct wireless_station { ++ struct vlist_node node; ++ const char *section; ++ char *name; ++ ++ struct wireless_device *wdev; ++ char *vif; ++ ++ struct blob_attr *config; ++ struct blob_attr *data; ++}; ++ + struct wireless_process { + struct list_head list; + +@@ -123,6 +137,7 @@ void wireless_device_status(struct wireless_device *wdev, struct blob_buf *b); + void wireless_device_get_validate(struct wireless_device *wdev, struct blob_buf *b); + struct wireless_interface* wireless_interface_create(struct wireless_device *wdev, struct blob_attr *data, const char *section); + void wireless_vlan_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section); ++void wireless_station_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section); + int wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data, + struct ubus_request_data *req); + +-- +2.20.1 + diff --git a/package/network/config/netifd/patches/0003-wireless-add-ubus-method-for-reloading-configuration.patch b/package/network/config/netifd/patches/0003-wireless-add-ubus-method-for-reloading-configuration.patch new file mode 100644 index 0000000000..26dc1afaf6 --- /dev/null +++ b/package/network/config/netifd/patches/0003-wireless-add-ubus-method-for-reloading-configuration.patch @@ -0,0 +1,123 @@ +From 7a723d0c797d28823f3d0eae9c72aca3ae69d976 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 25 Oct 2019 14:02:03 +0200 +Subject: [PATCH 3/4] wireless: add ubus method for reloading configuration + +Signed-off-by: Daniel Golle +--- + ubus.c | 23 +++++++++++++++++++++++ + wireless.c | 18 +++++++++++++----- + wireless.h | 1 + + 3 files changed, 37 insertions(+), 5 deletions(-) + +diff --git a/ubus.c b/ubus.c +index 150d818..5a2a339 100644 +--- a/ubus.c ++++ b/ubus.c +@@ -1081,6 +1081,28 @@ get_wdev(struct blob_attr *msg, int *ret) + return wdev; + } + ++static int ++netifd_handle_wdev_reconf(struct ubus_context *ctx, struct ubus_object *obj, ++ struct ubus_request_data *req, const char *method, ++ struct blob_attr *msg) ++{ ++ struct wireless_device *wdev; ++ int ret; ++ ++ wdev = get_wdev(msg, &ret); ++ if (ret == UBUS_STATUS_NOT_FOUND) ++ return ret; ++ ++ if (wdev) { ++ wireless_device_reconf(wdev); ++ } else { ++ vlist_for_each_element(&wireless_devices, wdev, node) ++ wireless_device_reconf(wdev); ++ } ++ ++ return 0; ++} ++ + static int + netifd_handle_wdev_up(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, +@@ -1189,6 +1211,7 @@ netifd_handle_wdev_notify(struct ubus_context *ctx, struct ubus_object *obj, + static struct ubus_method wireless_object_methods[] = { + { .name = "up", .handler = netifd_handle_wdev_up }, + { .name = "down", .handler = netifd_handle_wdev_down }, ++ { .name = "reconf", .handler = netifd_handle_wdev_reconf }, + { .name = "status", .handler = netifd_handle_wdev_status }, + { .name = "notify", .handler = netifd_handle_wdev_notify }, + { .name = "get_validate", .handler = netifd_handle_wdev_get_validate }, +diff --git a/wireless.c b/wireless.c +index 387f4ba..9986e9a 100644 +--- a/wireless.c ++++ b/wireless.c +@@ -282,7 +282,7 @@ wireless_device_run_handler(struct wireless_device *wdev, bool up) + } + + static void +-__wireless_device_set_up(struct wireless_device *wdev) ++__wireless_device_set_up(struct wireless_device *wdev, int force) + { + if (wdev->disabled) + return; +@@ -293,7 +293,7 @@ __wireless_device_set_up(struct wireless_device *wdev) + if (!wdev->autostart) + return; + +- if (wdev->state != IFS_DOWN || config_init) ++ if (!force && (wdev->state != IFS_DOWN || config_init)) + return; + + free(wdev->prev_config); +@@ -320,7 +320,7 @@ wdev_handle_config_change(struct wireless_device *wdev) + switch(state) { + case IFC_NORMAL: + case IFC_RELOAD: +- __wireless_device_set_up(wdev); ++ __wireless_device_set_up(wdev, 0); + + wdev->config_state = IFC_NORMAL; + break; +@@ -363,7 +363,15 @@ wireless_device_set_up(struct wireless_device *wdev) + { + wdev->retry = WIRELESS_SETUP_RETRY; + wdev->autostart = true; +- __wireless_device_set_up(wdev); ++ __wireless_device_set_up(wdev, 0); ++} ++ ++void ++wireless_device_reconf(struct wireless_device *wdev) ++{ ++ wdev->retry = WIRELESS_SETUP_RETRY; ++ wdev->autostart = true; ++ __wireless_device_set_up(wdev, 1); + } + + static void +@@ -1001,5 +1009,5 @@ wireless_start_pending(void) + struct wireless_device *wdev; + + vlist_for_each_element(&wireless_devices, wdev, node) +- __wireless_device_set_up(wdev); ++ __wireless_device_set_up(wdev, 0); + } +diff --git a/wireless.h b/wireless.h +index 3498bd8..bade738 100644 +--- a/wireless.h ++++ b/wireless.h +@@ -93,6 +93,7 @@ struct wireless_process { + void wireless_device_create(struct wireless_driver *drv, const char *name, struct blob_attr *data); + void wireless_device_set_up(struct wireless_device *wdev); + void wireless_device_set_down(struct wireless_device *wdev); ++void wireless_device_reconf(struct wireless_device *wdev); + void wireless_device_status(struct wireless_device *wdev, struct blob_buf *b); + void wireless_device_get_validate(struct wireless_device *wdev, struct blob_buf *b); + void wireless_interface_create(struct wireless_device *wdev, struct blob_attr *data, const char *section); +-- +2.25.1 + diff --git a/package/network/config/netifd/patches/0004-wireless-make-reconf-opt-in-and-allow-serializing-co.patch b/package/network/config/netifd/patches/0004-wireless-make-reconf-opt-in-and-allow-serializing-co.patch new file mode 100644 index 0000000000..04bf4397db --- /dev/null +++ b/package/network/config/netifd/patches/0004-wireless-make-reconf-opt-in-and-allow-serializing-co.patch @@ -0,0 +1,249 @@ +From e15147c272201eb17320c10ec95919e641bd03c5 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 25 Oct 2019 14:06:30 +0200 +Subject: [PATCH 4/4] 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 + diff --git a/package/network/config/netifd/patches/0005-netifd-fix-wdev-data-lifetime.patch b/package/network/config/netifd/patches/0005-netifd-fix-wdev-data-lifetime.patch new file mode 100644 index 0000000000..5ccefc5117 --- /dev/null +++ b/package/network/config/netifd/patches/0005-netifd-fix-wdev-data-lifetime.patch @@ -0,0 +1,42 @@ +From 1aee9aea386a510eb9e0f11fdb57984539294f0d Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 23 Jun 2020 10:09:13 +0200 +Subject: [PATCH V2] netifd: fix wdev->data lifetime + +The reconf patch breaks wifi down under certain conditions. The root cause +is that during reload the wdev state gets flushed. This has the effect, that +the phy is lost from the state resulting in teardown breaking. +Fix this by changing the lifetime of wdev->data. + +Signed-off-by: John Crispin +--- +Changes in V2 +* free() call was in the wrong place + + wireless.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/wireless.c b/wireless.c +index efb7992..e295f28 100644 +--- a/wireless.c ++++ b/wireless.c +@@ -275,8 +275,6 @@ wireless_device_free_state(struct wireless_device *wdev) + uloop_timeout_cancel(&wdev->script_check); + uloop_timeout_cancel(&wdev->timeout); + wireless_complete_kill_request(wdev); +- free(wdev->data); +- wdev->data = NULL; + vlist_for_each_element(&wdev->interfaces, vif, node) { + free(vif->data); + vif->data = NULL; +@@ -460,6 +458,7 @@ wireless_device_free(struct wireless_device *wdev) + vlist_flush_all(&wdev->vlans); + vlist_flush_all(&wdev->stations); + avl_delete(&wireless_devices.avl, &wdev->node.avl); ++ free(wdev->data); + free(wdev->config); + free(wdev->prev_config); + free(wdev); +-- +2.25.1 + -- 2.25.1