mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-29 10:08:59 +00:00
hostapd: add support for accessing 802.11k neighbor report elements via ubus
This API can be used to distribute neighbor report entries across multiple APs on the same LAN. Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
9f5f5d250e
commit
79216243d7
@ -9,8 +9,10 @@
|
|||||||
#include "utils/includes.h"
|
#include "utils/includes.h"
|
||||||
#include "utils/common.h"
|
#include "utils/common.h"
|
||||||
#include "utils/eloop.h"
|
#include "utils/eloop.h"
|
||||||
|
#include "utils/wpabuf.h"
|
||||||
#include "common/ieee802_11_defs.h"
|
#include "common/ieee802_11_defs.h"
|
||||||
#include "hostapd.h"
|
#include "hostapd.h"
|
||||||
|
#include "neighbor_db.h"
|
||||||
#include "wps_hostapd.h"
|
#include "wps_hostapd.h"
|
||||||
#include "sta_info.h"
|
#include "sta_info.h"
|
||||||
#include "ubus.h"
|
#include "ubus.h"
|
||||||
@ -447,6 +449,170 @@ hostapd_vendor_elements(struct ubus_context *ctx, struct ubus_object *obj,
|
|||||||
return UBUS_STATUS_OK;
|
return UBUS_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hostapd_rrm_print_nr(struct hostapd_neighbor_entry *nr)
|
||||||
|
{
|
||||||
|
const u8 *data;
|
||||||
|
char *str;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
blobmsg_printf(&b, "", MACSTR, MAC2STR(nr->bssid));
|
||||||
|
|
||||||
|
str = blobmsg_alloc_string_buffer(&b, "", nr->ssid.ssid_len + 1);
|
||||||
|
memcpy(str, nr->ssid.ssid, nr->ssid.ssid_len);
|
||||||
|
str[nr->ssid.ssid_len] = 0;
|
||||||
|
blobmsg_add_string_buffer(&b);
|
||||||
|
|
||||||
|
len = wpabuf_len(nr->nr);
|
||||||
|
str = blobmsg_alloc_string_buffer(&b, "", 2 * len + 1);
|
||||||
|
wpa_snprintf_hex(str, 2 * len + 1, wpabuf_head_u8(nr->nr), len);
|
||||||
|
blobmsg_add_string_buffer(&b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hostapd_rrm_nr_get_own(struct ubus_context *ctx, struct ubus_object *obj,
|
||||||
|
struct ubus_request_data *req, const char *method,
|
||||||
|
struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = get_hapd_from_object(obj);
|
||||||
|
struct hostapd_neighbor_entry *nr;
|
||||||
|
void *c;
|
||||||
|
|
||||||
|
if (!(hapd->conf->radio_measurements[0] & WLAN_RRM_CAPS_NEIGHBOR_REPORT))
|
||||||
|
return UBUS_STATUS_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
nr = hostapd_neighbor_get(hapd, hapd->own_addr, NULL);
|
||||||
|
if (!nr)
|
||||||
|
return UBUS_STATUS_NOT_FOUND;
|
||||||
|
|
||||||
|
blob_buf_init(&b, 0);
|
||||||
|
|
||||||
|
c = blobmsg_open_array(&b, "value");
|
||||||
|
hostapd_rrm_print_nr(nr);
|
||||||
|
blobmsg_close_array(&b, c);
|
||||||
|
|
||||||
|
ubus_send_reply(ctx, req, b.head);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hostapd_rrm_nr_list(struct ubus_context *ctx, struct ubus_object *obj,
|
||||||
|
struct ubus_request_data *req, const char *method,
|
||||||
|
struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = get_hapd_from_object(obj);
|
||||||
|
struct hostapd_neighbor_entry *nr;
|
||||||
|
void *c;
|
||||||
|
|
||||||
|
if (!(hapd->conf->radio_measurements[0] & WLAN_RRM_CAPS_NEIGHBOR_REPORT))
|
||||||
|
return UBUS_STATUS_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
blob_buf_init(&b, 0);
|
||||||
|
|
||||||
|
c = blobmsg_open_array(&b, "list");
|
||||||
|
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
|
||||||
|
void *cur;
|
||||||
|
|
||||||
|
if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cur = blobmsg_open_array(&b, NULL);
|
||||||
|
hostapd_rrm_print_nr(nr);
|
||||||
|
blobmsg_close_array(&b, cur);
|
||||||
|
}
|
||||||
|
blobmsg_close_array(&b, c);
|
||||||
|
|
||||||
|
ubus_send_reply(ctx, req, b.head);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NR_SET_LIST,
|
||||||
|
__NR_SET_LIST_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct blobmsg_policy nr_set_policy[__NR_SET_LIST_MAX] = {
|
||||||
|
[NR_SET_LIST] = { "list", BLOBMSG_TYPE_ARRAY },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
hostapd_rrm_nr_clear(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct hostapd_neighbor_entry *nr;
|
||||||
|
|
||||||
|
restart:
|
||||||
|
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
|
||||||
|
if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hostapd_neighbor_remove(hapd, nr->bssid, &nr->ssid);
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hostapd_rrm_nr_set(struct ubus_context *ctx, struct ubus_object *obj,
|
||||||
|
struct ubus_request_data *req, const char *method,
|
||||||
|
struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
static const struct blobmsg_policy nr_e_policy[] = {
|
||||||
|
{ .type = BLOBMSG_TYPE_STRING },
|
||||||
|
{ .type = BLOBMSG_TYPE_STRING },
|
||||||
|
{ .type = BLOBMSG_TYPE_STRING },
|
||||||
|
};
|
||||||
|
struct hostapd_data *hapd = get_hapd_from_object(obj);
|
||||||
|
struct blob_attr *tb_l[__NR_SET_LIST_MAX];
|
||||||
|
struct blob_attr *tb[ARRAY_SIZE(nr_e_policy)];
|
||||||
|
struct blob_attr *cur;
|
||||||
|
int ret = 0;
|
||||||
|
int rem;
|
||||||
|
|
||||||
|
if (!(hapd->conf->radio_measurements[0] & WLAN_RRM_CAPS_NEIGHBOR_REPORT))
|
||||||
|
return UBUS_STATUS_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
blobmsg_parse(nr_set_policy, __NR_SET_LIST_MAX, tb_l, blob_data(msg), blob_len(msg));
|
||||||
|
if (!tb_l[NR_SET_LIST])
|
||||||
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
hostapd_rrm_nr_clear(hapd);
|
||||||
|
blobmsg_for_each_attr(cur, tb_l[NR_SET_LIST], rem) {
|
||||||
|
struct wpa_ssid_value ssid;
|
||||||
|
struct wpabuf *data;
|
||||||
|
u8 bssid[ETH_ALEN];
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
blobmsg_parse_array(nr_e_policy, ARRAY_SIZE(nr_e_policy), tb, blobmsg_data(cur), blobmsg_data_len(cur));
|
||||||
|
if (!tb[0] || !tb[1] || !tb[2])
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
s = blobmsg_get_string(tb[0]);
|
||||||
|
if (hwaddr_aton(s, bssid))
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
s = blobmsg_get_string(tb[1]);
|
||||||
|
ssid.ssid_len = strlen(s);
|
||||||
|
if (ssid.ssid_len > sizeof(ssid.ssid))
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
memcpy(&ssid, s, ssid.ssid_len);
|
||||||
|
data = wpabuf_parse_bin(blobmsg_get_string(tb[2]));
|
||||||
|
if (!data)
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
hostapd_neighbor_set(hapd, bssid, &ssid, data, NULL, NULL, 0);
|
||||||
|
wpabuf_free(data);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
invalid:
|
||||||
|
ret = UBUS_STATUS_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct ubus_method bss_methods[] = {
|
static const struct ubus_method bss_methods[] = {
|
||||||
UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
|
UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
|
||||||
UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
|
UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
|
||||||
@ -459,6 +625,9 @@ static const struct ubus_method bss_methods[] = {
|
|||||||
#endif
|
#endif
|
||||||
UBUS_METHOD("set_vendor_elements", hostapd_vendor_elements, ve_policy),
|
UBUS_METHOD("set_vendor_elements", hostapd_vendor_elements, ve_policy),
|
||||||
UBUS_METHOD("notify_response", hostapd_notify_response, notify_policy),
|
UBUS_METHOD("notify_response", hostapd_notify_response, notify_policy),
|
||||||
|
UBUS_METHOD_NOARG("rrm_nr_get_own", hostapd_rrm_nr_get_own),
|
||||||
|
UBUS_METHOD_NOARG("rrm_nr_list", hostapd_rrm_nr_list),
|
||||||
|
UBUS_METHOD("rrm_nr_set", hostapd_rrm_nr_set, nr_set_policy),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ubus_object_type bss_object_type =
|
static struct ubus_object_type bss_object_type =
|
||||||
|
Loading…
Reference in New Issue
Block a user