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