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