3 #include "utils/eloop.h"
4 #include "crypto/crypto.h"
5 #include "crypto/sha1.h"
6 #include "common/ieee802_11_common.h"
7 #include <linux/netlink.h>
8 #include <linux/genetlink.h>
9 #include <linux/nl80211.h>
10 #include <libubox/uloop.h>
11 #include <ucode/compiler.h>
14 static uc_value_t
*registry
;
16 static struct uloop_timeout gc_timer
;
17 static struct udebug ud
;
18 static struct udebug_buf ud_log
, ud_nl
[3];
20 #define UDEBUG_FLAG_RX_FRAME (1ULL << 0)
22 static void uc_gc_timer(struct uloop_timeout
*timeout
)
27 uc_value_t
*uc_wpa_printf(uc_vm_t
*vm
, size_t nargs
)
29 uc_value_t
*level
= uc_fn_arg(0);
30 uc_value_t
*ret
, **args
;
31 uc_cfn_ptr_t _sprintf
;
35 _sprintf
= uc_stdlib_function("sprintf");
39 if (ucv_type(level
) == UC_INTEGER
) {
40 l
= ucv_int64_get(level
);
47 ret
= _sprintf(vm
, nargs
- start
);
48 if (ucv_type(ret
) != UC_STRING
)
51 wpa_printf(l
, "%s", ucv_string_get(ret
));
57 uc_value_t
*uc_wpa_freq_info(uc_vm_t
*vm
, size_t nargs
)
59 uc_value_t
*freq
= uc_fn_arg(0);
60 uc_value_t
*sec
= uc_fn_arg(1);
61 int width
= ucv_uint64_get(uc_fn_arg(2));
62 int freq_val
, center_idx
, center_ofs
;
63 enum oper_chan_width chanwidth
;
64 enum hostapd_hw_mode hw_mode
;
65 u8 op_class
, channel
, tmp_channel
;
70 if (ucv_type(freq
) != UC_INTEGER
)
73 freq_val
= ucv_int64_get(freq
);
74 if (ucv_type(sec
) == UC_INTEGER
)
75 sec_channel
= ucv_int64_get(sec
);
78 else if (freq_val
> 4000)
79 sec_channel
= (freq_val
/ 20) & 1 ? 1 : -1;
81 sec_channel
= freq_val
< 2442 ? 1 : -1;
83 if (sec_channel
!= -1 && sec_channel
!= 1 && sec_channel
!= 0)
88 chanwidth
= CONF_OPER_CHWIDTH_USE_HT
;
91 chanwidth
= CONF_OPER_CHWIDTH_80MHZ
;
94 chanwidth
= CONF_OPER_CHWIDTH_160MHZ
;
100 hw_mode
= ieee80211_freq_to_channel_ext(freq_val
, sec_channel
,
101 chanwidth
, &op_class
, &channel
);
103 case HOSTAPD_MODE_IEEE80211B
:
106 case HOSTAPD_MODE_IEEE80211G
:
109 case HOSTAPD_MODE_IEEE80211A
:
112 case HOSTAPD_MODE_IEEE80211AD
:
119 ret
= ucv_object_new(vm
);
120 ucv_object_add(ret
, "op_class", ucv_int64_new(op_class
));
121 ucv_object_add(ret
, "channel", ucv_int64_new(channel
));
122 ucv_object_add(ret
, "hw_mode", ucv_int64_new(hw_mode
));
123 ucv_object_add(ret
, "hw_mode_str", ucv_get(ucv_string_new(modestr
)));
124 ucv_object_add(ret
, "sec_channel", ucv_int64_new(sec_channel
));
125 ucv_object_add(ret
, "frequency", ucv_int64_new(freq_val
));
130 if (freq_val
>= 5900)
132 else if (freq_val
>= 5745)
136 tmp_channel
= channel
- center_ofs
;
137 tmp_channel
&= ~((8 << width
) - 1);
138 center_idx
= tmp_channel
+ center_ofs
+ (4 << width
) - 1;
141 ucv_object_add(ret
, "center_seg0_idx", ucv_int64_new(0));
143 ucv_object_add(ret
, "center_seg0_idx", ucv_int64_new(center_idx
));
144 center_idx
= (center_idx
- channel
) * 5 + freq_val
;
145 ucv_object_add(ret
, "center_freq1", ucv_int64_new(center_idx
));
151 uc_value_t
*uc_wpa_getpid(uc_vm_t
*vm
, size_t nargs
)
153 return ucv_int64_new(getpid());
156 uc_value_t
*uc_wpa_sha1(uc_vm_t
*vm
, size_t nargs
)
158 u8 hash
[SHA1_MAC_LEN
];
159 char hash_hex
[2 * ARRAY_SIZE(hash
) + 1];
168 args
= alloca(nargs
* sizeof(*args
));
169 lens
= alloca(nargs
* sizeof(*lens
));
170 for (i
= 0; i
< nargs
; i
++) {
172 if (ucv_type(val
) != UC_STRING
)
175 args
[i
] = ucv_string_get(val
);
176 lens
[i
] = ucv_string_length(val
);
179 if (sha1_vector(nargs
, args
, lens
, hash
))
182 for (i
= 0; i
< ARRAY_SIZE(hash
); i
++)
183 sprintf(hash_hex
+ 2 * i
, "%02x", hash
[i
]);
185 return ucv_string_new_length(hash_hex
, 2 * ARRAY_SIZE(hash
));
188 uc_vm_t
*wpa_ucode_create_vm(void)
190 static uc_parse_config_t config
= {
191 .strict_declarations
= true,
192 .lstrip_blocks
= true,
197 uc_search_path_init(&config
.module_search_path
);
198 uc_search_path_add(&config
.module_search_path
, HOSTAPD_UC_PATH
"*.so");
199 uc_search_path_add(&config
.module_search_path
, HOSTAPD_UC_PATH
"*.uc");
201 uc_vm_init(&vm
, &config
);
203 uc_stdlib_load(uc_vm_scope_get(&vm
));
205 gc_timer
.cb
= uc_gc_timer
;
210 int wpa_ucode_run(const char *script
)
218 source
= uc_source_new_file(script
);
222 prog
= uc_compile(vm
.config
, source
, &err
);
223 uc_source_put(source
);
225 wpa_printf(MSG_ERROR
, "Error loading ucode: %s\n", err
);
229 ret
= uc_vm_execute(&vm
, prog
, &ops
);
230 uc_program_put(prog
);
234 registry
= ucv_array_new(&vm
);
235 uc_vm_registry_set(&vm
, "hostap.registry", registry
);
236 ucv_array_set(registry
, 0, ucv_get(ops
));
241 int wpa_ucode_call_prepare(const char *fname
)
243 uc_value_t
*obj
, *func
;
248 obj
= ucv_array_get(registry
, 0);
252 func
= ucv_object_get(obj
, fname
, NULL
);
253 if (!ucv_is_callable(func
))
256 uc_vm_stack_push(&vm
, ucv_get(obj
));
257 uc_vm_stack_push(&vm
, ucv_get(func
));
262 static void udebug_printf_hook(int level
, const char *fmt
, va_list ap
)
264 udebug_entry_init(&ud_log
);
265 udebug_entry_vprintf(&ud_log
, fmt
, ap
);
266 udebug_entry_add(&ud_log
);
269 static void udebug_hexdump_hook(int level
, const char *title
,
270 const void *data
, size_t len
)
274 udebug_entry_init(&ud_log
);
275 udebug_entry_printf(&ud_log
, "%s - hexdump:", title
);
276 buf
= udebug_entry_append(&ud_log
, NULL
, 3 * len
);
277 for (size_t i
= 0; i
< len
; i
++)
278 buf
+= sprintf(buf
, " %02x", *(uint8_t *)(data
+ i
));
279 udebug_entry_add(&ud_log
);
282 static void udebug_netlink_hook(int tx
, const void *data
, size_t len
)
290 .pkttype
= host_to_be16(tx
? 7 : 6),
291 .arphdr
= host_to_be16(824),
292 .proto
= host_to_be16(16),
294 const struct nlmsghdr
*nlh
= data
;
295 const struct genlmsghdr
*gnlh
= data
+ NLMSG_HDRLEN
;
296 struct udebug_buf
*buf
= &ud_nl
[!!tx
];
298 if (nlh
->nlmsg_type
== 0x10)
300 else if (!tx
&& gnlh
->cmd
== NL80211_CMD_FRAME
&&
301 !(udebug_buf_flags(buf
) & UDEBUG_FLAG_RX_FRAME
))
304 udebug_entry_init(buf
);
305 udebug_entry_append(buf
, &hdr
, sizeof(hdr
));
306 udebug_entry_append(buf
, data
, len
);
307 udebug_entry_add(buf
);
310 uc_value_t
*uc_wpa_udebug_set(uc_vm_t
*vm
, size_t nargs
)
312 static const struct udebug_buf_meta meta_log
= {
314 .format
= UDEBUG_FORMAT_STRING
,
316 static const struct udebug_buf_meta meta_nl_ll
= {
317 .name
= "wpa_nl_ctrl",
318 .format
= UDEBUG_FORMAT_PACKET
,
319 .sub_format
= UDEBUG_DLT_NETLINK
,
321 static const struct udebug_buf_meta meta_nl_tx
= {
323 .format
= UDEBUG_FORMAT_PACKET
,
324 .sub_format
= UDEBUG_DLT_NETLINK
,
326 static const struct udebug_buf_flag rx_flags
[] = {
327 { "rx_frame", UDEBUG_FLAG_RX_FRAME
},
329 static const struct udebug_buf_meta meta_nl_rx
= {
331 .format
= UDEBUG_FORMAT_PACKET
,
332 .sub_format
= UDEBUG_DLT_NETLINK
,
334 .n_flags
= ARRAY_SIZE(rx_flags
),
336 bool val
= ucv_is_truish(uc_fn_arg(0));
337 static bool enabled
= false;
340 return ucv_boolean_new(true);
345 udebug_auto_connect(&ud
, NULL
);
346 udebug_buf_init(&ud_log
, 1024, 64 * 1024);
347 udebug_buf_add(&ud
, &ud_log
, &meta_log
);
348 udebug_buf_init(&ud_nl
[0], 1024, 256 * 1024);
349 udebug_buf_add(&ud
, &ud_nl
[0], &meta_nl_rx
);
350 udebug_buf_init(&ud_nl
[1], 1024, 64 * 1024);
351 udebug_buf_add(&ud
, &ud_nl
[1], &meta_nl_tx
);
352 udebug_buf_init(&ud_nl
[2], 256, 32 * 1024);
353 udebug_buf_add(&ud
, &ud_nl
[2], &meta_nl_ll
);
355 wpa_printf_hook
= udebug_printf_hook
;
356 wpa_hexdump_hook
= udebug_hexdump_hook
;
357 wpa_netlink_hook
= udebug_netlink_hook
;
359 for (size_t i
= 0; i
< ARRAY_SIZE(ud_nl
); i
++)
360 udebug_buf_free(&ud_nl
[i
]);
361 udebug_buf_free(&ud_log
);
363 wpa_printf_hook
= NULL
;
364 wpa_hexdump_hook
= NULL
;
365 wpa_netlink_hook
= NULL
;
368 return ucv_boolean_new(true);
371 uc_value_t
*wpa_ucode_global_init(const char *name
, uc_resource_type_t
*global_type
)
373 uc_value_t
*global
= uc_resource_new(global_type
, NULL
);
376 uc_vm_registry_set(&vm
, "hostap.global", global
);
377 proto
= ucv_prototype_get(global
);
378 ucv_object_add(proto
, "data", ucv_get(ucv_object_new(&vm
)));
380 #define ADD_CONST(x) ucv_object_add(proto, #x, ucv_int64_new(x))
381 ADD_CONST(MSG_EXCESSIVE
);
382 ADD_CONST(MSG_MSGDUMP
);
383 ADD_CONST(MSG_DEBUG
);
385 ADD_CONST(MSG_WARNING
);
386 ADD_CONST(MSG_ERROR
);
389 ucv_object_add(uc_vm_scope_get(&vm
), name
, ucv_get(global
));
394 int wpa_ucode_registry_add(uc_value_t
*reg
, uc_value_t
*val
)
399 while (ucv_array_get(reg
, i
))
402 ucv_array_set(reg
, i
, ucv_get(val
));
407 uc_value_t
*wpa_ucode_registry_get(uc_value_t
*reg
, int idx
)
412 return ucv_array_get(reg
, idx
- 1);
415 uc_value_t
*wpa_ucode_registry_remove(uc_value_t
*reg
, int idx
)
417 uc_value_t
*val
= wpa_ucode_registry_get(reg
, idx
);
423 ucv_array_set(reg
, idx
- 1, NULL
);
424 dataptr
= ucv_resource_dataptr(val
, NULL
);
432 uc_value_t
*wpa_ucode_call(size_t nargs
)
434 if (uc_vm_call(&vm
, true, nargs
) != EXCEPTION_NONE
)
437 if (!gc_timer
.pending
)
438 uloop_timeout_set(&gc_timer
, 10);
440 return uc_vm_stack_pop(&vm
);
443 void wpa_ucode_free_vm(void)
448 uc_search_path_free(&vm
.config
->module_search_path
);