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