/* compute the maximum report length for this device */ for (i = 0; i < HID_REPORT_TYPES; i++) { struct hid_report_enum *report_enum = hdev->report_enum + i;
if (report)
max_report_len = max(max_report_len, hid_report_len(report));
}
}
/* * Give us a little bit of extra space and some predictability in the * buffer length we create. This way, we can tell users that they can * work on chunks of 64 bytes of memory without having the bpf verifier * scream at them.
*/
alloc_size = DIV_ROUND_UP(max_report_len, 64) * 64;
alloc_data = kzalloc(alloc_size, GFP_KERNEL); if (!alloc_data) return -ENOMEM;
*data = alloc_data;
*size = alloc_size;
return 0;
}
int hid_bpf_allocate_event_data(struct hid_device *hdev)
{ /* hdev->bpf.device_data is already allocated, abort */ if (hdev->bpf.device_data) return 0;
int hid_bpf_reconnect(struct hid_device *hdev)
{ if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) { /* trigger call to call_hid_bpf_rdesc_fixup() during the next probe */
hdev->bpf_rsize = 0; return device_reprobe(&hdev->dev);
}
/** * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx * * @ctx: The HID-BPF context * @offset: The offset within the memory * @rdwr_buf_size: the const size of the buffer * * @returns %NULL on error, an %__u8 memory pointer on success
*/
__bpf_kfunc __u8 *
hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsignedint offset, const size_t rdwr_buf_size)
{ struct hid_bpf_ctx_kern *ctx_kern;
if (rdwr_buf_size + offset > ctx->allocated_size) return NULL;
return ctx_kern->data + offset;
}
/** * hid_bpf_allocate_context - Allocate a context to the given HID device * * @hid_id: the system unique identifier of the HID device * * @returns A pointer to &struct hid_bpf_ctx on success, %NULL on error.
*/
__bpf_kfunc struct hid_bpf_ctx *
hid_bpf_allocate_context(unsignedint hid_id)
{ struct hid_device *hdev; struct hid_bpf_ctx_kern *ctx_kern = NULL;
hdev = hid_get_device(hid_id); if (IS_ERR(hdev)) return NULL;
/** * hid_bpf_hw_request - Communicate with a HID device * * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context() * @buf: a %PTR_TO_MEM buffer * @buf__sz: the size of the data to transfer * @rtype: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT) * @reqtype: the type of the request (%HID_REQ_GET_REPORT, %HID_REQ_SET_REPORT, ...) * * @returns %0 on success, a negative error code otherwise.
*/
__bpf_kfunc int
hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, enum hid_report_type rtype, enum hid_class_request reqtype)
{ struct hid_bpf_ctx_kern *ctx_kern;
size_t size = buf__sz;
u8 *dma_data; int ret;
/* check arguments */
ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype); if (ret) return ret;
switch (reqtype) { case HID_REQ_GET_REPORT: case HID_REQ_GET_IDLE: case HID_REQ_GET_PROTOCOL: case HID_REQ_SET_REPORT: case HID_REQ_SET_IDLE: case HID_REQ_SET_PROTOCOL: break; default: return -EINVAL;
}
dma_data = kmemdup(buf, size, GFP_KERNEL); if (!dma_data) return -ENOMEM;
/** * hid_bpf_hw_output_report - Send an output report to a HID device * * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context() * @buf: a %PTR_TO_MEM buffer * @buf__sz: the size of the data to transfer * * Returns the number of bytes transferred on success, a negative error code otherwise.
*/
__bpf_kfunc int
hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
{ struct hid_bpf_ctx_kern *ctx_kern;
size_t size = buf__sz;
u8 *dma_data; int ret;
ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx); if (ctx_kern->from_bpf) return -EDEADLOCK;
/* check arguments */
ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT); if (ret) return ret;
dma_data = kmemdup(buf, size, GFP_KERNEL); if (!dma_data) return -ENOMEM;
ret = hid_ops->hid_hw_output_report(ctx->hid, dma_data, size, (u64)(long)ctx, true);
/** * hid_bpf_try_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. This function will immediately * fail if the device is not available, thus can be safely used in IRQ context.
*/
__bpf_kfunc int
hid_bpf_try_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)
{ struct hid_bpf_ctx_kern *ctx_kern; bool from_hid_event_hook;
/** * 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. This function will wait for the * device to be available before injecting the event, thus needs to be called in sleepable * context.
*/
__bpf_kfunc int
hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz)
{ int ret;
ret = down_interruptible(&ctx->hid->driver_input_lock); if (ret) return ret;
/* Note: if we exit with an error any time here, we would entirely break HID, which * is probably not something we want. So we log an error and return success. * * This is not a big deal: nobody will be able to use the functionality.
*/
err = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, &hid_bpf_kfunc_set); if (err) {
pr_warn("error while setting HID BPF tracing kfuncs: %d", err); return 0;
}
err = register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &hid_bpf_syscall_kfunc_set); if (err) {
pr_warn("error while setting HID BPF syscall kfuncs: %d", err); return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.