linux/net/atm/ioctl.c
<<
>>
Prefs
   1/* ATM ioctl handling */
   2
   3/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
   4/* 2003 John Levon  <levon@movementarian.org> */
   5
   6#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
   7
   8#include <linux/module.h>
   9#include <linux/kmod.h>
  10#include <linux/net.h>          /* struct socket, struct proto_ops */
  11#include <linux/atm.h>          /* ATM stuff */
  12#include <linux/atmdev.h>
  13#include <linux/atmclip.h>      /* CLIP_*ENCAP */
  14#include <linux/atmarp.h>       /* manifest constants */
  15#include <linux/capability.h>
  16#include <linux/sonet.h>        /* for ioctls */
  17#include <linux/atmsvc.h>
  18#include <linux/atmmpc.h>
  19#include <net/atmclip.h>
  20#include <linux/atmlec.h>
  21#include <linux/mutex.h>
  22#include <asm/ioctls.h>
  23#include <net/compat.h>
  24
  25#include "resources.h"
  26#include "signaling.h"          /* for WAITING and sigd_attach */
  27#include "common.h"
  28
  29
  30static DEFINE_MUTEX(ioctl_mutex);
  31static LIST_HEAD(ioctl_list);
  32
  33
  34void register_atm_ioctl(struct atm_ioctl *ioctl)
  35{
  36        mutex_lock(&ioctl_mutex);
  37        list_add_tail(&ioctl->list, &ioctl_list);
  38        mutex_unlock(&ioctl_mutex);
  39}
  40EXPORT_SYMBOL(register_atm_ioctl);
  41
  42void deregister_atm_ioctl(struct atm_ioctl *ioctl)
  43{
  44        mutex_lock(&ioctl_mutex);
  45        list_del(&ioctl->list);
  46        mutex_unlock(&ioctl_mutex);
  47}
  48EXPORT_SYMBOL(deregister_atm_ioctl);
  49
  50static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
  51                        unsigned long arg, int compat)
  52{
  53        struct sock *sk = sock->sk;
  54        struct atm_vcc *vcc;
  55        int error;
  56        struct list_head *pos;
  57        void __user *argp = (void __user *)arg;
  58
  59        vcc = ATM_SD(sock);
  60        switch (cmd) {
  61        case SIOCOUTQ:
  62                if (sock->state != SS_CONNECTED ||
  63                    !test_bit(ATM_VF_READY, &vcc->flags)) {
  64                        error =  -EINVAL;
  65                        goto done;
  66                }
  67                error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk),
  68                                 (int __user *)argp) ? -EFAULT : 0;
  69                goto done;
  70        case SIOCINQ:
  71        {
  72                struct sk_buff *skb;
  73
  74                if (sock->state != SS_CONNECTED) {
  75                        error = -EINVAL;
  76                        goto done;
  77                }
  78                skb = skb_peek(&sk->sk_receive_queue);
  79                error = put_user(skb ? skb->len : 0,
  80                                 (int __user *)argp) ? -EFAULT : 0;
  81                goto done;
  82        }
  83        case SIOCGSTAMP: /* borrowed from IP */
  84#ifdef CONFIG_COMPAT
  85                if (compat)
  86                        error = compat_sock_get_timestamp(sk, argp);
  87                else
  88#endif
  89                        error = sock_get_timestamp(sk, argp);
  90                goto done;
  91        case SIOCGSTAMPNS: /* borrowed from IP */
  92#ifdef CONFIG_COMPAT
  93                if (compat)
  94                        error = compat_sock_get_timestampns(sk, argp);
  95                else
  96#endif
  97                        error = sock_get_timestampns(sk, argp);
  98                goto done;
  99        case ATM_SETSC:
 100                if (net_ratelimit())
 101                        pr_warning("ATM_SETSC is obsolete; used by %s:%d\n",
 102                                   current->comm, task_pid_nr(current));
 103                error = 0;
 104                goto done;
 105        case ATMSIGD_CTRL:
 106                if (!capable(CAP_NET_ADMIN)) {
 107                        error = -EPERM;
 108                        goto done;
 109                }
 110                /*
 111                 * The user/kernel protocol for exchanging signalling
 112                 * info uses kernel pointers as opaque references,
 113                 * so the holder of the file descriptor can scribble
 114                 * on the kernel... so we should make sure that we
 115                 * have the same privileges that /proc/kcore needs
 116                 */
 117                if (!capable(CAP_SYS_RAWIO)) {
 118                        error = -EPERM;
 119                        goto done;
 120                }
 121#ifdef CONFIG_COMPAT
 122                /* WTF? I don't even want to _think_ about making this
 123                   work for 32-bit userspace. TBH I don't really want
 124                   to think about it at all. dwmw2. */
 125                if (compat) {
 126                        if (net_ratelimit())
 127                                pr_warning("32-bit task cannot be atmsigd\n");
 128                        error = -EINVAL;
 129                        goto done;
 130                }
 131#endif
 132                error = sigd_attach(vcc);
 133                if (!error)
 134                        sock->state = SS_CONNECTED;
 135                goto done;
 136        case ATM_SETBACKEND:
 137        case ATM_NEWBACKENDIF:
 138        {
 139                atm_backend_t backend;
 140                error = get_user(backend, (atm_backend_t __user *)argp);
 141                if (error)
 142                        goto done;
 143                switch (backend) {
 144                case ATM_BACKEND_PPP:
 145                        request_module("pppoatm");
 146                        break;
 147                case ATM_BACKEND_BR2684:
 148                        request_module("br2684");
 149                        break;
 150                }
 151                break;
 152        }
 153        case ATMMPC_CTRL:
 154        case ATMMPC_DATA:
 155                request_module("mpoa");
 156                break;
 157        case ATMARPD_CTRL:
 158                request_module("clip");
 159                break;
 160        case ATMLEC_CTRL:
 161                request_module("lec");
 162                break;
 163        }
 164
 165        error = -ENOIOCTLCMD;
 166
 167        mutex_lock(&ioctl_mutex);
 168        list_for_each(pos, &ioctl_list) {
 169                struct atm_ioctl *ic = list_entry(pos, struct atm_ioctl, list);
 170                if (try_module_get(ic->owner)) {
 171                        error = ic->ioctl(sock, cmd, arg);
 172                        module_put(ic->owner);
 173                        if (error != -ENOIOCTLCMD)
 174                                break;
 175                }
 176        }
 177        mutex_unlock(&ioctl_mutex);
 178
 179        if (error != -ENOIOCTLCMD)
 180                goto done;
 181
 182        error = atm_dev_ioctl(cmd, argp, compat);
 183
 184done:
 185        return error;
 186}
 187
 188int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 189{
 190        return do_vcc_ioctl(sock, cmd, arg, 0);
 191}
 192
 193#ifdef CONFIG_COMPAT
 194/*
 195 * FIXME:
 196 * The compat_ioctl handling is duplicated, using both these conversion
 197 * routines and the compat argument to the actual handlers. Both
 198 * versions are somewhat incomplete and should be merged, e.g. by
 199 * moving the ioctl number translation into the actual handlers and
 200 * killing the conversion code.
 201 *
 202 * -arnd, November 2009
 203 */
 204#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct compat_atmif_sioc)
 205#define ATM_GETNAMES32    _IOW('a', ATMIOC_ITF+3, struct compat_atm_iobuf)
 206#define ATM_GETTYPE32     _IOW('a', ATMIOC_ITF+4, struct compat_atmif_sioc)
 207#define ATM_GETESI32      _IOW('a', ATMIOC_ITF+5, struct compat_atmif_sioc)
 208#define ATM_GETADDR32     _IOW('a', ATMIOC_ITF+6, struct compat_atmif_sioc)
 209#define ATM_RSTADDR32     _IOW('a', ATMIOC_ITF+7, struct compat_atmif_sioc)
 210#define ATM_ADDADDR32     _IOW('a', ATMIOC_ITF+8, struct compat_atmif_sioc)
 211#define ATM_DELADDR32     _IOW('a', ATMIOC_ITF+9, struct compat_atmif_sioc)
 212#define ATM_GETCIRANGE32  _IOW('a', ATMIOC_ITF+10, struct compat_atmif_sioc)
 213#define ATM_SETCIRANGE32  _IOW('a', ATMIOC_ITF+11, struct compat_atmif_sioc)
 214#define ATM_SETESI32      _IOW('a', ATMIOC_ITF+12, struct compat_atmif_sioc)
 215#define ATM_SETESIF32     _IOW('a', ATMIOC_ITF+13, struct compat_atmif_sioc)
 216#define ATM_GETSTAT32     _IOW('a', ATMIOC_SARCOM+0, struct compat_atmif_sioc)
 217#define ATM_GETSTATZ32    _IOW('a', ATMIOC_SARCOM+1, struct compat_atmif_sioc)
 218#define ATM_GETLOOP32     _IOW('a', ATMIOC_SARCOM+2, struct compat_atmif_sioc)
 219#define ATM_SETLOOP32     _IOW('a', ATMIOC_SARCOM+3, struct compat_atmif_sioc)
 220#define ATM_QUERYLOOP32   _IOW('a', ATMIOC_SARCOM+4, struct compat_atmif_sioc)
 221
 222static struct {
 223        unsigned int cmd32;
 224        unsigned int cmd;
 225} atm_ioctl_map[] = {
 226        { ATM_GETLINKRATE32, ATM_GETLINKRATE },
 227        { ATM_GETNAMES32,    ATM_GETNAMES },
 228        { ATM_GETTYPE32,     ATM_GETTYPE },
 229        { ATM_GETESI32,      ATM_GETESI },
 230        { ATM_GETADDR32,     ATM_GETADDR },
 231        { ATM_RSTADDR32,     ATM_RSTADDR },
 232        { ATM_ADDADDR32,     ATM_ADDADDR },
 233        { ATM_DELADDR32,     ATM_DELADDR },
 234        { ATM_GETCIRANGE32,  ATM_GETCIRANGE },
 235        { ATM_SETCIRANGE32,  ATM_SETCIRANGE },
 236        { ATM_SETESI32,      ATM_SETESI },
 237        { ATM_SETESIF32,     ATM_SETESIF },
 238        { ATM_GETSTAT32,     ATM_GETSTAT },
 239        { ATM_GETSTATZ32,    ATM_GETSTATZ },
 240        { ATM_GETLOOP32,     ATM_GETLOOP },
 241        { ATM_SETLOOP32,     ATM_SETLOOP },
 242        { ATM_QUERYLOOP32,   ATM_QUERYLOOP },
 243};
 244
 245#define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map)
 246
 247static int do_atm_iobuf(struct socket *sock, unsigned int cmd,
 248                        unsigned long arg)
 249{
 250        struct atm_iobuf __user *iobuf;
 251        struct compat_atm_iobuf __user *iobuf32;
 252        u32 data;
 253        void __user *datap;
 254        int len, err;
 255
 256        iobuf = compat_alloc_user_space(sizeof(*iobuf));
 257        iobuf32 = compat_ptr(arg);
 258
 259        if (get_user(len, &iobuf32->length) ||
 260            get_user(data, &iobuf32->buffer))
 261                return -EFAULT;
 262        datap = compat_ptr(data);
 263        if (put_user(len, &iobuf->length) ||
 264            put_user(datap, &iobuf->buffer))
 265                return -EFAULT;
 266
 267        err = do_vcc_ioctl(sock, cmd, (unsigned long) iobuf, 0);
 268
 269        if (!err) {
 270                if (copy_in_user(&iobuf32->length, &iobuf->length,
 271                                 sizeof(int)))
 272                        err = -EFAULT;
 273        }
 274
 275        return err;
 276}
 277
 278static int do_atmif_sioc(struct socket *sock, unsigned int cmd,
 279                         unsigned long arg)
 280{
 281        struct atmif_sioc __user *sioc;
 282        struct compat_atmif_sioc __user *sioc32;
 283        u32 data;
 284        void __user *datap;
 285        int err;
 286
 287        sioc = compat_alloc_user_space(sizeof(*sioc));
 288        sioc32 = compat_ptr(arg);
 289
 290        if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) ||
 291            get_user(data, &sioc32->arg))
 292                return -EFAULT;
 293        datap = compat_ptr(data);
 294        if (put_user(datap, &sioc->arg))
 295                return -EFAULT;
 296
 297        err = do_vcc_ioctl(sock, cmd, (unsigned long) sioc, 0);
 298
 299        if (!err) {
 300                if (copy_in_user(&sioc32->length, &sioc->length,
 301                                 sizeof(int)))
 302                        err = -EFAULT;
 303        }
 304        return err;
 305}
 306
 307static int do_atm_ioctl(struct socket *sock, unsigned int cmd32,
 308                        unsigned long arg)
 309{
 310        int i;
 311        unsigned int cmd = 0;
 312
 313        switch (cmd32) {
 314        case SONET_GETSTAT:
 315        case SONET_GETSTATZ:
 316        case SONET_GETDIAG:
 317        case SONET_SETDIAG:
 318        case SONET_CLRDIAG:
 319        case SONET_SETFRAMING:
 320        case SONET_GETFRAMING:
 321        case SONET_GETFRSENSE:
 322                return do_atmif_sioc(sock, cmd32, arg);
 323        }
 324
 325        for (i = 0; i < NR_ATM_IOCTL; i++) {
 326                if (cmd32 == atm_ioctl_map[i].cmd32) {
 327                        cmd = atm_ioctl_map[i].cmd;
 328                        break;
 329                }
 330        }
 331        if (i == NR_ATM_IOCTL)
 332                return -EINVAL;
 333
 334        switch (cmd) {
 335        case ATM_GETNAMES:
 336                return do_atm_iobuf(sock, cmd, arg);
 337
 338        case ATM_GETLINKRATE:
 339        case ATM_GETTYPE:
 340        case ATM_GETESI:
 341        case ATM_GETADDR:
 342        case ATM_RSTADDR:
 343        case ATM_ADDADDR:
 344        case ATM_DELADDR:
 345        case ATM_GETCIRANGE:
 346        case ATM_SETCIRANGE:
 347        case ATM_SETESI:
 348        case ATM_SETESIF:
 349        case ATM_GETSTAT:
 350        case ATM_GETSTATZ:
 351        case ATM_GETLOOP:
 352        case ATM_SETLOOP:
 353        case ATM_QUERYLOOP:
 354                return do_atmif_sioc(sock, cmd, arg);
 355        }
 356
 357        return -EINVAL;
 358}
 359
 360int vcc_compat_ioctl(struct socket *sock, unsigned int cmd,
 361                     unsigned long arg)
 362{
 363        int ret;
 364
 365        ret = do_vcc_ioctl(sock, cmd, arg, 1);
 366        if (ret != -ENOIOCTLCMD)
 367                return ret;
 368
 369        return do_atm_ioctl(sock, cmd, arg);
 370}
 371#endif
 372