Merge master.kernel.org:/home/rmk/linux-2.6-arm
[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/config.h>
24 #include <linux/module.h>
25
26 #include <linux/types.h>
27 #include <linux/capability.h>
28 #include <linux/errno.h>
29 #include <linux/kernel.h>
30 #include <linux/sched.h>
31 #include <linux/slab.h>
32 #include <linux/poll.h>
33 #include <linux/fcntl.h>
34 #include <linux/skbuff.h>
35 #include <linux/socket.h>
36 #include <linux/ioctl.h>
37 #include <linux/file.h>
38 #include <linux/init.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 static const struct proto_ops hidp_sock_ops = {
148         .family         = PF_BLUETOOTH,
149         .owner          = THIS_MODULE,
150         .release        = hidp_sock_release,
151         .ioctl          = hidp_sock_ioctl,
152         .bind           = sock_no_bind,
153         .getname        = sock_no_getname,
154         .sendmsg        = sock_no_sendmsg,
155         .recvmsg        = sock_no_recvmsg,
156         .poll           = sock_no_poll,
157         .listen         = sock_no_listen,
158         .shutdown       = sock_no_shutdown,
159         .setsockopt     = sock_no_setsockopt,
160         .getsockopt     = sock_no_getsockopt,
161         .connect        = sock_no_connect,
162         .socketpair     = sock_no_socketpair,
163         .accept         = sock_no_accept,
164         .mmap           = sock_no_mmap
165 };
166
167 static struct proto hidp_proto = {
168         .name           = "HIDP",
169         .owner          = THIS_MODULE,
170         .obj_size       = sizeof(struct bt_sock)
171 };
172
173 static int hidp_sock_create(struct socket *sock, int protocol)
174 {
175         struct sock *sk;
176
177         BT_DBG("sock %p", sock);
178
179         if (sock->type != SOCK_RAW)
180                 return -ESOCKTNOSUPPORT;
181
182         sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hidp_proto, 1);
183         if (!sk)
184                 return -ENOMEM;
185
186         sock_init_data(sock, sk);
187
188         sock->ops = &hidp_sock_ops;
189
190         sock->state = SS_UNCONNECTED;
191
192         sock_reset_flag(sk, SOCK_ZAPPED);
193
194         sk->sk_protocol = protocol;
195         sk->sk_state    = BT_OPEN;
196
197         return 0;
198 }
199
200 static struct net_proto_family hidp_sock_family_ops = {
201         .family = PF_BLUETOOTH,
202         .owner  = THIS_MODULE,
203         .create = hidp_sock_create
204 };
205
206 int __init hidp_init_sockets(void)
207 {
208         int err;
209
210         err = proto_register(&hidp_proto, 0);
211         if (err < 0)
212                 return err;
213
214         err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
215         if (err < 0)
216                 goto error;
217
218         return 0;
219
220 error:
221         BT_ERR("Can't register HIDP socket");
222         proto_unregister(&hidp_proto);
223         return err;
224 }
225
226 void __exit hidp_cleanup_sockets(void)
227 {
228         if (bt_sock_unregister(BTPROTO_HIDP) < 0)
229                 BT_ERR("Can't unregister HIDP socket");
230
231         proto_unregister(&hidp_proto);
232 }