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"
10 #include <libubox/uloop.h>
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
;
18 hostapd_ucode_bss_get_uval(struct hostapd_data
*hapd
)
23 return wpa_ucode_registry_get(bss_registry
, hapd
->ucode
.idx
);
25 val
= uc_resource_new(bss_type
, hapd
);
26 wpa_ucode_registry_add(bss_registry
, val
, &hapd
->ucode
.idx
);
32 hostapd_ucode_iface_get_uval(struct hostapd_iface
*hapd
)
37 return wpa_ucode_registry_get(iface_registry
, hapd
->ucode
.idx
);
39 val
= uc_resource_new(iface_type
, hapd
);
40 wpa_ucode_registry_add(iface_registry
, val
, &hapd
->ucode
.idx
);
46 hostapd_ucode_update_bss_list(struct hostapd_iface
*iface
)
48 uc_value_t
*ifval
, *list
;
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
);
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
));
62 ifval
= hostapd_ucode_iface_get_uval(iface
);
63 ucv_object_add(ucv_prototype_get(ifval
), "bss", ucv_get(list
));
67 hostapd_ucode_update_interfaces(void)
69 uc_value_t
*ifs
= 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
);
79 ucv_object_add(ucv_prototype_get(global
), "interfaces", ucv_get(ifs
));
84 uc_hostapd_add_iface(uc_vm_t
*vm
, size_t nargs
)
86 uc_value_t
*iface
= uc_fn_arg(0);
89 if (ucv_type(iface
) != UC_STRING
)
90 return ucv_int64_new(-1);
92 ret
= hostapd_add_iface(interfaces
, ucv_string_get(iface
));
93 hostapd_ucode_update_interfaces();
95 return ucv_int64_new(ret
);
99 uc_hostapd_remove_iface(uc_vm_t
*vm
, size_t nargs
)
101 uc_value_t
*iface
= uc_fn_arg(0);
103 if (ucv_type(iface
) != UC_STRING
)
106 hostapd_remove_iface(interfaces
, ucv_string_get(iface
));
107 hostapd_ucode_update_interfaces();
113 uc_hostapd_bss_set_config(uc_vm_t
*vm
, size_t nargs
)
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;
124 if (!hapd
|| ucv_type(file
) != UC_STRING
)
127 if (ucv_type(index
) == UC_INTEGER
)
128 idx
= ucv_int64_get(index
);
131 conf
= interfaces
->config_read_cb(ucv_string_get(file
));
132 if (!conf
|| idx
> conf
->num_bss
|| !conf
->bss
[idx
])
135 hostapd_bss_deinit_no_free(hapd
);
136 hostapd_drv_stop_ap(hapd
);
137 hostapd_free_hapd_data(hapd
);
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
);
147 hostapd_setup_bss(hapd
, hapd
== iface
->bss
[0], !iface
->conf
->mbssid
);
152 return ucv_int64_new(ret
);
156 hostapd_remove_iface_bss_conf(struct hostapd_config
*iconf
,
157 struct hostapd_bss_config
*conf
)
161 for (i
= 0; i
< iconf
->num_bss
; i
++)
162 if (iconf
->bss
[i
] == conf
)
165 if (i
== iconf
->num_bss
)
168 for (i
++; i
< iconf
->num_bss
; i
++)
169 iconf
->bss
[i
- 1] = iconf
->bss
[i
];
175 uc_hostapd_bss_delete(uc_vm_t
*vm
, size_t nargs
)
177 struct hostapd_data
*hapd
= uc_fn_thisval("hostapd.bss");
178 struct hostapd_iface
*iface
;
181 if (!hapd
|| hapd
== hapd
->iface
->bss
[0])
185 for (idx
= 0; idx
< iface
->num_bss
; idx
++)
186 if (iface
->bss
[idx
] == hapd
)
189 if (idx
== iface
->num_bss
)
192 for (i
= idx
+ 1; i
< iface
->num_bss
; i
++)
193 iface
->bss
[i
- 1] = iface
->bss
[i
];
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
);
202 hostapd_ucode_update_bss_list(iface
);
209 uc_hostapd_iface_add_bss(uc_vm_t
*vm
, size_t nargs
)
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
;
220 if (!iface
|| ucv_type(file
) != UC_STRING
)
223 if (ucv_type(index
) == UC_INTEGER
)
224 idx
= ucv_int64_get(index
);
226 conf
= interfaces
->config_read_cb(ucv_string_get(file
));
227 if (!conf
|| idx
> conf
->num_bss
|| !conf
->bss
[idx
])
230 bss
= conf
->bss
[idx
];
231 hapd
= hostapd_alloc_bss_data(iface
, iface
->conf
, bss
);
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)
241 if (iface
->state
== HAPD_IFACE_ENABLED
&&
242 hostapd_setup_bss(hapd
, -1, true))
245 iface
->bss
= os_realloc_array(iface
->bss
, iface
->num_bss
+ 1,
246 sizeof(*iface
->bss
));
247 iface
->bss
[iface
->num_bss
++] = hapd
;
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
);
259 if (interfaces
->ctrl_iface_deinit
)
260 interfaces
->ctrl_iface_deinit(hapd
);
262 hostapd_free_hapd_data(hapd
);
265 hostapd_config_free(conf
);
270 uc_hostapd_bss_ctrl(uc_vm_t
*vm
, size_t nargs
)
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];
278 if (!hapd
|| !interfaces
->ctrl_iface_recv
||
279 ucv_type(arg
) != UC_STRING
)
282 reply_len
= interfaces
->ctrl_iface_recv(hapd
, ucv_string_get(arg
),
283 reply
, sizeof(reply
),
284 &from
, sizeof(from
));
288 if (reply_len
&& reply
[reply_len
- 1] == '\n')
291 return ucv_string_new_length(reply
, reply_len
);
295 uc_hostapd_iface_stop(uc_vm_t
*vm
, size_t nargs
)
297 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
300 for (i
= 0; i
< iface
->num_bss
; i
++) {
301 struct hostapd_data
*hapd
= iface
->bss
[i
];
303 hostapd_drv_stop_ap(hapd
);
309 uc_hostapd_iface_start(uc_vm_t
*vm
, size_t nargs
)
311 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
312 uc_value_t
*info
= uc_fn_arg(0);
313 struct hostapd_config
*conf
;
323 if (ucv_type(info
) != UC_OBJECT
)
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 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_seg0_idx", NULL
))) && !errno
) {
336 conf
->vht_oper_centr_freq_seg0_idx
= intval
;
337 conf
->he_oper_centr_freq_seg0_idx
= intval
;
338 #ifdef CONFIG_IEEE80211BE
339 conf
->eht_oper_centr_freq_seg0_idx
= intval
;
342 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_seg1_idx", NULL
))) && !errno
) {
343 conf
->vht_oper_centr_freq_seg1_idx
= intval
;
344 conf
->he_oper_centr_freq_seg1_idx
= intval
;
345 #ifdef CONFIG_IEEE80211BE
346 conf
->eht_oper_centr_freq_seg1_idx
= intval
;
349 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
351 conf
->vht_oper_chwidth
= intval
;
352 conf
->he_oper_chwidth
= intval
;
353 #ifdef CONFIG_IEEE80211BE
354 conf
->eht_oper_chwidth
= intval
;
360 iface
->freq
= hostapd_hw_get_freq(iface
->bss
[0], conf
->channel
);
362 for (i
= 0; i
< iface
->num_bss
; i
++) {
363 struct hostapd_data
*hapd
= iface
->bss
[i
];
367 hostapd_set_freq(hapd
, conf
->hw_mode
, iface
->freq
,
375 conf
->secondary_channel
,
376 hostapd_get_oper_chwidth(conf
),
377 hostapd_get_oper_centr_freq_seg0_idx(conf
),
378 hostapd_get_oper_centr_freq_seg1_idx(conf
));
380 ieee802_11_set_beacon(hapd
);
383 return ucv_boolean_new(true);
387 uc_hostapd_iface_switch_channel(uc_vm_t
*vm
, size_t nargs
)
389 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
390 uc_value_t
*info
= uc_fn_arg(0);
391 struct hostapd_config
*conf
;
392 struct csa_settings csa
= {};
396 if (!iface
|| ucv_type(info
) != UC_OBJECT
)
400 if ((intval
= ucv_int64_get(ucv_object_get(info
, "csa_count", NULL
))) && !errno
)
401 csa
.cs_count
= intval
;
402 if ((intval
= ucv_int64_get(ucv_object_get(info
, "sec_channel", NULL
))) && !errno
)
403 csa
.freq_params
.sec_channel_offset
= intval
;
405 csa
.freq_params
.ht_enabled
= conf
->ieee80211n
;
406 csa
.freq_params
.vht_enabled
= conf
->ieee80211ac
;
407 csa
.freq_params
.he_enabled
= conf
->ieee80211ax
;
408 #ifdef CONFIG_IEEE80211BE
409 csa
.freq_params
.eht_enabled
= conf
->ieee80211be
;
411 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
413 intval
= hostapd_get_oper_chwidth(conf
);
415 csa
.freq_params
.bandwidth
= 40 << intval
;
417 csa
.freq_params
.bandwidth
= csa
.freq_params
.sec_channel_offset
? 40 : 20;
419 if ((intval
= ucv_int64_get(ucv_object_get(info
, "frequency", NULL
))) && !errno
)
420 csa
.freq_params
.freq
= intval
;
421 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_freq1", NULL
))) && !errno
)
422 csa
.freq_params
.center_freq1
= intval
;
423 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_freq2", NULL
))) && !errno
)
424 csa
.freq_params
.center_freq2
= intval
;
426 for (i
= 0; i
< iface
->num_bss
; i
++)
427 ret
= hostapd_switch_channel(iface
->bss
[i
], &csa
);
429 return ucv_boolean_new(!ret
);
432 int hostapd_ucode_init(struct hapd_interfaces
*ifaces
)
434 static const uc_function_list_t global_fns
[] = {
435 { "printf", uc_wpa_printf
},
436 { "getpid", uc_wpa_getpid
},
437 { "sha1", uc_wpa_sha1
},
438 { "freq_info", uc_wpa_freq_info
},
439 { "add_iface", uc_hostapd_add_iface
},
440 { "remove_iface", uc_hostapd_remove_iface
},
442 static const uc_function_list_t bss_fns
[] = {
443 { "ctrl", uc_hostapd_bss_ctrl
},
444 { "set_config", uc_hostapd_bss_set_config
},
445 { "delete", uc_hostapd_bss_delete
},
447 static const uc_function_list_t iface_fns
[] = {
448 { "add_bss", uc_hostapd_iface_add_bss
},
449 { "stop", uc_hostapd_iface_stop
},
450 { "start", uc_hostapd_iface_start
},
451 { "switch_channel", uc_hostapd_iface_switch_channel
},
453 uc_value_t
*data
, *proto
;
456 vm
= wpa_ucode_create_vm();
458 global_type
= uc_type_declare(vm
, "hostapd.global", global_fns
, NULL
);
459 bss_type
= uc_type_declare(vm
, "hostapd.bss", bss_fns
, NULL
);
460 iface_type
= uc_type_declare(vm
, "hostapd.iface", iface_fns
, NULL
);
462 bss_registry
= ucv_array_new(vm
);
463 uc_vm_registry_set(vm
, "hostap.bss_registry", bss_registry
);
465 iface_registry
= ucv_array_new(vm
);
466 uc_vm_registry_set(vm
, "hostap.iface_registry", iface_registry
);
468 global
= wpa_ucode_global_init("hostapd", global_type
);
470 if (wpa_ucode_run(HOSTAPD_UC_PATH
"hostapd.uc"))
481 void hostapd_ucode_free(void)
483 if (wpa_ucode_call_prepare("shutdown") == 0)
484 ucv_put(wpa_ucode_call(0));
488 void hostapd_ucode_free_iface(struct hostapd_iface
*iface
)
490 wpa_ucode_registry_remove(iface_registry
, iface
->ucode
.idx
);
493 void hostapd_ucode_add_bss(struct hostapd_data
*hapd
)
497 if (wpa_ucode_call_prepare("bss_add"))
500 val
= hostapd_ucode_bss_get_uval(hapd
);
501 uc_value_push(ucv_get(ucv_string_new(hapd
->conf
->iface
)));
502 uc_value_push(ucv_get(val
));
503 ucv_put(wpa_ucode_call(2));
507 void hostapd_ucode_reload_bss(struct hostapd_data
*hapd
)
511 if (wpa_ucode_call_prepare("bss_reload"))
514 val
= hostapd_ucode_bss_get_uval(hapd
);
515 uc_value_push(ucv_get(ucv_string_new(hapd
->conf
->iface
)));
516 uc_value_push(ucv_get(val
));
517 ucv_put(wpa_ucode_call(2));
521 void hostapd_ucode_free_bss(struct hostapd_data
*hapd
)
525 val
= wpa_ucode_registry_remove(bss_registry
, hapd
->ucode
.idx
);
530 if (wpa_ucode_call_prepare("bss_remove"))
533 uc_value_push(ucv_string_new(hapd
->conf
->iface
));
534 uc_value_push(ucv_get(val
));
535 ucv_put(wpa_ucode_call(2));