tizen 2.3.1 release
[kernel/linux-3.0.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 #include <linux/export.h>
28 #include <linux/file.h>
29
30 #include "bnep.h"
31
32 static struct bt_sock_list bnep_sk_list = {
33         .lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
34 };
35
36 static int bnep_sock_release(struct socket *sock)
37 {
38         struct sock *sk = sock->sk;
39
40         BT_DBG("sock %p sk %p", sock, sk);
41
42         if (!sk)
43                 return 0;
44
45         bt_sock_unlink(&bnep_sk_list, sk);
46
47         sock_orphan(sk);
48         sock_put(sk);
49         return 0;
50 }
51
52 static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
53 {
54         struct bnep_connlist_req cl;
55         struct bnep_connadd_req  ca;
56         struct bnep_conndel_req  cd;
57         struct bnep_conninfo ci;
58         struct socket *nsock;
59         void __user *argp = (void __user *)arg;
60         int err;
61
62         BT_DBG("cmd %x arg %lx", cmd, arg);
63
64         switch (cmd) {
65         case BNEPCONNADD:
66                 if (!capable(CAP_NET_ADMIN))
67                         return -EPERM;
68
69                 if (copy_from_user(&ca, argp, sizeof(ca)))
70                         return -EFAULT;
71
72                 nsock = sockfd_lookup(ca.sock, &err);
73                 if (!nsock)
74                         return err;
75
76                 if (nsock->sk->sk_state != BT_CONNECTED) {
77                         sockfd_put(nsock);
78                         return -EBADFD;
79                 }
80                 ca.device[sizeof(ca.device)-1] = 0;
81
82                 err = bnep_add_connection(&ca, nsock);
83                 if (!err) {
84                         if (copy_to_user(argp, &ca, sizeof(ca)))
85                                 err = -EFAULT;
86                 } else
87                         sockfd_put(nsock);
88
89                 return err;
90
91         case BNEPCONNDEL:
92                 if (!capable(CAP_NET_ADMIN))
93                         return -EPERM;
94
95                 if (copy_from_user(&cd, argp, sizeof(cd)))
96                         return -EFAULT;
97
98                 return bnep_del_connection(&cd);
99
100         case BNEPGETCONNLIST:
101                 if (copy_from_user(&cl, argp, sizeof(cl)))
102                         return -EFAULT;
103
104                 if (cl.cnum <= 0)
105                         return -EINVAL;
106
107                 err = bnep_get_connlist(&cl);
108                 if (!err && copy_to_user(argp, &cl, sizeof(cl)))
109                         return -EFAULT;
110
111                 return err;
112
113         case BNEPGETCONNINFO:
114                 if (copy_from_user(&ci, argp, sizeof(ci)))
115                         return -EFAULT;
116
117                 err = bnep_get_conninfo(&ci);
118                 if (!err && copy_to_user(argp, &ci, sizeof(ci)))
119                         return -EFAULT;
120
121                 return err;
122
123         default:
124                 return -EINVAL;
125         }
126
127         return 0;
128 }
129
130 #ifdef CONFIG_COMPAT
131 static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
132 {
133         if (cmd == BNEPGETCONNLIST) {
134                 struct bnep_connlist_req cl;
135                 u32 uci;
136                 int err;
137
138                 if (get_user(cl.cnum, (u32 __user *) arg) ||
139                                 get_user(uci, (u32 __user *) (arg + 4)))
140                         return -EFAULT;
141
142                 cl.ci = compat_ptr(uci);
143
144                 if (cl.cnum <= 0)
145                         return -EINVAL;
146
147                 err = bnep_get_connlist(&cl);
148
149                 if (!err && put_user(cl.cnum, (u32 __user *) arg))
150                         err = -EFAULT;
151
152                 return err;
153         }
154
155         return bnep_sock_ioctl(sock, cmd, arg);
156 }
157 #endif
158
159 static const struct proto_ops bnep_sock_ops = {
160         .family         = PF_BLUETOOTH,
161         .owner          = THIS_MODULE,
162         .release        = bnep_sock_release,
163         .ioctl          = bnep_sock_ioctl,
164 #ifdef CONFIG_COMPAT
165         .compat_ioctl   = bnep_sock_compat_ioctl,
166 #endif
167         .bind           = sock_no_bind,
168         .getname        = sock_no_getname,
169         .sendmsg        = sock_no_sendmsg,
170         .recvmsg        = sock_no_recvmsg,
171         .poll           = sock_no_poll,
172         .listen         = sock_no_listen,
173         .shutdown       = sock_no_shutdown,
174         .setsockopt     = sock_no_setsockopt,
175         .getsockopt     = sock_no_getsockopt,
176         .connect        = sock_no_connect,
177         .socketpair     = sock_no_socketpair,
178         .accept         = sock_no_accept,
179         .mmap           = sock_no_mmap
180 };
181
182 static struct proto bnep_proto = {
183         .name           = "BNEP",
184         .owner          = THIS_MODULE,
185         .obj_size       = sizeof(struct bt_sock)
186 };
187
188 static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
189                             int kern)
190 {
191         struct sock *sk;
192
193         BT_DBG("sock %p", sock);
194
195         if (sock->type != SOCK_RAW)
196                 return -ESOCKTNOSUPPORT;
197
198         sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto);
199         if (!sk)
200                 return -ENOMEM;
201
202         sock_init_data(sock, sk);
203
204         sock->ops = &bnep_sock_ops;
205
206         sock->state = SS_UNCONNECTED;
207
208         sock_reset_flag(sk, SOCK_ZAPPED);
209
210         sk->sk_protocol = protocol;
211         sk->sk_state    = BT_OPEN;
212
213         bt_sock_link(&bnep_sk_list, sk);
214         return 0;
215 }
216
217 static const struct net_proto_family bnep_sock_family_ops = {
218         .family = PF_BLUETOOTH,
219         .owner  = THIS_MODULE,
220         .create = bnep_sock_create
221 };
222
223 int __init bnep_sock_init(void)
224 {
225         int err;
226
227         err = proto_register(&bnep_proto, 0);
228         if (err < 0)
229                 return err;
230
231         err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
232         if (err < 0) {
233                 BT_ERR("Can't register BNEP socket");
234                 goto error;
235         }
236
237         err = bt_procfs_init(&init_net, "bnep", &bnep_sk_list, NULL);
238         if (err < 0) {
239                 BT_ERR("Failed to create BNEP proc file");
240                 bt_sock_unregister(BTPROTO_BNEP);
241                 goto error;
242         }
243
244         BT_INFO("BNEP socket layer initialized");
245
246         return 0;
247
248 error:
249         proto_unregister(&bnep_proto);
250         return err;
251 }
252
253 void __exit bnep_sock_cleanup(void)
254 {
255         bt_procfs_cleanup(&init_net, "bnep");
256         bt_sock_unregister(BTPROTO_BNEP);
257         proto_unregister(&bnep_proto);
258 }