eec398032924c296b07206c1a9a3716e16fa0a00
[openwrt/openwrt.git] / package / network / services / hostapd / src / wpa_supplicant / ucode.c
1 #include "utils/includes.h"
2 #include "utils/common.h"
3 #include "utils/ucode.h"
4 #include "wpa_supplicant_i.h"
5 #include "wps_supplicant.h"
6 #include "ucode.h"
7
8 static struct wpa_global *wpa_global;
9 static uc_resource_type_t *global_type, *iface_type;
10 static uc_value_t *global, *iface_registry;
11 static uc_vm_t *vm;
12
13 static uc_value_t *
14 wpas_ucode_iface_get_uval(struct wpa_supplicant *wpa_s)
15 {
16 uc_value_t *val;
17
18 if (wpa_s->ucode.idx)
19 return wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
20
21 val = uc_resource_new(iface_type, wpa_s);
22 wpa_ucode_registry_add(iface_registry, val, &wpa_s->ucode.idx);
23
24 return val;
25 }
26
27 static void
28 wpas_ucode_update_interfaces(void)
29 {
30 uc_value_t *ifs = ucv_object_new(vm);
31 struct wpa_supplicant *wpa_s;
32 int i;
33
34 for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
35 ucv_object_add(ifs, wpa_s->ifname, ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
36
37 ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
38 ucv_gc(vm);
39 }
40
41 void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
42 {
43 uc_value_t *val;
44
45 if (wpa_ucode_call_prepare("iface_add"))
46 return;
47
48 uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
49 uc_value_push(ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
50 ucv_put(wpa_ucode_call(2));
51 ucv_gc(vm);
52 }
53
54 void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
55 {
56 uc_value_t *val;
57
58 val = wpa_ucode_registry_remove(iface_registry, wpa_s->ucode.idx);
59 if (!val)
60 return;
61
62 wpa_s->ucode.idx = 0;
63 if (wpa_ucode_call_prepare("iface_remove"))
64 return;
65
66 uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
67 uc_value_push(ucv_get(val));
68 ucv_put(wpa_ucode_call(2));
69 ucv_gc(vm);
70 }
71
72 static const char *obj_stringval(uc_value_t *obj, const char *name)
73 {
74 uc_value_t *val = ucv_object_get(obj, name, NULL);
75
76 return ucv_string_get(val);
77 }
78
79 static uc_value_t *
80 uc_wpas_add_iface(uc_vm_t *vm, size_t nargs)
81 {
82 uc_value_t *info = uc_fn_arg(0);
83 uc_value_t *ifname = ucv_object_get(info, "iface", NULL);
84 uc_value_t *bridge = ucv_object_get(info, "bridge", NULL);
85 uc_value_t *config = ucv_object_get(info, "config", NULL);
86 uc_value_t *ctrl = ucv_object_get(info, "ctrl", NULL);
87 uc_value_t *hapd_ctrl = ucv_object_get(info, "hostapd_ctrl", NULL);
88 struct wpa_interface iface;
89 int ret = -1;
90
91 if (ucv_type(info) != UC_OBJECT)
92 goto out;
93
94 iface = (struct wpa_interface){
95 .driver = "nl80211",
96 .ifname = ucv_string_get(ifname),
97 .bridge_ifname = ucv_string_get(bridge),
98 .confname = ucv_string_get(config),
99 .ctrl_interface = ucv_string_get(ctrl),
100 .hostapd_ctrl = ucv_string_get(hapd_ctrl),
101 };
102
103 if (!iface.ifname || !iface.confname)
104 goto out;
105
106 ret = wpa_supplicant_add_iface(wpa_global, &iface, 0) ? 0 : -1;
107 wpas_ucode_update_interfaces();
108
109 out:
110 return ucv_int64_new(ret);
111 }
112
113 static uc_value_t *
114 uc_wpas_remove_iface(uc_vm_t *vm, size_t nargs)
115 {
116 struct wpa_supplicant *wpa_s = NULL;
117 uc_value_t *ifname_arg = uc_fn_arg(0);
118 const char *ifname = ucv_string_get(ifname_arg);
119 int ret = -1;
120
121 if (!ifname)
122 goto out;
123
124 for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
125 if (!strcmp(wpa_s->ifname, ifname))
126 break;
127
128 if (!wpa_s)
129 goto out;
130
131 ret = wpa_supplicant_remove_iface(wpa_global, wpa_s, 0);
132 wpas_ucode_update_interfaces();
133
134 out:
135 return ucv_int64_new(ret);
136 }
137
138 int wpas_ucode_init(struct wpa_global *gl)
139 {
140 static const uc_function_list_t global_fns[] = {
141 { "printf", uc_wpa_printf },
142 { "getpid", uc_wpa_getpid },
143 { "add_iface", uc_wpas_add_iface },
144 { "remove_iface", uc_wpas_remove_iface },
145 };
146 static const uc_function_list_t iface_fns[] = {
147 };
148 uc_value_t *data, *proto;
149
150 wpa_global = gl;
151 vm = wpa_ucode_create_vm();
152
153 global_type = uc_type_declare(vm, "wpas.global", global_fns, NULL);
154 iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
155
156 iface_registry = ucv_array_new(vm);
157 uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
158
159 global = wpa_ucode_global_init("wpas", global_type);
160
161 if (wpa_ucode_run(HOSTAPD_UC_PATH "wpa_supplicant.uc"))
162 goto free_vm;
163
164 ucv_gc(vm);
165 return 0;
166
167 free_vm:
168 wpa_ucode_free_vm();
169 return -1;
170 }
171
172 void wpas_ucode_free(void)
173 {
174 if (wpa_ucode_call_prepare("shutdown") == 0)
175 ucv_put(wpa_ucode_call(0));
176 wpa_ucode_free_vm();
177 }