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