hostapd: add udebug support
[openwrt/staging/hauke.git] / package / network / services / hostapd / src / src / ap / ucode.c
1 #include <sys/un.h>
2
3 #include "utils/includes.h"
4 #include "utils/common.h"
5 #include "utils/ucode.h"
6 #include "hostapd.h"
7 #include "beacon.h"
8 #include "hw_features.h"
9 #include "ap_drv_ops.h"
10 #include "dfs.h"
11 #include "acs.h"
12 #include <libubox/uloop.h>
13
14 static uc_resource_type_t *global_type, *bss_type, *iface_type;
15 static struct hapd_interfaces *interfaces;
16 static uc_value_t *global, *bss_registry, *iface_registry;
17 static uc_vm_t *vm;
18
19 static uc_value_t *
20 hostapd_ucode_bss_get_uval(struct hostapd_data *hapd)
21 {
22 uc_value_t *val;
23
24 if (hapd->ucode.idx)
25 return wpa_ucode_registry_get(bss_registry, hapd->ucode.idx);
26
27 val = uc_resource_new(bss_type, hapd);
28 hapd->ucode.idx = wpa_ucode_registry_add(bss_registry, val);
29
30 return val;
31 }
32
33 static uc_value_t *
34 hostapd_ucode_iface_get_uval(struct hostapd_iface *hapd)
35 {
36 uc_value_t *val;
37
38 if (hapd->ucode.idx)
39 return wpa_ucode_registry_get(iface_registry, hapd->ucode.idx);
40
41 val = uc_resource_new(iface_type, hapd);
42 hapd->ucode.idx = wpa_ucode_registry_add(iface_registry, val);
43
44 return val;
45 }
46
47 static void
48 hostapd_ucode_update_bss_list(struct hostapd_iface *iface, uc_value_t *if_bss, uc_value_t *bss)
49 {
50 uc_value_t *list;
51 int i;
52
53 list = ucv_array_new(vm);
54 for (i = 0; i < iface->num_bss; i++) {
55 struct hostapd_data *hapd = iface->bss[i];
56 uc_value_t *val = hostapd_ucode_bss_get_uval(hapd);
57
58 ucv_array_set(list, i, ucv_get(ucv_string_new(hapd->conf->iface)));
59 ucv_object_add(bss, hapd->conf->iface, ucv_get(val));
60 }
61 ucv_object_add(if_bss, iface->phy, ucv_get(list));
62 }
63
64 static void
65 hostapd_ucode_update_interfaces(void)
66 {
67 uc_value_t *ifs = ucv_object_new(vm);
68 uc_value_t *if_bss = ucv_array_new(vm);
69 uc_value_t *bss = ucv_object_new(vm);
70 int i;
71
72 for (i = 0; i < interfaces->count; i++) {
73 struct hostapd_iface *iface = interfaces->iface[i];
74
75 ucv_object_add(ifs, iface->phy, ucv_get(hostapd_ucode_iface_get_uval(iface)));
76 hostapd_ucode_update_bss_list(iface, if_bss, bss);
77 }
78
79 ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
80 ucv_object_add(ucv_prototype_get(global), "interface_bss", ucv_get(if_bss));
81 ucv_object_add(ucv_prototype_get(global), "bss", ucv_get(bss));
82 ucv_gc(vm);
83 }
84
85 static uc_value_t *
86 uc_hostapd_add_iface(uc_vm_t *vm, size_t nargs)
87 {
88 uc_value_t *iface = uc_fn_arg(0);
89 int ret;
90
91 if (ucv_type(iface) != UC_STRING)
92 return ucv_int64_new(-1);
93
94 ret = hostapd_add_iface(interfaces, ucv_string_get(iface));
95 hostapd_ucode_update_interfaces();
96
97 return ucv_int64_new(ret);
98 }
99
100 static uc_value_t *
101 uc_hostapd_remove_iface(uc_vm_t *vm, size_t nargs)
102 {
103 uc_value_t *iface = uc_fn_arg(0);
104
105 if (ucv_type(iface) != UC_STRING)
106 return NULL;
107
108 hostapd_remove_iface(interfaces, ucv_string_get(iface));
109 hostapd_ucode_update_interfaces();
110
111 return NULL;
112 }
113
114 static struct hostapd_vlan *
115 bss_conf_find_vlan(struct hostapd_bss_config *bss, int id)
116 {
117 struct hostapd_vlan *vlan;
118
119 for (vlan = bss->vlan; vlan; vlan = vlan->next)
120 if (vlan->vlan_id == id)
121 return vlan;
122
123 return NULL;
124 }
125
126 static int
127 bss_conf_rename_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
128 const char *ifname)
129 {
130 if (!strcmp(ifname, vlan->ifname))
131 return 0;
132
133 hostapd_drv_if_rename(hapd, WPA_IF_AP_VLAN, vlan->ifname, ifname);
134 os_strlcpy(vlan->ifname, ifname, sizeof(vlan->ifname));
135
136 return 0;
137 }
138
139 static int
140 bss_reload_vlans(struct hostapd_data *hapd, struct hostapd_bss_config *bss)
141 {
142 struct hostapd_bss_config *old_bss = hapd->conf;
143 struct hostapd_vlan *vlan, *vlan_new, *wildcard;
144 char ifname[IFNAMSIZ + 1], vlan_ifname[IFNAMSIZ + 1], *pos;
145 int ret;
146
147 vlan = bss_conf_find_vlan(old_bss, VLAN_ID_WILDCARD);
148 wildcard = bss_conf_find_vlan(bss, VLAN_ID_WILDCARD);
149 if (!!vlan != !!wildcard)
150 return -1;
151
152 if (vlan && wildcard && strcmp(vlan->ifname, wildcard->ifname) != 0)
153 strcpy(vlan->ifname, wildcard->ifname);
154 else
155 wildcard = NULL;
156
157 for (vlan = bss->vlan; vlan; vlan = vlan->next) {
158 if (vlan->vlan_id == VLAN_ID_WILDCARD ||
159 vlan->dynamic_vlan > 0)
160 continue;
161
162 if (!bss_conf_find_vlan(old_bss, vlan->vlan_id))
163 return -1;
164 }
165
166 for (vlan = old_bss->vlan; vlan; vlan = vlan->next) {
167 if (vlan->vlan_id == VLAN_ID_WILDCARD)
168 continue;
169
170 if (vlan->dynamic_vlan == 0) {
171 vlan_new = bss_conf_find_vlan(bss, vlan->vlan_id);
172 if (!vlan_new)
173 return -1;
174
175 if (bss_conf_rename_vlan(hapd, vlan, vlan_new->ifname))
176 return -1;
177
178 continue;
179 }
180
181 if (!wildcard)
182 continue;
183
184 os_strlcpy(ifname, wildcard->ifname, sizeof(ifname));
185 pos = os_strchr(ifname, '#');
186 if (!pos)
187 return -1;
188
189 *pos++ = '\0';
190 ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s%d%s",
191 ifname, vlan->vlan_id, pos);
192 if (os_snprintf_error(sizeof(vlan_ifname), ret))
193 return -1;
194
195 if (bss_conf_rename_vlan(hapd, vlan, vlan_ifname))
196 return -1;
197 }
198
199 return 0;
200 }
201
202 static uc_value_t *
203 uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
204 {
205 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
206 struct hostapd_bss_config *old_bss;
207 struct hostapd_iface *iface;
208 struct hostapd_config *conf;
209 uc_value_t *file = uc_fn_arg(0);
210 uc_value_t *index = uc_fn_arg(1);
211 uc_value_t *files_only = uc_fn_arg(2);
212 unsigned int i, idx = 0;
213 int ret = -1;
214
215 if (!hapd || ucv_type(file) != UC_STRING)
216 goto out;
217
218 if (ucv_type(index) == UC_INTEGER)
219 idx = ucv_int64_get(index);
220
221 iface = hapd->iface;
222 conf = interfaces->config_read_cb(ucv_string_get(file));
223 if (!conf)
224 goto out;
225
226 if (idx > conf->num_bss || !conf->bss[idx])
227 goto free;
228
229 if (ucv_boolean_get(files_only)) {
230 struct hostapd_bss_config *bss = conf->bss[idx];
231 struct hostapd_bss_config *old_bss = hapd->conf;
232
233 #define swap_field(name) \
234 do { \
235 void *ptr = old_bss->name; \
236 old_bss->name = bss->name; \
237 bss->name = ptr; \
238 } while (0)
239
240 swap_field(ssid.wpa_psk_file);
241 ret = bss_reload_vlans(hapd, bss);
242 goto done;
243 }
244
245 hostapd_bss_deinit_no_free(hapd);
246 hostapd_drv_stop_ap(hapd);
247 hostapd_free_hapd_data(hapd);
248
249 old_bss = hapd->conf;
250 for (i = 0; i < iface->conf->num_bss; i++)
251 if (iface->conf->bss[i] == hapd->conf)
252 iface->conf->bss[i] = conf->bss[idx];
253 hapd->conf = conf->bss[idx];
254 conf->bss[idx] = old_bss;
255
256 hostapd_setup_bss(hapd, hapd == iface->bss[0], true);
257 hostapd_ucode_update_interfaces();
258
259 done:
260 ret = 0;
261 free:
262 hostapd_config_free(conf);
263 out:
264 return ucv_int64_new(ret);
265 }
266
267 static void
268 hostapd_remove_iface_bss_conf(struct hostapd_config *iconf,
269 struct hostapd_bss_config *conf)
270 {
271 int i;
272
273 for (i = 0; i < iconf->num_bss; i++)
274 if (iconf->bss[i] == conf)
275 break;
276
277 if (i == iconf->num_bss)
278 return;
279
280 for (i++; i < iconf->num_bss; i++)
281 iconf->bss[i - 1] = iconf->bss[i];
282 iconf->num_bss--;
283 }
284
285
286 static uc_value_t *
287 uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
288 {
289 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
290 struct hostapd_iface *iface;
291 int i, idx;
292
293 if (!hapd)
294 return NULL;
295
296 iface = hapd->iface;
297 if (iface->num_bss == 1) {
298 wpa_printf(MSG_ERROR, "trying to delete last bss of an iface: %s\n", hapd->conf->iface);
299 return NULL;
300 }
301
302 for (idx = 0; idx < iface->num_bss; idx++)
303 if (iface->bss[idx] == hapd)
304 break;
305
306 if (idx == iface->num_bss)
307 return NULL;
308
309 for (i = idx + 1; i < iface->num_bss; i++)
310 iface->bss[i - 1] = iface->bss[i];
311
312 iface->num_bss--;
313
314 iface->bss[0]->interface_added = 0;
315 hostapd_drv_set_first_bss(iface->bss[0]);
316 hapd->interface_added = 1;
317
318 hostapd_drv_stop_ap(hapd);
319 hostapd_bss_deinit(hapd);
320 hostapd_remove_iface_bss_conf(iface->conf, hapd->conf);
321 hostapd_config_free_bss(hapd->conf);
322 os_free(hapd);
323
324 hostapd_ucode_update_interfaces();
325 ucv_gc(vm);
326
327 return NULL;
328 }
329
330 static uc_value_t *
331 uc_hostapd_iface_add_bss(uc_vm_t *vm, size_t nargs)
332 {
333 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
334 struct hostapd_bss_config *bss;
335 struct hostapd_config *conf;
336 struct hostapd_data *hapd;
337 uc_value_t *file = uc_fn_arg(0);
338 uc_value_t *index = uc_fn_arg(1);
339 unsigned int idx = 0;
340 uc_value_t *ret = NULL;
341
342 if (!iface || ucv_type(file) != UC_STRING)
343 goto out;
344
345 if (ucv_type(index) == UC_INTEGER)
346 idx = ucv_int64_get(index);
347
348 conf = interfaces->config_read_cb(ucv_string_get(file));
349 if (!conf || idx > conf->num_bss || !conf->bss[idx])
350 goto out;
351
352 bss = conf->bss[idx];
353 hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
354 if (!hapd)
355 goto out;
356
357 hapd->driver = iface->bss[0]->driver;
358 hapd->drv_priv = iface->bss[0]->drv_priv;
359 if (interfaces->ctrl_iface_init &&
360 interfaces->ctrl_iface_init(hapd) < 0)
361 goto free_hapd;
362
363 if (iface->state == HAPD_IFACE_ENABLED &&
364 hostapd_setup_bss(hapd, -1, true))
365 goto deinit_ctrl;
366
367 iface->bss = os_realloc_array(iface->bss, iface->num_bss + 1,
368 sizeof(*iface->bss));
369 iface->bss[iface->num_bss++] = hapd;
370
371 iface->conf->bss = os_realloc_array(iface->conf->bss,
372 iface->conf->num_bss + 1,
373 sizeof(*iface->conf->bss));
374 iface->conf->bss[iface->conf->num_bss] = bss;
375 conf->bss[idx] = NULL;
376 ret = hostapd_ucode_bss_get_uval(hapd);
377 hostapd_ucode_update_interfaces();
378 goto out;
379
380 deinit_ctrl:
381 if (interfaces->ctrl_iface_deinit)
382 interfaces->ctrl_iface_deinit(hapd);
383 free_hapd:
384 hostapd_free_hapd_data(hapd);
385 os_free(hapd);
386 out:
387 hostapd_config_free(conf);
388 return ret;
389 }
390
391 static uc_value_t *
392 uc_hostapd_iface_set_bss_order(uc_vm_t *vm, size_t nargs)
393 {
394 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
395 uc_value_t *bss_list = uc_fn_arg(0);
396 struct hostapd_data **new_bss;
397 struct hostapd_bss_config **new_conf;
398
399 if (!iface)
400 return NULL;
401
402 if (ucv_type(bss_list) != UC_ARRAY ||
403 ucv_array_length(bss_list) != iface->num_bss)
404 return NULL;
405
406 new_bss = calloc(iface->num_bss, sizeof(*new_bss));
407 new_conf = calloc(iface->num_bss, sizeof(*new_conf));
408 for (size_t i = 0; i < iface->num_bss; i++) {
409 struct hostapd_data *bss;
410
411 bss = ucv_resource_data(ucv_array_get(bss_list, i), "hostapd.bss");
412 if (bss->iface != iface)
413 goto free;
414
415 for (size_t k = 0; k < i; k++)
416 if (new_bss[k] == bss)
417 goto free;
418
419 new_bss[i] = bss;
420 new_conf[i] = bss->conf;
421 }
422
423 new_bss[0]->interface_added = 0;
424 for (size_t i = 1; i < iface->num_bss; i++)
425 new_bss[i]->interface_added = 1;
426
427 free(iface->bss);
428 iface->bss = new_bss;
429
430 free(iface->conf->bss);
431 iface->conf->bss = new_conf;
432 iface->conf->num_bss = iface->num_bss;
433 hostapd_drv_set_first_bss(iface->bss[0]);
434
435 return ucv_boolean_new(true);
436
437 free:
438 free(new_bss);
439 free(new_conf);
440 return NULL;
441 }
442
443 static uc_value_t *
444 uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs)
445 {
446 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
447 uc_value_t *arg = uc_fn_arg(0);
448 struct sockaddr_storage from = {};
449 static char reply[4096];
450 int reply_len;
451
452 if (!hapd || !interfaces->ctrl_iface_recv ||
453 ucv_type(arg) != UC_STRING)
454 return NULL;
455
456 reply_len = interfaces->ctrl_iface_recv(hapd, ucv_string_get(arg),
457 reply, sizeof(reply),
458 &from, sizeof(from));
459 if (reply_len < 0)
460 return NULL;
461
462 if (reply_len && reply[reply_len - 1] == '\n')
463 reply_len--;
464
465 return ucv_string_new_length(reply, reply_len);
466 }
467
468 static void
469 uc_hostapd_disable_iface(struct hostapd_iface *iface)
470 {
471 switch (iface->state) {
472 case HAPD_IFACE_DISABLED:
473 break;
474 #ifdef CONFIG_ACS
475 case HAPD_IFACE_ACS:
476 acs_cleanup(iface);
477 iface->scan_cb = NULL;
478 /* fallthrough */
479 #endif
480 default:
481 hostapd_disable_iface(iface);
482 break;
483 }
484 }
485
486 static uc_value_t *
487 uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs)
488 {
489 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
490 int i;
491
492 if (!iface)
493 return NULL;
494
495 if (iface->state != HAPD_IFACE_ENABLED)
496 uc_hostapd_disable_iface(iface);
497
498 for (i = 0; i < iface->num_bss; i++) {
499 struct hostapd_data *hapd = iface->bss[i];
500
501 hostapd_drv_stop_ap(hapd);
502 hapd->beacon_set_done = 0;
503 }
504
505 return NULL;
506 }
507
508 static uc_value_t *
509 uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs)
510 {
511 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
512 uc_value_t *info = uc_fn_arg(0);
513 struct hostapd_config *conf;
514 bool changed = false;
515 uint64_t intval;
516 int i;
517
518 if (!iface)
519 return NULL;
520
521 if (!info) {
522 iface->freq = 0;
523 goto out;
524 }
525
526 if (ucv_type(info) != UC_OBJECT)
527 return NULL;
528
529 #define UPDATE_VAL(field, name) \
530 if ((intval = ucv_int64_get(ucv_object_get(info, name, NULL))) && \
531 !errno && intval != conf->field) do { \
532 conf->field = intval; \
533 changed = true; \
534 } while(0)
535
536 conf = iface->conf;
537 UPDATE_VAL(op_class, "op_class");
538 UPDATE_VAL(hw_mode, "hw_mode");
539 UPDATE_VAL(channel, "channel");
540 UPDATE_VAL(secondary_channel, "sec_channel");
541 if (!changed &&
542 (iface->bss[0]->beacon_set_done ||
543 iface->state == HAPD_IFACE_DFS))
544 return ucv_boolean_new(true);
545
546 intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL));
547 if (!errno)
548 hostapd_set_oper_centr_freq_seg0_idx(conf, intval);
549
550 intval = ucv_int64_get(ucv_object_get(info, "center_seg1_idx", NULL));
551 if (!errno)
552 hostapd_set_oper_centr_freq_seg1_idx(conf, intval);
553
554 intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
555 if (!errno)
556 hostapd_set_oper_chwidth(conf, intval);
557
558 intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL));
559 if (!errno)
560 iface->freq = intval;
561 else
562 iface->freq = 0;
563 conf->acs = 0;
564
565 out:
566 switch (iface->state) {
567 case HAPD_IFACE_ENABLED:
568 if (!hostapd_is_dfs_required(iface) ||
569 hostapd_is_dfs_chan_available(iface))
570 break;
571 wpa_printf(MSG_INFO, "DFS CAC required on new channel, restart interface");
572 /* fallthrough */
573 default:
574 uc_hostapd_disable_iface(iface);
575 break;
576 }
577
578 if (conf->channel && !iface->freq)
579 iface->freq = hostapd_hw_get_freq(iface->bss[0], conf->channel);
580
581 if (iface->state != HAPD_IFACE_ENABLED) {
582 hostapd_enable_iface(iface);
583 return ucv_boolean_new(true);
584 }
585
586 for (i = 0; i < iface->num_bss; i++) {
587 struct hostapd_data *hapd = iface->bss[i];
588 int ret;
589
590 hapd->conf->start_disabled = 0;
591 hostapd_set_freq(hapd, conf->hw_mode, iface->freq,
592 conf->channel,
593 conf->enable_edmg,
594 conf->edmg_channel,
595 conf->ieee80211n,
596 conf->ieee80211ac,
597 conf->ieee80211ax,
598 conf->ieee80211be,
599 conf->secondary_channel,
600 hostapd_get_oper_chwidth(conf),
601 hostapd_get_oper_centr_freq_seg0_idx(conf),
602 hostapd_get_oper_centr_freq_seg1_idx(conf));
603
604 ieee802_11_set_beacon(hapd);
605 }
606
607 return ucv_boolean_new(true);
608 }
609
610 static uc_value_t *
611 uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs)
612 {
613 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
614 uc_value_t *info = uc_fn_arg(0);
615 struct hostapd_config *conf;
616 struct csa_settings csa = {};
617 uint64_t intval;
618 int i, ret = 0;
619
620 if (!iface || ucv_type(info) != UC_OBJECT)
621 return NULL;
622
623 conf = iface->conf;
624 if ((intval = ucv_int64_get(ucv_object_get(info, "csa_count", NULL))) && !errno)
625 csa.cs_count = intval;
626 if ((intval = ucv_int64_get(ucv_object_get(info, "sec_channel", NULL))) && !errno)
627 csa.freq_params.sec_channel_offset = intval;
628
629 csa.freq_params.ht_enabled = conf->ieee80211n;
630 csa.freq_params.vht_enabled = conf->ieee80211ac;
631 csa.freq_params.he_enabled = conf->ieee80211ax;
632 #ifdef CONFIG_IEEE80211BE
633 csa.freq_params.eht_enabled = conf->ieee80211be;
634 #endif
635 intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
636 if (errno)
637 intval = hostapd_get_oper_chwidth(conf);
638 if (intval)
639 csa.freq_params.bandwidth = 40 << intval;
640 else
641 csa.freq_params.bandwidth = csa.freq_params.sec_channel_offset ? 40 : 20;
642
643 if ((intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL))) && !errno)
644 csa.freq_params.freq = intval;
645 if ((intval = ucv_int64_get(ucv_object_get(info, "center_freq1", NULL))) && !errno)
646 csa.freq_params.center_freq1 = intval;
647 if ((intval = ucv_int64_get(ucv_object_get(info, "center_freq2", NULL))) && !errno)
648 csa.freq_params.center_freq2 = intval;
649
650 for (i = 0; i < iface->num_bss; i++)
651 ret = hostapd_switch_channel(iface->bss[i], &csa);
652
653 return ucv_boolean_new(!ret);
654 }
655
656 static uc_value_t *
657 uc_hostapd_bss_rename(uc_vm_t *vm, size_t nargs)
658 {
659 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
660 uc_value_t *ifname_arg = uc_fn_arg(0);
661 char prev_ifname[IFNAMSIZ + 1];
662 struct sta_info *sta;
663 const char *ifname;
664 int ret;
665
666 if (!hapd || ucv_type(ifname_arg) != UC_STRING)
667 return NULL;
668
669 os_strlcpy(prev_ifname, hapd->conf->iface, sizeof(prev_ifname));
670 ifname = ucv_string_get(ifname_arg);
671
672 hostapd_ubus_free_bss(hapd);
673 if (interfaces->ctrl_iface_deinit)
674 interfaces->ctrl_iface_deinit(hapd);
675
676 ret = hostapd_drv_if_rename(hapd, WPA_IF_AP_BSS, NULL, ifname);
677 if (ret)
678 goto out;
679
680 for (sta = hapd->sta_list; sta; sta = sta->next) {
681 char cur_name[IFNAMSIZ + 1], new_name[IFNAMSIZ + 1];
682
683 if (!(sta->flags & WLAN_STA_WDS) || sta->pending_wds_enable)
684 continue;
685
686 snprintf(cur_name, sizeof(cur_name), "%s.sta%d", prev_ifname, sta->aid);
687 snprintf(new_name, sizeof(new_name), "%s.sta%d", ifname, sta->aid);
688 hostapd_drv_if_rename(hapd, WPA_IF_AP_VLAN, cur_name, new_name);
689 }
690
691 if (!strncmp(hapd->conf->ssid.vlan, hapd->conf->iface, sizeof(hapd->conf->ssid.vlan)))
692 os_strlcpy(hapd->conf->ssid.vlan, ifname, sizeof(hapd->conf->ssid.vlan));
693 os_strlcpy(hapd->conf->iface, ifname, sizeof(hapd->conf->iface));
694 hostapd_ubus_add_bss(hapd);
695
696 hostapd_ucode_update_interfaces();
697 out:
698 if (interfaces->ctrl_iface_init)
699 interfaces->ctrl_iface_init(hapd);
700
701 return ret ? NULL : ucv_boolean_new(true);
702 }
703
704
705 int hostapd_ucode_init(struct hapd_interfaces *ifaces)
706 {
707 static const uc_function_list_t global_fns[] = {
708 { "printf", uc_wpa_printf },
709 { "getpid", uc_wpa_getpid },
710 { "sha1", uc_wpa_sha1 },
711 { "freq_info", uc_wpa_freq_info },
712 { "add_iface", uc_hostapd_add_iface },
713 { "remove_iface", uc_hostapd_remove_iface },
714 { "udebug_set", uc_wpa_udebug_set },
715 };
716 static const uc_function_list_t bss_fns[] = {
717 { "ctrl", uc_hostapd_bss_ctrl },
718 { "set_config", uc_hostapd_bss_set_config },
719 { "rename", uc_hostapd_bss_rename },
720 { "delete", uc_hostapd_bss_delete },
721 };
722 static const uc_function_list_t iface_fns[] = {
723 { "set_bss_order", uc_hostapd_iface_set_bss_order },
724 { "add_bss", uc_hostapd_iface_add_bss },
725 { "stop", uc_hostapd_iface_stop },
726 { "start", uc_hostapd_iface_start },
727 { "switch_channel", uc_hostapd_iface_switch_channel },
728 };
729 uc_value_t *data, *proto;
730
731 interfaces = ifaces;
732 vm = wpa_ucode_create_vm();
733
734 global_type = uc_type_declare(vm, "hostapd.global", global_fns, NULL);
735 bss_type = uc_type_declare(vm, "hostapd.bss", bss_fns, NULL);
736 iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
737
738 bss_registry = ucv_array_new(vm);
739 uc_vm_registry_set(vm, "hostap.bss_registry", bss_registry);
740
741 iface_registry = ucv_array_new(vm);
742 uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
743
744 global = wpa_ucode_global_init("hostapd", global_type);
745
746 if (wpa_ucode_run(HOSTAPD_UC_PATH "hostapd.uc"))
747 goto free_vm;
748 ucv_gc(vm);
749
750 return 0;
751
752 free_vm:
753 wpa_ucode_free_vm();
754 return -1;
755 }
756
757 void hostapd_ucode_free(void)
758 {
759 if (wpa_ucode_call_prepare("shutdown") == 0)
760 ucv_put(wpa_ucode_call(0));
761 wpa_ucode_free_vm();
762 }
763
764 void hostapd_ucode_free_iface(struct hostapd_iface *iface)
765 {
766 wpa_ucode_registry_remove(iface_registry, iface->ucode.idx);
767 }
768
769 void hostapd_ucode_add_bss(struct hostapd_data *hapd)
770 {
771 uc_value_t *val;
772
773 if (wpa_ucode_call_prepare("bss_add"))
774 return;
775
776 val = hostapd_ucode_bss_get_uval(hapd);
777 uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
778 uc_value_push(ucv_get(val));
779 ucv_put(wpa_ucode_call(2));
780 ucv_gc(vm);
781 }
782
783 void hostapd_ucode_reload_bss(struct hostapd_data *hapd)
784 {
785 uc_value_t *val;
786
787 if (wpa_ucode_call_prepare("bss_reload"))
788 return;
789
790 val = hostapd_ucode_bss_get_uval(hapd);
791 uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
792 uc_value_push(ucv_get(val));
793 ucv_put(wpa_ucode_call(2));
794 ucv_gc(vm);
795 }
796
797 void hostapd_ucode_free_bss(struct hostapd_data *hapd)
798 {
799 uc_value_t *val;
800
801 val = wpa_ucode_registry_remove(bss_registry, hapd->ucode.idx);
802 if (!val)
803 return;
804
805 hapd->ucode.idx = 0;
806 if (wpa_ucode_call_prepare("bss_remove"))
807 return;
808
809 uc_value_push(ucv_string_new(hapd->conf->iface));
810 uc_value_push(ucv_get(val));
811 ucv_put(wpa_ucode_call(2));
812 ucv_gc(vm);
813 }