]> asedeno.scripts.mit.edu Git - linux.git/blob - net/bluetooth/hidp/sock.c
Merge branch 'next' into for-linus
[linux.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/export.h>
24 #include <linux/file.h>
25
26 #include "hidp.h"
27
28 static struct bt_sock_list hidp_sk_list = {
29         .lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
30 };
31
32 static int hidp_sock_release(struct socket *sock)
33 {
34         struct sock *sk = sock->sk;
35
36         BT_DBG("sock %p sk %p", sock, sk);
37
38         if (!sk)
39                 return 0;
40
41         bt_sock_unlink(&hidp_sk_list, sk);
42
43         sock_orphan(sk);
44         sock_put(sk);
45
46         return 0;
47 }
48
49 static int do_hidp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
50 {
51         struct hidp_connadd_req ca;
52         struct hidp_conndel_req cd;
53         struct hidp_connlist_req cl;
54         struct hidp_conninfo ci;
55         struct socket *csock;
56         struct socket *isock;
57         int err;
58
59         BT_DBG("cmd %x arg %p", cmd, argp);
60
61         switch (cmd) {
62         case HIDPCONNADD:
63                 if (!capable(CAP_NET_ADMIN))
64                         return -EPERM;
65
66                 if (copy_from_user(&ca, argp, sizeof(ca)))
67                         return -EFAULT;
68
69                 csock = sockfd_lookup(ca.ctrl_sock, &err);
70                 if (!csock)
71                         return err;
72
73                 isock = sockfd_lookup(ca.intr_sock, &err);
74                 if (!isock) {
75                         sockfd_put(csock);
76                         return err;
77                 }
78                 ca.name[sizeof(ca.name)-1] = 0;
79
80                 err = hidp_connection_add(&ca, csock, isock);
81                 if (!err && copy_to_user(argp, &ca, sizeof(ca)))
82                         err = -EFAULT;
83
84                 sockfd_put(csock);
85                 sockfd_put(isock);
86
87                 return err;
88
89         case HIDPCONNDEL:
90                 if (!capable(CAP_NET_ADMIN))
91                         return -EPERM;
92
93                 if (copy_from_user(&cd, argp, sizeof(cd)))
94                         return -EFAULT;
95
96                 return hidp_connection_del(&cd);
97
98         case HIDPGETCONNLIST:
99                 if (copy_from_user(&cl, argp, sizeof(cl)))
100                         return -EFAULT;
101
102                 if (cl.cnum <= 0)
103                         return -EINVAL;
104
105                 err = hidp_get_connlist(&cl);
106                 if (!err && copy_to_user(argp, &cl, sizeof(cl)))
107                         return -EFAULT;
108
109                 return err;
110
111         case HIDPGETCONNINFO:
112                 if (copy_from_user(&ci, argp, sizeof(ci)))
113                         return -EFAULT;
114
115                 err = hidp_get_conninfo(&ci);
116                 if (!err && copy_to_user(argp, &ci, sizeof(ci)))
117                         return -EFAULT;
118
119                 return err;
120         }
121
122         return -EINVAL;
123 }
124
125 static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
126 {
127         return do_hidp_sock_ioctl(sock, cmd, (void __user *)arg);
128 }
129
130 #ifdef CONFIG_COMPAT
131 struct compat_hidp_connadd_req {
132         int   ctrl_sock;        /* Connected control socket */
133         int   intr_sock;        /* Connected interrupt socket */
134         __u16 parser;
135         __u16 rd_size;
136         compat_uptr_t rd_data;
137         __u8  country;
138         __u8  subclass;
139         __u16 vendor;
140         __u16 product;
141         __u16 version;
142         __u32 flags;
143         __u32 idle_to;
144         char  name[128];
145 };
146
147 static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
148 {
149         void __user *argp = compat_ptr(arg);
150         int err;
151
152         if (cmd == HIDPGETCONNLIST) {
153                 struct hidp_connlist_req cl;
154                 u32 __user *p = argp;
155                 u32 uci;
156
157                 if (get_user(cl.cnum, p) || get_user(uci, p + 1))
158                         return -EFAULT;
159
160                 cl.ci = compat_ptr(uci);
161
162                 if (cl.cnum <= 0)
163                         return -EINVAL;
164
165                 err = hidp_get_connlist(&cl);
166
167                 if (!err && put_user(cl.cnum, p))
168                         err = -EFAULT;
169
170                 return err;
171         } else if (cmd == HIDPCONNADD) {
172                 struct compat_hidp_connadd_req ca32;
173                 struct hidp_connadd_req ca;
174                 struct socket *csock;
175                 struct socket *isock;
176
177                 if (!capable(CAP_NET_ADMIN))
178                         return -EPERM;
179
180                 if (copy_from_user(&ca32, (void __user *) arg, sizeof(ca32)))
181                         return -EFAULT;
182
183                 ca.ctrl_sock = ca32.ctrl_sock;
184                 ca.intr_sock = ca32.intr_sock;
185                 ca.parser = ca32.parser;
186                 ca.rd_size = ca32.rd_size;
187                 ca.rd_data = compat_ptr(ca32.rd_data);
188                 ca.country = ca32.country;
189                 ca.subclass = ca32.subclass;
190                 ca.vendor = ca32.vendor;
191                 ca.product = ca32.product;
192                 ca.version = ca32.version;
193                 ca.flags = ca32.flags;
194                 ca.idle_to = ca32.idle_to;
195                 memcpy(ca.name, ca32.name, 128);
196
197                 csock = sockfd_lookup(ca.ctrl_sock, &err);
198                 if (!csock)
199                         return err;
200
201                 isock = sockfd_lookup(ca.intr_sock, &err);
202                 if (!isock) {
203                         sockfd_put(csock);
204                         return err;
205                 }
206
207                 err = hidp_connection_add(&ca, csock, isock);
208                 if (!err && copy_to_user(argp, &ca32, sizeof(ca32)))
209                         err = -EFAULT;
210
211                 sockfd_put(csock);
212                 sockfd_put(isock);
213
214                 return err;
215         }
216
217         return hidp_sock_ioctl(sock, cmd, arg);
218 }
219 #endif
220
221 static const struct proto_ops hidp_sock_ops = {
222         .family         = PF_BLUETOOTH,
223         .owner          = THIS_MODULE,
224         .release        = hidp_sock_release,
225         .ioctl          = hidp_sock_ioctl,
226 #ifdef CONFIG_COMPAT
227         .compat_ioctl   = hidp_sock_compat_ioctl,
228 #endif
229         .bind           = sock_no_bind,
230         .getname        = sock_no_getname,
231         .sendmsg        = sock_no_sendmsg,
232         .recvmsg        = sock_no_recvmsg,
233         .listen         = sock_no_listen,
234         .shutdown       = sock_no_shutdown,
235         .setsockopt     = sock_no_setsockopt,
236         .getsockopt     = sock_no_getsockopt,
237         .connect        = sock_no_connect,
238         .socketpair     = sock_no_socketpair,
239         .accept         = sock_no_accept,
240         .mmap           = sock_no_mmap
241 };
242
243 static struct proto hidp_proto = {
244         .name           = "HIDP",
245         .owner          = THIS_MODULE,
246         .obj_size       = sizeof(struct bt_sock)
247 };
248
249 static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
250                             int kern)
251 {
252         struct sock *sk;
253
254         BT_DBG("sock %p", sock);
255
256         if (sock->type != SOCK_RAW)
257                 return -ESOCKTNOSUPPORT;
258
259         sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, kern);
260         if (!sk)
261                 return -ENOMEM;
262
263         sock_init_data(sock, sk);
264
265         sock->ops = &hidp_sock_ops;
266
267         sock->state = SS_UNCONNECTED;
268
269         sock_reset_flag(sk, SOCK_ZAPPED);
270
271         sk->sk_protocol = protocol;
272         sk->sk_state    = BT_OPEN;
273
274         bt_sock_link(&hidp_sk_list, sk);
275
276         return 0;
277 }
278
279 static const struct net_proto_family hidp_sock_family_ops = {
280         .family = PF_BLUETOOTH,
281         .owner  = THIS_MODULE,
282         .create = hidp_sock_create
283 };
284
285 int __init hidp_init_sockets(void)
286 {
287         int err;
288
289         err = proto_register(&hidp_proto, 0);
290         if (err < 0)
291                 return err;
292
293         err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
294         if (err < 0) {
295                 BT_ERR("Can't register HIDP socket");
296                 goto error;
297         }
298
299         err = bt_procfs_init(&init_net, "hidp", &hidp_sk_list, NULL);
300         if (err < 0) {
301                 BT_ERR("Failed to create HIDP proc file");
302                 bt_sock_unregister(BTPROTO_HIDP);
303                 goto error;
304         }
305
306         BT_INFO("HIDP socket layer initialized");
307
308         return 0;
309
310 error:
311         proto_unregister(&hidp_proto);
312         return err;
313 }
314
315 void __exit hidp_cleanup_sockets(void)
316 {
317         bt_procfs_cleanup(&init_net, "hidp");
318         bt_sock_unregister(BTPROTO_HIDP);
319         proto_unregister(&hidp_proto);
320 }