root/net/atm/resources.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __alloc_atm_dev
  2. __atm_dev_lookup
  3. atm_dev_lookup
  4. atm_dev_register
  5. atm_dev_deregister
  6. copy_aal_stats
  7. subtract_aal_stats
  8. fetch_stats
  9. atm_dev_ioctl
  10. atm_dev_seq_start
  11. atm_dev_seq_stop
  12. atm_dev_seq_next

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* net/atm/resources.c - Statically allocated resources */
   3 
   4 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
   5 
   6 /* Fixes
   7  * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   8  * 2002/01 - don't free the whole struct sock on sk->destruct time,
   9  *           use the default destruct function initialized by sock_init_data */
  10 
  11 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
  12 
  13 #include <linux/ctype.h>
  14 #include <linux/string.h>
  15 #include <linux/atmdev.h>
  16 #include <linux/sonet.h>
  17 #include <linux/kernel.h> /* for barrier */
  18 #include <linux/module.h>
  19 #include <linux/bitops.h>
  20 #include <linux/capability.h>
  21 #include <linux/delay.h>
  22 #include <linux/mutex.h>
  23 #include <linux/slab.h>
  24 
  25 #include <net/sock.h>    /* for struct sock */
  26 
  27 #include "common.h"
  28 #include "resources.h"
  29 #include "addr.h"
  30 
  31 
  32 LIST_HEAD(atm_devs);
  33 DEFINE_MUTEX(atm_dev_mutex);
  34 
  35 static struct atm_dev *__alloc_atm_dev(const char *type)
  36 {
  37         struct atm_dev *dev;
  38 
  39         dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  40         if (!dev)
  41                 return NULL;
  42         dev->type = type;
  43         dev->signal = ATM_PHY_SIG_UNKNOWN;
  44         dev->link_rate = ATM_OC3_PCR;
  45         spin_lock_init(&dev->lock);
  46         INIT_LIST_HEAD(&dev->local);
  47         INIT_LIST_HEAD(&dev->lecs);
  48 
  49         return dev;
  50 }
  51 
  52 static struct atm_dev *__atm_dev_lookup(int number)
  53 {
  54         struct atm_dev *dev;
  55         struct list_head *p;
  56 
  57         list_for_each(p, &atm_devs) {
  58                 dev = list_entry(p, struct atm_dev, dev_list);
  59                 if (dev->number == number) {
  60                         atm_dev_hold(dev);
  61                         return dev;
  62                 }
  63         }
  64         return NULL;
  65 }
  66 
  67 struct atm_dev *atm_dev_lookup(int number)
  68 {
  69         struct atm_dev *dev;
  70 
  71         mutex_lock(&atm_dev_mutex);
  72         dev = __atm_dev_lookup(number);
  73         mutex_unlock(&atm_dev_mutex);
  74         return dev;
  75 }
  76 EXPORT_SYMBOL(atm_dev_lookup);
  77 
  78 struct atm_dev *atm_dev_register(const char *type, struct device *parent,
  79                                  const struct atmdev_ops *ops, int number,
  80                                  unsigned long *flags)
  81 {
  82         struct atm_dev *dev, *inuse;
  83 
  84         dev = __alloc_atm_dev(type);
  85         if (!dev) {
  86                 pr_err("no space for dev %s\n", type);
  87                 return NULL;
  88         }
  89         mutex_lock(&atm_dev_mutex);
  90         if (number != -1) {
  91                 inuse = __atm_dev_lookup(number);
  92                 if (inuse) {
  93                         atm_dev_put(inuse);
  94                         mutex_unlock(&atm_dev_mutex);
  95                         kfree(dev);
  96                         return NULL;
  97                 }
  98                 dev->number = number;
  99         } else {
 100                 dev->number = 0;
 101                 while ((inuse = __atm_dev_lookup(dev->number))) {
 102                         atm_dev_put(inuse);
 103                         dev->number++;
 104                 }
 105         }
 106 
 107         dev->ops = ops;
 108         if (flags)
 109                 dev->flags = *flags;
 110         else
 111                 memset(&dev->flags, 0, sizeof(dev->flags));
 112         memset(&dev->stats, 0, sizeof(dev->stats));
 113         refcount_set(&dev->refcnt, 1);
 114 
 115         if (atm_proc_dev_register(dev) < 0) {
 116                 pr_err("atm_proc_dev_register failed for dev %s\n", type);
 117                 goto out_fail;
 118         }
 119 
 120         if (atm_register_sysfs(dev, parent) < 0) {
 121                 pr_err("atm_register_sysfs failed for dev %s\n", type);
 122                 atm_proc_dev_deregister(dev);
 123                 goto out_fail;
 124         }
 125 
 126         list_add_tail(&dev->dev_list, &atm_devs);
 127 
 128 out:
 129         mutex_unlock(&atm_dev_mutex);
 130         return dev;
 131 
 132 out_fail:
 133         kfree(dev);
 134         dev = NULL;
 135         goto out;
 136 }
 137 EXPORT_SYMBOL(atm_dev_register);
 138 
 139 void atm_dev_deregister(struct atm_dev *dev)
 140 {
 141         BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags));
 142         set_bit(ATM_DF_REMOVED, &dev->flags);
 143 
 144         /*
 145          * if we remove current device from atm_devs list, new device
 146          * with same number can appear, such we need deregister proc,
 147          * release async all vccs and remove them from vccs list too
 148          */
 149         mutex_lock(&atm_dev_mutex);
 150         list_del(&dev->dev_list);
 151         mutex_unlock(&atm_dev_mutex);
 152 
 153         atm_dev_release_vccs(dev);
 154         atm_unregister_sysfs(dev);
 155         atm_proc_dev_deregister(dev);
 156 
 157         atm_dev_put(dev);
 158 }
 159 EXPORT_SYMBOL(atm_dev_deregister);
 160 
 161 static void copy_aal_stats(struct k_atm_aal_stats *from,
 162     struct atm_aal_stats *to)
 163 {
 164 #define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
 165         __AAL_STAT_ITEMS
 166 #undef __HANDLE_ITEM
 167 }
 168 
 169 static void subtract_aal_stats(struct k_atm_aal_stats *from,
 170     struct atm_aal_stats *to)
 171 {
 172 #define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i)
 173         __AAL_STAT_ITEMS
 174 #undef __HANDLE_ITEM
 175 }
 176 
 177 static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg,
 178                        int zero)
 179 {
 180         struct atm_dev_stats tmp;
 181         int error = 0;
 182 
 183         copy_aal_stats(&dev->stats.aal0, &tmp.aal0);
 184         copy_aal_stats(&dev->stats.aal34, &tmp.aal34);
 185         copy_aal_stats(&dev->stats.aal5, &tmp.aal5);
 186         if (arg)
 187                 error = copy_to_user(arg, &tmp, sizeof(tmp));
 188         if (zero && !error) {
 189                 subtract_aal_stats(&dev->stats.aal0, &tmp.aal0);
 190                 subtract_aal_stats(&dev->stats.aal34, &tmp.aal34);
 191                 subtract_aal_stats(&dev->stats.aal5, &tmp.aal5);
 192         }
 193         return error ? -EFAULT : 0;
 194 }
 195 
 196 int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
 197 {
 198         void __user *buf;
 199         int error, len, number, size = 0;
 200         struct atm_dev *dev;
 201         struct list_head *p;
 202         int *tmp_buf, *tmp_p;
 203         int __user *sioc_len;
 204         int __user *iobuf_len;
 205 
 206         switch (cmd) {
 207         case ATM_GETNAMES:
 208                 if (IS_ENABLED(CONFIG_COMPAT) && compat) {
 209 #ifdef CONFIG_COMPAT
 210                         struct compat_atm_iobuf __user *ciobuf = arg;
 211                         compat_uptr_t cbuf;
 212                         iobuf_len = &ciobuf->length;
 213                         if (get_user(cbuf, &ciobuf->buffer))
 214                                 return -EFAULT;
 215                         buf = compat_ptr(cbuf);
 216 #endif
 217                 } else {
 218                         struct atm_iobuf __user *iobuf = arg;
 219                         iobuf_len = &iobuf->length;
 220                         if (get_user(buf, &iobuf->buffer))
 221                                 return -EFAULT;
 222                 }
 223                 if (get_user(len, iobuf_len))
 224                         return -EFAULT;
 225                 mutex_lock(&atm_dev_mutex);
 226                 list_for_each(p, &atm_devs)
 227                         size += sizeof(int);
 228                 if (size > len) {
 229                         mutex_unlock(&atm_dev_mutex);
 230                         return -E2BIG;
 231                 }
 232                 tmp_buf = kmalloc(size, GFP_ATOMIC);
 233                 if (!tmp_buf) {
 234                         mutex_unlock(&atm_dev_mutex);
 235                         return -ENOMEM;
 236                 }
 237                 tmp_p = tmp_buf;
 238                 list_for_each(p, &atm_devs) {
 239                         dev = list_entry(p, struct atm_dev, dev_list);
 240                         *tmp_p++ = dev->number;
 241                 }
 242                 mutex_unlock(&atm_dev_mutex);
 243                 error = ((copy_to_user(buf, tmp_buf, size)) ||
 244                          put_user(size, iobuf_len))
 245                         ? -EFAULT : 0;
 246                 kfree(tmp_buf);
 247                 return error;
 248         default:
 249                 break;
 250         }
 251 
 252         if (IS_ENABLED(CONFIG_COMPAT) && compat) {
 253 #ifdef CONFIG_COMPAT
 254                 struct compat_atmif_sioc __user *csioc = arg;
 255                 compat_uptr_t carg;
 256 
 257                 sioc_len = &csioc->length;
 258                 if (get_user(carg, &csioc->arg))
 259                         return -EFAULT;
 260                 buf = compat_ptr(carg);
 261 
 262                 if (get_user(len, &csioc->length))
 263                         return -EFAULT;
 264                 if (get_user(number, &csioc->number))
 265                         return -EFAULT;
 266 #endif
 267         } else {
 268                 struct atmif_sioc __user *sioc = arg;
 269 
 270                 sioc_len = &sioc->length;
 271                 if (get_user(buf, &sioc->arg))
 272                         return -EFAULT;
 273                 if (get_user(len, &sioc->length))
 274                         return -EFAULT;
 275                 if (get_user(number, &sioc->number))
 276                         return -EFAULT;
 277         }
 278 
 279         dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d",
 280                                       number);
 281         if (!dev)
 282                 return -ENODEV;
 283 
 284         switch (cmd) {
 285         case ATM_GETTYPE:
 286                 size = strlen(dev->type) + 1;
 287                 if (copy_to_user(buf, dev->type, size)) {
 288                         error = -EFAULT;
 289                         goto done;
 290                 }
 291                 break;
 292         case ATM_GETESI:
 293                 size = ESI_LEN;
 294                 if (copy_to_user(buf, dev->esi, size)) {
 295                         error = -EFAULT;
 296                         goto done;
 297                 }
 298                 break;
 299         case ATM_SETESI:
 300         {
 301                 int i;
 302 
 303                 for (i = 0; i < ESI_LEN; i++)
 304                         if (dev->esi[i]) {
 305                                 error = -EEXIST;
 306                                 goto done;
 307                         }
 308         }
 309         /* fall through */
 310         case ATM_SETESIF:
 311         {
 312                 unsigned char esi[ESI_LEN];
 313 
 314                 if (!capable(CAP_NET_ADMIN)) {
 315                         error = -EPERM;
 316                         goto done;
 317                 }
 318                 if (copy_from_user(esi, buf, ESI_LEN)) {
 319                         error = -EFAULT;
 320                         goto done;
 321                 }
 322                 memcpy(dev->esi, esi, ESI_LEN);
 323                 error =  ESI_LEN;
 324                 goto done;
 325         }
 326         case ATM_GETSTATZ:
 327                 if (!capable(CAP_NET_ADMIN)) {
 328                         error = -EPERM;
 329                         goto done;
 330                 }
 331                 /* fall through */
 332         case ATM_GETSTAT:
 333                 size = sizeof(struct atm_dev_stats);
 334                 error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
 335                 if (error)
 336                         goto done;
 337                 break;
 338         case ATM_GETCIRANGE:
 339                 size = sizeof(struct atm_cirange);
 340                 if (copy_to_user(buf, &dev->ci_range, size)) {
 341                         error = -EFAULT;
 342                         goto done;
 343                 }
 344                 break;
 345         case ATM_GETLINKRATE:
 346                 size = sizeof(int);
 347                 if (copy_to_user(buf, &dev->link_rate, size)) {
 348                         error = -EFAULT;
 349                         goto done;
 350                 }
 351                 break;
 352         case ATM_RSTADDR:
 353                 if (!capable(CAP_NET_ADMIN)) {
 354                         error = -EPERM;
 355                         goto done;
 356                 }
 357                 atm_reset_addr(dev, ATM_ADDR_LOCAL);
 358                 break;
 359         case ATM_ADDADDR:
 360         case ATM_DELADDR:
 361         case ATM_ADDLECSADDR:
 362         case ATM_DELLECSADDR:
 363         {
 364                 struct sockaddr_atmsvc addr;
 365 
 366                 if (!capable(CAP_NET_ADMIN)) {
 367                         error = -EPERM;
 368                         goto done;
 369                 }
 370 
 371                 if (copy_from_user(&addr, buf, sizeof(addr))) {
 372                         error = -EFAULT;
 373                         goto done;
 374                 }
 375                 if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR)
 376                         error = atm_add_addr(dev, &addr,
 377                                              (cmd == ATM_ADDADDR ?
 378                                               ATM_ADDR_LOCAL : ATM_ADDR_LECS));
 379                 else
 380                         error = atm_del_addr(dev, &addr,
 381                                              (cmd == ATM_DELADDR ?
 382                                               ATM_ADDR_LOCAL : ATM_ADDR_LECS));
 383                 goto done;
 384         }
 385         case ATM_GETADDR:
 386         case ATM_GETLECSADDR:
 387                 error = atm_get_addr(dev, buf, len,
 388                                      (cmd == ATM_GETADDR ?
 389                                       ATM_ADDR_LOCAL : ATM_ADDR_LECS));
 390                 if (error < 0)
 391                         goto done;
 392                 size = error;
 393                 /* may return 0, but later on size == 0 means "don't
 394                    write the length" */
 395                 error = put_user(size, sioc_len) ? -EFAULT : 0;
 396                 goto done;
 397         case ATM_SETLOOP:
 398                 if (__ATM_LM_XTRMT((int) (unsigned long) buf) &&
 399                     __ATM_LM_XTLOC((int) (unsigned long) buf) >
 400                     __ATM_LM_XTRMT((int) (unsigned long) buf)) {
 401                         error = -EINVAL;
 402                         goto done;
 403                 }
 404                 /* fall through */
 405         case ATM_SETCIRANGE:
 406         case SONET_GETSTATZ:
 407         case SONET_SETDIAG:
 408         case SONET_CLRDIAG:
 409         case SONET_SETFRAMING:
 410                 if (!capable(CAP_NET_ADMIN)) {
 411                         error = -EPERM;
 412                         goto done;
 413                 }
 414                 /* fall through */
 415         default:
 416                 if (IS_ENABLED(CONFIG_COMPAT) && compat) {
 417 #ifdef CONFIG_COMPAT
 418                         if (!dev->ops->compat_ioctl) {
 419                                 error = -EINVAL;
 420                                 goto done;
 421                         }
 422                         size = dev->ops->compat_ioctl(dev, cmd, buf);
 423 #endif
 424                 } else {
 425                         if (!dev->ops->ioctl) {
 426                                 error = -EINVAL;
 427                                 goto done;
 428                         }
 429                         size = dev->ops->ioctl(dev, cmd, buf);
 430                 }
 431                 if (size < 0) {
 432                         error = (size == -ENOIOCTLCMD ? -ENOTTY : size);
 433                         goto done;
 434                 }
 435         }
 436 
 437         if (size)
 438                 error = put_user(size, sioc_len) ? -EFAULT : 0;
 439         else
 440                 error = 0;
 441 done:
 442         atm_dev_put(dev);
 443         return error;
 444 }
 445 
 446 void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos)
 447 {
 448         mutex_lock(&atm_dev_mutex);
 449         return seq_list_start_head(&atm_devs, *pos);
 450 }
 451 
 452 void atm_dev_seq_stop(struct seq_file *seq, void *v)
 453 {
 454         mutex_unlock(&atm_dev_mutex);
 455 }
 456 
 457 void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 458 {
 459         return seq_list_next(v, &atm_devs, pos);
 460 }

/* [<][>][^][v][top][bottom][index][help] */