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
;
336 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_seg0_idx", NULL
))) && !errno
)
337 hostapd_set_oper_centr_freq_seg0_idx(conf
, intval
);
338 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_seg1_idx", NULL
))) && !errno
)
339 hostapd_set_oper_centr_freq_seg1_idx(conf
, intval
);
340 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
342 hostapd_set_oper_chwidth(conf
, intval
);
346 iface
->freq
= hostapd_hw_get_freq(iface
->bss
[0], conf
->channel
);
348 if (hostapd_is_dfs_required(iface
) && !hostapd_is_dfs_chan_available(iface
)) {
349 wpa_printf(MSG_INFO
, "DFS CAC required on new channel, restart interface");
350 hostapd_disable_iface(iface
);
351 hostapd_enable_iface(iface
);
352 return ucv_boolean_new(true);
355 for (i
= 0; i
< iface
->num_bss
; i
++) {
356 struct hostapd_data
*hapd
= iface
->bss
[i
];
360 hostapd_set_freq(hapd
, conf
->hw_mode
, iface
->freq
,
368 conf
->secondary_channel
,
369 hostapd_get_oper_chwidth(conf
),
370 hostapd_get_oper_centr_freq_seg0_idx(conf
),
371 hostapd_get_oper_centr_freq_seg1_idx(conf
));
373 ieee802_11_set_beacon(hapd
);
376 return ucv_boolean_new(true);
380 uc_hostapd_iface_switch_channel(uc_vm_t
*vm
, size_t nargs
)
382 struct hostapd_iface
*iface
= uc_fn_thisval("hostapd.iface");
383 uc_value_t
*info
= uc_fn_arg(0);
384 struct hostapd_config
*conf
;
385 struct csa_settings csa
= {};
389 if (!iface
|| ucv_type(info
) != UC_OBJECT
)
393 if ((intval
= ucv_int64_get(ucv_object_get(info
, "csa_count", NULL
))) && !errno
)
394 csa
.cs_count
= intval
;
395 if ((intval
= ucv_int64_get(ucv_object_get(info
, "sec_channel", NULL
))) && !errno
)
396 csa
.freq_params
.sec_channel_offset
= intval
;
398 csa
.freq_params
.ht_enabled
= conf
->ieee80211n
;
399 csa
.freq_params
.vht_enabled
= conf
->ieee80211ac
;
400 csa
.freq_params
.he_enabled
= conf
->ieee80211ax
;
401 #ifdef CONFIG_IEEE80211BE
402 csa
.freq_params
.eht_enabled
= conf
->ieee80211be
;
404 intval
= ucv_int64_get(ucv_object_get(info
, "oper_chwidth", NULL
));
406 intval
= hostapd_get_oper_chwidth(conf
);
408 csa
.freq_params
.bandwidth
= 40 << intval
;
410 csa
.freq_params
.bandwidth
= csa
.freq_params
.sec_channel_offset
? 40 : 20;
412 if ((intval
= ucv_int64_get(ucv_object_get(info
, "frequency", NULL
))) && !errno
)
413 csa
.freq_params
.freq
= intval
;
414 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_freq1", NULL
))) && !errno
)
415 csa
.freq_params
.center_freq1
= intval
;
416 if ((intval
= ucv_int64_get(ucv_object_get(info
, "center_freq2", NULL
))) && !errno
)
417 csa
.freq_params
.center_freq2
= intval
;
419 for (i
= 0; i
< iface
->num_bss
; i
++)
420 ret
= hostapd_switch_channel(iface
->bss
[i
], &csa
);
422 return ucv_boolean_new(!ret
);
425 int hostapd_ucode_init(struct hapd_interfaces
*ifaces
)
427 static const uc_function_list_t global_fns
[] = {
428 { "printf", uc_wpa_printf
},
429 { "getpid", uc_wpa_getpid
},
430 { "sha1", uc_wpa_sha1
},
431 { "freq_info", uc_wpa_freq_info
},
432 { "add_iface", uc_hostapd_add_iface
},
433 { "remove_iface", uc_hostapd_remove_iface
},
435 static const uc_function_list_t bss_fns
[] = {
436 { "ctrl", uc_hostapd_bss_ctrl
},
437 { "set_config", uc_hostapd_bss_set_config
},
438 { "delete", uc_hostapd_bss_delete
},
440 static const uc_function_list_t iface_fns
[] = {
441 { "add_bss", uc_hostapd_iface_add_bss
},
442 { "stop", uc_hostapd_iface_stop
},
443 { "start", uc_hostapd_iface_start
},
444 { "switch_channel", uc_hostapd_iface_switch_channel
},
446 uc_value_t
*data
, *proto
;
449 vm
= wpa_ucode_create_vm();
451 global_type
= uc_type_declare(vm
, "hostapd.global", global_fns
, NULL
);
452 bss_type
= uc_type_declare(vm
, "hostapd.bss", bss_fns
, NULL
);
453 iface_type
= uc_type_declare(vm
, "hostapd.iface", iface_fns
, NULL
);
455 bss_registry
= ucv_array_new(vm
);
456 uc_vm_registry_set(vm
, "hostap.bss_registry", bss_registry
);
458 iface_registry
= ucv_array_new(vm
);
459 uc_vm_registry_set(vm
, "hostap.iface_registry", iface_registry
);
461 global
= wpa_ucode_global_init("hostapd", global_type
);
463 if (wpa_ucode_run(HOSTAPD_UC_PATH
"hostapd.uc"))
474 void hostapd_ucode_free(void)
476 if (wpa_ucode_call_prepare("shutdown") == 0)
477 ucv_put(wpa_ucode_call(0));
481 void hostapd_ucode_free_iface(struct hostapd_iface
*iface
)
483 wpa_ucode_registry_remove(iface_registry
, iface
->ucode
.idx
);
486 void hostapd_ucode_add_bss(struct hostapd_data
*hapd
)
490 if (wpa_ucode_call_prepare("bss_add"))
493 val
= hostapd_ucode_bss_get_uval(hapd
);
494 uc_value_push(ucv_get(ucv_string_new(hapd
->conf
->iface
)));
495 uc_value_push(ucv_get(val
));
496 ucv_put(wpa_ucode_call(2));
500 void hostapd_ucode_reload_bss(struct hostapd_data
*hapd
)
504 if (wpa_ucode_call_prepare("bss_reload"))
507 val
= hostapd_ucode_bss_get_uval(hapd
);
508 uc_value_push(ucv_get(ucv_string_new(hapd
->conf
->iface
)));
509 uc_value_push(ucv_get(val
));
510 ucv_put(wpa_ucode_call(2));
514 void hostapd_ucode_free_bss(struct hostapd_data
*hapd
)
518 val
= wpa_ucode_registry_remove(bss_registry
, hapd
->ucode
.idx
);
523 if (wpa_ucode_call_prepare("bss_remove"))
526 uc_value_push(ucv_string_new(hapd
->conf
->iface
));
527 uc_value_push(ucv_get(val
));
528 ucv_put(wpa_ucode_call(2));