From befac1e06547e8c7c9ba1d2fa2081fd9f9dc7ca8 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 16 Sep 2023 16:55:57 +0200 Subject: [PATCH] netifd: backport vlan rewrite Signed-off-by: John Crispin --- patches/backports/0061-netifd-vlan-fix.patch | 607 +++++++++++++++++++ 1 file changed, 607 insertions(+) create mode 100644 patches/backports/0061-netifd-vlan-fix.patch diff --git a/patches/backports/0061-netifd-vlan-fix.patch b/patches/backports/0061-netifd-vlan-fix.patch new file mode 100644 index 000000000..16b9e68bf --- /dev/null +++ b/patches/backports/0061-netifd-vlan-fix.patch @@ -0,0 +1,607 @@ +From f7feafa6a88a70f96ac4bf556ff5b0665eb9735a Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 15 Sep 2023 15:01:44 +0200 +Subject: [PATCH] netifd: add wireless vlan/sta fix + +Signed-off-by: Felix Fietkau +--- + .../patches/400-wireless_vlan_fix.patch | 587 ++++++++++++++++++ + 1 file changed, 587 insertions(+) + create mode 100644 package/network/config/netifd/patches/400-wireless_vlan_fix.patch + +diff --git a/package/network/config/netifd/patches/400-wireless_vlan_fix.patch b/package/network/config/netifd/patches/400-wireless_vlan_fix.patch +new file mode 100644 +index 000000000000..449121dd3d9e +--- /dev/null ++++ b/package/network/config/netifd/patches/400-wireless_vlan_fix.patch +@@ -0,0 +1,587 @@ ++--- a/config.c +++++ b/config.c ++@@ -557,8 +557,8 @@ config_parse_wireless_device(struct uci_ ++ wireless_device_create(drv, s->e.name, b.head); ++ } ++ ++-static struct wireless_interface* ++-config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s) +++static void +++config_parse_wireless_vlan(struct wireless_interface *vif, struct uci_section *s) ++ { ++ char *name; ++ ++@@ -566,12 +566,12 @@ config_parse_wireless_interface(struct w ++ sprintf(name, "@%s[%d]", s->type, config_section_idx(s)); ++ ++ blob_buf_init(&b, 0); ++- uci_to_blob(&b, s, wdev->drv->interface.config); ++- return wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name); +++ uci_to_blob(&b, s, vif->wdev->drv->vlan.config); +++ wireless_vlan_create(vif, b.head, s->anonymous ? name : s->e.name); ++ } ++ ++ static void ++-config_parse_wireless_vlan(struct wireless_device *wdev, char *vif, struct uci_section *s) +++config_parse_wireless_station(struct wireless_interface *vif, struct uci_section *s) ++ { ++ char *name; ++ ++@@ -579,21 +579,62 @@ config_parse_wireless_vlan(struct wirele ++ 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); +++ uci_to_blob(&b, s, vif->wdev->drv->station.config); +++ wireless_station_create(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) +++config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s) ++ { +++ struct wireless_interface *vif; +++ struct uci_element *f; ++ 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); +++ uci_to_blob(&b, s, wdev->drv->interface.config); +++ vif = wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name); +++ if (!vif) +++ return; +++ +++ vif->vlan_idx = vif->sta_idx = 0; +++ vlist_update(&vif->vlans); +++ vlist_update(&vif->stations); +++ +++ if (s->anonymous) +++ goto out; +++ +++ uci_foreach_element(&uci_wireless->sections, f) { +++ struct uci_section *cur = uci_to_section(f); +++ const char *vif_name; +++ +++ if (strcmp(cur->type, "wifi-vlan") != 0) +++ continue; +++ +++ vif_name = uci_lookup_option_string(uci_ctx, cur, "iface"); +++ if (vif_name && strcmp(s->e.name, vif_name)) +++ continue; +++ config_parse_wireless_vlan(vif, cur); +++ } +++ +++ uci_foreach_element(&uci_wireless->sections, f) { +++ struct uci_section *cur = uci_to_section(f); +++ const char *vif_name; +++ +++ if (strcmp(cur->type, "wifi-station") != 0) +++ continue; +++ +++ vif_name = uci_lookup_option_string(uci_ctx, cur, "iface"); +++ if (vif_name && strcmp(s->e.name, vif_name)) +++ continue; +++ config_parse_wireless_station(vif, cur); +++ } +++ +++out: +++ vlist_flush(&vif->vlans); +++ vlist_flush(&vif->stations); ++ } ++ ++ static void ++@@ -623,16 +664,10 @@ 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); ++- wdev->sta_idx = 0; ++- vlist_update(&wdev->stations); ++ } ++ ++ 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; ++@@ -647,42 +682,11 @@ config_init_wireless(void) ++ continue; ++ } ++ ++- 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); ++- } ++- ++- 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); ++- } +++ config_parse_wireless_interface(wdev, 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); ++- vlist_flush(&wdev->stations); ++- } ++ } ++ ++ ++--- a/scripts/netifd-wireless.sh +++++ b/scripts/netifd-wireless.sh ++@@ -108,14 +108,16 @@ _wdev_wrapper() { ++ } ++ ++ _wdev_notify_init() { ++- local command="$1" ++- local name="$2" ++- local value="$3" +++ local command="$1"; shift; ++ ++ json_init ++ json_add_int "command" "$command" ++ json_add_string "device" "$__netifd_device" ++- [ -n "$name" -a -n "$value" ] && json_add_string "$name" "$value" +++ while [ -n "$1" ]; do +++ local name="$1"; shift +++ local value="$1"; shift +++ json_add_string "$name" "$value" +++ done ++ json_add_object "data" ++ } ++ ++@@ -151,7 +153,7 @@ _wireless_add_vlan() { ++ local name="$1"; shift ++ local ifname="$1"; shift ++ ++- _wdev_notify_init $CMD_SET_DATA "vlan" "$name" +++ _wdev_notify_init $CMD_SET_DATA interface "$__cur_interface" "vlan" "$name" ++ json_add_string "ifname" "$ifname" ++ _wdev_add_variables "$@" ++ _wdev_notify ++@@ -333,6 +335,7 @@ for_each_interface() { ++ continue ++ } ++ fi +++ __cur_interface="$_w_iface" ++ "$@" "$_w_iface" ++ json_select .. ++ done ++--- a/wireless.c +++++ b/wireless.c ++@@ -205,9 +205,7 @@ prepare_config(struct wireless_device *w ++ 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; +++ vlist_for_each_element(&vif->vlans, vlan, node) { ++ k = blobmsg_open_table(&b, vlan->name); ++ vif_config_add_bridge(&b, vlan->network, up); ++ put_container(&b, vlan->config, "config"); ++@@ -218,9 +216,7 @@ prepare_config(struct wireless_device *w ++ 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; +++ vlist_for_each_element(&vif->stations, sta, node) { ++ k = blobmsg_open_table(&b, sta->name); ++ put_container(&b, sta->config, "config"); ++ if (sta->data) ++@@ -311,15 +307,15 @@ wireless_device_free_state(struct wirele ++ free(vif->data); ++ vif->data = NULL; ++ vif->ifname = NULL; ++- } ++- vlist_for_each_element(&wdev->vlans, vlan, node) { ++- free(vlan->data); ++- vlan->data = NULL; ++- vlan->ifname = NULL; ++- } ++- vlist_for_each_element(&wdev->stations, sta, node) { ++- free(sta->data); ++- sta->data = NULL; +++ vlist_for_each_element(&vif->vlans, vlan, node) { +++ free(vlan->data); +++ vlan->data = NULL; +++ vlan->ifname = NULL; +++ } +++ vlist_for_each_element(&vif->stations, sta, node) { +++ free(sta->data); +++ sta->data = NULL; +++ } ++ } ++ } ++ ++@@ -510,8 +506,6 @@ wireless_device_free(struct wireless_dev ++ { ++ 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); ++@@ -547,11 +541,12 @@ wireless_device_mark_down(struct wireles ++ ++ netifd_log_message(L_NOTICE, "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) +++ vlist_for_each_element(&wdev->interfaces, vif, node) { ++ wireless_interface_handle_link(vif, NULL, false); +++ vlist_for_each_element(&vif->vlans, vlan, node) +++ wireless_vlan_handle_link(vlan, false); +++ } ++ ++ wireless_process_kill_all(wdev, SIGTERM, true); ++ ++@@ -623,10 +618,11 @@ wireless_device_mark_up(struct wireless_ ++ netifd_log_message(L_NOTICE, "Wireless device '%s' is now up\n", wdev->name); ++ wdev->retry = WIRELESS_SETUP_RETRY; ++ wdev->state = IFS_UP; ++- vlist_for_each_element(&wdev->interfaces, vif, node) +++ vlist_for_each_element(&wdev->interfaces, vif, node) { ++ wireless_interface_handle_link(vif, NULL, true); ++- vlist_for_each_element(&wdev->vlans, vlan, node) ++- wireless_vlan_handle_link(vlan, true); +++ vlist_for_each_element(&vif->vlans, vlan, node) +++ wireless_vlan_handle_link(vlan, true); +++ } ++ } ++ ++ static void ++@@ -848,6 +844,16 @@ wireless_interface_init_config(struct wi ++ vif->multicast_to_unicast = cur ? blobmsg_get_bool(cur) : -1; ++ } ++ +++static void +++vif_free(struct wireless_interface *vif) +++{ +++ vlist_flush_all(&vif->vlans); +++ vlist_flush_all(&vif->stations); +++ free((void *) vif->section); +++ free(vif->config); +++ free(vif); +++} +++ ++ /* vlist update call for wireless interface list */ ++ static void ++ vif_update(struct vlist_tree *tree, struct vlist_node *node_new, ++@@ -884,9 +890,7 @@ vif_update(struct vlist_tree *tree, stru ++ } else if (vif_old) { ++ D(WIRELESS, "Delete wireless interface %s on device %s\n", vif_old->name, wdev->name); ++ wireless_interface_handle_link(vif_old, NULL, false); ++- free((void *) vif_old->section); ++- free(vif_old->config); ++- free(vif_old); +++ vif_free(vif_old); ++ } ++ ++ wdev->config_update = true; ++@@ -921,14 +925,10 @@ 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; +++ struct wireless_vlan *vlan_old = container_of_safe(node_old, struct wireless_vlan, node); +++ struct wireless_vlan *vlan_new = container_of_safe(node_new, struct wireless_vlan, node); +++ struct wireless_interface *vif = container_of(tree, struct wireless_interface, vlans); +++ struct wireless_device *wdev = vif->wdev; ++ ++ if (vlan_old && vlan_new) { ++ free((void *) vlan_old->section); ++@@ -951,7 +951,7 @@ vlan_update(struct vlist_tree *tree, str ++ 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); +++ D(WIRELESS, "Delete wireless vlan %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); ++@@ -966,14 +966,10 @@ 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; +++ struct wireless_station *sta_old = container_of_safe(node_old, struct wireless_station, node); +++ struct wireless_station *sta_new = container_of_safe(node_new, struct wireless_station, node); +++ struct wireless_interface *vif = container_of(tree, struct wireless_interface, stations); +++ struct wireless_device *wdev = vif->wdev; ++ ++ if (sta_old && sta_new) { ++ free((void *) sta_old->section); ++@@ -1088,10 +1084,6 @@ wireless_device_create(struct wireless_d ++ 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; ++- 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; ++@@ -1108,12 +1100,12 @@ wireless_device_create(struct wireless_d ++ ++ /* creates a wireless station object. Called by config */ ++ void ++-wireless_station_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section) +++wireless_station_create(struct wireless_interface *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_buf; ++ char name[8]; ++ ++ blobmsg_parse(sta_policy, __STA_ATTR_MAX, tb, blob_data(data), blob_len(data)); ++@@ -1122,18 +1114,15 @@ wireless_station_create(struct wireless_ ++ if (cur && blobmsg_get_bool(cur)) ++ return; ++ ++- sprintf(name, "%d", wdev->sta_idx++); +++ sprintf(name, "%d", vif->sta_idx++); ++ ++ sta = calloc_a(sizeof(*sta), ++- &name_buf, strlen(name) + 1, ++- &vif_buf, strlen(vif) + 1); +++ &name_buf, strlen(name) + 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); +++ vlist_add(&vif->stations, &sta->node, sta->name); ++ } ++ ++ /* ubus callback network.wireless.status, runs for every interface, encode the station */ ++@@ -1151,12 +1140,12 @@ wireless_station_status(struct wireless_ ++ ++ /* create a vlan object. Called by config */ ++ void ++-wireless_vlan_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section) +++wireless_vlan_create(struct wireless_interface *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_buf; ++ char name[8]; ++ ++ blobmsg_parse(vlan_policy, __VLAN_ATTR_MAX, tb, blob_data(data), blob_len(data)); ++@@ -1165,19 +1154,14 @@ wireless_vlan_create(struct wireless_dev ++ if (cur && blobmsg_get_bool(cur)) ++ return; ++ ++- sprintf(name, "%d", wdev->vlan_idx++); +++ sprintf(name, "%d", vif->vlan_idx++); ++ ++- vlan = calloc_a(sizeof(*vlan), ++- &name_buf, strlen(name) + 1, ++- &vif_buf, strlen(vif) + 1); +++ vlan = calloc_a(sizeof(*vlan), &name_buf, strlen(name) + 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); +++ vlist_add(&vif->vlans, &vlan->node, vlan->name); ++ } ++ ++ /* ubus callback network.wireless.status, runs for every interface, encode the vlan informations */ ++@@ -1220,6 +1204,12 @@ struct wireless_interface* wireless_inte ++ vif->section = section; ++ vif->isolate = false; ++ +++ vlist_init(&vif->vlans, avl_strcmp, vlan_update); +++ vif->vlans.keep_old = true; +++ +++ vlist_init(&vif->stations, avl_strcmp, station_update); +++ vif->stations.keep_old = true; +++ ++ vlist_add(&wdev->interfaces, &vif->node, vif->name); ++ ++ return vlist_find(&wdev->interfaces, name, vif, node); ++@@ -1240,14 +1230,12 @@ wireless_interface_status(struct wireles ++ 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); +++ vlist_for_each_element(&iface->vlans, vlan, node) +++ 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); +++ vlist_for_each_element(&iface->stations, sta, node) +++ wireless_station_status(sta, b); ++ blobmsg_close_array(b, j); ++ blobmsg_close_table(b, i); ++ } ++@@ -1496,7 +1484,9 @@ wireless_device_notify(struct wireless_d ++ } ++ ++ if ((cur = tb[NOTIFY_ATTR_VLAN]) != NULL) { ++- vlan = vlist_find(&wdev->vlans, blobmsg_data(cur), vlan, node); +++ if (!vif) +++ return UBUS_STATUS_NOT_FOUND; +++ vlan = vlist_find(&vif->vlans, blobmsg_data(cur), vlan, node); ++ if (!vlan) ++ return UBUS_STATUS_NOT_FOUND; ++ } ++@@ -1516,19 +1506,19 @@ wireless_device_notify(struct wireless_d ++ wireless_device_mark_up(wdev); ++ break; ++ case NOTIFY_CMD_SET_DATA: ++- if (vif) ++- pdata = &vif->data; ++- else if (vlan) +++ if (vlan) ++ pdata = &vlan->data; +++ else if (vif) +++ pdata = &vif->data; ++ else ++ pdata = &wdev->data; ++ ++ free(*pdata); ++ *pdata = blob_memdup(cur); ++- if (vif) ++- wireless_interface_set_data(vif); ++- else if (vlan) +++ if (vlan) ++ wireless_vlan_set_data(vlan); +++ else if (vif) +++ wireless_interface_set_data(vif); ++ break; ++ case NOTIFY_CMD_PROCESS_ADD: ++ return wireless_device_add_process(wdev, cur); ++--- a/wireless.h +++++ b/wireless.h ++@@ -44,8 +44,6 @@ 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; ++@@ -73,8 +71,6 @@ struct wireless_device { ++ int retry; ++ ++ int vif_idx; ++- int vlan_idx; ++- int sta_idx; ++ }; ++ ++ struct wireless_interface { ++@@ -82,6 +78,8 @@ struct wireless_interface { ++ const char *section; ++ char *name; ++ +++ struct vlist_tree vlans; +++ struct vlist_tree stations; ++ struct wireless_device *wdev; ++ ++ struct blob_attr *config; ++@@ -94,6 +92,8 @@ struct wireless_interface { ++ bool isolate; ++ bool ap_mode; ++ int multicast_to_unicast; +++ int vlan_idx; +++ int sta_idx; ++ }; ++ ++ struct wireless_vlan { ++@@ -101,9 +101,6 @@ struct wireless_vlan { ++ const char *section; ++ char *name; ++ ++- struct wireless_device *wdev; ++- char *vif; ++- ++ struct blob_attr *config; ++ struct blob_attr *data; ++ ++@@ -119,9 +116,6 @@ struct wireless_station { ++ const char *section; ++ char *name; ++ ++- struct wireless_device *wdev; ++- char *vif; ++- ++ struct blob_attr *config; ++ struct blob_attr *data; ++ }; ++@@ -143,8 +137,8 @@ void wireless_device_reconf(struct wirel ++ 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); +++void wireless_vlan_create(struct wireless_interface *vif, struct blob_attr *data, const char *section); +++void wireless_station_create(struct wireless_interface *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.39.2 +