blob: cc80c76177b6e3f5e3343c758ebc462eee201fae [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 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
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090013 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 SOFTWARE IS DISCLAIMED.
21*/
22
Gustavo Padovan8c520a52012-05-23 04:04:22 -030023#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26#include "hidp.h"
27
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +090028static struct bt_sock_list hidp_sk_list = {
29 .lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
30};
31
Linus Torvalds1da177e2005-04-16 15:20:36 -070032static 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
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +090041 bt_sock_unlink(&hidp_sk_list, sk);
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 sock_orphan(sk);
44 sock_put(sk);
45
46 return 0;
47}
48
49static 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))
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +000065 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
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) {
Julia Lawall67b23212008-01-07 22:38:42 -080076 sockfd_put(csock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 return err;
78 }
Young Xiao0d134ae2019-04-12 15:24:30 +080079 ca.name[sizeof(ca.name)-1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
David Herrmann52051852013-04-06 20:28:47 +020081 err = hidp_connection_add(&ca, csock, isock);
82 if (!err && copy_to_user(argp, &ca, sizeof(ca)))
83 err = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
David Herrmann52051852013-04-06 20:28:47 +020085 sockfd_put(csock);
86 sockfd_put(isock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
88 return err;
89
90 case HIDPCONNDEL:
91 if (!capable(CAP_NET_ADMIN))
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +000092 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94 if (copy_from_user(&cd, argp, sizeof(cd)))
95 return -EFAULT;
96
David Herrmann52051852013-04-06 20:28:47 +020097 return hidp_connection_del(&cd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99 case HIDPGETCONNLIST:
100 if (copy_from_user(&cl, argp, sizeof(cl)))
101 return -EFAULT;
102
103 if (cl.cnum <= 0)
104 return -EINVAL;
105
106 err = hidp_get_connlist(&cl);
107 if (!err && copy_to_user(argp, &cl, sizeof(cl)))
108 return -EFAULT;
109
110 return err;
111
112 case HIDPGETCONNINFO:
113 if (copy_from_user(&ci, argp, sizeof(ci)))
114 return -EFAULT;
115
116 err = hidp_get_conninfo(&ci);
117 if (!err && copy_to_user(argp, &ci, sizeof(ci)))
118 return -EFAULT;
119
120 return err;
121 }
122
123 return -EINVAL;
124}
125
Marcel Holtmanne9c57022006-10-15 17:30:22 +0200126#ifdef CONFIG_COMPAT
127struct compat_hidp_connadd_req {
Szymon Janc17f09a72011-03-21 14:20:01 +0100128 int ctrl_sock; /* Connected control socket */
129 int intr_sock; /* Connected interrupt socket */
Marcel Holtmanne9c57022006-10-15 17:30:22 +0200130 __u16 parser;
131 __u16 rd_size;
132 compat_uptr_t rd_data;
133 __u8 country;
134 __u8 subclass;
135 __u16 vendor;
136 __u16 product;
137 __u16 version;
138 __u32 flags;
139 __u32 idle_to;
140 char name[128];
141};
142
143static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
144{
145 if (cmd == HIDPGETCONNLIST) {
146 struct hidp_connlist_req cl;
Johan Hedberg816a11d2012-02-26 13:04:52 +0200147 u32 uci;
Marcel Holtmanne9c57022006-10-15 17:30:22 +0200148 int err;
149
Johan Hedberg816a11d2012-02-26 13:04:52 +0200150 if (get_user(cl.cnum, (u32 __user *) arg) ||
Marcel Holtmanne9c57022006-10-15 17:30:22 +0200151 get_user(uci, (u32 __user *) (arg + 4)))
152 return -EFAULT;
153
154 cl.ci = compat_ptr(uci);
155
156 if (cl.cnum <= 0)
157 return -EINVAL;
158
159 err = hidp_get_connlist(&cl);
160
Johan Hedberg816a11d2012-02-26 13:04:52 +0200161 if (!err && put_user(cl.cnum, (u32 __user *) arg))
Marcel Holtmanne9c57022006-10-15 17:30:22 +0200162 err = -EFAULT;
163
164 return err;
165 } else if (cmd == HIDPCONNADD) {
166 struct compat_hidp_connadd_req ca;
167 struct hidp_connadd_req __user *uca;
168
169 uca = compat_alloc_user_space(sizeof(*uca));
170
Al Viro55e74742007-02-09 16:38:00 +0000171 if (copy_from_user(&ca, (void __user *) arg, sizeof(ca)))
Marcel Holtmanne9c57022006-10-15 17:30:22 +0200172 return -EFAULT;
173
174 if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
175 put_user(ca.intr_sock, &uca->intr_sock) ||
176 put_user(ca.parser, &uca->parser) ||
Marcel Holtmanna83d6c0d2007-02-17 23:58:44 +0100177 put_user(ca.rd_size, &uca->rd_size) ||
Marcel Holtmanne9c57022006-10-15 17:30:22 +0200178 put_user(compat_ptr(ca.rd_data), &uca->rd_data) ||
179 put_user(ca.country, &uca->country) ||
180 put_user(ca.subclass, &uca->subclass) ||
181 put_user(ca.vendor, &uca->vendor) ||
182 put_user(ca.product, &uca->product) ||
183 put_user(ca.version, &uca->version) ||
184 put_user(ca.flags, &uca->flags) ||
185 put_user(ca.idle_to, &uca->idle_to) ||
186 copy_to_user(&uca->name[0], &ca.name[0], 128))
187 return -EFAULT;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900188
Marcel Holtmanne9c57022006-10-15 17:30:22 +0200189 arg = (unsigned long) uca;
190
191 /* Fall through. We don't actually write back any _changes_
192 to the structure anyway, so there's no need to copy back
193 into the original compat version */
194 }
195
196 return hidp_sock_ioctl(sock, cmd, arg);
197}
198#endif
199
Eric Dumazet90ddc4f2005-12-22 12:49:22 -0800200static const struct proto_ops hidp_sock_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 .family = PF_BLUETOOTH,
202 .owner = THIS_MODULE,
203 .release = hidp_sock_release,
204 .ioctl = hidp_sock_ioctl,
Marcel Holtmanne9c57022006-10-15 17:30:22 +0200205#ifdef CONFIG_COMPAT
206 .compat_ioctl = hidp_sock_compat_ioctl,
207#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 .bind = sock_no_bind,
209 .getname = sock_no_getname,
210 .sendmsg = sock_no_sendmsg,
211 .recvmsg = sock_no_recvmsg,
212 .poll = sock_no_poll,
213 .listen = sock_no_listen,
214 .shutdown = sock_no_shutdown,
215 .setsockopt = sock_no_setsockopt,
216 .getsockopt = sock_no_getsockopt,
217 .connect = sock_no_connect,
218 .socketpair = sock_no_socketpair,
219 .accept = sock_no_accept,
220 .mmap = sock_no_mmap
221};
222
223static struct proto hidp_proto = {
224 .name = "HIDP",
225 .owner = THIS_MODULE,
226 .obj_size = sizeof(struct bt_sock)
227};
228
Eric Paris3f378b62009-11-05 22:18:14 -0800229static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
230 int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
232 struct sock *sk;
233
234 BT_DBG("sock %p", sock);
235
236 if (sock->type != SOCK_RAW)
237 return -ESOCKTNOSUPPORT;
238
Eric W. Biederman11aa9c22015-05-08 21:09:13 -0500239 sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, kern);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 if (!sk)
241 return -ENOMEM;
242
243 sock_init_data(sock, sk);
244
245 sock->ops = &hidp_sock_ops;
246
247 sock->state = SS_UNCONNECTED;
248
249 sock_reset_flag(sk, SOCK_ZAPPED);
250
251 sk->sk_protocol = protocol;
252 sk->sk_state = BT_OPEN;
253
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +0900254 bt_sock_link(&hidp_sk_list, sk);
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 return 0;
257}
258
Stephen Hemmingerec1b4cf2009-10-05 05:58:39 +0000259static const struct net_proto_family hidp_sock_family_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 .family = PF_BLUETOOTH,
261 .owner = THIS_MODULE,
262 .create = hidp_sock_create
263};
264
265int __init hidp_init_sockets(void)
266{
267 int err;
268
269 err = proto_register(&hidp_proto, 0);
270 if (err < 0)
271 return err;
272
273 err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +0900274 if (err < 0) {
275 BT_ERR("Can't register HIDP socket");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 goto error;
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +0900277 }
278
Al Virob0316612013-04-04 19:14:33 -0400279 err = bt_procfs_init(&init_net, "hidp", &hidp_sk_list, NULL);
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +0900280 if (err < 0) {
281 BT_ERR("Failed to create HIDP proc file");
282 bt_sock_unregister(BTPROTO_HIDP);
283 goto error;
284 }
285
286 BT_INFO("HIDP socket layer initialized");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 return 0;
289
290error:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 proto_unregister(&hidp_proto);
292 return err;
293}
294
295void __exit hidp_cleanup_sockets(void)
296{
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +0900297 bt_procfs_cleanup(&init_net, "hidp");
David Herrmann5e9d7f82013-02-24 19:36:51 +0100298 bt_sock_unregister(BTPROTO_HIDP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 proto_unregister(&hidp_proto);
300}