xref: /linux/net/bluetooth/hidp/sock.c (revision bea06c7c1b83bcd0519b91141999369eae6925bd)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3    HIDP implementation for Linux Bluetooth stack (BlueZ).
4    Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
5 
6    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
7    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
9    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
10    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
11    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
16    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
17    SOFTWARE IS DISCLAIMED.
18 */
19 
20 #include <linux/compat.h>
21 #include <linux/export.h>
22 #include <linux/file.h>
23 
24 #include "hidp.h"
25 
26 static struct bt_sock_list hidp_sk_list = {
27 	.lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
28 };
29 
30 static int hidp_sock_release(struct socket *sock)
31 {
32 	struct sock *sk = sock->sk;
33 
34 	BT_DBG("sock %p sk %p", sock, sk);
35 
36 	if (!sk)
37 		return 0;
38 
39 	bt_sock_unlink(&hidp_sk_list, sk);
40 
41 	sock_orphan(sk);
42 	sock_put(sk);
43 
44 	return 0;
45 }
46 
47 static int do_hidp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
48 {
49 	struct hidp_connadd_req ca;
50 	struct hidp_conndel_req cd;
51 	struct hidp_connlist_req cl;
52 	struct hidp_conninfo ci;
53 	struct socket *csock;
54 	struct socket *isock;
55 	int err;
56 
57 	BT_DBG("cmd %x arg %p", cmd, argp);
58 
59 	switch (cmd) {
60 	case HIDPCONNADD:
61 		if (!capable(CAP_NET_ADMIN))
62 			return -EPERM;
63 
64 		if (copy_from_user(&ca, argp, sizeof(ca)))
65 			return -EFAULT;
66 
67 		csock = sockfd_lookup(ca.ctrl_sock, &err);
68 		if (!csock)
69 			return err;
70 
71 		isock = sockfd_lookup(ca.intr_sock, &err);
72 		if (!isock) {
73 			sockfd_put(csock);
74 			return err;
75 		}
76 		ca.name[sizeof(ca.name)-1] = 0;
77 
78 		err = hidp_connection_add(&ca, csock, isock);
79 		if (!err && copy_to_user(argp, &ca, sizeof(ca)))
80 			err = -EFAULT;
81 
82 		sockfd_put(csock);
83 		sockfd_put(isock);
84 
85 		return err;
86 
87 	case HIDPCONNDEL:
88 		if (!capable(CAP_NET_ADMIN))
89 			return -EPERM;
90 
91 		if (copy_from_user(&cd, argp, sizeof(cd)))
92 			return -EFAULT;
93 
94 		return hidp_connection_del(&cd);
95 
96 	case HIDPGETCONNLIST:
97 		if (copy_from_user(&cl, argp, sizeof(cl)))
98 			return -EFAULT;
99 
100 		if (cl.cnum <= 0)
101 			return -EINVAL;
102 
103 		err = hidp_get_connlist(&cl);
104 		if (!err && copy_to_user(argp, &cl, sizeof(cl)))
105 			return -EFAULT;
106 
107 		return err;
108 
109 	case HIDPGETCONNINFO:
110 		if (copy_from_user(&ci, argp, sizeof(ci)))
111 			return -EFAULT;
112 
113 		err = hidp_get_conninfo(&ci);
114 		if (!err && copy_to_user(argp, &ci, sizeof(ci)))
115 			return -EFAULT;
116 
117 		return err;
118 	}
119 
120 	return -EINVAL;
121 }
122 
123 static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
124 {
125 	return do_hidp_sock_ioctl(sock, cmd, (void __user *)arg);
126 }
127 
128 #ifdef CONFIG_COMPAT
129 struct compat_hidp_connadd_req {
130 	int   ctrl_sock;	/* Connected control socket */
131 	int   intr_sock;	/* Connected interrupt socket */
132 	__u16 parser;
133 	__u16 rd_size;
134 	compat_uptr_t rd_data;
135 	__u8  country;
136 	__u8  subclass;
137 	__u16 vendor;
138 	__u16 product;
139 	__u16 version;
140 	__u32 flags;
141 	__u32 idle_to;
142 	char  name[128];
143 };
144 
145 static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
146 {
147 	void __user *argp = compat_ptr(arg);
148 	int err;
149 
150 	if (cmd == HIDPGETCONNLIST) {
151 		struct hidp_connlist_req cl;
152 		u32 __user *p = argp;
153 		u32 uci;
154 
155 		if (get_user(cl.cnum, p) || get_user(uci, p + 1))
156 			return -EFAULT;
157 
158 		cl.ci = compat_ptr(uci);
159 
160 		if (cl.cnum <= 0)
161 			return -EINVAL;
162 
163 		err = hidp_get_connlist(&cl);
164 
165 		if (!err && put_user(cl.cnum, p))
166 			err = -EFAULT;
167 
168 		return err;
169 	} else if (cmd == HIDPCONNADD) {
170 		struct compat_hidp_connadd_req ca32;
171 		struct hidp_connadd_req ca;
172 		struct socket *csock;
173 		struct socket *isock;
174 
175 		if (!capable(CAP_NET_ADMIN))
176 			return -EPERM;
177 
178 		if (copy_from_user(&ca32, (void __user *) arg, sizeof(ca32)))
179 			return -EFAULT;
180 
181 		ca.ctrl_sock = ca32.ctrl_sock;
182 		ca.intr_sock = ca32.intr_sock;
183 		ca.parser = ca32.parser;
184 		ca.rd_size = ca32.rd_size;
185 		ca.rd_data = compat_ptr(ca32.rd_data);
186 		ca.country = ca32.country;
187 		ca.subclass = ca32.subclass;
188 		ca.vendor = ca32.vendor;
189 		ca.product = ca32.product;
190 		ca.version = ca32.version;
191 		ca.flags = ca32.flags;
192 		ca.idle_to = ca32.idle_to;
193 		ca32.name[sizeof(ca32.name) - 1] = '\0';
194 		memcpy(ca.name, ca32.name, 128);
195 
196 		csock = sockfd_lookup(ca.ctrl_sock, &err);
197 		if (!csock)
198 			return err;
199 
200 		isock = sockfd_lookup(ca.intr_sock, &err);
201 		if (!isock) {
202 			sockfd_put(csock);
203 			return err;
204 		}
205 
206 		err = hidp_connection_add(&ca, csock, isock);
207 		if (!err && copy_to_user(argp, &ca32, sizeof(ca32)))
208 			err = -EFAULT;
209 
210 		sockfd_put(csock);
211 		sockfd_put(isock);
212 
213 		return err;
214 	}
215 
216 	return hidp_sock_ioctl(sock, cmd, arg);
217 }
218 #endif
219 
220 static 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 	.listen		= sock_no_listen,
233 	.shutdown	= sock_no_shutdown,
234 	.connect	= sock_no_connect,
235 	.socketpair	= sock_no_socketpair,
236 	.accept		= sock_no_accept,
237 	.mmap		= sock_no_mmap
238 };
239 
240 static struct proto hidp_proto = {
241 	.name		= "HIDP",
242 	.owner		= THIS_MODULE,
243 	.obj_size	= sizeof(struct bt_sock)
244 };
245 
246 static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
247 			    int kern)
248 {
249 	struct sock *sk;
250 
251 	BT_DBG("sock %p", sock);
252 
253 	if (sock->type != SOCK_RAW)
254 		return -ESOCKTNOSUPPORT;
255 
256 	sk = bt_sock_alloc(net, sock, &hidp_proto, protocol, GFP_ATOMIC, kern);
257 	if (!sk)
258 		return -ENOMEM;
259 
260 	sock->ops = &hidp_sock_ops;
261 	sock->state = SS_UNCONNECTED;
262 
263 	bt_sock_link(&hidp_sk_list, sk);
264 
265 	return 0;
266 }
267 
268 static const struct net_proto_family hidp_sock_family_ops = {
269 	.family	= PF_BLUETOOTH,
270 	.owner	= THIS_MODULE,
271 	.create	= hidp_sock_create
272 };
273 
274 int __init hidp_init_sockets(void)
275 {
276 	int err;
277 
278 	err = proto_register(&hidp_proto, 0);
279 	if (err < 0)
280 		return err;
281 
282 	err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
283 	if (err < 0) {
284 		BT_ERR("Can't register HIDP socket");
285 		goto error;
286 	}
287 
288 	err = bt_procfs_init(&init_net, "hidp", &hidp_sk_list, NULL);
289 	if (err < 0) {
290 		BT_ERR("Failed to create HIDP proc file");
291 		bt_sock_unregister(BTPROTO_HIDP);
292 		goto error;
293 	}
294 
295 	BT_INFO("HIDP socket layer initialized");
296 
297 	return 0;
298 
299 error:
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 	bt_sock_unregister(BTPROTO_HIDP);
308 	proto_unregister(&hidp_proto);
309 }
310