2f92b785932c729219521cdc48fef96ffadd5eb1
[openwrt/openwrt.git] / package / network / services / hostapd / src / src / ap / ubus.c
1 /*
2 * hostapd / ubus support
3 * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "utils/includes.h"
10 #include "utils/common.h"
11 #include "utils/eloop.h"
12 #include "utils/wpabuf.h"
13 #include "common/ieee802_11_defs.h"
14 #include "hostapd.h"
15 #include "neighbor_db.h"
16 #include "wps_hostapd.h"
17 #include "sta_info.h"
18 #include "ubus.h"
19 #include "ap_drv_ops.h"
20 #include "beacon.h"
21
22 static struct ubus_context *ctx;
23 static struct blob_buf b;
24 static int ctx_ref;
25
26 static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj)
27 {
28 return container_of(obj, struct hostapd_data, ubus.obj);
29 }
30
31
32 struct ubus_banned_client {
33 struct avl_node avl;
34 u8 addr[ETH_ALEN];
35 };
36
37 static void ubus_receive(int sock, void *eloop_ctx, void *sock_ctx)
38 {
39 struct ubus_context *ctx = eloop_ctx;
40 ubus_handle_event(ctx);
41 }
42
43 static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
44 {
45 if (ubus_reconnect(ctx, NULL)) {
46 eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
47 return;
48 }
49
50 eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL);
51 }
52
53 static void hostapd_ubus_connection_lost(struct ubus_context *ctx)
54 {
55 eloop_unregister_read_sock(ctx->sock.fd);
56 eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
57 }
58
59 static bool hostapd_ubus_init(void)
60 {
61 if (ctx)
62 return true;
63
64 ctx = ubus_connect(NULL);
65 if (!ctx)
66 return false;
67
68 ctx->connection_lost = hostapd_ubus_connection_lost;
69 eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL);
70 return true;
71 }
72
73 static void hostapd_ubus_ref_inc(void)
74 {
75 ctx_ref++;
76 }
77
78 static void hostapd_ubus_ref_dec(void)
79 {
80 ctx_ref--;
81 if (!ctx)
82 return;
83
84 if (ctx_ref)
85 return;
86
87 eloop_unregister_read_sock(ctx->sock.fd);
88 ubus_free(ctx);
89 ctx = NULL;
90 }
91
92 void hostapd_ubus_add_iface(struct hostapd_iface *iface)
93 {
94 if (!hostapd_ubus_init())
95 return;
96 }
97
98 void hostapd_ubus_free_iface(struct hostapd_iface *iface)
99 {
100 if (!ctx)
101 return;
102 }
103
104 static void
105 hostapd_bss_del_ban(void *eloop_data, void *user_ctx)
106 {
107 struct ubus_banned_client *ban = eloop_data;
108 struct hostapd_data *hapd = user_ctx;
109
110 avl_delete(&hapd->ubus.banned, &ban->avl);
111 free(ban);
112 }
113
114 static void
115 hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time)
116 {
117 struct ubus_banned_client *ban;
118
119 if (time < 0)
120 time = 0;
121
122 ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
123 if (!ban) {
124 if (!time)
125 return;
126
127 ban = os_zalloc(sizeof(*ban));
128 memcpy(ban->addr, addr, sizeof(ban->addr));
129 ban->avl.key = ban->addr;
130 avl_insert(&hapd->ubus.banned, &ban->avl);
131 } else {
132 eloop_cancel_timeout(hostapd_bss_del_ban, ban, hapd);
133 if (!time) {
134 hostapd_bss_del_ban(ban, hapd);
135 return;
136 }
137 }
138
139 eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd);
140 }
141
142 static int
143 hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
144 struct ubus_request_data *req, const char *method,
145 struct blob_attr *msg)
146 {
147 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
148 struct sta_info *sta;
149 void *list, *c;
150 char mac_buf[20];
151 static const struct {
152 const char *name;
153 uint32_t flag;
154 } sta_flags[] = {
155 { "auth", WLAN_STA_AUTH },
156 { "assoc", WLAN_STA_ASSOC },
157 { "authorized", WLAN_STA_AUTHORIZED },
158 { "preauth", WLAN_STA_PREAUTH },
159 { "wds", WLAN_STA_WDS },
160 { "wmm", WLAN_STA_WMM },
161 { "ht", WLAN_STA_HT },
162 { "vht", WLAN_STA_VHT },
163 { "wps", WLAN_STA_WPS },
164 { "mfp", WLAN_STA_MFP },
165 };
166
167 blob_buf_init(&b, 0);
168 blobmsg_add_u32(&b, "freq", hapd->iface->freq);
169 list = blobmsg_open_table(&b, "clients");
170 for (sta = hapd->sta_list; sta; sta = sta->next) {
171 void *r;
172 int i;
173
174 sprintf(mac_buf, MACSTR, MAC2STR(sta->addr));
175 c = blobmsg_open_table(&b, mac_buf);
176 for (i = 0; i < ARRAY_SIZE(sta_flags); i++)
177 blobmsg_add_u8(&b, sta_flags[i].name,
178 !!(sta->flags & sta_flags[i].flag));
179
180 r = blobmsg_open_array(&b, "rrm");
181 for (i = 0; i < ARRAY_SIZE(sta->rrm_enabled_capa); i++)
182 blobmsg_add_u32(&b, "", sta->rrm_enabled_capa[i]);
183 blobmsg_close_array(&b, r);
184 blobmsg_add_u32(&b, "aid", sta->aid);
185 blobmsg_close_table(&b, c);
186 }
187 blobmsg_close_array(&b, list);
188 ubus_send_reply(ctx, req, b.head);
189
190 return 0;
191 }
192
193 enum {
194 NOTIFY_RESPONSE,
195 __NOTIFY_MAX
196 };
197
198 static const struct blobmsg_policy notify_policy[__NOTIFY_MAX] = {
199 [NOTIFY_RESPONSE] = { "notify_response", BLOBMSG_TYPE_INT32 },
200 };
201
202 static int
203 hostapd_notify_response(struct ubus_context *ctx, struct ubus_object *obj,
204 struct ubus_request_data *req, const char *method,
205 struct blob_attr *msg)
206 {
207 struct blob_attr *tb[__NOTIFY_MAX];
208 struct hostapd_data *hapd = get_hapd_from_object(obj);
209 struct wpabuf *elems;
210 const char *pos;
211 size_t len;
212
213 blobmsg_parse(notify_policy, __NOTIFY_MAX, tb,
214 blob_data(msg), blob_len(msg));
215
216 if (!tb[NOTIFY_RESPONSE])
217 return UBUS_STATUS_INVALID_ARGUMENT;
218
219 hapd->ubus.notify_response = blobmsg_get_u32(tb[NOTIFY_RESPONSE]);
220
221 return UBUS_STATUS_OK;
222 }
223
224 enum {
225 DEL_CLIENT_ADDR,
226 DEL_CLIENT_REASON,
227 DEL_CLIENT_DEAUTH,
228 DEL_CLIENT_BAN_TIME,
229 __DEL_CLIENT_MAX
230 };
231
232 static const struct blobmsg_policy del_policy[__DEL_CLIENT_MAX] = {
233 [DEL_CLIENT_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
234 [DEL_CLIENT_REASON] = { "reason", BLOBMSG_TYPE_INT32 },
235 [DEL_CLIENT_DEAUTH] = { "deauth", BLOBMSG_TYPE_INT8 },
236 [DEL_CLIENT_BAN_TIME] = { "ban_time", BLOBMSG_TYPE_INT32 },
237 };
238
239 static int
240 hostapd_bss_del_client(struct ubus_context *ctx, struct ubus_object *obj,
241 struct ubus_request_data *req, const char *method,
242 struct blob_attr *msg)
243 {
244 struct blob_attr *tb[__DEL_CLIENT_MAX];
245 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
246 struct sta_info *sta;
247 bool deauth = false;
248 int reason;
249 u8 addr[ETH_ALEN];
250
251 blobmsg_parse(del_policy, __DEL_CLIENT_MAX, tb, blob_data(msg), blob_len(msg));
252
253 if (!tb[DEL_CLIENT_ADDR])
254 return UBUS_STATUS_INVALID_ARGUMENT;
255
256 if (hwaddr_aton(blobmsg_data(tb[DEL_CLIENT_ADDR]), addr))
257 return UBUS_STATUS_INVALID_ARGUMENT;
258
259 if (tb[DEL_CLIENT_REASON])
260 reason = blobmsg_get_u32(tb[DEL_CLIENT_REASON]);
261
262 if (tb[DEL_CLIENT_DEAUTH])
263 deauth = blobmsg_get_bool(tb[DEL_CLIENT_DEAUTH]);
264
265 sta = ap_get_sta(hapd, addr);
266 if (sta) {
267 if (deauth) {
268 hostapd_drv_sta_deauth(hapd, addr, reason);
269 ap_sta_deauthenticate(hapd, sta, reason);
270 } else {
271 hostapd_drv_sta_disassoc(hapd, addr, reason);
272 ap_sta_disassociate(hapd, sta, reason);
273 }
274 }
275
276 if (tb[DEL_CLIENT_BAN_TIME])
277 hostapd_bss_ban_client(hapd, addr, blobmsg_get_u32(tb[DEL_CLIENT_BAN_TIME]));
278
279 return 0;
280 }
281
282 static void
283 blobmsg_add_macaddr(struct blob_buf *buf, const char *name, const u8 *addr)
284 {
285 char *s;
286
287 s = blobmsg_alloc_string_buffer(buf, name, 20);
288 sprintf(s, MACSTR, MAC2STR(addr));
289 blobmsg_add_string_buffer(buf);
290 }
291
292 static int
293 hostapd_bss_list_bans(struct ubus_context *ctx, struct ubus_object *obj,
294 struct ubus_request_data *req, const char *method,
295 struct blob_attr *msg)
296 {
297 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
298 struct ubus_banned_client *ban;
299 void *c;
300
301 blob_buf_init(&b, 0);
302 c = blobmsg_open_array(&b, "clients");
303 avl_for_each_element(&hapd->ubus.banned, ban, avl)
304 blobmsg_add_macaddr(&b, NULL, ban->addr);
305 blobmsg_close_array(&b, c);
306 ubus_send_reply(ctx, req, b.head);
307
308 return 0;
309 }
310
311 static int
312 hostapd_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
313 struct ubus_request_data *req, const char *method,
314 struct blob_attr *msg)
315 {
316 int rc;
317 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
318
319 rc = hostapd_wps_button_pushed(hapd, NULL);
320
321 if (rc != 0)
322 return UBUS_STATUS_NOT_SUPPORTED;
323
324 return 0;
325 }
326
327 static int
328 hostapd_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
329 struct ubus_request_data *req, const char *method,
330 struct blob_attr *msg)
331 {
332 int rc;
333 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
334
335 rc = hostapd_wps_cancel(hapd);
336
337 if (rc != 0)
338 return UBUS_STATUS_NOT_SUPPORTED;
339
340 return 0;
341 }
342
343 static int
344 hostapd_bss_update_beacon(struct ubus_context *ctx, struct ubus_object *obj,
345 struct ubus_request_data *req, const char *method,
346 struct blob_attr *msg)
347 {
348 int rc;
349 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
350
351 rc = ieee802_11_set_beacon(hapd);
352
353 if (rc != 0)
354 return UBUS_STATUS_NOT_SUPPORTED;
355
356 return 0;
357 }
358
359 enum {
360 CSA_FREQ,
361 CSA_BCN_COUNT,
362 __CSA_MAX
363 };
364
365 static const struct blobmsg_policy csa_policy[__CSA_MAX] = {
366 /*
367 * for now, frequency and beacon count are enough, add more
368 * parameters on demand
369 */
370 [CSA_FREQ] = { "freq", BLOBMSG_TYPE_INT32 },
371 [CSA_BCN_COUNT] = { "bcn_count", BLOBMSG_TYPE_INT32 },
372 };
373
374 #ifdef NEED_AP_MLME
375 static int
376 hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
377 struct ubus_request_data *req, const char *method,
378 struct blob_attr *msg)
379 {
380 struct blob_attr *tb[__CSA_MAX];
381 struct hostapd_data *hapd = get_hapd_from_object(obj);
382 struct csa_settings css;
383
384 blobmsg_parse(csa_policy, __CSA_MAX, tb, blob_data(msg), blob_len(msg));
385
386 if (!tb[CSA_FREQ])
387 return UBUS_STATUS_INVALID_ARGUMENT;
388
389 memset(&css, 0, sizeof(css));
390 css.freq_params.freq = blobmsg_get_u32(tb[CSA_FREQ]);
391 if (tb[CSA_BCN_COUNT])
392 css.cs_count = blobmsg_get_u32(tb[CSA_BCN_COUNT]);
393
394 if (hostapd_switch_channel(hapd, &css) != 0)
395 return UBUS_STATUS_NOT_SUPPORTED;
396 return UBUS_STATUS_OK;
397 }
398 #endif
399
400 enum {
401 VENDOR_ELEMENTS,
402 __VENDOR_ELEMENTS_MAX
403 };
404
405 static const struct blobmsg_policy ve_policy[__VENDOR_ELEMENTS_MAX] = {
406 /* vendor elements are provided as hex-string */
407 [VENDOR_ELEMENTS] = { "vendor_elements", BLOBMSG_TYPE_STRING },
408 };
409
410 static int
411 hostapd_vendor_elements(struct ubus_context *ctx, struct ubus_object *obj,
412 struct ubus_request_data *req, const char *method,
413 struct blob_attr *msg)
414 {
415 struct blob_attr *tb[__VENDOR_ELEMENTS_MAX];
416 struct hostapd_data *hapd = get_hapd_from_object(obj);
417 struct hostapd_bss_config *bss = hapd->conf;
418 struct wpabuf *elems;
419 const char *pos;
420 size_t len;
421
422 blobmsg_parse(ve_policy, __VENDOR_ELEMENTS_MAX, tb,
423 blob_data(msg), blob_len(msg));
424
425 if (!tb[VENDOR_ELEMENTS])
426 return UBUS_STATUS_INVALID_ARGUMENT;
427
428 pos = blobmsg_data(tb[VENDOR_ELEMENTS]);
429 len = os_strlen(pos);
430 if (len & 0x01)
431 return UBUS_STATUS_INVALID_ARGUMENT;
432
433 len /= 2;
434 if (len == 0) {
435 wpabuf_free(bss->vendor_elements);
436 bss->vendor_elements = NULL;
437 return 0;
438 }
439
440 elems = wpabuf_alloc(len);
441 if (elems == NULL)
442 return 1;
443
444 if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
445 wpabuf_free(elems);
446 return UBUS_STATUS_INVALID_ARGUMENT;
447 }
448
449 wpabuf_free(bss->vendor_elements);
450 bss->vendor_elements = elems;
451
452 /* update beacons if vendor elements were set successfully */
453 if (ieee802_11_update_beacons(hapd->iface) != 0)
454 return UBUS_STATUS_NOT_SUPPORTED;
455 return UBUS_STATUS_OK;
456 }
457
458 static void
459 hostapd_rrm_print_nr(struct hostapd_neighbor_entry *nr)
460 {
461 const u8 *data;
462 char *str;
463 int len;
464
465 blobmsg_printf(&b, "", MACSTR, MAC2STR(nr->bssid));
466
467 str = blobmsg_alloc_string_buffer(&b, "", nr->ssid.ssid_len + 1);
468 memcpy(str, nr->ssid.ssid, nr->ssid.ssid_len);
469 str[nr->ssid.ssid_len] = 0;
470 blobmsg_add_string_buffer(&b);
471
472 len = wpabuf_len(nr->nr);
473 str = blobmsg_alloc_string_buffer(&b, "", 2 * len + 1);
474 wpa_snprintf_hex(str, 2 * len + 1, wpabuf_head_u8(nr->nr), len);
475 blobmsg_add_string_buffer(&b);
476 }
477
478 enum {
479 BSS_MGMT_EN_NEIGHBOR,
480 BSS_MGMT_EN_BEACON,
481 #ifdef CONFIG_WNM_AP
482 BSS_MGMT_EN_BSS_TRANSITION,
483 #endif
484 __BSS_MGMT_EN_MAX
485 };
486
487 static bool
488 __hostapd_bss_mgmt_enable_f(struct hostapd_data *hapd, int flag)
489 {
490 struct hostapd_bss_config *bss = hapd->conf;
491 uint32_t flags;
492
493 switch (flag) {
494 case BSS_MGMT_EN_NEIGHBOR:
495 if (bss->radio_measurements[0] &
496 WLAN_RRM_CAPS_NEIGHBOR_REPORT)
497 return false;
498
499 bss->radio_measurements[0] |=
500 WLAN_RRM_CAPS_NEIGHBOR_REPORT;
501 hostapd_set_own_neighbor_report(hapd);
502 return true;
503 case BSS_MGMT_EN_BEACON:
504 flags = WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
505 WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
506 WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
507
508 if (bss->radio_measurements[0] & flags == flags)
509 return false;
510
511 bss->radio_measurements[0] |= (u8) flags;
512 return true;
513 #ifdef CONFIG_WNM_AP
514 case BSS_MGMT_EN_BSS_TRANSITION:
515 if (bss->bss_transition)
516 return false;
517
518 bss->bss_transition = 1;
519 return true;
520 #endif
521 }
522 }
523
524 static void
525 __hostapd_bss_mgmt_enable(struct hostapd_data *hapd, uint32_t flags)
526 {
527 bool update = false;
528 int i;
529
530 for (i = 0; i < __BSS_MGMT_EN_MAX; i++) {
531 if (!(flags & (1 << i)))
532 continue;
533
534 update |= __hostapd_bss_mgmt_enable_f(hapd, i);
535 }
536
537 if (update)
538 ieee802_11_update_beacons(hapd->iface);
539 }
540
541
542 static const struct blobmsg_policy bss_mgmt_enable_policy[__BSS_MGMT_EN_MAX] = {
543 [BSS_MGMT_EN_NEIGHBOR] = { "neighbor_report", BLOBMSG_TYPE_BOOL },
544 [BSS_MGMT_EN_BEACON] = { "beacon_report", BLOBMSG_TYPE_BOOL },
545 #ifdef CONFIG_WNM_AP
546 [BSS_MGMT_EN_BSS_TRANSITION] = { "bss_transition", BLOBMSG_TYPE_BOOL },
547 #endif
548 };
549
550 static int
551 hostapd_bss_mgmt_enable(struct ubus_context *ctx, struct ubus_object *obj,
552 struct ubus_request_data *req, const char *method,
553 struct blob_attr *msg)
554
555 {
556 struct hostapd_data *hapd = get_hapd_from_object(obj);
557 struct blob_attr *tb[__BSS_MGMT_EN_MAX];
558 struct blob_attr *cur;
559 uint32_t flags = 0;
560 int i;
561 bool neigh = false, beacon = false;
562
563 blobmsg_parse(bss_mgmt_enable_policy, __BSS_MGMT_EN_MAX, tb, blob_data(msg), blob_len(msg));
564
565 for (i = 0; i < ARRAY_SIZE(tb); i++) {
566 if (!tb[i] || !blobmsg_get_bool(tb[i]))
567 continue;
568
569 flags |= (1 << i);
570 }
571
572 __hostapd_bss_mgmt_enable(hapd, flags);
573 }
574
575
576 static void
577 hostapd_rrm_nr_enable(struct hostapd_data *hapd)
578 {
579 __hostapd_bss_mgmt_enable(hapd, 1 << BSS_MGMT_EN_NEIGHBOR);
580 }
581
582 static int
583 hostapd_rrm_nr_get_own(struct ubus_context *ctx, struct ubus_object *obj,
584 struct ubus_request_data *req, const char *method,
585 struct blob_attr *msg)
586 {
587 struct hostapd_data *hapd = get_hapd_from_object(obj);
588 struct hostapd_neighbor_entry *nr;
589 void *c;
590
591 hostapd_rrm_nr_enable(hapd);
592
593 nr = hostapd_neighbor_get(hapd, hapd->own_addr, NULL);
594 if (!nr)
595 return UBUS_STATUS_NOT_FOUND;
596
597 blob_buf_init(&b, 0);
598
599 c = blobmsg_open_array(&b, "value");
600 hostapd_rrm_print_nr(nr);
601 blobmsg_close_array(&b, c);
602
603 ubus_send_reply(ctx, req, b.head);
604
605 return 0;
606 }
607
608 static int
609 hostapd_rrm_nr_list(struct ubus_context *ctx, struct ubus_object *obj,
610 struct ubus_request_data *req, const char *method,
611 struct blob_attr *msg)
612 {
613 struct hostapd_data *hapd = get_hapd_from_object(obj);
614 struct hostapd_neighbor_entry *nr;
615 void *c;
616
617 hostapd_rrm_nr_enable(hapd);
618 blob_buf_init(&b, 0);
619
620 c = blobmsg_open_array(&b, "list");
621 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
622 void *cur;
623
624 if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
625 continue;
626
627 cur = blobmsg_open_array(&b, NULL);
628 hostapd_rrm_print_nr(nr);
629 blobmsg_close_array(&b, cur);
630 }
631 blobmsg_close_array(&b, c);
632
633 ubus_send_reply(ctx, req, b.head);
634
635 return 0;
636 }
637
638 enum {
639 NR_SET_LIST,
640 __NR_SET_LIST_MAX
641 };
642
643 static const struct blobmsg_policy nr_set_policy[__NR_SET_LIST_MAX] = {
644 [NR_SET_LIST] = { "list", BLOBMSG_TYPE_ARRAY },
645 };
646
647
648 static void
649 hostapd_rrm_nr_clear(struct hostapd_data *hapd)
650 {
651 struct hostapd_neighbor_entry *nr;
652
653 restart:
654 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
655 if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
656 continue;
657
658 hostapd_neighbor_remove(hapd, nr->bssid, &nr->ssid);
659 goto restart;
660 }
661 }
662
663 static int
664 hostapd_rrm_nr_set(struct ubus_context *ctx, struct ubus_object *obj,
665 struct ubus_request_data *req, const char *method,
666 struct blob_attr *msg)
667 {
668 static const struct blobmsg_policy nr_e_policy[] = {
669 { .type = BLOBMSG_TYPE_STRING },
670 { .type = BLOBMSG_TYPE_STRING },
671 { .type = BLOBMSG_TYPE_STRING },
672 };
673 struct hostapd_data *hapd = get_hapd_from_object(obj);
674 struct blob_attr *tb_l[__NR_SET_LIST_MAX];
675 struct blob_attr *tb[ARRAY_SIZE(nr_e_policy)];
676 struct blob_attr *cur;
677 int ret = 0;
678 int rem;
679
680 hostapd_rrm_nr_enable(hapd);
681
682 blobmsg_parse(nr_set_policy, __NR_SET_LIST_MAX, tb_l, blob_data(msg), blob_len(msg));
683 if (!tb_l[NR_SET_LIST])
684 return UBUS_STATUS_INVALID_ARGUMENT;
685
686 hostapd_rrm_nr_clear(hapd);
687 blobmsg_for_each_attr(cur, tb_l[NR_SET_LIST], rem) {
688 struct wpa_ssid_value ssid;
689 struct wpabuf *data;
690 u8 bssid[ETH_ALEN];
691 char *s;
692
693 blobmsg_parse_array(nr_e_policy, ARRAY_SIZE(nr_e_policy), tb, blobmsg_data(cur), blobmsg_data_len(cur));
694 if (!tb[0] || !tb[1] || !tb[2])
695 goto invalid;
696
697 s = blobmsg_get_string(tb[0]);
698 if (hwaddr_aton(s, bssid))
699 goto invalid;
700
701 s = blobmsg_get_string(tb[1]);
702 ssid.ssid_len = strlen(s);
703 if (ssid.ssid_len > sizeof(ssid.ssid))
704 goto invalid;
705
706 memcpy(&ssid, s, ssid.ssid_len);
707 data = wpabuf_parse_bin(blobmsg_get_string(tb[2]));
708 if (!data)
709 goto invalid;
710
711 hostapd_neighbor_set(hapd, bssid, &ssid, data, NULL, NULL, 0);
712 wpabuf_free(data);
713 continue;
714
715 invalid:
716 ret = UBUS_STATUS_INVALID_ARGUMENT;
717 }
718
719 return 0;
720 }
721
722 static const struct ubus_method bss_methods[] = {
723 UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
724 UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
725 UBUS_METHOD_NOARG("list_bans", hostapd_bss_list_bans),
726 UBUS_METHOD_NOARG("wps_start", hostapd_bss_wps_start),
727 UBUS_METHOD_NOARG("wps_cancel", hostapd_bss_wps_cancel),
728 UBUS_METHOD_NOARG("update_beacon", hostapd_bss_update_beacon),
729 #ifdef NEED_AP_MLME
730 UBUS_METHOD("switch_chan", hostapd_switch_chan, csa_policy),
731 #endif
732 UBUS_METHOD("set_vendor_elements", hostapd_vendor_elements, ve_policy),
733 UBUS_METHOD("notify_response", hostapd_notify_response, notify_policy),
734 UBUS_METHOD("bss_mgmt_enable", hostapd_bss_mgmt_enable, bss_mgmt_enable_policy),
735 UBUS_METHOD_NOARG("rrm_nr_get_own", hostapd_rrm_nr_get_own),
736 UBUS_METHOD_NOARG("rrm_nr_list", hostapd_rrm_nr_list),
737 UBUS_METHOD("rrm_nr_set", hostapd_rrm_nr_set, nr_set_policy),
738 };
739
740 static struct ubus_object_type bss_object_type =
741 UBUS_OBJECT_TYPE("hostapd_bss", bss_methods);
742
743 static int avl_compare_macaddr(const void *k1, const void *k2, void *ptr)
744 {
745 return memcmp(k1, k2, ETH_ALEN);
746 }
747
748 void hostapd_ubus_add_bss(struct hostapd_data *hapd)
749 {
750 struct ubus_object *obj = &hapd->ubus.obj;
751 char *name;
752 int ret;
753
754 if (!hostapd_ubus_init())
755 return;
756
757 if (asprintf(&name, "hostapd.%s", hapd->conf->iface) < 0)
758 return;
759
760 avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL);
761 obj->name = name;
762 obj->type = &bss_object_type;
763 obj->methods = bss_object_type.methods;
764 obj->n_methods = bss_object_type.n_methods;
765 ret = ubus_add_object(ctx, obj);
766 hostapd_ubus_ref_inc();
767 }
768
769 void hostapd_ubus_free_bss(struct hostapd_data *hapd)
770 {
771 struct ubus_object *obj = &hapd->ubus.obj;
772 char *name = (char *) obj->name;
773
774 if (!ctx)
775 return;
776
777 if (obj->id) {
778 ubus_remove_object(ctx, obj);
779 hostapd_ubus_ref_dec();
780 }
781
782 free(name);
783 }
784
785 struct ubus_event_req {
786 struct ubus_notify_request nreq;
787 int resp;
788 };
789
790 static void
791 ubus_event_cb(struct ubus_notify_request *req, int idx, int ret)
792 {
793 struct ubus_event_req *ureq = container_of(req, struct ubus_event_req, nreq);
794
795 ureq->resp = ret;
796 }
797
798 int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
799 {
800 struct ubus_banned_client *ban;
801 const char *types[HOSTAPD_UBUS_TYPE_MAX] = {
802 [HOSTAPD_UBUS_PROBE_REQ] = "probe",
803 [HOSTAPD_UBUS_AUTH_REQ] = "auth",
804 [HOSTAPD_UBUS_ASSOC_REQ] = "assoc",
805 };
806 const char *type = "mgmt";
807 struct ubus_event_req ureq = {};
808 const u8 *addr;
809
810 if (req->mgmt_frame)
811 addr = req->mgmt_frame->sa;
812 else
813 addr = req->addr;
814
815 ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
816 if (ban)
817 return WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
818
819 if (!hapd->ubus.obj.has_subscribers)
820 return WLAN_STATUS_SUCCESS;
821
822 if (req->type < ARRAY_SIZE(types))
823 type = types[req->type];
824
825 blob_buf_init(&b, 0);
826 blobmsg_add_macaddr(&b, "address", addr);
827 if (req->mgmt_frame)
828 blobmsg_add_macaddr(&b, "target", req->mgmt_frame->da);
829 if (req->frame_info)
830 blobmsg_add_u32(&b, "signal", req->frame_info->ssi_signal);
831 blobmsg_add_u32(&b, "freq", hapd->iface->freq);
832
833 if (!hapd->ubus.notify_response) {
834 ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
835 return WLAN_STATUS_SUCCESS;
836 }
837
838 if (ubus_notify_async(ctx, &hapd->ubus.obj, type, b.head, &ureq.nreq))
839 return WLAN_STATUS_SUCCESS;
840
841 ureq.nreq.status_cb = ubus_event_cb;
842 ubus_complete_request(ctx, &ureq.nreq.req, 100);
843
844 if (ureq.resp)
845 return ureq.resp;
846
847 return WLAN_STATUS_SUCCESS;
848 }
849
850 void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *addr)
851 {
852 if (!hapd->ubus.obj.has_subscribers)
853 return;
854
855 if (!addr)
856 return;
857
858 blob_buf_init(&b, 0);
859 blobmsg_add_macaddr(&b, "address", addr);
860
861 ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
862 }