xref: /openbmc/linux/net/bluetooth/cmtp/sock.c (revision a44d9e72)
1 /*
2    CMTP implementation for Linux Bluetooth stack (BlueZ).
3    Copyright (C) 2002-2003 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 
25 #include <linux/types.h>
26 #include <linux/capability.h>
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
29 #include <linux/poll.h>
30 #include <linux/fcntl.h>
31 #include <linux/skbuff.h>
32 #include <linux/socket.h>
33 #include <linux/ioctl.h>
34 #include <linux/file.h>
35 #include <linux/compat.h>
36 #include <linux/gfp.h>
37 #include <linux/uaccess.h>
38 #include <net/sock.h>
39 
40 #include <linux/isdn/capilli.h>
41 
42 
43 #include "cmtp.h"
44 
45 static struct bt_sock_list cmtp_sk_list = {
46 	.lock = __RW_LOCK_UNLOCKED(cmtp_sk_list.lock)
47 };
48 
cmtp_sock_release(struct socket * sock)49 static int cmtp_sock_release(struct socket *sock)
50 {
51 	struct sock *sk = sock->sk;
52 
53 	BT_DBG("sock %p sk %p", sock, sk);
54 
55 	if (!sk)
56 		return 0;
57 
58 	bt_sock_unlink(&cmtp_sk_list, sk);
59 
60 	sock_orphan(sk);
61 	sock_put(sk);
62 
63 	return 0;
64 }
65 
do_cmtp_sock_ioctl(struct socket * sock,unsigned int cmd,void __user * argp)66 static int do_cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
67 {
68 	struct cmtp_connadd_req ca;
69 	struct cmtp_conndel_req cd;
70 	struct cmtp_connlist_req cl;
71 	struct cmtp_conninfo ci;
72 	struct socket *nsock;
73 	int err;
74 
75 	BT_DBG("cmd %x arg %p", cmd, argp);
76 
77 	switch (cmd) {
78 	case CMTPCONNADD:
79 		if (!capable(CAP_NET_ADMIN))
80 			return -EPERM;
81 
82 		if (copy_from_user(&ca, argp, sizeof(ca)))
83 			return -EFAULT;
84 
85 		nsock = sockfd_lookup(ca.sock, &err);
86 		if (!nsock)
87 			return err;
88 
89 		if (nsock->sk->sk_state != BT_CONNECTED) {
90 			sockfd_put(nsock);
91 			return -EBADFD;
92 		}
93 
94 		err = cmtp_add_connection(&ca, nsock);
95 		if (!err) {
96 			if (copy_to_user(argp, &ca, sizeof(ca)))
97 				err = -EFAULT;
98 		} else
99 			sockfd_put(nsock);
100 
101 		return err;
102 
103 	case CMTPCONNDEL:
104 		if (!capable(CAP_NET_ADMIN))
105 			return -EPERM;
106 
107 		if (copy_from_user(&cd, argp, sizeof(cd)))
108 			return -EFAULT;
109 
110 		return cmtp_del_connection(&cd);
111 
112 	case CMTPGETCONNLIST:
113 		if (copy_from_user(&cl, argp, sizeof(cl)))
114 			return -EFAULT;
115 
116 		if (cl.cnum <= 0)
117 			return -EINVAL;
118 
119 		err = cmtp_get_connlist(&cl);
120 		if (!err && copy_to_user(argp, &cl, sizeof(cl)))
121 			return -EFAULT;
122 
123 		return err;
124 
125 	case CMTPGETCONNINFO:
126 		if (copy_from_user(&ci, argp, sizeof(ci)))
127 			return -EFAULT;
128 
129 		err = cmtp_get_conninfo(&ci);
130 		if (!err && copy_to_user(argp, &ci, sizeof(ci)))
131 			return -EFAULT;
132 
133 		return err;
134 	}
135 
136 	return -EINVAL;
137 }
138 
cmtp_sock_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)139 static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
140 {
141 	return do_cmtp_sock_ioctl(sock, cmd, (void __user *)arg);
142 }
143 
144 #ifdef CONFIG_COMPAT
cmtp_sock_compat_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)145 static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
146 {
147 	void __user *argp = compat_ptr(arg);
148 	if (cmd == CMTPGETCONNLIST) {
149 		struct cmtp_connlist_req cl;
150 		u32 __user *p = argp;
151 		u32 uci;
152 		int err;
153 
154 		if (get_user(cl.cnum, p) || get_user(uci, p + 1))
155 			return -EFAULT;
156 
157 		cl.ci = compat_ptr(uci);
158 
159 		if (cl.cnum <= 0)
160 			return -EINVAL;
161 
162 		err = cmtp_get_connlist(&cl);
163 
164 		if (!err && put_user(cl.cnum, p))
165 			err = -EFAULT;
166 
167 		return err;
168 	}
169 
170 	return do_cmtp_sock_ioctl(sock, cmd, argp);
171 }
172 #endif
173 
174 static const struct proto_ops cmtp_sock_ops = {
175 	.family		= PF_BLUETOOTH,
176 	.owner		= THIS_MODULE,
177 	.release	= cmtp_sock_release,
178 	.ioctl		= cmtp_sock_ioctl,
179 #ifdef CONFIG_COMPAT
180 	.compat_ioctl	= cmtp_sock_compat_ioctl,
181 #endif
182 	.bind		= sock_no_bind,
183 	.getname	= sock_no_getname,
184 	.sendmsg	= sock_no_sendmsg,
185 	.recvmsg	= sock_no_recvmsg,
186 	.listen		= sock_no_listen,
187 	.shutdown	= sock_no_shutdown,
188 	.connect	= sock_no_connect,
189 	.socketpair	= sock_no_socketpair,
190 	.accept		= sock_no_accept,
191 	.mmap		= sock_no_mmap
192 };
193 
194 static struct proto cmtp_proto = {
195 	.name		= "CMTP",
196 	.owner		= THIS_MODULE,
197 	.obj_size	= sizeof(struct bt_sock)
198 };
199 
cmtp_sock_create(struct net * net,struct socket * sock,int protocol,int kern)200 static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol,
201 			    int kern)
202 {
203 	struct sock *sk;
204 
205 	BT_DBG("sock %p", sock);
206 
207 	if (sock->type != SOCK_RAW)
208 		return -ESOCKTNOSUPPORT;
209 
210 	sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, kern);
211 	if (!sk)
212 		return -ENOMEM;
213 
214 	sock_init_data(sock, sk);
215 
216 	sock->ops = &cmtp_sock_ops;
217 
218 	sock->state = SS_UNCONNECTED;
219 
220 	sock_reset_flag(sk, SOCK_ZAPPED);
221 
222 	sk->sk_protocol = protocol;
223 	sk->sk_state    = BT_OPEN;
224 
225 	bt_sock_link(&cmtp_sk_list, sk);
226 
227 	return 0;
228 }
229 
230 static const struct net_proto_family cmtp_sock_family_ops = {
231 	.family	= PF_BLUETOOTH,
232 	.owner	= THIS_MODULE,
233 	.create	= cmtp_sock_create
234 };
235 
cmtp_init_sockets(void)236 int cmtp_init_sockets(void)
237 {
238 	int err;
239 
240 	err = proto_register(&cmtp_proto, 0);
241 	if (err < 0)
242 		return err;
243 
244 	err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
245 	if (err < 0) {
246 		BT_ERR("Can't register CMTP socket");
247 		goto error;
248 	}
249 
250 	err = bt_procfs_init(&init_net, "cmtp", &cmtp_sk_list, NULL);
251 	if (err < 0) {
252 		BT_ERR("Failed to create CMTP proc file");
253 		bt_sock_unregister(BTPROTO_HIDP);
254 		goto error;
255 	}
256 
257 	BT_INFO("CMTP socket layer initialized");
258 
259 	return 0;
260 
261 error:
262 	proto_unregister(&cmtp_proto);
263 	return err;
264 }
265 
cmtp_cleanup_sockets(void)266 void cmtp_cleanup_sockets(void)
267 {
268 	bt_procfs_cleanup(&init_net, "cmtp");
269 	bt_sock_unregister(BTPROTO_CMTP);
270 	proto_unregister(&cmtp_proto);
271 }
272