Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / net / bluetooth / hidp / sock.c
1 /*
2    HIDP implementation for Linux Bluetooth stack (BlueZ).
3    Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License version 2 as
7    published by the Free Software Foundation;
8
9    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20    SOFTWARE IS DISCLAIMED.
21 */
22
23 #include <linux/export.h>
24 #include <linux/file.h>
25
26 #include "hidp.h"
27
28 static struct bt_sock_list hidp_sk_list = {
29         .lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
30 };
31
32 static 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
49 static 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
125 static 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
131 struct compat_hidp_connadd_req {
132         int   ctrl_sock;        /* Connected control socket */
133         int   intr_sock;        /* Connected interrupt socket */
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
147 static 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
222 static 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
244 static struct proto hidp_proto = {
245         .name           = "HIDP",
246         .owner          = THIS_MODULE,
247         .obj_size       = sizeof(struct bt_sock)
248 };
249
250 static 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
280 static const struct net_proto_family hidp_sock_family_ops = {
281         .family = PF_BLUETOOTH,
282         .owner  = THIS_MODULE,
283         .create = hidp_sock_create
284 };
285
286 int __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
311 error:
312         proto_unregister(&hidp_proto);
313         return err;
314 }
315
316 void __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 }