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