[ATM]: add support for LECS addresses learned from network
authorEric Kinzie <ekinzie@cmf.nrl.navy.mil>
Fri, 7 Oct 2005 05:19:28 +0000 (22:19 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 7 Oct 2005 05:19:28 +0000 (22:19 -0700)
From: Eric Kinzie <ekinzie@cmf.nrl.navy.mil>
Signed-off-by: Chas Williams <chas@cmf.nrl.navy.mil>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/atmdev.h
net/atm/addr.c
net/atm/addr.h
net/atm/resources.c

index f1fd849e5535e35dbe37b22c57c0118e2908e87d..aca9b344bd356d5fa62cda22811d902957bb7edb 100644 (file)
@@ -76,6 +76,13 @@ struct atm_dev_stats {
                                        /* set interface ESI */
 #define ATM_SETESIF    _IOW('a',ATMIOC_ITF+13,struct atmif_sioc)
                                        /* force interface ESI */
+#define ATM_ADDLECSADDR        _IOW('a', ATMIOC_ITF+14, struct atmif_sioc)
+                                       /* register a LECS address */
+#define ATM_DELLECSADDR        _IOW('a', ATMIOC_ITF+15, struct atmif_sioc)
+                                       /* unregister a LECS address */
+#define ATM_GETLECSADDR        _IOW('a', ATMIOC_ITF+16, struct atmif_sioc)
+                                       /* retrieve LECS address(es) */
+
 #define ATM_GETSTAT    _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc)
                                        /* get AAL layer statistics */
 #define ATM_GETSTATZ   _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc)
@@ -328,6 +335,8 @@ struct atm_dev_addr {
        struct list_head entry;         /* next address */
 };
 
+enum atm_addr_type_t { ATM_ADDR_LOCAL, ATM_ADDR_LECS };
+
 struct atm_dev {
        const struct atmdev_ops *ops;   /* device operations; NULL if unused */
        const struct atmphy_ops *phy;   /* PHY operations, may be undefined */
@@ -338,6 +347,7 @@ struct atm_dev {
        void            *phy_data;      /* private PHY date */
        unsigned long   flags;          /* device flags (ATM_DF_*) */
        struct list_head local;         /* local ATM addresses */
+       struct list_head lecs;          /* LECS ATM addresses learned via ILMI */
        unsigned char   esi[ESI_LEN];   /* ESI ("MAC" addr) */
        struct atm_cirange ci_range;    /* VPI/VCI range */
        struct k_atm_dev_stats stats;   /* statistics */
index a30d0bf480638de8a44c18b221b007d65085047a..3060fd0ba4b9fb51ca79a8079f22365433cc4470 100644 (file)
@@ -44,31 +44,43 @@ static void notify_sigd(struct atm_dev *dev)
        sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL);
 }
 
-void atm_reset_addr(struct atm_dev *dev)
+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);
-       list_for_each_entry_safe(this, p, &dev->local, entry) {
+       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);
-       notify_sigd(dev);
+       if (head == &dev->local)
+               notify_sigd(dev);
 }
 
-int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr)
+int atm_add_addr(struct atm_dev *dev, 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);
-       list_for_each_entry(this, &dev->local, entry) {
+       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;
@@ -80,28 +92,36 @@ int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr)
                return -ENOMEM;
        }
        this->addr = *addr;
-       list_add(&this->entry, &dev->local);
+       list_add(&this->entry, head);
        spin_unlock_irqrestore(&dev->lock, flags);
-       notify_sigd(dev);
+       if (head == &dev->local)
+               notify_sigd(dev);
        return 0;
 }
 
-int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr)
+int atm_del_addr(struct atm_dev *dev, 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);
-       list_for_each_entry(this, &dev->local, entry) {
+       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);
-                       notify_sigd(dev);
+                       if (head == &dev->local)
+                               notify_sigd(dev);
                        return 0;
                }
        }
@@ -110,22 +130,27 @@ int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr)
 }
 
 int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
-                size_t size)
+                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);
-       list_for_each_entry(this, &dev->local, entry)
+       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, &dev->local, entry)
+       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;
index 3099d21feeaa427d49197f8ea879183ce4c3f26c..f39433ad45dab62bd02c6628552f4d964cdb03f8 100644 (file)
@@ -9,10 +9,12 @@
 #include <linux/atm.h>
 #include <linux/atmdev.h>
 
-
-void atm_reset_addr(struct atm_dev *dev);
-int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr);
-int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr);
-int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc __user *buf,size_t size);
+void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t type);
+int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr,
+                enum atm_addr_type_t type);
+int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr,
+                enum atm_addr_type_t type);
+int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user *buf,
+                size_t size, enum atm_addr_type_t type);
 
 #endif
index a57a9268bd2436e565cdaf1e15cc9dcf10bb14c7..415d2615d475fa3c284d4a11cf565408d8c5c385 100644 (file)
@@ -40,6 +40,7 @@ static struct atm_dev *__alloc_atm_dev(const char *type)
        dev->link_rate = ATM_OC3_PCR;
        spin_lock_init(&dev->lock);
        INIT_LIST_HEAD(&dev->local);
+       INIT_LIST_HEAD(&dev->lecs);
 
        return dev;
 }
@@ -320,10 +321,12 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg)
                                error = -EPERM;
                                goto done;
                        }
-                       atm_reset_addr(dev);
+                       atm_reset_addr(dev, ATM_ADDR_LOCAL);
                        break;
                case ATM_ADDADDR:
                case ATM_DELADDR:
+               case ATM_ADDLECSADDR:
+               case ATM_DELLECSADDR:
                        if (!capable(CAP_NET_ADMIN)) {
                                error = -EPERM;
                                goto done;
@@ -335,14 +338,21 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg)
                                        error = -EFAULT;
                                        goto done;
                                }
-                               if (cmd == ATM_ADDADDR)
-                                       error = atm_add_addr(dev, &addr);
+                               if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR)
+                                       error = atm_add_addr(dev, &addr,
+                                                            (cmd == ATM_ADDADDR ?
+                                                             ATM_ADDR_LOCAL : ATM_ADDR_LECS));
                                else
-                                       error = atm_del_addr(dev, &addr);
+                                       error = atm_del_addr(dev, &addr,
+                                                            (cmd == ATM_DELADDR ?
+                                                             ATM_ADDR_LOCAL : ATM_ADDR_LECS));
                                goto done;
                        }
                case ATM_GETADDR:
-                       error = atm_get_addr(dev, buf, len);
+               case ATM_GETLECSADDR:
+                       error = atm_get_addr(dev, buf, len,
+                                            (cmd == ATM_GETADDR ?
+                                             ATM_ADDR_LOCAL : ATM_ADDR_LECS));
                        if (error < 0)
                                goto done;
                        size = error;