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
   7#include <linux/module.h>
   8#include <linux/kmod.h>
   9#include <linux/net.h>          /* struct socket, struct proto_ops */
  10#include <linux/atm.h>          /* ATM stuff */
  11#include <linux/atmdev.h>
  12#include <linux/atmclip.h>      /* CLIP_*ENCAP */
  13#include <linux/atmarp.h>       /* manifest constants */
  14#include <linux/capability.h>
  15#include <linux/sonet.h>        /* for ioctls */
  16#include <linux/atmsvc.h>
  17#include <linux/atmmpc.h>
  18#include <net/atmclip.h>
  19#include <linux/atmlec.h>
  20#include <linux/mutex.h>
  21#include <asm/ioctls.h>
  22#include <net/compat.h>
  23
  24#include "resources.h"
  25#include "signaling.h"          /* for WAITING and sigd_attach */
  26#include "common.h"
  27
  28
  29static DEFINE_MUTEX(ioctl_mutex);
  30static LIST_HEAD(ioctl_list);
  31
  32
  33void register_atm_ioctl(struct atm_ioctl *ioctl)
  34{
  35        mutex_lock(&ioctl_mutex);
  36        list_add_tail(&ioctl->list, &ioctl_list);
  37        mutex_unlock(&ioctl_mutex);
  38}
  39
  40void deregister_atm_ioctl(struct atm_ioctl *ioctl)
  41{
  42        mutex_lock(&ioctl_mutex);
  43        list_del(&ioctl->list);
  44        mutex_unlock(&ioctl_mutex);
  45}
  46
  47EXPORT_SYMBOL(register_atm_ioctl);
  48EXPORT_SYMBOL(deregister_atm_ioctl);
  49
  50static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg, int compat)
  51{
  52        struct sock *sk = sock->sk;
  53        struct atm_vcc *vcc;
  54        int error;
  55        struct list_head * pos;
  56        void __user *argp = (void __user *)arg;
  57
  58        vcc = ATM_SD(sock);
  59        switch (cmd) {
  60                case SIOCOUTQ:
  61                        if (sock->state != SS_CONNECTED ||
  62                            !test_bit(ATM_VF_READY, &vcc->flags)) {
  63                                error =  -EINVAL;
  64                                goto done;
  65                        }
  66                        error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk),
  67                                         (int __user *) argp) ? -EFAULT : 0;
  68                        goto done;
  69                case SIOCINQ:
  70                        {
  71                                struct sk_buff *skb;
  72
  73                                if (sock->state != SS_CONNECTED) {
  74                                        error = -EINVAL;
  75                                        goto done;
  76                                }
  77                                skb = skb_peek(&sk->sk_receive_queue);
  78                                error = put_user(skb ? skb->len : 0,
  79                                                 (int __user *)argp) ? -EFAULT : 0;
  80                                goto done;
  81                        }
  82                case SIOCGSTAMP: /* borrowed from IP */
  83#ifdef CONFIG_COMPAT
  84                        if (compat)
  85                                error = compat_sock_get_timestamp(sk, argp);
  86                        else
  87#endif
  88                                error = sock_get_timestamp(sk, argp);
  89                        goto done;
  90                case SIOCGSTAMPNS: /* borrowed from IP */
  91#ifdef CONFIG_COMPAT
  92                        if (compat)
  93                                error = compat_sock_get_timestampns(sk, argp);
  94                        else
  95#endif
  96                                error = sock_get_timestampns(sk, argp);
  97                        goto done;
  98                case ATM_SETSC:
  99                        if (net_ratelimit())
 100                                printk(KERN_WARNING "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                                if (net_ratelimit())
 126                                        printk(KERN_WARNING "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                        }
 151                        break;
 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
 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
 194int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 195{
 196        return do_vcc_ioctl(sock, cmd, arg, 1);
 197}
 198#endif
 199