linux/net/bluetooth/hidp/sock.c
<<
>>
Prefs
   1/*
   2   HIDP implementation for Linux Bluetooth stack (BlueZ).
   3   Copyright (C) 2003-2004 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/module.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/slab.h>
  30#include <linux/poll.h>
  31#include <linux/fcntl.h>
  32#include <linux/skbuff.h>
  33#include <linux/socket.h>
  34#include <linux/ioctl.h>
  35#include <linux/file.h>
  36#include <linux/init.h>
  37#include <linux/compat.h>
  38#include <net/sock.h>
  39
  40#include "hidp.h"
  41
  42static int hidp_sock_release(struct socket *sock)
  43{
  44        struct sock *sk = sock->sk;
  45
  46        BT_DBG("sock %p sk %p", sock, sk);
  47
  48        if (!sk)
  49                return 0;
  50
  51        sock_orphan(sk);
  52        sock_put(sk);
  53
  54        return 0;
  55}
  56
  57static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
  58{
  59        void __user *argp = (void __user *) arg;
  60        struct hidp_connadd_req ca;
  61        struct hidp_conndel_req cd;
  62        struct hidp_connlist_req cl;
  63        struct hidp_conninfo ci;
  64        struct socket *csock;
  65        struct socket *isock;
  66        int err;
  67
  68        BT_DBG("cmd %x arg %lx", cmd, arg);
  69
  70        switch (cmd) {
  71        case HIDPCONNADD:
  72                if (!capable(CAP_NET_ADMIN))
  73                        return -EACCES;
  74
  75                if (copy_from_user(&ca, argp, sizeof(ca)))
  76                        return -EFAULT;
  77
  78                csock = sockfd_lookup(ca.ctrl_sock, &err);
  79                if (!csock)
  80                        return err;
  81
  82                isock = sockfd_lookup(ca.intr_sock, &err);
  83                if (!isock) {
  84                        sockfd_put(csock);
  85                        return err;
  86                }
  87
  88                if (csock->sk->sk_state != BT_CONNECTED || isock->sk->sk_state != BT_CONNECTED) {
  89                        sockfd_put(csock);
  90                        sockfd_put(isock);
  91                        return -EBADFD;
  92                }
  93
  94                err = hidp_add_connection(&ca, csock, isock);
  95                if (!err) {
  96                        if (copy_to_user(argp, &ca, sizeof(ca)))
  97                                err = -EFAULT;
  98                } else {
  99                        sockfd_put(csock);
 100                        sockfd_put(isock);
 101                }
 102
 103                return err;
 104
 105        case HIDPCONNDEL:
 106                if (!capable(CAP_NET_ADMIN))
 107                        return -EACCES;
 108
 109                if (copy_from_user(&cd, argp, sizeof(cd)))
 110                        return -EFAULT;
 111
 112                return hidp_del_connection(&cd);
 113
 114        case HIDPGETCONNLIST:
 115                if (copy_from_user(&cl, argp, sizeof(cl)))
 116                        return -EFAULT;
 117
 118                if (cl.cnum <= 0)
 119                        return -EINVAL;
 120
 121                err = hidp_get_connlist(&cl);
 122                if (!err && copy_to_user(argp, &cl, sizeof(cl)))
 123                        return -EFAULT;
 124
 125                return err;
 126
 127        case HIDPGETCONNINFO:
 128                if (copy_from_user(&ci, argp, sizeof(ci)))
 129                        return -EFAULT;
 130
 131                err = hidp_get_conninfo(&ci);
 132                if (!err && copy_to_user(argp, &ci, sizeof(ci)))
 133                        return -EFAULT;
 134
 135                return err;
 136        }
 137
 138        return -EINVAL;
 139}
 140
 141#ifdef CONFIG_COMPAT
 142struct compat_hidp_connadd_req {
 143        int   ctrl_sock;        // Connected control socket
 144        int   intr_sock;        // Connteted interrupt socket
 145        __u16 parser;
 146        __u16 rd_size;
 147        compat_uptr_t rd_data;
 148        __u8  country;
 149        __u8  subclass;
 150        __u16 vendor;
 151        __u16 product;
 152        __u16 version;
 153        __u32 flags;
 154        __u32 idle_to;
 155        char  name[128];
 156};
 157
 158static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 159{
 160        if (cmd == HIDPGETCONNLIST) {
 161                struct hidp_connlist_req cl;
 162                uint32_t uci;
 163                int err;
 164
 165                if (get_user(cl.cnum, (uint32_t __user *) arg) ||
 166                                get_user(uci, (u32 __user *) (arg + 4)))
 167                        return -EFAULT;
 168
 169                cl.ci = compat_ptr(uci);
 170
 171                if (cl.cnum <= 0)
 172                        return -EINVAL;
 173
 174                err = hidp_get_connlist(&cl);
 175
 176                if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
 177                        err = -EFAULT;
 178
 179                return err;
 180        } else if (cmd == HIDPCONNADD) {
 181                struct compat_hidp_connadd_req ca;
 182                struct hidp_connadd_req __user *uca;
 183
 184                uca = compat_alloc_user_space(sizeof(*uca));
 185
 186                if (copy_from_user(&ca, (void __user *) arg, sizeof(ca)))
 187                        return -EFAULT;
 188
 189                if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
 190                                put_user(ca.intr_sock, &uca->intr_sock) ||
 191                                put_user(ca.parser, &uca->parser) ||
 192                                put_user(ca.rd_size, &uca->rd_size) ||
 193                                put_user(compat_ptr(ca.rd_data), &uca->rd_data) ||
 194                                put_user(ca.country, &uca->country) ||
 195                                put_user(ca.subclass, &uca->subclass) ||
 196                                put_user(ca.vendor, &uca->vendor) ||
 197                                put_user(ca.product, &uca->product) ||
 198                                put_user(ca.version, &uca->version) ||
 199                                put_user(ca.flags, &uca->flags) ||
 200                                put_user(ca.idle_to, &uca->idle_to) ||
 201                                copy_to_user(&uca->name[0], &ca.name[0], 128))
 202                        return -EFAULT;
 203
 204                arg = (unsigned long) uca;
 205
 206                /* Fall through. We don't actually write back any _changes_
 207                   to the structure anyway, so there's no need to copy back
 208                   into the original compat version */
 209        }
 210
 211        return hidp_sock_ioctl(sock, cmd, arg);
 212}
 213#endif
 214
 215static const struct proto_ops hidp_sock_ops = {
 216        .family         = PF_BLUETOOTH,
 217        .owner          = THIS_MODULE,
 218        .release        = hidp_sock_release,
 219        .ioctl          = hidp_sock_ioctl,
 220#ifdef CONFIG_COMPAT
 221        .compat_ioctl   = hidp_sock_compat_ioctl,
 222#endif
 223        .bind           = sock_no_bind,
 224        .getname        = sock_no_getname,
 225        .sendmsg        = sock_no_sendmsg,
 226        .recvmsg        = sock_no_recvmsg,
 227        .poll           = sock_no_poll,
 228        .listen         = sock_no_listen,
 229        .shutdown       = sock_no_shutdown,
 230        .setsockopt     = sock_no_setsockopt,
 231        .getsockopt     = sock_no_getsockopt,
 232        .connect        = sock_no_connect,
 233        .socketpair     = sock_no_socketpair,
 234        .accept         = sock_no_accept,
 235        .mmap           = sock_no_mmap
 236};
 237
 238static struct proto hidp_proto = {
 239        .name           = "HIDP",
 240        .owner          = THIS_MODULE,
 241        .obj_size       = sizeof(struct bt_sock)
 242};
 243
 244static int hidp_sock_create(struct net *net, struct socket *sock, int protocol)
 245{
 246        struct sock *sk;
 247
 248        BT_DBG("sock %p", sock);
 249
 250        if (sock->type != SOCK_RAW)
 251                return -ESOCKTNOSUPPORT;
 252
 253        sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto);
 254        if (!sk)
 255                return -ENOMEM;
 256
 257        sock_init_data(sock, sk);
 258
 259        sock->ops = &hidp_sock_ops;
 260
 261        sock->state = SS_UNCONNECTED;
 262
 263        sock_reset_flag(sk, SOCK_ZAPPED);
 264
 265        sk->sk_protocol = protocol;
 266        sk->sk_state    = BT_OPEN;
 267
 268        return 0;
 269}
 270
 271static struct net_proto_family hidp_sock_family_ops = {
 272        .family = PF_BLUETOOTH,
 273        .owner  = THIS_MODULE,
 274        .create = hidp_sock_create
 275};
 276
 277int __init hidp_init_sockets(void)
 278{
 279        int err;
 280
 281        err = proto_register(&hidp_proto, 0);
 282        if (err < 0)
 283                return err;
 284
 285        err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
 286        if (err < 0)
 287                goto error;
 288
 289        return 0;
 290
 291error:
 292        BT_ERR("Can't register HIDP socket");
 293        proto_unregister(&hidp_proto);
 294        return err;
 295}
 296
 297void __exit hidp_cleanup_sockets(void)
 298{
 299        if (bt_sock_unregister(BTPROTO_HIDP) < 0)
 300                BT_ERR("Can't unregister HIDP socket");
 301
 302        proto_unregister(&hidp_proto);
 303}
 304