beb4388f7c5af2d89acb1a5cc52b0facaded6029
[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 int i;
172
173 sprintf(mac_buf, MACSTR, MAC2STR(sta->addr));
174 c = blobmsg_open_table(&b, mac_buf);
175 for (i = 0; i < ARRAY_SIZE(sta_flags); i++)
176 blobmsg_add_u8(&b, sta_flags[i].name,
177 !!(sta->flags & sta_flags[i].flag));
178 blobmsg_add_u32(&b, "aid", sta->aid);
179 blobmsg_close_table(&b, c);
180 }
181 blobmsg_close_array(&b, list);
182 ubus_send_reply(ctx, req, b.head);
183
184 return 0;
185 }
186
187 enum {
188 NOTIFY_RESPONSE,
189 __NOTIFY_MAX
190 };
191
192 static const struct blobmsg_policy notify_policy[__NOTIFY_MAX] = {
193 [NOTIFY_RESPONSE] = { "notify_response", BLOBMSG_TYPE_INT32 },
194 };
195
196 static int
197 hostapd_notify_response(struct ubus_context *ctx, struct ubus_object *obj,
198 struct ubus_request_data *req, const char *method,
199 struct blob_attr *msg)
200 {
201 struct blob_attr *tb[__NOTIFY_MAX];
202 struct hostapd_data *hapd = get_hapd_from_object(obj);
203 struct wpabuf *elems;
204 const char *pos;
205 size_t len;
206
207 blobmsg_parse(notify_policy, __NOTIFY_MAX, tb,
208 blob_data(msg), blob_len(msg));
209
210 if (!tb[NOTIFY_RESPONSE])
211 return UBUS_STATUS_INVALID_ARGUMENT;
212
213 hapd->ubus.notify_response = blobmsg_get_u32(tb[NOTIFY_RESPONSE]);
214
215 return UBUS_STATUS_OK;
216 }
217
218 enum {
219 DEL_CLIENT_ADDR,
220 DEL_CLIENT_REASON,
221 DEL_CLIENT_DEAUTH,
222 DEL_CLIENT_BAN_TIME,
223 __DEL_CLIENT_MAX
224 };
225
226 static const struct blobmsg_policy del_policy[__DEL_CLIENT_MAX] = {
227 [DEL_CLIENT_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
228 [DEL_CLIENT_REASON] = { "reason", BLOBMSG_TYPE_INT32 },
229 [DEL_CLIENT_DEAUTH] = { "deauth", BLOBMSG_TYPE_INT8 },
230 [DEL_CLIENT_BAN_TIME] = { "ban_time", BLOBMSG_TYPE_INT32 },
231 };
232
233 static int
234 hostapd_bss_del_client(struct ubus_context *ctx, struct ubus_object *obj,
235 struct ubus_request_data *req, const char *method,
236 struct blob_attr *msg)
237 {
238 struct blob_attr *tb[__DEL_CLIENT_MAX];
239 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
240 struct sta_info *sta;
241 bool deauth = false;
242 int reason;
243 u8 addr[ETH_ALEN];
244
245 blobmsg_parse(del_policy, __DEL_CLIENT_MAX, tb, blob_data(msg), blob_len(msg));
246
247 if (!tb[DEL_CLIENT_ADDR])
248 return UBUS_STATUS_INVALID_ARGUMENT;
249
250 if (hwaddr_aton(blobmsg_data(tb[DEL_CLIENT_ADDR]), addr))
251 return UBUS_STATUS_INVALID_ARGUMENT;
252
253 if (tb[DEL_CLIENT_REASON])
254 reason = blobmsg_get_u32(tb[DEL_CLIENT_REASON]);
255
256 if (tb[DEL_CLIENT_DEAUTH])
257 deauth = blobmsg_get_bool(tb[DEL_CLIENT_DEAUTH]);
258
259 sta = ap_get_sta(hapd, addr);
260 if (sta) {
261 if (deauth) {
262 hostapd_drv_sta_deauth(hapd, addr, reason);
263 ap_sta_deauthenticate(hapd, sta, reason);
264 } else {
265 hostapd_drv_sta_disassoc(hapd, addr, reason);
266 ap_sta_disassociate(hapd, sta, reason);
267 }
268 }
269
270 if (tb[DEL_CLIENT_BAN_TIME])
271 hostapd_bss_ban_client(hapd, addr, blobmsg_get_u32(tb[DEL_CLIENT_BAN_TIME]));
272
273 return 0;
274 }
275
276 static void
277 blobmsg_add_macaddr(struct blob_buf *buf, const char *name, const u8 *addr)
278 {
279 char *s;
280
281 s = blobmsg_alloc_string_buffer(buf, name, 20);
282 sprintf(s, MACSTR, MAC2STR(addr));
283 blobmsg_add_string_buffer(buf);
284 }
285
286 static int
287 hostapd_bss_list_bans(struct ubus_context *ctx, struct ubus_object *obj,
288 struct ubus_request_data *req, const char *method,
289 struct blob_attr *msg)
290 {
291 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
292 struct ubus_banned_client *ban;
293 void *c;
294
295 blob_buf_init(&b, 0);
296 c = blobmsg_open_array(&b, "clients");
297 avl_for_each_element(&hapd->ubus.banned, ban, avl)
298 blobmsg_add_macaddr(&b, NULL, ban->addr);
299 blobmsg_close_array(&b, c);
300 ubus_send_reply(ctx, req, b.head);
301
302 return 0;
303 }
304
305 static int
306 hostapd_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
307 struct ubus_request_data *req, const char *method,
308 struct blob_attr *msg)
309 {
310 int rc;
311 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
312
313 rc = hostapd_wps_button_pushed(hapd, NULL);
314
315 if (rc != 0)
316 return UBUS_STATUS_NOT_SUPPORTED;
317
318 return 0;
319 }
320
321 static int
322 hostapd_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
323 struct ubus_request_data *req, const char *method,
324 struct blob_attr *msg)
325 {
326 int rc;
327 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
328
329 rc = hostapd_wps_cancel(hapd);
330
331 if (rc != 0)
332 return UBUS_STATUS_NOT_SUPPORTED;
333
334 return 0;
335 }
336
337 static int
338 hostapd_bss_update_beacon(struct ubus_context *ctx, struct ubus_object *obj,
339 struct ubus_request_data *req, const char *method,
340 struct blob_attr *msg)
341 {
342 int rc;
343 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
344
345 rc = ieee802_11_set_beacon(hapd);
346
347 if (rc != 0)
348 return UBUS_STATUS_NOT_SUPPORTED;
349
350 return 0;
351 }
352
353 enum {
354 CSA_FREQ,
355 CSA_BCN_COUNT,
356 __CSA_MAX
357 };
358
359 static const struct blobmsg_policy csa_policy[__CSA_MAX] = {
360 /*
361 * for now, frequency and beacon count are enough, add more
362 * parameters on demand
363 */
364 [CSA_FREQ] = { "freq", BLOBMSG_TYPE_INT32 },
365 [CSA_BCN_COUNT] = { "bcn_count", BLOBMSG_TYPE_INT32 },
366 };
367
368 #ifdef NEED_AP_MLME
369 static int
370 hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
371 struct ubus_request_data *req, const char *method,
372 struct blob_attr *msg)
373 {
374 struct blob_attr *tb[__CSA_MAX];
375 struct hostapd_data *hapd = get_hapd_from_object(obj);
376 struct csa_settings css;
377
378 blobmsg_parse(csa_policy, __CSA_MAX, tb, blob_data(msg), blob_len(msg));
379
380 if (!tb[CSA_FREQ])
381 return UBUS_STATUS_INVALID_ARGUMENT;
382
383 memset(&css, 0, sizeof(css));
384 css.freq_params.freq = blobmsg_get_u32(tb[CSA_FREQ]);
385 if (tb[CSA_BCN_COUNT])
386 css.cs_count = blobmsg_get_u32(tb[CSA_BCN_COUNT]);
387
388 if (hostapd_switch_channel(hapd, &css) != 0)
389 return UBUS_STATUS_NOT_SUPPORTED;
390 return UBUS_STATUS_OK;
391 }
392 #endif
393
394 enum {
395 VENDOR_ELEMENTS,
396 __VENDOR_ELEMENTS_MAX
397 };
398
399 static const struct blobmsg_policy ve_policy[__VENDOR_ELEMENTS_MAX] = {
400 /* vendor elements are provided as hex-string */
401 [VENDOR_ELEMENTS] = { "vendor_elements", BLOBMSG_TYPE_STRING },
402 };
403
404 static int
405 hostapd_vendor_elements(struct ubus_context *ctx, struct ubus_object *obj,
406 struct ubus_request_data *req, const char *method,
407 struct blob_attr *msg)
408 {
409 struct blob_attr *tb[__VENDOR_ELEMENTS_MAX];
410 struct hostapd_data *hapd = get_hapd_from_object(obj);
411 struct hostapd_bss_config *bss = hapd->conf;
412 struct wpabuf *elems;
413 const char *pos;
414 size_t len;
415
416 blobmsg_parse(ve_policy, __VENDOR_ELEMENTS_MAX, tb,
417 blob_data(msg), blob_len(msg));
418
419 if (!tb[VENDOR_ELEMENTS])
420 return UBUS_STATUS_INVALID_ARGUMENT;
421
422 pos = blobmsg_data(tb[VENDOR_ELEMENTS]);
423 len = os_strlen(pos);
424 if (len & 0x01)
425 return UBUS_STATUS_INVALID_ARGUMENT;
426
427 len /= 2;
428 if (len == 0) {
429 wpabuf_free(bss->vendor_elements);
430 bss->vendor_elements = NULL;
431 return 0;
432 }
433
434 elems = wpabuf_alloc(len);
435 if (elems == NULL)
436 return 1;
437
438 if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
439 wpabuf_free(elems);
440 return UBUS_STATUS_INVALID_ARGUMENT;
441 }
442
443 wpabuf_free(bss->vendor_elements);
444 bss->vendor_elements = elems;
445
446 /* update beacons if vendor elements were set successfully */
447 if (ieee802_11_update_beacons(hapd->iface) != 0)
448 return UBUS_STATUS_NOT_SUPPORTED;
449 return UBUS_STATUS_OK;
450 }
451
452 static void
453 hostapd_rrm_print_nr(struct hostapd_neighbor_entry *nr)
454 {
455 const u8 *data;
456 char *str;
457 int len;
458
459 blobmsg_printf(&b, "", MACSTR, MAC2STR(nr->bssid));
460
461 str = blobmsg_alloc_string_buffer(&b, "", nr->ssid.ssid_len + 1);
462 memcpy(str, nr->ssid.ssid, nr->ssid.ssid_len);
463 str[nr->ssid.ssid_len] = 0;
464 blobmsg_add_string_buffer(&b);
465
466 len = wpabuf_len(nr->nr);
467 str = blobmsg_alloc_string_buffer(&b, "", 2 * len + 1);
468 wpa_snprintf_hex(str, 2 * len + 1, wpabuf_head_u8(nr->nr), len);
469 blobmsg_add_string_buffer(&b);
470 }
471
472 static int
473 hostapd_rrm_nr_get_own(struct ubus_context *ctx, struct ubus_object *obj,
474 struct ubus_request_data *req, const char *method,
475 struct blob_attr *msg)
476 {
477 struct hostapd_data *hapd = get_hapd_from_object(obj);
478 struct hostapd_neighbor_entry *nr;
479 void *c;
480
481 if (!(hapd->conf->radio_measurements[0] & WLAN_RRM_CAPS_NEIGHBOR_REPORT))
482 return UBUS_STATUS_NOT_SUPPORTED;
483
484 nr = hostapd_neighbor_get(hapd, hapd->own_addr, NULL);
485 if (!nr)
486 return UBUS_STATUS_NOT_FOUND;
487
488 blob_buf_init(&b, 0);
489
490 c = blobmsg_open_array(&b, "value");
491 hostapd_rrm_print_nr(nr);
492 blobmsg_close_array(&b, c);
493
494 ubus_send_reply(ctx, req, b.head);
495
496 return 0;
497 }
498
499 static int
500 hostapd_rrm_nr_list(struct ubus_context *ctx, struct ubus_object *obj,
501 struct ubus_request_data *req, const char *method,
502 struct blob_attr *msg)
503 {
504 struct hostapd_data *hapd = get_hapd_from_object(obj);
505 struct hostapd_neighbor_entry *nr;
506 void *c;
507
508 if (!(hapd->conf->radio_measurements[0] & WLAN_RRM_CAPS_NEIGHBOR_REPORT))
509 return UBUS_STATUS_NOT_SUPPORTED;
510
511 blob_buf_init(&b, 0);
512
513 c = blobmsg_open_array(&b, "list");
514 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
515 void *cur;
516
517 if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
518 continue;
519
520 cur = blobmsg_open_array(&b, NULL);
521 hostapd_rrm_print_nr(nr);
522 blobmsg_close_array(&b, cur);
523 }
524 blobmsg_close_array(&b, c);
525
526 ubus_send_reply(ctx, req, b.head);
527
528 return 0;
529 }
530
531 enum {
532 NR_SET_LIST,
533 __NR_SET_LIST_MAX
534 };
535
536 static const struct blobmsg_policy nr_set_policy[__NR_SET_LIST_MAX] = {
537 [NR_SET_LIST] = { "list", BLOBMSG_TYPE_ARRAY },
538 };
539
540
541 static void
542 hostapd_rrm_nr_clear(struct hostapd_data *hapd)
543 {
544 struct hostapd_neighbor_entry *nr;
545
546 restart:
547 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
548 if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
549 continue;
550
551 hostapd_neighbor_remove(hapd, nr->bssid, &nr->ssid);
552 goto restart;
553 }
554 }
555
556 static int
557 hostapd_rrm_nr_set(struct ubus_context *ctx, struct ubus_object *obj,
558 struct ubus_request_data *req, const char *method,
559 struct blob_attr *msg)
560 {
561 static const struct blobmsg_policy nr_e_policy[] = {
562 { .type = BLOBMSG_TYPE_STRING },
563 { .type = BLOBMSG_TYPE_STRING },
564 { .type = BLOBMSG_TYPE_STRING },
565 };
566 struct hostapd_data *hapd = get_hapd_from_object(obj);
567 struct blob_attr *tb_l[__NR_SET_LIST_MAX];
568 struct blob_attr *tb[ARRAY_SIZE(nr_e_policy)];
569 struct blob_attr *cur;
570 int ret = 0;
571 int rem;
572
573 if (!(hapd->conf->radio_measurements[0] & WLAN_RRM_CAPS_NEIGHBOR_REPORT))
574 return UBUS_STATUS_NOT_SUPPORTED;
575
576 blobmsg_parse(nr_set_policy, __NR_SET_LIST_MAX, tb_l, blob_data(msg), blob_len(msg));
577 if (!tb_l[NR_SET_LIST])
578 return UBUS_STATUS_INVALID_ARGUMENT;
579
580 hostapd_rrm_nr_clear(hapd);
581 blobmsg_for_each_attr(cur, tb_l[NR_SET_LIST], rem) {
582 struct wpa_ssid_value ssid;
583 struct wpabuf *data;
584 u8 bssid[ETH_ALEN];
585 char *s;
586
587 blobmsg_parse_array(nr_e_policy, ARRAY_SIZE(nr_e_policy), tb, blobmsg_data(cur), blobmsg_data_len(cur));
588 if (!tb[0] || !tb[1] || !tb[2])
589 goto invalid;
590
591 s = blobmsg_get_string(tb[0]);
592 if (hwaddr_aton(s, bssid))
593 goto invalid;
594
595 s = blobmsg_get_string(tb[1]);
596 ssid.ssid_len = strlen(s);
597 if (ssid.ssid_len > sizeof(ssid.ssid))
598 goto invalid;
599
600 memcpy(&ssid, s, ssid.ssid_len);
601 data = wpabuf_parse_bin(blobmsg_get_string(tb[2]));
602 if (!data)
603 goto invalid;
604
605 hostapd_neighbor_set(hapd, bssid, &ssid, data, NULL, NULL, 0);
606 wpabuf_free(data);
607 continue;
608
609 invalid:
610 ret = UBUS_STATUS_INVALID_ARGUMENT;
611 }
612
613 return 0;
614 }
615
616 static const struct ubus_method bss_methods[] = {
617 UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
618 UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
619 UBUS_METHOD_NOARG("list_bans", hostapd_bss_list_bans),
620 UBUS_METHOD_NOARG("wps_start", hostapd_bss_wps_start),
621 UBUS_METHOD_NOARG("wps_cancel", hostapd_bss_wps_cancel),
622 UBUS_METHOD_NOARG("update_beacon", hostapd_bss_update_beacon),
623 #ifdef NEED_AP_MLME
624 UBUS_METHOD("switch_chan", hostapd_switch_chan, csa_policy),
625 #endif
626 UBUS_METHOD("set_vendor_elements", hostapd_vendor_elements, ve_policy),
627 UBUS_METHOD("notify_response", hostapd_notify_response, notify_policy),
628 UBUS_METHOD_NOARG("rrm_nr_get_own", hostapd_rrm_nr_get_own),
629 UBUS_METHOD_NOARG("rrm_nr_list", hostapd_rrm_nr_list),
630 UBUS_METHOD("rrm_nr_set", hostapd_rrm_nr_set, nr_set_policy),
631 };
632
633 static struct ubus_object_type bss_object_type =
634 UBUS_OBJECT_TYPE("hostapd_bss", bss_methods);
635
636 static int avl_compare_macaddr(const void *k1, const void *k2, void *ptr)
637 {
638 return memcmp(k1, k2, ETH_ALEN);
639 }
640
641 void hostapd_ubus_add_bss(struct hostapd_data *hapd)
642 {
643 struct ubus_object *obj = &hapd->ubus.obj;
644 char *name;
645 int ret;
646
647 if (!hostapd_ubus_init())
648 return;
649
650 if (asprintf(&name, "hostapd.%s", hapd->conf->iface) < 0)
651 return;
652
653 avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL);
654 obj->name = name;
655 obj->type = &bss_object_type;
656 obj->methods = bss_object_type.methods;
657 obj->n_methods = bss_object_type.n_methods;
658 ret = ubus_add_object(ctx, obj);
659 hostapd_ubus_ref_inc();
660 }
661
662 void hostapd_ubus_free_bss(struct hostapd_data *hapd)
663 {
664 struct ubus_object *obj = &hapd->ubus.obj;
665 char *name = (char *) obj->name;
666
667 if (!ctx)
668 return;
669
670 if (obj->id) {
671 ubus_remove_object(ctx, obj);
672 hostapd_ubus_ref_dec();
673 }
674
675 free(name);
676 }
677
678 struct ubus_event_req {
679 struct ubus_notify_request nreq;
680 bool deny;
681 };
682
683 static void
684 ubus_event_cb(struct ubus_notify_request *req, int idx, int ret)
685 {
686 struct ubus_event_req *ureq = container_of(req, struct ubus_event_req, nreq);
687
688 if (ret)
689 ureq->deny = true;
690 }
691
692 int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
693 {
694 struct ubus_banned_client *ban;
695 const char *types[HOSTAPD_UBUS_TYPE_MAX] = {
696 [HOSTAPD_UBUS_PROBE_REQ] = "probe",
697 [HOSTAPD_UBUS_AUTH_REQ] = "auth",
698 [HOSTAPD_UBUS_ASSOC_REQ] = "assoc",
699 };
700 const char *type = "mgmt";
701 struct ubus_event_req ureq = {};
702 const u8 *addr;
703
704 if (req->mgmt_frame)
705 addr = req->mgmt_frame->sa;
706 else
707 addr = req->addr;
708
709 ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
710 if (ban)
711 return -2;
712
713 if (!hapd->ubus.obj.has_subscribers)
714 return 0;
715
716 if (req->type < ARRAY_SIZE(types))
717 type = types[req->type];
718
719 blob_buf_init(&b, 0);
720 blobmsg_add_macaddr(&b, "address", addr);
721 if (req->mgmt_frame)
722 blobmsg_add_macaddr(&b, "target", req->mgmt_frame->da);
723 if (req->frame_info)
724 blobmsg_add_u32(&b, "signal", req->frame_info->ssi_signal);
725 blobmsg_add_u32(&b, "freq", hapd->iface->freq);
726
727 if (!hapd->ubus.notify_response) {
728 ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
729 return 0;
730 }
731
732 if (ubus_notify_async(ctx, &hapd->ubus.obj, type, b.head, &ureq.nreq))
733 return 0;
734
735 ureq.nreq.status_cb = ubus_event_cb;
736 ubus_complete_request(ctx, &ureq.nreq.req, 100);
737
738 if (ureq.deny)
739 return -1;
740
741 return 0;
742 }
743
744 void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *addr)
745 {
746 if (!hapd->ubus.obj.has_subscribers)
747 return;
748
749 if (!addr)
750 return;
751
752 blob_buf_init(&b, 0);
753 blobmsg_add_macaddr(&b, "address", addr);
754
755 ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
756 }