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