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

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.org


Acked-by: default avatarJiri Kosina <jkosina@suse.com>
Signed-off-by: default avatarBenjamin Tissoires <bentiss@kernel.org>
parent 9acbb7ba
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -1168,6 +1168,42 @@ TEST_F(hid_bpf, test_multiply_events_wq)
	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,
 * retrieve and open the matching hidraw node,
+39 −0
Original line number Diff line number Diff line
@@ -522,3 +522,42 @@ SEC(".struct_ops.link")
struct hid_bpf_ops 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,
};
+4 −0
Original line number Diff line number Diff line
@@ -89,6 +89,10 @@ extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
				enum hid_report_type type,
				__u8 *data,
				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 */
extern int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags) __weak __ksym;