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