hostapd: add udebug support
[openwrt/staging/jow.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 "drivers/driver.h"
5 #include "ap/hostapd.h"
6 #include "wpa_supplicant_i.h"
7 #include "wps_supplicant.h"
8 #include "bss.h"
9 #include "ucode.h"
10
11 static struct wpa_global *wpa_global;
12 static uc_resource_type_t *global_type, *iface_type;
13 static uc_value_t *global, *iface_registry;
14 static uc_vm_t *vm;
15
16 static uc_value_t *
17 wpas_ucode_iface_get_uval(struct wpa_supplicant *wpa_s)
18 {
19 uc_value_t *val;
20
21 if (wpa_s->ucode.idx)
22 return wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
23
24 val = uc_resource_new(iface_type, wpa_s);
25 wpa_s->ucode.idx = wpa_ucode_registry_add(iface_registry, val);
26
27 return val;
28 }
29
30 static void
31 wpas_ucode_update_interfaces(void)
32 {
33 uc_value_t *ifs = ucv_object_new(vm);
34 struct wpa_supplicant *wpa_s;
35 int i;
36
37 for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
38 ucv_object_add(ifs, wpa_s->ifname, ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
39
40 ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
41 ucv_gc(vm);
42 }
43
44 void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
45 {
46 uc_value_t *val;
47
48 if (wpa_ucode_call_prepare("iface_add"))
49 return;
50
51 uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
52 uc_value_push(ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
53 ucv_put(wpa_ucode_call(2));
54 ucv_gc(vm);
55 }
56
57 void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
58 {
59 uc_value_t *val;
60
61 val = wpa_ucode_registry_remove(iface_registry, wpa_s->ucode.idx);
62 if (!val)
63 return;
64
65 wpa_s->ucode.idx = 0;
66 if (wpa_ucode_call_prepare("iface_remove"))
67 return;
68
69 uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
70 uc_value_push(ucv_get(val));
71 ucv_put(wpa_ucode_call(2));
72 ucv_gc(vm);
73 }
74
75 void wpas_ucode_update_state(struct wpa_supplicant *wpa_s)
76 {
77 const char *state;
78 uc_value_t *val;
79
80 val = wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
81 if (!val)
82 return;
83
84 if (wpa_ucode_call_prepare("state"))
85 return;
86
87 state = wpa_supplicant_state_txt(wpa_s->wpa_state);
88 uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
89 uc_value_push(ucv_get(val));
90 uc_value_push(ucv_get(ucv_string_new(state)));
91 ucv_put(wpa_ucode_call(3));
92 ucv_gc(vm);
93 }
94
95 void wpas_ucode_event(struct wpa_supplicant *wpa_s, int event, union wpa_event_data *data)
96 {
97 const char *state;
98 uc_value_t *val;
99
100 if (event != EVENT_CH_SWITCH_STARTED)
101 return;
102
103 val = wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
104 if (!val)
105 return;
106
107 if (wpa_ucode_call_prepare("event"))
108 return;
109
110 uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
111 uc_value_push(ucv_get(val));
112 uc_value_push(ucv_get(ucv_string_new(event_to_string(event))));
113 val = ucv_object_new(vm);
114 uc_value_push(ucv_get(val));
115
116 if (event == EVENT_CH_SWITCH_STARTED) {
117 ucv_object_add(val, "csa_count", ucv_int64_new(data->ch_switch.count));
118 ucv_object_add(val, "frequency", ucv_int64_new(data->ch_switch.freq));
119 ucv_object_add(val, "sec_chan_offset", ucv_int64_new(data->ch_switch.ch_offset));
120 ucv_object_add(val, "center_freq1", ucv_int64_new(data->ch_switch.cf1));
121 ucv_object_add(val, "center_freq2", ucv_int64_new(data->ch_switch.cf2));
122 }
123
124 ucv_put(wpa_ucode_call(4));
125 ucv_gc(vm);
126 }
127
128 static const char *obj_stringval(uc_value_t *obj, const char *name)
129 {
130 uc_value_t *val = ucv_object_get(obj, name, NULL);
131
132 return ucv_string_get(val);
133 }
134
135 static uc_value_t *
136 uc_wpas_add_iface(uc_vm_t *vm, size_t nargs)
137 {
138 uc_value_t *info = uc_fn_arg(0);
139 uc_value_t *driver = ucv_object_get(info, "driver", NULL);
140 uc_value_t *ifname = ucv_object_get(info, "iface", NULL);
141 uc_value_t *bridge = ucv_object_get(info, "bridge", NULL);
142 uc_value_t *config = ucv_object_get(info, "config", NULL);
143 uc_value_t *ctrl = ucv_object_get(info, "ctrl", NULL);
144 struct wpa_interface iface;
145 int ret = -1;
146
147 if (ucv_type(info) != UC_OBJECT)
148 goto out;
149
150 iface = (struct wpa_interface){
151 .driver = "nl80211",
152 .ifname = ucv_string_get(ifname),
153 .bridge_ifname = ucv_string_get(bridge),
154 .confname = ucv_string_get(config),
155 .ctrl_interface = ucv_string_get(ctrl),
156 };
157
158 if (driver) {
159 const char *drvname;
160 if (ucv_type(driver) != UC_STRING)
161 goto out;
162
163 iface.driver = NULL;
164 drvname = ucv_string_get(driver);
165 for (int i = 0; wpa_drivers[i]; i++) {
166 if (!strcmp(drvname, wpa_drivers[i]->name))
167 iface.driver = wpa_drivers[i]->name;
168 }
169
170 if (!iface.driver)
171 goto out;
172 }
173
174 if (!iface.ifname || !iface.confname)
175 goto out;
176
177 ret = wpa_supplicant_add_iface(wpa_global, &iface, 0) ? 0 : -1;
178 wpas_ucode_update_interfaces();
179
180 out:
181 return ucv_int64_new(ret);
182 }
183
184 static uc_value_t *
185 uc_wpas_remove_iface(uc_vm_t *vm, size_t nargs)
186 {
187 struct wpa_supplicant *wpa_s = NULL;
188 uc_value_t *ifname_arg = uc_fn_arg(0);
189 const char *ifname = ucv_string_get(ifname_arg);
190 int ret = -1;
191
192 if (!ifname)
193 goto out;
194
195 for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
196 if (!strcmp(wpa_s->ifname, ifname))
197 break;
198
199 if (!wpa_s)
200 goto out;
201
202 ret = wpa_supplicant_remove_iface(wpa_global, wpa_s, 0);
203 wpas_ucode_update_interfaces();
204
205 out:
206 return ucv_int64_new(ret);
207 }
208
209 static uc_value_t *
210 uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
211 {
212 struct wpa_supplicant *wpa_s = uc_fn_thisval("wpas.iface");
213 struct wpa_bss *bss;
214 uc_value_t *ret, *val;
215
216 if (!wpa_s)
217 return NULL;
218
219 ret = ucv_object_new(vm);
220
221 val = ucv_string_new(wpa_supplicant_state_txt(wpa_s->wpa_state));
222 ucv_object_add(ret, "state", ucv_get(val));
223
224 bss = wpa_s->current_bss;
225 if (bss) {
226 int sec_chan = 0;
227 const u8 *ie;
228
229 ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
230 if (ie && ie[1] >= 2) {
231 const struct ieee80211_ht_operation *ht_oper;
232 int sec;
233
234 ht_oper = (const void *) (ie + 2);
235 sec = ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
236 if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
237 sec_chan = 1;
238 else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
239 sec_chan = -1;
240 }
241
242 ucv_object_add(ret, "sec_chan_offset", ucv_int64_new(sec_chan));
243 ucv_object_add(ret, "frequency", ucv_int64_new(bss->freq));
244 }
245
246 #ifdef CONFIG_MESH
247 if (wpa_s->ifmsh) {
248 struct hostapd_iface *ifmsh = wpa_s->ifmsh;
249
250 ucv_object_add(ret, "sec_chan_offset", ucv_int64_new(ifmsh->conf->secondary_channel));
251 ucv_object_add(ret, "frequency", ucv_int64_new(ifmsh->freq));
252 }
253 #endif
254
255 return ret;
256 }
257
258 int wpas_ucode_init(struct wpa_global *gl)
259 {
260 static const uc_function_list_t global_fns[] = {
261 { "printf", uc_wpa_printf },
262 { "getpid", uc_wpa_getpid },
263 { "add_iface", uc_wpas_add_iface },
264 { "remove_iface", uc_wpas_remove_iface },
265 { "udebug_set", uc_wpa_udebug_set },
266 };
267 static const uc_function_list_t iface_fns[] = {
268 { "status", uc_wpas_iface_status },
269 };
270 uc_value_t *data, *proto;
271
272 wpa_global = gl;
273 vm = wpa_ucode_create_vm();
274
275 global_type = uc_type_declare(vm, "wpas.global", global_fns, NULL);
276 iface_type = uc_type_declare(vm, "wpas.iface", iface_fns, NULL);
277
278 iface_registry = ucv_array_new(vm);
279 uc_vm_registry_set(vm, "wpas.iface_registry", iface_registry);
280
281 global = wpa_ucode_global_init("wpas", global_type);
282
283 if (wpa_ucode_run(HOSTAPD_UC_PATH "wpa_supplicant.uc"))
284 goto free_vm;
285
286 ucv_gc(vm);
287 return 0;
288
289 free_vm:
290 wpa_ucode_free_vm();
291 return -1;
292 }
293
294 void wpas_ucode_free(void)
295 {
296 if (wpa_ucode_call_prepare("shutdown") == 0)
297 ucv_put(wpa_ucode_call(0));
298 wpa_ucode_free_vm();
299 }