0001
0002
0003
0004
0005
0006 #include <linux/atm.h>
0007 #include <linux/atmdev.h>
0008 #include <linux/slab.h>
0009 #include <linux/uaccess.h>
0010
0011 #include "signaling.h"
0012 #include "addr.h"
0013
0014 static int check_addr(const struct sockaddr_atmsvc *addr)
0015 {
0016 int i;
0017
0018 if (addr->sas_family != AF_ATMSVC)
0019 return -EAFNOSUPPORT;
0020 if (!*addr->sas_addr.pub)
0021 return *addr->sas_addr.prv ? 0 : -EINVAL;
0022 for (i = 1; i < ATM_E164_LEN + 1; i++)
0023 if (!addr->sas_addr.pub[i])
0024 return 0;
0025 return -EINVAL;
0026 }
0027
0028 static int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b)
0029 {
0030 if (*a->sas_addr.prv)
0031 if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN))
0032 return 0;
0033 if (!*a->sas_addr.pub)
0034 return !*b->sas_addr.pub;
0035 if (!*b->sas_addr.pub)
0036 return 0;
0037 return !strcmp(a->sas_addr.pub, b->sas_addr.pub);
0038 }
0039
0040 static void notify_sigd(const struct atm_dev *dev)
0041 {
0042 struct sockaddr_atmpvc pvc;
0043
0044 pvc.sap_addr.itf = dev->number;
0045 sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL);
0046 }
0047
0048 void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype)
0049 {
0050 unsigned long flags;
0051 struct atm_dev_addr *this, *p;
0052 struct list_head *head;
0053
0054 spin_lock_irqsave(&dev->lock, flags);
0055 if (atype == ATM_ADDR_LECS)
0056 head = &dev->lecs;
0057 else
0058 head = &dev->local;
0059 list_for_each_entry_safe(this, p, head, entry) {
0060 list_del(&this->entry);
0061 kfree(this);
0062 }
0063 spin_unlock_irqrestore(&dev->lock, flags);
0064 if (head == &dev->local)
0065 notify_sigd(dev);
0066 }
0067
0068 int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
0069 enum atm_addr_type_t atype)
0070 {
0071 unsigned long flags;
0072 struct atm_dev_addr *this;
0073 struct list_head *head;
0074 int error;
0075
0076 error = check_addr(addr);
0077 if (error)
0078 return error;
0079 spin_lock_irqsave(&dev->lock, flags);
0080 if (atype == ATM_ADDR_LECS)
0081 head = &dev->lecs;
0082 else
0083 head = &dev->local;
0084 list_for_each_entry(this, head, entry) {
0085 if (identical(&this->addr, addr)) {
0086 spin_unlock_irqrestore(&dev->lock, flags);
0087 return -EEXIST;
0088 }
0089 }
0090 this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
0091 if (!this) {
0092 spin_unlock_irqrestore(&dev->lock, flags);
0093 return -ENOMEM;
0094 }
0095 this->addr = *addr;
0096 list_add(&this->entry, head);
0097 spin_unlock_irqrestore(&dev->lock, flags);
0098 if (head == &dev->local)
0099 notify_sigd(dev);
0100 return 0;
0101 }
0102
0103 int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
0104 enum atm_addr_type_t atype)
0105 {
0106 unsigned long flags;
0107 struct atm_dev_addr *this;
0108 struct list_head *head;
0109 int error;
0110
0111 error = check_addr(addr);
0112 if (error)
0113 return error;
0114 spin_lock_irqsave(&dev->lock, flags);
0115 if (atype == ATM_ADDR_LECS)
0116 head = &dev->lecs;
0117 else
0118 head = &dev->local;
0119 list_for_each_entry(this, head, entry) {
0120 if (identical(&this->addr, addr)) {
0121 list_del(&this->entry);
0122 spin_unlock_irqrestore(&dev->lock, flags);
0123 kfree(this);
0124 if (head == &dev->local)
0125 notify_sigd(dev);
0126 return 0;
0127 }
0128 }
0129 spin_unlock_irqrestore(&dev->lock, flags);
0130 return -ENOENT;
0131 }
0132
0133 int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
0134 size_t size, enum atm_addr_type_t atype)
0135 {
0136 unsigned long flags;
0137 struct atm_dev_addr *this;
0138 struct list_head *head;
0139 int total = 0, error;
0140 struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
0141
0142 spin_lock_irqsave(&dev->lock, flags);
0143 if (atype == ATM_ADDR_LECS)
0144 head = &dev->lecs;
0145 else
0146 head = &dev->local;
0147 list_for_each_entry(this, head, entry)
0148 total += sizeof(struct sockaddr_atmsvc);
0149 tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
0150 if (!tmp_buf) {
0151 spin_unlock_irqrestore(&dev->lock, flags);
0152 return -ENOMEM;
0153 }
0154 list_for_each_entry(this, head, entry)
0155 memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc));
0156 spin_unlock_irqrestore(&dev->lock, flags);
0157 error = total > size ? -E2BIG : total;
0158 if (copy_to_user(buf, tmp_buf, total < size ? total : size))
0159 error = -EFAULT;
0160 kfree(tmp_buf);
0161 return error;
0162 }