linux/net/bluetooth/bnep/sock.c
<<
>>
Prefs
   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
  32static struct bt_sock_list bnep_sk_list = {
  33        .lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
  34};
  35
  36static 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
  52static int do_bnep_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
  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        __u32 supp_feat = BIT(BNEP_SETUP_RESPONSE);
  60        int err;
  61
  62        BT_DBG("cmd %x arg %p", cmd, argp);
  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        case BNEPGETSUPPFEAT:
 124                if (copy_to_user(argp, &supp_feat, sizeof(supp_feat)))
 125                        return -EFAULT;
 126
 127                return 0;
 128
 129        default:
 130                return -EINVAL;
 131        }
 132
 133        return 0;
 134}
 135
 136static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 137{
 138        return do_bnep_sock_ioctl(sock, cmd, (void __user *)arg);
 139}
 140
 141#ifdef CONFIG_COMPAT
 142static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 143{
 144        void __user *argp = compat_ptr(arg);
 145        if (cmd == BNEPGETCONNLIST) {
 146                struct bnep_connlist_req cl;
 147                unsigned __user *p = argp;
 148                u32 uci;
 149                int err;
 150
 151                if (get_user(cl.cnum, p) || get_user(uci, p + 1))
 152                        return -EFAULT;
 153
 154                cl.ci = compat_ptr(uci);
 155
 156                if (cl.cnum <= 0)
 157                        return -EINVAL;
 158
 159                err = bnep_get_connlist(&cl);
 160
 161                if (!err && put_user(cl.cnum, p))
 162                        err = -EFAULT;
 163
 164                return err;
 165        }
 166
 167        return do_bnep_sock_ioctl(sock, cmd, argp);
 168}
 169#endif
 170
 171static const struct proto_ops bnep_sock_ops = {
 172        .family         = PF_BLUETOOTH,
 173        .owner          = THIS_MODULE,
 174        .release        = bnep_sock_release,
 175        .ioctl          = bnep_sock_ioctl,
 176#ifdef CONFIG_COMPAT
 177        .compat_ioctl   = bnep_sock_compat_ioctl,
 178#endif
 179        .bind           = sock_no_bind,
 180        .getname        = sock_no_getname,
 181        .sendmsg        = sock_no_sendmsg,
 182        .recvmsg        = sock_no_recvmsg,
 183        .listen         = sock_no_listen,
 184        .shutdown       = sock_no_shutdown,
 185        .connect        = sock_no_connect,
 186        .socketpair     = sock_no_socketpair,
 187        .accept         = sock_no_accept,
 188        .mmap           = sock_no_mmap
 189};
 190
 191static struct proto bnep_proto = {
 192        .name           = "BNEP",
 193        .owner          = THIS_MODULE,
 194        .obj_size       = sizeof(struct bt_sock)
 195};
 196
 197static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
 198                            int kern)
 199{
 200        struct sock *sk;
 201
 202        BT_DBG("sock %p", sock);
 203
 204        if (sock->type != SOCK_RAW)
 205                return -ESOCKTNOSUPPORT;
 206
 207        sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, kern);
 208        if (!sk)
 209                return -ENOMEM;
 210
 211        sock_init_data(sock, sk);
 212
 213        sock->ops = &bnep_sock_ops;
 214
 215        sock->state = SS_UNCONNECTED;
 216
 217        sock_reset_flag(sk, SOCK_ZAPPED);
 218
 219        sk->sk_protocol = protocol;
 220        sk->sk_state    = BT_OPEN;
 221
 222        bt_sock_link(&bnep_sk_list, sk);
 223        return 0;
 224}
 225
 226static const struct net_proto_family bnep_sock_family_ops = {
 227        .family = PF_BLUETOOTH,
 228        .owner  = THIS_MODULE,
 229        .create = bnep_sock_create
 230};
 231
 232int __init bnep_sock_init(void)
 233{
 234        int err;
 235
 236        err = proto_register(&bnep_proto, 0);
 237        if (err < 0)
 238                return err;
 239
 240        err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
 241        if (err < 0) {
 242                BT_ERR("Can't register BNEP socket");
 243                goto error;
 244        }
 245
 246        err = bt_procfs_init(&init_net, "bnep", &bnep_sk_list, NULL);
 247        if (err < 0) {
 248                BT_ERR("Failed to create BNEP proc file");
 249                bt_sock_unregister(BTPROTO_BNEP);
 250                goto error;
 251        }
 252
 253        BT_INFO("BNEP socket layer initialized");
 254
 255        return 0;
 256
 257error:
 258        proto_unregister(&bnep_proto);
 259        return err;
 260}
 261
 262void __exit bnep_sock_cleanup(void)
 263{
 264        bt_procfs_cleanup(&init_net, "bnep");
 265        bt_sock_unregister(BTPROTO_BNEP);
 266        proto_unregister(&bnep_proto);
 267}
 268