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