mirror of
https://dev.iopsys.eu/hal/wifimngr.git
synced 2025-12-20 01:11:11 +08:00
684 lines
19 KiB
C
684 lines
19 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* ubus.c - provides wifimngr UBUS commands.
|
|
*
|
|
* Copyright (C) 2024 Iopsys Software Solutions AB. All rights reserved.
|
|
* Copyright (C) 2025 Genexis AB.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <dirent.h>
|
|
#include <limits.h>
|
|
#include <net/if.h>
|
|
#include <libubox/blobmsg.h>
|
|
#include <libubox/blobmsg_json.h>
|
|
#include <libubox/uloop.h>
|
|
#include <libubox/ustream.h>
|
|
#include <libubox/utils.h>
|
|
#include <libubus.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
#include <easy/easy.h>
|
|
#include <wifi.h>
|
|
#include <wifidefs.h>
|
|
|
|
#include "wifimngr.h"
|
|
#include "debug.h"
|
|
|
|
#include "policy.c"
|
|
|
|
extern void *libsta_ratings;
|
|
|
|
int wifimngr_add_object(struct wifimngr *w, const char *objname,
|
|
int (*add_methods)(struct wifimngr *w, struct ubus_object *o),
|
|
struct ubus_object *object)
|
|
{
|
|
struct ubus_object_type *obj_type;
|
|
struct ubus_object *obj;
|
|
int ret;
|
|
|
|
obj = object;
|
|
memset(obj, 0, sizeof(*obj));
|
|
obj_type = calloc(1, sizeof(struct ubus_object_type));
|
|
if (!obj_type)
|
|
return -ENOMEM;
|
|
|
|
obj->name = strdup(objname);
|
|
if (add_methods)
|
|
add_methods(w, obj);
|
|
|
|
obj_type->name = obj->name;
|
|
obj_type->n_methods = obj->n_methods;
|
|
obj_type->methods = obj->methods;
|
|
obj->type = obj_type;
|
|
|
|
ret = ubus_add_object(w->ubus_ctx, obj);
|
|
if (ret) {
|
|
wifimngr_dbg("Failed to add '%s' object\n", obj->name);
|
|
free((void *)obj->methods);
|
|
free((void *)obj->name);
|
|
free(obj_type);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#define MAX_RADIO_METHODS 16
|
|
|
|
static int add_radio_methods(struct wifimngr *w, struct ubus_object *radio_obj,
|
|
const char *radioname)
|
|
{
|
|
struct wifimngr_device *wdev = wifimngr_lookup_wifi_device(w, radioname);
|
|
struct ubus_method *radio_methods;
|
|
enum wifi_band band;
|
|
int n_methods = 0;
|
|
char *phyname;
|
|
|
|
|
|
if (!wdev)
|
|
return -1;
|
|
|
|
radio_methods = calloc(MAX_RADIO_METHODS, sizeof(struct ubus_method));
|
|
if (!radio_methods)
|
|
return -ENOMEM;
|
|
|
|
phyname = wdev->phy;
|
|
band = wdev->band;
|
|
|
|
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD_NOARG("help", wl_radio_help));
|
|
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD_NOARG("status", wl_radio_status));
|
|
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD_NOARG("stats", wl_radio_stats));
|
|
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("get", wl_radio_get_param, radio_get_param_policy));
|
|
|
|
//UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
// UBUS_METHOD_NOARG("temperature", wl_temperature));
|
|
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("scan", wl_scan, wl_scan_policy));
|
|
|
|
if (libwifi_supports(phyname, "wifi_scan_ex")) {
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("scan_ex", wl_scan_ex, wl_scan_ex_policy));
|
|
}
|
|
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("scanresults", wl_scanresults, wl_scanres_policy));
|
|
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("autochannel", wl_autochannel, wl_acs_policy));
|
|
|
|
if (libwifi_supports(phyname, "wifi_start_cac")) {
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("start_cac", wl_start_cac, wl_cac_policy));
|
|
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("stop_cac", wl_stop_cac, wl_cac_policy));
|
|
}
|
|
|
|
if (libwifi_supports(phyname, "wifi_add_iface")) {
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("add_iface", wl_add_iface, add_iface_policy));
|
|
}
|
|
|
|
if (libwifi_supports(phyname, "wifi_del_iface")) {
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("del_iface", wl_del_iface, del_iface_policy));
|
|
}
|
|
|
|
if (libwifi_supports(phyname, "wifi_channels_info")) {
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD_NOARG("channels_info", wl_channels_info));
|
|
}
|
|
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("channels", wl_channels, wl_dump_channels_policy));
|
|
|
|
if (libwifi_supports(phyname, "wifi_get_opclass_preferences")) {
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD_NOARG("opclass_preferences", wl_opclass_preferences));
|
|
}
|
|
|
|
if (libwifi_supports(phyname, "wifi_simulate_radar") &&
|
|
(band == BAND_5 || band == BAND_DUAL || band == BAND_UNKNOWN)) {
|
|
UBUS_METHOD_ADD(radio_methods, n_methods,
|
|
UBUS_METHOD("simulate_radar", wl_simulate_radar, wl_radar_policy));
|
|
}
|
|
|
|
radio_obj->methods = radio_methods;
|
|
radio_obj->n_methods = n_methods;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#define MAX_WIFI_METHODS 8
|
|
int add_wifi_methods(struct wifimngr *w, struct ubus_object *wifi_obj)
|
|
{
|
|
int n_methods = 0;
|
|
struct ubus_method *wifi_methods;
|
|
|
|
wifi_methods = calloc(MAX_WIFI_METHODS, sizeof(struct ubus_method));
|
|
if (!wifi_methods)
|
|
return -ENOMEM;
|
|
|
|
UBUS_METHOD_ADD(wifi_methods, n_methods,
|
|
UBUS_METHOD_NOARG("status", wl_status));
|
|
|
|
UBUS_METHOD_ADD(wifi_methods, n_methods,
|
|
UBUS_METHOD_NOARG("help", wl_help));
|
|
|
|
UBUS_METHOD_ADD(wifi_methods, n_methods,
|
|
UBUS_METHOD("debug", wifi_set_debug, wifi_set_debug_policy));
|
|
|
|
wifi_obj->methods = wifi_methods;
|
|
wifi_obj->n_methods = n_methods;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int wifimngr_lookup_object(struct wifimngr *w, const char *objname)
|
|
{
|
|
uint32_t id;
|
|
int ret;
|
|
|
|
ret = ubus_lookup_id(w->ubus_ctx, objname, &id);
|
|
if (ret == UBUS_STATUS_OK)
|
|
return id;
|
|
|
|
return ret == UBUS_STATUS_OK ? id : -1;
|
|
}
|
|
|
|
int wifimngr_add_radio_object(struct wifimngr *w, struct wifimngr_device *wdev)
|
|
{
|
|
char *radioname = wdev->device;
|
|
struct wifi_ubus_object *wobj;
|
|
char objname[64] = {0};
|
|
uint32_t id;
|
|
int ret;
|
|
|
|
|
|
snprintf(objname, 63, "%s.%s", WIFI_RADIO_OBJECT, radioname);
|
|
|
|
/* Already added */
|
|
if (ubus_lookup_id(w->ubus_ctx, objname, &id) == UBUS_STATUS_OK) {
|
|
wdev->object_id = id;
|
|
return 0;
|
|
}
|
|
|
|
if (w->num_wifi_device_obj == WIFI_DEV_MAX_NUM) {
|
|
wifimngr_dbg("Cannot add more than %d wifi-device objects\n", w->num_wifi_device_obj);
|
|
return -1;
|
|
}
|
|
|
|
wobj = calloc(1, sizeof(struct wifi_ubus_object));
|
|
if (!wobj)
|
|
return -ENOMEM;
|
|
|
|
wobj->priv = wdev;
|
|
wobj->obj.name = strdup(objname);
|
|
add_radio_methods(w, &wobj->obj, radioname);
|
|
|
|
wobj->obj_type.name = wobj->obj.name;
|
|
wobj->obj_type.n_methods = wobj->obj.n_methods;
|
|
wobj->obj_type.methods = wobj->obj.methods;
|
|
wobj->obj.type = &wobj->obj_type;
|
|
|
|
ret = ubus_add_object(w->ubus_ctx, &wobj->obj);
|
|
if (ret) {
|
|
free((void *)wobj->obj.methods);
|
|
free((void *)wobj->obj.name);
|
|
free(wobj);
|
|
return ret;
|
|
}
|
|
|
|
w->num_wifi_device_obj++;
|
|
wifimngr_dbg("Added '%s' radio obj\n", wobj->obj.name);
|
|
wdev->object_id = wobj->obj.id;
|
|
list_add_tail(&wobj->list, &w->radiolist);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define MAX_AP_METHODS 48
|
|
static int add_ap_methods(struct wifimngr *w, struct ubus_object *interface_obj,
|
|
const char *ifname)
|
|
{
|
|
struct ubus_method *ap_methods;
|
|
int n_methods = 0;
|
|
|
|
ap_methods = calloc(MAX_AP_METHODS, sizeof(struct ubus_method));
|
|
if (!ap_methods)
|
|
return -ENOMEM;
|
|
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD_NOARG("help", wl_ap_help));
|
|
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD_NOARG("status", wl_ap_status));
|
|
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD_NOARG("stats", wl_ap_stats));
|
|
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD_NOARG("assoclist", wl_assoclist));
|
|
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("stations", wl_stations, stainfo_policy));
|
|
|
|
if (libsta_ratings) {
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("sta_ratings", wl_sta_ratings, stainfo_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_get_blocked_stas")) {
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD_NOARG("blocked_stas", wl_blocked_stas));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_block_sta")) {
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("block_sta", wl_block_sta, block_station_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_disconnect_sta")) {
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("disconnect", sta_disconnect, sta_disconnect_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_probe_sta")) {
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("probe_sta", sta_probe, sta_monitor_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_monitor_sta")) {
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("monitor_add", sta_monitor_add, sta_monitor_policy));
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("monitor_del", sta_monitor_del, sta_monitor_policy));
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("monitor_get", sta_monitor_get, sta_monitor_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_subscribe_frame"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("subscribe_frame", subscribe_frame, subscribe_frame_policy));
|
|
if (libwifi_supports(ifname, "wifi_unsubscribe_frame"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("unsubscribe_frame", unsubscribe_frame, subscribe_frame_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_add_neighbor"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("add_neighbor", nbr_add, nbr_add_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_del_neighbor"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("del_neighbor", nbr_del, nbr_del_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_get_neighbor_list"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("list_neighbor", nbr_list, nbr_list_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_req_beacon_report"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("request_neighbor", nbr_request, nbr_req_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_req_btm"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("request_btm", btm_request, btmreq_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_restrict_sta"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("assoc_control", assoc_control, assoc_cntrl_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_add_vendor_ie"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("add_vendor_ie", vsie_add, vsie_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_del_vendor_ie"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("del_vendor_ie", vsie_del, vsie_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_get_beacon_ies"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD_NOARG("dump_beacon", wl_ap_dump_beacon));
|
|
|
|
if (libwifi_supports(ifname, "wifi_chan_switch"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("chan_switch", ap_chan_switch, chan_switch_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_link_measure"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("measure_link", ap_measure_link, linkmeas_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_mbo_disallow_assoc"))
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("mbo_disallow_assoc", ap_mbo_disallow_assoc, mbo_disallow_assoc_policy));
|
|
|
|
if (libwifi_supports(ifname, "wifi_ap_set_state")) {
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD_NOARG("up", ap_bss_up));
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD_NOARG("down", ap_bss_down));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_send_action_frame")) {
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("send_action", ap_send_action, send_action_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_ap_set_qos_map")) {
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("set_qos_map", set_qos_map,
|
|
ap_set_qos_map_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_ap_send_qos_map_conf")) {
|
|
UBUS_METHOD_ADD(ap_methods, n_methods,
|
|
UBUS_METHOD("send_qos_map_conf", send_qos_map_conf,
|
|
ap_send_qos_map_conf_policy));
|
|
}
|
|
|
|
interface_obj->methods = ap_methods;
|
|
interface_obj->n_methods = n_methods;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define MAX_STA_METHODS 8
|
|
static int add_sta_methods(struct wifimngr *w, struct ubus_object *interface_obj,
|
|
const char *ifname)
|
|
{
|
|
int n_methods = 0;
|
|
struct ubus_method *sta_methods;
|
|
|
|
sta_methods = calloc(MAX_STA_METHODS, sizeof(struct ubus_method));
|
|
if (!sta_methods)
|
|
return -ENOMEM;
|
|
|
|
UBUS_METHOD_ADD(sta_methods, n_methods,
|
|
UBUS_METHOD_NOARG("status", wl_sta_status));
|
|
|
|
UBUS_METHOD_ADD(sta_methods, n_methods,
|
|
UBUS_METHOD_NOARG("stats", wl_sta_stats));
|
|
|
|
if (libwifi_supports(ifname, "wifi_sta_disconnect_ap")) {
|
|
UBUS_METHOD_ADD(sta_methods, n_methods,
|
|
UBUS_METHOD("disconnect", wl_sta_disconnect_ap,
|
|
ap_disconnect_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_set_4addr")) {
|
|
UBUS_METHOD_ADD(sta_methods, n_methods,
|
|
UBUS_METHOD("4addr", wl_sta_4addr,
|
|
sta_4addr_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_send_action_frame")) {
|
|
UBUS_METHOD_ADD(sta_methods, n_methods,
|
|
UBUS_METHOD("send_action", ap_send_action, send_action_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_dpp_listen")) {
|
|
UBUS_METHOD_ADD(sta_methods, n_methods,
|
|
UBUS_METHOD("dpp_listen", wl_sta_dpp_listen, dpp_listen_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_dpp_stop_listen")) {
|
|
UBUS_METHOD_ADD(sta_methods, n_methods,
|
|
UBUS_METHOD_NOARG("dpp_stop_listen", wl_sta_dpp_stop_listen));
|
|
}
|
|
|
|
interface_obj->methods = sta_methods;
|
|
interface_obj->n_methods = n_methods;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int wifimngr_add_interface_object(struct wifimngr *w, struct wifimngr_iface *iface)
|
|
{
|
|
struct wifi_ubus_object *wobj;
|
|
char objname[64] = {0};
|
|
uint32_t id;
|
|
int ret;
|
|
|
|
|
|
if (iface->mode == WIFI_MODE_AP) {
|
|
snprintf(objname, 63, "%s.%s", WIFI_AP_OBJECT, iface->iface);
|
|
} else if (iface->mode == WIFI_MODE_STA) {
|
|
snprintf(objname, 63, "%s.%s", WIFI_BSTA_OBJECT, iface->iface);
|
|
} else {
|
|
/* unhandled wifi mode */
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Already added */
|
|
if (ubus_lookup_id(w->ubus_ctx, objname, &id) == UBUS_STATUS_OK) {
|
|
iface->object_id = id;
|
|
return 0;
|
|
}
|
|
|
|
wobj = calloc(1, sizeof(struct wifi_ubus_object));
|
|
if (!wobj)
|
|
return -ENOMEM;
|
|
|
|
wobj->priv = iface;
|
|
if (iface->mode == WIFI_MODE_AP)
|
|
add_ap_methods(w, &wobj->obj, iface->iface);
|
|
else
|
|
add_sta_methods(w, &wobj->obj, iface->iface);
|
|
|
|
wobj->obj.name = strdup(objname);
|
|
wobj->obj_type.name = wobj->obj.name;
|
|
wobj->obj_type.n_methods = wobj->obj.n_methods;
|
|
wobj->obj_type.methods = wobj->obj.methods;
|
|
wobj->obj.type = &wobj->obj_type;
|
|
|
|
ret = ubus_add_object(w->ubus_ctx, &wobj->obj);
|
|
if (!ret) {
|
|
iface->object_id = wobj->obj.id;
|
|
list_add_tail(&wobj->list, &w->iflist);
|
|
} else {
|
|
free((void *)wobj->obj.methods);
|
|
free((void *)wobj->obj.name);
|
|
free(wobj);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#define MAX_APMLD_METHODS 16
|
|
static int add_apmld_methods(struct wifimngr *w,
|
|
struct ubus_object *interface_obj,
|
|
const char *ifname)
|
|
{
|
|
struct ubus_method *apmld_methods;
|
|
int n_methods = 0;
|
|
|
|
apmld_methods = calloc(MAX_APMLD_METHODS, sizeof(struct ubus_method));
|
|
if (!apmld_methods)
|
|
return -ENOMEM;
|
|
|
|
UBUS_METHOD_ADD(apmld_methods, n_methods,
|
|
UBUS_METHOD_NOARG("help", wl_apmld_help));
|
|
|
|
UBUS_METHOD_ADD(apmld_methods, n_methods,
|
|
UBUS_METHOD_NOARG("status", wl_apmld_status));
|
|
|
|
UBUS_METHOD_ADD(apmld_methods, n_methods,
|
|
UBUS_METHOD_NOARG("stats", wl_apmld_stats));
|
|
|
|
UBUS_METHOD_ADD(apmld_methods, n_methods,
|
|
UBUS_METHOD_NOARG("assoclist", wl_apmld_assoclist));
|
|
|
|
UBUS_METHOD_ADD(apmld_methods, n_methods,
|
|
UBUS_METHOD("stations", wl_apmld_stations, stainfo_policy));
|
|
|
|
if (libsta_ratings) {
|
|
UBUS_METHOD_ADD(apmld_methods, n_methods,
|
|
UBUS_METHOD("sta_ratings", wl_apmld_sta_ratings, stainfo_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_disconnect_sta")) {
|
|
UBUS_METHOD_ADD(apmld_methods, n_methods,
|
|
UBUS_METHOD("disconnect", wl_apmld_disconnect_sta, sta_disconnect_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_block_sta")) {
|
|
UBUS_METHOD_ADD(apmld_methods, n_methods,
|
|
UBUS_METHOD("block_sta", wl_apmld_block_sta, apmld_block_station_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_get_blocked_stas")) {
|
|
UBUS_METHOD_ADD(apmld_methods, n_methods,
|
|
UBUS_METHOD("blocked_stas", wl_apmld_blocked_stas, apmld_blocked_maclist_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_get_beacon_ies")) {
|
|
UBUS_METHOD_ADD(apmld_methods, n_methods,
|
|
UBUS_METHOD("dump_beacon", wl_apmld_dump_beacon, dump_beacon_policy));
|
|
}
|
|
|
|
interface_obj->methods = apmld_methods;
|
|
interface_obj->n_methods = n_methods;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define MAX_MLDSTA_METHODS 8
|
|
static int add_mldsta_methods(struct wifimngr *w,
|
|
struct ubus_object *interface_obj,
|
|
const char *ifname)
|
|
{
|
|
struct ubus_method *mldsta_methods;
|
|
int n_methods = 0;
|
|
|
|
mldsta_methods = calloc(MAX_MLDSTA_METHODS, sizeof(struct ubus_method));
|
|
if (!mldsta_methods)
|
|
return -ENOMEM;
|
|
|
|
UBUS_METHOD_ADD(mldsta_methods, n_methods,
|
|
UBUS_METHOD_NOARG("status", wl_mldsta_status));
|
|
|
|
UBUS_METHOD_ADD(mldsta_methods, n_methods,
|
|
UBUS_METHOD_NOARG("stats", wl_mldsta_stats));
|
|
|
|
if (libwifi_supports(ifname, "wifi_sta_disconnect_ap")) {
|
|
UBUS_METHOD_ADD(mldsta_methods, n_methods,
|
|
UBUS_METHOD("disconnect", wl_mldsta_disconnect_ap,
|
|
ap_disconnect_policy));
|
|
}
|
|
|
|
if (libwifi_supports(ifname, "wifi_set_4addr")) {
|
|
UBUS_METHOD_ADD(mldsta_methods, n_methods,
|
|
UBUS_METHOD("4addr", wl_sta_4addr,
|
|
sta_4addr_policy));
|
|
}
|
|
|
|
interface_obj->methods = mldsta_methods;
|
|
interface_obj->n_methods = n_methods;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int wifimngr_add_mld_interface_object(struct wifimngr *w, struct wifimngr_mld *mldif)
|
|
{
|
|
struct wifi_ubus_object *wobj;
|
|
char objname[64] = {0};
|
|
uint32_t id;
|
|
int ret;
|
|
|
|
if (mldif->mode == WIFI_MODE_AP)
|
|
snprintf(objname, 63, "%s.%s", WIFI_APMLD_OBJECT, mldif->ifname);
|
|
else if (mldif->mode == WIFI_MODE_STA)
|
|
snprintf(objname, 63, "%s.%s", WIFI_BSTAMLD_OBJECT, mldif->ifname);
|
|
else
|
|
return -EINVAL;
|
|
|
|
/* Already added */
|
|
if (ubus_lookup_id(w->ubus_ctx, objname, &id) == UBUS_STATUS_OK) {
|
|
mldif->object_id = id;
|
|
return 0;
|
|
}
|
|
|
|
wobj = calloc(1, sizeof(struct wifi_ubus_object));
|
|
if (!wobj)
|
|
return -ENOMEM;
|
|
|
|
wobj->priv = mldif;
|
|
if (mldif->mode == WIFI_MODE_AP)
|
|
add_apmld_methods(w, &wobj->obj, mldif->ifname);
|
|
else
|
|
add_mldsta_methods(w, &wobj->obj, mldif->ifname);
|
|
|
|
wobj->obj.name = strdup(objname);
|
|
wobj->obj_type.name = wobj->obj.name;
|
|
wobj->obj_type.n_methods = wobj->obj.n_methods;
|
|
wobj->obj_type.methods = wobj->obj.methods;
|
|
wobj->obj.type = &wobj->obj_type;
|
|
|
|
ret = ubus_add_object(w->ubus_ctx, &wobj->obj);
|
|
if (!ret) {
|
|
mldif->object_id = wobj->obj.id;
|
|
list_add_tail(&wobj->list, &w->iflist);
|
|
} else {
|
|
free((void *)wobj->obj.methods);
|
|
free((void *)wobj->obj.name);
|
|
free(wobj);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void wifimngr_del_object(struct wifimngr *w, struct ubus_object *obj, bool remove_from_ubus)
|
|
{
|
|
/* Remove from ubus before freeing memory to avoid use-after-free.
|
|
* Skip removal only during final cleanup when ubus_free() will handle it. */
|
|
if (remove_from_ubus && w->ubus_ctx && obj->id)
|
|
ubus_remove_object(w->ubus_ctx, obj);
|
|
|
|
if (obj->methods)
|
|
free((void *)obj->methods);
|
|
|
|
if (obj->name)
|
|
free((void *)obj->name);
|
|
}
|
|
|
|
int wifimngr_add_objects(struct wifimngr *w)
|
|
{
|
|
int ret;
|
|
|
|
ret = wifimngr_add_object(w, WIFI_OBJECT, add_wifi_methods, &w->wifi_obj);
|
|
if (ret) {
|
|
wifimngr_err("Failed to add '%s' ubus object: %s\n",
|
|
WIFI_OBJECT, ubus_strerror(ret));
|
|
goto out_exit;
|
|
}
|
|
|
|
ret = wifimngr_add_object(w, WIFI_WPS_OBJECT, add_wps_methods, &w->wifi_wps_obj);
|
|
if (ret) {
|
|
wifimngr_err("Failed to add '%s' ubus object: %s\n",
|
|
WIFI_WPS_OBJECT, ubus_strerror(ret));
|
|
goto out_exit;
|
|
}
|
|
|
|
wifimngr_reconfig(w);
|
|
return 0;
|
|
|
|
out_exit:
|
|
return -1;
|
|
}
|
|
|