X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fax25%2Fax25_route.c;h=5ac98250797bf8de2e1a0e5b158ce19315d55bd3;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=51b7bdaf27eb4877d0155b55b0a749a1f7cff8ff;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index 51b7bdaf2..5ac982507 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c @@ -41,6 +41,8 @@ static ax25_route *ax25_route_list; static DEFINE_RWLOCK(ax25_route_lock); +static ax25_route *ax25_get_route(ax25_address *, struct net_device *); + void ax25_rt_device_down(struct net_device *dev) { ax25_route *s, *t, *ax25_rt; @@ -113,7 +115,7 @@ static int ax25_rt_add(struct ax25_routes_struct *route) return -ENOMEM; } - atomic_set(&ax25_rt->refcount, 1); + atomic_set(&ax25_rt->ref, 0); ax25_rt->callsign = route->dest_addr; ax25_rt->dev = ax25_dev->dev; ax25_rt->digipeat = NULL; @@ -138,10 +140,23 @@ static int ax25_rt_add(struct ax25_routes_struct *route) return 0; } -void __ax25_put_route(ax25_route *ax25_rt) +static void ax25_rt_destroy(ax25_route *ax25_rt) { - kfree(ax25_rt->digipeat); - kfree(ax25_rt); + if (atomic_read(&ax25_rt->ref) == 0) { + kfree(ax25_rt->digipeat); + kfree(ax25_rt); + return; + } + + /* + * Uh... Route is still in use; we can't yet destroy it. Retry later. + */ + init_timer(&ax25_rt->timer); + ax25_rt->timer.data = (unsigned long) ax25_rt; + ax25_rt->timer.function = (void *) ax25_rt_destroy; + ax25_rt->timer.expires = jiffies + 5 * HZ; + + add_timer(&ax25_rt->timer); } static int ax25_rt_del(struct ax25_routes_struct *route) @@ -162,12 +177,12 @@ static int ax25_rt_del(struct ax25_routes_struct *route) ax25cmp(&route->dest_addr, &s->callsign) == 0) { if (ax25_route_list == s) { ax25_route_list = s->next; - ax25_put_route(s); + ax25_rt_destroy(s); } else { for (t = ax25_route_list; t != NULL; t = t->next) { if (t->next == s) { t->next = s->next; - ax25_put_route(s); + ax25_rt_destroy(s); break; } } @@ -347,7 +362,7 @@ struct file_operations ax25_route_fops = { * * Only routes with a reference count of zero can be destroyed. */ -ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) +static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) { ax25_route *ax25_spe_rt = NULL; ax25_route *ax25_def_rt = NULL; @@ -377,7 +392,7 @@ ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) ax25_rt = ax25_spe_rt; if (ax25_rt != NULL) - ax25_hold_route(ax25_rt); + atomic_inc(&ax25_rt->ref); read_unlock(&ax25_route_lock); @@ -452,6 +467,24 @@ put: return 0; } +ax25_route *ax25_rt_find_route(ax25_route * route, ax25_address *addr, + struct net_device *dev) +{ + ax25_route *ax25_rt; + + if ((ax25_rt = ax25_get_route(addr, dev))) + return ax25_rt; + + route->next = NULL; + atomic_set(&route->ref, 1); + route->callsign = *addr; + route->dev = dev; + route->digipeat = NULL; + route->ip_mode = ' '; + + return route; +} + struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_address *dest, ax25_digi *digi) {