xref: /linux/net/bluetooth/bnep/sock.c (revision 60e13231561b3a4c5269bfa1ef6c0569ad6f28ec)
1 /*
2    BNEP implementation for Linux Bluetooth stack (BlueZ).
3    Copyright (C) 2001-2002 Inventel Systemes
4    Written 2001-2002 by
5 	David Libault  <david.libault@inventel.fr>
6 
7    Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License version 2 as
11    published by the Free Software Foundation;
12 
13    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
17    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 
22    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
24    SOFTWARE IS DISCLAIMED.
25 */
26 
27 #include <linux/module.h>
28 
29 #include <linux/types.h>
30 #include <linux/capability.h>
31 #include <linux/errno.h>
32 #include <linux/kernel.h>
33 #include <linux/poll.h>
34 #include <linux/fcntl.h>
35 #include <linux/skbuff.h>
36 #include <linux/socket.h>
37 #include <linux/ioctl.h>
38 #include <linux/file.h>
39 #include <linux/init.h>
40 #include <linux/compat.h>
41 #include <linux/gfp.h>
42 #include <linux/uaccess.h>
43 #include <net/sock.h>
44 
45 #include <asm/system.h>
46 
47 #include "bnep.h"
48 
49 static int bnep_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 	sock_orphan(sk);
59 	sock_put(sk);
60 	return 0;
61 }
62 
63 static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
64 {
65 	struct bnep_connlist_req cl;
66 	struct bnep_connadd_req  ca;
67 	struct bnep_conndel_req  cd;
68 	struct bnep_conninfo ci;
69 	struct socket *nsock;
70 	void __user *argp = (void __user *)arg;
71 	int err;
72 
73 	BT_DBG("cmd %x arg %lx", cmd, arg);
74 
75 	switch (cmd) {
76 	case BNEPCONNADD:
77 		if (!capable(CAP_NET_ADMIN))
78 			return -EACCES;
79 
80 		if (copy_from_user(&ca, argp, sizeof(ca)))
81 			return -EFAULT;
82 
83 		nsock = sockfd_lookup(ca.sock, &err);
84 		if (!nsock)
85 			return err;
86 
87 		if (nsock->sk->sk_state != BT_CONNECTED) {
88 			sockfd_put(nsock);
89 			return -EBADFD;
90 		}
91 		ca.device[sizeof(ca.device)-1] = 0;
92 
93 		err = bnep_add_connection(&ca, nsock);
94 		if (!err) {
95 			if (copy_to_user(argp, &ca, sizeof(ca)))
96 				err = -EFAULT;
97 		} else
98 			sockfd_put(nsock);
99 
100 		return err;
101 
102 	case BNEPCONNDEL:
103 		if (!capable(CAP_NET_ADMIN))
104 			return -EACCES;
105 
106 		if (copy_from_user(&cd, argp, sizeof(cd)))
107 			return -EFAULT;
108 
109 		return bnep_del_connection(&cd);
110 
111 	case BNEPGETCONNLIST:
112 		if (copy_from_user(&cl, argp, sizeof(cl)))
113 			return -EFAULT;
114 
115 		if (cl.cnum <= 0)
116 			return -EINVAL;
117 
118 		err = bnep_get_connlist(&cl);
119 		if (!err && copy_to_user(argp, &cl, sizeof(cl)))
120 			return -EFAULT;
121 
122 		return err;
123 
124 	case BNEPGETCONNINFO:
125 		if (copy_from_user(&ci, argp, sizeof(ci)))
126 			return -EFAULT;
127 
128 		err = bnep_get_conninfo(&ci);
129 		if (!err && copy_to_user(argp, &ci, sizeof(ci)))
130 			return -EFAULT;
131 
132 		return err;
133 
134 	default:
135 		return -EINVAL;
136 	}
137 
138 	return 0;
139 }
140 
141 #ifdef CONFIG_COMPAT
142 static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
143 {
144 	if (cmd == BNEPGETCONNLIST) {
145 		struct bnep_connlist_req cl;
146 		uint32_t uci;
147 		int err;
148 
149 		if (get_user(cl.cnum, (uint32_t __user *) arg) ||
150 				get_user(uci, (u32 __user *) (arg + 4)))
151 			return -EFAULT;
152 
153 		cl.ci = compat_ptr(uci);
154 
155 		if (cl.cnum <= 0)
156 			return -EINVAL;
157 
158 		err = bnep_get_connlist(&cl);
159 
160 		if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
161 			err = -EFAULT;
162 
163 		return err;
164 	}
165 
166 	return bnep_sock_ioctl(sock, cmd, arg);
167 }
168 #endif
169 
170 static const struct proto_ops bnep_sock_ops = {
171 	.family		= PF_BLUETOOTH,
172 	.owner		= THIS_MODULE,
173 	.release	= bnep_sock_release,
174 	.ioctl		= bnep_sock_ioctl,
175 #ifdef CONFIG_COMPAT
176 	.compat_ioctl	= bnep_sock_compat_ioctl,
177 #endif
178 	.bind		= sock_no_bind,
179 	.getname	= sock_no_getname,
180 	.sendmsg	= sock_no_sendmsg,
181 	.recvmsg	= sock_no_recvmsg,
182 	.poll		= sock_no_poll,
183 	.listen		= sock_no_listen,
184 	.shutdown	= sock_no_shutdown,
185 	.setsockopt	= sock_no_setsockopt,
186 	.getsockopt	= sock_no_getsockopt,
187 	.connect	= sock_no_connect,
188 	.socketpair	= sock_no_socketpair,
189 	.accept		= sock_no_accept,
190 	.mmap		= sock_no_mmap
191 };
192 
193 static struct proto bnep_proto = {
194 	.name		= "BNEP",
195 	.owner		= THIS_MODULE,
196 	.obj_size	= sizeof(struct bt_sock)
197 };
198 
199 static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
200 			    int kern)
201 {
202 	struct sock *sk;
203 
204 	BT_DBG("sock %p", sock);
205 
206 	if (sock->type != SOCK_RAW)
207 		return -ESOCKTNOSUPPORT;
208 
209 	sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto);
210 	if (!sk)
211 		return -ENOMEM;
212 
213 	sock_init_data(sock, sk);
214 
215 	sock->ops = &bnep_sock_ops;
216 
217 	sock->state = SS_UNCONNECTED;
218 
219 	sock_reset_flag(sk, SOCK_ZAPPED);
220 
221 	sk->sk_protocol = protocol;
222 	sk->sk_state	= BT_OPEN;
223 
224 	return 0;
225 }
226 
227 static const struct net_proto_family bnep_sock_family_ops = {
228 	.family = PF_BLUETOOTH,
229 	.owner	= THIS_MODULE,
230 	.create = bnep_sock_create
231 };
232 
233 int __init bnep_sock_init(void)
234 {
235 	int err;
236 
237 	err = proto_register(&bnep_proto, 0);
238 	if (err < 0)
239 		return err;
240 
241 	err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
242 	if (err < 0)
243 		goto error;
244 
245 	return 0;
246 
247 error:
248 	BT_ERR("Can't register BNEP socket");
249 	proto_unregister(&bnep_proto);
250 	return err;
251 }
252 
253 void __exit bnep_sock_cleanup(void)
254 {
255 	if (bt_sock_unregister(BTPROTO_BNEP) < 0)
256 		BT_ERR("Can't unregister BNEP socket");
257 
258 	proto_unregister(&bnep_proto);
259 }
260