This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.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/config.h>
24 #include <linux/module.h>
25
26 #include <linux/types.h>
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
29 #include <linux/major.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 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 int hidp_sock_create(struct socket *sock, int protocol)
168 {
169         struct sock *sk;
170
171         BT_DBG("sock %p", sock);
172
173         if (sock->type != SOCK_RAW)
174                 return -ESOCKTNOSUPPORT;
175
176         if (!(sk = bt_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL)))
177                 return -ENOMEM;
178
179         sk_set_owner(sk, THIS_MODULE);
180
181         sock->ops = &hidp_sock_ops;
182
183         sock->state = SS_UNCONNECTED;
184
185         sk->sk_destruct = NULL;
186         sk->sk_protocol = protocol;
187
188         return 0;
189 }
190
191 static struct net_proto_family hidp_sock_family_ops = {
192         .family = PF_BLUETOOTH,
193         .owner  = THIS_MODULE,
194         .create = hidp_sock_create
195 };
196
197 int __init hidp_init_sockets(void)
198 {
199         int err;
200
201         err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
202         if (err < 0)
203                 BT_ERR("Can't register HIDP socket");
204
205         return err;
206 }
207
208 void __exit hidp_cleanup_sockets(void)
209 {
210         if (bt_sock_unregister(BTPROTO_HIDP) < 0)
211                 BT_ERR("Can't unregister HIDP socket");
212 }