selftests/hid: Add test for hid_bpf_hw_output_report
authorBenjamin Tissoires <bentiss@kernel.org>
Fri, 15 Mar 2024 14:44:41 +0000 (15:44 +0100)
committerBenjamin Tissoires <bentiss@kernel.org>
Wed, 10 Apr 2024 14:37:23 +0000 (16:37 +0200)
This time we need to ensure uhid receives it, thus the new mutex and
condition.

Link: https://lore.kernel.org/r/20240315-b4-hid-bpf-new-funcs-v4-4-079c282469d3@kernel.org
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
tools/testing/selftests/hid/hid_bpf.c
tools/testing/selftests/hid/progs/hid.c
tools/testing/selftests/hid/progs/hid_bpf_helpers.h

index 2cf96f818f2578df7b1e17d93b44baa376f97cbc..8332014838b0906843f72140892fa36e83edc1b2 100644 (file)
 
 #define SHOW_UHID_DEBUG 0
 
+#define min(a, b) \
+       ({ __typeof__(a) _a = (a); \
+       __typeof__(b) _b = (b); \
+       _a < _b ? _a : _b; })
+
 static unsigned char rdesc[] = {
        0x06, 0x00, 0xff,       /* Usage Page (Vendor Defined Page 1) */
        0x09, 0x21,             /* Usage (Vendor Usage 0x21) */
@@ -111,6 +116,10 @@ struct hid_hw_request_syscall_args {
 static pthread_mutex_t uhid_started_mtx = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t uhid_started = PTHREAD_COND_INITIALIZER;
 
+static pthread_mutex_t uhid_output_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t uhid_output_cond = PTHREAD_COND_INITIALIZER;
+static unsigned char output_report[10];
+
 /* no need to protect uhid_stopped, only one thread accesses it */
 static bool uhid_stopped;
 
@@ -205,6 +214,13 @@ static int uhid_event(struct __test_metadata *_metadata, int fd)
                break;
        case UHID_OUTPUT:
                UHID_LOG("UHID_OUTPUT from uhid-dev");
+
+               pthread_mutex_lock(&uhid_output_mtx);
+               memcpy(output_report,
+                      ev.u.output.data,
+                      min(ev.u.output.size, sizeof(output_report)));
+               pthread_cond_signal(&uhid_output_cond);
+               pthread_mutex_unlock(&uhid_output_mtx);
                break;
        case UHID_GET_REPORT:
                UHID_LOG("UHID_GET_REPORT from uhid-dev");
@@ -733,6 +749,53 @@ TEST_F(hid_bpf, test_hid_change_report)
        ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");
 }
 
+/*
+ * Call hid_bpf_hw_output_report against the given uhid device,
+ * check that the program is called and does the expected.
+ */
+TEST_F(hid_bpf, test_hid_user_output_report_call)
+{
+       struct hid_hw_request_syscall_args args = {
+               .retval = -1,
+               .size = 10,
+       };
+       DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,
+                           .ctx_in = &args,
+                           .ctx_size_in = sizeof(args),
+       );
+       int err, cond_err, prog_fd;
+       struct timespec time_to_wait;
+
+       LOAD_BPF;
+
+       args.hid = self->hid_id;
+       args.data[0] = 1; /* report ID */
+       args.data[1] = 2; /* report ID */
+       args.data[2] = 42; /* report ID */
+
+       prog_fd = bpf_program__fd(self->skel->progs.hid_user_output_report);
+
+       pthread_mutex_lock(&uhid_output_mtx);
+
+       memset(output_report, 0, sizeof(output_report));
+       clock_gettime(CLOCK_REALTIME, &time_to_wait);
+       time_to_wait.tv_sec += 2;
+
+       err = bpf_prog_test_run_opts(prog_fd, &tattrs);
+       cond_err = pthread_cond_timedwait(&uhid_output_cond, &uhid_output_mtx, &time_to_wait);
+
+       ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts");
+       ASSERT_OK(cond_err) TH_LOG("error while calling waiting for the condition");
+
+       ASSERT_EQ(args.retval, 3);
+
+       ASSERT_EQ(output_report[0], 1);
+       ASSERT_EQ(output_report[1], 2);
+       ASSERT_EQ(output_report[2], 42);
+
+       pthread_mutex_unlock(&uhid_output_mtx);
+}
+
 /*
  * Attach hid_user_raw_request to the given uhid device,
  * call the bpf program from userspace
index 1e558826b809e1aefb215cecb01a3fda6d5cf9d8..2c2b679a83b17be217927785dfd02ec7fba3cb12 100644 (file)
@@ -101,6 +101,30 @@ int hid_user_raw_request(struct hid_hw_request_syscall_args *args)
        return 0;
 }
 
+SEC("syscall")
+int hid_user_output_report(struct hid_hw_request_syscall_args *args)
+{
+       struct hid_bpf_ctx *ctx;
+       const size_t size = args->size;
+       int i, ret = 0;
+
+       if (size > sizeof(args->data))
+               return -7; /* -E2BIG */
+
+       ctx = hid_bpf_allocate_context(args->hid);
+       if (!ctx)
+               return -1; /* EPERM check */
+
+       ret = hid_bpf_hw_output_report(ctx,
+                                      args->data,
+                                      size);
+       args->retval = ret;
+
+       hid_bpf_release_context(ctx);
+
+       return 0;
+}
+
 static const __u8 rdesc[] = {
        0x05, 0x01,                             /* USAGE_PAGE (Generic Desktop) */
        0x09, 0x32,                             /* USAGE (Z) */
index 65e657ac11985d455c854ec38d053f69eac756e7..50c6a0d5765eeb63a1a144131403b028cf3929b4 100644 (file)
@@ -94,5 +94,7 @@ extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
                              size_t buf__sz,
                              enum hid_report_type type,
                              enum hid_class_request reqtype) __ksym;
+extern int hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx,
+                                   __u8 *buf, size_t buf__sz) __ksym;
 
 #endif /* __HID_BPF_HELPERS_H */