3 #include "utils/includes.h"
4 #include "utils/common.h"
5 #include "utils/ucode.h"
8 #include "hw_features.h"
9 #include "ap_drv_ops.h"
12 #include <libubox/uloop.h>
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
;
20 hostapd_ucode_bss_get_uval(struct hostapd_data
*hapd
)
25 return wpa_ucode_registry_get(bss_registry
, hapd
->ucode
.idx
);
27 val
= uc_resource_new(bss_type
, hapd
);
28 hapd
->ucode
.idx
= wpa_ucode_registry_add(bss_registry
, val
);
34 hostapd_ucode_iface_get_uval(struct hostapd_iface
*hapd
)
39 return wpa_ucode_registry_get(iface_registry
, hapd
->ucode
.idx
);
41 val
= uc_resource_new(iface_type
, hapd
);
42 hapd
->ucode
.idx
= wpa_ucode_registry_add(iface_registry
, val
);
48 hostapd_ucode_update_bss_list(struct hostapd_iface
*iface
, uc_value_t
*if_bss
, uc_value_t
*bss
)
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
);
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
));
61 ucv_object_add(if_bss
, iface
->phy
, ucv_get(list
));
65 hostapd_ucode_update_interfaces(void)
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
);
72 for (i
= 0; i
< interfaces
->count
; i
++) {
73 struct hostapd_iface
*iface
= interfaces
->iface
[i
];
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
);
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
));
86 uc_hostapd_add_iface(uc_vm_t
*vm
, size_t nargs
)
88 uc_value_t
*iface
= uc_fn_arg(0);
91 if (ucv_type(iface
) != UC_STRING
)
92 return ucv_int64_new(-1);
94 ret
= hostapd_add_iface(interfaces
, ucv_string_get(iface
));
95 hostapd_ucode_update_interfaces();
97 return ucv_int64_new(ret
);
101 uc_hostapd_remove_iface(uc_vm_t
*vm
, size_t nargs
)
103 uc_value_t
*iface
= uc_fn_arg(0);
105 if (ucv_type(iface
) != UC_STRING
)
108 hostapd_remove_iface(interfaces
, ucv_string_get(iface
));
109 hostapd_ucode_update_interfaces();
115 uc_hostapd_bss_set_config(uc_vm_t
*vm
, size_t nargs
)
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;
127 if (!hapd
|| ucv_type(file
) != UC_STRING
)
130 if (ucv_type(index
) == UC_INTEGER
)
131 idx
= ucv_int64_get(index
);
134 conf
= interfaces
->config_read_cb(ucv_string_get(file
));
138 if (idx
> conf
->num_bss
|| !conf
->bss
[idx
])
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
;
145 #define swap_field(name) \
147 void *ptr = old_bss->name; \
148 old_bss->name = bss->name; \
152 swap_field(ssid
.wpa_psk_file
);
156 hostapd_bss_deinit_no_free(hapd
);
157 hostapd_drv_stop_ap(hapd
);
158 hostapd_free_hapd_data(hapd
);
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
;
167 hostapd_setup_bss(hapd
, hapd
== iface
->bss
[0], true);
168 hostapd_ucode_update_interfaces();
173 hostapd_config_free(conf
);
175 return ucv_int64_new(ret
);
179 hostapd_remove_iface_bss_conf(struct hostapd_config
*iconf
,
180 struct hostapd_bss_config
*conf
)
184 for (i
= 0; i
< iconf
->num_bss
; i
++)
185 if (iconf
->bss
[i
] == conf
)
188 if (i
== iconf
->num_bss
)
191 for (i
++; i
< iconf
->num_bss
; i
++)
192 iconf
->bss
[i
- 1] = iconf
->bss
[i
];
198 uc_hostapd_bss_delete(uc_vm_t
*vm
, size_t nargs
)
200 struct hostapd_data
*hapd
= uc_fn_thisval("hostapd.bss");
201 struct hostapd_iface
*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
);
213 for (idx
= 0; idx
< iface
->num_bss
; idx
++)
214 if (iface
->bss
[idx
] == hapd
)
217 if (idx
== iface
->num_bss
)
220 for (i
= idx
+ 1; i
< iface
->num_bss
; i
++)
221 iface
->bss
[i
- 1] = iface
->bss
[i
];
225 iface
->bss
[0]->interface_added
= 0;
226 hostapd_drv_set_first_bss(iface
->bss
[0]);
227 hapd
->interface_added
= 1;
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
);
235 hostapd_ucode_update_interfaces();
242 uc_hostapd_iface_add_bss(uc_vm_t
*vm
, size_t nargs
)
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
;
253 if (!iface
|| ucv_type(file
) != UC_STRING
)
256 if (ucv_type(index
) == UC_INTEGER
)
257 idx
= ucv_int64_get(index
);
259 conf
= interfaces
->config_read_cb(ucv_string_get(file
));
260 if (!conf
|| idx
> conf
->num_bss
|| !conf
->bss
[idx
])
263 bss
= conf
->bss
[idx
];
264 hapd
= hostapd_alloc_bss_data(iface
, iface
->conf
, bss
);
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)
274 if (iface
->state
== HAPD_IFACE_ENABLED
&&
275 hostapd_setup_bss(hapd
, -1, true))
278 iface
->bss
= os_realloc_array(iface
->bss
, iface
->num_bss
+ 1,
279 sizeof(*iface
->bss
));
280 iface
->bss
[iface
->num_bss
++] = hapd
;
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();
292 if (interfaces
->ctrl_iface_deinit
)
293 interfaces
->ctrl_iface_deinit(hapd
);
295 hostapd_free_hapd_data(hapd
);
298 hostapd_config_free(conf
);
303 uc_hostapd_iface_set_bss_order(uc_vm_t
*vm
, size_t nargs
)
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
;
313 if (ucv_type(bss_list
) != UC_ARRAY
||
314 ucv_array_length(bss_list
) != iface
->num_bss
)
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
;
322 bss
= ucv_resource_data(ucv_array_get(bss_list
, i
), "hostapd.bss");
323 if (bss
->iface
!= iface
)
326 for (size_t k
= 0; k
< i
; k
++)
327 if (new_bss
[k
] == bss
)
331 new_conf
[i
] = bss
->conf
;
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;
339 iface
->bss
= new_bss
;
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]);
346 return ucv_boolean_new(true);
355 uc_hostapd_bss_ctrl(uc_vm_t
*vm
, size_t nargs
)
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];
363 if (!hapd
|| !interfaces
->ctrl_iface_recv
||
364 ucv_type(arg
) != UC_STRING
)
367 reply_len
= interfaces
->ctrl_iface_recv(hapd
, ucv_string_get(arg
),
368 reply
, sizeof(reply
),
369 &from
, sizeof(from
));
373 if (reply_len
&& reply
[reply_len
- 1] == '\n')
376 return ucv_string_new_length(reply
, reply_len
);
380 uc_hostapd_iface_stop(uc_vm_t
*vm
, size_t nargs
)
382 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
386 if (iface
->state
== HAPD_IFACE_ACS
) {
388 iface
->scan_cb
= NULL
;
389 hostapd_disable_iface(iface
);
393 for (i
= 0; i
< iface
->num_bss
; i
++) {
394 struct hostapd_data
*hapd
= iface
->bss
[i
];
396 hostapd_drv_stop_ap(hapd
);
397 hapd
->beacon_set_done
= 0;
404 uc_hostapd_iface_start(uc_vm_t
*vm
, size_t nargs
)
406 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
407 uc_value_t
*info
= uc_fn_arg(0);
408 struct hostapd_config
*conf
;
419 if (ucv_type(info
) != UC_OBJECT
)
423 if ((intval
= ucv_int64_get(ucv_object_get(info
, "op_class", NULL
))) && !errno
)
424 conf
->op_class
= intval
;
425 if ((intval
= ucv_int64_get(ucv_object_get(info
, "hw_mode", NULL
))) && !errno
)
426 conf
->hw_mode
= intval
;
427 if ((intval
= ucv_int64_get(ucv_object_get(info
, "channel", NULL
))) && !errno
)
428 conf
->channel
= intval
;
429 if ((intval
= ucv_int64_get(ucv_object_get(info
, "sec_channel", NULL
))) && !errno
)
430 conf
->secondary_channel
= intval
;
432 intval
= ucv_int64_get(ucv_object_get(info
, "center_seg0_idx", NULL
));
434 hostapd_set_oper_centr_freq_seg0_idx(conf
, intval
);
436 intval
= ucv_int64_get(ucv_object_get(info
, "center_seg1_idx", NULL
));
438 hostapd_set_oper_centr_freq_seg1_idx(conf
, intval
);
440 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
442 hostapd_set_oper_chwidth(conf
, intval
);
444 intval
= ucv_int64_get(ucv_object_get(info
, "frequency", NULL
));
446 iface
->freq
= intval
;
450 switch (iface
->state
) {
451 case HAPD_IFACE_DISABLED
:
453 case HAPD_IFACE_ENABLED
:
454 if (!hostapd_is_dfs_required(iface
) ||
455 hostapd_is_dfs_chan_available(iface
))
457 wpa_printf(MSG_INFO
, "DFS CAC required on new channel, restart interface");
460 hostapd_disable_iface(iface
);
464 if (conf
->channel
&& !iface
->freq
)
465 iface
->freq
= hostapd_hw_get_freq(iface
->bss
[0], conf
->channel
);
467 if (iface
->state
!= HAPD_IFACE_ENABLED
) {
468 hostapd_enable_iface(iface
);
469 return ucv_boolean_new(true);
472 for (i
= 0; i
< iface
->num_bss
; i
++) {
473 struct hostapd_data
*hapd
= iface
->bss
[i
];
476 hapd
->conf
->start_disabled
= 0;
477 hostapd_set_freq(hapd
, conf
->hw_mode
, iface
->freq
,
485 conf
->secondary_channel
,
486 hostapd_get_oper_chwidth(conf
),
487 hostapd_get_oper_centr_freq_seg0_idx(conf
),
488 hostapd_get_oper_centr_freq_seg1_idx(conf
));
490 ieee802_11_set_beacon(hapd
);
493 return ucv_boolean_new(true);
497 uc_hostapd_iface_switch_channel(uc_vm_t
*vm
, size_t nargs
)
499 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
500 uc_value_t
*info
= uc_fn_arg(0);
501 struct hostapd_config
*conf
;
502 struct csa_settings csa
= {};
506 if (!iface
|| ucv_type(info
) != UC_OBJECT
)
510 if ((intval
= ucv_int64_get(ucv_object_get(info
, "csa_count", NULL
))) && !errno
)
511 csa
.cs_count
= intval
;
512 if ((intval
= ucv_int64_get(ucv_object_get(info
, "sec_channel", NULL
))) && !errno
)
513 csa
.freq_params
.sec_channel_offset
= intval
;
515 csa
.freq_params
.ht_enabled
= conf
->ieee80211n
;
516 csa
.freq_params
.vht_enabled
= conf
->ieee80211ac
;
517 csa
.freq_params
.he_enabled
= conf
->ieee80211ax
;
518 #ifdef CONFIG_IEEE80211BE
519 csa
.freq_params
.eht_enabled
= conf
->ieee80211be
;
521 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
523 intval
= hostapd_get_oper_chwidth(conf
);
525 csa
.freq_params
.bandwidth
= 40 << intval
;
527 csa
.freq_params
.bandwidth
= csa
.freq_params
.sec_channel_offset
? 40 : 20;
529 if ((intval
= ucv_int64_get(ucv_object_get(info
, "frequency", NULL
))) && !errno
)
530 csa
.freq_params
.freq
= intval
;
531 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_freq1", NULL
))) && !errno
)
532 csa
.freq_params
.center_freq1
= intval
;
533 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_freq2", NULL
))) && !errno
)
534 csa
.freq_params
.center_freq2
= intval
;
536 for (i
= 0; i
< iface
->num_bss
; i
++)
537 ret
= hostapd_switch_channel(iface
->bss
[i
], &csa
);
539 return ucv_boolean_new(!ret
);
543 uc_hostapd_bss_rename(uc_vm_t
*vm
, size_t nargs
)
545 struct hostapd_data
*hapd
= uc_fn_thisval("hostapd.bss");
546 uc_value_t
*ifname_arg
= uc_fn_arg(0);
547 char prev_ifname
[IFNAMSIZ
+ 1];
548 struct sta_info
*sta
;
552 if (!hapd
|| ucv_type(ifname_arg
) != UC_STRING
)
555 os_strlcpy(prev_ifname
, hapd
->conf
->iface
, sizeof(prev_ifname
));
556 ifname
= ucv_string_get(ifname_arg
);
558 hostapd_ubus_free_bss(hapd
);
559 if (interfaces
->ctrl_iface_deinit
)
560 interfaces
->ctrl_iface_deinit(hapd
);
562 ret
= hostapd_drv_if_rename(hapd
, WPA_IF_AP_BSS
, NULL
, ifname
);
566 for (sta
= hapd
->sta_list
; sta
; sta
= sta
->next
) {
567 char cur_name
[IFNAMSIZ
+ 1], new_name
[IFNAMSIZ
+ 1];
569 if (!(sta
->flags
& WLAN_STA_WDS
) || sta
->pending_wds_enable
)
572 snprintf(cur_name
, sizeof(cur_name
), "%s.sta%d", prev_ifname
, sta
->aid
);
573 snprintf(new_name
, sizeof(new_name
), "%s.sta%d", ifname
, sta
->aid
);
574 hostapd_drv_if_rename(hapd
, WPA_IF_AP_VLAN
, cur_name
, new_name
);
577 if (!strncmp(hapd
->conf
->ssid
.vlan
, hapd
->conf
->iface
, sizeof(hapd
->conf
->ssid
.vlan
)))
578 os_strlcpy(hapd
->conf
->ssid
.vlan
, ifname
, sizeof(hapd
->conf
->ssid
.vlan
));
579 os_strlcpy(hapd
->conf
->iface
, ifname
, sizeof(hapd
->conf
->iface
));
580 hostapd_ubus_add_bss(hapd
);
582 hostapd_ucode_update_interfaces();
584 if (interfaces
->ctrl_iface_init
)
585 interfaces
->ctrl_iface_init(hapd
);
587 return ret
? NULL
: ucv_boolean_new(true);
591 int hostapd_ucode_init(struct hapd_interfaces
*ifaces
)
593 static const uc_function_list_t global_fns
[] = {
594 { "printf", uc_wpa_printf
},
595 { "getpid", uc_wpa_getpid
},
596 { "sha1", uc_wpa_sha1
},
597 { "freq_info", uc_wpa_freq_info
},
598 { "add_iface", uc_hostapd_add_iface
},
599 { "remove_iface", uc_hostapd_remove_iface
},
601 static const uc_function_list_t bss_fns
[] = {
602 { "ctrl", uc_hostapd_bss_ctrl
},
603 { "set_config", uc_hostapd_bss_set_config
},
604 { "rename", uc_hostapd_bss_rename
},
605 { "delete", uc_hostapd_bss_delete
},
607 static const uc_function_list_t iface_fns
[] = {
608 { "set_bss_order", uc_hostapd_iface_set_bss_order
},
609 { "add_bss", uc_hostapd_iface_add_bss
},
610 { "stop", uc_hostapd_iface_stop
},
611 { "start", uc_hostapd_iface_start
},
612 { "switch_channel", uc_hostapd_iface_switch_channel
},
614 uc_value_t
*data
, *proto
;
617 vm
= wpa_ucode_create_vm();
619 global_type
= uc_type_declare(vm
, "hostapd.global", global_fns
, NULL
);
620 bss_type
= uc_type_declare(vm
, "hostapd.bss", bss_fns
, NULL
);
621 iface_type
= uc_type_declare(vm
, "hostapd.iface", iface_fns
, NULL
);
623 bss_registry
= ucv_array_new(vm
);
624 uc_vm_registry_set(vm
, "hostap.bss_registry", bss_registry
);
626 iface_registry
= ucv_array_new(vm
);
627 uc_vm_registry_set(vm
, "hostap.iface_registry", iface_registry
);
629 global
= wpa_ucode_global_init("hostapd", global_type
);
631 if (wpa_ucode_run(HOSTAPD_UC_PATH
"hostapd.uc"))
642 void hostapd_ucode_free(void)
644 if (wpa_ucode_call_prepare("shutdown") == 0)
645 ucv_put(wpa_ucode_call(0));
649 void hostapd_ucode_free_iface(struct hostapd_iface
*iface
)
651 wpa_ucode_registry_remove(iface_registry
, iface
->ucode
.idx
);
654 void hostapd_ucode_add_bss(struct hostapd_data
*hapd
)
658 if (wpa_ucode_call_prepare("bss_add"))
661 val
= hostapd_ucode_bss_get_uval(hapd
);
662 uc_value_push(ucv_get(ucv_string_new(hapd
->conf
->iface
)));
663 uc_value_push(ucv_get(val
));
664 ucv_put(wpa_ucode_call(2));
668 void hostapd_ucode_reload_bss(struct hostapd_data
*hapd
)
672 if (wpa_ucode_call_prepare("bss_reload"))
675 val
= hostapd_ucode_bss_get_uval(hapd
);
676 uc_value_push(ucv_get(ucv_string_new(hapd
->conf
->iface
)));
677 uc_value_push(ucv_get(val
));
678 ucv_put(wpa_ucode_call(2));
682 void hostapd_ucode_free_bss(struct hostapd_data
*hapd
)
686 val
= wpa_ucode_registry_remove(bss_registry
, hapd
->ucode
.idx
);
691 if (wpa_ucode_call_prepare("bss_remove"))
694 uc_value_push(ucv_string_new(hapd
->conf
->iface
));
695 uc_value_push(ucv_get(val
));
696 ucv_put(wpa_ucode_call(2));