hostapd: fix more AP+STA issues
[openwrt/staging/jow.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 uc_value_t *
115 uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
116 {
117 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
118 struct hostapd_bss_config *old_bss;
119 struct hostapd_iface *iface;
120 struct hostapd_config *conf;
121 uc_value_t *file = uc_fn_arg(0);
122 uc_value_t *index = uc_fn_arg(1);
123 uc_value_t *files_only = uc_fn_arg(2);
124 unsigned int i, idx = 0;
125 int ret = -1;
126
127 if (!hapd || ucv_type(file) != UC_STRING)
128 goto out;
129
130 if (ucv_type(index) == UC_INTEGER)
131 idx = ucv_int64_get(index);
132
133 iface = hapd->iface;
134 conf = interfaces->config_read_cb(ucv_string_get(file));
135 if (!conf)
136 goto out;
137
138 if (idx > conf->num_bss || !conf->bss[idx])
139 goto free;
140
141 if (ucv_boolean_get(files_only)) {
142 struct hostapd_bss_config *bss = conf->bss[idx];
143 struct hostapd_bss_config *old_bss = hapd->conf;
144
145 #define swap_field(name) \
146 do { \
147 void *ptr = old_bss->name; \
148 old_bss->name = bss->name; \
149 bss->name = ptr; \
150 } while (0)
151
152 swap_field(ssid.wpa_psk_file);
153 goto done;
154 }
155
156 hostapd_bss_deinit_no_free(hapd);
157 hostapd_drv_stop_ap(hapd);
158 hostapd_free_hapd_data(hapd);
159
160 old_bss = hapd->conf;
161 for (i = 0; i < iface->conf->num_bss; i++)
162 if (iface->conf->bss[i] == hapd->conf)
163 iface->conf->bss[i] = conf->bss[idx];
164 hapd->conf = conf->bss[idx];
165 conf->bss[idx] = old_bss;
166
167 hostapd_setup_bss(hapd, hapd == iface->bss[0], true);
168 hostapd_ucode_update_interfaces();
169
170 done:
171 ret = 0;
172 free:
173 hostapd_config_free(conf);
174 out:
175 return ucv_int64_new(ret);
176 }
177
178 static void
179 hostapd_remove_iface_bss_conf(struct hostapd_config *iconf,
180 struct hostapd_bss_config *conf)
181 {
182 int i;
183
184 for (i = 0; i < iconf->num_bss; i++)
185 if (iconf->bss[i] == conf)
186 break;
187
188 if (i == iconf->num_bss)
189 return;
190
191 for (i++; i < iconf->num_bss; i++)
192 iconf->bss[i - 1] = iconf->bss[i];
193 iconf->num_bss--;
194 }
195
196
197 static uc_value_t *
198 uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
199 {
200 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
201 struct hostapd_iface *iface;
202 int i, idx;
203
204 if (!hapd)
205 return NULL;
206
207 iface = hapd->iface;
208 if (iface->num_bss == 1) {
209 wpa_printf(MSG_ERROR, "trying to delete last bss of an iface: %s\n", hapd->conf->iface);
210 return NULL;
211 }
212
213 for (idx = 0; idx < iface->num_bss; idx++)
214 if (iface->bss[idx] == hapd)
215 break;
216
217 if (idx == iface->num_bss)
218 return NULL;
219
220 for (i = idx + 1; i < iface->num_bss; i++)
221 iface->bss[i - 1] = iface->bss[i];
222
223 iface->num_bss--;
224
225 iface->bss[0]->interface_added = 0;
226 hostapd_drv_set_first_bss(iface->bss[0]);
227 hapd->interface_added = 1;
228
229 hostapd_drv_stop_ap(hapd);
230 hostapd_bss_deinit(hapd);
231 hostapd_remove_iface_bss_conf(iface->conf, hapd->conf);
232 hostapd_config_free_bss(hapd->conf);
233 os_free(hapd);
234
235 hostapd_ucode_update_interfaces();
236 ucv_gc(vm);
237
238 return NULL;
239 }
240
241 static uc_value_t *
242 uc_hostapd_iface_add_bss(uc_vm_t *vm, size_t nargs)
243 {
244 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
245 struct hostapd_bss_config *bss;
246 struct hostapd_config *conf;
247 struct hostapd_data *hapd;
248 uc_value_t *file = uc_fn_arg(0);
249 uc_value_t *index = uc_fn_arg(1);
250 unsigned int idx = 0;
251 uc_value_t *ret = NULL;
252
253 if (!iface || ucv_type(file) != UC_STRING)
254 goto out;
255
256 if (ucv_type(index) == UC_INTEGER)
257 idx = ucv_int64_get(index);
258
259 conf = interfaces->config_read_cb(ucv_string_get(file));
260 if (!conf || idx > conf->num_bss || !conf->bss[idx])
261 goto out;
262
263 bss = conf->bss[idx];
264 hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
265 if (!hapd)
266 goto out;
267
268 hapd->driver = iface->bss[0]->driver;
269 hapd->drv_priv = iface->bss[0]->drv_priv;
270 if (interfaces->ctrl_iface_init &&
271 interfaces->ctrl_iface_init(hapd) < 0)
272 goto free_hapd;
273
274 if (iface->state == HAPD_IFACE_ENABLED &&
275 hostapd_setup_bss(hapd, -1, true))
276 goto deinit_ctrl;
277
278 iface->bss = os_realloc_array(iface->bss, iface->num_bss + 1,
279 sizeof(*iface->bss));
280 iface->bss[iface->num_bss++] = hapd;
281
282 iface->conf->bss = os_realloc_array(iface->conf->bss,
283 iface->conf->num_bss + 1,
284 sizeof(*iface->conf->bss));
285 iface->conf->bss[iface->conf->num_bss] = bss;
286 conf->bss[idx] = NULL;
287 ret = hostapd_ucode_bss_get_uval(hapd);
288 hostapd_ucode_update_interfaces();
289 goto out;
290
291 deinit_ctrl:
292 if (interfaces->ctrl_iface_deinit)
293 interfaces->ctrl_iface_deinit(hapd);
294 free_hapd:
295 hostapd_free_hapd_data(hapd);
296 os_free(hapd);
297 out:
298 hostapd_config_free(conf);
299 return ret;
300 }
301
302 static uc_value_t *
303 uc_hostapd_iface_set_bss_order(uc_vm_t *vm, size_t nargs)
304 {
305 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
306 uc_value_t *bss_list = uc_fn_arg(0);
307 struct hostapd_data **new_bss;
308 struct hostapd_bss_config **new_conf;
309
310 if (!iface)
311 return NULL;
312
313 if (ucv_type(bss_list) != UC_ARRAY ||
314 ucv_array_length(bss_list) != iface->num_bss)
315 return NULL;
316
317 new_bss = calloc(iface->num_bss, sizeof(*new_bss));
318 new_conf = calloc(iface->num_bss, sizeof(*new_conf));
319 for (size_t i = 0; i < iface->num_bss; i++) {
320 struct hostapd_data *bss;
321
322 bss = ucv_resource_data(ucv_array_get(bss_list, i), "hostapd.bss");
323 if (bss->iface != iface)
324 goto free;
325
326 for (size_t k = 0; k < i; k++)
327 if (new_bss[k] == bss)
328 goto free;
329
330 new_bss[i] = bss;
331 new_conf[i] = bss->conf;
332 }
333
334 new_bss[0]->interface_added = 0;
335 for (size_t i = 1; i < iface->num_bss; i++)
336 new_bss[i]->interface_added = 1;
337
338 free(iface->bss);
339 iface->bss = new_bss;
340
341 free(iface->conf->bss);
342 iface->conf->bss = new_conf;
343 iface->conf->num_bss = iface->num_bss;
344 hostapd_drv_set_first_bss(iface->bss[0]);
345
346 return ucv_boolean_new(true);
347
348 free:
349 free(new_bss);
350 free(new_conf);
351 return NULL;
352 }
353
354 static uc_value_t *
355 uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs)
356 {
357 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
358 uc_value_t *arg = uc_fn_arg(0);
359 struct sockaddr_storage from = {};
360 static char reply[4096];
361 int reply_len;
362
363 if (!hapd || !interfaces->ctrl_iface_recv ||
364 ucv_type(arg) != UC_STRING)
365 return NULL;
366
367 reply_len = interfaces->ctrl_iface_recv(hapd, ucv_string_get(arg),
368 reply, sizeof(reply),
369 &from, sizeof(from));
370 if (reply_len < 0)
371 return NULL;
372
373 if (reply_len && reply[reply_len - 1] == '\n')
374 reply_len--;
375
376 return ucv_string_new_length(reply, reply_len);
377 }
378
379 static uc_value_t *
380 uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs)
381 {
382 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
383 int i;
384
385 switch (iface->state) {
386 case HAPD_IFACE_ENABLED:
387 case HAPD_IFACE_DISABLED:
388 break;
389 #ifdef CONFIG_ACS
390 case HAPD_IFACE_ACS:
391 acs_cleanup(iface);
392 iface->scan_cb = NULL;
393 /* fallthrough */
394 #endif
395 default:
396 hostapd_disable_iface(iface);
397 break;
398 }
399
400 if (iface->state != HAPD_IFACE_ENABLED)
401 hostapd_disable_iface(iface);
402
403 for (i = 0; i < iface->num_bss; i++) {
404 struct hostapd_data *hapd = iface->bss[i];
405
406 hostapd_drv_stop_ap(hapd);
407 hapd->beacon_set_done = 0;
408 }
409
410 return NULL;
411 }
412
413 static uc_value_t *
414 uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs)
415 {
416 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
417 uc_value_t *info = uc_fn_arg(0);
418 struct hostapd_config *conf;
419 bool changed = false;
420 uint64_t intval;
421 int i;
422
423 if (!iface)
424 return NULL;
425
426 if (!info) {
427 iface->freq = 0;
428 goto out;
429 }
430
431 if (ucv_type(info) != UC_OBJECT)
432 return NULL;
433
434 #define UPDATE_VAL(field, name) \
435 if ((intval = ucv_int64_get(ucv_object_get(info, name, NULL))) && \
436 !errno && intval != conf->field) do { \
437 conf->field = intval; \
438 changed = true; \
439 } while(0)
440
441 conf = iface->conf;
442 UPDATE_VAL(op_class, "op_class");
443 UPDATE_VAL(hw_mode, "hw_mode");
444 UPDATE_VAL(channel, "channel");
445 UPDATE_VAL(secondary_channel, "sec_channel");
446 if (!changed &&
447 (iface->bss[0]->beacon_set_done ||
448 iface->state == HAPD_IFACE_DFS))
449 return ucv_boolean_new(true);
450
451 intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL));
452 if (!errno)
453 hostapd_set_oper_centr_freq_seg0_idx(conf, intval);
454
455 intval = ucv_int64_get(ucv_object_get(info, "center_seg1_idx", NULL));
456 if (!errno)
457 hostapd_set_oper_centr_freq_seg1_idx(conf, intval);
458
459 intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
460 if (!errno)
461 hostapd_set_oper_chwidth(conf, intval);
462
463 intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL));
464 if (!errno)
465 iface->freq = intval;
466 else
467 iface->freq = 0;
468 conf->acs = 0;
469
470 out:
471 switch (iface->state) {
472 case HAPD_IFACE_DISABLED:
473 break;
474 case HAPD_IFACE_ENABLED:
475 if (!hostapd_is_dfs_required(iface) ||
476 hostapd_is_dfs_chan_available(iface))
477 break;
478 wpa_printf(MSG_INFO, "DFS CAC required on new channel, restart interface");
479 /* fallthrough */
480 default:
481 hostapd_disable_iface(iface);
482 break;
483 }
484
485 if (conf->channel && !iface->freq)
486 iface->freq = hostapd_hw_get_freq(iface->bss[0], conf->channel);
487
488 if (iface->state != HAPD_IFACE_ENABLED) {
489 hostapd_enable_iface(iface);
490 return ucv_boolean_new(true);
491 }
492
493 for (i = 0; i < iface->num_bss; i++) {
494 struct hostapd_data *hapd = iface->bss[i];
495 int ret;
496
497 hapd->conf->start_disabled = 0;
498 hostapd_set_freq(hapd, conf->hw_mode, iface->freq,
499 conf->channel,
500 conf->enable_edmg,
501 conf->edmg_channel,
502 conf->ieee80211n,
503 conf->ieee80211ac,
504 conf->ieee80211ax,
505 conf->ieee80211be,
506 conf->secondary_channel,
507 hostapd_get_oper_chwidth(conf),
508 hostapd_get_oper_centr_freq_seg0_idx(conf),
509 hostapd_get_oper_centr_freq_seg1_idx(conf));
510
511 ieee802_11_set_beacon(hapd);
512 }
513
514 return ucv_boolean_new(true);
515 }
516
517 static uc_value_t *
518 uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs)
519 {
520 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
521 uc_value_t *info = uc_fn_arg(0);
522 struct hostapd_config *conf;
523 struct csa_settings csa = {};
524 uint64_t intval;
525 int i, ret = 0;
526
527 if (!iface || ucv_type(info) != UC_OBJECT)
528 return NULL;
529
530 conf = iface->conf;
531 if ((intval = ucv_int64_get(ucv_object_get(info, "csa_count", NULL))) && !errno)
532 csa.cs_count = intval;
533 if ((intval = ucv_int64_get(ucv_object_get(info, "sec_channel", NULL))) && !errno)
534 csa.freq_params.sec_channel_offset = intval;
535
536 csa.freq_params.ht_enabled = conf->ieee80211n;
537 csa.freq_params.vht_enabled = conf->ieee80211ac;
538 csa.freq_params.he_enabled = conf->ieee80211ax;
539 #ifdef CONFIG_IEEE80211BE
540 csa.freq_params.eht_enabled = conf->ieee80211be;
541 #endif
542 intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
543 if (errno)
544 intval = hostapd_get_oper_chwidth(conf);
545 if (intval)
546 csa.freq_params.bandwidth = 40 << intval;
547 else
548 csa.freq_params.bandwidth = csa.freq_params.sec_channel_offset ? 40 : 20;
549
550 if ((intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL))) && !errno)
551 csa.freq_params.freq = intval;
552 if ((intval = ucv_int64_get(ucv_object_get(info, "center_freq1", NULL))) && !errno)
553 csa.freq_params.center_freq1 = intval;
554 if ((intval = ucv_int64_get(ucv_object_get(info, "center_freq2", NULL))) && !errno)
555 csa.freq_params.center_freq2 = intval;
556
557 for (i = 0; i < iface->num_bss; i++)
558 ret = hostapd_switch_channel(iface->bss[i], &csa);
559
560 return ucv_boolean_new(!ret);
561 }
562
563 static uc_value_t *
564 uc_hostapd_bss_rename(uc_vm_t *vm, size_t nargs)
565 {
566 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
567 uc_value_t *ifname_arg = uc_fn_arg(0);
568 char prev_ifname[IFNAMSIZ + 1];
569 struct sta_info *sta;
570 const char *ifname;
571 int ret;
572
573 if (!hapd || ucv_type(ifname_arg) != UC_STRING)
574 return NULL;
575
576 os_strlcpy(prev_ifname, hapd->conf->iface, sizeof(prev_ifname));
577 ifname = ucv_string_get(ifname_arg);
578
579 hostapd_ubus_free_bss(hapd);
580 if (interfaces->ctrl_iface_deinit)
581 interfaces->ctrl_iface_deinit(hapd);
582
583 ret = hostapd_drv_if_rename(hapd, WPA_IF_AP_BSS, NULL, ifname);
584 if (ret)
585 goto out;
586
587 for (sta = hapd->sta_list; sta; sta = sta->next) {
588 char cur_name[IFNAMSIZ + 1], new_name[IFNAMSIZ + 1];
589
590 if (!(sta->flags & WLAN_STA_WDS) || sta->pending_wds_enable)
591 continue;
592
593 snprintf(cur_name, sizeof(cur_name), "%s.sta%d", prev_ifname, sta->aid);
594 snprintf(new_name, sizeof(new_name), "%s.sta%d", ifname, sta->aid);
595 hostapd_drv_if_rename(hapd, WPA_IF_AP_VLAN, cur_name, new_name);
596 }
597
598 if (!strncmp(hapd->conf->ssid.vlan, hapd->conf->iface, sizeof(hapd->conf->ssid.vlan)))
599 os_strlcpy(hapd->conf->ssid.vlan, ifname, sizeof(hapd->conf->ssid.vlan));
600 os_strlcpy(hapd->conf->iface, ifname, sizeof(hapd->conf->iface));
601 hostapd_ubus_add_bss(hapd);
602
603 hostapd_ucode_update_interfaces();
604 out:
605 if (interfaces->ctrl_iface_init)
606 interfaces->ctrl_iface_init(hapd);
607
608 return ret ? NULL : ucv_boolean_new(true);
609 }
610
611
612 int hostapd_ucode_init(struct hapd_interfaces *ifaces)
613 {
614 static const uc_function_list_t global_fns[] = {
615 { "printf", uc_wpa_printf },
616 { "getpid", uc_wpa_getpid },
617 { "sha1", uc_wpa_sha1 },
618 { "freq_info", uc_wpa_freq_info },
619 { "add_iface", uc_hostapd_add_iface },
620 { "remove_iface", uc_hostapd_remove_iface },
621 };
622 static const uc_function_list_t bss_fns[] = {
623 { "ctrl", uc_hostapd_bss_ctrl },
624 { "set_config", uc_hostapd_bss_set_config },
625 { "rename", uc_hostapd_bss_rename },
626 { "delete", uc_hostapd_bss_delete },
627 };
628 static const uc_function_list_t iface_fns[] = {
629 { "set_bss_order", uc_hostapd_iface_set_bss_order },
630 { "add_bss", uc_hostapd_iface_add_bss },
631 { "stop", uc_hostapd_iface_stop },
632 { "start", uc_hostapd_iface_start },
633 { "switch_channel", uc_hostapd_iface_switch_channel },
634 };
635 uc_value_t *data, *proto;
636
637 interfaces = ifaces;
638 vm = wpa_ucode_create_vm();
639
640 global_type = uc_type_declare(vm, "hostapd.global", global_fns, NULL);
641 bss_type = uc_type_declare(vm, "hostapd.bss", bss_fns, NULL);
642 iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
643
644 bss_registry = ucv_array_new(vm);
645 uc_vm_registry_set(vm, "hostap.bss_registry", bss_registry);
646
647 iface_registry = ucv_array_new(vm);
648 uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
649
650 global = wpa_ucode_global_init("hostapd", global_type);
651
652 if (wpa_ucode_run(HOSTAPD_UC_PATH "hostapd.uc"))
653 goto free_vm;
654 ucv_gc(vm);
655
656 return 0;
657
658 free_vm:
659 wpa_ucode_free_vm();
660 return -1;
661 }
662
663 void hostapd_ucode_free(void)
664 {
665 if (wpa_ucode_call_prepare("shutdown") == 0)
666 ucv_put(wpa_ucode_call(0));
667 wpa_ucode_free_vm();
668 }
669
670 void hostapd_ucode_free_iface(struct hostapd_iface *iface)
671 {
672 wpa_ucode_registry_remove(iface_registry, iface->ucode.idx);
673 }
674
675 void hostapd_ucode_add_bss(struct hostapd_data *hapd)
676 {
677 uc_value_t *val;
678
679 if (wpa_ucode_call_prepare("bss_add"))
680 return;
681
682 val = hostapd_ucode_bss_get_uval(hapd);
683 uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
684 uc_value_push(ucv_get(val));
685 ucv_put(wpa_ucode_call(2));
686 ucv_gc(vm);
687 }
688
689 void hostapd_ucode_reload_bss(struct hostapd_data *hapd)
690 {
691 uc_value_t *val;
692
693 if (wpa_ucode_call_prepare("bss_reload"))
694 return;
695
696 val = hostapd_ucode_bss_get_uval(hapd);
697 uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
698 uc_value_push(ucv_get(val));
699 ucv_put(wpa_ucode_call(2));
700 ucv_gc(vm);
701 }
702
703 void hostapd_ucode_free_bss(struct hostapd_data *hapd)
704 {
705 uc_value_t *val;
706
707 val = wpa_ucode_registry_remove(bss_registry, hapd->ucode.idx);
708 if (!val)
709 return;
710
711 hapd->ucode.idx = 0;
712 if (wpa_ucode_call_prepare("bss_remove"))
713 return;
714
715 uc_value_push(ucv_string_new(hapd->conf->iface));
716 uc_value_push(ucv_get(val));
717 ucv_put(wpa_ucode_call(2));
718 ucv_gc(vm);
719 }