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