123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- /* net/atm/addr.c - Local ATM address registry */
- /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
- #include <linux/atm.h>
- #include <linux/atmdev.h>
- #include <linux/slab.h>
- #include <linux/uaccess.h>
- #include "signaling.h"
- #include "addr.h"
- static int check_addr(const struct sockaddr_atmsvc *addr)
- {
- int i;
- if (addr->sas_family != AF_ATMSVC)
- return -EAFNOSUPPORT;
- if (!*addr->sas_addr.pub)
- return *addr->sas_addr.prv ? 0 : -EINVAL;
- for (i = 1; i < ATM_E164_LEN + 1; i++) /* make sure it's \0-terminated */
- if (!addr->sas_addr.pub[i])
- return 0;
- return -EINVAL;
- }
- static int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b)
- {
- if (*a->sas_addr.prv)
- if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN))
- return 0;
- if (!*a->sas_addr.pub)
- return !*b->sas_addr.pub;
- if (!*b->sas_addr.pub)
- return 0;
- return !strcmp(a->sas_addr.pub, b->sas_addr.pub);
- }
- static void notify_sigd(const struct atm_dev *dev)
- {
- struct sockaddr_atmpvc pvc;
- pvc.sap_addr.itf = dev->number;
- sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL);
- }
- void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype)
- {
- unsigned long flags;
- struct atm_dev_addr *this, *p;
- struct list_head *head;
- spin_lock_irqsave(&dev->lock, flags);
- if (atype == ATM_ADDR_LECS)
- head = &dev->lecs;
- else
- head = &dev->local;
- list_for_each_entry_safe(this, p, head, entry) {
- list_del(&this->entry);
- kfree(this);
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- if (head == &dev->local)
- notify_sigd(dev);
- }
- int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
- enum atm_addr_type_t atype)
- {
- unsigned long flags;
- struct atm_dev_addr *this;
- struct list_head *head;
- int error;
- error = check_addr(addr);
- if (error)
- return error;
- spin_lock_irqsave(&dev->lock, flags);
- if (atype == ATM_ADDR_LECS)
- head = &dev->lecs;
- else
- head = &dev->local;
- list_for_each_entry(this, head, entry) {
- if (identical(&this->addr, addr)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EEXIST;
- }
- }
- this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
- if (!this) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -ENOMEM;
- }
- this->addr = *addr;
- list_add(&this->entry, head);
- spin_unlock_irqrestore(&dev->lock, flags);
- if (head == &dev->local)
- notify_sigd(dev);
- return 0;
- }
- int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
- enum atm_addr_type_t atype)
- {
- unsigned long flags;
- struct atm_dev_addr *this;
- struct list_head *head;
- int error;
- error = check_addr(addr);
- if (error)
- return error;
- spin_lock_irqsave(&dev->lock, flags);
- if (atype == ATM_ADDR_LECS)
- head = &dev->lecs;
- else
- head = &dev->local;
- list_for_each_entry(this, head, entry) {
- if (identical(&this->addr, addr)) {
- list_del(&this->entry);
- spin_unlock_irqrestore(&dev->lock, flags);
- kfree(this);
- if (head == &dev->local)
- notify_sigd(dev);
- return 0;
- }
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- return -ENOENT;
- }
- int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
- size_t size, enum atm_addr_type_t atype)
- {
- unsigned long flags;
- struct atm_dev_addr *this;
- struct list_head *head;
- int total = 0, error;
- struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
- spin_lock_irqsave(&dev->lock, flags);
- if (atype == ATM_ADDR_LECS)
- head = &dev->lecs;
- else
- head = &dev->local;
- list_for_each_entry(this, head, entry)
- total += sizeof(struct sockaddr_atmsvc);
- tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
- if (!tmp_buf) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -ENOMEM;
- }
- list_for_each_entry(this, head, entry)
- memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc));
- spin_unlock_irqrestore(&dev->lock, flags);
- error = total > size ? -E2BIG : total;
- if (copy_to_user(buf, tmp_buf, total < size ? total : size))
- error = -EFAULT;
- kfree(tmp_buf);
- return error;
- }
|