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