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];
19 static const struct udebug_buf_meta meta_log
= {
21 .format
= UDEBUG_FORMAT_STRING
,
23 static const struct udebug_buf_meta meta_nl_ll
= {
24 .name
= "wpa_nl_ctrl",
25 .format
= UDEBUG_FORMAT_PACKET
,
26 .sub_format
= UDEBUG_DLT_NETLINK
,
28 static const struct udebug_buf_meta meta_nl_tx
= {
30 .format
= UDEBUG_FORMAT_PACKET
,
31 .sub_format
= UDEBUG_DLT_NETLINK
,
33 #define UDEBUG_FLAG_RX_FRAME (1ULL << 0)
34 static const struct udebug_buf_flag rx_flags
[] = {
35 { "rx_frame", UDEBUG_FLAG_RX_FRAME
},
37 static const struct udebug_buf_meta meta_nl_rx
= {
39 .format
= UDEBUG_FORMAT_PACKET
,
40 .sub_format
= UDEBUG_DLT_NETLINK
,
42 .n_flags
= ARRAY_SIZE(rx_flags
),
44 static struct udebug_ubus_ring udebug_rings
[] = {
48 .default_entries
= 1024,
49 .default_size
= 64 * 1024
54 .default_entries
= 1024,
55 .default_size
= 256 * 1024,
60 .default_entries
= 1024,
61 .default_size
= 64 * 1024,
66 .default_entries
= 1024,
67 .default_size
= 32 * 1024,
71 struct udebug_ubus ud_ubus
;
73 static void uc_gc_timer(struct uloop_timeout
*timeout
)
78 uc_value_t
*uc_wpa_printf(uc_vm_t
*vm
, size_t nargs
)
80 uc_value_t
*level
= uc_fn_arg(0);
81 uc_value_t
*ret
, **args
;
82 uc_cfn_ptr_t _sprintf
;
86 _sprintf
= uc_stdlib_function("sprintf");
90 if (ucv_type(level
) == UC_INTEGER
) {
91 l
= ucv_int64_get(level
);
98 ret
= _sprintf(vm
, nargs
- start
);
99 if (ucv_type(ret
) != UC_STRING
)
102 wpa_printf(l
, "%s", ucv_string_get(ret
));
108 uc_value_t
*uc_wpa_freq_info(uc_vm_t
*vm
, size_t nargs
)
110 uc_value_t
*freq
= uc_fn_arg(0);
111 uc_value_t
*sec
= uc_fn_arg(1);
112 int width
= ucv_uint64_get(uc_fn_arg(2));
113 int freq_val
, center_idx
, center_ofs
;
114 enum oper_chan_width chanwidth
;
115 enum hostapd_hw_mode hw_mode
;
116 u8 op_class
, channel
, tmp_channel
;
121 if (ucv_type(freq
) != UC_INTEGER
)
124 freq_val
= ucv_int64_get(freq
);
125 if (ucv_type(sec
) == UC_INTEGER
)
126 sec_channel
= ucv_int64_get(sec
);
129 else if (freq_val
> 4000)
130 sec_channel
= (freq_val
/ 20) & 1 ? 1 : -1;
132 sec_channel
= freq_val
< 2442 ? 1 : -1;
134 if (sec_channel
!= -1 && sec_channel
!= 1 && sec_channel
!= 0)
139 chanwidth
= CONF_OPER_CHWIDTH_USE_HT
;
142 chanwidth
= CONF_OPER_CHWIDTH_80MHZ
;
145 chanwidth
= CONF_OPER_CHWIDTH_160MHZ
;
151 hw_mode
= ieee80211_freq_to_channel_ext(freq_val
, sec_channel
,
152 chanwidth
, &op_class
, &channel
);
154 case HOSTAPD_MODE_IEEE80211B
:
157 case HOSTAPD_MODE_IEEE80211G
:
160 case HOSTAPD_MODE_IEEE80211A
:
163 case HOSTAPD_MODE_IEEE80211AD
:
170 ret
= ucv_object_new(vm
);
171 ucv_object_add(ret
, "op_class", ucv_int64_new(op_class
));
172 ucv_object_add(ret
, "channel", ucv_int64_new(channel
));
173 ucv_object_add(ret
, "hw_mode", ucv_int64_new(hw_mode
));
174 ucv_object_add(ret
, "hw_mode_str", ucv_get(ucv_string_new(modestr
)));
175 ucv_object_add(ret
, "sec_channel", ucv_int64_new(sec_channel
));
176 ucv_object_add(ret
, "frequency", ucv_int64_new(freq_val
));
181 if (freq_val
>= 5900)
183 else if (freq_val
>= 5745)
187 tmp_channel
= channel
- center_ofs
;
188 tmp_channel
&= ~((8 << width
) - 1);
189 center_idx
= tmp_channel
+ center_ofs
+ (4 << width
) - 1;
192 ucv_object_add(ret
, "center_seg0_idx", ucv_int64_new(0));
194 ucv_object_add(ret
, "center_seg0_idx", ucv_int64_new(center_idx
));
195 center_idx
= (center_idx
- channel
) * 5 + freq_val
;
196 ucv_object_add(ret
, "center_freq1", ucv_int64_new(center_idx
));
202 uc_value_t
*uc_wpa_getpid(uc_vm_t
*vm
, size_t nargs
)
204 return ucv_int64_new(getpid());
207 uc_value_t
*uc_wpa_sha1(uc_vm_t
*vm
, size_t nargs
)
209 u8 hash
[SHA1_MAC_LEN
];
210 char hash_hex
[2 * ARRAY_SIZE(hash
) + 1];
219 args
= alloca(nargs
* sizeof(*args
));
220 lens
= alloca(nargs
* sizeof(*lens
));
221 for (i
= 0; i
< nargs
; i
++) {
223 if (ucv_type(val
) != UC_STRING
)
226 args
[i
] = ucv_string_get(val
);
227 lens
[i
] = ucv_string_length(val
);
230 if (sha1_vector(nargs
, args
, lens
, hash
))
233 for (i
= 0; i
< ARRAY_SIZE(hash
); i
++)
234 sprintf(hash_hex
+ 2 * i
, "%02x", hash
[i
]);
236 return ucv_string_new_length(hash_hex
, 2 * ARRAY_SIZE(hash
));
239 uc_vm_t
*wpa_ucode_create_vm(void)
241 static uc_parse_config_t config
= {
242 .strict_declarations
= true,
243 .lstrip_blocks
= true,
248 uc_search_path_init(&config
.module_search_path
);
249 uc_search_path_add(&config
.module_search_path
, HOSTAPD_UC_PATH
"*.so");
250 uc_search_path_add(&config
.module_search_path
, HOSTAPD_UC_PATH
"*.uc");
252 uc_vm_init(&vm
, &config
);
254 uc_stdlib_load(uc_vm_scope_get(&vm
));
256 gc_timer
.cb
= uc_gc_timer
;
261 int wpa_ucode_run(const char *script
)
269 source
= uc_source_new_file(script
);
273 prog
= uc_compile(vm
.config
, source
, &err
);
274 uc_source_put(source
);
276 wpa_printf(MSG_ERROR
, "Error loading ucode: %s\n", err
);
280 ret
= uc_vm_execute(&vm
, prog
, &ops
);
281 uc_program_put(prog
);
285 registry
= ucv_array_new(&vm
);
286 uc_vm_registry_set(&vm
, "hostap.registry", registry
);
287 ucv_array_set(registry
, 0, ucv_get(ops
));
292 int wpa_ucode_call_prepare(const char *fname
)
294 uc_value_t
*obj
, *func
;
299 obj
= ucv_array_get(registry
, 0);
303 func
= ucv_object_get(obj
, fname
, NULL
);
304 if (!ucv_is_callable(func
))
307 uc_vm_stack_push(&vm
, ucv_get(obj
));
308 uc_vm_stack_push(&vm
, ucv_get(func
));
313 static void udebug_printf_hook(int level
, const char *fmt
, va_list ap
)
315 udebug_entry_init(&ud_log
);
316 udebug_entry_vprintf(&ud_log
, fmt
, ap
);
317 udebug_entry_add(&ud_log
);
320 static void udebug_hexdump_hook(int level
, const char *title
,
321 const void *data
, size_t len
)
325 udebug_entry_init(&ud_log
);
326 udebug_entry_printf(&ud_log
, "%s - hexdump:", title
);
327 buf
= udebug_entry_append(&ud_log
, NULL
, 3 * len
);
328 for (size_t i
= 0; i
< len
; i
++)
329 buf
+= sprintf(buf
, " %02x", *(uint8_t *)(data
+ i
));
330 udebug_entry_add(&ud_log
);
333 static void udebug_netlink_hook(int tx
, const void *data
, size_t len
)
341 .pkttype
= host_to_be16(tx
? 7 : 6),
342 .arphdr
= host_to_be16(824),
343 .proto
= host_to_be16(16),
345 const struct nlmsghdr
*nlh
= data
;
346 const struct genlmsghdr
*gnlh
= data
+ NLMSG_HDRLEN
;
347 struct udebug_buf
*buf
= &ud_nl
[!!tx
];
349 if (nlh
->nlmsg_type
== 0x10)
351 else if (!tx
&& gnlh
->cmd
== NL80211_CMD_FRAME
&&
352 !(udebug_buf_flags(buf
) & UDEBUG_FLAG_RX_FRAME
))
355 if (!udebug_buf_valid(buf
))
358 udebug_entry_init(buf
);
359 udebug_entry_append(buf
, &hdr
, sizeof(hdr
));
360 udebug_entry_append(buf
, data
, len
);
361 udebug_entry_add(buf
);
365 wpa_udebug_config(struct udebug_ubus
*ctx
, struct blob_attr
*data
,
368 udebug_ubus_apply_config(&ud
, udebug_rings
, ARRAY_SIZE(udebug_rings
),
371 if (udebug_buf_valid(&ud_log
)) {
372 wpa_printf_hook
= udebug_printf_hook
;
373 wpa_hexdump_hook
= udebug_hexdump_hook
;
375 wpa_printf_hook
= NULL
;
376 wpa_hexdump_hook
= NULL
;
379 if (udebug_buf_valid(&ud_nl
[0]) ||
380 udebug_buf_valid(&ud_nl
[1]) ||
381 udebug_buf_valid(&ud_nl
[2]))
382 wpa_netlink_hook
= udebug_netlink_hook
;
384 wpa_netlink_hook
= NULL
;
387 uc_value_t
*uc_wpa_udebug_set(uc_vm_t
*vm
, size_t nargs
)
389 uc_value_t
*name
= uc_fn_arg(0);
390 uc_value_t
*ubus
= uc_fn_arg(1);
391 static bool enabled
= false;
392 struct ubus_context
*ctx
;
395 cur_en
= ucv_type(name
) == UC_STRING
;
396 ctx
= ucv_resource_data(ubus
, "ubus.connection");
400 if (enabled
== cur_en
)
401 return ucv_boolean_new(true);
405 udebug_service
= strdup(ucv_string_get(name
));
407 udebug_auto_connect(&ud
, NULL
);
408 udebug_ubus_init(&ud_ubus
, ctx
, udebug_service
, wpa_udebug_config
);
410 udebug_ubus_free(&ud_ubus
);
411 for (size_t i
= 0; i
< ARRAY_SIZE(udebug_rings
); i
++)
412 if (udebug_buf_valid(udebug_rings
[i
].buf
))
413 udebug_buf_free(udebug_rings
[i
].buf
);
415 free(udebug_service
);
418 return ucv_boolean_new(true);
421 uc_value_t
*wpa_ucode_global_init(const char *name
, uc_resource_type_t
*global_type
)
423 uc_value_t
*global
= uc_resource_new(global_type
, NULL
);
426 uc_vm_registry_set(&vm
, "hostap.global", global
);
427 proto
= ucv_prototype_get(global
);
428 ucv_object_add(proto
, "data", ucv_get(ucv_object_new(&vm
)));
430 #define ADD_CONST(x) ucv_object_add(proto, #x, ucv_int64_new(x))
431 ADD_CONST(MSG_EXCESSIVE
);
432 ADD_CONST(MSG_MSGDUMP
);
433 ADD_CONST(MSG_DEBUG
);
435 ADD_CONST(MSG_WARNING
);
436 ADD_CONST(MSG_ERROR
);
439 ucv_object_add(uc_vm_scope_get(&vm
), name
, ucv_get(global
));
444 int wpa_ucode_registry_add(uc_value_t
*reg
, uc_value_t
*val
)
449 while (ucv_array_get(reg
, i
))
452 ucv_array_set(reg
, i
, ucv_get(val
));
457 uc_value_t
*wpa_ucode_registry_get(uc_value_t
*reg
, int idx
)
462 return ucv_array_get(reg
, idx
- 1);
465 uc_value_t
*wpa_ucode_registry_remove(uc_value_t
*reg
, int idx
)
467 uc_value_t
*val
= wpa_ucode_registry_get(reg
, idx
);
473 ucv_array_set(reg
, idx
- 1, NULL
);
474 dataptr
= ucv_resource_dataptr(val
, NULL
);
482 uc_value_t
*wpa_ucode_call(size_t nargs
)
484 if (uc_vm_call(&vm
, true, nargs
) != EXCEPTION_NONE
)
487 if (!gc_timer
.pending
)
488 uloop_timeout_set(&gc_timer
, 10);
490 return uc_vm_stack_pop(&vm
);
493 void wpa_ucode_free_vm(void)
498 uc_search_path_free(&vm
.config
->module_search_path
);