[ATM]: add support for LECS addresses learned from network

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>

authored by Eric Kinzie and committed by David S. Miller 0f21ba7c 20c9c825

+70 -23
+10
include/linux/atmdev.h
··· 76 /* set interface ESI */ 77 #define ATM_SETESIF _IOW('a',ATMIOC_ITF+13,struct atmif_sioc) 78 /* force interface ESI */ 79 #define ATM_GETSTAT _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc) 80 /* get AAL layer statistics */ 81 #define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc) ··· 335 struct list_head entry; /* next address */ 336 }; 337 338 struct atm_dev { 339 const struct atmdev_ops *ops; /* device operations; NULL if unused */ 340 const struct atmphy_ops *phy; /* PHY operations, may be undefined */ ··· 347 void *phy_data; /* private PHY date */ 348 unsigned long flags; /* device flags (ATM_DF_*) */ 349 struct list_head local; /* local ATM addresses */ 350 unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */ 351 struct atm_cirange ci_range; /* VPI/VCI range */ 352 struct k_atm_dev_stats stats; /* statistics */
··· 76 /* set interface ESI */ 77 #define ATM_SETESIF _IOW('a',ATMIOC_ITF+13,struct atmif_sioc) 78 /* force interface ESI */ 79 + #define ATM_ADDLECSADDR _IOW('a', ATMIOC_ITF+14, struct atmif_sioc) 80 + /* register a LECS address */ 81 + #define ATM_DELLECSADDR _IOW('a', ATMIOC_ITF+15, struct atmif_sioc) 82 + /* unregister a LECS address */ 83 + #define ATM_GETLECSADDR _IOW('a', ATMIOC_ITF+16, struct atmif_sioc) 84 + /* retrieve LECS address(es) */ 85 + 86 #define ATM_GETSTAT _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc) 87 /* get AAL layer statistics */ 88 #define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc) ··· 328 struct list_head entry; /* next address */ 329 }; 330 331 + enum atm_addr_type_t { ATM_ADDR_LOCAL, ATM_ADDR_LECS }; 332 + 333 struct atm_dev { 334 const struct atmdev_ops *ops; /* device operations; NULL if unused */ 335 const struct atmphy_ops *phy; /* PHY operations, may be undefined */ ··· 338 void *phy_data; /* private PHY date */ 339 unsigned long flags; /* device flags (ATM_DF_*) */ 340 struct list_head local; /* local ATM addresses */ 341 + struct list_head lecs; /* LECS ATM addresses learned via ILMI */ 342 unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */ 343 struct atm_cirange ci_range; /* VPI/VCI range */ 344 struct k_atm_dev_stats stats; /* statistics */
+38 -13
net/atm/addr.c
··· 44 sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL); 45 } 46 47 - void atm_reset_addr(struct atm_dev *dev) 48 { 49 unsigned long flags; 50 struct atm_dev_addr *this, *p; 51 52 spin_lock_irqsave(&dev->lock, flags); 53 - list_for_each_entry_safe(this, p, &dev->local, entry) { 54 list_del(&this->entry); 55 kfree(this); 56 } 57 spin_unlock_irqrestore(&dev->lock, flags); 58 - notify_sigd(dev); 59 } 60 61 - int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) 62 { 63 unsigned long flags; 64 struct atm_dev_addr *this; 65 int error; 66 67 error = check_addr(addr); 68 if (error) 69 return error; 70 spin_lock_irqsave(&dev->lock, flags); 71 - list_for_each_entry(this, &dev->local, entry) { 72 if (identical(&this->addr, addr)) { 73 spin_unlock_irqrestore(&dev->lock, flags); 74 return -EEXIST; ··· 92 return -ENOMEM; 93 } 94 this->addr = *addr; 95 - list_add(&this->entry, &dev->local); 96 spin_unlock_irqrestore(&dev->lock, flags); 97 - notify_sigd(dev); 98 return 0; 99 } 100 101 - int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) 102 { 103 unsigned long flags; 104 struct atm_dev_addr *this; 105 int error; 106 107 error = check_addr(addr); 108 if (error) 109 return error; 110 spin_lock_irqsave(&dev->lock, flags); 111 - list_for_each_entry(this, &dev->local, entry) { 112 if (identical(&this->addr, addr)) { 113 list_del(&this->entry); 114 spin_unlock_irqrestore(&dev->lock, flags); 115 kfree(this); 116 - notify_sigd(dev); 117 return 0; 118 } 119 } ··· 130 } 131 132 int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf, 133 - size_t size) 134 { 135 unsigned long flags; 136 struct atm_dev_addr *this; 137 int total = 0, error; 138 struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; 139 140 spin_lock_irqsave(&dev->lock, flags); 141 - list_for_each_entry(this, &dev->local, entry) 142 total += sizeof(struct sockaddr_atmsvc); 143 tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); 144 if (!tmp_buf) { 145 spin_unlock_irqrestore(&dev->lock, flags); 146 return -ENOMEM; 147 } 148 - list_for_each_entry(this, &dev->local, entry) 149 memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc)); 150 spin_unlock_irqrestore(&dev->lock, flags); 151 error = total > size ? -E2BIG : total;
··· 44 sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL); 45 } 46 47 + void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype) 48 { 49 unsigned long flags; 50 struct atm_dev_addr *this, *p; 51 + struct list_head *head; 52 53 spin_lock_irqsave(&dev->lock, flags); 54 + if (atype == ATM_ADDR_LECS) 55 + head = &dev->lecs; 56 + else 57 + head = &dev->local; 58 + list_for_each_entry_safe(this, p, head, entry) { 59 list_del(&this->entry); 60 kfree(this); 61 } 62 spin_unlock_irqrestore(&dev->lock, flags); 63 + if (head == &dev->local) 64 + notify_sigd(dev); 65 } 66 67 + int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, 68 + enum atm_addr_type_t atype) 69 { 70 unsigned long flags; 71 struct atm_dev_addr *this; 72 + struct list_head *head; 73 int error; 74 75 error = check_addr(addr); 76 if (error) 77 return error; 78 spin_lock_irqsave(&dev->lock, flags); 79 + if (atype == ATM_ADDR_LECS) 80 + head = &dev->lecs; 81 + else 82 + head = &dev->local; 83 + list_for_each_entry(this, head, entry) { 84 if (identical(&this->addr, addr)) { 85 spin_unlock_irqrestore(&dev->lock, flags); 86 return -EEXIST; ··· 80 return -ENOMEM; 81 } 82 this->addr = *addr; 83 + list_add(&this->entry, head); 84 spin_unlock_irqrestore(&dev->lock, flags); 85 + if (head == &dev->local) 86 + notify_sigd(dev); 87 return 0; 88 } 89 90 + int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, 91 + enum atm_addr_type_t atype) 92 { 93 unsigned long flags; 94 struct atm_dev_addr *this; 95 + struct list_head *head; 96 int error; 97 98 error = check_addr(addr); 99 if (error) 100 return error; 101 spin_lock_irqsave(&dev->lock, flags); 102 + if (atype == ATM_ADDR_LECS) 103 + head = &dev->lecs; 104 + else 105 + head = &dev->local; 106 + list_for_each_entry(this, head, entry) { 107 if (identical(&this->addr, addr)) { 108 list_del(&this->entry); 109 spin_unlock_irqrestore(&dev->lock, flags); 110 kfree(this); 111 + if (head == &dev->local) 112 + notify_sigd(dev); 113 return 0; 114 } 115 } ··· 110 } 111 112 int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf, 113 + size_t size, enum atm_addr_type_t atype) 114 { 115 unsigned long flags; 116 struct atm_dev_addr *this; 117 + struct list_head *head; 118 int total = 0, error; 119 struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; 120 121 spin_lock_irqsave(&dev->lock, flags); 122 + if (atype == ATM_ADDR_LECS) 123 + head = &dev->lecs; 124 + else 125 + head = &dev->local; 126 + list_for_each_entry(this, head, entry) 127 total += sizeof(struct sockaddr_atmsvc); 128 tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); 129 if (!tmp_buf) { 130 spin_unlock_irqrestore(&dev->lock, flags); 131 return -ENOMEM; 132 } 133 + list_for_each_entry(this, head, entry) 134 memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc)); 135 spin_unlock_irqrestore(&dev->lock, flags); 136 error = total > size ? -E2BIG : total;
+7 -5
net/atm/addr.h
··· 9 #include <linux/atm.h> 10 #include <linux/atmdev.h> 11 12 - 13 - void atm_reset_addr(struct atm_dev *dev); 14 - int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); 15 - int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); 16 - int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc __user *buf,size_t size); 17 18 #endif
··· 9 #include <linux/atm.h> 10 #include <linux/atmdev.h> 11 12 + void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t type); 13 + int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, 14 + enum atm_addr_type_t type); 15 + int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, 16 + enum atm_addr_type_t type); 17 + int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user *buf, 18 + size_t size, enum atm_addr_type_t type); 19 20 #endif
+15 -5
net/atm/resources.c
··· 40 dev->link_rate = ATM_OC3_PCR; 41 spin_lock_init(&dev->lock); 42 INIT_LIST_HEAD(&dev->local); 43 44 return dev; 45 } ··· 321 error = -EPERM; 322 goto done; 323 } 324 - atm_reset_addr(dev); 325 break; 326 case ATM_ADDADDR: 327 case ATM_DELADDR: 328 if (!capable(CAP_NET_ADMIN)) { 329 error = -EPERM; 330 goto done; ··· 338 error = -EFAULT; 339 goto done; 340 } 341 - if (cmd == ATM_ADDADDR) 342 - error = atm_add_addr(dev, &addr); 343 else 344 - error = atm_del_addr(dev, &addr); 345 goto done; 346 } 347 case ATM_GETADDR: 348 - error = atm_get_addr(dev, buf, len); 349 if (error < 0) 350 goto done; 351 size = error;
··· 40 dev->link_rate = ATM_OC3_PCR; 41 spin_lock_init(&dev->lock); 42 INIT_LIST_HEAD(&dev->local); 43 + INIT_LIST_HEAD(&dev->lecs); 44 45 return dev; 46 } ··· 320 error = -EPERM; 321 goto done; 322 } 323 + atm_reset_addr(dev, ATM_ADDR_LOCAL); 324 break; 325 case ATM_ADDADDR: 326 case ATM_DELADDR: 327 + case ATM_ADDLECSADDR: 328 + case ATM_DELLECSADDR: 329 if (!capable(CAP_NET_ADMIN)) { 330 error = -EPERM; 331 goto done; ··· 335 error = -EFAULT; 336 goto done; 337 } 338 + if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) 339 + error = atm_add_addr(dev, &addr, 340 + (cmd == ATM_ADDADDR ? 341 + ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 342 else 343 + error = atm_del_addr(dev, &addr, 344 + (cmd == ATM_DELADDR ? 345 + ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 346 goto done; 347 } 348 case ATM_GETADDR: 349 + case ATM_GETLECSADDR: 350 + error = atm_get_addr(dev, buf, len, 351 + (cmd == ATM_GETADDR ? 352 + ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 353 if (error < 0) 354 goto done; 355 size = error;