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