hostapd: switch to using uloop (integrated with built-in eloop)
[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 "common/hw_features_common.h"
15 #include "hostapd.h"
16 #include "neighbor_db.h"
17 #include "wps_hostapd.h"
18 #include "sta_info.h"
19 #include "ubus.h"
20 #include "ap_drv_ops.h"
21 #include "beacon.h"
22 #include "rrm.h"
23 #include "wnm_ap.h"
24 #include "taxonomy.h"
25 #include "airtime_policy.h"
26 #include "hw_features.h"
27
28 static struct ubus_context *ctx;
29 static struct blob_buf b;
30 static int ctx_ref;
31
32 static inline struct hapd_interfaces *get_hapd_interfaces_from_object(struct ubus_object *obj)
33 {
34 return container_of(obj, struct hapd_interfaces, ubus);
35 }
36
37 static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj)
38 {
39 return container_of(obj, struct hostapd_data, ubus.obj);
40 }
41
42 struct ubus_banned_client {
43 struct avl_node avl;
44 u8 addr[ETH_ALEN];
45 };
46
47 static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
48 {
49 if (ubus_reconnect(ctx, NULL)) {
50 eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
51 return;
52 }
53
54 ubus_add_uloop(ctx);
55 }
56
57 static void hostapd_ubus_connection_lost(struct ubus_context *ctx)
58 {
59 uloop_fd_delete(&ctx->sock);
60 eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
61 }
62
63 static bool hostapd_ubus_init(void)
64 {
65 if (ctx)
66 return true;
67
68 eloop_add_uloop();
69 ctx = ubus_connect(NULL);
70 if (!ctx)
71 return false;
72
73 ctx->connection_lost = hostapd_ubus_connection_lost;
74 ubus_add_uloop(ctx);
75
76 return true;
77 }
78
79 static void hostapd_ubus_ref_inc(void)
80 {
81 ctx_ref++;
82 }
83
84 static void hostapd_ubus_ref_dec(void)
85 {
86 ctx_ref--;
87 if (!ctx)
88 return;
89
90 if (ctx_ref)
91 return;
92
93 uloop_fd_delete(&ctx->sock);
94 ubus_free(ctx);
95 ctx = NULL;
96 }
97
98 void hostapd_ubus_add_iface(struct hostapd_iface *iface)
99 {
100 if (!hostapd_ubus_init())
101 return;
102 }
103
104 void hostapd_ubus_free_iface(struct hostapd_iface *iface)
105 {
106 if (!ctx)
107 return;
108 }
109
110 static void hostapd_notify_ubus(struct ubus_object *obj, char *bssname, char *event)
111 {
112 char *event_type;
113
114 if (!ctx || !obj)
115 return;
116
117 if (asprintf(&event_type, "bss.%s", event) < 0)
118 return;
119
120 blob_buf_init(&b, 0);
121 blobmsg_add_string(&b, "name", bssname);
122 ubus_notify(ctx, obj, event_type, b.head, -1);
123 free(event_type);
124 }
125
126 static void hostapd_send_procd_event(char *bssname, char *event)
127 {
128 char *name, *s;
129 uint32_t id;
130 void *v;
131
132 if (!ctx || ubus_lookup_id(ctx, "service", &id))
133 return;
134
135 if (asprintf(&name, "hostapd.%s.%s", bssname, event) < 0)
136 return;
137
138 blob_buf_init(&b, 0);
139
140 s = blobmsg_alloc_string_buffer(&b, "type", strlen(name) + 1);
141 sprintf(s, "%s", name);
142 blobmsg_add_string_buffer(&b);
143
144 v = blobmsg_open_table(&b, "data");
145 blobmsg_close_table(&b, v);
146
147 ubus_invoke(ctx, id, "event", b.head, NULL, NULL, 1000);
148
149 free(name);
150 }
151
152 static void hostapd_send_shared_event(struct ubus_object *obj, char *bssname, char *event)
153 {
154 hostapd_send_procd_event(bssname, event);
155 hostapd_notify_ubus(obj, bssname, event);
156 }
157
158 static void
159 hostapd_bss_del_ban(void *eloop_data, void *user_ctx)
160 {
161 struct ubus_banned_client *ban = eloop_data;
162 struct hostapd_data *hapd = user_ctx;
163
164 avl_delete(&hapd->ubus.banned, &ban->avl);
165 free(ban);
166 }
167
168 static void
169 hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time)
170 {
171 struct ubus_banned_client *ban;
172
173 if (time < 0)
174 time = 0;
175
176 ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
177 if (!ban) {
178 if (!time)
179 return;
180
181 ban = os_zalloc(sizeof(*ban));
182 memcpy(ban->addr, addr, sizeof(ban->addr));
183 ban->avl.key = ban->addr;
184 avl_insert(&hapd->ubus.banned, &ban->avl);
185 } else {
186 eloop_cancel_timeout(hostapd_bss_del_ban, ban, hapd);
187 if (!time) {
188 hostapd_bss_del_ban(ban, hapd);
189 return;
190 }
191 }
192
193 eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd);
194 }
195
196 static int
197 hostapd_bss_reload(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 hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
202 int ret = hostapd_reload_config(hapd->iface, 1);
203
204 hostapd_send_shared_event(&hapd->iface->interfaces->ubus, hapd->conf->iface, "reload");
205 return ret;
206 }
207
208
209 static void
210 hostapd_parse_vht_map_blobmsg(uint16_t map)
211 {
212 char label[4];
213 int16_t val;
214 int i;
215
216 for (i = 0; i < 8; i++) {
217 snprintf(label, 4, "%dss", i + 1);
218
219 val = (map & (BIT(1) | BIT(0))) + 7;
220 blobmsg_add_u16(&b, label, val == 10 ? -1 : val);
221 map = map >> 2;
222 }
223 }
224
225 static void
226 hostapd_parse_vht_capab_blobmsg(struct ieee80211_vht_capabilities *vhtc)
227 {
228 void *supported_mcs;
229 void *map;
230 int i;
231
232 static const struct {
233 const char *name;
234 uint32_t flag;
235 } vht_capas[] = {
236 { "su_beamformee", VHT_CAP_SU_BEAMFORMEE_CAPABLE },
237 { "mu_beamformee", VHT_CAP_MU_BEAMFORMEE_CAPABLE },
238 };
239
240 for (i = 0; i < ARRAY_SIZE(vht_capas); i++)
241 blobmsg_add_u8(&b, vht_capas[i].name,
242 !!(vhtc->vht_capabilities_info & vht_capas[i].flag));
243
244 supported_mcs = blobmsg_open_table(&b, "mcs_map");
245
246 /* RX map */
247 map = blobmsg_open_table(&b, "rx");
248 hostapd_parse_vht_map_blobmsg(le_to_host16(vhtc->vht_supported_mcs_set.rx_map));
249 blobmsg_close_table(&b, map);
250
251 /* TX map */
252 map = blobmsg_open_table(&b, "tx");
253 hostapd_parse_vht_map_blobmsg(le_to_host16(vhtc->vht_supported_mcs_set.tx_map));
254 blobmsg_close_table(&b, map);
255
256 blobmsg_close_table(&b, supported_mcs);
257 }
258
259 static void
260 hostapd_parse_capab_blobmsg(struct sta_info *sta)
261 {
262 void *r, *v;
263
264 v = blobmsg_open_table(&b, "capabilities");
265
266 if (sta->vht_capabilities) {
267 r = blobmsg_open_table(&b, "vht");
268 hostapd_parse_vht_capab_blobmsg(sta->vht_capabilities);
269 blobmsg_close_table(&b, r);
270 }
271
272 /* ToDo: Add HT / HE capability parsing */
273
274 blobmsg_close_table(&b, v);
275 }
276
277 static int
278 hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
279 struct ubus_request_data *req, const char *method,
280 struct blob_attr *msg)
281 {
282 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
283 struct hostap_sta_driver_data sta_driver_data;
284 struct sta_info *sta;
285 void *list, *c;
286 char mac_buf[20];
287 static const struct {
288 const char *name;
289 uint32_t flag;
290 } sta_flags[] = {
291 { "auth", WLAN_STA_AUTH },
292 { "assoc", WLAN_STA_ASSOC },
293 { "authorized", WLAN_STA_AUTHORIZED },
294 { "preauth", WLAN_STA_PREAUTH },
295 { "wds", WLAN_STA_WDS },
296 { "wmm", WLAN_STA_WMM },
297 { "ht", WLAN_STA_HT },
298 { "vht", WLAN_STA_VHT },
299 { "he", WLAN_STA_HE },
300 { "wps", WLAN_STA_WPS },
301 { "mfp", WLAN_STA_MFP },
302 };
303
304 blob_buf_init(&b, 0);
305 blobmsg_add_u32(&b, "freq", hapd->iface->freq);
306 list = blobmsg_open_table(&b, "clients");
307 for (sta = hapd->sta_list; sta; sta = sta->next) {
308 void *r;
309 int i;
310
311 sprintf(mac_buf, MACSTR, MAC2STR(sta->addr));
312 c = blobmsg_open_table(&b, mac_buf);
313 for (i = 0; i < ARRAY_SIZE(sta_flags); i++)
314 blobmsg_add_u8(&b, sta_flags[i].name,
315 !!(sta->flags & sta_flags[i].flag));
316
317 #ifdef CONFIG_MBO
318 blobmsg_add_u8(&b, "mbo", !!(sta->cell_capa));
319 #endif
320
321 r = blobmsg_open_array(&b, "rrm");
322 for (i = 0; i < ARRAY_SIZE(sta->rrm_enabled_capa); i++)
323 blobmsg_add_u32(&b, "", sta->rrm_enabled_capa[i]);
324 blobmsg_close_array(&b, r);
325
326 r = blobmsg_open_array(&b, "extended_capabilities");
327 /* Check if client advertises extended capabilities */
328 if (sta->ext_capability && sta->ext_capability[0] > 0) {
329 for (i = 0; i < sta->ext_capability[0]; i++) {
330 blobmsg_add_u32(&b, "", sta->ext_capability[1 + i]);
331 }
332 }
333 blobmsg_close_array(&b, r);
334
335 blobmsg_add_u32(&b, "aid", sta->aid);
336 #ifdef CONFIG_TAXONOMY
337 r = blobmsg_alloc_string_buffer(&b, "signature", 1024);
338 if (retrieve_sta_taxonomy(hapd, sta, r, 1024) > 0)
339 blobmsg_add_string_buffer(&b);
340 #endif
341
342 /* Driver information */
343 if (hostapd_drv_read_sta_data(hapd, &sta_driver_data, sta->addr) >= 0) {
344 r = blobmsg_open_table(&b, "bytes");
345 blobmsg_add_u64(&b, "rx", sta_driver_data.rx_bytes);
346 blobmsg_add_u64(&b, "tx", sta_driver_data.tx_bytes);
347 blobmsg_close_table(&b, r);
348 r = blobmsg_open_table(&b, "airtime");
349 blobmsg_add_u64(&b, "rx", sta_driver_data.rx_airtime);
350 blobmsg_add_u64(&b, "tx", sta_driver_data.tx_airtime);
351 blobmsg_close_table(&b, r);
352 r = blobmsg_open_table(&b, "packets");
353 blobmsg_add_u32(&b, "rx", sta_driver_data.rx_packets);
354 blobmsg_add_u32(&b, "tx", sta_driver_data.tx_packets);
355 blobmsg_close_table(&b, r);
356 r = blobmsg_open_table(&b, "rate");
357 /* Rate in kbits */
358 blobmsg_add_u32(&b, "rx", sta_driver_data.current_rx_rate * 100);
359 blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100);
360 blobmsg_close_table(&b, r);
361 blobmsg_add_u32(&b, "signal", sta_driver_data.signal);
362 }
363
364 hostapd_parse_capab_blobmsg(sta);
365
366 blobmsg_close_table(&b, c);
367 }
368 blobmsg_close_array(&b, list);
369 ubus_send_reply(ctx, req, b.head);
370
371 return 0;
372 }
373
374 static int
375 hostapd_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
376 struct ubus_request_data *req, const char *method,
377 struct blob_attr *msg)
378 {
379 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
380
381 blob_buf_init(&b, 0);
382 blobmsg_add_u8(&b, "ht_supported", ht_supported(hapd->iface->hw_features));
383 blobmsg_add_u8(&b, "vht_supported", vht_supported(hapd->iface->hw_features));
384 ubus_send_reply(ctx, req, b.head);
385
386 return 0;
387 }
388
389 static int
390 hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
391 struct ubus_request_data *req, const char *method,
392 struct blob_attr *msg)
393 {
394 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
395 void *airtime_table, *dfs_table, *rrm_table, *wnm_table;
396 struct os_reltime now;
397 char ssid[SSID_MAX_LEN + 1];
398 char phy_name[17];
399 size_t ssid_len = SSID_MAX_LEN;
400 u8 channel = 0, op_class = 0;
401
402 if (hapd->conf->ssid.ssid_len < SSID_MAX_LEN)
403 ssid_len = hapd->conf->ssid.ssid_len;
404
405 ieee80211_freq_to_channel_ext(hapd->iface->freq,
406 hapd->iconf->secondary_channel,
407 hostapd_get_oper_chwidth(hapd->iconf),
408 &op_class, &channel);
409
410 blob_buf_init(&b, 0);
411 blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state));
412 blobmsg_printf(&b, "bssid", MACSTR, MAC2STR(hapd->conf->bssid));
413
414 memset(ssid, 0, SSID_MAX_LEN + 1);
415 memcpy(ssid, hapd->conf->ssid.ssid, ssid_len);
416 blobmsg_add_string(&b, "ssid", ssid);
417
418 blobmsg_add_u32(&b, "freq", hapd->iface->freq);
419 blobmsg_add_u32(&b, "channel", channel);
420 blobmsg_add_u32(&b, "op_class", op_class);
421 blobmsg_add_u32(&b, "beacon_interval", hapd->iconf->beacon_int);
422 #ifdef CONFIG_IEEE80211AX
423 blobmsg_add_u32(&b, "bss_color", hapd->iface->conf->he_op.he_bss_color_disabled ? -1 :
424 hapd->iface->conf->he_op.he_bss_color);
425 #else
426 blobmsg_add_u32(&b, "bss_color", -1);
427 #endif
428
429 snprintf(phy_name, 17, "%s", hapd->iface->phy);
430 blobmsg_add_string(&b, "phy", phy_name);
431
432 /* RRM */
433 rrm_table = blobmsg_open_table(&b, "rrm");
434 blobmsg_add_u64(&b, "neighbor_report_tx", hapd->openwrt_stats.rrm.neighbor_report_tx);
435 blobmsg_close_table(&b, rrm_table);
436
437 /* WNM */
438 wnm_table = blobmsg_open_table(&b, "wnm");
439 blobmsg_add_u64(&b, "bss_transition_query_rx", hapd->openwrt_stats.wnm.bss_transition_query_rx);
440 blobmsg_add_u64(&b, "bss_transition_request_tx", hapd->openwrt_stats.wnm.bss_transition_request_tx);
441 blobmsg_add_u64(&b, "bss_transition_response_rx", hapd->openwrt_stats.wnm.bss_transition_response_rx);
442 blobmsg_close_table(&b, wnm_table);
443
444 /* Airtime */
445 airtime_table = blobmsg_open_table(&b, "airtime");
446 blobmsg_add_u64(&b, "time", hapd->iface->last_channel_time);
447 blobmsg_add_u64(&b, "time_busy", hapd->iface->last_channel_time_busy);
448 blobmsg_add_u16(&b, "utilization", hapd->iface->channel_utilization);
449 blobmsg_close_table(&b, airtime_table);
450
451 /* DFS */
452 dfs_table = blobmsg_open_table(&b, "dfs");
453 blobmsg_add_u32(&b, "cac_seconds", hapd->iface->dfs_cac_ms / 1000);
454 blobmsg_add_u8(&b, "cac_active", !!(hapd->iface->cac_started));
455 os_reltime_age(&hapd->iface->dfs_cac_start, &now);
456 blobmsg_add_u32(&b, "cac_seconds_left",
457 hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0);
458 blobmsg_close_table(&b, dfs_table);
459
460 ubus_send_reply(ctx, req, b.head);
461
462 return 0;
463 }
464
465 enum {
466 NOTIFY_RESPONSE,
467 __NOTIFY_MAX
468 };
469
470 static const struct blobmsg_policy notify_policy[__NOTIFY_MAX] = {
471 [NOTIFY_RESPONSE] = { "notify_response", BLOBMSG_TYPE_INT32 },
472 };
473
474 static int
475 hostapd_notify_response(struct ubus_context *ctx, struct ubus_object *obj,
476 struct ubus_request_data *req, const char *method,
477 struct blob_attr *msg)
478 {
479 struct blob_attr *tb[__NOTIFY_MAX];
480 struct hostapd_data *hapd = get_hapd_from_object(obj);
481 struct wpabuf *elems;
482 const char *pos;
483 size_t len;
484
485 blobmsg_parse(notify_policy, __NOTIFY_MAX, tb,
486 blob_data(msg), blob_len(msg));
487
488 if (!tb[NOTIFY_RESPONSE])
489 return UBUS_STATUS_INVALID_ARGUMENT;
490
491 hapd->ubus.notify_response = blobmsg_get_u32(tb[NOTIFY_RESPONSE]);
492
493 return UBUS_STATUS_OK;
494 }
495
496 enum {
497 DEL_CLIENT_ADDR,
498 DEL_CLIENT_REASON,
499 DEL_CLIENT_DEAUTH,
500 DEL_CLIENT_BAN_TIME,
501 __DEL_CLIENT_MAX
502 };
503
504 static const struct blobmsg_policy del_policy[__DEL_CLIENT_MAX] = {
505 [DEL_CLIENT_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
506 [DEL_CLIENT_REASON] = { "reason", BLOBMSG_TYPE_INT32 },
507 [DEL_CLIENT_DEAUTH] = { "deauth", BLOBMSG_TYPE_INT8 },
508 [DEL_CLIENT_BAN_TIME] = { "ban_time", BLOBMSG_TYPE_INT32 },
509 };
510
511 static int
512 hostapd_bss_del_client(struct ubus_context *ctx, struct ubus_object *obj,
513 struct ubus_request_data *req, const char *method,
514 struct blob_attr *msg)
515 {
516 struct blob_attr *tb[__DEL_CLIENT_MAX];
517 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
518 struct sta_info *sta;
519 bool deauth = false;
520 int reason;
521 u8 addr[ETH_ALEN];
522
523 blobmsg_parse(del_policy, __DEL_CLIENT_MAX, tb, blob_data(msg), blob_len(msg));
524
525 if (!tb[DEL_CLIENT_ADDR])
526 return UBUS_STATUS_INVALID_ARGUMENT;
527
528 if (hwaddr_aton(blobmsg_data(tb[DEL_CLIENT_ADDR]), addr))
529 return UBUS_STATUS_INVALID_ARGUMENT;
530
531 if (tb[DEL_CLIENT_REASON])
532 reason = blobmsg_get_u32(tb[DEL_CLIENT_REASON]);
533
534 if (tb[DEL_CLIENT_DEAUTH])
535 deauth = blobmsg_get_bool(tb[DEL_CLIENT_DEAUTH]);
536
537 sta = ap_get_sta(hapd, addr);
538 if (sta) {
539 if (deauth) {
540 hostapd_drv_sta_deauth(hapd, addr, reason);
541 ap_sta_deauthenticate(hapd, sta, reason);
542 } else {
543 hostapd_drv_sta_disassoc(hapd, addr, reason);
544 ap_sta_disassociate(hapd, sta, reason);
545 }
546 }
547
548 if (tb[DEL_CLIENT_BAN_TIME])
549 hostapd_bss_ban_client(hapd, addr, blobmsg_get_u32(tb[DEL_CLIENT_BAN_TIME]));
550
551 return 0;
552 }
553
554 static void
555 blobmsg_add_macaddr(struct blob_buf *buf, const char *name, const u8 *addr)
556 {
557 char *s;
558
559 s = blobmsg_alloc_string_buffer(buf, name, 20);
560 sprintf(s, MACSTR, MAC2STR(addr));
561 blobmsg_add_string_buffer(buf);
562 }
563
564 static int
565 hostapd_bss_list_bans(struct ubus_context *ctx, struct ubus_object *obj,
566 struct ubus_request_data *req, const char *method,
567 struct blob_attr *msg)
568 {
569 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
570 struct ubus_banned_client *ban;
571 void *c;
572
573 blob_buf_init(&b, 0);
574 c = blobmsg_open_array(&b, "clients");
575 avl_for_each_element(&hapd->ubus.banned, ban, avl)
576 blobmsg_add_macaddr(&b, NULL, ban->addr);
577 blobmsg_close_array(&b, c);
578 ubus_send_reply(ctx, req, b.head);
579
580 return 0;
581 }
582
583 #ifdef CONFIG_WPS
584 static int
585 hostapd_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
586 struct ubus_request_data *req, const char *method,
587 struct blob_attr *msg)
588 {
589 int rc;
590 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
591
592 rc = hostapd_wps_button_pushed(hapd, NULL);
593
594 if (rc != 0)
595 return UBUS_STATUS_NOT_SUPPORTED;
596
597 return 0;
598 }
599
600
601 static const char * pbc_status_enum_str(enum pbc_status status)
602 {
603 switch (status) {
604 case WPS_PBC_STATUS_DISABLE:
605 return "Disabled";
606 case WPS_PBC_STATUS_ACTIVE:
607 return "Active";
608 case WPS_PBC_STATUS_TIMEOUT:
609 return "Timed-out";
610 case WPS_PBC_STATUS_OVERLAP:
611 return "Overlap";
612 default:
613 return "Unknown";
614 }
615 }
616
617 static int
618 hostapd_bss_wps_status(struct ubus_context *ctx, struct ubus_object *obj,
619 struct ubus_request_data *req, const char *method,
620 struct blob_attr *msg)
621 {
622 int rc;
623 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
624
625 blob_buf_init(&b, 0);
626
627 blobmsg_add_string(&b, "pbc_status", pbc_status_enum_str(hapd->wps_stats.pbc_status));
628 blobmsg_add_string(&b, "last_wps_result",
629 (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
630 "Success":
631 (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
632 "Failed" : "None")));
633
634 /* If status == Failure - Add possible Reasons */
635 if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
636 hapd->wps_stats.failure_reason > 0)
637 blobmsg_add_string(&b, "reason", wps_ei_str(hapd->wps_stats.failure_reason));
638
639 if (hapd->wps_stats.status)
640 blobmsg_printf(&b, "peer_address", MACSTR, MAC2STR(hapd->wps_stats.peer_addr));
641
642 ubus_send_reply(ctx, req, b.head);
643
644 return 0;
645 }
646
647 static int
648 hostapd_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
649 struct ubus_request_data *req, const char *method,
650 struct blob_attr *msg)
651 {
652 int rc;
653 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
654
655 rc = hostapd_wps_cancel(hapd);
656
657 if (rc != 0)
658 return UBUS_STATUS_NOT_SUPPORTED;
659
660 return 0;
661 }
662 #endif /* CONFIG_WPS */
663
664 static int
665 hostapd_bss_update_beacon(struct ubus_context *ctx, struct ubus_object *obj,
666 struct ubus_request_data *req, const char *method,
667 struct blob_attr *msg)
668 {
669 int rc;
670 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
671
672 rc = ieee802_11_set_beacon(hapd);
673
674 if (rc != 0)
675 return UBUS_STATUS_NOT_SUPPORTED;
676
677 return 0;
678 }
679
680 enum {
681 CONFIG_IFACE,
682 CONFIG_FILE,
683 __CONFIG_MAX
684 };
685
686 static const struct blobmsg_policy config_add_policy[__CONFIG_MAX] = {
687 [CONFIG_IFACE] = { "iface", BLOBMSG_TYPE_STRING },
688 [CONFIG_FILE] = { "config", BLOBMSG_TYPE_STRING },
689 };
690
691 static int
692 hostapd_config_add(struct ubus_context *ctx, struct ubus_object *obj,
693 struct ubus_request_data *req, const char *method,
694 struct blob_attr *msg)
695 {
696 struct blob_attr *tb[__CONFIG_MAX];
697 struct hapd_interfaces *interfaces = get_hapd_interfaces_from_object(obj);
698 char buf[128];
699
700 blobmsg_parse(config_add_policy, __CONFIG_MAX, tb, blob_data(msg), blob_len(msg));
701
702 if (!tb[CONFIG_FILE] || !tb[CONFIG_IFACE])
703 return UBUS_STATUS_INVALID_ARGUMENT;
704
705 snprintf(buf, sizeof(buf), "bss_config=%s:%s",
706 blobmsg_get_string(tb[CONFIG_IFACE]),
707 blobmsg_get_string(tb[CONFIG_FILE]));
708
709 if (hostapd_add_iface(interfaces, buf))
710 return UBUS_STATUS_INVALID_ARGUMENT;
711
712 blob_buf_init(&b, 0);
713 blobmsg_add_u32(&b, "pid", getpid());
714 ubus_send_reply(ctx, req, b.head);
715
716 return UBUS_STATUS_OK;
717 }
718
719 enum {
720 CONFIG_REM_IFACE,
721 __CONFIG_REM_MAX
722 };
723
724 static const struct blobmsg_policy config_remove_policy[__CONFIG_REM_MAX] = {
725 [CONFIG_REM_IFACE] = { "iface", BLOBMSG_TYPE_STRING },
726 };
727
728 static int
729 hostapd_config_remove(struct ubus_context *ctx, struct ubus_object *obj,
730 struct ubus_request_data *req, const char *method,
731 struct blob_attr *msg)
732 {
733 struct blob_attr *tb[__CONFIG_REM_MAX];
734 struct hapd_interfaces *interfaces = get_hapd_interfaces_from_object(obj);
735 char buf[128];
736
737 blobmsg_parse(config_remove_policy, __CONFIG_REM_MAX, tb, blob_data(msg), blob_len(msg));
738
739 if (!tb[CONFIG_REM_IFACE])
740 return UBUS_STATUS_INVALID_ARGUMENT;
741
742 if (hostapd_remove_iface(interfaces, blobmsg_get_string(tb[CONFIG_REM_IFACE])))
743 return UBUS_STATUS_INVALID_ARGUMENT;
744
745 return UBUS_STATUS_OK;
746 }
747
748 enum {
749 CSA_FREQ,
750 CSA_BCN_COUNT,
751 CSA_CENTER_FREQ1,
752 CSA_CENTER_FREQ2,
753 CSA_BANDWIDTH,
754 CSA_SEC_CHANNEL_OFFSET,
755 CSA_HT,
756 CSA_VHT,
757 CSA_HE,
758 CSA_BLOCK_TX,
759 CSA_FORCE,
760 __CSA_MAX
761 };
762
763 static const struct blobmsg_policy csa_policy[__CSA_MAX] = {
764 [CSA_FREQ] = { "freq", BLOBMSG_TYPE_INT32 },
765 [CSA_BCN_COUNT] = { "bcn_count", BLOBMSG_TYPE_INT32 },
766 [CSA_CENTER_FREQ1] = { "center_freq1", BLOBMSG_TYPE_INT32 },
767 [CSA_CENTER_FREQ2] = { "center_freq2", BLOBMSG_TYPE_INT32 },
768 [CSA_BANDWIDTH] = { "bandwidth", BLOBMSG_TYPE_INT32 },
769 [CSA_SEC_CHANNEL_OFFSET] = { "sec_channel_offset", BLOBMSG_TYPE_INT32 },
770 [CSA_HT] = { "ht", BLOBMSG_TYPE_BOOL },
771 [CSA_VHT] = { "vht", BLOBMSG_TYPE_BOOL },
772 [CSA_HE] = { "he", BLOBMSG_TYPE_BOOL },
773 [CSA_BLOCK_TX] = { "block_tx", BLOBMSG_TYPE_BOOL },
774 [CSA_FORCE] = { "force", BLOBMSG_TYPE_BOOL },
775 };
776
777
778 static void switch_chan_fallback_cb(void *eloop_data, void *user_ctx)
779 {
780 struct hostapd_iface *iface = eloop_data;
781 struct hostapd_freq_params *freq_params = user_ctx;
782
783 hostapd_switch_channel_fallback(iface, freq_params);
784 }
785
786 #ifdef NEED_AP_MLME
787 static int
788 hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
789 struct ubus_request_data *req, const char *method,
790 struct blob_attr *msg)
791 {
792 struct blob_attr *tb[__CSA_MAX];
793 struct hostapd_data *hapd = get_hapd_from_object(obj);
794 struct hostapd_config *iconf = hapd->iface->conf;
795 struct hostapd_freq_params *freq_params;
796 struct hostapd_hw_modes *mode = hapd->iface->current_mode;
797 struct csa_settings css = {
798 .freq_params = {
799 .ht_enabled = iconf->ieee80211n,
800 .vht_enabled = iconf->ieee80211ac,
801 .he_enabled = iconf->ieee80211ax,
802 .sec_channel_offset = iconf->secondary_channel,
803 }
804 };
805 u8 chwidth = hostapd_get_oper_chwidth(iconf);
806 u8 seg0 = 0, seg1 = 0;
807 int ret = UBUS_STATUS_OK;
808 int i;
809
810 blobmsg_parse(csa_policy, __CSA_MAX, tb, blob_data(msg), blob_len(msg));
811
812 if (!tb[CSA_FREQ])
813 return UBUS_STATUS_INVALID_ARGUMENT;
814
815 switch (iconf->vht_oper_chwidth) {
816 case CHANWIDTH_USE_HT:
817 if (iconf->secondary_channel)
818 css.freq_params.bandwidth = 40;
819 else
820 css.freq_params.bandwidth = 20;
821 break;
822 case CHANWIDTH_160MHZ:
823 css.freq_params.bandwidth = 160;
824 break;
825 default:
826 css.freq_params.bandwidth = 80;
827 break;
828 }
829
830 css.freq_params.freq = blobmsg_get_u32(tb[CSA_FREQ]);
831
832 #define SET_CSA_SETTING(name, field, type) \
833 do { \
834 if (tb[name]) \
835 css.field = blobmsg_get_ ## type(tb[name]); \
836 } while(0)
837
838 SET_CSA_SETTING(CSA_BCN_COUNT, cs_count, u32);
839 SET_CSA_SETTING(CSA_CENTER_FREQ1, freq_params.center_freq1, u32);
840 SET_CSA_SETTING(CSA_CENTER_FREQ2, freq_params.center_freq2, u32);
841 SET_CSA_SETTING(CSA_BANDWIDTH, freq_params.bandwidth, u32);
842 SET_CSA_SETTING(CSA_SEC_CHANNEL_OFFSET, freq_params.sec_channel_offset, u32);
843 SET_CSA_SETTING(CSA_HT, freq_params.ht_enabled, bool);
844 SET_CSA_SETTING(CSA_VHT, freq_params.vht_enabled, bool);
845 SET_CSA_SETTING(CSA_HE, freq_params.he_enabled, bool);
846 SET_CSA_SETTING(CSA_BLOCK_TX, block_tx, bool);
847
848 css.freq_params.channel = hostapd_hw_get_channel(hapd, css.freq_params.freq);
849 if (!css.freq_params.channel)
850 return UBUS_STATUS_NOT_SUPPORTED;
851
852 switch (css.freq_params.bandwidth) {
853 case 160:
854 chwidth = CHANWIDTH_160MHZ;
855 break;
856 case 80:
857 chwidth = css.freq_params.center_freq2 ? CHANWIDTH_80P80MHZ : CHANWIDTH_80MHZ;
858 break;
859 default:
860 chwidth = CHANWIDTH_USE_HT;
861 break;
862 }
863
864 hostapd_set_freq_params(&css.freq_params, iconf->hw_mode,
865 css.freq_params.freq,
866 css.freq_params.channel, iconf->enable_edmg,
867 iconf->edmg_channel,
868 css.freq_params.ht_enabled,
869 css.freq_params.vht_enabled,
870 css.freq_params.he_enabled,
871 css.freq_params.eht_enabled,
872 css.freq_params.sec_channel_offset,
873 chwidth, seg0, seg1,
874 iconf->vht_capab,
875 mode ? &mode->he_capab[IEEE80211_MODE_AP] :
876 NULL,
877 mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
878 NULL);
879
880 for (i = 0; i < hapd->iface->num_bss; i++) {
881 struct hostapd_data *bss = hapd->iface->bss[i];
882
883 if (hostapd_switch_channel(bss, &css) != 0)
884 ret = UBUS_STATUS_NOT_SUPPORTED;
885 }
886
887 if (!ret || !tb[CSA_FORCE] || !blobmsg_get_bool(tb[CSA_FORCE]))
888 return ret;
889
890 freq_params = malloc(sizeof(*freq_params));
891 memcpy(freq_params, &css.freq_params, sizeof(*freq_params));
892 eloop_register_timeout(0, 1, switch_chan_fallback_cb,
893 hapd->iface, freq_params);
894
895 return 0;
896 #undef SET_CSA_SETTING
897 }
898 #endif
899
900 enum {
901 VENDOR_ELEMENTS,
902 __VENDOR_ELEMENTS_MAX
903 };
904
905 static const struct blobmsg_policy ve_policy[__VENDOR_ELEMENTS_MAX] = {
906 /* vendor elements are provided as hex-string */
907 [VENDOR_ELEMENTS] = { "vendor_elements", BLOBMSG_TYPE_STRING },
908 };
909
910 static int
911 hostapd_vendor_elements(struct ubus_context *ctx, struct ubus_object *obj,
912 struct ubus_request_data *req, const char *method,
913 struct blob_attr *msg)
914 {
915 struct blob_attr *tb[__VENDOR_ELEMENTS_MAX];
916 struct hostapd_data *hapd = get_hapd_from_object(obj);
917 struct hostapd_bss_config *bss = hapd->conf;
918 struct wpabuf *elems;
919 const char *pos;
920 size_t len;
921
922 blobmsg_parse(ve_policy, __VENDOR_ELEMENTS_MAX, tb,
923 blob_data(msg), blob_len(msg));
924
925 if (!tb[VENDOR_ELEMENTS])
926 return UBUS_STATUS_INVALID_ARGUMENT;
927
928 pos = blobmsg_data(tb[VENDOR_ELEMENTS]);
929 len = os_strlen(pos);
930 if (len & 0x01)
931 return UBUS_STATUS_INVALID_ARGUMENT;
932
933 len /= 2;
934 if (len == 0) {
935 wpabuf_free(bss->vendor_elements);
936 bss->vendor_elements = NULL;
937 return 0;
938 }
939
940 elems = wpabuf_alloc(len);
941 if (elems == NULL)
942 return 1;
943
944 if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
945 wpabuf_free(elems);
946 return UBUS_STATUS_INVALID_ARGUMENT;
947 }
948
949 wpabuf_free(bss->vendor_elements);
950 bss->vendor_elements = elems;
951
952 /* update beacons if vendor elements were set successfully */
953 if (ieee802_11_update_beacons(hapd->iface) != 0)
954 return UBUS_STATUS_NOT_SUPPORTED;
955 return UBUS_STATUS_OK;
956 }
957
958 static void
959 hostapd_rrm_print_nr(struct hostapd_neighbor_entry *nr)
960 {
961 const u8 *data;
962 char *str;
963 int len;
964
965 blobmsg_printf(&b, "", MACSTR, MAC2STR(nr->bssid));
966
967 str = blobmsg_alloc_string_buffer(&b, "", nr->ssid.ssid_len + 1);
968 memcpy(str, nr->ssid.ssid, nr->ssid.ssid_len);
969 str[nr->ssid.ssid_len] = 0;
970 blobmsg_add_string_buffer(&b);
971
972 len = wpabuf_len(nr->nr);
973 str = blobmsg_alloc_string_buffer(&b, "", 2 * len + 1);
974 wpa_snprintf_hex(str, 2 * len + 1, wpabuf_head_u8(nr->nr), len);
975 blobmsg_add_string_buffer(&b);
976 }
977
978 enum {
979 BSS_MGMT_EN_NEIGHBOR,
980 BSS_MGMT_EN_BEACON,
981 BSS_MGMT_EN_LINK_MEASUREMENT,
982 #ifdef CONFIG_WNM_AP
983 BSS_MGMT_EN_BSS_TRANSITION,
984 #endif
985 __BSS_MGMT_EN_MAX
986 };
987
988 static bool
989 __hostapd_bss_mgmt_enable_f(struct hostapd_data *hapd, int flag)
990 {
991 struct hostapd_bss_config *bss = hapd->conf;
992 uint32_t flags;
993
994 switch (flag) {
995 case BSS_MGMT_EN_NEIGHBOR:
996 if (bss->radio_measurements[0] &
997 WLAN_RRM_CAPS_NEIGHBOR_REPORT)
998 return false;
999
1000 bss->radio_measurements[0] |=
1001 WLAN_RRM_CAPS_NEIGHBOR_REPORT;
1002 hostapd_neighbor_set_own_report(hapd);
1003 return true;
1004 case BSS_MGMT_EN_BEACON:
1005 flags = WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
1006 WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
1007 WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
1008
1009 if (bss->radio_measurements[0] & flags == flags)
1010 return false;
1011
1012 bss->radio_measurements[0] |= (u8) flags;
1013 return true;
1014 case BSS_MGMT_EN_LINK_MEASUREMENT:
1015 flags = WLAN_RRM_CAPS_LINK_MEASUREMENT;
1016
1017 if (bss->radio_measurements[0] & flags == flags)
1018 return false;
1019
1020 bss->radio_measurements[0] |= (u8) flags;
1021 return true;
1022 #ifdef CONFIG_WNM_AP
1023 case BSS_MGMT_EN_BSS_TRANSITION:
1024 if (bss->bss_transition)
1025 return false;
1026
1027 bss->bss_transition = 1;
1028 return true;
1029 #endif
1030 }
1031 }
1032
1033 static void
1034 __hostapd_bss_mgmt_enable(struct hostapd_data *hapd, uint32_t flags)
1035 {
1036 bool update = false;
1037 int i;
1038
1039 for (i = 0; i < __BSS_MGMT_EN_MAX; i++) {
1040 if (!(flags & (1 << i)))
1041 continue;
1042
1043 update |= __hostapd_bss_mgmt_enable_f(hapd, i);
1044 }
1045
1046 if (update)
1047 ieee802_11_update_beacons(hapd->iface);
1048 }
1049
1050
1051 static const struct blobmsg_policy bss_mgmt_enable_policy[__BSS_MGMT_EN_MAX] = {
1052 [BSS_MGMT_EN_NEIGHBOR] = { "neighbor_report", BLOBMSG_TYPE_BOOL },
1053 [BSS_MGMT_EN_BEACON] = { "beacon_report", BLOBMSG_TYPE_BOOL },
1054 [BSS_MGMT_EN_LINK_MEASUREMENT] = { "link_measurement", BLOBMSG_TYPE_BOOL },
1055 #ifdef CONFIG_WNM_AP
1056 [BSS_MGMT_EN_BSS_TRANSITION] = { "bss_transition", BLOBMSG_TYPE_BOOL },
1057 #endif
1058 };
1059
1060 static int
1061 hostapd_bss_mgmt_enable(struct ubus_context *ctx, struct ubus_object *obj,
1062 struct ubus_request_data *req, const char *method,
1063 struct blob_attr *msg)
1064
1065 {
1066 struct hostapd_data *hapd = get_hapd_from_object(obj);
1067 struct blob_attr *tb[__BSS_MGMT_EN_MAX];
1068 struct blob_attr *cur;
1069 uint32_t flags = 0;
1070 int i;
1071 bool neigh = false, beacon = false;
1072
1073 blobmsg_parse(bss_mgmt_enable_policy, __BSS_MGMT_EN_MAX, tb, blob_data(msg), blob_len(msg));
1074
1075 for (i = 0; i < ARRAY_SIZE(tb); i++) {
1076 if (!tb[i] || !blobmsg_get_bool(tb[i]))
1077 continue;
1078
1079 flags |= (1 << i);
1080 }
1081
1082 __hostapd_bss_mgmt_enable(hapd, flags);
1083
1084 return 0;
1085 }
1086
1087
1088 static void
1089 hostapd_rrm_nr_enable(struct hostapd_data *hapd)
1090 {
1091 __hostapd_bss_mgmt_enable(hapd, 1 << BSS_MGMT_EN_NEIGHBOR);
1092 }
1093
1094 static int
1095 hostapd_rrm_nr_get_own(struct ubus_context *ctx, struct ubus_object *obj,
1096 struct ubus_request_data *req, const char *method,
1097 struct blob_attr *msg)
1098 {
1099 struct hostapd_data *hapd = get_hapd_from_object(obj);
1100 struct hostapd_neighbor_entry *nr;
1101 void *c;
1102
1103 hostapd_rrm_nr_enable(hapd);
1104
1105 nr = hostapd_neighbor_get(hapd, hapd->own_addr, NULL);
1106 if (!nr)
1107 return UBUS_STATUS_NOT_FOUND;
1108
1109 blob_buf_init(&b, 0);
1110
1111 c = blobmsg_open_array(&b, "value");
1112 hostapd_rrm_print_nr(nr);
1113 blobmsg_close_array(&b, c);
1114
1115 ubus_send_reply(ctx, req, b.head);
1116
1117 return 0;
1118 }
1119
1120 static int
1121 hostapd_rrm_nr_list(struct ubus_context *ctx, struct ubus_object *obj,
1122 struct ubus_request_data *req, const char *method,
1123 struct blob_attr *msg)
1124 {
1125 struct hostapd_data *hapd = get_hapd_from_object(obj);
1126 struct hostapd_neighbor_entry *nr;
1127 void *c;
1128
1129 hostapd_rrm_nr_enable(hapd);
1130 blob_buf_init(&b, 0);
1131
1132 c = blobmsg_open_array(&b, "list");
1133 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
1134 void *cur;
1135
1136 if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
1137 continue;
1138
1139 cur = blobmsg_open_array(&b, NULL);
1140 hostapd_rrm_print_nr(nr);
1141 blobmsg_close_array(&b, cur);
1142 }
1143 blobmsg_close_array(&b, c);
1144
1145 ubus_send_reply(ctx, req, b.head);
1146
1147 return 0;
1148 }
1149
1150 enum {
1151 NR_SET_LIST,
1152 __NR_SET_LIST_MAX
1153 };
1154
1155 static const struct blobmsg_policy nr_set_policy[__NR_SET_LIST_MAX] = {
1156 [NR_SET_LIST] = { "list", BLOBMSG_TYPE_ARRAY },
1157 };
1158
1159
1160 static void
1161 hostapd_rrm_nr_clear(struct hostapd_data *hapd)
1162 {
1163 struct hostapd_neighbor_entry *nr;
1164
1165 restart:
1166 dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
1167 if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
1168 continue;
1169
1170 hostapd_neighbor_remove(hapd, nr->bssid, &nr->ssid);
1171 goto restart;
1172 }
1173 }
1174
1175 static int
1176 hostapd_rrm_nr_set(struct ubus_context *ctx, struct ubus_object *obj,
1177 struct ubus_request_data *req, const char *method,
1178 struct blob_attr *msg)
1179 {
1180 static const struct blobmsg_policy nr_e_policy[] = {
1181 { .type = BLOBMSG_TYPE_STRING },
1182 { .type = BLOBMSG_TYPE_STRING },
1183 { .type = BLOBMSG_TYPE_STRING },
1184 };
1185 struct hostapd_data *hapd = get_hapd_from_object(obj);
1186 struct blob_attr *tb_l[__NR_SET_LIST_MAX];
1187 struct blob_attr *tb[ARRAY_SIZE(nr_e_policy)];
1188 struct blob_attr *cur;
1189 int rem;
1190
1191 hostapd_rrm_nr_enable(hapd);
1192
1193 blobmsg_parse(nr_set_policy, __NR_SET_LIST_MAX, tb_l, blob_data(msg), blob_len(msg));
1194 if (!tb_l[NR_SET_LIST])
1195 return UBUS_STATUS_INVALID_ARGUMENT;
1196
1197 hostapd_rrm_nr_clear(hapd);
1198 blobmsg_for_each_attr(cur, tb_l[NR_SET_LIST], rem) {
1199 struct wpa_ssid_value ssid;
1200 struct wpabuf *data;
1201 u8 bssid[ETH_ALEN];
1202 char *s, *nr_s;
1203
1204 blobmsg_parse_array(nr_e_policy, ARRAY_SIZE(nr_e_policy), tb, blobmsg_data(cur), blobmsg_data_len(cur));
1205 if (!tb[0] || !tb[1] || !tb[2])
1206 goto invalid;
1207
1208 /* Neighbor Report binary */
1209 nr_s = blobmsg_get_string(tb[2]);
1210 data = wpabuf_parse_bin(nr_s);
1211 if (!data)
1212 goto invalid;
1213
1214 /* BSSID */
1215 s = blobmsg_get_string(tb[0]);
1216 if (strlen(s) == 0) {
1217 /* Copy BSSID from neighbor report */
1218 if (hwaddr_compact_aton(nr_s, bssid))
1219 goto invalid;
1220 } else if (hwaddr_aton(s, bssid)) {
1221 goto invalid;
1222 }
1223
1224 /* SSID */
1225 s = blobmsg_get_string(tb[1]);
1226 if (strlen(s) == 0) {
1227 /* Copy SSID from hostapd BSS conf */
1228 memcpy(&ssid, &hapd->conf->ssid, sizeof(ssid));
1229 } else {
1230 ssid.ssid_len = strlen(s);
1231 if (ssid.ssid_len > sizeof(ssid.ssid))
1232 goto invalid;
1233
1234 memcpy(&ssid, s, ssid.ssid_len);
1235 }
1236
1237 hostapd_neighbor_set(hapd, bssid, &ssid, data, NULL, NULL, 0, 0);
1238 wpabuf_free(data);
1239 continue;
1240
1241 invalid:
1242 return UBUS_STATUS_INVALID_ARGUMENT;
1243 }
1244
1245 return 0;
1246 }
1247
1248 enum {
1249 BEACON_REQ_ADDR,
1250 BEACON_REQ_MODE,
1251 BEACON_REQ_OP_CLASS,
1252 BEACON_REQ_CHANNEL,
1253 BEACON_REQ_DURATION,
1254 BEACON_REQ_BSSID,
1255 BEACON_REQ_SSID,
1256 __BEACON_REQ_MAX,
1257 };
1258
1259 static const struct blobmsg_policy beacon_req_policy[__BEACON_REQ_MAX] = {
1260 [BEACON_REQ_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
1261 [BEACON_REQ_OP_CLASS] { "op_class", BLOBMSG_TYPE_INT32 },
1262 [BEACON_REQ_CHANNEL] { "channel", BLOBMSG_TYPE_INT32 },
1263 [BEACON_REQ_DURATION] { "duration", BLOBMSG_TYPE_INT32 },
1264 [BEACON_REQ_MODE] { "mode", BLOBMSG_TYPE_INT32 },
1265 [BEACON_REQ_BSSID] { "bssid", BLOBMSG_TYPE_STRING },
1266 [BEACON_REQ_SSID] { "ssid", BLOBMSG_TYPE_STRING },
1267 };
1268
1269 static int
1270 hostapd_rrm_beacon_req(struct ubus_context *ctx, struct ubus_object *obj,
1271 struct ubus_request_data *ureq, const char *method,
1272 struct blob_attr *msg)
1273 {
1274 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
1275 struct blob_attr *tb[__BEACON_REQ_MAX];
1276 struct blob_attr *cur;
1277 struct wpabuf *req;
1278 u8 bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1279 u8 addr[ETH_ALEN];
1280 int mode, rem, ret;
1281 int buf_len = 13;
1282
1283 blobmsg_parse(beacon_req_policy, __BEACON_REQ_MAX, tb, blob_data(msg), blob_len(msg));
1284
1285 if (!tb[BEACON_REQ_ADDR] || !tb[BEACON_REQ_MODE] || !tb[BEACON_REQ_DURATION] ||
1286 !tb[BEACON_REQ_OP_CLASS] || !tb[BEACON_REQ_CHANNEL])
1287 return UBUS_STATUS_INVALID_ARGUMENT;
1288
1289 if (tb[BEACON_REQ_SSID])
1290 buf_len += blobmsg_data_len(tb[BEACON_REQ_SSID]) + 2 - 1;
1291
1292 mode = blobmsg_get_u32(tb[BEACON_REQ_MODE]);
1293 if (hwaddr_aton(blobmsg_data(tb[BEACON_REQ_ADDR]), addr))
1294 return UBUS_STATUS_INVALID_ARGUMENT;
1295
1296 if (tb[BEACON_REQ_BSSID] &&
1297 hwaddr_aton(blobmsg_data(tb[BEACON_REQ_BSSID]), bssid))
1298 return UBUS_STATUS_INVALID_ARGUMENT;
1299
1300 req = wpabuf_alloc(buf_len);
1301 if (!req)
1302 return UBUS_STATUS_UNKNOWN_ERROR;
1303
1304 /* 1: regulatory class */
1305 wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_OP_CLASS]));
1306
1307 /* 2: channel number */
1308 wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_CHANNEL]));
1309
1310 /* 3-4: randomization interval */
1311 wpabuf_put_le16(req, 0);
1312
1313 /* 5-6: duration */
1314 wpabuf_put_le16(req, blobmsg_get_u32(tb[BEACON_REQ_DURATION]));
1315
1316 /* 7: mode */
1317 wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_MODE]));
1318
1319 /* 8-13: BSSID */
1320 wpabuf_put_data(req, bssid, ETH_ALEN);
1321
1322 if ((cur = tb[BEACON_REQ_SSID]) != NULL) {
1323 wpabuf_put_u8(req, WLAN_EID_SSID);
1324 wpabuf_put_u8(req, blobmsg_data_len(cur) - 1);
1325 wpabuf_put_data(req, blobmsg_data(cur), blobmsg_data_len(cur) - 1);
1326 }
1327
1328 ret = hostapd_send_beacon_req(hapd, addr, 0, req);
1329 if (ret < 0)
1330 return -ret;
1331
1332 return 0;
1333 }
1334
1335 enum {
1336 LM_REQ_ADDR,
1337 LM_REQ_TX_POWER_USED,
1338 LM_REQ_TX_POWER_MAX,
1339 __LM_REQ_MAX,
1340 };
1341
1342 static const struct blobmsg_policy lm_req_policy[__LM_REQ_MAX] = {
1343 [LM_REQ_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
1344 [LM_REQ_TX_POWER_USED] = { "tx-power-used", BLOBMSG_TYPE_INT32 },
1345 [LM_REQ_TX_POWER_MAX] = { "tx-power-max", BLOBMSG_TYPE_INT32 },
1346 };
1347
1348 static int
1349 hostapd_rrm_lm_req(struct ubus_context *ctx, struct ubus_object *obj,
1350 struct ubus_request_data *ureq, const char *method,
1351 struct blob_attr *msg)
1352 {
1353 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
1354 struct blob_attr *tb[__LM_REQ_MAX];
1355 struct wpabuf *buf;
1356 u8 addr[ETH_ALEN];
1357 int ret;
1358 int8_t txp_used, txp_max;
1359
1360 txp_used = 0;
1361 txp_max = 0;
1362
1363 blobmsg_parse(lm_req_policy, __LM_REQ_MAX, tb, blob_data(msg), blob_len(msg));
1364
1365 if (!tb[LM_REQ_ADDR])
1366 return UBUS_STATUS_INVALID_ARGUMENT;
1367
1368 if (tb[LM_REQ_TX_POWER_USED])
1369 txp_used = (int8_t) blobmsg_get_u32(tb[LM_REQ_TX_POWER_USED]);
1370
1371 if (tb[LM_REQ_TX_POWER_MAX])
1372 txp_max = (int8_t) blobmsg_get_u32(tb[LM_REQ_TX_POWER_MAX]);
1373
1374 if (hwaddr_aton(blobmsg_data(tb[LM_REQ_ADDR]), addr))
1375 return UBUS_STATUS_INVALID_ARGUMENT;
1376
1377 buf = wpabuf_alloc(5);
1378 if (!buf)
1379 return UBUS_STATUS_UNKNOWN_ERROR;
1380
1381 wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
1382 wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST);
1383 wpabuf_put_u8(buf, 1);
1384 /* TX-Power used */
1385 wpabuf_put_u8(buf, txp_used);
1386 /* Max TX Power */
1387 wpabuf_put_u8(buf, txp_max);
1388
1389 ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
1390 wpabuf_head(buf), wpabuf_len(buf));
1391
1392 wpabuf_free(buf);
1393 if (ret < 0)
1394 return -ret;
1395
1396 return 0;
1397 }
1398
1399
1400 void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
1401 {
1402 const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) data;
1403 const u8 *pos, *end;
1404 u8 token;
1405
1406 end = data + len;
1407 token = mgmt->u.action.u.rrm.dialog_token;
1408 pos = mgmt->u.action.u.rrm.variable;
1409
1410 if (end - pos < 8)
1411 return;
1412
1413 if (!hapd->ubus.obj.has_subscribers)
1414 return;
1415
1416 blob_buf_init(&b, 0);
1417 blobmsg_add_macaddr(&b, "address", mgmt->sa);
1418 blobmsg_add_u16(&b, "dialog-token", token);
1419 blobmsg_add_u16(&b, "rx-antenna-id", pos[4]);
1420 blobmsg_add_u16(&b, "tx-antenna-id", pos[5]);
1421 blobmsg_add_u16(&b, "rcpi", pos[6]);
1422 blobmsg_add_u16(&b, "rsni", pos[7]);
1423
1424 ubus_notify(ctx, &hapd->ubus.obj, "link-measurement-report", b.head, -1);
1425 }
1426
1427
1428 #ifdef CONFIG_WNM_AP
1429
1430 static int
1431 hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
1432 u16 disassoc_timer, u8 validity_period, u8 dialog_token,
1433 struct blob_attr *neighbors, u8 mbo_reason, u8 cell_pref, u8 reassoc_delay)
1434 {
1435 struct blob_attr *cur;
1436 struct sta_info *sta;
1437 int nr_len = 0;
1438 int rem;
1439 u8 *nr = NULL;
1440 u8 req_mode = 0;
1441 u8 mbo[10];
1442 size_t mbo_len = 0;
1443
1444 sta = ap_get_sta(hapd, addr);
1445 if (!sta)
1446 return UBUS_STATUS_NOT_FOUND;
1447
1448 if (neighbors) {
1449 u8 *nr_cur;
1450
1451 if (blobmsg_check_array(neighbors,
1452 BLOBMSG_TYPE_STRING) < 0)
1453 return UBUS_STATUS_INVALID_ARGUMENT;
1454
1455 blobmsg_for_each_attr(cur, neighbors, rem) {
1456 int len = strlen(blobmsg_get_string(cur));
1457
1458 if (len % 2)
1459 return UBUS_STATUS_INVALID_ARGUMENT;
1460
1461 nr_len += (len / 2) + 2;
1462 }
1463
1464 if (nr_len) {
1465 nr = os_zalloc(nr_len);
1466 if (!nr)
1467 return UBUS_STATUS_UNKNOWN_ERROR;
1468 }
1469
1470 nr_cur = nr;
1471 blobmsg_for_each_attr(cur, neighbors, rem) {
1472 int len = strlen(blobmsg_get_string(cur)) / 2;
1473
1474 *nr_cur++ = WLAN_EID_NEIGHBOR_REPORT;
1475 *nr_cur++ = (u8) len;
1476 if (hexstr2bin(blobmsg_data(cur), nr_cur, len)) {
1477 free(nr);
1478 return UBUS_STATUS_INVALID_ARGUMENT;
1479 }
1480
1481 nr_cur += len;
1482 }
1483 }
1484
1485 if (nr)
1486 req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
1487
1488 if (abridged)
1489 req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
1490
1491 if (disassoc_imminent)
1492 req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
1493
1494 #ifdef CONFIG_MBO
1495 u8 *mbo_pos = mbo;
1496
1497 if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP)
1498 return UBUS_STATUS_INVALID_ARGUMENT;
1499
1500 if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255)
1501 return UBUS_STATUS_INVALID_ARGUMENT;
1502
1503 if (reassoc_delay > 65535 || (reassoc_delay && !disassoc_imminent))
1504 return UBUS_STATUS_INVALID_ARGUMENT;
1505
1506 *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
1507 *mbo_pos++ = 1;
1508 *mbo_pos++ = mbo_reason;
1509 *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
1510 *mbo_pos++ = 1;
1511 *mbo_pos++ = cell_pref;
1512
1513 if (reassoc_delay) {
1514 *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
1515 *mbo_pos++ = 2;
1516 WPA_PUT_LE16(mbo_pos, reassoc_delay);
1517 mbo_pos += 2;
1518 }
1519
1520 mbo_len = mbo_pos - mbo;
1521 #endif
1522
1523 if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
1524 dialog_token, NULL, nr, nr_len, mbo_len ? mbo : NULL, mbo_len))
1525 return UBUS_STATUS_UNKNOWN_ERROR;
1526
1527 return 0;
1528 }
1529
1530 enum {
1531 BSS_TR_ADDR,
1532 BSS_TR_DA_IMMINENT,
1533 BSS_TR_DA_TIMER,
1534 BSS_TR_VALID_PERIOD,
1535 BSS_TR_NEIGHBORS,
1536 BSS_TR_ABRIDGED,
1537 BSS_TR_DIALOG_TOKEN,
1538 #ifdef CONFIG_MBO
1539 BSS_TR_MBO_REASON,
1540 BSS_TR_CELL_PREF,
1541 BSS_TR_REASSOC_DELAY,
1542 #endif
1543 __BSS_TR_DISASSOC_MAX
1544 };
1545
1546 static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
1547 [BSS_TR_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
1548 [BSS_TR_DA_IMMINENT] = { "disassociation_imminent", BLOBMSG_TYPE_BOOL },
1549 [BSS_TR_DA_TIMER] = { "disassociation_timer", BLOBMSG_TYPE_INT32 },
1550 [BSS_TR_VALID_PERIOD] = { "validity_period", BLOBMSG_TYPE_INT32 },
1551 [BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
1552 [BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
1553 [BSS_TR_DIALOG_TOKEN] = { "dialog_token", BLOBMSG_TYPE_INT32 },
1554 #ifdef CONFIG_MBO
1555 [BSS_TR_MBO_REASON] = { "mbo_reason", BLOBMSG_TYPE_INT32 },
1556 [BSS_TR_CELL_PREF] = { "cell_pref", BLOBMSG_TYPE_INT32 },
1557 [BSS_TR_REASSOC_DELAY] = { "reassoc_delay", BLOBMSG_TYPE_INT32 },
1558 #endif
1559 };
1560
1561 static int
1562 hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj,
1563 struct ubus_request_data *ureq, const char *method,
1564 struct blob_attr *msg)
1565 {
1566 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
1567 struct blob_attr *tb[__BSS_TR_DISASSOC_MAX];
1568 struct sta_info *sta;
1569 u32 da_timer = 0;
1570 u32 valid_period = 0;
1571 u8 addr[ETH_ALEN];
1572 u32 dialog_token = 1;
1573 bool abridged;
1574 bool da_imminent;
1575 u8 mbo_reason;
1576 u8 cell_pref;
1577 u8 reassoc_delay;
1578
1579 blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
1580
1581 if (!tb[BSS_TR_ADDR])
1582 return UBUS_STATUS_INVALID_ARGUMENT;
1583
1584 if (hwaddr_aton(blobmsg_data(tb[BSS_TR_ADDR]), addr))
1585 return UBUS_STATUS_INVALID_ARGUMENT;
1586
1587 if (tb[BSS_TR_DA_TIMER])
1588 da_timer = blobmsg_get_u32(tb[BSS_TR_DA_TIMER]);
1589
1590 if (tb[BSS_TR_VALID_PERIOD])
1591 valid_period = blobmsg_get_u32(tb[BSS_TR_VALID_PERIOD]);
1592
1593 if (tb[BSS_TR_DIALOG_TOKEN])
1594 dialog_token = blobmsg_get_u32(tb[BSS_TR_DIALOG_TOKEN]);
1595
1596 da_imminent = !!(tb[BSS_TR_DA_IMMINENT] && blobmsg_get_bool(tb[BSS_TR_DA_IMMINENT]));
1597 abridged = !!(tb[BSS_TR_ABRIDGED] && blobmsg_get_bool(tb[BSS_TR_ABRIDGED]));
1598
1599 #ifdef CONFIG_MBO
1600 if (tb[BSS_TR_MBO_REASON])
1601 mbo_reason = blobmsg_get_u32(tb[BSS_TR_MBO_REASON]);
1602
1603 if (tb[BSS_TR_CELL_PREF])
1604 cell_pref = blobmsg_get_u32(tb[BSS_TR_CELL_PREF]);
1605
1606 if (tb[BSS_TR_REASSOC_DELAY])
1607 reassoc_delay = blobmsg_get_u32(tb[BSS_TR_REASSOC_DELAY]);
1608 #endif
1609
1610 return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
1611 dialog_token, tb[BSS_TR_NEIGHBORS], mbo_reason, cell_pref, reassoc_delay);
1612 }
1613 #endif
1614
1615 #ifdef CONFIG_AIRTIME_POLICY
1616 enum {
1617 UPDATE_AIRTIME_STA,
1618 UPDATE_AIRTIME_WEIGHT,
1619 __UPDATE_AIRTIME_MAX,
1620 };
1621
1622
1623 static const struct blobmsg_policy airtime_policy[__UPDATE_AIRTIME_MAX] = {
1624 [UPDATE_AIRTIME_STA] = { "sta", BLOBMSG_TYPE_STRING },
1625 [UPDATE_AIRTIME_WEIGHT] = { "weight", BLOBMSG_TYPE_INT32 },
1626 };
1627
1628 static int
1629 hostapd_bss_update_airtime(struct ubus_context *ctx, struct ubus_object *obj,
1630 struct ubus_request_data *ureq, const char *method,
1631 struct blob_attr *msg)
1632 {
1633 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
1634 struct blob_attr *tb[__UPDATE_AIRTIME_MAX];
1635 struct sta_info *sta = NULL;
1636 u8 addr[ETH_ALEN];
1637 int weight;
1638
1639 blobmsg_parse(airtime_policy, __UPDATE_AIRTIME_MAX, tb, blob_data(msg), blob_len(msg));
1640
1641 if (!tb[UPDATE_AIRTIME_WEIGHT])
1642 return UBUS_STATUS_INVALID_ARGUMENT;
1643
1644 weight = blobmsg_get_u32(tb[UPDATE_AIRTIME_WEIGHT]);
1645
1646 if (!tb[UPDATE_AIRTIME_STA]) {
1647 if (!weight)
1648 return UBUS_STATUS_INVALID_ARGUMENT;
1649
1650 hapd->conf->airtime_weight = weight;
1651 return 0;
1652 }
1653
1654 if (hwaddr_aton(blobmsg_data(tb[UPDATE_AIRTIME_STA]), addr))
1655 return UBUS_STATUS_INVALID_ARGUMENT;
1656
1657 sta = ap_get_sta(hapd, addr);
1658 if (!sta)
1659 return UBUS_STATUS_NOT_FOUND;
1660
1661 sta->dyn_airtime_weight = weight;
1662 airtime_policy_new_sta(hapd, sta);
1663
1664 return 0;
1665 }
1666 #endif
1667
1668 #ifdef CONFIG_TAXONOMY
1669 static const struct blobmsg_policy addr_policy[] = {
1670 { "address", BLOBMSG_TYPE_STRING }
1671 };
1672
1673 static bool
1674 hostapd_add_b64_data(const char *name, const struct wpabuf *buf)
1675 {
1676 char *str;
1677
1678 if (!buf)
1679 return false;
1680
1681 str = blobmsg_alloc_string_buffer(&b, name, B64_ENCODE_LEN(wpabuf_len(buf)));
1682 b64_encode(wpabuf_head(buf), wpabuf_len(buf), str, B64_ENCODE_LEN(wpabuf_len(buf)));
1683 blobmsg_add_string_buffer(&b);
1684
1685 return true;
1686 }
1687
1688 static int
1689 hostapd_bss_get_sta_ies(struct ubus_context *ctx, struct ubus_object *obj,
1690 struct ubus_request_data *req, const char *method,
1691 struct blob_attr *msg)
1692 {
1693 struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
1694 struct blob_attr *tb;
1695 struct sta_info *sta;
1696 u8 addr[ETH_ALEN];
1697
1698 blobmsg_parse(addr_policy, 1, &tb, blobmsg_data(msg), blobmsg_len(msg));
1699
1700 if (!tb || hwaddr_aton(blobmsg_data(tb), addr))
1701 return UBUS_STATUS_INVALID_ARGUMENT;
1702
1703 sta = ap_get_sta(hapd, addr);
1704 if (!sta || (!sta->probe_ie_taxonomy && !sta->assoc_ie_taxonomy))
1705 return UBUS_STATUS_NOT_FOUND;
1706
1707 blob_buf_init(&b, 0);
1708 hostapd_add_b64_data("probe_ie", sta->probe_ie_taxonomy);
1709 hostapd_add_b64_data("assoc_ie", sta->assoc_ie_taxonomy);
1710 ubus_send_reply(ctx, req, b.head);
1711
1712 return 0;
1713 }
1714 #endif
1715
1716
1717 static const struct ubus_method bss_methods[] = {
1718 UBUS_METHOD_NOARG("reload", hostapd_bss_reload),
1719 UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
1720 #ifdef CONFIG_TAXONOMY
1721 UBUS_METHOD("get_sta_ies", hostapd_bss_get_sta_ies, addr_policy),
1722 #endif
1723 UBUS_METHOD_NOARG("get_status", hostapd_bss_get_status),
1724 UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
1725 #ifdef CONFIG_AIRTIME_POLICY
1726 UBUS_METHOD("update_airtime", hostapd_bss_update_airtime, airtime_policy),
1727 #endif
1728 UBUS_METHOD_NOARG("list_bans", hostapd_bss_list_bans),
1729 #ifdef CONFIG_WPS
1730 UBUS_METHOD_NOARG("wps_start", hostapd_bss_wps_start),
1731 UBUS_METHOD_NOARG("wps_status", hostapd_bss_wps_status),
1732 UBUS_METHOD_NOARG("wps_cancel", hostapd_bss_wps_cancel),
1733 #endif
1734 UBUS_METHOD_NOARG("update_beacon", hostapd_bss_update_beacon),
1735 UBUS_METHOD_NOARG("get_features", hostapd_bss_get_features),
1736 #ifdef NEED_AP_MLME
1737 UBUS_METHOD("switch_chan", hostapd_switch_chan, csa_policy),
1738 #endif
1739 UBUS_METHOD("set_vendor_elements", hostapd_vendor_elements, ve_policy),
1740 UBUS_METHOD("notify_response", hostapd_notify_response, notify_policy),
1741 UBUS_METHOD("bss_mgmt_enable", hostapd_bss_mgmt_enable, bss_mgmt_enable_policy),
1742 UBUS_METHOD_NOARG("rrm_nr_get_own", hostapd_rrm_nr_get_own),
1743 UBUS_METHOD_NOARG("rrm_nr_list", hostapd_rrm_nr_list),
1744 UBUS_METHOD("rrm_nr_set", hostapd_rrm_nr_set, nr_set_policy),
1745 UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy),
1746 UBUS_METHOD("link_measurement_req", hostapd_rrm_lm_req, lm_req_policy),
1747 #ifdef CONFIG_WNM_AP
1748 UBUS_METHOD("bss_transition_request", hostapd_bss_transition_request, bss_tr_policy),
1749 #endif
1750 };
1751
1752 static struct ubus_object_type bss_object_type =
1753 UBUS_OBJECT_TYPE("hostapd_bss", bss_methods);
1754
1755 static int avl_compare_macaddr(const void *k1, const void *k2, void *ptr)
1756 {
1757 return memcmp(k1, k2, ETH_ALEN);
1758 }
1759
1760 void hostapd_ubus_add_bss(struct hostapd_data *hapd)
1761 {
1762 struct ubus_object *obj = &hapd->ubus.obj;
1763 char *name;
1764 int ret;
1765
1766 #ifdef CONFIG_MESH
1767 if (hapd->conf->mesh & MESH_ENABLED)
1768 return;
1769 #endif
1770
1771 if (!hostapd_ubus_init())
1772 return;
1773
1774 if (asprintf(&name, "hostapd.%s", hapd->conf->iface) < 0)
1775 return;
1776
1777 avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL);
1778 obj->name = name;
1779 obj->type = &bss_object_type;
1780 obj->methods = bss_object_type.methods;
1781 obj->n_methods = bss_object_type.n_methods;
1782 ret = ubus_add_object(ctx, obj);
1783 hostapd_ubus_ref_inc();
1784
1785 hostapd_send_shared_event(&hapd->iface->interfaces->ubus, hapd->conf->iface, "add");
1786 }
1787
1788 void hostapd_ubus_free_bss(struct hostapd_data *hapd)
1789 {
1790 struct ubus_object *obj = &hapd->ubus.obj;
1791 char *name = (char *) obj->name;
1792
1793 #ifdef CONFIG_MESH
1794 if (hapd->conf->mesh & MESH_ENABLED)
1795 return;
1796 #endif
1797
1798 if (!ctx)
1799 return;
1800
1801 hostapd_send_shared_event(&hapd->iface->interfaces->ubus, hapd->conf->iface, "remove");
1802
1803 if (obj->id) {
1804 ubus_remove_object(ctx, obj);
1805 hostapd_ubus_ref_dec();
1806 }
1807
1808 free(name);
1809 }
1810
1811 static void
1812 hostapd_ubus_vlan_action(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
1813 const char *action)
1814 {
1815 struct vlan_description *desc = &vlan->vlan_desc;
1816 void *c;
1817 int i;
1818
1819 if (!hapd->ubus.obj.has_subscribers)
1820 return;
1821
1822 blob_buf_init(&b, 0);
1823 blobmsg_add_string(&b, "ifname", vlan->ifname);
1824 blobmsg_add_string(&b, "bridge", vlan->bridge);
1825 blobmsg_add_u32(&b, "vlan_id", vlan->vlan_id);
1826
1827 if (desc->notempty) {
1828 blobmsg_add_u32(&b, "untagged", desc->untagged);
1829 c = blobmsg_open_array(&b, "tagged");
1830 for (i = 0; i < ARRAY_SIZE(desc->tagged) && desc->tagged[i]; i++)
1831 blobmsg_add_u32(&b, "", desc->tagged[i]);
1832 blobmsg_close_array(&b, c);
1833 }
1834
1835 ubus_notify(ctx, &hapd->ubus.obj, action, b.head, -1);
1836 }
1837
1838 void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
1839 {
1840 hostapd_ubus_vlan_action(hapd, vlan, "vlan_add");
1841 }
1842
1843 void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
1844 {
1845 hostapd_ubus_vlan_action(hapd, vlan, "vlan_remove");
1846 }
1847
1848 static const struct ubus_method daemon_methods[] = {
1849 UBUS_METHOD("config_add", hostapd_config_add, config_add_policy),
1850 UBUS_METHOD("config_remove", hostapd_config_remove, config_remove_policy),
1851 };
1852
1853 static struct ubus_object_type daemon_object_type =
1854 UBUS_OBJECT_TYPE("hostapd", daemon_methods);
1855
1856 void hostapd_ubus_add(struct hapd_interfaces *interfaces)
1857 {
1858 struct ubus_object *obj = &interfaces->ubus;
1859 int ret;
1860
1861 if (!hostapd_ubus_init())
1862 return;
1863
1864 obj->name = strdup("hostapd");
1865
1866 obj->type = &daemon_object_type;
1867 obj->methods = daemon_object_type.methods;
1868 obj->n_methods = daemon_object_type.n_methods;
1869 ret = ubus_add_object(ctx, obj);
1870 hostapd_ubus_ref_inc();
1871 }
1872
1873 void hostapd_ubus_free(struct hapd_interfaces *interfaces)
1874 {
1875 struct ubus_object *obj = &interfaces->ubus;
1876 char *name = (char *) obj->name;
1877
1878 if (!ctx)
1879 return;
1880
1881 if (obj->id) {
1882 ubus_remove_object(ctx, obj);
1883 hostapd_ubus_ref_dec();
1884 }
1885
1886 free(name);
1887 }
1888
1889 struct ubus_event_req {
1890 struct ubus_notify_request nreq;
1891 int resp;
1892 };
1893
1894 static void
1895 ubus_event_cb(struct ubus_notify_request *req, int idx, int ret)
1896 {
1897 struct ubus_event_req *ureq = container_of(req, struct ubus_event_req, nreq);
1898
1899 ureq->resp = ret;
1900 }
1901
1902 int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
1903 {
1904 struct ubus_banned_client *ban;
1905 const char *types[HOSTAPD_UBUS_TYPE_MAX] = {
1906 [HOSTAPD_UBUS_PROBE_REQ] = "probe",
1907 [HOSTAPD_UBUS_AUTH_REQ] = "auth",
1908 [HOSTAPD_UBUS_ASSOC_REQ] = "assoc",
1909 };
1910 const char *type = "mgmt";
1911 struct ubus_event_req ureq = {};
1912 const u8 *addr;
1913
1914 if (req->mgmt_frame)
1915 addr = req->mgmt_frame->sa;
1916 else
1917 addr = req->addr;
1918
1919 ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
1920 if (ban)
1921 return WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
1922
1923 if (!hapd->ubus.obj.has_subscribers)
1924 return WLAN_STATUS_SUCCESS;
1925
1926 if (req->type < ARRAY_SIZE(types))
1927 type = types[req->type];
1928
1929 blob_buf_init(&b, 0);
1930 blobmsg_add_macaddr(&b, "address", addr);
1931 if (req->mgmt_frame)
1932 blobmsg_add_macaddr(&b, "target", req->mgmt_frame->da);
1933 if (req->ssi_signal)
1934 blobmsg_add_u32(&b, "signal", req->ssi_signal);
1935 blobmsg_add_u32(&b, "freq", hapd->iface->freq);
1936
1937 if (req->elems) {
1938 if(req->elems->ht_capabilities)
1939 {
1940 struct ieee80211_ht_capabilities *ht_capabilities;
1941 void *ht_cap, *ht_cap_mcs_set, *mcs_set;
1942
1943
1944 ht_capabilities = (struct ieee80211_ht_capabilities*) req->elems->ht_capabilities;
1945 ht_cap = blobmsg_open_table(&b, "ht_capabilities");
1946 blobmsg_add_u16(&b, "ht_capabilities_info", ht_capabilities->ht_capabilities_info);
1947 ht_cap_mcs_set = blobmsg_open_table(&b, "supported_mcs_set");
1948 blobmsg_add_u16(&b, "a_mpdu_params", ht_capabilities->a_mpdu_params);
1949 blobmsg_add_u16(&b, "ht_extended_capabilities", ht_capabilities->ht_extended_capabilities);
1950 blobmsg_add_u32(&b, "tx_bf_capability_info", ht_capabilities->tx_bf_capability_info);
1951 blobmsg_add_u16(&b, "asel_capabilities", ht_capabilities->asel_capabilities);
1952 mcs_set = blobmsg_open_array(&b, "supported_mcs_set");
1953 for (int i = 0; i < 16; i++) {
1954 blobmsg_add_u16(&b, NULL, (u16) ht_capabilities->supported_mcs_set[i]);
1955 }
1956 blobmsg_close_array(&b, mcs_set);
1957 blobmsg_close_table(&b, ht_cap_mcs_set);
1958 blobmsg_close_table(&b, ht_cap);
1959 }
1960 if(req->elems->vht_capabilities)
1961 {
1962 struct ieee80211_vht_capabilities *vht_capabilities;
1963 void *vht_cap, *vht_cap_mcs_set;
1964
1965 vht_capabilities = (struct ieee80211_vht_capabilities*) req->elems->vht_capabilities;
1966 vht_cap = blobmsg_open_table(&b, "vht_capabilities");
1967 blobmsg_add_u32(&b, "vht_capabilities_info", vht_capabilities->vht_capabilities_info);
1968 vht_cap_mcs_set = blobmsg_open_table(&b, "vht_supported_mcs_set");
1969 blobmsg_add_u16(&b, "rx_map", vht_capabilities->vht_supported_mcs_set.rx_map);
1970 blobmsg_add_u16(&b, "rx_highest", vht_capabilities->vht_supported_mcs_set.rx_highest);
1971 blobmsg_add_u16(&b, "tx_map", vht_capabilities->vht_supported_mcs_set.tx_map);
1972 blobmsg_add_u16(&b, "tx_highest", vht_capabilities->vht_supported_mcs_set.tx_highest);
1973 blobmsg_close_table(&b, vht_cap_mcs_set);
1974 blobmsg_close_table(&b, vht_cap);
1975 }
1976 }
1977
1978 if (!hapd->ubus.notify_response) {
1979 ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
1980 return WLAN_STATUS_SUCCESS;
1981 }
1982
1983 if (ubus_notify_async(ctx, &hapd->ubus.obj, type, b.head, &ureq.nreq))
1984 return WLAN_STATUS_SUCCESS;
1985
1986 ureq.nreq.status_cb = ubus_event_cb;
1987 ubus_complete_request(ctx, &ureq.nreq.req, 100);
1988
1989 if (ureq.resp)
1990 return ureq.resp;
1991
1992 return WLAN_STATUS_SUCCESS;
1993 }
1994
1995 void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *addr)
1996 {
1997 if (!hapd->ubus.obj.has_subscribers)
1998 return;
1999
2000 if (!addr)
2001 return;
2002
2003 blob_buf_init(&b, 0);
2004 blobmsg_add_macaddr(&b, "address", addr);
2005
2006 ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
2007 }
2008
2009 void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
2010 const char *auth_alg)
2011 {
2012 if (!hapd->ubus.obj.has_subscribers)
2013 return;
2014
2015 blob_buf_init(&b, 0);
2016 blobmsg_add_macaddr(&b, "address", sta->addr);
2017 if (auth_alg)
2018 blobmsg_add_string(&b, "auth-alg", auth_alg);
2019
2020 ubus_notify(ctx, &hapd->ubus.obj, "sta-authorized", b.head, -1);
2021 }
2022
2023 void hostapd_ubus_notify_beacon_report(
2024 struct hostapd_data *hapd, const u8 *addr, u8 token, u8 rep_mode,
2025 struct rrm_measurement_beacon_report *rep, size_t len)
2026 {
2027 if (!hapd->ubus.obj.has_subscribers)
2028 return;
2029
2030 if (!addr || !rep)
2031 return;
2032
2033 blob_buf_init(&b, 0);
2034 blobmsg_add_macaddr(&b, "address", addr);
2035 blobmsg_add_u16(&b, "op-class", rep->op_class);
2036 blobmsg_add_u16(&b, "channel", rep->channel);
2037 blobmsg_add_u64(&b, "start-time", rep->start_time);
2038 blobmsg_add_u16(&b, "duration", rep->duration);
2039 blobmsg_add_u16(&b, "report-info", rep->report_info);
2040 blobmsg_add_u16(&b, "rcpi", rep->rcpi);
2041 blobmsg_add_u16(&b, "rsni", rep->rsni);
2042 blobmsg_add_macaddr(&b, "bssid", rep->bssid);
2043 blobmsg_add_u16(&b, "antenna-id", rep->antenna_id);
2044 blobmsg_add_u16(&b, "parent-tsf", rep->parent_tsf);
2045 blobmsg_add_u16(&b, "rep-mode", rep_mode);
2046
2047 ubus_notify(ctx, &hapd->ubus.obj, "beacon-report", b.head, -1);
2048 }
2049
2050 void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
2051 int chan_width, int cf1, int cf2)
2052 {
2053 struct hostapd_data *hapd;
2054 int i;
2055
2056 blob_buf_init(&b, 0);
2057 blobmsg_add_u16(&b, "frequency", frequency);
2058 blobmsg_add_u16(&b, "width", chan_width);
2059 blobmsg_add_u16(&b, "center1", cf1);
2060 blobmsg_add_u16(&b, "center2", cf2);
2061
2062 for (i = 0; i < iface->num_bss; i++) {
2063 hapd = iface->bss[i];
2064 ubus_notify(ctx, &hapd->ubus.obj, "radar-detected", b.head, -1);
2065 }
2066 }
2067
2068 #ifdef CONFIG_WNM_AP
2069 static void hostapd_ubus_notify_bss_transition_add_candidate_list(
2070 const u8 *candidate_list, u16 candidate_list_len)
2071 {
2072 char *cl_str;
2073 int i;
2074
2075 if (candidate_list_len == 0)
2076 return;
2077
2078 cl_str = blobmsg_alloc_string_buffer(&b, "candidate-list", candidate_list_len * 2 + 1);
2079 for (i = 0; i < candidate_list_len; i++)
2080 snprintf(&cl_str[i*2], 3, "%02X", candidate_list[i]);
2081 blobmsg_add_string_buffer(&b);
2082
2083 }
2084 #endif
2085
2086 void hostapd_ubus_notify_bss_transition_response(
2087 struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
2088 u8 bss_termination_delay, const u8 *target_bssid,
2089 const u8 *candidate_list, u16 candidate_list_len)
2090 {
2091 #ifdef CONFIG_WNM_AP
2092 u16 i;
2093
2094 if (!hapd->ubus.obj.has_subscribers)
2095 return;
2096
2097 if (!addr)
2098 return;
2099
2100 blob_buf_init(&b, 0);
2101 blobmsg_add_macaddr(&b, "address", addr);
2102 blobmsg_add_u8(&b, "dialog-token", dialog_token);
2103 blobmsg_add_u8(&b, "status-code", status_code);
2104 blobmsg_add_u8(&b, "bss-termination-delay", bss_termination_delay);
2105 if (target_bssid)
2106 blobmsg_add_macaddr(&b, "target-bssid", target_bssid);
2107
2108 hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
2109
2110 ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-response", b.head, -1);
2111 #endif
2112 }
2113
2114 int hostapd_ubus_notify_bss_transition_query(
2115 struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
2116 const u8 *candidate_list, u16 candidate_list_len)
2117 {
2118 #ifdef CONFIG_WNM_AP
2119 struct ubus_event_req ureq = {};
2120 char *cl_str;
2121 u16 i;
2122
2123 if (!hapd->ubus.obj.has_subscribers)
2124 return 0;
2125
2126 if (!addr)
2127 return 0;
2128
2129 blob_buf_init(&b, 0);
2130 blobmsg_add_macaddr(&b, "address", addr);
2131 blobmsg_add_u8(&b, "dialog-token", dialog_token);
2132 blobmsg_add_u8(&b, "reason", reason);
2133 hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
2134
2135 if (!hapd->ubus.notify_response) {
2136 ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, -1);
2137 return 0;
2138 }
2139
2140 if (ubus_notify_async(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, &ureq.nreq))
2141 return 0;
2142
2143 ureq.nreq.status_cb = ubus_event_cb;
2144 ubus_complete_request(ctx, &ureq.nreq.req, 100);
2145
2146 return ureq.resp;
2147 #endif
2148 }