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 hapd
->ucode
.idx
= wpa_ucode_registry_add(bss_registry
, val
);
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 hapd
->ucode
.idx
= wpa_ucode_registry_add(iface_registry
, val
);
46 hostapd_ucode_update_bss_list(struct hostapd_iface
*iface
, uc_value_t
*if_bss
, uc_value_t
*bss
)
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
);
56 ucv_array_set(list
, i
, ucv_get(ucv_string_new(hapd
->conf
->iface
)));
57 ucv_object_add(bss
, hapd
->conf
->iface
, ucv_get(val
));
59 ucv_object_add(if_bss
, iface
->phy
, ucv_get(list
));
63 hostapd_ucode_update_interfaces(void)
65 uc_value_t
*ifs
= ucv_object_new(vm
);
66 uc_value_t
*if_bss
= ucv_array_new(vm
);
67 uc_value_t
*bss
= ucv_object_new(vm
);
70 for (i
= 0; i
< interfaces
->count
; i
++) {
71 struct hostapd_iface
*iface
= interfaces
->iface
[i
];
73 ucv_object_add(ifs
, iface
->phy
, ucv_get(hostapd_ucode_iface_get_uval(iface
)));
74 hostapd_ucode_update_bss_list(iface
, if_bss
, bss
);
77 ucv_object_add(ucv_prototype_get(global
), "interfaces", ucv_get(ifs
));
78 ucv_object_add(ucv_prototype_get(global
), "interface_bss", ucv_get(if_bss
));
79 ucv_object_add(ucv_prototype_get(global
), "bss", ucv_get(bss
));
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_interfaces();
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_interfaces();
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 #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
;
341 #ifdef CONFIG_IEEE80211BE
342 conf
->eht_oper_centr_freq_seg0_idx
= intval
;
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
;
350 #ifdef CONFIG_IEEE80211BE
351 conf
->eht_oper_centr_freq_seg1_idx
= intval
;
354 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
356 conf
->vht_oper_chwidth
= intval
;
357 #ifdef CONFIG_IEEE80211AX
358 conf
->he_oper_chwidth
= intval
;
360 #ifdef CONFIG_IEEE80211BE
361 conf
->eht_oper_chwidth
= intval
;
368 iface
->freq
= hostapd_hw_get_freq(iface
->bss
[0], conf
->channel
);
370 for (i
= 0; i
< iface
->num_bss
; i
++) {
371 struct hostapd_data
*hapd
= iface
->bss
[i
];
375 hostapd_set_freq(hapd
, conf
->hw_mode
, iface
->freq
,
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
));
388 ieee802_11_set_beacon(hapd
);
391 return ucv_boolean_new(true);
395 uc_hostapd_iface_switch_channel(uc_vm_t
*vm
, size_t nargs
)
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
= {};
404 if (!iface
|| ucv_type(info
) != UC_OBJECT
)
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
;
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
;
419 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
421 intval
= hostapd_get_oper_chwidth(conf
);
423 csa
.freq_params
.bandwidth
= 40 << intval
;
425 csa
.freq_params
.bandwidth
= csa
.freq_params
.sec_channel_offset
? 40 : 20;
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
;
434 for (i
= 0; i
< iface
->num_bss
; i
++)
435 ret
= hostapd_switch_channel(iface
->bss
[i
], &csa
);
437 return ucv_boolean_new(!ret
);
440 int hostapd_ucode_init(struct hapd_interfaces
*ifaces
)
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
},
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
},
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
},
461 uc_value_t
*data
, *proto
;
464 vm
= wpa_ucode_create_vm();
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
);
470 bss_registry
= ucv_array_new(vm
);
471 uc_vm_registry_set(vm
, "hostap.bss_registry", bss_registry
);
473 iface_registry
= ucv_array_new(vm
);
474 uc_vm_registry_set(vm
, "hostap.iface_registry", iface_registry
);
476 global
= wpa_ucode_global_init("hostapd", global_type
);
478 if (wpa_ucode_run(HOSTAPD_UC_PATH
"hostapd.uc"))
489 void hostapd_ucode_free(void)
491 if (wpa_ucode_call_prepare("shutdown") == 0)
492 ucv_put(wpa_ucode_call(0));
496 void hostapd_ucode_free_iface(struct hostapd_iface
*iface
)
498 wpa_ucode_registry_remove(iface_registry
, iface
->ucode
.idx
);
501 void hostapd_ucode_add_bss(struct hostapd_data
*hapd
)
505 if (wpa_ucode_call_prepare("bss_add"))
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));
515 void hostapd_ucode_reload_bss(struct hostapd_data
*hapd
)
519 if (wpa_ucode_call_prepare("bss_reload"))
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));
529 void hostapd_ucode_free_bss(struct hostapd_data
*hapd
)
533 val
= wpa_ucode_registry_remove(bss_registry
, hapd
->ucode
.idx
);
538 if (wpa_ucode_call_prepare("bss_remove"))
541 uc_value_push(ucv_string_new(hapd
->conf
->iface
));
542 uc_value_push(ucv_get(val
));
543 ucv_put(wpa_ucode_call(2));