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