Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* net/atm/addr.c - Local ATM address registry */
0003 
0004 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
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++)  /* make sure it's \0-terminated */
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 }