diff options
author | Ralf Baechle DL5RB <ralf@linux-mips.org> | 2006-07-03 22:30:18 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-07-03 22:30:18 -0400 |
commit | 006f68b84fe19fc5015a8cf838a10d75f91f0218 (patch) | |
tree | 2c9377778e4e09bb8d10084341207ba1352f600a /net | |
parent | 8dc22d2b642f8a6f14ef8878777a05311e5d1d7e (diff) |
[AX.25]: Reference counting for AX.25 routes.
In the past routes could be freed even though the were possibly in use ...
Signed-off-by: Ralf Baechle DL5RB <ralf@linux-mips.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ax25/ax25_ip.c | 23 | ||||
-rw-r--r-- | net/ax25/ax25_route.c | 49 |
2 files changed, 23 insertions, 49 deletions
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index 9be5c15e63d3..136c3aefa9de 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c | |||
@@ -103,11 +103,13 @@ int ax25_rebuild_header(struct sk_buff *skb) | |||
103 | { | 103 | { |
104 | struct sk_buff *ourskb; | 104 | struct sk_buff *ourskb; |
105 | unsigned char *bp = skb->data; | 105 | unsigned char *bp = skb->data; |
106 | struct net_device *dev; | 106 | ax25_route *route; |
107 | struct net_device *dev = NULL; | ||
107 | ax25_address *src, *dst; | 108 | ax25_address *src, *dst; |
109 | ax25_digi *digipeat = NULL; | ||
108 | ax25_dev *ax25_dev; | 110 | ax25_dev *ax25_dev; |
109 | ax25_route _route, *route = &_route; | ||
110 | ax25_cb *ax25; | 111 | ax25_cb *ax25; |
112 | char ip_mode = ' '; | ||
111 | 113 | ||
112 | dst = (ax25_address *)(bp + 1); | 114 | dst = (ax25_address *)(bp + 1); |
113 | src = (ax25_address *)(bp + 8); | 115 | src = (ax25_address *)(bp + 8); |
@@ -115,8 +117,12 @@ int ax25_rebuild_header(struct sk_buff *skb) | |||
115 | if (arp_find(bp + 1, skb)) | 117 | if (arp_find(bp + 1, skb)) |
116 | return 1; | 118 | return 1; |
117 | 119 | ||
118 | route = ax25_rt_find_route(route, dst, NULL); | 120 | route = ax25_get_route(dst, NULL); |
119 | dev = route->dev; | 121 | if (route) { |
122 | digipeat = route->digipeat; | ||
123 | dev = route->dev; | ||
124 | ip_mode = route->ip_mode; | ||
125 | }; | ||
120 | 126 | ||
121 | if (dev == NULL) | 127 | if (dev == NULL) |
122 | dev = skb->dev; | 128 | dev = skb->dev; |
@@ -126,7 +132,7 @@ int ax25_rebuild_header(struct sk_buff *skb) | |||
126 | } | 132 | } |
127 | 133 | ||
128 | if (bp[16] == AX25_P_IP) { | 134 | if (bp[16] == AX25_P_IP) { |
129 | if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) { | 135 | if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) { |
130 | /* | 136 | /* |
131 | * We copy the buffer and release the original thereby | 137 | * We copy the buffer and release the original thereby |
132 | * keeping it straight | 138 | * keeping it straight |
@@ -172,7 +178,7 @@ int ax25_rebuild_header(struct sk_buff *skb) | |||
172 | ourskb, | 178 | ourskb, |
173 | ax25_dev->values[AX25_VALUES_PACLEN], | 179 | ax25_dev->values[AX25_VALUES_PACLEN], |
174 | &src_c, | 180 | &src_c, |
175 | &dst_c, route->digipeat, dev); | 181 | &dst_c, digipeat, dev); |
176 | if (ax25) { | 182 | if (ax25) { |
177 | ax25_cb_put(ax25); | 183 | ax25_cb_put(ax25); |
178 | } | 184 | } |
@@ -190,7 +196,7 @@ int ax25_rebuild_header(struct sk_buff *skb) | |||
190 | 196 | ||
191 | skb_pull(skb, AX25_KISS_HEADER_LEN); | 197 | skb_pull(skb, AX25_KISS_HEADER_LEN); |
192 | 198 | ||
193 | if (route->digipeat != NULL) { | 199 | if (digipeat != NULL) { |
194 | if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) { | 200 | if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) { |
195 | kfree_skb(skb); | 201 | kfree_skb(skb); |
196 | goto put; | 202 | goto put; |
@@ -202,7 +208,8 @@ int ax25_rebuild_header(struct sk_buff *skb) | |||
202 | ax25_queue_xmit(skb, dev); | 208 | ax25_queue_xmit(skb, dev); |
203 | 209 | ||
204 | put: | 210 | put: |
205 | ax25_put_route(route); | 211 | if (route) |
212 | ax25_put_route(route); | ||
206 | 213 | ||
207 | return 1; | 214 | return 1; |
208 | } | 215 | } |
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index 5ac98250797b..51b7bdaf27eb 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c | |||
@@ -41,8 +41,6 @@ | |||
41 | static ax25_route *ax25_route_list; | 41 | static ax25_route *ax25_route_list; |
42 | static DEFINE_RWLOCK(ax25_route_lock); | 42 | static DEFINE_RWLOCK(ax25_route_lock); |
43 | 43 | ||
44 | static ax25_route *ax25_get_route(ax25_address *, struct net_device *); | ||
45 | |||
46 | void ax25_rt_device_down(struct net_device *dev) | 44 | void ax25_rt_device_down(struct net_device *dev) |
47 | { | 45 | { |
48 | ax25_route *s, *t, *ax25_rt; | 46 | ax25_route *s, *t, *ax25_rt; |
@@ -115,7 +113,7 @@ static int ax25_rt_add(struct ax25_routes_struct *route) | |||
115 | return -ENOMEM; | 113 | return -ENOMEM; |
116 | } | 114 | } |
117 | 115 | ||
118 | atomic_set(&ax25_rt->ref, 0); | 116 | atomic_set(&ax25_rt->refcount, 1); |
119 | ax25_rt->callsign = route->dest_addr; | 117 | ax25_rt->callsign = route->dest_addr; |
120 | ax25_rt->dev = ax25_dev->dev; | 118 | ax25_rt->dev = ax25_dev->dev; |
121 | ax25_rt->digipeat = NULL; | 119 | ax25_rt->digipeat = NULL; |
@@ -140,23 +138,10 @@ static int ax25_rt_add(struct ax25_routes_struct *route) | |||
140 | return 0; | 138 | return 0; |
141 | } | 139 | } |
142 | 140 | ||
143 | static void ax25_rt_destroy(ax25_route *ax25_rt) | 141 | void __ax25_put_route(ax25_route *ax25_rt) |
144 | { | 142 | { |
145 | if (atomic_read(&ax25_rt->ref) == 0) { | 143 | kfree(ax25_rt->digipeat); |
146 | kfree(ax25_rt->digipeat); | 144 | kfree(ax25_rt); |
147 | kfree(ax25_rt); | ||
148 | return; | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * Uh... Route is still in use; we can't yet destroy it. Retry later. | ||
153 | */ | ||
154 | init_timer(&ax25_rt->timer); | ||
155 | ax25_rt->timer.data = (unsigned long) ax25_rt; | ||
156 | ax25_rt->timer.function = (void *) ax25_rt_destroy; | ||
157 | ax25_rt->timer.expires = jiffies + 5 * HZ; | ||
158 | |||
159 | add_timer(&ax25_rt->timer); | ||
160 | } | 145 | } |
161 | 146 | ||
162 | static int ax25_rt_del(struct ax25_routes_struct *route) | 147 | static int ax25_rt_del(struct ax25_routes_struct *route) |
@@ -177,12 +162,12 @@ static int ax25_rt_del(struct ax25_routes_struct *route) | |||
177 | ax25cmp(&route->dest_addr, &s->callsign) == 0) { | 162 | ax25cmp(&route->dest_addr, &s->callsign) == 0) { |
178 | if (ax25_route_list == s) { | 163 | if (ax25_route_list == s) { |
179 | ax25_route_list = s->next; | 164 | ax25_route_list = s->next; |
180 | ax25_rt_destroy(s); | 165 | ax25_put_route(s); |
181 | } else { | 166 | } else { |
182 | for (t = ax25_route_list; t != NULL; t = t->next) { | 167 | for (t = ax25_route_list; t != NULL; t = t->next) { |
183 | if (t->next == s) { | 168 | if (t->next == s) { |
184 | t->next = s->next; | 169 | t->next = s->next; |
185 | ax25_rt_destroy(s); | 170 | ax25_put_route(s); |
186 | break; | 171 | break; |
187 | } | 172 | } |
188 | } | 173 | } |
@@ -362,7 +347,7 @@ struct file_operations ax25_route_fops = { | |||
362 | * | 347 | * |
363 | * Only routes with a reference count of zero can be destroyed. | 348 | * Only routes with a reference count of zero can be destroyed. |
364 | */ | 349 | */ |
365 | static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) | 350 | ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) |
366 | { | 351 | { |
367 | ax25_route *ax25_spe_rt = NULL; | 352 | ax25_route *ax25_spe_rt = NULL; |
368 | ax25_route *ax25_def_rt = NULL; | 353 | ax25_route *ax25_def_rt = NULL; |
@@ -392,7 +377,7 @@ static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) | |||
392 | ax25_rt = ax25_spe_rt; | 377 | ax25_rt = ax25_spe_rt; |
393 | 378 | ||
394 | if (ax25_rt != NULL) | 379 | if (ax25_rt != NULL) |
395 | atomic_inc(&ax25_rt->ref); | 380 | ax25_hold_route(ax25_rt); |
396 | 381 | ||
397 | read_unlock(&ax25_route_lock); | 382 | read_unlock(&ax25_route_lock); |
398 | 383 | ||
@@ -467,24 +452,6 @@ put: | |||
467 | return 0; | 452 | return 0; |
468 | } | 453 | } |
469 | 454 | ||
470 | ax25_route *ax25_rt_find_route(ax25_route * route, ax25_address *addr, | ||
471 | struct net_device *dev) | ||
472 | { | ||
473 | ax25_route *ax25_rt; | ||
474 | |||
475 | if ((ax25_rt = ax25_get_route(addr, dev))) | ||
476 | return ax25_rt; | ||
477 | |||
478 | route->next = NULL; | ||
479 | atomic_set(&route->ref, 1); | ||
480 | route->callsign = *addr; | ||
481 | route->dev = dev; | ||
482 | route->digipeat = NULL; | ||
483 | route->ip_mode = ' '; | ||
484 | |||
485 | return route; | ||
486 | } | ||
487 | |||
488 | struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, | 455 | struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, |
489 | ax25_address *dest, ax25_digi *digi) | 456 | ax25_address *dest, ax25_digi *digi) |
490 | { | 457 | { |