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