hostapd: add missing #ifdef for non-802.11ax builds
[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 <libubox/uloop.h>
11
12 static uc_resource_type_t *global_type, *bss_type, *iface_type;
13 static struct hapd_interfaces *interfaces;
14 static uc_value_t *global, *bss_registry, *iface_registry;
15 static uc_vm_t *vm;
16
17 static uc_value_t *
18 hostapd_ucode_bss_get_uval(struct hostapd_data *hapd)
19 {
20 uc_value_t *val;
21
22 if (hapd->ucode.idx)
23 return wpa_ucode_registry_get(bss_registry, hapd->ucode.idx);
24
25 val = uc_resource_new(bss_type, hapd);
26 wpa_ucode_registry_add(bss_registry, val, &hapd->ucode.idx);
27
28 return val;
29 }
30
31 static uc_value_t *
32 hostapd_ucode_iface_get_uval(struct hostapd_iface *hapd)
33 {
34 uc_value_t *val;
35
36 if (hapd->ucode.idx)
37 return wpa_ucode_registry_get(iface_registry, hapd->ucode.idx);
38
39 val = uc_resource_new(iface_type, hapd);
40 wpa_ucode_registry_add(iface_registry, val, &hapd->ucode.idx);
41
42 return val;
43 }
44
45 static void
46 hostapd_ucode_update_bss_list(struct hostapd_iface *iface)
47 {
48 uc_value_t *ifval, *list;
49 int i;
50
51 list = ucv_array_new(vm);
52 for (i = 0; i < iface->num_bss; i++) {
53 struct hostapd_data *hapd = iface->bss[i];
54 uc_value_t *val = hostapd_ucode_bss_get_uval(hapd);
55 uc_value_t *proto = ucv_prototype_get(val);
56
57 ucv_object_add(proto, "name", ucv_get(ucv_string_new(hapd->conf->iface)));
58 ucv_object_add(proto, "index", ucv_int64_new(i));
59 ucv_array_set(list, i, ucv_get(val));
60 }
61
62 ifval = hostapd_ucode_iface_get_uval(iface);
63 ucv_object_add(ucv_prototype_get(ifval), "bss", ucv_get(list));
64 }
65
66 static void
67 hostapd_ucode_update_interfaces(void)
68 {
69 uc_value_t *ifs = 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);
77 }
78
79 ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
80 ucv_gc(vm);
81 }
82
83 static uc_value_t *
84 uc_hostapd_add_iface(uc_vm_t *vm, size_t nargs)
85 {
86 uc_value_t *iface = uc_fn_arg(0);
87 int ret;
88
89 if (ucv_type(iface) != UC_STRING)
90 return ucv_int64_new(-1);
91
92 ret = hostapd_add_iface(interfaces, ucv_string_get(iface));
93 hostapd_ucode_update_interfaces();
94
95 return ucv_int64_new(ret);
96 }
97
98 static uc_value_t *
99 uc_hostapd_remove_iface(uc_vm_t *vm, size_t nargs)
100 {
101 uc_value_t *iface = uc_fn_arg(0);
102
103 if (ucv_type(iface) != UC_STRING)
104 return NULL;
105
106 hostapd_remove_iface(interfaces, ucv_string_get(iface));
107 hostapd_ucode_update_interfaces();
108
109 return NULL;
110 }
111
112 static uc_value_t *
113 uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
114 {
115 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
116 struct hostapd_bss_config *old_bss;
117 struct hostapd_iface *iface;
118 struct hostapd_config *conf;
119 uc_value_t *file = uc_fn_arg(0);
120 uc_value_t *index = uc_fn_arg(1);
121 unsigned int i, idx = 0;
122 int ret = -1;
123
124 if (!hapd || ucv_type(file) != UC_STRING)
125 goto out;
126
127 if (ucv_type(index) == UC_INTEGER)
128 idx = ucv_int64_get(index);
129
130 iface = hapd->iface;
131 conf = interfaces->config_read_cb(ucv_string_get(file));
132 if (!conf || idx > conf->num_bss || !conf->bss[idx])
133 goto out;
134
135 hostapd_bss_deinit_no_free(hapd);
136 hostapd_drv_stop_ap(hapd);
137 hostapd_free_hapd_data(hapd);
138
139 old_bss = hapd->conf;
140 for (i = 0; i < iface->conf->num_bss; i++)
141 if (iface->conf->bss[i] == hapd->conf)
142 iface->conf->bss[i] = conf->bss[idx];
143 hapd->conf = conf->bss[idx];
144 conf->bss[idx] = old_bss;
145 hostapd_config_free(conf);
146
147 hostapd_setup_bss(hapd, hapd == iface->bss[0], !iface->conf->mbssid);
148
149 ret = 0;
150
151 out:
152 return ucv_int64_new(ret);
153 }
154
155 static void
156 hostapd_remove_iface_bss_conf(struct hostapd_config *iconf,
157 struct hostapd_bss_config *conf)
158 {
159 int i;
160
161 for (i = 0; i < iconf->num_bss; i++)
162 if (iconf->bss[i] == conf)
163 break;
164
165 if (i == iconf->num_bss)
166 return;
167
168 for (i++; i < iconf->num_bss; i++)
169 iconf->bss[i - 1] = iconf->bss[i];
170 iconf->num_bss--;
171 }
172
173
174 static uc_value_t *
175 uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
176 {
177 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
178 struct hostapd_iface *iface;
179 int i, idx;
180
181 if (!hapd || hapd == hapd->iface->bss[0])
182 return NULL;
183
184 iface = hapd->iface;
185 for (idx = 0; idx < iface->num_bss; idx++)
186 if (iface->bss[idx] == hapd)
187 break;
188
189 if (idx == iface->num_bss)
190 return NULL;
191
192 for (i = idx + 1; i < iface->num_bss; i++)
193 iface->bss[i - 1] = iface->bss[i];
194 iface->num_bss--;
195
196 hostapd_drv_stop_ap(hapd);
197 hostapd_bss_deinit(hapd);
198 hostapd_remove_iface_bss_conf(iface->conf, hapd->conf);
199 hostapd_config_free_bss(hapd->conf);
200 os_free(hapd);
201
202 hostapd_ucode_update_bss_list(iface);
203 ucv_gc(vm);
204
205 return NULL;
206 }
207
208 static uc_value_t *
209 uc_hostapd_iface_add_bss(uc_vm_t *vm, size_t nargs)
210 {
211 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
212 struct hostapd_bss_config *bss;
213 struct hostapd_config *conf;
214 struct hostapd_data *hapd;
215 uc_value_t *file = uc_fn_arg(0);
216 uc_value_t *index = uc_fn_arg(1);
217 unsigned int idx = 0;
218 uc_value_t *ret = NULL;
219
220 if (!iface || ucv_type(file) != UC_STRING)
221 goto out;
222
223 if (ucv_type(index) == UC_INTEGER)
224 idx = ucv_int64_get(index);
225
226 conf = interfaces->config_read_cb(ucv_string_get(file));
227 if (!conf || idx > conf->num_bss || !conf->bss[idx])
228 goto out;
229
230 bss = conf->bss[idx];
231 hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
232 if (!hapd)
233 goto out;
234
235 hapd->driver = iface->bss[0]->driver;
236 hapd->drv_priv = iface->bss[0]->drv_priv;
237 if (interfaces->ctrl_iface_init &&
238 interfaces->ctrl_iface_init(hapd) < 0)
239 goto free_hapd;
240
241 if (iface->state == HAPD_IFACE_ENABLED &&
242 hostapd_setup_bss(hapd, -1, true))
243 goto deinit_ctrl;
244
245 iface->bss = os_realloc_array(iface->bss, iface->num_bss + 1,
246 sizeof(*iface->bss));
247 iface->bss[iface->num_bss++] = hapd;
248
249 iface->conf->bss = os_realloc_array(iface->conf->bss,
250 iface->conf->num_bss + 1,
251 sizeof(*iface->conf->bss));
252 iface->conf->bss[iface->conf->num_bss] = bss;
253 conf->bss[idx] = NULL;
254 ret = hostapd_ucode_bss_get_uval(hapd);
255 hostapd_ucode_update_bss_list(iface);
256 goto out;
257
258 deinit_ctrl:
259 if (interfaces->ctrl_iface_deinit)
260 interfaces->ctrl_iface_deinit(hapd);
261 free_hapd:
262 hostapd_free_hapd_data(hapd);
263 os_free(hapd);
264 out:
265 hostapd_config_free(conf);
266 return ret;
267 }
268
269 static uc_value_t *
270 uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs)
271 {
272 struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
273 uc_value_t *arg = uc_fn_arg(0);
274 struct sockaddr_storage from = {};
275 static char reply[4096];
276 int reply_len;
277
278 if (!hapd || !interfaces->ctrl_iface_recv ||
279 ucv_type(arg) != UC_STRING)
280 return NULL;
281
282 reply_len = interfaces->ctrl_iface_recv(hapd, ucv_string_get(arg),
283 reply, sizeof(reply),
284 &from, sizeof(from));
285 if (reply_len < 0)
286 return NULL;
287
288 if (reply_len && reply[reply_len - 1] == '\n')
289 reply_len--;
290
291 return ucv_string_new_length(reply, reply_len);
292 }
293
294 static uc_value_t *
295 uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs)
296 {
297 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
298 int i;
299
300 for (i = 0; i < iface->num_bss; i++) {
301 struct hostapd_data *hapd = iface->bss[i];
302
303 hostapd_drv_stop_ap(hapd);
304 hapd->started = 0;
305 }
306 }
307
308 static uc_value_t *
309 uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs)
310 {
311 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
312 uc_value_t *info = uc_fn_arg(0);
313 struct hostapd_config *conf;
314 uint64_t intval;
315 int i;
316
317 if (!iface)
318 return NULL;
319
320 if (!info)
321 goto out;
322
323 if (ucv_type(info) != UC_OBJECT)
324 return NULL;
325
326 conf = iface->conf;
327 if ((intval = ucv_int64_get(ucv_object_get(info, "op_class", NULL))) && !errno)
328 conf->op_class = intval;
329 if ((intval = ucv_int64_get(ucv_object_get(info, "hw_mode", NULL))) && !errno)
330 conf->hw_mode = intval;
331 if ((intval = ucv_int64_get(ucv_object_get(info, "channel", NULL))) && !errno)
332 conf->channel = intval;
333 if ((intval = ucv_int64_get(ucv_object_get(info, "sec_channel", NULL))) && !errno)
334 conf->secondary_channel = intval;
335 #ifdef CONFIG_IEEE80211AC
336 if ((intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL))) && !errno) {
337 conf->vht_oper_centr_freq_seg0_idx = intval;
338 #ifdef CONFIG_IEEE80211AX
339 conf->he_oper_centr_freq_seg0_idx = intval;
340 #endif
341 #ifdef CONFIG_IEEE80211BE
342 conf->eht_oper_centr_freq_seg0_idx = intval;
343 #endif
344 }
345 if ((intval = ucv_int64_get(ucv_object_get(info, "center_seg1_idx", NULL))) && !errno) {
346 conf->vht_oper_centr_freq_seg1_idx = intval;
347 #ifdef CONFIG_IEEE80211AX
348 conf->he_oper_centr_freq_seg1_idx = intval;
349 #endif
350 #ifdef CONFIG_IEEE80211BE
351 conf->eht_oper_centr_freq_seg1_idx = intval;
352 #endif
353 }
354 intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
355 if (!errno) {
356 conf->vht_oper_chwidth = intval;
357 #ifdef CONFIG_IEEE80211AX
358 conf->he_oper_chwidth = intval;
359 #endif
360 #ifdef CONFIG_IEEE80211BE
361 conf->eht_oper_chwidth = intval;
362 #endif
363 }
364 #endif
365
366 out:
367 if (conf->channel)
368 iface->freq = hostapd_hw_get_freq(iface->bss[0], conf->channel);
369
370 for (i = 0; i < iface->num_bss; i++) {
371 struct hostapd_data *hapd = iface->bss[i];
372 int ret;
373
374 hapd->started = 1;
375 hostapd_set_freq(hapd, conf->hw_mode, iface->freq,
376 conf->channel,
377 conf->enable_edmg,
378 conf->edmg_channel,
379 conf->ieee80211n,
380 conf->ieee80211ac,
381 conf->ieee80211ax,
382 conf->ieee80211be,
383 conf->secondary_channel,
384 hostapd_get_oper_chwidth(conf),
385 hostapd_get_oper_centr_freq_seg0_idx(conf),
386 hostapd_get_oper_centr_freq_seg1_idx(conf));
387
388 ieee802_11_set_beacon(hapd);
389 }
390
391 return ucv_boolean_new(true);
392 }
393
394 static uc_value_t *
395 uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs)
396 {
397 struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
398 uc_value_t *info = uc_fn_arg(0);
399 struct hostapd_config *conf;
400 struct csa_settings csa = {};
401 uint64_t intval;
402 int i, ret = 0;
403
404 if (!iface || ucv_type(info) != UC_OBJECT)
405 return NULL;
406
407 conf = iface->conf;
408 if ((intval = ucv_int64_get(ucv_object_get(info, "csa_count", NULL))) && !errno)
409 csa.cs_count = intval;
410 if ((intval = ucv_int64_get(ucv_object_get(info, "sec_channel", NULL))) && !errno)
411 csa.freq_params.sec_channel_offset = intval;
412
413 csa.freq_params.ht_enabled = conf->ieee80211n;
414 csa.freq_params.vht_enabled = conf->ieee80211ac;
415 csa.freq_params.he_enabled = conf->ieee80211ax;
416 #ifdef CONFIG_IEEE80211BE
417 csa.freq_params.eht_enabled = conf->ieee80211be;
418 #endif
419 intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
420 if (errno)
421 intval = hostapd_get_oper_chwidth(conf);
422 if (intval)
423 csa.freq_params.bandwidth = 40 << intval;
424 else
425 csa.freq_params.bandwidth = csa.freq_params.sec_channel_offset ? 40 : 20;
426
427 if ((intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL))) && !errno)
428 csa.freq_params.freq = intval;
429 if ((intval = ucv_int64_get(ucv_object_get(info, "center_freq1", NULL))) && !errno)
430 csa.freq_params.center_freq1 = intval;
431 if ((intval = ucv_int64_get(ucv_object_get(info, "center_freq2", NULL))) && !errno)
432 csa.freq_params.center_freq2 = intval;
433
434 for (i = 0; i < iface->num_bss; i++)
435 ret = hostapd_switch_channel(iface->bss[i], &csa);
436
437 return ucv_boolean_new(!ret);
438 }
439
440 int hostapd_ucode_init(struct hapd_interfaces *ifaces)
441 {
442 static const uc_function_list_t global_fns[] = {
443 { "printf", uc_wpa_printf },
444 { "getpid", uc_wpa_getpid },
445 { "sha1", uc_wpa_sha1 },
446 { "freq_info", uc_wpa_freq_info },
447 { "add_iface", uc_hostapd_add_iface },
448 { "remove_iface", uc_hostapd_remove_iface },
449 };
450 static const uc_function_list_t bss_fns[] = {
451 { "ctrl", uc_hostapd_bss_ctrl },
452 { "set_config", uc_hostapd_bss_set_config },
453 { "delete", uc_hostapd_bss_delete },
454 };
455 static const uc_function_list_t iface_fns[] = {
456 { "add_bss", uc_hostapd_iface_add_bss },
457 { "stop", uc_hostapd_iface_stop },
458 { "start", uc_hostapd_iface_start },
459 { "switch_channel", uc_hostapd_iface_switch_channel },
460 };
461 uc_value_t *data, *proto;
462
463 interfaces = ifaces;
464 vm = wpa_ucode_create_vm();
465
466 global_type = uc_type_declare(vm, "hostapd.global", global_fns, NULL);
467 bss_type = uc_type_declare(vm, "hostapd.bss", bss_fns, NULL);
468 iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
469
470 bss_registry = ucv_array_new(vm);
471 uc_vm_registry_set(vm, "hostap.bss_registry", bss_registry);
472
473 iface_registry = ucv_array_new(vm);
474 uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
475
476 global = wpa_ucode_global_init("hostapd", global_type);
477
478 if (wpa_ucode_run(HOSTAPD_UC_PATH "hostapd.uc"))
479 goto free_vm;
480 ucv_gc(vm);
481
482 return 0;
483
484 free_vm:
485 wpa_ucode_free_vm();
486 return -1;
487 }
488
489 void hostapd_ucode_free(void)
490 {
491 if (wpa_ucode_call_prepare("shutdown") == 0)
492 ucv_put(wpa_ucode_call(0));
493 wpa_ucode_free_vm();
494 }
495
496 void hostapd_ucode_free_iface(struct hostapd_iface *iface)
497 {
498 wpa_ucode_registry_remove(iface_registry, iface->ucode.idx);
499 }
500
501 void hostapd_ucode_add_bss(struct hostapd_data *hapd)
502 {
503 uc_value_t *val;
504
505 if (wpa_ucode_call_prepare("bss_add"))
506 return;
507
508 val = hostapd_ucode_bss_get_uval(hapd);
509 uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
510 uc_value_push(ucv_get(val));
511 ucv_put(wpa_ucode_call(2));
512 ucv_gc(vm);
513 }
514
515 void hostapd_ucode_reload_bss(struct hostapd_data *hapd)
516 {
517 uc_value_t *val;
518
519 if (wpa_ucode_call_prepare("bss_reload"))
520 return;
521
522 val = hostapd_ucode_bss_get_uval(hapd);
523 uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
524 uc_value_push(ucv_get(val));
525 ucv_put(wpa_ucode_call(2));
526 ucv_gc(vm);
527 }
528
529 void hostapd_ucode_free_bss(struct hostapd_data *hapd)
530 {
531 uc_value_t *val;
532
533 val = wpa_ucode_registry_remove(bss_registry, hapd->ucode.idx);
534 if (!val)
535 return;
536
537 hapd->ucode.idx = 0;
538 if (wpa_ucode_call_prepare("bss_remove"))
539 return;
540
541 uc_value_push(ucv_string_new(hapd->conf->iface));
542 uc_value_push(ucv_get(val));
543 ucv_put(wpa_ucode_call(2));
544 ucv_gc(vm);
545 }