From 1a4f868fd7c61592856e97bb43e61231b0f5e17b Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 19 Apr 2024 20:01:39 +0200 Subject: [PATCH] ubus: filter interfaces --- .../node-whisperer/files/node-whisperer.init | 7 +++ .../node-whisperer/files/node-whisperer.uci | 2 + src/daemon.c | 2 + src/daemon.h | 6 ++ src/interface.c | 34 +++++++++++ src/ubus.c | 57 +++++++++++++++++++ 6 files changed, 108 insertions(+) diff --git a/openwrt/node-whisperer/files/node-whisperer.init b/openwrt/node-whisperer/files/node-whisperer.init index dd828e3..2d21f06 100644 --- a/openwrt/node-whisperer/files/node-whisperer.init +++ b/openwrt/node-whisperer/files/node-whisperer.init @@ -23,6 +23,13 @@ uci_nw() { config_list_foreach "$cfg" "information" uci_nw_add_json_string json_close_array ubus call node_whisperer set_sources "$(json_dump)" + + # Enabled interfaces + json_init + json_add_array interface + config_list_foreach "$cfg" "interface" uci_nw_add_json_string + json_close_array + ubus call node_whisperer set_interfaces "$(json_dump)" } load_config() { diff --git a/openwrt/node-whisperer/files/node-whisperer.uci b/openwrt/node-whisperer/files/node-whisperer.uci index 4b6bf33..33fce56 100644 --- a/openwrt/node-whisperer/files/node-whisperer.uci +++ b/openwrt/node-whisperer/files/node-whisperer.uci @@ -10,3 +10,5 @@ config settings 'settings' list information 'system_load' list information 'firmware_version' list information 'batman_adv' + list interface 'client0' + list interface 'client1' diff --git a/src/daemon.c b/src/daemon.c index 87c2047..8ea6c77 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -141,6 +141,8 @@ static void nw_daemon_collect_information(struct uloop_timeout *timeout) { static int start_daemon() { struct nw instance = {}; + + INIT_LIST_HEAD(&instance.enabled_interfaces); uloop_init(); diff --git a/src/daemon.h b/src/daemon.h index bacf0d1..150d9f9 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -2,9 +2,15 @@ #include "node-whisperer.h" +struct nw_enabled_interface { + struct list_head list; + char *name; +}; + struct nw { struct ubus_context *ubus_ctx; struct uloop_timeout update_timeout; + struct list_head enabled_interfaces; struct { uint8_t *buf; diff --git a/src/interface.c b/src/interface.c index acd7dc9..786f974 100644 --- a/src/interface.c +++ b/src/interface.c @@ -1,4 +1,7 @@ #include "node-whisperer.h" +#include "daemon.h" + +#define UBUS_HOSTAPD_PREFIX "hostapd." static LIST_HEAD(nw_interfaces); static struct blob_buf b; @@ -23,8 +26,34 @@ static void nw_interface_handle_remove(struct ubus_context *ctx, nw_interface_remove(ctx, iface); } +static int nw_interface_enabled(struct nw *instance, const char *name) +{ + struct nw_enabled_interface *iface; + const char *hostapd_name; + + /* Always enabled when list of enabled interfaces empty */ + if (list_empty(&instance->enabled_interfaces)) { + return 1; + } + + if (strlen(name) <= strlen(UBUS_HOSTAPD_PREFIX)) { + return 0; + } + + hostapd_name = (char *)name + strlen(UBUS_HOSTAPD_PREFIX); + + list_for_each_entry(iface, &instance->enabled_interfaces, list) { + if (!strcmp(hostapd_name, name)) { + return 1; + } + } + + return 0; +} + int nw_interface_update(struct ubus_context *ctx, char *vendor_elements) { + struct nw *instance = container_of(ctx, struct nw, ubus_ctx); struct nw_interface *iface; int ret; @@ -40,6 +69,11 @@ int nw_interface_update(struct ubus_context *ctx, char *vendor_elements) /* Delete element */ blob_buf_init(&b, 0); blobmsg_add_string(&b, "vendor_elements", ""); + + if (!nw_interface_enabled(instance, iface->ubus.name)) { + continue; + } + ret = ubus_invoke(ctx, iface->ubus.id, "set_vendor_elements", b.head, NULL, NULL, 1000); if (ret) { log_error("Failed to reset vendor elements for id=%d name=%s code=%d", iface->ubus.id, iface->ubus.name, ret); diff --git a/src/ubus.c b/src/ubus.c index 8e6d357..f69d49e 100644 --- a/src/ubus.c +++ b/src/ubus.c @@ -1,3 +1,5 @@ +#include + #include "node-whisperer.h" #include "daemon.h" @@ -5,6 +7,60 @@ extern struct nw_information_source information_sources[]; static struct blob_buf b; +static struct blobmsg_policy set_interfaces_policy[] = { + { .name = "interfaces", .type = BLOBMSG_TYPE_ARRAY, }, +}; + +static int nw_ubus_set_interfaces(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct nw *nw = container_of(ctx, struct nw, ubus_ctx); + struct nw_enabled_interface *iface; + const char *ifname; + struct blob_attr *cur; + struct blob_attr *tb[1]; + size_t rem; + + /* Parse message */ + blobmsg_parse(set_interfaces_policy, ARRAY_SIZE(set_interfaces_policy), tb, blob_data(msg), blob_len(msg)); + if (!tb[0]) + return UBUS_STATUS_INVALID_ARGUMENT; + + /* Clear list */ + while (!list_empty(&nw->enabled_interfaces)) { + iface = list_first_entry(&nw->enabled_interfaces, struct nw_enabled_interface, list); + list_del(&iface->list); + free(iface->name); + free(iface); + } + + /* Add new interfaces */ + blobmsg_for_each_attr(cur, tb[0], rem) { + if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) + return UBUS_STATUS_INVALID_ARGUMENT; + + ifname = blobmsg_get_string(cur); + if (!ifname) + return UBUS_STATUS_INVALID_ARGUMENT; + + iface = calloc(1, sizeof(*iface)); + if (!iface) + return UBUS_STATUS_UNKNOWN_ERROR; + + iface->name = strdup(ifname); + if (!iface->name) { + free(iface); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + list_add_tail(&iface->list, &nw->enabled_interfaces); + } + + return 0; +} + + static struct blobmsg_policy source_toggle_arg[] = { { .name = "information_sources", .type = BLOBMSG_TYPE_ARRAY, }, }; @@ -109,6 +165,7 @@ static int nw_ubus_statistics(struct ubus_context *ctx, struct ubus_object *obj, } static const struct ubus_method nw_methods[] = { + UBUS_METHOD("set_interfaces", nw_ubus_set_interfaces, set_interfaces_policy), UBUS_METHOD("set_sources", nw_ubus_enable_source, source_toggle_arg), UBUS_METHOD_NOARG("get_sources", nw_ubus_get_sources), UBUS_METHOD_NOARG("statistics", nw_ubus_statistics),