root/net/atm/addr.c

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

DEFINITIONS

This source file includes following definitions.
  1. check_addr
  2. identical
  3. notify_sigd
  4. atm_reset_addr
  5. atm_add_addr
  6. atm_del_addr
  7. atm_get_addr

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* net/atm/addr.c - Local ATM address registry */
   3 
   4 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
   5 
   6 #include <linux/atm.h>
   7 #include <linux/atmdev.h>
   8 #include <linux/slab.h>
   9 #include <linux/uaccess.h>
  10 
  11 #include "signaling.h"
  12 #include "addr.h"
  13 
  14 static int check_addr(const struct sockaddr_atmsvc *addr)
  15 {
  16         int i;
  17 
  18         if (addr->sas_family != AF_ATMSVC)
  19                 return -EAFNOSUPPORT;
  20         if (!*addr->sas_addr.pub)
  21                 return *addr->sas_addr.prv ? 0 : -EINVAL;
  22         for (i = 1; i < ATM_E164_LEN + 1; i++)  /* make sure it's \0-terminated */
  23                 if (!addr->sas_addr.pub[i])
  24                         return 0;
  25         return -EINVAL;
  26 }
  27 
  28 static int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b)
  29 {
  30         if (*a->sas_addr.prv)
  31                 if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN))
  32                         return 0;
  33         if (!*a->sas_addr.pub)
  34                 return !*b->sas_addr.pub;
  35         if (!*b->sas_addr.pub)
  36                 return 0;
  37         return !strcmp(a->sas_addr.pub, b->sas_addr.pub);
  38 }
  39 
  40 static void notify_sigd(const struct atm_dev *dev)
  41 {
  42         struct sockaddr_atmpvc pvc;
  43 
  44         pvc.sap_addr.itf = dev->number;
  45         sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL);
  46 }
  47 
  48 void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype)
  49 {
  50         unsigned long flags;
  51         struct atm_dev_addr *this, *p;
  52         struct list_head *head;
  53 
  54         spin_lock_irqsave(&dev->lock, flags);
  55         if (atype == ATM_ADDR_LECS)
  56                 head = &dev->lecs;
  57         else
  58                 head = &dev->local;
  59         list_for_each_entry_safe(this, p, head, entry) {
  60                 list_del(&this->entry);
  61                 kfree(this);
  62         }
  63         spin_unlock_irqrestore(&dev->lock, flags);
  64         if (head == &dev->local)
  65                 notify_sigd(dev);
  66 }
  67 
  68 int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
  69                  enum atm_addr_type_t atype)
  70 {
  71         unsigned long flags;
  72         struct atm_dev_addr *this;
  73         struct list_head *head;
  74         int error;
  75 
  76         error = check_addr(addr);
  77         if (error)
  78                 return error;
  79         spin_lock_irqsave(&dev->lock, flags);
  80         if (atype == ATM_ADDR_LECS)
  81                 head = &dev->lecs;
  82         else
  83                 head = &dev->local;
  84         list_for_each_entry(this, head, entry) {
  85                 if (identical(&this->addr, addr)) {
  86                         spin_unlock_irqrestore(&dev->lock, flags);
  87                         return -EEXIST;
  88                 }
  89         }
  90         this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
  91         if (!this) {
  92                 spin_unlock_irqrestore(&dev->lock, flags);
  93                 return -ENOMEM;
  94         }
  95         this->addr = *addr;
  96         list_add(&this->entry, head);
  97         spin_unlock_irqrestore(&dev->lock, flags);
  98         if (head == &dev->local)
  99                 notify_sigd(dev);
 100         return 0;
 101 }
 102 
 103 int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
 104                  enum atm_addr_type_t atype)
 105 {
 106         unsigned long flags;
 107         struct atm_dev_addr *this;
 108         struct list_head *head;
 109         int error;
 110 
 111         error = check_addr(addr);
 112         if (error)
 113                 return error;
 114         spin_lock_irqsave(&dev->lock, flags);
 115         if (atype == ATM_ADDR_LECS)
 116                 head = &dev->lecs;
 117         else
 118                 head = &dev->local;
 119         list_for_each_entry(this, head, entry) {
 120                 if (identical(&this->addr, addr)) {
 121                         list_del(&this->entry);
 122                         spin_unlock_irqrestore(&dev->lock, flags);
 123                         kfree(this);
 124                         if (head == &dev->local)
 125                                 notify_sigd(dev);
 126                         return 0;
 127                 }
 128         }
 129         spin_unlock_irqrestore(&dev->lock, flags);
 130         return -ENOENT;
 131 }
 132 
 133 int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
 134                  size_t size, enum atm_addr_type_t atype)
 135 {
 136         unsigned long flags;
 137         struct atm_dev_addr *this;
 138         struct list_head *head;
 139         int total = 0, error;
 140         struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
 141 
 142         spin_lock_irqsave(&dev->lock, flags);
 143         if (atype == ATM_ADDR_LECS)
 144                 head = &dev->lecs;
 145         else
 146                 head = &dev->local;
 147         list_for_each_entry(this, head, entry)
 148             total += sizeof(struct sockaddr_atmsvc);
 149         tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
 150         if (!tmp_buf) {
 151                 spin_unlock_irqrestore(&dev->lock, flags);
 152                 return -ENOMEM;
 153         }
 154         list_for_each_entry(this, head, entry)
 155             memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc));
 156         spin_unlock_irqrestore(&dev->lock, flags);
 157         error = total > size ? -E2BIG : total;
 158         if (copy_to_user(buf, tmp_buf, total < size ? total : size))
 159                 error = -EFAULT;
 160         kfree(tmp_buf);
 161         return error;
 162 }

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