blob: 2151913892ce8705d093a96fa65c3888e8a6dbb1 [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
Al Viro702ec302018-08-16 21:55:55 -040049static int do_hidp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 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
Al Viro702ec302018-08-16 21:55:55 -040059 BT_DBG("cmd %x arg %p", cmd, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61 switch (cmd) {
62 case HIDPCONNADD:
63 if (!capable(CAP_NET_ADMIN))
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +000064 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
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) {
Julia Lawall67b23212008-01-07 22:38:42 -080075 sockfd_put(csock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 return err;
77 }
Young Xiaoa1616a52019-04-12 15:24:30 +080078 ca.name[sizeof(ca.name)-1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
David Herrmann52051852013-04-06 20:28:47 +020080 err = hidp_connection_add(&ca, csock, isock);
81 if (!err && copy_to_user(argp, &ca, sizeof(ca)))
82 err = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
David Herrmann52051852013-04-06 20:28:47 +020084 sockfd_put(csock);
85 sockfd_put(isock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
87 return err;
88
89 case HIDPCONNDEL:
90 if (!capable(CAP_NET_ADMIN))
Zhao Hongjiangbf5b30b2012-09-20 22:37:25 +000091 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93 if (copy_from_user(&cd, argp, sizeof(cd)))
94 return -EFAULT;
95
David Herrmann52051852013-04-06 20:28:47 +020096 return hidp_connection_del(&cd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
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
Al Viro702ec302018-08-16 21:55:55 -0400125static 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
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200130#ifdef CONFIG_COMPAT
131struct compat_hidp_connadd_req {
Szymon Janc17f09a72011-03-21 14:20:01 +0100132 int ctrl_sock; /* Connected control socket */
133 int intr_sock; /* Connected interrupt socket */
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200134 __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
147static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
148{
Al Viro702ec302018-08-16 21:55:55 -0400149 void __user *argp = compat_ptr(arg);
150 int err;
151
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200152 if (cmd == HIDPGETCONNLIST) {
153 struct hidp_connlist_req cl;
Al Viro702ec302018-08-16 21:55:55 -0400154 u32 __user *p = argp;
Johan Hedberg816a11d2012-02-26 13:04:52 +0200155 u32 uci;
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200156
Al Viro702ec302018-08-16 21:55:55 -0400157 if (get_user(cl.cnum, p) || get_user(uci, p + 1))
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200158 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
Al Viro702ec302018-08-16 21:55:55 -0400167 if (!err && put_user(cl.cnum, p))
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200168 err = -EFAULT;
169
170 return err;
171 } else if (cmd == HIDPCONNADD) {
Al Viro702ec302018-08-16 21:55:55 -0400172 struct compat_hidp_connadd_req ca32;
173 struct hidp_connadd_req ca;
174 struct socket *csock;
175 struct socket *isock;
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200176
Al Viro702ec302018-08-16 21:55:55 -0400177 if (!capable(CAP_NET_ADMIN))
178 return -EPERM;
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200179
Al Viro702ec302018-08-16 21:55:55 -0400180 if (copy_from_user(&ca32, (void __user *) arg, sizeof(ca32)))
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200181 return -EFAULT;
182
Al Viro702ec302018-08-16 21:55:55 -0400183 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);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900196
Al Viro702ec302018-08-16 21:55:55 -0400197 csock = sockfd_lookup(ca.ctrl_sock, &err);
198 if (!csock)
199 return err;
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200200
Al Viro702ec302018-08-16 21:55:55 -0400201 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;
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200215 }
216
217 return hidp_sock_ioctl(sock, cmd, arg);
218}
219#endif
220
Eric Dumazet90ddc4f2005-12-22 12:49:22 -0800221static const struct proto_ops hidp_sock_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 .family = PF_BLUETOOTH,
223 .owner = THIS_MODULE,
224 .release = hidp_sock_release,
225 .ioctl = hidp_sock_ioctl,
Marcel Holtmanne9c5702e2006-10-15 17:30:22 +0200226#ifdef CONFIG_COMPAT
227 .compat_ioctl = hidp_sock_compat_ioctl,
228#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 .bind = sock_no_bind,
230 .getname = sock_no_getname,
231 .sendmsg = sock_no_sendmsg,
232 .recvmsg = sock_no_recvmsg,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 .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
Eric Paris3f378b62009-11-05 22:18:14 -0800249static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
250 int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251{
252 struct sock *sk;
253
254 BT_DBG("sock %p", sock);
255
256 if (sock->type != SOCK_RAW)
257 return -ESOCKTNOSUPPORT;
258
Eric W. Biederman11aa9c22015-05-08 21:09:13 -0500259 sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, kern);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 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
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +0900274 bt_sock_link(&hidp_sk_list, sk);
275
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 return 0;
277}
278
Stephen Hemmingerec1b4cf2009-10-05 05:58:39 +0000279static const struct net_proto_family hidp_sock_family_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 .family = PF_BLUETOOTH,
281 .owner = THIS_MODULE,
282 .create = hidp_sock_create
283};
284
285int __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);
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +0900294 if (err < 0) {
295 BT_ERR("Can't register HIDP socket");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 goto error;
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +0900297 }
298
Al Virob0316612013-04-04 19:14:33 -0400299 err = bt_procfs_init(&init_net, "hidp", &hidp_sk_list, NULL);
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +0900300 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
308 return 0;
309
310error:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 proto_unregister(&hidp_proto);
312 return err;
313}
314
315void __exit hidp_cleanup_sockets(void)
316{
Masatake YAMATO5c6ad8e2012-07-26 01:29:00 +0900317 bt_procfs_cleanup(&init_net, "hidp");
David Herrmann5e9d7f82013-02-24 19:36:51 +0100318 bt_sock_unregister(BTPROTO_HIDP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 proto_unregister(&hidp_proto);
320}