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