@@ -45,6 +45,11 @@ __weak noinline int hid_bpf_device_event(struct hid_bpf_ctx *ctx)
return 0;
}
+__weak noinline int hid_bpf_raw_request(struct hid_bpf_ctx *ctx)
+{
+ return 0;
+}
+
u8 *
dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data,
u32 *size, int interrupt, u64 source)
@@ -71,6 +76,9 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
memset(ctx_kern.data, 0, hdev->bpf.allocated_data);
memcpy(ctx_kern.data, data, *size);
+ if (*size)
+ ctx_kern.ctx.reportnum = data[0];
+
ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern, false);
if (ret < 0)
return ERR_PTR(ret);
@@ -86,6 +94,49 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
}
EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event);
+u8 *
+dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
+ unsigned char reportnum, u8 *buf,
+ u32 *size, enum hid_report_type rtype,
+ enum hid_class_request reqtype,
+ u64 source)
+{
+ struct hid_bpf_ctx_kern ctx_kern = {
+ .ctx = {
+ .hid = hdev,
+ .report_type = rtype,
+ .reqtype = reqtype,
+ .allocated_size = *size,
+ .size = *size,
+ .source = source,
+ .reportnum = reportnum,
+ },
+ .data = buf,
+ };
+ int ret;
+
+ if (rtype >= HID_REPORT_TYPES)
+ return ERR_PTR(-EINVAL);
+
+ /* no program has been attached yet */
+ // if (!hdev->bpf.device_data)
+ // return buf;
+
+ ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RAW_REQUEST, &ctx_kern, true);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ if (ret) {
+ if (ret > ctx_kern.ctx.allocated_size)
+ return ERR_PTR(-EINVAL);
+
+ *size = ret;
+ }
+
+ return ctx_kern.data;
+}
+EXPORT_SYMBOL_GPL(dispatch_hid_bpf_raw_requests);
+
/**
* hid_bpf_rdesc_fixup - Called when the probe function parses the report
* descriptor of the HID device
@@ -64,6 +64,7 @@ static int hid_bpf_max_programs(enum hid_bpf_prog_type type)
{
switch (type) {
case HID_BPF_PROG_TYPE_DEVICE_EVENT:
+ case HID_BPF_PROG_TYPE_RAW_REQUEST:
return HID_BPF_MAX_PROGS_PER_DEV;
case HID_BPF_PROG_TYPE_RDESC_FIXUP:
return 1;
@@ -2407,6 +2407,7 @@ int __hid_hw_raw_request(struct hid_device *hdev,
__u64 source)
{
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
+ u32 size = (u32)len; /* max_buffer_size is 16 KB */
if (hdev->ll_driver->max_buffer_size)
max_buffer_size = hdev->ll_driver->max_buffer_size;
@@ -2414,7 +2415,12 @@ int __hid_hw_raw_request(struct hid_device *hdev,
if (len < 1 || len > max_buffer_size || !buf)
return -EINVAL;
- return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
+ buf = dispatch_hid_bpf_raw_requests(hdev, reportnum, buf, &size, rtype,
+ reqtype, source);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ return hdev->ll_driver->raw_request(hdev, reportnum, buf, size,
rtype, reqtype);
}
@@ -52,10 +52,12 @@ struct hid_bpf_ctx {
__u64 source;
const struct hid_device *hid;
enum hid_report_type report_type;
+ enum hid_class_request reqtype; /* for HID_BPF_PROG_TYPE_RAW_REQUEST */
union {
__s32 retval;
__s32 size;
};
+ __u8 reportnum;
};
/**
@@ -77,6 +79,7 @@ enum hid_bpf_attach_flags {
/* Following functions are tracepoints that BPF programs can attach to */
int hid_bpf_device_event(struct hid_bpf_ctx *ctx);
int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx);
+int hid_bpf_raw_request(struct hid_bpf_ctx *ctx);
/*
* Below is HID internal
@@ -90,6 +93,7 @@ enum hid_bpf_prog_type {
HID_BPF_PROG_TYPE_UNDEF = -1,
HID_BPF_PROG_TYPE_DEVICE_EVENT, /* an event is emitted from the device */
HID_BPF_PROG_TYPE_RDESC_FIXUP,
+ HID_BPF_PROG_TYPE_RAW_REQUEST,
HID_BPF_PROG_TYPE_MAX,
};
@@ -140,6 +144,11 @@ struct hid_bpf_link {
#ifdef CONFIG_HID_BPF
u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
u32 *size, int interrupt, u64 source);
+u8 *dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
+ unsigned char reportnum, __u8 *buf,
+ u32 *size, enum hid_report_type rtype,
+ enum hid_class_request reqtype,
+ __u64 source);
int hid_bpf_connect_device(struct hid_device *hdev);
void hid_bpf_disconnect_device(struct hid_device *hdev);
void hid_bpf_destroy_device(struct hid_device *hid);
@@ -149,6 +158,11 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
u8 *data, u32 *size, int interrupt,
u64 source) { return data; }
+static inline u8 *dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
+ unsigned char reportnum, u8 *buf,
+ u32 *size, enum hid_report_type rtype,
+ enum hid_class_request reqtype,
+ u64 source) { return buf; }
static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}