openwrt/package/network/services/hostapd/src/wpa_supplicant/ucode.c

178 lines
4.1 KiB
C

#include "utils/includes.h"
#include "utils/common.h"
#include "utils/ucode.h"
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
#include "ucode.h"
static struct wpa_global *wpa_global;
static uc_resource_type_t *global_type, *iface_type;
static uc_value_t *global, *iface_registry;
static uc_vm_t *vm;
static uc_value_t *
wpas_ucode_iface_get_uval(struct wpa_supplicant *wpa_s)
{
uc_value_t *val;
if (wpa_s->ucode.idx)
return wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
val = uc_resource_new(iface_type, wpa_s);
wpa_ucode_registry_add(iface_registry, val, &wpa_s->ucode.idx);
return val;
}
static void
wpas_ucode_update_interfaces(void)
{
uc_value_t *ifs = ucv_object_new(vm);
struct wpa_supplicant *wpa_s;
int i;
for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
ucv_object_add(ifs, wpa_s->ifname, ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
ucv_gc(vm);
}
void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
{
uc_value_t *val;
if (wpa_ucode_call_prepare("iface_add"))
return;
uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
uc_value_push(ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
ucv_put(wpa_ucode_call(2));
ucv_gc(vm);
}
void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
{
uc_value_t *val;
val = wpa_ucode_registry_remove(iface_registry, wpa_s->ucode.idx);
if (!val)
return;
wpa_s->ucode.idx = 0;
if (wpa_ucode_call_prepare("iface_remove"))
return;
uc_value_push(ucv_string_new(wpa_s->ifname));
uc_value_push(ucv_get(val));
ucv_put(wpa_ucode_call(2));
ucv_gc(vm);
}
static const char *obj_stringval(uc_value_t *obj, const char *name)
{
uc_value_t *val = ucv_object_get(obj, name, NULL);
return ucv_string_get(val);
}
static uc_value_t *
uc_wpas_add_iface(uc_vm_t *vm, size_t nargs)
{
uc_value_t *info = uc_fn_arg(0);
uc_value_t *ifname = ucv_object_get(info, "iface", NULL);
uc_value_t *bridge = ucv_object_get(info, "bridge", NULL);
uc_value_t *config = ucv_object_get(info, "config", NULL);
uc_value_t *ctrl = ucv_object_get(info, "ctrl", NULL);
uc_value_t *hapd_ctrl = ucv_object_get(info, "hostapd_ctrl", NULL);
struct wpa_interface iface;
int ret = -1;
if (ucv_type(info) != UC_OBJECT)
goto out;
iface = (struct wpa_interface){
.driver = "nl80211",
.ifname = ucv_string_get(ifname),
.bridge_ifname = ucv_string_get(bridge),
.confname = ucv_string_get(config),
.ctrl_interface = ucv_string_get(ctrl),
.hostapd_ctrl = ucv_string_get(hapd_ctrl),
};
if (!iface.ifname || !iface.confname)
goto out;
ret = wpa_supplicant_add_iface(wpa_global, &iface, 0) ? 0 : -1;
wpas_ucode_update_interfaces();
out:
return ucv_int64_new(ret);
}
static uc_value_t *
uc_wpas_remove_iface(uc_vm_t *vm, size_t nargs)
{
struct wpa_supplicant *wpa_s = NULL;
uc_value_t *ifname_arg = uc_fn_arg(0);
const char *ifname = ucv_string_get(ifname_arg);
int ret = -1;
if (!ifname)
goto out;
for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
if (!strcmp(wpa_s->ifname, ifname))
break;
if (!wpa_s)
goto out;
ret = wpa_supplicant_remove_iface(wpa_global, wpa_s, 0);
wpas_ucode_update_interfaces();
out:
return ucv_int64_new(ret);
}
int wpas_ucode_init(struct wpa_global *gl)
{
static const uc_function_list_t global_fns[] = {
{ "printf", uc_wpa_printf },
{ "getpid", uc_wpa_getpid },
{ "add_iface", uc_wpas_add_iface },
{ "remove_iface", uc_wpas_remove_iface },
};
static const uc_function_list_t iface_fns[] = {
};
uc_value_t *data, *proto;
wpa_global = gl;
vm = wpa_ucode_create_vm();
global_type = uc_type_declare(vm, "wpas.global", global_fns, NULL);
iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
iface_registry = ucv_array_new(vm);
uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
global = wpa_ucode_global_init("wpas", global_type);
if (wpa_ucode_run(HOSTAPD_UC_PATH "wpa_supplicant.uc"))
goto free_vm;
ucv_gc(vm);
return 0;
free_vm:
wpa_ucode_free_vm();
return -1;
}
void wpas_ucode_free(void)
{
if (wpa_ucode_call_prepare("shutdown") == 0)
ucv_put(wpa_ucode_call(0));
wpa_ucode_free_vm();
}