Commit 62f2e1a0 authored by Benjamin Tissoires's avatar Benjamin Tissoires

selftests/hid: add another test for injecting an event from an event hook

Similar to test_multiply_events_wq: we receive one event and inject a
new one. But given that this time we are already in the event hook, we
can use hid_bpf_try_input_report() directly as this function will not
sleep.

Note that the injected event gets processed before the original one this
way.

Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-12-cfd60fb6c79f@kernel.orgAcked-by: default avatarJiri Kosina <jkosina@suse.com>
Signed-off-by: default avatarBenjamin Tissoires <bentiss@kernel.org>
parent 9acbb7ba
...@@ -1168,6 +1168,42 @@ TEST_F(hid_bpf, test_multiply_events_wq) ...@@ -1168,6 +1168,42 @@ TEST_F(hid_bpf, test_multiply_events_wq)
ASSERT_EQ(buf[1], 3); ASSERT_EQ(buf[1], 3);
} }
/*
* Attach hid_multiply_event to the given uhid device,
* retrieve and open the matching hidraw node,
* inject one event in the uhid device,
* check that the program sees it and can add extra data
*/
TEST_F(hid_bpf, test_multiply_events)
{
const struct test_program progs[] = {
{ .name = "hid_test_multiply_events" },
};
__u8 buf[10] = {0};
int err;
LOAD_PROGRAMS(progs);
/* inject one event */
buf[0] = 1;
buf[1] = 42;
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
/* read the data from hidraw */
memset(buf, 0, sizeof(buf));
err = read(self->hidraw_fd, buf, sizeof(buf));
ASSERT_EQ(err, 9) TH_LOG("read_hidraw");
ASSERT_EQ(buf[0], 2);
ASSERT_EQ(buf[1], 47);
/* read the data from hidraw */
memset(buf, 0, sizeof(buf));
err = read(self->hidraw_fd, buf, sizeof(buf));
ASSERT_EQ(err, 9) TH_LOG("read_hidraw");
ASSERT_EQ(buf[0], 2);
ASSERT_EQ(buf[1], 52);
}
/* /*
* Attach hid_insert{0,1,2} to the given uhid device, * Attach hid_insert{0,1,2} to the given uhid device,
* retrieve and open the matching hidraw node, * retrieve and open the matching hidraw node,
......
...@@ -522,3 +522,42 @@ SEC(".struct_ops.link") ...@@ -522,3 +522,42 @@ SEC(".struct_ops.link")
struct hid_bpf_ops test_multiply_events_wq = { struct hid_bpf_ops test_multiply_events_wq = {
.hid_device_event = (void *)hid_test_multiply_events_wq, .hid_device_event = (void *)hid_test_multiply_events_wq,
}; };
SEC("?struct_ops/hid_device_event")
int BPF_PROG(hid_test_multiply_events, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
{
__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 9 /* size */);
__u8 buf[9];
int ret;
if (!data)
return 0; /* EPERM check */
if (data[0] != 1)
return 0;
/*
* we have to use an intermediate buffer as hid_bpf_input_report
* will memset data to \0
*/
__builtin_memcpy(buf, data, sizeof(buf));
buf[0] = 2;
buf[1] += 5;
ret = hid_bpf_try_input_report(hid_ctx, HID_INPUT_REPORT, buf, sizeof(buf));
if (ret < 0)
return ret;
/*
* In real world we should reset the original buffer as data might be garbage now,
* but it actually now has the content of 'buf'
*/
data[1] += 5;
return 9;
}
SEC(".struct_ops.link")
struct hid_bpf_ops test_multiply_events = {
.hid_device_event = (void *)hid_test_multiply_events,
};
...@@ -89,6 +89,10 @@ extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx, ...@@ -89,6 +89,10 @@ extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
enum hid_report_type type, enum hid_report_type type,
__u8 *data, __u8 *data,
size_t buf__sz) __ksym; size_t buf__sz) __ksym;
extern int hid_bpf_try_input_report(struct hid_bpf_ctx *ctx,
enum hid_report_type type,
__u8 *data,
size_t buf__sz) __ksym;
/* bpf_wq implementation */ /* bpf_wq implementation */
extern int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags) __weak __ksym; extern int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags) __weak __ksym;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment