diff options
author | Eric Kinzie <ekinzie@cmf.nrl.navy.mil> | 2005-10-07 01:19:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-10-07 01:19:28 -0400 |
commit | 0f21ba7cc3320d33459ecb3f538f1a42040c29cd (patch) | |
tree | 158b360de6547262d99f4861ac166709a7e17172 | |
parent | 20c9c825b12fcb8526a29cf20a17a5a3fc581726 (diff) |
[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>
-rw-r--r-- | include/linux/atmdev.h | 10 | ||||
-rw-r--r-- | net/atm/addr.c | 51 | ||||
-rw-r--r-- | net/atm/addr.h | 12 | ||||
-rw-r--r-- | net/atm/resources.c | 20 |
4 files changed, 70 insertions, 23 deletions
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index f1fd849e5535..aca9b344bd35 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h | |||
@@ -76,6 +76,13 @@ struct atm_dev_stats { | |||
76 | /* set interface ESI */ | 76 | /* set interface ESI */ |
77 | #define ATM_SETESIF _IOW('a',ATMIOC_ITF+13,struct atmif_sioc) | 77 | #define ATM_SETESIF _IOW('a',ATMIOC_ITF+13,struct atmif_sioc) |
78 | /* force interface ESI */ | 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 | #define ATM_GETSTAT _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc) | 86 | #define ATM_GETSTAT _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc) |
80 | /* get AAL layer statistics */ | 87 | /* get AAL layer statistics */ |
81 | #define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc) | 88 | #define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc) |
@@ -328,6 +335,8 @@ struct atm_dev_addr { | |||
328 | struct list_head entry; /* next address */ | 335 | struct list_head entry; /* next address */ |
329 | }; | 336 | }; |
330 | 337 | ||
338 | enum atm_addr_type_t { ATM_ADDR_LOCAL, ATM_ADDR_LECS }; | ||
339 | |||
331 | struct atm_dev { | 340 | struct atm_dev { |
332 | const struct atmdev_ops *ops; /* device operations; NULL if unused */ | 341 | const struct atmdev_ops *ops; /* device operations; NULL if unused */ |
333 | const struct atmphy_ops *phy; /* PHY operations, may be undefined */ | 342 | const struct atmphy_ops *phy; /* PHY operations, may be undefined */ |
@@ -338,6 +347,7 @@ struct atm_dev { | |||
338 | void *phy_data; /* private PHY date */ | 347 | void *phy_data; /* private PHY date */ |
339 | unsigned long flags; /* device flags (ATM_DF_*) */ | 348 | unsigned long flags; /* device flags (ATM_DF_*) */ |
340 | struct list_head local; /* local ATM addresses */ | 349 | struct list_head local; /* local ATM addresses */ |
350 | struct list_head lecs; /* LECS ATM addresses learned via ILMI */ | ||
341 | unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */ | 351 | unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */ |
342 | struct atm_cirange ci_range; /* VPI/VCI range */ | 352 | struct atm_cirange ci_range; /* VPI/VCI range */ |
343 | struct k_atm_dev_stats stats; /* statistics */ | 353 | struct k_atm_dev_stats stats; /* statistics */ |
diff --git a/net/atm/addr.c b/net/atm/addr.c index a30d0bf48063..3060fd0ba4b9 100644 --- a/net/atm/addr.c +++ b/net/atm/addr.c | |||
@@ -44,31 +44,43 @@ static void notify_sigd(struct atm_dev *dev) | |||
44 | sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL); | 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 | unsigned long flags; | 49 | unsigned long flags; |
50 | struct atm_dev_addr *this, *p; | 50 | struct atm_dev_addr *this, *p; |
51 | struct list_head *head; | ||
51 | 52 | ||
52 | spin_lock_irqsave(&dev->lock, flags); | 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 | list_del(&this->entry); | 59 | list_del(&this->entry); |
55 | kfree(this); | 60 | kfree(this); |
56 | } | 61 | } |
57 | spin_unlock_irqrestore(&dev->lock, flags); | 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 | unsigned long flags; | 70 | unsigned long flags; |
64 | struct atm_dev_addr *this; | 71 | struct atm_dev_addr *this; |
72 | struct list_head *head; | ||
65 | int error; | 73 | int error; |
66 | 74 | ||
67 | error = check_addr(addr); | 75 | error = check_addr(addr); |
68 | if (error) | 76 | if (error) |
69 | return error; | 77 | return error; |
70 | spin_lock_irqsave(&dev->lock, flags); | 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 | if (identical(&this->addr, addr)) { | 84 | if (identical(&this->addr, addr)) { |
73 | spin_unlock_irqrestore(&dev->lock, flags); | 85 | spin_unlock_irqrestore(&dev->lock, flags); |
74 | return -EEXIST; | 86 | return -EEXIST; |
@@ -80,28 +92,36 @@ int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) | |||
80 | return -ENOMEM; | 92 | return -ENOMEM; |
81 | } | 93 | } |
82 | this->addr = *addr; | 94 | this->addr = *addr; |
83 | list_add(&this->entry, &dev->local); | 95 | list_add(&this->entry, head); |
84 | spin_unlock_irqrestore(&dev->lock, flags); | 96 | spin_unlock_irqrestore(&dev->lock, flags); |
85 | notify_sigd(dev); | 97 | if (head == &dev->local) |
98 | notify_sigd(dev); | ||
86 | return 0; | 99 | return 0; |
87 | } | 100 | } |
88 | 101 | ||
89 | int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) | 102 | int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, |
103 | enum atm_addr_type_t atype) | ||
90 | { | 104 | { |
91 | unsigned long flags; | 105 | unsigned long flags; |
92 | struct atm_dev_addr *this; | 106 | struct atm_dev_addr *this; |
107 | struct list_head *head; | ||
93 | int error; | 108 | int error; |
94 | 109 | ||
95 | error = check_addr(addr); | 110 | error = check_addr(addr); |
96 | if (error) | 111 | if (error) |
97 | return error; | 112 | return error; |
98 | spin_lock_irqsave(&dev->lock, flags); | 113 | spin_lock_irqsave(&dev->lock, flags); |
99 | list_for_each_entry(this, &dev->local, entry) { | 114 | if (atype == ATM_ADDR_LECS) |
115 | head = &dev->lecs; | ||
116 | else | ||
117 | head = &dev->local; | ||
118 | list_for_each_entry(this, head, entry) { | ||
100 | if (identical(&this->addr, addr)) { | 119 | if (identical(&this->addr, addr)) { |
101 | list_del(&this->entry); | 120 | list_del(&this->entry); |
102 | spin_unlock_irqrestore(&dev->lock, flags); | 121 | spin_unlock_irqrestore(&dev->lock, flags); |
103 | kfree(this); | 122 | kfree(this); |
104 | notify_sigd(dev); | 123 | if (head == &dev->local) |
124 | notify_sigd(dev); | ||
105 | return 0; | 125 | return 0; |
106 | } | 126 | } |
107 | } | 127 | } |
@@ -110,22 +130,27 @@ int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) | |||
110 | } | 130 | } |
111 | 131 | ||
112 | int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf, | 132 | int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf, |
113 | size_t size) | 133 | size_t size, enum atm_addr_type_t atype) |
114 | { | 134 | { |
115 | unsigned long flags; | 135 | unsigned long flags; |
116 | struct atm_dev_addr *this; | 136 | struct atm_dev_addr *this; |
137 | struct list_head *head; | ||
117 | int total = 0, error; | 138 | int total = 0, error; |
118 | struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; | 139 | struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; |
119 | 140 | ||
120 | spin_lock_irqsave(&dev->lock, flags); | 141 | spin_lock_irqsave(&dev->lock, flags); |
121 | list_for_each_entry(this, &dev->local, entry) | 142 | if (atype == ATM_ADDR_LECS) |
143 | head = &dev->lecs; | ||
144 | else | ||
145 | head = &dev->local; | ||
146 | list_for_each_entry(this, head, entry) | ||
122 | total += sizeof(struct sockaddr_atmsvc); | 147 | total += sizeof(struct sockaddr_atmsvc); |
123 | tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); | 148 | tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); |
124 | if (!tmp_buf) { | 149 | if (!tmp_buf) { |
125 | spin_unlock_irqrestore(&dev->lock, flags); | 150 | spin_unlock_irqrestore(&dev->lock, flags); |
126 | return -ENOMEM; | 151 | return -ENOMEM; |
127 | } | 152 | } |
128 | list_for_each_entry(this, &dev->local, entry) | 153 | list_for_each_entry(this, head, entry) |
129 | memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc)); | 154 | memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc)); |
130 | spin_unlock_irqrestore(&dev->lock, flags); | 155 | spin_unlock_irqrestore(&dev->lock, flags); |
131 | error = total > size ? -E2BIG : total; | 156 | error = total > size ? -E2BIG : total; |
diff --git a/net/atm/addr.h b/net/atm/addr.h index 3099d21feeaa..f39433ad45da 100644 --- a/net/atm/addr.h +++ b/net/atm/addr.h | |||
@@ -9,10 +9,12 @@ | |||
9 | #include <linux/atm.h> | 9 | #include <linux/atm.h> |
10 | #include <linux/atmdev.h> | 10 | #include <linux/atmdev.h> |
11 | 11 | ||
12 | 12 | void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t type); | |
13 | void atm_reset_addr(struct atm_dev *dev); | 13 | int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, |
14 | 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); | 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); | 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 | #endif | 20 | #endif |
diff --git a/net/atm/resources.c b/net/atm/resources.c index a57a9268bd24..415d2615d475 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c | |||
@@ -40,6 +40,7 @@ static struct atm_dev *__alloc_atm_dev(const char *type) | |||
40 | dev->link_rate = ATM_OC3_PCR; | 40 | dev->link_rate = ATM_OC3_PCR; |
41 | spin_lock_init(&dev->lock); | 41 | spin_lock_init(&dev->lock); |
42 | INIT_LIST_HEAD(&dev->local); | 42 | INIT_LIST_HEAD(&dev->local); |
43 | INIT_LIST_HEAD(&dev->lecs); | ||
43 | 44 | ||
44 | return dev; | 45 | return dev; |
45 | } | 46 | } |
@@ -320,10 +321,12 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
320 | error = -EPERM; | 321 | error = -EPERM; |
321 | goto done; | 322 | goto done; |
322 | } | 323 | } |
323 | atm_reset_addr(dev); | 324 | atm_reset_addr(dev, ATM_ADDR_LOCAL); |
324 | break; | 325 | break; |
325 | case ATM_ADDADDR: | 326 | case ATM_ADDADDR: |
326 | case ATM_DELADDR: | 327 | case ATM_DELADDR: |
328 | case ATM_ADDLECSADDR: | ||
329 | case ATM_DELLECSADDR: | ||
327 | if (!capable(CAP_NET_ADMIN)) { | 330 | if (!capable(CAP_NET_ADMIN)) { |
328 | error = -EPERM; | 331 | error = -EPERM; |
329 | goto done; | 332 | goto done; |
@@ -335,14 +338,21 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
335 | error = -EFAULT; | 338 | error = -EFAULT; |
336 | goto done; | 339 | goto done; |
337 | } | 340 | } |
338 | if (cmd == ATM_ADDADDR) | 341 | if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) |
339 | error = atm_add_addr(dev, &addr); | 342 | error = atm_add_addr(dev, &addr, |
343 | (cmd == ATM_ADDADDR ? | ||
344 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
340 | else | 345 | else |
341 | error = atm_del_addr(dev, &addr); | 346 | error = atm_del_addr(dev, &addr, |
347 | (cmd == ATM_DELADDR ? | ||
348 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
342 | goto done; | 349 | goto done; |
343 | } | 350 | } |
344 | case ATM_GETADDR: | 351 | case ATM_GETADDR: |
345 | error = atm_get_addr(dev, buf, len); | 352 | case ATM_GETLECSADDR: |
353 | error = atm_get_addr(dev, buf, len, | ||
354 | (cmd == ATM_GETADDR ? | ||
355 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
346 | if (error < 0) | 356 | if (error < 0) |
347 | goto done; | 357 | goto done; |
348 | size = error; | 358 | size = error; |