xref: /openbmc/linux/net/bluetooth/bnep/sock.c (revision 93d90ad7)
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/export.h>
28 #include <linux/file.h>
29 
30 #include "bnep.h"
31 
32 static struct bt_sock_list bnep_sk_list = {
33 	.lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
34 };
35 
36 static int bnep_sock_release(struct socket *sock)
37 {
38 	struct sock *sk = sock->sk;
39 
40 	BT_DBG("sock %p sk %p", sock, sk);
41 
42 	if (!sk)
43 		return 0;
44 
45 	bt_sock_unlink(&bnep_sk_list, sk);
46 
47 	sock_orphan(sk);
48 	sock_put(sk);
49 	return 0;
50 }
51 
52 static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
53 {
54 	struct bnep_connlist_req cl;
55 	struct bnep_connadd_req  ca;
56 	struct bnep_conndel_req  cd;
57 	struct bnep_conninfo ci;
58 	struct socket *nsock;
59 	void __user *argp = (void __user *)arg;
60 	int err;
61 
62 	BT_DBG("cmd %x arg %lx", cmd, arg);
63 
64 	switch (cmd) {
65 	case BNEPCONNADD:
66 		if (!capable(CAP_NET_ADMIN))
67 			return -EPERM;
68 
69 		if (copy_from_user(&ca, argp, sizeof(ca)))
70 			return -EFAULT;
71 
72 		nsock = sockfd_lookup(ca.sock, &err);
73 		if (!nsock)
74 			return err;
75 
76 		if (nsock->sk->sk_state != BT_CONNECTED) {
77 			sockfd_put(nsock);
78 			return -EBADFD;
79 		}
80 		ca.device[sizeof(ca.device)-1] = 0;
81 
82 		err = bnep_add_connection(&ca, nsock);
83 		if (!err) {
84 			if (copy_to_user(argp, &ca, sizeof(ca)))
85 				err = -EFAULT;
86 		} else
87 			sockfd_put(nsock);
88 
89 		return err;
90 
91 	case BNEPCONNDEL:
92 		if (!capable(CAP_NET_ADMIN))
93 			return -EPERM;
94 
95 		if (copy_from_user(&cd, argp, sizeof(cd)))
96 			return -EFAULT;
97 
98 		return bnep_del_connection(&cd);
99 
100 	case BNEPGETCONNLIST:
101 		if (copy_from_user(&cl, argp, sizeof(cl)))
102 			return -EFAULT;
103 
104 		if (cl.cnum <= 0)
105 			return -EINVAL;
106 
107 		err = bnep_get_connlist(&cl);
108 		if (!err && copy_to_user(argp, &cl, sizeof(cl)))
109 			return -EFAULT;
110 
111 		return err;
112 
113 	case BNEPGETCONNINFO:
114 		if (copy_from_user(&ci, argp, sizeof(ci)))
115 			return -EFAULT;
116 
117 		err = bnep_get_conninfo(&ci);
118 		if (!err && copy_to_user(argp, &ci, sizeof(ci)))
119 			return -EFAULT;
120 
121 		return err;
122 
123 	default:
124 		return -EINVAL;
125 	}
126 
127 	return 0;
128 }
129 
130 #ifdef CONFIG_COMPAT
131 static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
132 {
133 	if (cmd == BNEPGETCONNLIST) {
134 		struct bnep_connlist_req cl;
135 		u32 uci;
136 		int err;
137 
138 		if (get_user(cl.cnum, (u32 __user *) arg) ||
139 				get_user(uci, (u32 __user *) (arg + 4)))
140 			return -EFAULT;
141 
142 		cl.ci = compat_ptr(uci);
143 
144 		if (cl.cnum <= 0)
145 			return -EINVAL;
146 
147 		err = bnep_get_connlist(&cl);
148 
149 		if (!err && put_user(cl.cnum, (u32 __user *) arg))
150 			err = -EFAULT;
151 
152 		return err;
153 	}
154 
155 	return bnep_sock_ioctl(sock, cmd, arg);
156 }
157 #endif
158 
159 static const struct proto_ops bnep_sock_ops = {
160 	.family		= PF_BLUETOOTH,
161 	.owner		= THIS_MODULE,
162 	.release	= bnep_sock_release,
163 	.ioctl		= bnep_sock_ioctl,
164 #ifdef CONFIG_COMPAT
165 	.compat_ioctl	= bnep_sock_compat_ioctl,
166 #endif
167 	.bind		= sock_no_bind,
168 	.getname	= sock_no_getname,
169 	.sendmsg	= sock_no_sendmsg,
170 	.recvmsg	= sock_no_recvmsg,
171 	.poll		= sock_no_poll,
172 	.listen		= sock_no_listen,
173 	.shutdown	= sock_no_shutdown,
174 	.setsockopt	= sock_no_setsockopt,
175 	.getsockopt	= sock_no_getsockopt,
176 	.connect	= sock_no_connect,
177 	.socketpair	= sock_no_socketpair,
178 	.accept		= sock_no_accept,
179 	.mmap		= sock_no_mmap
180 };
181 
182 static struct proto bnep_proto = {
183 	.name		= "BNEP",
184 	.owner		= THIS_MODULE,
185 	.obj_size	= sizeof(struct bt_sock)
186 };
187 
188 static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
189 			    int kern)
190 {
191 	struct sock *sk;
192 
193 	BT_DBG("sock %p", sock);
194 
195 	if (sock->type != SOCK_RAW)
196 		return -ESOCKTNOSUPPORT;
197 
198 	sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto);
199 	if (!sk)
200 		return -ENOMEM;
201 
202 	sock_init_data(sock, sk);
203 
204 	sock->ops = &bnep_sock_ops;
205 
206 	sock->state = SS_UNCONNECTED;
207 
208 	sock_reset_flag(sk, SOCK_ZAPPED);
209 
210 	sk->sk_protocol = protocol;
211 	sk->sk_state	= BT_OPEN;
212 
213 	bt_sock_link(&bnep_sk_list, sk);
214 	return 0;
215 }
216 
217 static const struct net_proto_family bnep_sock_family_ops = {
218 	.family = PF_BLUETOOTH,
219 	.owner	= THIS_MODULE,
220 	.create = bnep_sock_create
221 };
222 
223 int __init bnep_sock_init(void)
224 {
225 	int err;
226 
227 	err = proto_register(&bnep_proto, 0);
228 	if (err < 0)
229 		return err;
230 
231 	err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
232 	if (err < 0) {
233 		BT_ERR("Can't register BNEP socket");
234 		goto error;
235 	}
236 
237 	err = bt_procfs_init(&init_net, "bnep", &bnep_sk_list, NULL);
238 	if (err < 0) {
239 		BT_ERR("Failed to create BNEP proc file");
240 		bt_sock_unregister(BTPROTO_BNEP);
241 		goto error;
242 	}
243 
244 	BT_INFO("BNEP socket layer initialized");
245 
246 	return 0;
247 
248 error:
249 	proto_unregister(&bnep_proto);
250 	return err;
251 }
252 
253 void __exit bnep_sock_cleanup(void)
254 {
255 	bt_procfs_cleanup(&init_net, "bnep");
256 	bt_sock_unregister(BTPROTO_BNEP);
257 	proto_unregister(&bnep_proto);
258 }
259