1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/export.h>
24#include <linux/file.h>
25
26#include "hidp.h"
27
28static struct bt_sock_list hidp_sk_list = {
29 .lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
30};
31
32static int hidp_sock_release(struct socket *sock)
33{
34 struct sock *sk = sock->sk;
35
36 BT_DBG("sock %p sk %p", sock, sk);
37
38 if (!sk)
39 return 0;
40
41 bt_sock_unlink(&hidp_sk_list, sk);
42
43 sock_orphan(sk);
44 sock_put(sk);
45
46 return 0;
47}
48
49static int do_hidp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
50{
51 struct hidp_connadd_req ca;
52 struct hidp_conndel_req cd;
53 struct hidp_connlist_req cl;
54 struct hidp_conninfo ci;
55 struct socket *csock;
56 struct socket *isock;
57 int err;
58
59 BT_DBG("cmd %x arg %p", cmd, argp);
60
61 switch (cmd) {
62 case HIDPCONNADD:
63 if (!capable(CAP_NET_ADMIN))
64 return -EPERM;
65
66 if (copy_from_user(&ca, argp, sizeof(ca)))
67 return -EFAULT;
68
69 csock = sockfd_lookup(ca.ctrl_sock, &err);
70 if (!csock)
71 return err;
72
73 isock = sockfd_lookup(ca.intr_sock, &err);
74 if (!isock) {
75 sockfd_put(csock);
76 return err;
77 }
78
79 err = hidp_connection_add(&ca, csock, isock);
80 if (!err && copy_to_user(argp, &ca, sizeof(ca)))
81 err = -EFAULT;
82
83 sockfd_put(csock);
84 sockfd_put(isock);
85
86 return err;
87
88 case HIDPCONNDEL:
89 if (!capable(CAP_NET_ADMIN))
90 return -EPERM;
91
92 if (copy_from_user(&cd, argp, sizeof(cd)))
93 return -EFAULT;
94
95 return hidp_connection_del(&cd);
96
97 case HIDPGETCONNLIST:
98 if (copy_from_user(&cl, argp, sizeof(cl)))
99 return -EFAULT;
100
101 if (cl.cnum <= 0)
102 return -EINVAL;
103
104 err = hidp_get_connlist(&cl);
105 if (!err && copy_to_user(argp, &cl, sizeof(cl)))
106 return -EFAULT;
107
108 return err;
109
110 case HIDPGETCONNINFO:
111 if (copy_from_user(&ci, argp, sizeof(ci)))
112 return -EFAULT;
113
114 err = hidp_get_conninfo(&ci);
115 if (!err && copy_to_user(argp, &ci, sizeof(ci)))
116 return -EFAULT;
117
118 return err;
119 }
120
121 return -EINVAL;
122}
123
124static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
125{
126 return do_hidp_sock_ioctl(sock, cmd, (void __user *)arg);
127}
128
129#ifdef CONFIG_COMPAT
130struct compat_hidp_connadd_req {
131 int ctrl_sock;
132 int intr_sock;
133 __u16 parser;
134 __u16 rd_size;
135 compat_uptr_t rd_data;
136 __u8 country;
137 __u8 subclass;
138 __u16 vendor;
139 __u16 product;
140 __u16 version;
141 __u32 flags;
142 __u32 idle_to;
143 char name[128];
144};
145
146static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
147{
148 void __user *argp = compat_ptr(arg);
149 int err;
150
151 if (cmd == HIDPGETCONNLIST) {
152 struct hidp_connlist_req cl;
153 u32 __user *p = argp;
154 u32 uci;
155
156 if (get_user(cl.cnum, p) || get_user(uci, p + 1))
157 return -EFAULT;
158
159 cl.ci = compat_ptr(uci);
160
161 if (cl.cnum <= 0)
162 return -EINVAL;
163
164 err = hidp_get_connlist(&cl);
165
166 if (!err && put_user(cl.cnum, p))
167 err = -EFAULT;
168
169 return err;
170 } else if (cmd == HIDPCONNADD) {
171 struct compat_hidp_connadd_req ca32;
172 struct hidp_connadd_req ca;
173 struct socket *csock;
174 struct socket *isock;
175
176 if (!capable(CAP_NET_ADMIN))
177 return -EPERM;
178
179 if (copy_from_user(&ca32, (void __user *) arg, sizeof(ca32)))
180 return -EFAULT;
181
182 ca.ctrl_sock = ca32.ctrl_sock;
183 ca.intr_sock = ca32.intr_sock;
184 ca.parser = ca32.parser;
185 ca.rd_size = ca32.rd_size;
186 ca.rd_data = compat_ptr(ca32.rd_data);
187 ca.country = ca32.country;
188 ca.subclass = ca32.subclass;
189 ca.vendor = ca32.vendor;
190 ca.product = ca32.product;
191 ca.version = ca32.version;
192 ca.flags = ca32.flags;
193 ca.idle_to = ca32.idle_to;
194 memcpy(ca.name, ca32.name, 128);
195
196 csock = sockfd_lookup(ca.ctrl_sock, &err);
197 if (!csock)
198 return err;
199
200 isock = sockfd_lookup(ca.intr_sock, &err);
201 if (!isock) {
202 sockfd_put(csock);
203 return err;
204 }
205
206 err = hidp_connection_add(&ca, csock, isock);
207 if (!err && copy_to_user(argp, &ca32, sizeof(ca32)))
208 err = -EFAULT;
209
210 sockfd_put(csock);
211 sockfd_put(isock);
212
213 return err;
214 }
215
216 return hidp_sock_ioctl(sock, cmd, arg);
217}
218#endif
219
220static const struct proto_ops hidp_sock_ops = {
221 .family = PF_BLUETOOTH,
222 .owner = THIS_MODULE,
223 .release = hidp_sock_release,
224 .ioctl = hidp_sock_ioctl,
225#ifdef CONFIG_COMPAT
226 .compat_ioctl = hidp_sock_compat_ioctl,
227#endif
228 .bind = sock_no_bind,
229 .getname = sock_no_getname,
230 .sendmsg = sock_no_sendmsg,
231 .recvmsg = sock_no_recvmsg,
232 .listen = sock_no_listen,
233 .shutdown = sock_no_shutdown,
234 .setsockopt = sock_no_setsockopt,
235 .getsockopt = sock_no_getsockopt,
236 .connect = sock_no_connect,
237 .socketpair = sock_no_socketpair,
238 .accept = sock_no_accept,
239 .mmap = sock_no_mmap
240};
241
242static struct proto hidp_proto = {
243 .name = "HIDP",
244 .owner = THIS_MODULE,
245 .obj_size = sizeof(struct bt_sock)
246};
247
248static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
249 int kern)
250{
251 struct sock *sk;
252
253 BT_DBG("sock %p", sock);
254
255 if (sock->type != SOCK_RAW)
256 return -ESOCKTNOSUPPORT;
257
258 sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, kern);
259 if (!sk)
260 return -ENOMEM;
261
262 sock_init_data(sock, sk);
263
264 sock->ops = &hidp_sock_ops;
265
266 sock->state = SS_UNCONNECTED;
267
268 sock_reset_flag(sk, SOCK_ZAPPED);
269
270 sk->sk_protocol = protocol;
271 sk->sk_state = BT_OPEN;
272
273 bt_sock_link(&hidp_sk_list, sk);
274
275 return 0;
276}
277
278static const struct net_proto_family hidp_sock_family_ops = {
279 .family = PF_BLUETOOTH,
280 .owner = THIS_MODULE,
281 .create = hidp_sock_create
282};
283
284int __init hidp_init_sockets(void)
285{
286 int err;
287
288 err = proto_register(&hidp_proto, 0);
289 if (err < 0)
290 return err;
291
292 err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
293 if (err < 0) {
294 BT_ERR("Can't register HIDP socket");
295 goto error;
296 }
297
298 err = bt_procfs_init(&init_net, "hidp", &hidp_sk_list, NULL);
299 if (err < 0) {
300 BT_ERR("Failed to create HIDP proc file");
301 bt_sock_unregister(BTPROTO_HIDP);
302 goto error;
303 }
304
305 BT_INFO("HIDP socket layer initialized");
306
307 return 0;
308
309error:
310 proto_unregister(&hidp_proto);
311 return err;
312}
313
314void __exit hidp_cleanup_sockets(void)
315{
316 bt_procfs_cleanup(&init_net, "hidp");
317 bt_sock_unregister(BTPROTO_HIDP);
318 proto_unregister(&hidp_proto);
319}
320