summaryrefslogtreecommitdiff
path: root/include/linux/hid_bpf.h
blob: d4d063cf63b56cae15ee8544d0323acdf6b552ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/* SPDX-License-Identifier: GPL-2.0+ */

#ifndef __HID_BPF_H
#define __HID_BPF_H

#include <linux/bpf.h>
#include <linux/mutex.h>
#include <linux/srcu.h>
#include <uapi/linux/hid.h>

struct hid_device;

/*
 * The following is the user facing HID BPF API.
 *
 * Extra care should be taken when editing this part, as
 * it might break existing out of the tree bpf programs.
 */

/**
 * struct hid_bpf_ctx - User accessible data for all HID programs
 *
 * ``data`` is not directly accessible from the context. We need to issue
 * a call to hid_bpf_get_data() in order to get a pointer to that field.
 *
 * @hid: the &struct hid_device representing the device itself
 * @allocated_size: Allocated size of data.
 *
 *                  This is how much memory is available and can be requested
 *                  by the HID program.
 *                  Note that for ``HID_BPF_RDESC_FIXUP``, that memory is set to
 *                  ``4096`` (4 KB)
 * @size: Valid data in the data field.
 *
 *        Programs can get the available valid size in data by fetching this field.
 *        Programs can also change this value by returning a positive number in the
 *        program.
 *        To discard the event, return a negative error code.
 *
 *        ``size`` must always be less or equal than ``allocated_size`` (it is enforced
 *        once all BPF programs have been run).
 * @retval: Return value of the previous program.
 *
 * ``hid`` and ``allocated_size`` are read-only, ``size`` and ``retval`` are read-write.
 */
struct hid_bpf_ctx {
	struct hid_device *hid;
	__u32 allocated_size;
	union {
		__s32 retval;
		__s32 size;
	};
};

/*
 * Below is HID internal
 */

#define HID_BPF_MAX_PROGS_PER_DEV 64
#define HID_BPF_FLAG_MASK (((HID_BPF_FLAG_MAX - 1) << 1) - 1)


struct hid_report_enum;

struct hid_ops {
	struct hid_report *(*hid_get_report)(struct hid_report_enum *report_enum, const u8 *data);
	int (*hid_hw_raw_request)(struct hid_device *hdev,
				  unsigned char reportnum, __u8 *buf,
				  size_t len, enum hid_report_type rtype,
				  enum hid_class_request reqtype,
				  u64 source, bool from_bpf);
	int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len,
				    u64 source, bool from_bpf);
	int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type,
				u8 *data, u32 size, int interrupt, u64 source, bool from_bpf,
				bool lock_already_taken);
	struct module *owner;
	const struct bus_type *bus_type;
};

extern struct hid_ops *hid_ops;

/**
 * struct hid_bpf_ops - A BPF struct_ops of callbacks allowing to attach HID-BPF
 *			programs to a HID device
 * @hid_id: the HID uniq ID to attach to. This is writeable before ``load()``, and
 *	    cannot be changed after
 * @flags: flags used while attaching the struct_ops to the device. Currently only
 *	   available value is %0 or ``BPF_F_BEFORE``.
 *	   Writeable only before ``load()``
 */
struct hid_bpf_ops {
	/* hid_id needs to stay first so we can easily change it
	 * from userspace.
	 */
	int			hid_id;
	u32			flags;

	/* private: do not show up in the docs */
	struct list_head	list;

	/* public: rest should show up in the docs */

	/**
	 * @hid_device_event: called whenever an event is coming in from the device
	 *
	 * It has the following arguments:
	 *
	 * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx
	 *
	 * Return: %0 on success and keep processing; a positive
	 * value to change the incoming size buffer; a negative
	 * error code to interrupt the processing of this event
	 *
	 * Context: Interrupt context.
	 */
	int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type,
				u64 source);

	/**
	 * @hid_rdesc_fixup: called when the probe function parses the report descriptor
	 * of the HID device
	 *
	 * It has the following arguments:
	 *
	 * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx
	 *
	 * Return: %0 on success and keep processing; a positive
	 * value to change the incoming size buffer; a negative
	 * error code to interrupt the processing of this device
	 */
	int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx);

	/**
	 * @hid_hw_request: called whenever a hid_hw_raw_request() call is emitted
	 * on the HID device
	 *
	 * It has the following arguments:
	 *
	 * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx
	 *
	 * ``reportnum``: the report number, as in hid_hw_raw_request()
	 *
	 * ``rtype``: the report type (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``,
	 * ``HID_OUTPUT_REPORT``)
	 *
	 * ``reqtype``: the request
	 *
	 * ``source``: a u64 referring to a uniq but identifiable source. If %0, the
	 * kernel itself emitted that call. For hidraw, ``source`` is set
	 * to the associated ``struct file *``.
	 *
	 * Return: %0 to keep processing the request by hid-core; any other value
	 * stops hid-core from processing that event. A positive value should be
	 * returned with the number of bytes returned in the incoming buffer; a
	 * negative error code interrupts the processing of this call.
	 */
	int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum,
			       enum hid_report_type rtype, enum hid_class_request reqtype,
			       u64 source);

	/**
	 * @hid_hw_output_report: called whenever a hid_hw_output_report() call is emitted
	 * on the HID device
	 *
	 * It has the following arguments:
	 *
	 * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx
	 *
	 * ``source``: a u64 referring to a uniq but identifiable source. If %0, the
	 * kernel itself emitted that call. For hidraw, ``source`` is set
	 * to the associated ``struct file *``.
	 *
	 * Return: %0 to keep processing the request by hid-core; any other value
	 * stops hid-core from processing that event. A positive value should be
	 * returned with the number of bytes written to the device; a negative error
	 * code interrupts the processing of this call.
	 */
	int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source);


	/* private: do not show up in the docs */
	struct hid_device *hdev;
};

/* stored in each device */
struct hid_bpf {
	u8 *device_data;		/* allocated when a bpf program of type
					 * SEC(f.../hid_bpf_device_event) has been attached
					 * to this HID device
					 */
	u32 allocated_data;
	bool destroyed;			/* prevents the assignment of any progs */

	struct hid_bpf_ops *rdesc_ops;
	struct list_head prog_list;
	struct mutex prog_list_lock;	/* protects prog_list update */
	struct srcu_struct srcu;	/* protects prog_list read-only access */
};

#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, bool from_bpf);
int 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, bool from_bpf);
int dispatch_hid_bpf_output_report(struct hid_device *hdev, __u8 *buf, u32 size,
				   u64 source, bool from_bpf);
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);
int hid_bpf_device_init(struct hid_device *hid);
u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size);
#else /* CONFIG_HID_BPF */
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, bool from_bpf) { return data; }
static inline int 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, bool from_bpf) { return 0; }
static inline int dispatch_hid_bpf_output_report(struct hid_device *hdev, __u8 *buf, u32 size,
						 u64 source, bool from_bpf) { return 0; }
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) {}
static inline int hid_bpf_device_init(struct hid_device *hid) { return 0; }
/*
 * This specialized allocator has to be a macro for its allocations to be
 * accounted separately (to have a separate alloc_tag). The typecast is
 * intentional to enforce typesafety.
 */
#define call_hid_bpf_rdesc_fixup(_hdev, _rdesc, _size)	\
		((u8 *)kmemdup(_rdesc, *(_size), GFP_KERNEL))

#endif /* CONFIG_HID_BPF */

#endif /* __HID_BPF_H */