From 890929baa8164b4813212fb5e9b8541b7ec61541 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Jun 2024 20:29:20 +0200 Subject: [PATCH] wireless: add support for defining wifi interfaces via procd service data This makes it possible to dynamically define wifi interfaces from other services without having to update the config. Signed-off-by: Felix Fietkau --- config.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++--- ubus.c | 42 +++++++++++++++++++++++++++++++ ubus.h | 3 +++ wireless.c | 12 +++++++-- 4 files changed, 125 insertions(+), 6 deletions(-) diff --git a/config.c b/config.c index a7f9c0b..d187152 100644 --- a/config.c +++ b/config.c @@ -27,6 +27,7 @@ #include "proto.h" #include "wireless.h" #include "config.h" +#include "ubus.h" bool config_init = false; @@ -599,10 +600,6 @@ config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section if (!vif) return; - vif->vlan_idx = vif->sta_idx = 0; - vlist_update(&vif->vlans); - vlist_update(&vif->stations); - if (s->anonymous) goto out; @@ -637,6 +634,73 @@ out: vlist_flush(&vif->stations); } +static void +config_init_procd_wireless_interface(const char *wdev_name, const char *vif_name, + struct blob_attr *config, + struct blob_attr *vlans, + struct blob_attr *stations) +{ + struct wireless_interface *vif; + struct wireless_device *wdev; + struct blob_attr *cur; + char name[16]; + int idx = 0; + int rem; + + wdev = vlist_find(&wireless_devices, wdev_name, wdev, node); + if (!wdev) { + D(WIRELESS, "device %s not found!", wdev_name); + return; + } + + vif = wireless_interface_create(wdev, config, vif_name); + if (!vif) + return; + + blobmsg_for_each_attr(cur, vlans, rem) { + snprintf(name, sizeof(name), "%d", ++idx); + wireless_vlan_create(vif, cur, name); + } + + blobmsg_for_each_attr(cur, stations, rem) { + snprintf(name, sizeof(name), "%d", ++idx); + wireless_station_create(vif, cur, name); + } + + vlist_flush(&vif->vlans); + vlist_flush(&vif->stations); +} + +static void +config_procd_wireless_interface_cb(struct blob_attr *data) +{ + enum { + UDATA_ATTR_DEVICE, + UDATA_ATTR_CONFIG, + UDATA_ATTR_STATIONS, + UDATA_ATTR_VLANS, + __UDATA_ATTR_MAX, + }; + static const struct blobmsg_policy policy[__UDATA_ATTR_MAX] = { + [UDATA_ATTR_DEVICE] = { "device", BLOBMSG_TYPE_STRING }, + [UDATA_ATTR_CONFIG] = { "config", BLOBMSG_TYPE_TABLE }, + [UDATA_ATTR_STATIONS] = { "stations", BLOBMSG_TYPE_ARRAY }, + [UDATA_ATTR_VLANS] = { "vlans", BLOBMSG_TYPE_ARRAY }, + }; + struct blob_attr *tb[__UDATA_ATTR_MAX]; + const char *dev; + + blobmsg_parse_attr(policy, __UDATA_ATTR_MAX, tb, data); + if (!tb[UDATA_ATTR_DEVICE] || !tb[UDATA_ATTR_CONFIG]) + return; + + dev = blobmsg_get_string(tb[UDATA_ATTR_DEVICE]); + config_init_procd_wireless_interface(dev, blobmsg_name(data), + tb[UDATA_ATTR_CONFIG], + tb[UDATA_ATTR_VLANS], + tb[UDATA_ATTR_STATIONS]); +} + static void config_init_wireless(void) { @@ -685,6 +749,8 @@ config_init_wireless(void) config_parse_wireless_interface(wdev, s); } + netifd_ubus_get_procd_data("wifi-iface", config_procd_wireless_interface_cb); + vlist_for_each_element(&wireless_devices, wdev, node) vlist_flush(&wdev->interfaces); } diff --git a/ubus.c b/ubus.c index 3d24dc7..f8662c2 100644 --- a/ubus.c +++ b/ubus.c @@ -1445,3 +1445,45 @@ netifd_ubus_remove_interface(struct interface *iface) ubus_remove_object(ubus_ctx, &iface->ubus); free((void *) iface->ubus.name); } + +static void +netifd_ubus_data_cb(struct ubus_request *req, int type, struct blob_attr *msg) +{ + struct blob_attr *srv, *in, *t, *data; + procd_data_cb cb = req->priv; + int rem, rem2, rem3, rem4; + + blobmsg_for_each_attr(srv, msg, rem) { + if (!blobmsg_check_attr(srv, true) || + blobmsg_type(srv) != BLOBMSG_TYPE_TABLE) + continue; + blobmsg_for_each_attr(in, srv, rem2) { + if (!blobmsg_check_attr(in , true) || + blobmsg_type(in) != BLOBMSG_TYPE_TABLE) + continue; + blobmsg_for_each_attr(t, in, rem3) { + if (!blobmsg_check_attr(t, true) || + blobmsg_type(t) != BLOBMSG_TYPE_TABLE) + continue; + blobmsg_for_each_attr(data, t, rem4) { + if (!blobmsg_check_attr(t, true) || + blobmsg_type(t) != BLOBMSG_TYPE_TABLE) + continue; + cb(data); + } + } + } + } +} + +void netifd_ubus_get_procd_data(const char *type, procd_data_cb cb) +{ + uint32_t id; + + if (ubus_lookup_id(ubus_ctx, "service", &id)) + return; + + blob_buf_init(&b, 0); + blobmsg_add_string(&b, "type", type); + ubus_invoke(ubus_ctx, id, "get_data", b.head, netifd_ubus_data_cb, cb, 30000); +} diff --git a/ubus.h b/ubus.h index dde7124..b9b4b69 100644 --- a/ubus.h +++ b/ubus.h @@ -14,6 +14,8 @@ #ifndef __NETIFD_UBUS_H #define __NETIFD_UBUS_H +typedef void (*procd_data_cb)(struct blob_attr *data); + extern struct ubus_context *ubus_ctx; int netifd_ubus_init(const char *path); @@ -26,5 +28,6 @@ void netifd_ubus_remove_interface(struct interface *iface); void netifd_ubus_interface_event(struct interface *iface, bool up); void netifd_ubus_interface_notify(struct interface *iface, bool up); void netifd_ubus_device_notify(const char *event, struct blob_attr *data, int timeout); +void netifd_ubus_get_procd_data(const char *type, procd_data_cb cb); #endif diff --git a/wireless.c b/wireless.c index ea6e6b4..3a03988 100644 --- a/wireless.c +++ b/wireless.c @@ -138,7 +138,7 @@ static void put_container(struct blob_buf *buf, struct blob_attr *attr, const char *name) { void *c = blobmsg_open_table(buf, name); - blob_put_raw(buf, blob_data(attr), blob_len(attr)); + blob_put_raw(buf, blobmsg_data(attr), blobmsg_len(attr)); blobmsg_close_table(buf, c); } @@ -1232,7 +1232,15 @@ struct wireless_interface* wireless_interface_create(struct wireless_device *wde vlist_add(&wdev->interfaces, &vif->node, vif->name); - return vlist_find(&wdev->interfaces, name, vif, node); + vif = vlist_find(&wdev->interfaces, name, vif, node); + if (!vif) + return NULL; + + vif->vlan_idx = vif->sta_idx = 0; + vlist_update(&vif->vlans); + vlist_update(&vif->stations); + + return vif; } /* ubus callback network.wireless.status, runs for every interface */ -- 2.30.2