3 #include "utils/eloop.h"
4 #include "crypto/crypto.h"
5 #include "crypto/sha1.h"
6 #include "common/ieee802_11_common.h"
7 #include <libubox/uloop.h>
8 #include <ucode/compiler.h>
10 static uc_value_t
*registry
;
12 static struct uloop_timeout gc_timer
;
14 static void uc_gc_timer(struct uloop_timeout
*timeout
)
19 uc_value_t
*uc_wpa_printf(uc_vm_t
*vm
, size_t nargs
)
21 uc_value_t
*level
= uc_fn_arg(0);
22 uc_value_t
*ret
, **args
;
23 uc_cfn_ptr_t _sprintf
;
27 _sprintf
= uc_stdlib_function("sprintf");
31 if (ucv_type(level
) == UC_INTEGER
) {
32 l
= ucv_int64_get(level
);
39 ret
= _sprintf(vm
, nargs
- start
);
40 if (ucv_type(ret
) != UC_STRING
)
43 wpa_printf(l
, "%s", ucv_string_get(ret
));
49 uc_value_t
*uc_wpa_freq_info(uc_vm_t
*vm
, size_t nargs
)
51 uc_value_t
*freq
= uc_fn_arg(0);
52 uc_value_t
*sec
= uc_fn_arg(1);
53 int width
= ucv_uint64_get(uc_fn_arg(2));
54 int freq_val
, center_idx
, center_ofs
;
55 enum oper_chan_width chanwidth
;
56 enum hostapd_hw_mode hw_mode
;
57 u8 op_class
, channel
, tmp_channel
;
62 if (ucv_type(freq
) != UC_INTEGER
)
65 freq_val
= ucv_int64_get(freq
);
66 if (ucv_type(sec
) == UC_INTEGER
)
67 sec_channel
= ucv_int64_get(sec
);
70 else if (freq_val
> 4000)
71 sec_channel
= (freq_val
/ 20) & 1 ? 1 : -1;
73 sec_channel
= freq_val
< 2442 ? 1 : -1;
75 if (sec_channel
!= -1 && sec_channel
!= 1 && sec_channel
!= 0)
80 chanwidth
= CONF_OPER_CHWIDTH_USE_HT
;
83 chanwidth
= CONF_OPER_CHWIDTH_80MHZ
;
86 chanwidth
= CONF_OPER_CHWIDTH_160MHZ
;
92 hw_mode
= ieee80211_freq_to_channel_ext(freq_val
, sec_channel
,
93 chanwidth
, &op_class
, &channel
);
95 case HOSTAPD_MODE_IEEE80211B
:
98 case HOSTAPD_MODE_IEEE80211G
:
101 case HOSTAPD_MODE_IEEE80211A
:
104 case HOSTAPD_MODE_IEEE80211AD
:
111 ret
= ucv_object_new(vm
);
112 ucv_object_add(ret
, "op_class", ucv_int64_new(op_class
));
113 ucv_object_add(ret
, "channel", ucv_int64_new(channel
));
114 ucv_object_add(ret
, "hw_mode", ucv_int64_new(hw_mode
));
115 ucv_object_add(ret
, "hw_mode_str", ucv_get(ucv_string_new(modestr
)));
116 ucv_object_add(ret
, "sec_channel", ucv_int64_new(sec_channel
));
117 ucv_object_add(ret
, "frequency", ucv_int64_new(freq_val
));
122 if (freq_val
>= 5900)
124 else if (freq_val
>= 5745)
128 tmp_channel
= channel
- center_ofs
;
129 tmp_channel
&= ~((8 << width
) - 1);
130 center_idx
= tmp_channel
+ center_ofs
+ (4 << width
) - 1;
133 ucv_object_add(ret
, "center_seg0_idx", ucv_int64_new(0));
135 ucv_object_add(ret
, "center_seg0_idx", ucv_int64_new(center_idx
));
136 center_idx
= (center_idx
- channel
) * 5 + freq_val
;
137 ucv_object_add(ret
, "center_freq1", ucv_int64_new(center_idx
));
143 uc_value_t
*uc_wpa_getpid(uc_vm_t
*vm
, size_t nargs
)
145 return ucv_int64_new(getpid());
148 uc_value_t
*uc_wpa_sha1(uc_vm_t
*vm
, size_t nargs
)
150 u8 hash
[SHA1_MAC_LEN
];
151 char hash_hex
[2 * ARRAY_SIZE(hash
) + 1];
160 args
= alloca(nargs
* sizeof(*args
));
161 lens
= alloca(nargs
* sizeof(*lens
));
162 for (i
= 0; i
< nargs
; i
++) {
164 if (ucv_type(val
) != UC_STRING
)
167 args
[i
] = ucv_string_get(val
);
168 lens
[i
] = ucv_string_length(val
);
171 if (sha1_vector(nargs
, args
, lens
, hash
))
174 for (i
= 0; i
< ARRAY_SIZE(hash
); i
++)
175 sprintf(hash_hex
+ 2 * i
, "%02x", hash
[i
]);
177 return ucv_string_new_length(hash_hex
, 2 * ARRAY_SIZE(hash
));
180 uc_vm_t
*wpa_ucode_create_vm(void)
182 static uc_parse_config_t config
= {
183 .strict_declarations
= true,
184 .lstrip_blocks
= true,
189 uc_search_path_init(&config
.module_search_path
);
190 uc_search_path_add(&config
.module_search_path
, HOSTAPD_UC_PATH
"*.so");
191 uc_search_path_add(&config
.module_search_path
, HOSTAPD_UC_PATH
"*.uc");
193 uc_vm_init(&vm
, &config
);
195 uc_stdlib_load(uc_vm_scope_get(&vm
));
197 gc_timer
.cb
= uc_gc_timer
;
202 int wpa_ucode_run(const char *script
)
210 source
= uc_source_new_file(script
);
214 prog
= uc_compile(vm
.config
, source
, &err
);
215 uc_source_put(source
);
217 wpa_printf(MSG_ERROR
, "Error loading ucode: %s\n", err
);
221 ret
= uc_vm_execute(&vm
, prog
, &ops
);
222 uc_program_put(prog
);
226 registry
= ucv_array_new(&vm
);
227 uc_vm_registry_set(&vm
, "hostap.registry", registry
);
228 ucv_array_set(registry
, 0, ucv_get(ops
));
233 int wpa_ucode_call_prepare(const char *fname
)
235 uc_value_t
*obj
, *func
;
240 obj
= ucv_array_get(registry
, 0);
244 func
= ucv_object_get(obj
, fname
, NULL
);
245 if (!ucv_is_callable(func
))
248 uc_vm_stack_push(&vm
, ucv_get(obj
));
249 uc_vm_stack_push(&vm
, ucv_get(func
));
254 uc_value_t
*wpa_ucode_global_init(const char *name
, uc_resource_type_t
*global_type
)
256 uc_value_t
*global
= uc_resource_new(global_type
, NULL
);
259 uc_vm_registry_set(&vm
, "hostap.global", global
);
260 proto
= ucv_prototype_get(global
);
261 ucv_object_add(proto
, "data", ucv_get(ucv_object_new(&vm
)));
263 #define ADD_CONST(x) ucv_object_add(proto, #x, ucv_int64_new(x))
264 ADD_CONST(MSG_EXCESSIVE
);
265 ADD_CONST(MSG_MSGDUMP
);
266 ADD_CONST(MSG_DEBUG
);
268 ADD_CONST(MSG_WARNING
);
269 ADD_CONST(MSG_ERROR
);
272 ucv_object_add(uc_vm_scope_get(&vm
), name
, ucv_get(global
));
277 int wpa_ucode_registry_add(uc_value_t
*reg
, uc_value_t
*val
)
282 while (ucv_array_get(reg
, i
))
285 ucv_array_set(reg
, i
, ucv_get(val
));
290 uc_value_t
*wpa_ucode_registry_get(uc_value_t
*reg
, int idx
)
295 return ucv_array_get(reg
, idx
- 1);
298 uc_value_t
*wpa_ucode_registry_remove(uc_value_t
*reg
, int idx
)
300 uc_value_t
*val
= wpa_ucode_registry_get(reg
, idx
);
303 ucv_array_set(reg
, idx
- 1, NULL
);
309 uc_value_t
*wpa_ucode_call(size_t nargs
)
311 if (uc_vm_call(&vm
, true, nargs
) != EXCEPTION_NONE
)
314 if (!gc_timer
.pending
)
315 uloop_timeout_set(&gc_timer
, 10);
317 return uc_vm_stack_pop(&vm
);
320 void wpa_ucode_free_vm(void)
325 uc_search_path_free(&vm
.config
->module_search_path
);