- Update to 2.6.25-rc3.
[linux-flexiantxendom0-3.2.10.git] / net / bluetooth / bnep / sock.c
1 /*
2    BNEP implementation for Linux Bluetooth stack (BlueZ).
3    Copyright (C) 2001-2002 Inventel Systemes
4    Written 2001-2002 by
5         David Libault  <david.libault@inventel.fr>
6
7    Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License version 2 as
11    published by the Free Software Foundation;
12
13    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
17    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
22    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
24    SOFTWARE IS DISCLAIMED.
25 */
26
27 /*
28  * $Id: sock.c,v 1.4 2002/08/04 21:23:58 maxk Exp $
29  */
30
31 #include <linux/module.h>
32
33 #include <linux/types.h>
34 #include <linux/capability.h>
35 #include <linux/errno.h>
36 #include <linux/kernel.h>
37 #include <linux/slab.h>
38 #include <linux/poll.h>
39 #include <linux/fcntl.h>
40 #include <linux/skbuff.h>
41 #include <linux/socket.h>
42 #include <linux/ioctl.h>
43 #include <linux/file.h>
44 #include <linux/init.h>
45 #include <linux/compat.h>
46 #include <net/sock.h>
47
48 #include <asm/system.h>
49 #include <asm/uaccess.h>
50
51 #include "bnep.h"
52
53 #ifndef CONFIG_BT_BNEP_DEBUG
54 #undef  BT_DBG
55 #define BT_DBG( A... )
56 #endif
57
58 static int bnep_sock_release(struct socket *sock)
59 {
60         struct sock *sk = sock->sk;
61
62         BT_DBG("sock %p sk %p", sock, sk);
63
64         if (!sk)
65                 return 0;
66
67         sock_orphan(sk);
68         sock_put(sk);
69         return 0;
70 }
71
72 static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
73 {
74         struct bnep_connlist_req cl;
75         struct bnep_connadd_req  ca;
76         struct bnep_conndel_req  cd;
77         struct bnep_conninfo ci;
78         struct socket *nsock;
79         void __user *argp = (void __user *)arg;
80         int err;
81
82         BT_DBG("cmd %x arg %lx", cmd, arg);
83
84         switch (cmd) {
85         case BNEPCONNADD:
86                 if (!capable(CAP_NET_ADMIN))
87                         return -EACCES;
88
89                 if (copy_from_user(&ca, argp, sizeof(ca)))
90                         return -EFAULT;
91
92                 nsock = sockfd_lookup(ca.sock, &err);
93                 if (!nsock)
94                         return err;
95
96                 if (nsock->sk->sk_state != BT_CONNECTED) {
97                         sockfd_put(nsock);
98                         return -EBADFD;
99                 }
100
101                 err = bnep_add_connection(&ca, nsock);
102                 if (!err) {
103                         if (copy_to_user(argp, &ca, sizeof(ca)))
104                                 err = -EFAULT;
105                 } else
106                         sockfd_put(nsock);
107
108                 return err;
109
110         case BNEPCONNDEL:
111                 if (!capable(CAP_NET_ADMIN))
112                         return -EACCES;
113
114                 if (copy_from_user(&cd, argp, sizeof(cd)))
115                         return -EFAULT;
116
117                 return bnep_del_connection(&cd);
118
119         case BNEPGETCONNLIST:
120                 if (copy_from_user(&cl, argp, sizeof(cl)))
121                         return -EFAULT;
122
123                 if (cl.cnum <= 0)
124                         return -EINVAL;
125
126                 err = bnep_get_connlist(&cl);
127                 if (!err && copy_to_user(argp, &cl, sizeof(cl)))
128                         return -EFAULT;
129
130                 return err;
131
132         case BNEPGETCONNINFO:
133                 if (copy_from_user(&ci, argp, sizeof(ci)))
134                         return -EFAULT;
135
136                 err = bnep_get_conninfo(&ci);
137                 if (!err && copy_to_user(argp, &ci, sizeof(ci)))
138                         return -EFAULT;
139
140                 return err;
141
142         default:
143                 return -EINVAL;
144         }
145
146         return 0;
147 }
148
149 #ifdef CONFIG_COMPAT
150 static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
151 {
152         if (cmd == BNEPGETCONNLIST) {
153                 struct bnep_connlist_req cl;
154                 uint32_t uci;
155                 int err;
156
157                 if (get_user(cl.cnum, (uint32_t __user *) arg) ||
158                                 get_user(uci, (u32 __user *) (arg + 4)))
159                         return -EFAULT;
160
161                 cl.ci = compat_ptr(uci);
162
163                 if (cl.cnum <= 0)
164                         return -EINVAL;
165
166                 err = bnep_get_connlist(&cl);
167
168                 if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
169                         err = -EFAULT;
170
171                 return err;
172         }
173
174         return bnep_sock_ioctl(sock, cmd, arg);
175 }
176 #endif
177
178 static const struct proto_ops bnep_sock_ops = {
179         .family         = PF_BLUETOOTH,
180         .owner          = THIS_MODULE,
181         .release        = bnep_sock_release,
182         .ioctl          = bnep_sock_ioctl,
183 #ifdef CONFIG_COMPAT
184         .compat_ioctl   = bnep_sock_compat_ioctl,
185 #endif
186         .bind           = sock_no_bind,
187         .getname        = sock_no_getname,
188         .sendmsg        = sock_no_sendmsg,
189         .recvmsg        = sock_no_recvmsg,
190         .poll           = sock_no_poll,
191         .listen         = sock_no_listen,
192         .shutdown       = sock_no_shutdown,
193         .setsockopt     = sock_no_setsockopt,
194         .getsockopt     = sock_no_getsockopt,
195         .connect        = sock_no_connect,
196         .socketpair     = sock_no_socketpair,
197         .accept         = sock_no_accept,
198         .mmap           = sock_no_mmap
199 };
200
201 static struct proto bnep_proto = {
202         .name           = "BNEP",
203         .owner          = THIS_MODULE,
204         .obj_size       = sizeof(struct bt_sock)
205 };
206
207 static int bnep_sock_create(struct net *net, struct socket *sock, int protocol)
208 {
209         struct sock *sk;
210
211         BT_DBG("sock %p", sock);
212
213         if (sock->type != SOCK_RAW)
214                 return -ESOCKTNOSUPPORT;
215
216         sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto);
217         if (!sk)
218                 return -ENOMEM;
219
220         sock_init_data(sock, sk);
221
222         sock->ops = &bnep_sock_ops;
223
224         sock->state = SS_UNCONNECTED;
225
226         sock_reset_flag(sk, SOCK_ZAPPED);
227
228         sk->sk_protocol = protocol;
229         sk->sk_state    = BT_OPEN;
230
231         return 0;
232 }
233
234 static struct net_proto_family bnep_sock_family_ops = {
235         .family = PF_BLUETOOTH,
236         .owner  = THIS_MODULE,
237         .create = bnep_sock_create
238 };
239
240 int __init bnep_sock_init(void)
241 {
242         int err;
243
244         err = proto_register(&bnep_proto, 0);
245         if (err < 0)
246                 return err;
247
248         err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
249         if (err < 0)
250                 goto error;
251
252         return 0;
253
254 error:
255         BT_ERR("Can't register BNEP socket");
256         proto_unregister(&bnep_proto);
257         return err;
258 }
259
260 int __exit bnep_sock_cleanup(void)
261 {
262         if (bt_sock_unregister(BTPROTO_BNEP) < 0)
263                 BT_ERR("Can't unregister BNEP socket");
264
265         proto_unregister(&bnep_proto);
266
267         return 0;
268 }