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                net_warn_ratelimited("ATM_SETSC is obsolete; used by %s:%d\n",
 101                                     current->comm, task_pid_nr(current));
 102                error = 0;
 103                goto done;
 104        case ATMSIGD_CTRL:
 105                if (!capable(CAP_NET_ADMIN)) {
 106                        error = -EPERM;
 107                        goto done;
 108                }
 109                /*
 110                 * The user/kernel protocol for exchanging signalling
 111                 * info uses kernel pointers as opaque references,
 112                 * so the holder of the file descriptor can scribble
 113                 * on the kernel... so we should make sure that we
 114                 * have the same privileges that /proc/kcore needs
 115                 */
 116                if (!capable(CAP_SYS_RAWIO)) {
 117                        error = -EPERM;
 118                        goto done;
 119                }
 120#ifdef CONFIG_COMPAT
 121                /* WTF? I don't even want to _think_ about making this
 122                   work for 32-bit userspace. TBH I don't really want
 123                   to think about it at all. dwmw2. */
 124                if (compat) {
 125                        net_warn_ratelimited("32-bit task cannot be atmsigd\n");
 126                        error = -EINVAL;
 127                        goto done;
 128                }
 129#endif
 130                error = sigd_attach(vcc);
 131                if (!error)
 132                        sock->state = SS_CONNECTED;
 133                goto done;
 134        case ATM_SETBACKEND:
 135        case ATM_NEWBACKENDIF:
 136        {
 137                atm_backend_t backend;
 138                error = get_user(backend, (atm_backend_t __user *)argp);
 139                if (error)
 140                        goto done;
 141                switch (backend) {
 142                case ATM_BACKEND_PPP:
 143                        request_module("pppoatm");
 144                        break;
 145                case ATM_BACKEND_BR2684:
 146                        request_module("br2684");
 147                        break;
 148                }
 149                break;
 150        }
 151        case ATMMPC_CTRL:
 152        case ATMMPC_DATA:
 153                request_module("mpoa");
 154                break;
 155        case ATMARPD_CTRL:
 156                request_module("clip");
 157                break;
 158        case ATMLEC_CTRL:
 159                request_module("lec");
 160                break;
 161        }
 162
 163        error = -ENOIOCTLCMD;
 164
 165        mutex_lock(&ioctl_mutex);
 166        list_for_each(pos, &ioctl_list) {
 167                struct atm_ioctl *ic = list_entry(pos, struct atm_ioctl, list);
 168                if (try_module_get(ic->owner)) {
 169                        error = ic->ioctl(sock, cmd, arg);
 170                        module_put(ic->owner);
 171                        if (error != -ENOIOCTLCMD)
 172                                break;
 173                }
 174        }
 175        mutex_unlock(&ioctl_mutex);
 176
 177        if (error != -ENOIOCTLCMD)
 178                goto done;
 179
 180        error = atm_dev_ioctl(cmd, argp, compat);
 181
 182done:
 183        return error;
 184}
 185
 186int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 187{
 188        return do_vcc_ioctl(sock, cmd, arg, 0);
 189}
 190
 191#ifdef CONFIG_COMPAT
 192/*
 193 * FIXME:
 194 * The compat_ioctl handling is duplicated, using both these conversion
 195 * routines and the compat argument to the actual handlers. Both
 196 * versions are somewhat incomplete and should be merged, e.g. by
 197 * moving the ioctl number translation into the actual handlers and
 198 * killing the conversion code.
 199 *
 200 * -arnd, November 2009
 201 */
 202#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct compat_atmif_sioc)
 203#define ATM_GETNAMES32    _IOW('a', ATMIOC_ITF+3, struct compat_atm_iobuf)
 204#define ATM_GETTYPE32     _IOW('a', ATMIOC_ITF+4, struct compat_atmif_sioc)
 205#define ATM_GETESI32      _IOW('a', ATMIOC_ITF+5, struct compat_atmif_sioc)
 206#define ATM_GETADDR32     _IOW('a', ATMIOC_ITF+6, struct compat_atmif_sioc)
 207#define ATM_RSTADDR32     _IOW('a', ATMIOC_ITF+7, struct compat_atmif_sioc)
 208#define ATM_ADDADDR32     _IOW('a', ATMIOC_ITF+8, struct compat_atmif_sioc)
 209#define ATM_DELADDR32     _IOW('a', ATMIOC_ITF+9, struct compat_atmif_sioc)
 210#define ATM_GETCIRANGE32  _IOW('a', ATMIOC_ITF+10, struct compat_atmif_sioc)
 211#define ATM_SETCIRANGE32  _IOW('a', ATMIOC_ITF+11, struct compat_atmif_sioc)
 212#define ATM_SETESI32      _IOW('a', ATMIOC_ITF+12, struct compat_atmif_sioc)
 213#define ATM_SETESIF32     _IOW('a', ATMIOC_ITF+13, struct compat_atmif_sioc)
 214#define ATM_GETSTAT32     _IOW('a', ATMIOC_SARCOM+0, struct compat_atmif_sioc)
 215#define ATM_GETSTATZ32    _IOW('a', ATMIOC_SARCOM+1, struct compat_atmif_sioc)
 216#define ATM_GETLOOP32     _IOW('a', ATMIOC_SARCOM+2, struct compat_atmif_sioc)
 217#define ATM_SETLOOP32     _IOW('a', ATMIOC_SARCOM+3, struct compat_atmif_sioc)
 218#define ATM_QUERYLOOP32   _IOW('a', ATMIOC_SARCOM+4, struct compat_atmif_sioc)
 219
 220static struct {
 221        unsigned int cmd32;
 222        unsigned int cmd;
 223} atm_ioctl_map[] = {
 224        { ATM_GETLINKRATE32, ATM_GETLINKRATE },
 225        { ATM_GETNAMES32,    ATM_GETNAMES },
 226        { ATM_GETTYPE32,     ATM_GETTYPE },
 227        { ATM_GETESI32,      ATM_GETESI },
 228        { ATM_GETADDR32,     ATM_GETADDR },
 229        { ATM_RSTADDR32,     ATM_RSTADDR },
 230        { ATM_ADDADDR32,     ATM_ADDADDR },
 231        { ATM_DELADDR32,     ATM_DELADDR },
 232        { ATM_GETCIRANGE32,  ATM_GETCIRANGE },
 233        { ATM_SETCIRANGE32,  ATM_SETCIRANGE },
 234        { ATM_SETESI32,      ATM_SETESI },
 235        { ATM_SETESIF32,     ATM_SETESIF },
 236        { ATM_GETSTAT32,     ATM_GETSTAT },
 237        { ATM_GETSTATZ32,    ATM_GETSTATZ },
 238        { ATM_GETLOOP32,     ATM_GETLOOP },
 239        { ATM_SETLOOP32,     ATM_SETLOOP },
 240        { ATM_QUERYLOOP32,   ATM_QUERYLOOP },
 241};
 242
 243#define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map)
 244
 245static int do_atm_iobuf(struct socket *sock, unsigned int cmd,
 246                        unsigned long arg)
 247{
 248        struct atm_iobuf __user *iobuf;
 249        struct compat_atm_iobuf __user *iobuf32;
 250        u32 data;
 251        void __user *datap;
 252        int len, err;
 253
 254        iobuf = compat_alloc_user_space(sizeof(*iobuf));
 255        iobuf32 = compat_ptr(arg);
 256
 257        if (get_user(len, &iobuf32->length) ||
 258            get_user(data, &iobuf32->buffer))
 259                return -EFAULT;
 260        datap = compat_ptr(data);
 261        if (put_user(len, &iobuf->length) ||
 262            put_user(datap, &iobuf->buffer))
 263                return -EFAULT;
 264
 265        err = do_vcc_ioctl(sock, cmd, (unsigned long) iobuf, 0);
 266
 267        if (!err) {
 268                if (copy_in_user(&iobuf32->length, &iobuf->length,
 269                                 sizeof(int)))
 270                        err = -EFAULT;
 271        }
 272
 273        return err;
 274}
 275
 276static int do_atmif_sioc(struct socket *sock, unsigned int cmd,
 277                         unsigned long arg)
 278{
 279        struct atmif_sioc __user *sioc;
 280        struct compat_atmif_sioc __user *sioc32;
 281        u32 data;
 282        void __user *datap;
 283        int err;
 284
 285        sioc = compat_alloc_user_space(sizeof(*sioc));
 286        sioc32 = compat_ptr(arg);
 287
 288        if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) ||
 289            get_user(data, &sioc32->arg))
 290                return -EFAULT;
 291        datap = compat_ptr(data);
 292        if (put_user(datap, &sioc->arg))
 293                return -EFAULT;
 294
 295        err = do_vcc_ioctl(sock, cmd, (unsigned long) sioc, 0);
 296
 297        if (!err) {
 298                if (copy_in_user(&sioc32->length, &sioc->length,
 299                                 sizeof(int)))
 300                        err = -EFAULT;
 301        }
 302        return err;
 303}
 304
 305static int do_atm_ioctl(struct socket *sock, unsigned int cmd32,
 306                        unsigned long arg)
 307{
 308        int i;
 309        unsigned int cmd = 0;
 310
 311        switch (cmd32) {
 312        case SONET_GETSTAT:
 313        case SONET_GETSTATZ:
 314        case SONET_GETDIAG:
 315        case SONET_SETDIAG:
 316        case SONET_CLRDIAG:
 317        case SONET_SETFRAMING:
 318        case SONET_GETFRAMING:
 319        case SONET_GETFRSENSE:
 320                return do_atmif_sioc(sock, cmd32, arg);
 321        }
 322
 323        for (i = 0; i < NR_ATM_IOCTL; i++) {
 324                if (cmd32 == atm_ioctl_map[i].cmd32) {
 325                        cmd = atm_ioctl_map[i].cmd;
 326                        break;
 327                }
 328        }
 329        if (i == NR_ATM_IOCTL)
 330                return -EINVAL;
 331
 332        switch (cmd) {
 333        case ATM_GETNAMES:
 334                return do_atm_iobuf(sock, cmd, arg);
 335
 336        case ATM_GETLINKRATE:
 337        case ATM_GETTYPE:
 338        case ATM_GETESI:
 339        case ATM_GETADDR:
 340        case ATM_RSTADDR:
 341        case ATM_ADDADDR:
 342        case ATM_DELADDR:
 343        case ATM_GETCIRANGE:
 344        case ATM_SETCIRANGE:
 345        case ATM_SETESI:
 346        case ATM_SETESIF:
 347        case ATM_GETSTAT:
 348        case ATM_GETSTATZ:
 349        case ATM_GETLOOP:
 350        case ATM_SETLOOP:
 351        case ATM_QUERYLOOP:
 352                return do_atmif_sioc(sock, cmd, arg);
 353        }
 354
 355        return -EINVAL;
 356}
 357
 358int vcc_compat_ioctl(struct socket *sock, unsigned int cmd,
 359                     unsigned long arg)
 360{
 361        int ret;
 362
 363        ret = do_vcc_ioctl(sock, cmd, arg, 1);
 364        if (ret != -ENOIOCTLCMD)
 365                return ret;
 366
 367        return do_atm_ioctl(sock, cmd, arg);
 368}
 369#endif
 370
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.