1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022-2024 Red Hat */
4 #include "hid_common.h"
7 struct hid_hw_request_syscall_args
{
12 enum hid_report_type type
;
17 struct uhid_device hid
;
20 struct bpf_link
*hid_links
[3]; /* max number of programs loaded in a single test */
22 static void detach_bpf(FIXTURE_DATA(hid_bpf
) * self
)
27 close(self
->hidraw_fd
);
33 hid__detach(self
->skel
);
35 for (i
= 0; i
< ARRAY_SIZE(self
->hid_links
); i
++) {
36 if (self
->hid_links
[i
])
37 bpf_link__destroy(self
->hid_links
[i
]);
40 hid__destroy(self
->skel
);
44 FIXTURE_TEARDOWN(hid_bpf
) {
47 uhid_destroy(_metadata
, &self
->hid
);
50 pthread_join(self
->hid
.tid
, &uhid_err
);
52 #define TEARDOWN_LOG(fmt, ...) do { \
53 TH_LOG(fmt, ##__VA_ARGS__); \
54 hid_bpf_teardown(_metadata, self, variant); \
57 FIXTURE_SETUP(hid_bpf
)
61 err
= setup_uhid(_metadata
, &self
->hid
, BUS_USB
, 0x0001, 0x0a36, rdesc
, sizeof(rdesc
));
69 #define LOAD_PROGRAMS(progs) \
70 load_programs(progs, ARRAY_SIZE(progs), _metadata, self, variant)
72 load_programs(NULL, 0, _metadata, self, variant)
73 static void load_programs(const struct test_program programs
[],
74 const size_t progs_count
,
75 struct __test_metadata
*_metadata
,
76 FIXTURE_DATA(hid_bpf
) * self
,
77 const FIXTURE_VARIANT(hid_bpf
) * variant
)
79 struct bpf_map
*iter_map
;
82 ASSERT_LE(progs_count
, ARRAY_SIZE(self
->hid_links
))
83 TH_LOG("too many programs are to be loaded");
85 /* open the bpf file */
86 self
->skel
= hid__open();
87 ASSERT_OK_PTR(self
->skel
) TEARDOWN_LOG("Error while calling hid__open");
89 for (int i
= 0; i
< progs_count
; i
++) {
90 struct bpf_program
*prog
;
94 prog
= bpf_object__find_program_by_name(*self
->skel
->skeleton
->obj
,
96 ASSERT_OK_PTR(prog
) TH_LOG("can not find program by name '%s'", programs
[i
].name
);
98 bpf_program__set_autoload(prog
, true);
100 map
= bpf_object__find_map_by_name(*self
->skel
->skeleton
->obj
,
101 programs
[i
].name
+ 4);
102 ASSERT_OK_PTR(map
) TH_LOG("can not find struct_ops by name '%s'",
103 programs
[i
].name
+ 4);
105 /* hid_id is the first field of struct hid_bpf_ops */
106 ops_hid_id
= bpf_map__initial_value(map
, NULL
);
107 ASSERT_OK_PTR(ops_hid_id
) TH_LOG("unable to retrieve struct_ops data");
109 *ops_hid_id
= self
->hid
.hid_id
;
112 /* we disable the auto-attach feature of all maps because we
113 * only want the tested one to be manually attached in the next
114 * call to bpf_map__attach_struct_ops()
116 bpf_object__for_each_map(iter_map
, *self
->skel
->skeleton
->obj
)
117 bpf_map__set_autoattach(iter_map
, false);
119 err
= hid__load(self
->skel
);
120 ASSERT_OK(err
) TH_LOG("hid_skel_load failed: %d", err
);
122 for (int i
= 0; i
< progs_count
; i
++) {
125 map
= bpf_object__find_map_by_name(*self
->skel
->skeleton
->obj
,
126 programs
[i
].name
+ 4);
127 ASSERT_OK_PTR(map
) TH_LOG("can not find struct_ops by name '%s'",
128 programs
[i
].name
+ 4);
130 self
->hid_links
[i
] = bpf_map__attach_struct_ops(map
);
131 ASSERT_OK_PTR(self
->hid_links
[i
]) TH_LOG("failed to attach struct ops '%s'",
132 programs
[i
].name
+ 4);
135 hid__attach(self
->skel
);
137 self
->hidraw_fd
= open_hidraw(&self
->hid
);
138 ASSERT_GE(self
->hidraw_fd
, 0) TH_LOG("open_hidraw");
142 * A simple test to see if the fixture is working fine.
143 * If this fails, none of the other tests will pass.
145 TEST_F(hid_bpf
, test_create_uhid
)
150 * Attach hid_first_event to the given uhid device,
151 * retrieve and open the matching hidraw node,
152 * inject one event in the uhid device,
153 * check that the program sees it and can change the data
155 TEST_F(hid_bpf
, raw_event
)
157 const struct test_program progs
[] = {
158 { .name
= "hid_first_event" },
163 LOAD_PROGRAMS(progs
);
165 /* check that the program is correctly loaded */
166 ASSERT_EQ(self
->skel
->data
->callback_check
, 52) TH_LOG("callback_check1");
167 ASSERT_EQ(self
->skel
->data
->callback2_check
, 52) TH_LOG("callback2_check1");
169 /* inject one event */
172 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
174 /* check that hid_first_event() was executed */
175 ASSERT_EQ(self
->skel
->data
->callback_check
, 42) TH_LOG("callback_check1");
177 /* read the data from hidraw */
178 memset(buf
, 0, sizeof(buf
));
179 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
180 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
181 ASSERT_EQ(buf
[0], 1);
182 ASSERT_EQ(buf
[2], 47);
184 /* inject another event */
185 memset(buf
, 0, sizeof(buf
));
188 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
190 /* check that hid_first_event() was executed */
191 ASSERT_EQ(self
->skel
->data
->callback_check
, 47) TH_LOG("callback_check1");
193 /* read the data from hidraw */
194 memset(buf
, 0, sizeof(buf
));
195 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
196 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
197 ASSERT_EQ(buf
[2], 52);
201 * Attach hid_first_event to the given uhid device,
202 * retrieve and open the matching hidraw node,
203 * inject one event in the uhid device,
204 * check that the program sees it and can change the data
206 TEST_F(hid_bpf
, subprog_raw_event
)
208 const struct test_program progs
[] = {
209 { .name
= "hid_subprog_first_event" },
214 LOAD_PROGRAMS(progs
);
216 /* inject one event */
219 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
221 /* read the data from hidraw */
222 memset(buf
, 0, sizeof(buf
));
223 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
224 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
225 ASSERT_EQ(buf
[0], 1);
226 ASSERT_EQ(buf
[2], 47);
228 /* inject another event */
229 memset(buf
, 0, sizeof(buf
));
232 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
234 /* read the data from hidraw */
235 memset(buf
, 0, sizeof(buf
));
236 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
237 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
238 ASSERT_EQ(buf
[2], 52);
242 * Attach hid_first_event to the given uhid device,
243 * attempt at re-attaching it, we should not lock and
244 * return an invalid struct bpf_link
246 TEST_F(hid_bpf
, multiple_attach
)
248 const struct test_program progs
[] = {
249 { .name
= "hid_first_event" },
251 struct bpf_link
*link
;
253 LOAD_PROGRAMS(progs
);
255 link
= bpf_map__attach_struct_ops(self
->skel
->maps
.first_event
);
256 ASSERT_NULL(link
) TH_LOG("unexpected return value when re-attaching the struct_ops");
260 * Ensures that we can attach/detach programs
262 TEST_F(hid_bpf
, test_attach_detach
)
264 const struct test_program progs
[] = {
265 { .name
= "hid_first_event" },
266 { .name
= "hid_second_event" },
268 struct bpf_link
*link
;
272 LOAD_PROGRAMS(progs
);
274 link
= self
->hid_links
[0];
275 ASSERT_OK_PTR(link
) TH_LOG("HID-BPF link not created");
277 link_fd
= bpf_link__fd(link
);
278 ASSERT_GE(link_fd
, 0) TH_LOG("HID-BPF link FD not valid");
280 /* inject one event */
283 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
285 /* read the data from hidraw */
286 memset(buf
, 0, sizeof(buf
));
287 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
288 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
289 ASSERT_EQ(buf
[0], 1);
290 ASSERT_EQ(buf
[2], 47);
292 /* make sure both programs are run */
293 ASSERT_EQ(buf
[3], 52);
295 /* pin the first program and immediately unpin it */
296 #define PIN_PATH "/sys/fs/bpf/hid_first_event"
297 err
= bpf_obj_pin(link_fd
, PIN_PATH
);
298 ASSERT_OK(err
) TH_LOG("error while calling bpf_obj_pin");
303 /* detach the program */
306 self
->hidraw_fd
= open_hidraw(&self
->hid
);
307 ASSERT_GE(self
->hidraw_fd
, 0) TH_LOG("open_hidraw");
309 /* inject another event */
310 memset(buf
, 0, sizeof(buf
));
313 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
315 /* read the data from hidraw */
316 memset(buf
, 0, sizeof(buf
));
317 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
318 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw_no_bpf");
319 ASSERT_EQ(buf
[0], 1);
320 ASSERT_EQ(buf
[1], 47);
321 ASSERT_EQ(buf
[2], 0);
322 ASSERT_EQ(buf
[3], 0);
324 /* re-attach our program */
326 LOAD_PROGRAMS(progs
);
328 /* inject one event */
329 memset(buf
, 0, sizeof(buf
));
332 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
334 /* read the data from hidraw */
335 memset(buf
, 0, sizeof(buf
));
336 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
337 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
338 ASSERT_EQ(buf
[0], 1);
339 ASSERT_EQ(buf
[2], 47);
340 ASSERT_EQ(buf
[3], 52);
344 * Attach hid_change_report_id to the given uhid device,
345 * retrieve and open the matching hidraw node,
346 * inject one event in the uhid device,
347 * check that the program sees it and can change the data
349 TEST_F(hid_bpf
, test_hid_change_report
)
351 const struct test_program progs
[] = {
352 { .name
= "hid_change_report_id" },
357 LOAD_PROGRAMS(progs
);
359 /* inject one event */
362 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
364 /* read the data from hidraw */
365 memset(buf
, 0, sizeof(buf
));
366 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
367 ASSERT_EQ(err
, 9) TH_LOG("read_hidraw");
368 ASSERT_EQ(buf
[0], 2);
369 ASSERT_EQ(buf
[1], 42);
370 ASSERT_EQ(buf
[2], 0) TH_LOG("leftovers_from_previous_test");
374 * Call hid_bpf_input_report against the given uhid device,
375 * check that the program is called and does the expected.
377 TEST_F(hid_bpf
, test_hid_user_input_report_call
)
379 struct hid_hw_request_syscall_args args
= {
383 DECLARE_LIBBPF_OPTS(bpf_test_run_opts
, tattrs
,
385 .ctx_size_in
= sizeof(args
),
392 args
.hid
= self
->hid
.hid_id
;
393 args
.data
[0] = 1; /* report ID */
394 args
.data
[1] = 2; /* report ID */
395 args
.data
[2] = 42; /* report ID */
397 prog_fd
= bpf_program__fd(self
->skel
->progs
.hid_user_input_report
);
399 /* check that there is no data to read from hidraw */
400 memset(buf
, 0, sizeof(buf
));
401 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
402 ASSERT_EQ(err
, -1) TH_LOG("read_hidraw");
404 err
= bpf_prog_test_run_opts(prog_fd
, &tattrs
);
406 ASSERT_OK(err
) TH_LOG("error while calling bpf_prog_test_run_opts");
408 ASSERT_EQ(args
.retval
, 0);
410 /* read the data from hidraw */
411 memset(buf
, 0, sizeof(buf
));
412 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
413 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
414 ASSERT_EQ(buf
[0], 1);
415 ASSERT_EQ(buf
[1], 2);
416 ASSERT_EQ(buf
[2], 42);
420 * Call hid_bpf_hw_output_report against the given uhid device,
421 * check that the program is called and does the expected.
423 TEST_F(hid_bpf
, test_hid_user_output_report_call
)
425 struct hid_hw_request_syscall_args args
= {
429 DECLARE_LIBBPF_OPTS(bpf_test_run_opts
, tattrs
,
431 .ctx_size_in
= sizeof(args
),
433 int err
, cond_err
, prog_fd
;
434 struct timespec time_to_wait
;
438 args
.hid
= self
->hid
.hid_id
;
439 args
.data
[0] = 1; /* report ID */
440 args
.data
[1] = 2; /* report ID */
441 args
.data
[2] = 42; /* report ID */
443 prog_fd
= bpf_program__fd(self
->skel
->progs
.hid_user_output_report
);
445 pthread_mutex_lock(&uhid_output_mtx
);
447 memset(output_report
, 0, sizeof(output_report
));
448 clock_gettime(CLOCK_REALTIME
, &time_to_wait
);
449 time_to_wait
.tv_sec
+= 2;
451 err
= bpf_prog_test_run_opts(prog_fd
, &tattrs
);
452 cond_err
= pthread_cond_timedwait(&uhid_output_cond
, &uhid_output_mtx
, &time_to_wait
);
454 ASSERT_OK(err
) TH_LOG("error while calling bpf_prog_test_run_opts");
455 ASSERT_OK(cond_err
) TH_LOG("error while calling waiting for the condition");
457 ASSERT_EQ(args
.retval
, 3);
459 ASSERT_EQ(output_report
[0], 1);
460 ASSERT_EQ(output_report
[1], 2);
461 ASSERT_EQ(output_report
[2], 42);
463 pthread_mutex_unlock(&uhid_output_mtx
);
467 * Call hid_hw_raw_request against the given uhid device,
468 * check that the program is called and does the expected.
470 TEST_F(hid_bpf
, test_hid_user_raw_request_call
)
472 struct hid_hw_request_syscall_args args
= {
474 .type
= HID_FEATURE_REPORT
,
475 .request_type
= HID_REQ_GET_REPORT
,
478 DECLARE_LIBBPF_OPTS(bpf_test_run_opts
, tattrs
,
480 .ctx_size_in
= sizeof(args
),
486 args
.hid
= self
->hid
.hid_id
;
487 args
.data
[0] = 1; /* report ID */
489 prog_fd
= bpf_program__fd(self
->skel
->progs
.hid_user_raw_request
);
491 err
= bpf_prog_test_run_opts(prog_fd
, &tattrs
);
492 ASSERT_OK(err
) TH_LOG("error while calling bpf_prog_test_run_opts");
494 ASSERT_EQ(args
.retval
, 2);
496 ASSERT_EQ(args
.data
[1], 2);
500 * Call hid_hw_raw_request against the given uhid device,
501 * check that the program is called and prevents the
504 TEST_F(hid_bpf
, test_hid_filter_raw_request_call
)
506 const struct test_program progs
[] = {
507 { .name
= "hid_test_filter_raw_request" },
512 LOAD_PROGRAMS(progs
);
514 /* first check that we did not attach to device_event */
516 /* inject one event */
519 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
521 /* read the data from hidraw */
522 memset(buf
, 0, sizeof(buf
));
523 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
524 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
525 ASSERT_EQ(buf
[0], 1);
526 ASSERT_EQ(buf
[1], 42);
527 ASSERT_EQ(buf
[2], 0) TH_LOG("leftovers_from_previous_test");
529 /* now check that our program is preventing hid_hw_raw_request() */
531 /* emit hid_hw_raw_request from hidraw */
533 memset(buf
, 0, sizeof(buf
));
534 buf
[0] = 0x1; /* Report Number */
535 err
= ioctl(self
->hidraw_fd
, HIDIOCGFEATURE(sizeof(buf
)), buf
);
536 ASSERT_LT(err
, 0) TH_LOG("unexpected success while reading HIDIOCGFEATURE: %d", err
);
537 ASSERT_EQ(errno
, 20) TH_LOG("unexpected error code while reading HIDIOCGFEATURE: %d",
540 /* remove our bpf program and check that we can now emit commands */
542 /* detach the program */
545 self
->hidraw_fd
= open_hidraw(&self
->hid
);
546 ASSERT_GE(self
->hidraw_fd
, 0) TH_LOG("open_hidraw");
548 err
= ioctl(self
->hidraw_fd
, HIDIOCGFEATURE(sizeof(buf
)), buf
);
549 ASSERT_GE(err
, 0) TH_LOG("error while reading HIDIOCGFEATURE: %d", err
);
553 * Call hid_hw_raw_request against the given uhid device,
554 * check that the program is called and can issue the call
555 * to uhid and transform the answer.
557 TEST_F(hid_bpf
, test_hid_change_raw_request_call
)
559 const struct test_program progs
[] = {
560 { .name
= "hid_test_hidraw_raw_request" },
565 LOAD_PROGRAMS(progs
);
567 /* emit hid_hw_raw_request from hidraw */
569 memset(buf
, 0, sizeof(buf
));
570 buf
[0] = 0x1; /* Report Number */
571 err
= ioctl(self
->hidraw_fd
, HIDIOCGFEATURE(sizeof(buf
)), buf
);
572 ASSERT_EQ(err
, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err
);
574 ASSERT_EQ(buf
[0], 2);
575 ASSERT_EQ(buf
[1], 3);
576 ASSERT_EQ(buf
[2], 4);
580 * Call hid_hw_raw_request against the given uhid device,
581 * check that the program is not making infinite loops.
583 TEST_F(hid_bpf
, test_hid_infinite_loop_raw_request_call
)
585 const struct test_program progs
[] = {
586 { .name
= "hid_test_infinite_loop_raw_request" },
591 LOAD_PROGRAMS(progs
);
593 /* emit hid_hw_raw_request from hidraw */
595 memset(buf
, 0, sizeof(buf
));
596 buf
[0] = 0x1; /* Report Number */
597 err
= ioctl(self
->hidraw_fd
, HIDIOCGFEATURE(sizeof(buf
)), buf
);
598 ASSERT_EQ(err
, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err
);
602 * Call hid_hw_output_report against the given uhid device,
603 * check that the program is called and prevents the
606 TEST_F(hid_bpf
, test_hid_filter_output_report_call
)
608 const struct test_program progs
[] = {
609 { .name
= "hid_test_filter_output_report" },
614 LOAD_PROGRAMS(progs
);
616 /* first check that we did not attach to device_event */
618 /* inject one event */
621 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
623 /* read the data from hidraw */
624 memset(buf
, 0, sizeof(buf
));
625 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
626 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
627 ASSERT_EQ(buf
[0], 1);
628 ASSERT_EQ(buf
[1], 42);
629 ASSERT_EQ(buf
[2], 0) TH_LOG("leftovers_from_previous_test");
631 /* now check that our program is preventing hid_hw_output_report() */
633 buf
[0] = 1; /* report ID */
637 err
= write(self
->hidraw_fd
, buf
, 3);
638 ASSERT_LT(err
, 0) TH_LOG("unexpected success while sending hid_hw_output_report: %d", err
);
639 ASSERT_EQ(errno
, 25) TH_LOG("unexpected error code while sending hid_hw_output_report: %d",
642 /* remove our bpf program and check that we can now emit commands */
644 /* detach the program */
647 self
->hidraw_fd
= open_hidraw(&self
->hid
);
648 ASSERT_GE(self
->hidraw_fd
, 0) TH_LOG("open_hidraw");
650 err
= write(self
->hidraw_fd
, buf
, 3);
651 ASSERT_GE(err
, 0) TH_LOG("error while sending hid_hw_output_report: %d", err
);
655 * Call hid_hw_output_report against the given uhid device,
656 * check that the program is called and can issue the call
657 * to uhid and transform the answer.
659 TEST_F(hid_bpf
, test_hid_change_output_report_call
)
661 const struct test_program progs
[] = {
662 { .name
= "hid_test_hidraw_output_report" },
667 LOAD_PROGRAMS(progs
);
669 /* emit hid_hw_output_report from hidraw */
670 buf
[0] = 1; /* report ID */
674 err
= write(self
->hidraw_fd
, buf
, 10);
675 ASSERT_EQ(err
, 2) TH_LOG("unexpected returned size while sending hid_hw_output_report: %d",
680 * Call hid_hw_output_report against the given uhid device,
681 * check that the program is not making infinite loops.
683 TEST_F(hid_bpf
, test_hid_infinite_loop_output_report_call
)
685 const struct test_program progs
[] = {
686 { .name
= "hid_test_infinite_loop_output_report" },
691 LOAD_PROGRAMS(progs
);
693 /* emit hid_hw_output_report from hidraw */
694 buf
[0] = 1; /* report ID */
698 err
= write(self
->hidraw_fd
, buf
, 8);
699 ASSERT_EQ(err
, 2) TH_LOG("unexpected returned size while sending hid_hw_output_report: %d",
704 * Attach hid_multiply_event_wq to the given uhid device,
705 * retrieve and open the matching hidraw node,
706 * inject one event in the uhid device,
707 * check that the program sees it and can add extra data
709 TEST_F(hid_bpf
, test_multiply_events_wq
)
711 const struct test_program progs
[] = {
712 { .name
= "hid_test_multiply_events_wq" },
717 LOAD_PROGRAMS(progs
);
719 /* inject one event */
722 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
724 /* read the data from hidraw */
725 memset(buf
, 0, sizeof(buf
));
726 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
727 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
728 ASSERT_EQ(buf
[0], 1);
729 ASSERT_EQ(buf
[1], 47);
733 /* read the data from hidraw */
734 memset(buf
, 0, sizeof(buf
));
735 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
736 ASSERT_EQ(err
, 9) TH_LOG("read_hidraw");
737 ASSERT_EQ(buf
[0], 2);
738 ASSERT_EQ(buf
[1], 3);
742 * Attach hid_multiply_event to the given uhid device,
743 * retrieve and open the matching hidraw node,
744 * inject one event in the uhid device,
745 * check that the program sees it and can add extra data
747 TEST_F(hid_bpf
, test_multiply_events
)
749 const struct test_program progs
[] = {
750 { .name
= "hid_test_multiply_events" },
755 LOAD_PROGRAMS(progs
);
757 /* inject one event */
760 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
762 /* read the data from hidraw */
763 memset(buf
, 0, sizeof(buf
));
764 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
765 ASSERT_EQ(err
, 9) TH_LOG("read_hidraw");
766 ASSERT_EQ(buf
[0], 2);
767 ASSERT_EQ(buf
[1], 47);
769 /* read the data from hidraw */
770 memset(buf
, 0, sizeof(buf
));
771 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
772 ASSERT_EQ(err
, 9) TH_LOG("read_hidraw");
773 ASSERT_EQ(buf
[0], 2);
774 ASSERT_EQ(buf
[1], 52);
778 * Call hid_bpf_input_report against the given uhid device,
779 * check that the program is not making infinite loops.
781 TEST_F(hid_bpf
, test_hid_infinite_loop_input_report_call
)
783 const struct test_program progs
[] = {
784 { .name
= "hid_test_infinite_loop_input_report" },
789 LOAD_PROGRAMS(progs
);
791 /* emit hid_hw_output_report from hidraw */
792 buf
[0] = 1; /* report ID */
796 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
798 /* read the data from hidraw */
799 memset(buf
, 0, sizeof(buf
));
800 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
801 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
802 ASSERT_EQ(buf
[0], 1);
803 ASSERT_EQ(buf
[1], 3);
805 /* read the data from hidraw: hid_bpf_try_input_report should work exactly one time */
806 memset(buf
, 0, sizeof(buf
));
807 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
808 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
809 ASSERT_EQ(buf
[0], 1);
810 ASSERT_EQ(buf
[1], 4);
812 /* read the data from hidraw: there should be none */
813 memset(buf
, 0, sizeof(buf
));
814 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
815 ASSERT_EQ(err
, -1) TH_LOG("read_hidraw");
819 * Attach hid_insert{0,1,2} to the given uhid device,
820 * retrieve and open the matching hidraw node,
821 * inject one event in the uhid device,
822 * check that the programs have been inserted in the correct order.
824 TEST_F(hid_bpf
, test_hid_attach_flags
)
826 const struct test_program progs
[] = {
828 .name
= "hid_test_insert2",
832 .name
= "hid_test_insert1",
836 .name
= "hid_test_insert3",
843 LOAD_PROGRAMS(progs
);
845 /* inject one event */
847 uhid_send_event(_metadata
, &self
->hid
, buf
, 6);
849 /* read the data from hidraw */
850 memset(buf
, 0, sizeof(buf
));
851 err
= read(self
->hidraw_fd
, buf
, sizeof(buf
));
852 ASSERT_EQ(err
, 6) TH_LOG("read_hidraw");
853 ASSERT_EQ(buf
[1], 1);
854 ASSERT_EQ(buf
[2], 2);
855 ASSERT_EQ(buf
[3], 3);
859 * Attach hid_rdesc_fixup to the given uhid device,
860 * retrieve and open the matching hidraw node,
861 * check that the hidraw report descriptor has been updated.
863 TEST_F(hid_bpf
, test_rdesc_fixup
)
865 struct hidraw_report_descriptor rpt_desc
= {0};
866 const struct test_program progs
[] = {
867 { .name
= "hid_rdesc_fixup" },
871 LOAD_PROGRAMS(progs
);
873 /* check that hid_rdesc_fixup() was executed */
874 ASSERT_EQ(self
->skel
->data
->callback2_check
, 0x21);
876 /* read the exposed report descriptor from hidraw */
877 err
= ioctl(self
->hidraw_fd
, HIDIOCGRDESCSIZE
, &desc_size
);
878 ASSERT_GE(err
, 0) TH_LOG("error while reading HIDIOCGRDESCSIZE: %d", err
);
880 /* ensure the new size of the rdesc is bigger than the old one */
881 ASSERT_GT(desc_size
, sizeof(rdesc
));
883 rpt_desc
.size
= desc_size
;
884 err
= ioctl(self
->hidraw_fd
, HIDIOCGRDESC
, &rpt_desc
);
885 ASSERT_GE(err
, 0) TH_LOG("error while reading HIDIOCGRDESC: %d", err
);
887 ASSERT_EQ(rpt_desc
.value
[4], 0x42);
890 static int libbpf_print_fn(enum libbpf_print_level level
,
891 const char *format
, va_list args
)
895 if (level
== LIBBPF_DEBUG
)
898 snprintf(buf
, sizeof(buf
), "# %s", format
);
900 vfprintf(stdout
, buf
, args
);
904 int main(int argc
, char **argv
)
906 /* Use libbpf 1.0 API mode */
907 libbpf_set_strict_mode(LIBBPF_STRICT_ALL
);
908 libbpf_set_print(libbpf_print_fn
);
910 return test_harness_run(argc
, argv
);