aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ax25.h24
-rw-r--r--net/ax25/ax25_ip.c23
-rw-r--r--net/ax25/ax25_route.c49
3 files changed, 38 insertions, 58 deletions
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 7cd528e9d668..69374cd1a857 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -182,14 +182,26 @@ typedef struct {
182 182
183typedef struct ax25_route { 183typedef struct ax25_route {
184 struct ax25_route *next; 184 struct ax25_route *next;
185 atomic_t ref; 185 atomic_t refcount;
186 ax25_address callsign; 186 ax25_address callsign;
187 struct net_device *dev; 187 struct net_device *dev;
188 ax25_digi *digipeat; 188 ax25_digi *digipeat;
189 char ip_mode; 189 char ip_mode;
190 struct timer_list timer;
191} ax25_route; 190} ax25_route;
192 191
192static inline void ax25_hold_route(ax25_route *ax25_rt)
193{
194 atomic_inc(&ax25_rt->refcount);
195}
196
197extern void __ax25_put_route(ax25_route *ax25_rt);
198
199static inline void ax25_put_route(ax25_route *ax25_rt)
200{
201 if (atomic_dec_and_test(&ax25_rt->refcount))
202 __ax25_put_route(ax25_rt);
203}
204
193typedef struct { 205typedef struct {
194 char slave; /* slave_mode? */ 206 char slave; /* slave_mode? */
195 struct timer_list slave_timer; /* timeout timer */ 207 struct timer_list slave_timer; /* timeout timer */
@@ -348,17 +360,11 @@ extern int ax25_check_iframes_acked(ax25_cb *, unsigned short);
348extern void ax25_rt_device_down(struct net_device *); 360extern void ax25_rt_device_down(struct net_device *);
349extern int ax25_rt_ioctl(unsigned int, void __user *); 361extern int ax25_rt_ioctl(unsigned int, void __user *);
350extern struct file_operations ax25_route_fops; 362extern struct file_operations ax25_route_fops;
363extern ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev);
351extern int ax25_rt_autobind(ax25_cb *, ax25_address *); 364extern int ax25_rt_autobind(ax25_cb *, ax25_address *);
352extern ax25_route *ax25_rt_find_route(ax25_route *, ax25_address *,
353 struct net_device *);
354extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *); 365extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *);
355extern void ax25_rt_free(void); 366extern void ax25_rt_free(void);
356 367
357static inline void ax25_put_route(ax25_route *ax25_rt)
358{
359 atomic_dec(&ax25_rt->ref);
360}
361
362/* ax25_std_in.c */ 368/* ax25_std_in.c */
363extern int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int); 369extern int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int);
364 370
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
204put: 210put:
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 @@
41static ax25_route *ax25_route_list; 41static ax25_route *ax25_route_list;
42static DEFINE_RWLOCK(ax25_route_lock); 42static DEFINE_RWLOCK(ax25_route_lock);
43 43
44static ax25_route *ax25_get_route(ax25_address *, struct net_device *);
45
46void ax25_rt_device_down(struct net_device *dev) 44void 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
143static void ax25_rt_destroy(ax25_route *ax25_rt) 141void __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
162static int ax25_rt_del(struct ax25_routes_struct *route) 147static 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 */
365static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) 350ax25_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
470ax25_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
488struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, 455struct 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{