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