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 unsigned int i
, idx
= 0;
126 if (!hapd
|| ucv_type(file
) != UC_STRING
)
129 if (ucv_type(index
) == UC_INTEGER
)
130 idx
= ucv_int64_get(index
);
133 conf
= interfaces
->config_read_cb(ucv_string_get(file
));
134 if (!conf
|| idx
> conf
->num_bss
|| !conf
->bss
[idx
])
137 hostapd_bss_deinit_no_free(hapd
);
138 hostapd_drv_stop_ap(hapd
);
139 hostapd_free_hapd_data(hapd
);
141 old_bss
= hapd
->conf
;
142 for (i
= 0; i
< iface
->conf
->num_bss
; i
++)
143 if (iface
->conf
->bss
[i
] == hapd
->conf
)
144 iface
->conf
->bss
[i
] = conf
->bss
[idx
];
145 hapd
->conf
= conf
->bss
[idx
];
146 conf
->bss
[idx
] = old_bss
;
147 hostapd_config_free(conf
);
149 hostapd_setup_bss(hapd
, hapd
== iface
->bss
[0], !iface
->conf
->mbssid
);
150 hostapd_ucode_update_interfaces();
155 return ucv_int64_new(ret
);
159 hostapd_remove_iface_bss_conf(struct hostapd_config
*iconf
,
160 struct hostapd_bss_config
*conf
)
164 for (i
= 0; i
< iconf
->num_bss
; i
++)
165 if (iconf
->bss
[i
] == conf
)
168 if (i
== iconf
->num_bss
)
171 for (i
++; i
< iconf
->num_bss
; i
++)
172 iconf
->bss
[i
- 1] = iconf
->bss
[i
];
178 uc_hostapd_bss_delete(uc_vm_t
*vm
, size_t nargs
)
180 struct hostapd_data
*hapd
= uc_fn_thisval("hostapd.bss");
181 struct hostapd_iface
*iface
;
184 if (!hapd
|| hapd
== hapd
->iface
->bss
[0])
188 for (idx
= 0; idx
< iface
->num_bss
; idx
++)
189 if (iface
->bss
[idx
] == hapd
)
192 if (idx
== iface
->num_bss
)
195 for (i
= idx
+ 1; i
< iface
->num_bss
; i
++)
196 iface
->bss
[i
- 1] = iface
->bss
[i
];
199 hostapd_drv_stop_ap(hapd
);
200 hostapd_bss_deinit(hapd
);
201 hostapd_remove_iface_bss_conf(iface
->conf
, hapd
->conf
);
202 hostapd_config_free_bss(hapd
->conf
);
205 hostapd_ucode_update_interfaces();
212 uc_hostapd_iface_add_bss(uc_vm_t
*vm
, size_t nargs
)
214 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
215 struct hostapd_bss_config
*bss
;
216 struct hostapd_config
*conf
;
217 struct hostapd_data
*hapd
;
218 uc_value_t
*file
= uc_fn_arg(0);
219 uc_value_t
*index
= uc_fn_arg(1);
220 unsigned int idx
= 0;
221 uc_value_t
*ret
= NULL
;
223 if (!iface
|| ucv_type(file
) != UC_STRING
)
226 if (ucv_type(index
) == UC_INTEGER
)
227 idx
= ucv_int64_get(index
);
229 conf
= interfaces
->config_read_cb(ucv_string_get(file
));
230 if (!conf
|| idx
> conf
->num_bss
|| !conf
->bss
[idx
])
233 bss
= conf
->bss
[idx
];
234 hapd
= hostapd_alloc_bss_data(iface
, iface
->conf
, bss
);
238 hapd
->driver
= iface
->bss
[0]->driver
;
239 hapd
->drv_priv
= iface
->bss
[0]->drv_priv
;
240 if (interfaces
->ctrl_iface_init
&&
241 interfaces
->ctrl_iface_init(hapd
) < 0)
244 if (iface
->state
== HAPD_IFACE_ENABLED
&&
245 hostapd_setup_bss(hapd
, -1, true))
248 iface
->bss
= os_realloc_array(iface
->bss
, iface
->num_bss
+ 1,
249 sizeof(*iface
->bss
));
250 iface
->bss
[iface
->num_bss
++] = hapd
;
252 iface
->conf
->bss
= os_realloc_array(iface
->conf
->bss
,
253 iface
->conf
->num_bss
+ 1,
254 sizeof(*iface
->conf
->bss
));
255 iface
->conf
->bss
[iface
->conf
->num_bss
] = bss
;
256 conf
->bss
[idx
] = NULL
;
257 ret
= hostapd_ucode_bss_get_uval(hapd
);
258 hostapd_ucode_update_interfaces();
262 if (interfaces
->ctrl_iface_deinit
)
263 interfaces
->ctrl_iface_deinit(hapd
);
265 hostapd_free_hapd_data(hapd
);
268 hostapd_config_free(conf
);
273 uc_hostapd_bss_ctrl(uc_vm_t
*vm
, size_t nargs
)
275 struct hostapd_data
*hapd
= uc_fn_thisval("hostapd.bss");
276 uc_value_t
*arg
= uc_fn_arg(0);
277 struct sockaddr_storage from
= {};
278 static char reply
[4096];
281 if (!hapd
|| !interfaces
->ctrl_iface_recv
||
282 ucv_type(arg
) != UC_STRING
)
285 reply_len
= interfaces
->ctrl_iface_recv(hapd
, ucv_string_get(arg
),
286 reply
, sizeof(reply
),
287 &from
, sizeof(from
));
291 if (reply_len
&& reply
[reply_len
- 1] == '\n')
294 return ucv_string_new_length(reply
, reply_len
);
298 uc_hostapd_iface_stop(uc_vm_t
*vm
, size_t nargs
)
300 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
304 if (iface
->state
== HAPD_IFACE_ACS
) {
306 iface
->scan_cb
= NULL
;
307 hostapd_disable_iface(iface
);
311 for (i
= 0; i
< iface
->num_bss
; i
++) {
312 struct hostapd_data
*hapd
= iface
->bss
[i
];
314 hostapd_drv_stop_ap(hapd
);
320 uc_hostapd_iface_start(uc_vm_t
*vm
, size_t nargs
)
322 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
323 uc_value_t
*info
= uc_fn_arg(0);
324 struct hostapd_config
*conf
;
335 if (ucv_type(info
) != UC_OBJECT
)
339 if ((intval
= ucv_int64_get(ucv_object_get(info
, "op_class", NULL
))) && !errno
)
340 conf
->op_class
= intval
;
341 if ((intval
= ucv_int64_get(ucv_object_get(info
, "hw_mode", NULL
))) && !errno
)
342 conf
->hw_mode
= intval
;
343 if ((intval
= ucv_int64_get(ucv_object_get(info
, "channel", NULL
))) && !errno
)
344 conf
->channel
= intval
;
345 if ((intval
= ucv_int64_get(ucv_object_get(info
, "sec_channel", NULL
))) && !errno
)
346 conf
->secondary_channel
= intval
;
348 intval
= ucv_int64_get(ucv_object_get(info
, "center_seg0_idx", NULL
));
350 hostapd_set_oper_centr_freq_seg0_idx(conf
, intval
);
352 intval
= ucv_int64_get(ucv_object_get(info
, "center_seg1_idx", NULL
));
354 hostapd_set_oper_centr_freq_seg1_idx(conf
, intval
);
356 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
358 hostapd_set_oper_chwidth(conf
, intval
);
360 intval
= ucv_int64_get(ucv_object_get(info
, "frequency", NULL
));
362 iface
->freq
= intval
;
366 switch (iface
->state
) {
367 case HAPD_IFACE_DISABLED
:
369 case HAPD_IFACE_ENABLED
:
370 if (!hostapd_is_dfs_required(iface
) ||
371 hostapd_is_dfs_chan_available(iface
))
373 wpa_printf(MSG_INFO
, "DFS CAC required on new channel, restart interface");
376 hostapd_disable_iface(iface
);
380 if (conf
->channel
&& !iface
->freq
)
381 iface
->freq
= hostapd_hw_get_freq(iface
->bss
[0], conf
->channel
);
383 if (iface
->state
!= HAPD_IFACE_ENABLED
) {
384 hostapd_enable_iface(iface
);
385 return ucv_boolean_new(true);
388 for (i
= 0; i
< iface
->num_bss
; i
++) {
389 struct hostapd_data
*hapd
= iface
->bss
[i
];
393 hapd
->conf
->start_disabled
= 0;
394 hostapd_set_freq(hapd
, conf
->hw_mode
, iface
->freq
,
402 conf
->secondary_channel
,
403 hostapd_get_oper_chwidth(conf
),
404 hostapd_get_oper_centr_freq_seg0_idx(conf
),
405 hostapd_get_oper_centr_freq_seg1_idx(conf
));
407 ieee802_11_set_beacon(hapd
);
410 return ucv_boolean_new(true);
414 uc_hostapd_iface_switch_channel(uc_vm_t
*vm
, size_t nargs
)
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 struct csa_settings csa
= {};
423 if (!iface
|| ucv_type(info
) != UC_OBJECT
)
427 if ((intval
= ucv_int64_get(ucv_object_get(info
, "csa_count", NULL
))) && !errno
)
428 csa
.cs_count
= intval
;
429 if ((intval
= ucv_int64_get(ucv_object_get(info
, "sec_channel", NULL
))) && !errno
)
430 csa
.freq_params
.sec_channel_offset
= intval
;
432 csa
.freq_params
.ht_enabled
= conf
->ieee80211n
;
433 csa
.freq_params
.vht_enabled
= conf
->ieee80211ac
;
434 csa
.freq_params
.he_enabled
= conf
->ieee80211ax
;
435 #ifdef CONFIG_IEEE80211BE
436 csa
.freq_params
.eht_enabled
= conf
->ieee80211be
;
438 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
440 intval
= hostapd_get_oper_chwidth(conf
);
442 csa
.freq_params
.bandwidth
= 40 << intval
;
444 csa
.freq_params
.bandwidth
= csa
.freq_params
.sec_channel_offset
? 40 : 20;
446 if ((intval
= ucv_int64_get(ucv_object_get(info
, "frequency", NULL
))) && !errno
)
447 csa
.freq_params
.freq
= intval
;
448 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_freq1", NULL
))) && !errno
)
449 csa
.freq_params
.center_freq1
= intval
;
450 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_freq2", NULL
))) && !errno
)
451 csa
.freq_params
.center_freq2
= intval
;
453 for (i
= 0; i
< iface
->num_bss
; i
++)
454 ret
= hostapd_switch_channel(iface
->bss
[i
], &csa
);
456 return ucv_boolean_new(!ret
);
459 int hostapd_ucode_init(struct hapd_interfaces
*ifaces
)
461 static const uc_function_list_t global_fns
[] = {
462 { "printf", uc_wpa_printf
},
463 { "getpid", uc_wpa_getpid
},
464 { "sha1", uc_wpa_sha1
},
465 { "freq_info", uc_wpa_freq_info
},
466 { "add_iface", uc_hostapd_add_iface
},
467 { "remove_iface", uc_hostapd_remove_iface
},
469 static const uc_function_list_t bss_fns
[] = {
470 { "ctrl", uc_hostapd_bss_ctrl
},
471 { "set_config", uc_hostapd_bss_set_config
},
472 { "delete", uc_hostapd_bss_delete
},
474 static const uc_function_list_t iface_fns
[] = {
475 { "add_bss", uc_hostapd_iface_add_bss
},
476 { "stop", uc_hostapd_iface_stop
},
477 { "start", uc_hostapd_iface_start
},
478 { "switch_channel", uc_hostapd_iface_switch_channel
},
480 uc_value_t
*data
, *proto
;
483 vm
= wpa_ucode_create_vm();
485 global_type
= uc_type_declare(vm
, "hostapd.global", global_fns
, NULL
);
486 bss_type
= uc_type_declare(vm
, "hostapd.bss", bss_fns
, NULL
);
487 iface_type
= uc_type_declare(vm
, "hostapd.iface", iface_fns
, NULL
);
489 bss_registry
= ucv_array_new(vm
);
490 uc_vm_registry_set(vm
, "hostap.bss_registry", bss_registry
);
492 iface_registry
= ucv_array_new(vm
);
493 uc_vm_registry_set(vm
, "hostap.iface_registry", iface_registry
);
495 global
= wpa_ucode_global_init("hostapd", global_type
);
497 if (wpa_ucode_run(HOSTAPD_UC_PATH
"hostapd.uc"))
508 void hostapd_ucode_free(void)
510 if (wpa_ucode_call_prepare("shutdown") == 0)
511 ucv_put(wpa_ucode_call(0));
515 void hostapd_ucode_free_iface(struct hostapd_iface
*iface
)
517 wpa_ucode_registry_remove(iface_registry
, iface
->ucode
.idx
);
520 void hostapd_ucode_add_bss(struct hostapd_data
*hapd
)
524 if (wpa_ucode_call_prepare("bss_add"))
527 val
= hostapd_ucode_bss_get_uval(hapd
);
528 uc_value_push(ucv_get(ucv_string_new(hapd
->conf
->iface
)));
529 uc_value_push(ucv_get(val
));
530 ucv_put(wpa_ucode_call(2));
534 void hostapd_ucode_reload_bss(struct hostapd_data
*hapd
)
538 if (wpa_ucode_call_prepare("bss_reload"))
541 val
= hostapd_ucode_bss_get_uval(hapd
);
542 uc_value_push(ucv_get(ucv_string_new(hapd
->conf
->iface
)));
543 uc_value_push(ucv_get(val
));
544 ucv_put(wpa_ucode_call(2));
548 void hostapd_ucode_free_bss(struct hostapd_data
*hapd
)
552 val
= wpa_ucode_registry_remove(bss_registry
, hapd
->ucode
.idx
);
557 if (wpa_ucode_call_prepare("bss_remove"))
560 uc_value_push(ucv_string_new(hapd
->conf
->iface
));
561 uc_value_push(ucv_get(val
));
562 ucv_put(wpa_ucode_call(2));