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