HID: bpf: allow to inject HID event from BPF
authorBenjamin Tissoires <bentiss@kernel.org>
Fri, 15 Mar 2024 14:44:42 +0000 (15:44 +0100)
committerBenjamin Tissoires <bentiss@kernel.org>
Wed, 10 Apr 2024 14:38:11 +0000 (16:38 +0200)
It can be interesting to inject events from BPF as if the event were
to come from the device.
For example, some multitouch devices do not all the time send a proximity
out event, and we might want to send it for the physical device.

Compared to uhid, we can now inject events on any physical device, not
just uhid virtual ones.

Link: https://lore.kernel.org/r/20240315-b4-hid-bpf-new-funcs-v4-5-079c282469d3@kernel.org
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Documentation/hid/hid-bpf.rst
drivers/hid/bpf/hid_bpf_dispatch.c
drivers/hid/hid-core.c
include/linux/hid_bpf.h

index a575004..0765b32 100644 (file)
@@ -179,7 +179,7 @@ Available API that can be used in syscall HID-BPF programs:
 -----------------------------------------------------------
 
 .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
-   :functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_allocate_context hid_bpf_release_context
+   :functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_allocate_context hid_bpf_release_context
 
 General overview of a HID-BPF program
 =====================================
index 0ccd7cd..83e5c73 100644 (file)
@@ -508,6 +508,34 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
        kfree(dma_data);
        return ret;
 }
+
+/**
+ * hid_bpf_input_report - Inject a HID report in the kernel from a HID device
+ *
+ * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
+ * @type: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT)
+ * @buf: a %PTR_TO_MEM buffer
+ * @buf__sz: the size of the data to transfer
+ *
+ * Returns %0 on success, a negative error code otherwise.
+ */
+__bpf_kfunc int
+hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf,
+                    const size_t buf__sz)
+{
+       struct hid_device *hdev;
+       size_t size = buf__sz;
+       int ret;
+
+       /* check arguments */
+       ret = __hid_bpf_hw_check_params(ctx, buf, &size, type);
+       if (ret)
+               return ret;
+
+       hdev = (struct hid_device *)ctx->hid; /* discard const */
+
+       return hid_input_report(hdev, type, buf, size, 0);
+}
 __bpf_kfunc_end_defs();
 
 /*
@@ -542,6 +570,7 @@ BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL)
 BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE)
 BTF_ID_FLAGS(func, hid_bpf_hw_request)
 BTF_ID_FLAGS(func, hid_bpf_hw_output_report)
+BTF_ID_FLAGS(func, hid_bpf_input_report)
 BTF_KFUNCS_END(hid_bpf_syscall_kfunc_ids)
 
 static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {
index 1243595..b1fa037 100644 (file)
@@ -2975,6 +2975,7 @@ static struct hid_bpf_ops hid_ops = {
        .hid_get_report = hid_get_report,
        .hid_hw_raw_request = hid_hw_raw_request,
        .hid_hw_output_report = hid_hw_output_report,
+       .hid_input_report = hid_input_report,
        .owner = THIS_MODULE,
        .bus_type = &hid_bus_type,
 };
index 5c7ff93..17b08f5 100644 (file)
@@ -104,6 +104,8 @@ struct hid_bpf_ops {
                                  size_t len, enum hid_report_type rtype,
                                  enum hid_class_request reqtype);
        int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len);
+       int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type,
+                               u8 *data, u32 size, int interrupt);
        struct module *owner;
        const struct bus_type *bus_type;
 };