xref: /openbmc/linux/net/bluetooth/bnep/sock.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds    BNEP implementation for Linux Bluetooth stack (BlueZ).
31da177e4SLinus Torvalds    Copyright (C) 2001-2002 Inventel Systemes
41da177e4SLinus Torvalds    Written 2001-2002 by
51da177e4SLinus Torvalds 	David Libault  <david.libault@inventel.fr>
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds    Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds    This program is free software; you can redistribute it and/or modify
101da177e4SLinus Torvalds    it under the terms of the GNU General Public License version 2 as
111da177e4SLinus Torvalds    published by the Free Software Foundation;
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
141da177e4SLinus Torvalds    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
151da177e4SLinus Torvalds    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
161da177e4SLinus Torvalds    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
171da177e4SLinus Torvalds    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
181da177e4SLinus Torvalds    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
191da177e4SLinus Torvalds    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
201da177e4SLinus Torvalds    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
231da177e4SLinus Torvalds    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
241da177e4SLinus Torvalds    SOFTWARE IS DISCLAIMED.
251da177e4SLinus Torvalds */
261da177e4SLinus Torvalds 
27b6459415SJakub Kicinski #include <linux/compat.h>
288c520a59SGustavo Padovan #include <linux/export.h>
291da177e4SLinus Torvalds #include <linux/file.h>
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds #include "bnep.h"
321da177e4SLinus Torvalds 
3377cf5585SMasatake YAMATO static struct bt_sock_list bnep_sk_list = {
3477cf5585SMasatake YAMATO 	.lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
3577cf5585SMasatake YAMATO };
3677cf5585SMasatake YAMATO 
bnep_sock_release(struct socket * sock)371da177e4SLinus Torvalds static int bnep_sock_release(struct socket *sock)
381da177e4SLinus Torvalds {
391da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds 	BT_DBG("sock %p sk %p", sock, sk);
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 	if (!sk)
441da177e4SLinus Torvalds 		return 0;
451da177e4SLinus Torvalds 
4677cf5585SMasatake YAMATO 	bt_sock_unlink(&bnep_sk_list, sk);
4777cf5585SMasatake YAMATO 
481da177e4SLinus Torvalds 	sock_orphan(sk);
491da177e4SLinus Torvalds 	sock_put(sk);
501da177e4SLinus Torvalds 	return 0;
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds 
do_bnep_sock_ioctl(struct socket * sock,unsigned int cmd,void __user * argp)53cc04f6e2SAl Viro static int do_bnep_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
541da177e4SLinus Torvalds {
551da177e4SLinus Torvalds 	struct bnep_connlist_req cl;
561da177e4SLinus Torvalds 	struct bnep_connadd_req  ca;
571da177e4SLinus Torvalds 	struct bnep_conndel_req  cd;
581da177e4SLinus Torvalds 	struct bnep_conninfo ci;
591da177e4SLinus Torvalds 	struct socket *nsock;
60836a061bSGrzegorz Kolodziejczyk 	__u32 supp_feat = BIT(BNEP_SETUP_RESPONSE);
611da177e4SLinus Torvalds 	int err;
621da177e4SLinus Torvalds 
63cc04f6e2SAl Viro 	BT_DBG("cmd %x arg %p", cmd, argp);
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds 	switch (cmd) {
661da177e4SLinus Torvalds 	case BNEPCONNADD:
671da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
68bf5b30b8SZhao Hongjiang 			return -EPERM;
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 		if (copy_from_user(&ca, argp, sizeof(ca)))
711da177e4SLinus Torvalds 			return -EFAULT;
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 		nsock = sockfd_lookup(ca.sock, &err);
741da177e4SLinus Torvalds 		if (!nsock)
751da177e4SLinus Torvalds 			return err;
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 		if (nsock->sk->sk_state != BT_CONNECTED) {
7867b23219SJulia Lawall 			sockfd_put(nsock);
791da177e4SLinus Torvalds 			return -EBADFD;
801da177e4SLinus Torvalds 		}
8143629f8fSVasiliy Kulikov 		ca.device[sizeof(ca.device)-1] = 0;
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds 		err = bnep_add_connection(&ca, nsock);
841da177e4SLinus Torvalds 		if (!err) {
851da177e4SLinus Torvalds 			if (copy_to_user(argp, &ca, sizeof(ca)))
861da177e4SLinus Torvalds 				err = -EFAULT;
871da177e4SLinus Torvalds 		} else
8867b23219SJulia Lawall 			sockfd_put(nsock);
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds 		return err;
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds 	case BNEPCONNDEL:
931da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
94bf5b30b8SZhao Hongjiang 			return -EPERM;
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 		if (copy_from_user(&cd, argp, sizeof(cd)))
971da177e4SLinus Torvalds 			return -EFAULT;
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 		return bnep_del_connection(&cd);
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 	case BNEPGETCONNLIST:
1021da177e4SLinus Torvalds 		if (copy_from_user(&cl, argp, sizeof(cl)))
1031da177e4SLinus Torvalds 			return -EFAULT;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 		if (cl.cnum <= 0)
1061da177e4SLinus Torvalds 			return -EINVAL;
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds 		err = bnep_get_connlist(&cl);
1091da177e4SLinus Torvalds 		if (!err && copy_to_user(argp, &cl, sizeof(cl)))
1101da177e4SLinus Torvalds 			return -EFAULT;
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds 		return err;
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	case BNEPGETCONNINFO:
1151da177e4SLinus Torvalds 		if (copy_from_user(&ci, argp, sizeof(ci)))
1161da177e4SLinus Torvalds 			return -EFAULT;
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds 		err = bnep_get_conninfo(&ci);
1191da177e4SLinus Torvalds 		if (!err && copy_to_user(argp, &ci, sizeof(ci)))
1201da177e4SLinus Torvalds 			return -EFAULT;
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds 		return err;
1231da177e4SLinus Torvalds 
1240477e2e8SGrzegorz Kolodziejczyk 	case BNEPGETSUPPFEAT:
1250477e2e8SGrzegorz Kolodziejczyk 		if (copy_to_user(argp, &supp_feat, sizeof(supp_feat)))
1260477e2e8SGrzegorz Kolodziejczyk 			return -EFAULT;
1270477e2e8SGrzegorz Kolodziejczyk 
1280477e2e8SGrzegorz Kolodziejczyk 		return 0;
1290477e2e8SGrzegorz Kolodziejczyk 
1301da177e4SLinus Torvalds 	default:
1311da177e4SLinus Torvalds 		return -EINVAL;
1321da177e4SLinus Torvalds 	}
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 	return 0;
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds 
bnep_sock_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)137cc04f6e2SAl Viro static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
138cc04f6e2SAl Viro {
139cc04f6e2SAl Viro 	return do_bnep_sock_ioctl(sock, cmd, (void __user *)arg);
140cc04f6e2SAl Viro }
141cc04f6e2SAl Viro 
142e9c5702eSMarcel Holtmann #ifdef CONFIG_COMPAT
bnep_sock_compat_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)143e9c5702eSMarcel Holtmann static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
144e9c5702eSMarcel Holtmann {
145cc04f6e2SAl Viro 	void __user *argp = compat_ptr(arg);
146e9c5702eSMarcel Holtmann 	if (cmd == BNEPGETCONNLIST) {
147e9c5702eSMarcel Holtmann 		struct bnep_connlist_req cl;
148cc04f6e2SAl Viro 		unsigned __user *p = argp;
149816a11d5SJohan Hedberg 		u32 uci;
150e9c5702eSMarcel Holtmann 		int err;
151e9c5702eSMarcel Holtmann 
152cc04f6e2SAl Viro 		if (get_user(cl.cnum, p) || get_user(uci, p + 1))
153e9c5702eSMarcel Holtmann 			return -EFAULT;
154e9c5702eSMarcel Holtmann 
155e9c5702eSMarcel Holtmann 		cl.ci = compat_ptr(uci);
156e9c5702eSMarcel Holtmann 
157e9c5702eSMarcel Holtmann 		if (cl.cnum <= 0)
158e9c5702eSMarcel Holtmann 			return -EINVAL;
159e9c5702eSMarcel Holtmann 
160e9c5702eSMarcel Holtmann 		err = bnep_get_connlist(&cl);
161e9c5702eSMarcel Holtmann 
162cc04f6e2SAl Viro 		if (!err && put_user(cl.cnum, p))
163e9c5702eSMarcel Holtmann 			err = -EFAULT;
164e9c5702eSMarcel Holtmann 
165e9c5702eSMarcel Holtmann 		return err;
166e9c5702eSMarcel Holtmann 	}
167e9c5702eSMarcel Holtmann 
168cc04f6e2SAl Viro 	return do_bnep_sock_ioctl(sock, cmd, argp);
169e9c5702eSMarcel Holtmann }
170e9c5702eSMarcel Holtmann #endif
171e9c5702eSMarcel Holtmann 
17290ddc4f0SEric Dumazet static const struct proto_ops bnep_sock_ops = {
1731da177e4SLinus Torvalds 	.family		= PF_BLUETOOTH,
1741da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
1751da177e4SLinus Torvalds 	.release	= bnep_sock_release,
1761da177e4SLinus Torvalds 	.ioctl		= bnep_sock_ioctl,
177e9c5702eSMarcel Holtmann #ifdef CONFIG_COMPAT
178e9c5702eSMarcel Holtmann 	.compat_ioctl	= bnep_sock_compat_ioctl,
179e9c5702eSMarcel Holtmann #endif
1801da177e4SLinus Torvalds 	.bind		= sock_no_bind,
1811da177e4SLinus Torvalds 	.getname	= sock_no_getname,
1821da177e4SLinus Torvalds 	.sendmsg	= sock_no_sendmsg,
1831da177e4SLinus Torvalds 	.recvmsg	= sock_no_recvmsg,
1841da177e4SLinus Torvalds 	.listen		= sock_no_listen,
1851da177e4SLinus Torvalds 	.shutdown	= sock_no_shutdown,
1861da177e4SLinus Torvalds 	.connect	= sock_no_connect,
1871da177e4SLinus Torvalds 	.socketpair	= sock_no_socketpair,
1881da177e4SLinus Torvalds 	.accept		= sock_no_accept,
1891da177e4SLinus Torvalds 	.mmap		= sock_no_mmap
1901da177e4SLinus Torvalds };
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds static struct proto bnep_proto = {
1931da177e4SLinus Torvalds 	.name		= "BNEP",
1941da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
1951da177e4SLinus Torvalds 	.obj_size	= sizeof(struct bt_sock)
1961da177e4SLinus Torvalds };
1971da177e4SLinus Torvalds 
bnep_sock_create(struct net * net,struct socket * sock,int protocol,int kern)1983f378b68SEric Paris static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
1993f378b68SEric Paris 			    int kern)
2001da177e4SLinus Torvalds {
2011da177e4SLinus Torvalds 	struct sock *sk;
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	BT_DBG("sock %p", sock);
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 	if (sock->type != SOCK_RAW)
2061da177e4SLinus Torvalds 		return -ESOCKTNOSUPPORT;
2071da177e4SLinus Torvalds 
208*6bfa273eSLuiz Augusto von Dentz 	sk = bt_sock_alloc(net, sock, &bnep_proto, protocol, GFP_ATOMIC, kern);
2091da177e4SLinus Torvalds 	if (!sk)
2101da177e4SLinus Torvalds 		return -ENOMEM;
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 	sock->ops = &bnep_sock_ops;
2131da177e4SLinus Torvalds 	sock->state = SS_UNCONNECTED;
2141da177e4SLinus Torvalds 
21577cf5585SMasatake YAMATO 	bt_sock_link(&bnep_sk_list, sk);
2161da177e4SLinus Torvalds 	return 0;
2171da177e4SLinus Torvalds }
2181da177e4SLinus Torvalds 
219ec1b4cf7SStephen Hemminger static const struct net_proto_family bnep_sock_family_ops = {
2201da177e4SLinus Torvalds 	.family = PF_BLUETOOTH,
2211da177e4SLinus Torvalds 	.owner	= THIS_MODULE,
2221da177e4SLinus Torvalds 	.create = bnep_sock_create
2231da177e4SLinus Torvalds };
2241da177e4SLinus Torvalds 
bnep_sock_init(void)2251da177e4SLinus Torvalds int __init bnep_sock_init(void)
2261da177e4SLinus Torvalds {
2271da177e4SLinus Torvalds 	int err;
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 	err = proto_register(&bnep_proto, 0);
2301da177e4SLinus Torvalds 	if (err < 0)
2311da177e4SLinus Torvalds 		return err;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
23477cf5585SMasatake YAMATO 	if (err < 0) {
23577cf5585SMasatake YAMATO 		BT_ERR("Can't register BNEP socket");
2361da177e4SLinus Torvalds 		goto error;
23777cf5585SMasatake YAMATO 	}
23877cf5585SMasatake YAMATO 
239b0316615SAl Viro 	err = bt_procfs_init(&init_net, "bnep", &bnep_sk_list, NULL);
24077cf5585SMasatake YAMATO 	if (err < 0) {
24177cf5585SMasatake YAMATO 		BT_ERR("Failed to create BNEP proc file");
24277cf5585SMasatake YAMATO 		bt_sock_unregister(BTPROTO_BNEP);
24377cf5585SMasatake YAMATO 		goto error;
24477cf5585SMasatake YAMATO 	}
24577cf5585SMasatake YAMATO 
24677cf5585SMasatake YAMATO 	BT_INFO("BNEP socket layer initialized");
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds 	return 0;
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds error:
2511da177e4SLinus Torvalds 	proto_unregister(&bnep_proto);
2521da177e4SLinus Torvalds 	return err;
2531da177e4SLinus Torvalds }
2541da177e4SLinus Torvalds 
bnep_sock_cleanup(void)255a4e2acf0STobias Klauser void __exit bnep_sock_cleanup(void)
2561da177e4SLinus Torvalds {
25777cf5585SMasatake YAMATO 	bt_procfs_cleanup(&init_net, "bnep");
2585e9d7f86SDavid Herrmann 	bt_sock_unregister(BTPROTO_BNEP);
2591da177e4SLinus Torvalds 	proto_unregister(&bnep_proto);
2601da177e4SLinus Torvalds }
261