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"
11 #include <libubox/uloop.h>
13 static uc_resource_type_t
*global_type
, *bss_type
, *iface_type
;
14 static struct hapd_interfaces
*interfaces
;
15 static uc_value_t
*global
, *bss_registry
, *iface_registry
;
19 hostapd_ucode_bss_get_uval(struct hostapd_data
*hapd
)
24 return wpa_ucode_registry_get(bss_registry
, hapd
->ucode
.idx
);
26 val
= uc_resource_new(bss_type
, hapd
);
27 hapd
->ucode
.idx
= wpa_ucode_registry_add(bss_registry
, val
);
33 hostapd_ucode_iface_get_uval(struct hostapd_iface
*hapd
)
38 return wpa_ucode_registry_get(iface_registry
, hapd
->ucode
.idx
);
40 val
= uc_resource_new(iface_type
, hapd
);
41 hapd
->ucode
.idx
= wpa_ucode_registry_add(iface_registry
, val
);
47 hostapd_ucode_update_bss_list(struct hostapd_iface
*iface
, uc_value_t
*if_bss
, uc_value_t
*bss
)
52 list
= ucv_array_new(vm
);
53 for (i
= 0; i
< iface
->num_bss
; i
++) {
54 struct hostapd_data
*hapd
= iface
->bss
[i
];
55 uc_value_t
*val
= hostapd_ucode_bss_get_uval(hapd
);
57 ucv_array_set(list
, i
, ucv_get(ucv_string_new(hapd
->conf
->iface
)));
58 ucv_object_add(bss
, hapd
->conf
->iface
, ucv_get(val
));
60 ucv_object_add(if_bss
, iface
->phy
, ucv_get(list
));
64 hostapd_ucode_update_interfaces(void)
66 uc_value_t
*ifs
= ucv_object_new(vm
);
67 uc_value_t
*if_bss
= ucv_array_new(vm
);
68 uc_value_t
*bss
= ucv_object_new(vm
);
71 for (i
= 0; i
< interfaces
->count
; i
++) {
72 struct hostapd_iface
*iface
= interfaces
->iface
[i
];
74 ucv_object_add(ifs
, iface
->phy
, ucv_get(hostapd_ucode_iface_get_uval(iface
)));
75 hostapd_ucode_update_bss_list(iface
, if_bss
, bss
);
78 ucv_object_add(ucv_prototype_get(global
), "interfaces", ucv_get(ifs
));
79 ucv_object_add(ucv_prototype_get(global
), "interface_bss", ucv_get(if_bss
));
80 ucv_object_add(ucv_prototype_get(global
), "bss", ucv_get(bss
));
85 uc_hostapd_add_iface(uc_vm_t
*vm
, size_t nargs
)
87 uc_value_t
*iface
= uc_fn_arg(0);
90 if (ucv_type(iface
) != UC_STRING
)
91 return ucv_int64_new(-1);
93 ret
= hostapd_add_iface(interfaces
, ucv_string_get(iface
));
94 hostapd_ucode_update_interfaces();
96 return ucv_int64_new(ret
);
100 uc_hostapd_remove_iface(uc_vm_t
*vm
, size_t nargs
)
102 uc_value_t
*iface
= uc_fn_arg(0);
104 if (ucv_type(iface
) != UC_STRING
)
107 hostapd_remove_iface(interfaces
, ucv_string_get(iface
));
108 hostapd_ucode_update_interfaces();
114 uc_hostapd_bss_set_config(uc_vm_t
*vm
, size_t nargs
)
116 struct hostapd_data
*hapd
= uc_fn_thisval("hostapd.bss");
117 struct hostapd_bss_config
*old_bss
;
118 struct hostapd_iface
*iface
;
119 struct hostapd_config
*conf
;
120 uc_value_t
*file
= uc_fn_arg(0);
121 uc_value_t
*index
= uc_fn_arg(1);
122 unsigned int i
, idx
= 0;
125 if (!hapd
|| ucv_type(file
) != UC_STRING
)
128 if (ucv_type(index
) == UC_INTEGER
)
129 idx
= ucv_int64_get(index
);
132 conf
= interfaces
->config_read_cb(ucv_string_get(file
));
133 if (!conf
|| idx
> conf
->num_bss
|| !conf
->bss
[idx
])
136 hostapd_bss_deinit_no_free(hapd
);
137 hostapd_drv_stop_ap(hapd
);
138 hostapd_free_hapd_data(hapd
);
140 old_bss
= hapd
->conf
;
141 for (i
= 0; i
< iface
->conf
->num_bss
; i
++)
142 if (iface
->conf
->bss
[i
] == hapd
->conf
)
143 iface
->conf
->bss
[i
] = conf
->bss
[idx
];
144 hapd
->conf
= conf
->bss
[idx
];
145 conf
->bss
[idx
] = old_bss
;
146 hostapd_config_free(conf
);
148 hostapd_setup_bss(hapd
, hapd
== iface
->bss
[0], !iface
->conf
->mbssid
);
153 return ucv_int64_new(ret
);
157 hostapd_remove_iface_bss_conf(struct hostapd_config
*iconf
,
158 struct hostapd_bss_config
*conf
)
162 for (i
= 0; i
< iconf
->num_bss
; i
++)
163 if (iconf
->bss
[i
] == conf
)
166 if (i
== iconf
->num_bss
)
169 for (i
++; i
< iconf
->num_bss
; i
++)
170 iconf
->bss
[i
- 1] = iconf
->bss
[i
];
176 uc_hostapd_bss_delete(uc_vm_t
*vm
, size_t nargs
)
178 struct hostapd_data
*hapd
= uc_fn_thisval("hostapd.bss");
179 struct hostapd_iface
*iface
;
182 if (!hapd
|| hapd
== hapd
->iface
->bss
[0])
186 for (idx
= 0; idx
< iface
->num_bss
; idx
++)
187 if (iface
->bss
[idx
] == hapd
)
190 if (idx
== iface
->num_bss
)
193 for (i
= idx
+ 1; i
< iface
->num_bss
; i
++)
194 iface
->bss
[i
- 1] = iface
->bss
[i
];
197 hostapd_drv_stop_ap(hapd
);
198 hostapd_bss_deinit(hapd
);
199 hostapd_remove_iface_bss_conf(iface
->conf
, hapd
->conf
);
200 hostapd_config_free_bss(hapd
->conf
);
203 hostapd_ucode_update_interfaces();
210 uc_hostapd_iface_add_bss(uc_vm_t
*vm
, size_t nargs
)
212 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
213 struct hostapd_bss_config
*bss
;
214 struct hostapd_config
*conf
;
215 struct hostapd_data
*hapd
;
216 uc_value_t
*file
= uc_fn_arg(0);
217 uc_value_t
*index
= uc_fn_arg(1);
218 unsigned int idx
= 0;
219 uc_value_t
*ret
= NULL
;
221 if (!iface
|| ucv_type(file
) != UC_STRING
)
224 if (ucv_type(index
) == UC_INTEGER
)
225 idx
= ucv_int64_get(index
);
227 conf
= interfaces
->config_read_cb(ucv_string_get(file
));
228 if (!conf
|| idx
> conf
->num_bss
|| !conf
->bss
[idx
])
231 bss
= conf
->bss
[idx
];
232 hapd
= hostapd_alloc_bss_data(iface
, iface
->conf
, bss
);
236 hapd
->driver
= iface
->bss
[0]->driver
;
237 hapd
->drv_priv
= iface
->bss
[0]->drv_priv
;
238 if (interfaces
->ctrl_iface_init
&&
239 interfaces
->ctrl_iface_init(hapd
) < 0)
242 if (iface
->state
== HAPD_IFACE_ENABLED
&&
243 hostapd_setup_bss(hapd
, -1, true))
246 iface
->bss
= os_realloc_array(iface
->bss
, iface
->num_bss
+ 1,
247 sizeof(*iface
->bss
));
248 iface
->bss
[iface
->num_bss
++] = hapd
;
250 iface
->conf
->bss
= os_realloc_array(iface
->conf
->bss
,
251 iface
->conf
->num_bss
+ 1,
252 sizeof(*iface
->conf
->bss
));
253 iface
->conf
->bss
[iface
->conf
->num_bss
] = bss
;
254 conf
->bss
[idx
] = NULL
;
255 ret
= hostapd_ucode_bss_get_uval(hapd
);
256 hostapd_ucode_update_interfaces();
260 if (interfaces
->ctrl_iface_deinit
)
261 interfaces
->ctrl_iface_deinit(hapd
);
263 hostapd_free_hapd_data(hapd
);
266 hostapd_config_free(conf
);
271 uc_hostapd_bss_ctrl(uc_vm_t
*vm
, size_t nargs
)
273 struct hostapd_data
*hapd
= uc_fn_thisval("hostapd.bss");
274 uc_value_t
*arg
= uc_fn_arg(0);
275 struct sockaddr_storage from
= {};
276 static char reply
[4096];
279 if (!hapd
|| !interfaces
->ctrl_iface_recv
||
280 ucv_type(arg
) != UC_STRING
)
283 reply_len
= interfaces
->ctrl_iface_recv(hapd
, ucv_string_get(arg
),
284 reply
, sizeof(reply
),
285 &from
, sizeof(from
));
289 if (reply_len
&& reply
[reply_len
- 1] == '\n')
292 return ucv_string_new_length(reply
, reply_len
);
296 uc_hostapd_iface_stop(uc_vm_t
*vm
, size_t nargs
)
298 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
301 for (i
= 0; i
< iface
->num_bss
; i
++) {
302 struct hostapd_data
*hapd
= iface
->bss
[i
];
304 hostapd_drv_stop_ap(hapd
);
310 uc_hostapd_iface_start(uc_vm_t
*vm
, size_t nargs
)
312 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
313 uc_value_t
*info
= uc_fn_arg(0);
314 struct hostapd_config
*conf
;
324 if (ucv_type(info
) != UC_OBJECT
)
328 if ((intval
= ucv_int64_get(ucv_object_get(info
, "op_class", NULL
))) && !errno
)
329 conf
->op_class
= intval
;
330 if ((intval
= ucv_int64_get(ucv_object_get(info
, "hw_mode", NULL
))) && !errno
)
331 conf
->hw_mode
= intval
;
332 if ((intval
= ucv_int64_get(ucv_object_get(info
, "channel", NULL
))) && !errno
)
333 conf
->channel
= intval
;
334 if ((intval
= ucv_int64_get(ucv_object_get(info
, "sec_channel", NULL
))) && !errno
)
335 conf
->secondary_channel
= intval
;
337 intval
= ucv_int64_get(ucv_object_get(info
, "center_seg0_idx", NULL
));
339 hostapd_set_oper_centr_freq_seg0_idx(conf
, intval
);
341 intval
= ucv_int64_get(ucv_object_get(info
, "center_seg1_idx", NULL
));
343 hostapd_set_oper_centr_freq_seg1_idx(conf
, intval
);
345 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
347 hostapd_set_oper_chwidth(conf
, intval
);
351 iface
->freq
= hostapd_hw_get_freq(iface
->bss
[0], conf
->channel
);
353 if (hostapd_is_dfs_required(iface
) && !hostapd_is_dfs_chan_available(iface
)) {
354 wpa_printf(MSG_INFO
, "DFS CAC required on new channel, restart interface");
355 hostapd_disable_iface(iface
);
356 hostapd_enable_iface(iface
);
357 return ucv_boolean_new(true);
360 for (i
= 0; i
< iface
->num_bss
; i
++) {
361 struct hostapd_data
*hapd
= iface
->bss
[i
];
365 hapd
->conf
->start_disabled
= 0;
366 hostapd_set_freq(hapd
, conf
->hw_mode
, iface
->freq
,
374 conf
->secondary_channel
,
375 hostapd_get_oper_chwidth(conf
),
376 hostapd_get_oper_centr_freq_seg0_idx(conf
),
377 hostapd_get_oper_centr_freq_seg1_idx(conf
));
379 ieee802_11_set_beacon(hapd
);
382 return ucv_boolean_new(true);
386 uc_hostapd_iface_switch_channel(uc_vm_t
*vm
, size_t nargs
)
388 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
389 uc_value_t
*info
= uc_fn_arg(0);
390 struct hostapd_config
*conf
;
391 struct csa_settings csa
= {};
395 if (!iface
|| ucv_type(info
) != UC_OBJECT
)
399 if ((intval
= ucv_int64_get(ucv_object_get(info
, "csa_count", NULL
))) && !errno
)
400 csa
.cs_count
= intval
;
401 if ((intval
= ucv_int64_get(ucv_object_get(info
, "sec_channel", NULL
))) && !errno
)
402 csa
.freq_params
.sec_channel_offset
= intval
;
404 csa
.freq_params
.ht_enabled
= conf
->ieee80211n
;
405 csa
.freq_params
.vht_enabled
= conf
->ieee80211ac
;
406 csa
.freq_params
.he_enabled
= conf
->ieee80211ax
;
407 #ifdef CONFIG_IEEE80211BE
408 csa
.freq_params
.eht_enabled
= conf
->ieee80211be
;
410 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
412 intval
= hostapd_get_oper_chwidth(conf
);
414 csa
.freq_params
.bandwidth
= 40 << intval
;
416 csa
.freq_params
.bandwidth
= csa
.freq_params
.sec_channel_offset
? 40 : 20;
418 if ((intval
= ucv_int64_get(ucv_object_get(info
, "frequency", NULL
))) && !errno
)
419 csa
.freq_params
.freq
= intval
;
420 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_freq1", NULL
))) && !errno
)
421 csa
.freq_params
.center_freq1
= intval
;
422 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_freq2", NULL
))) && !errno
)
423 csa
.freq_params
.center_freq2
= intval
;
425 for (i
= 0; i
< iface
->num_bss
; i
++)
426 ret
= hostapd_switch_channel(iface
->bss
[i
], &csa
);
428 return ucv_boolean_new(!ret
);
431 int hostapd_ucode_init(struct hapd_interfaces
*ifaces
)
433 static const uc_function_list_t global_fns
[] = {
434 { "printf", uc_wpa_printf
},
435 { "getpid", uc_wpa_getpid
},
436 { "sha1", uc_wpa_sha1
},
437 { "freq_info", uc_wpa_freq_info
},
438 { "add_iface", uc_hostapd_add_iface
},
439 { "remove_iface", uc_hostapd_remove_iface
},
441 static const uc_function_list_t bss_fns
[] = {
442 { "ctrl", uc_hostapd_bss_ctrl
},
443 { "set_config", uc_hostapd_bss_set_config
},
444 { "delete", uc_hostapd_bss_delete
},
446 static const uc_function_list_t iface_fns
[] = {
447 { "add_bss", uc_hostapd_iface_add_bss
},
448 { "stop", uc_hostapd_iface_stop
},
449 { "start", uc_hostapd_iface_start
},
450 { "switch_channel", uc_hostapd_iface_switch_channel
},
452 uc_value_t
*data
, *proto
;
455 vm
= wpa_ucode_create_vm();
457 global_type
= uc_type_declare(vm
, "hostapd.global", global_fns
, NULL
);
458 bss_type
= uc_type_declare(vm
, "hostapd.bss", bss_fns
, NULL
);
459 iface_type
= uc_type_declare(vm
, "hostapd.iface", iface_fns
, NULL
);
461 bss_registry
= ucv_array_new(vm
);
462 uc_vm_registry_set(vm
, "hostap.bss_registry", bss_registry
);
464 iface_registry
= ucv_array_new(vm
);
465 uc_vm_registry_set(vm
, "hostap.iface_registry", iface_registry
);
467 global
= wpa_ucode_global_init("hostapd", global_type
);
469 if (wpa_ucode_run(HOSTAPD_UC_PATH
"hostapd.uc"))
480 void hostapd_ucode_free(void)
482 if (wpa_ucode_call_prepare("shutdown") == 0)
483 ucv_put(wpa_ucode_call(0));
487 void hostapd_ucode_free_iface(struct hostapd_iface
*iface
)
489 wpa_ucode_registry_remove(iface_registry
, iface
->ucode
.idx
);
492 void hostapd_ucode_add_bss(struct hostapd_data
*hapd
)
496 if (wpa_ucode_call_prepare("bss_add"))
499 val
= hostapd_ucode_bss_get_uval(hapd
);
500 uc_value_push(ucv_get(ucv_string_new(hapd
->conf
->iface
)));
501 uc_value_push(ucv_get(val
));
502 ucv_put(wpa_ucode_call(2));
506 void hostapd_ucode_reload_bss(struct hostapd_data
*hapd
)
510 if (wpa_ucode_call_prepare("bss_reload"))
513 val
= hostapd_ucode_bss_get_uval(hapd
);
514 uc_value_push(ucv_get(ucv_string_new(hapd
->conf
->iface
)));
515 uc_value_push(ucv_get(val
));
516 ucv_put(wpa_ucode_call(2));
520 void hostapd_ucode_free_bss(struct hostapd_data
*hapd
)
524 val
= wpa_ucode_registry_remove(bss_registry
, hapd
->ucode
.idx
);
529 if (wpa_ucode_call_prepare("bss_remove"))
532 uc_value_push(ucv_string_new(hapd
->conf
->iface
));
533 uc_value_push(ucv_get(val
));
534 ucv_put(wpa_ucode_call(2));