diff options
Diffstat (limited to 'net/ipv4/fib_frontend.c')
-rw-r--r-- | net/ipv4/fib_frontend.c | 107 |
1 files changed, 75 insertions, 32 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index d57d4daa9..656acf2c9 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: FIB frontend. * - * Version: $Id: fib_frontend.c,v 1.16 1999/06/09 10:10:42 davem Exp $ + * Version: $Id: fib_frontend.c,v 1.19 1999/08/31 07:03:23 davem Exp $ * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * @@ -142,25 +142,37 @@ fib_get_procinfo(char *buffer, char **start, off_t offset, int length, int dummy * Find the first device with a given source address. */ -struct device * ip_dev_find(u32 addr) +struct net_device * ip_dev_find(u32 addr) { struct rt_key key; struct fib_result res; + struct net_device *dev = NULL; memset(&key, 0, sizeof(key)); key.dst = addr; +#ifdef CONFIG_IP_MULTIPLE_TABLES + res.r = NULL; +#endif - if (!local_table || local_table->tb_lookup(local_table, &key, &res) - || res.type != RTN_LOCAL) + if (!local_table || local_table->tb_lookup(local_table, &key, &res)) { return NULL; - - return FIB_RES_DEV(res); + } + if (res.type != RTN_LOCAL) + goto out; + dev = FIB_RES_DEV(res); + if (dev) + atomic_inc(&dev->refcnt); + +out: + fib_res_put(&res); + return dev; } unsigned inet_addr_type(u32 addr) { struct rt_key key; struct fib_result res; + unsigned ret = RTN_BROADCAST; if (ZERONET(addr) || BADCLASS(addr)) return RTN_BROADCAST; @@ -169,13 +181,18 @@ unsigned inet_addr_type(u32 addr) memset(&key, 0, sizeof(key)); key.dst = addr; - +#ifdef CONFIG_IP_MULTIPLE_TABLES + res.r = NULL; +#endif + if (local_table) { - if (local_table->tb_lookup(local_table, &key, &res) == 0) - return res.type; - return RTN_UNICAST; + ret = RTN_UNICAST; + if (local_table->tb_lookup(local_table, &key, &res) == 0) { + ret = res.type; + fib_res_put(&res); + } } - return RTN_BROADCAST; + return ret; } /* Given (packet source, input interface) and optional (dst, oif, tos): @@ -187,11 +204,13 @@ unsigned inet_addr_type(u32 addr) */ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, - struct device *dev, u32 *spec_dst, u32 *itag) + struct net_device *dev, u32 *spec_dst, u32 *itag) { - struct in_device *in_dev = dev->ip_ptr; + struct in_device *in_dev; struct rt_key key; struct fib_result res; + int no_addr, rpf; + int ret; key.dst = src; key.src = dst; @@ -200,12 +219,22 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, key.iif = oif; key.scope = RT_SCOPE_UNIVERSE; + no_addr = rpf = 0; + read_lock(&inetdev_lock); + in_dev = __in_dev_get(dev); + if (in_dev) { + no_addr = in_dev->ifa_list == NULL; + rpf = IN_DEV_RPFILTER(in_dev); + } + read_unlock(&inetdev_lock); + if (in_dev == NULL) - return -EINVAL; + goto e_inval; + if (fib_lookup(&key, &res)) goto last_resort; if (res.type != RTN_UNICAST) - return -EINVAL; + goto e_inval_res; *spec_dst = FIB_RES_PREFSRC(res); if (itag) fib_combine_itag(itag, &res); @@ -214,25 +243,39 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, #else if (FIB_RES_DEV(res) == dev) #endif - return FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; - - if (in_dev->ifa_list == NULL) + { + ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; + fib_res_put(&res); + return ret; + } + fib_res_put(&res); + if (no_addr) goto last_resort; - if (IN_DEV_RPFILTER(in_dev)) - return -EINVAL; + if (rpf) + goto e_inval; key.oif = dev->ifindex; - if (fib_lookup(&key, &res) == 0 && res.type == RTN_UNICAST) { - *spec_dst = FIB_RES_PREFSRC(res); - return FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; + + ret = 0; + if (fib_lookup(&key, &res) == 0) { + if (res.type == RTN_UNICAST) { + *spec_dst = FIB_RES_PREFSRC(res); + ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; + } + fib_res_put(&res); } - return 0; + return ret; last_resort: - if (IN_DEV_RPFILTER(in_dev)) - return -EINVAL; + if (rpf) + goto e_inval; *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); *itag = 0; return 0; + +e_inval_res: + fib_res_put(&res); +e_inval: + return -EINVAL; } #ifndef CONFIG_IP_NOSIOCRT @@ -421,7 +464,7 @@ static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr static void fib_add_ifaddr(struct in_ifaddr *ifa) { struct in_device *in_dev = ifa->ifa_dev; - struct device *dev = in_dev->dev; + struct net_device *dev = in_dev->dev; struct in_ifaddr *prim = ifa; u32 mask = ifa->ifa_mask; u32 addr = ifa->ifa_local; @@ -460,7 +503,7 @@ static void fib_add_ifaddr(struct in_ifaddr *ifa) static void fib_del_ifaddr(struct in_ifaddr *ifa) { struct in_device *in_dev = ifa->ifa_dev; - struct device *dev = in_dev->dev; + struct net_device *dev = in_dev->dev; struct in_ifaddr *ifa1; struct in_ifaddr *prim = ifa; u32 brd = ifa->ifa_address|~ifa->ifa_mask; @@ -526,7 +569,7 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) #undef BRD1_OK } -static void fib_disable_ip(struct device *dev, int force) +static void fib_disable_ip(struct net_device *dev, int force) { if (fib_sync_down(0, dev, force)) fib_flush(); @@ -560,8 +603,8 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { - struct device *dev = ptr; - struct in_device *in_dev = dev->ip_ptr; + struct net_device *dev = ptr; + struct in_device *in_dev = __in_dev_get(dev); if (!in_dev) return NOTIFY_DONE; @@ -602,7 +645,7 @@ struct notifier_block fib_netdev_notifier = { 0 }; -__initfunc(void ip_fib_init(void)) +void __init ip_fib_init(void) { #ifdef CONFIG_PROC_FS proc_net_register(&(struct proc_dir_entry) { |