Merge tag '5.14-rc1-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6
[linux-2.6-microblaze.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         .connect        = sock_no_connect,
237         .socketpair     = sock_no_socketpair,
238         .accept         = sock_no_accept,
239         .mmap           = sock_no_mmap
240 };
241
242 static struct proto hidp_proto = {
243         .name           = "HIDP",
244         .owner          = THIS_MODULE,
245         .obj_size       = sizeof(struct bt_sock)
246 };
247
248 static 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
278 static const struct net_proto_family hidp_sock_family_ops = {
279         .family = PF_BLUETOOTH,
280         .owner  = THIS_MODULE,
281         .create = hidp_sock_create
282 };
283
284 int __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
309 error:
310         proto_unregister(&hidp_proto);
311         return err;
312 }
313
314 void __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 }