Commit 44d28ab1 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-next-2.6-v6ready-20080703' of...

Merge branch 'net-next-2.6-v6ready-20080703' of git://git.linux-ipv6.org/gitroot/yoshfuji/linux-2.6-next
parents 40b215e5 e0835f8f
...@@ -1025,6 +1025,17 @@ max_addresses - INTEGER ...@@ -1025,6 +1025,17 @@ max_addresses - INTEGER
autoconfigured addresses. autoconfigured addresses.
Default: 16 Default: 16
disable_ipv6 - BOOLEAN
Disable IPv6 operation.
Default: FALSE (enable IPv6 operation)
accept_dad - INTEGER
Whether to accept DAD (Duplicate Address Detection).
0: Disable DAD
1: Enable DAD (default)
2: Enable DAD, and disable IPv6 operation if MAC-based duplicate
link-local address has been found.
icmp/*: icmp/*:
ratelimit - INTEGER ratelimit - INTEGER
Limit the maximal rates for sending ICMPv6 packets. Limit the maximal rates for sending ICMPv6 packets.
......
...@@ -228,7 +228,6 @@ extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, ...@@ -228,7 +228,6 @@ extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
struct group_filter __user *optval, int __user *optlen); struct group_filter __user *optval, int __user *optlen);
extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif); extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif);
extern void ip_mr_init(void);
extern void ip_mc_init_dev(struct in_device *); extern void ip_mc_init_dev(struct in_device *);
extern void ip_mc_destroy_dev(struct in_device *); extern void ip_mc_destroy_dev(struct in_device *);
extern void ip_mc_up(struct in_device *); extern void ip_mc_up(struct in_device *);
......
...@@ -163,6 +163,8 @@ struct ipv6_devconf { ...@@ -163,6 +163,8 @@ struct ipv6_devconf {
#ifdef CONFIG_IPV6_MROUTE #ifdef CONFIG_IPV6_MROUTE
__s32 mc_forwarding; __s32 mc_forwarding;
#endif #endif
__s32 disable_ipv6;
__s32 accept_dad;
void *sysctl; void *sysctl;
}; };
...@@ -194,6 +196,8 @@ enum { ...@@ -194,6 +196,8 @@ enum {
DEVCONF_OPTIMISTIC_DAD, DEVCONF_OPTIMISTIC_DAD,
DEVCONF_ACCEPT_SOURCE_ROUTE, DEVCONF_ACCEPT_SOURCE_ROUTE,
DEVCONF_MC_FORWARDING, DEVCONF_MC_FORWARDING,
DEVCONF_DISABLE_IPV6,
DEVCONF_ACCEPT_DAD,
DEVCONF_MAX DEVCONF_MAX
}; };
......
...@@ -144,11 +144,37 @@ static inline int ip_mroute_opt(int opt) ...@@ -144,11 +144,37 @@ static inline int ip_mroute_opt(int opt)
} }
#endif #endif
#ifdef CONFIG_IP_MROUTE
extern int ip_mroute_setsockopt(struct sock *, int, char __user *, int); extern int ip_mroute_setsockopt(struct sock *, int, char __user *, int);
extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *); extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg); extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);
extern void ip_mr_init(void); extern int ip_mr_init(void);
#else
static inline
int ip_mroute_setsockopt(struct sock *sock,
int optname, char __user *optval, int optlen)
{
return -ENOPROTOOPT;
}
static inline
int ip_mroute_getsockopt(struct sock *sock,
int optname, char __user *optval, int __user *optlen)
{
return -ENOPROTOOPT;
}
static inline
int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
{
return -ENOIOCTLCMD;
}
static inline int ip_mr_init(void)
{
return 0;
}
#endif
struct vif_device struct vif_device
{ {
......
...@@ -131,11 +131,44 @@ static inline int ip6_mroute_opt(int opt) ...@@ -131,11 +131,44 @@ static inline int ip6_mroute_opt(int opt)
struct sock; struct sock;
#ifdef CONFIG_IPV6_MROUTE
extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int); extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int);
extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *); extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
extern int ip6_mr_input(struct sk_buff *skb); extern int ip6_mr_input(struct sk_buff *skb);
extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg); extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg);
extern void ip6_mr_init(void); extern int ip6_mr_init(void);
extern void ip6_mr_cleanup(void);
#else
static inline
int ip6_mroute_setsockopt(struct sock *sock,
int optname, char __user *optval, int optlen)
{
return -ENOPROTOOPT;
}
static inline
int ip6_mroute_getsockopt(struct sock *sock,
int optname, char __user *optval, int __user *optlen)
{
return -ENOPROTOOPT;
}
static inline
int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
{
return -ENOIOCTLCMD;
}
static inline int ip6_mr_init(void)
{
return 0;
}
static inline void ip6_mr_cleanup(void)
{
return;
}
#endif
struct mif_device struct mif_device
{ {
......
...@@ -1479,14 +1479,15 @@ static int __init inet_init(void) ...@@ -1479,14 +1479,15 @@ static int __init inet_init(void)
* Initialise the multicast router * Initialise the multicast router
*/ */
#if defined(CONFIG_IP_MROUTE) #if defined(CONFIG_IP_MROUTE)
ip_mr_init(); if (ip_mr_init())
printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n");
#endif #endif
/* /*
* Initialise per-cpu ipv4 mibs * Initialise per-cpu ipv4 mibs
*/ */
if (init_ipv4_mibs()) if (init_ipv4_mibs())
printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ; printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n");
ipv4_proc_init(); ipv4_proc_init();
......
...@@ -1878,16 +1878,36 @@ static struct net_protocol pim_protocol = { ...@@ -1878,16 +1878,36 @@ static struct net_protocol pim_protocol = {
* Setup for IP multicast routing * Setup for IP multicast routing
*/ */
void __init ip_mr_init(void) int __init ip_mr_init(void)
{ {
int err;
mrt_cachep = kmem_cache_create("ip_mrt_cache", mrt_cachep = kmem_cache_create("ip_mrt_cache",
sizeof(struct mfc_cache), sizeof(struct mfc_cache),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
NULL); NULL);
if (!mrt_cachep)
return -ENOMEM;
setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
register_netdevice_notifier(&ip_mr_notifier); err = register_netdevice_notifier(&ip_mr_notifier);
if (err)
goto reg_notif_fail;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops); err = -ENOMEM;
proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops); if (!proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops))
goto proc_vif_fail;
if (!proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops))
goto proc_cache_fail;
#endif #endif
return 0;
reg_notif_fail:
kmem_cache_destroy(mrt_cachep);
#ifdef CONFIG_PROC_FS
proc_vif_fail:
unregister_netdevice_notifier(&ip_mr_notifier);
proc_cache_fail:
proc_net_remove(&init_net, "ip_mr_vif");
#endif
return err;
} }
...@@ -119,6 +119,7 @@ static void ipv6_regen_rndid(unsigned long data); ...@@ -119,6 +119,7 @@ static void ipv6_regen_rndid(unsigned long data);
static int desync_factor = MAX_DESYNC_FACTOR * HZ; static int desync_factor = MAX_DESYNC_FACTOR * HZ;
#endif #endif
static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
static int ipv6_count_addresses(struct inet6_dev *idev); static int ipv6_count_addresses(struct inet6_dev *idev);
/* /*
...@@ -183,6 +184,8 @@ struct ipv6_devconf ipv6_devconf __read_mostly = { ...@@ -183,6 +184,8 @@ struct ipv6_devconf ipv6_devconf __read_mostly = {
#endif #endif
.proxy_ndp = 0, .proxy_ndp = 0,
.accept_source_route = 0, /* we do not accept RH0 by default. */ .accept_source_route = 0, /* we do not accept RH0 by default. */
.disable_ipv6 = 0,
.accept_dad = 1,
}; };
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
...@@ -215,6 +218,8 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { ...@@ -215,6 +218,8 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
#endif #endif
.proxy_ndp = 0, .proxy_ndp = 0,
.accept_source_route = 0, /* we do not accept RH0 by default. */ .accept_source_route = 0, /* we do not accept RH0 by default. */
.disable_ipv6 = 0,
.accept_dad = 1,
}; };
/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
...@@ -378,6 +383,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) ...@@ -378,6 +383,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
*/ */
in6_dev_hold(ndev); in6_dev_hold(ndev);
if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
ndev->cnf.accept_dad = -1;
#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {
printk(KERN_INFO printk(KERN_INFO
...@@ -578,6 +586,13 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, ...@@ -578,6 +586,13 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
struct rt6_info *rt; struct rt6_info *rt;
int hash; int hash;
int err = 0; int err = 0;
int addr_type = ipv6_addr_type(addr);
if (addr_type == IPV6_ADDR_ANY ||
addr_type & IPV6_ADDR_MULTICAST ||
(!(idev->dev->flags & IFF_LOOPBACK) &&
addr_type & IPV6_ADDR_LOOPBACK))
return ERR_PTR(-EADDRNOTAVAIL);
rcu_read_lock_bh(); rcu_read_lock_bh();
if (idev->dead) { if (idev->dead) {
...@@ -1412,6 +1427,20 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp) ...@@ -1412,6 +1427,20 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
void addrconf_dad_failure(struct inet6_ifaddr *ifp) void addrconf_dad_failure(struct inet6_ifaddr *ifp)
{ {
struct inet6_dev *idev = ifp->idev;
if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
struct in6_addr addr;
addr.s6_addr32[0] = htonl(0xfe800000);
addr.s6_addr32[1] = 0;
if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) &&
ipv6_addr_equal(&ifp->addr, &addr)) {
/* DAD failed for link-local based on MAC address */
idev->cnf.disable_ipv6 = 1;
}
}
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
addrconf_dad_stop(ifp); addrconf_dad_stop(ifp);
...@@ -2744,6 +2773,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) ...@@ -2744,6 +2773,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
spin_lock_bh(&ifp->lock); spin_lock_bh(&ifp->lock);
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
idev->cnf.accept_dad < 1 ||
!(ifp->flags&IFA_F_TENTATIVE) || !(ifp->flags&IFA_F_TENTATIVE) ||
ifp->flags & IFA_F_NODAD) { ifp->flags & IFA_F_NODAD) {
ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
...@@ -2791,6 +2821,11 @@ static void addrconf_dad_timer(unsigned long data) ...@@ -2791,6 +2821,11 @@ static void addrconf_dad_timer(unsigned long data)
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
goto out; goto out;
} }
if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
read_unlock_bh(&idev->lock);
addrconf_dad_failure(ifp);
return;
}
spin_lock_bh(&ifp->lock); spin_lock_bh(&ifp->lock);
if (ifp->probes == 0) { if (ifp->probes == 0) {
/* /*
...@@ -3650,6 +3685,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, ...@@ -3650,6 +3685,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
#ifdef CONFIG_IPV6_MROUTE #ifdef CONFIG_IPV6_MROUTE
array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
#endif #endif
array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
} }
static inline size_t inet6_if_nlmsg_size(void) static inline size_t inet6_if_nlmsg_size(void)
...@@ -4208,6 +4245,22 @@ static struct addrconf_sysctl_table ...@@ -4208,6 +4245,22 @@ static struct addrconf_sysctl_table
.proc_handler = &proc_dointvec, .proc_handler = &proc_dointvec,
}, },
#endif #endif
{
.ctl_name = CTL_UNNUMBERED,
.procname = "disable_ipv6",
.data = &ipv6_devconf.disable_ipv6,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = CTL_UNNUMBERED,
.procname = "accept_dad",
.data = &ipv6_devconf.accept_dad,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{ {
.ctl_name = 0, /* sentinel */ .ctl_name = 0, /* sentinel */
} }
......
...@@ -59,9 +59,7 @@ ...@@ -59,9 +59,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#ifdef CONFIG_IPV6_MROUTE
#include <linux/mroute6.h> #include <linux/mroute6.h>
#endif
MODULE_AUTHOR("Cast of dozens"); MODULE_AUTHOR("Cast of dozens");
MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
...@@ -952,9 +950,9 @@ static int __init inet6_init(void) ...@@ -952,9 +950,9 @@ static int __init inet6_init(void)
err = icmpv6_init(); err = icmpv6_init();
if (err) if (err)
goto icmp_fail; goto icmp_fail;
#ifdef CONFIG_IPV6_MROUTE err = ip6_mr_init();
ip6_mr_init(); if (err)
#endif goto ipmr_fail;
err = ndisc_init(); err = ndisc_init();
if (err) if (err)
goto ndisc_fail; goto ndisc_fail;
...@@ -1057,6 +1055,8 @@ static int __init inet6_init(void) ...@@ -1057,6 +1055,8 @@ static int __init inet6_init(void)
igmp_fail: igmp_fail:
ndisc_cleanup(); ndisc_cleanup();
ndisc_fail: ndisc_fail:
ip6_mr_cleanup();
ipmr_fail:
icmpv6_cleanup(); icmpv6_cleanup();
icmp_fail: icmp_fail:
unregister_pernet_subsys(&inet6_net_ops); unregister_pernet_subsys(&inet6_net_ops);
...@@ -1111,6 +1111,7 @@ static void __exit inet6_exit(void) ...@@ -1111,6 +1111,7 @@ static void __exit inet6_exit(void)
ipv6_netfilter_fini(); ipv6_netfilter_fini();
igmp6_cleanup(); igmp6_cleanup();
ndisc_cleanup(); ndisc_cleanup();
ip6_mr_cleanup();
icmpv6_cleanup(); icmpv6_cleanup();
rawv6_exit(); rawv6_exit();
......
...@@ -71,7 +71,8 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt ...@@ -71,7 +71,8 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES); IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES);
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
!idev || unlikely(idev->cnf.disable_ipv6)) {
IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS); IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
rcu_read_unlock(); rcu_read_unlock();
goto out; goto out;
......
...@@ -173,6 +173,13 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb) ...@@ -173,6 +173,13 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
int ip6_output(struct sk_buff *skb) int ip6_output(struct sk_buff *skb)
{ {
struct inet6_dev *idev = ip6_dst_idev(skb->dst);
if (unlikely(idev->cnf.disable_ipv6)) {
IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
return 0;
}
if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
dst_allfrag(skb->dst)) dst_allfrag(skb->dst))
return ip6_fragment(skb, ip6_output2); return ip6_fragment(skb, ip6_output2);
...@@ -498,7 +505,8 @@ int ip6_forward(struct sk_buff *skb) ...@@ -498,7 +505,8 @@ int ip6_forward(struct sk_buff *skb)
int addrtype = ipv6_addr_type(&hdr->saddr); int addrtype = ipv6_addr_type(&hdr->saddr);
/* This check is security critical. */ /* This check is security critical. */
if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK)) if (addrtype == IPV6_ADDR_ANY ||
addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK))
goto error; goto error;
if (addrtype & IPV6_ADDR_LINKLOCAL) { if (addrtype & IPV6_ADDR_LINKLOCAL) {
icmpv6_send(skb, ICMPV6_DEST_UNREACH, icmpv6_send(skb, ICMPV6_DEST_UNREACH,
......
...@@ -948,23 +948,51 @@ static struct notifier_block ip6_mr_notifier = { ...@@ -948,23 +948,51 @@ static struct notifier_block ip6_mr_notifier = {
* Setup for IP multicast routing * Setup for IP multicast routing
*/ */
void __init ip6_mr_init(void) int __init ip6_mr_init(void)
{ {
int err;
mrt_cachep = kmem_cache_create("ip6_mrt_cache", mrt_cachep = kmem_cache_create("ip6_mrt_cache",
sizeof(struct mfc6_cache), sizeof(struct mfc6_cache),
0, SLAB_HWCACHE_ALIGN, 0, SLAB_HWCACHE_ALIGN,
NULL); NULL);
if (!mrt_cachep) if (!mrt_cachep)
panic("cannot allocate ip6_mrt_cache"); return -ENOMEM;
setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
register_netdevice_notifier(&ip6_mr_notifier); err = register_netdevice_notifier(&ip6_mr_notifier);
if (err)
goto reg_notif_fail;
#ifdef CONFIG_PROC_FS
err = -ENOMEM;
if (!proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops))
goto proc_vif_fail;
if (!proc_net_fops_create(&init_net, "ip6_mr_cache",
0, &ip6mr_mfc_fops))
goto proc_cache_fail;
#endif
return 0;
reg_notif_fail:
kmem_cache_destroy(mrt_cachep);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops); proc_vif_fail:
proc_net_fops_create(&init_net, "ip6_mr_cache", 0, &ip6mr_mfc_fops); unregister_netdevice_notifier(&ip6_mr_notifier);
proc_cache_fail:
proc_net_remove(&init_net, "ip6_mr_vif");
#endif #endif
return err;
} }
void ip6_mr_cleanup(void)
{
#ifdef CONFIG_PROC_FS
proc_net_remove(&init_net, "ip6_mr_cache");
proc_net_remove(&init_net, "ip6_mr_vif");
#endif
unregister_netdevice_notifier(&ip6_mr_notifier);
del_timer(&ipmr_expire_timer);
kmem_cache_destroy(mrt_cachep);
}
static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock)
{ {
......
...@@ -228,7 +228,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt) ...@@ -228,7 +228,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt)
static inline int rt6_need_strict(struct in6_addr *daddr) static inline int rt6_need_strict(struct in6_addr *daddr)
{ {
return (ipv6_addr_type(daddr) & return (ipv6_addr_type(daddr) &
(IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK));
} }
/* /*
...@@ -237,15 +237,20 @@ static inline int rt6_need_strict(struct in6_addr *daddr) ...@@ -237,15 +237,20 @@ static inline int rt6_need_strict(struct in6_addr *daddr)
static inline struct rt6_info *rt6_device_match(struct net *net, static inline struct rt6_info *rt6_device_match(struct net *net,
struct rt6_info *rt, struct rt6_info *rt,
struct in6_addr *saddr,
int oif, int oif,
int flags) int flags)
{ {
struct rt6_info *local = NULL; struct rt6_info *local = NULL;
struct rt6_info *sprt; struct rt6_info *sprt;
if (oif) { if (!oif && ipv6_addr_any(saddr))
for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) { goto out;
struct net_device *dev = sprt->rt6i_dev;
for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) {
struct net_device *dev = sprt->rt6i_dev;
if (oif) {
if (dev->ifindex == oif) if (dev->ifindex == oif)
return sprt; return sprt;
if (dev->flags & IFF_LOOPBACK) { if (dev->flags & IFF_LOOPBACK) {
...@@ -259,14 +264,21 @@ static inline struct rt6_info *rt6_device_match(struct net *net, ...@@ -259,14 +264,21 @@ static inline struct rt6_info *rt6_device_match(struct net *net,
} }
local = sprt; local = sprt;
} }
} else {
if (ipv6_chk_addr(net, saddr, dev,
flags & RT6_LOOKUP_F_IFACE))
return sprt;
} }
}
if (oif) {
if (local) if (local)
return local; return local;
if (flags & RT6_LOOKUP_F_IFACE) if (flags & RT6_LOOKUP_F_IFACE)
return net->ipv6.ip6_null_entry; return net->ipv6.ip6_null_entry;
} }
out:
return rt; return rt;
} }
...@@ -539,7 +551,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, ...@@ -539,7 +551,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
restart: restart:
rt = fn->leaf; rt = fn->leaf;
rt = rt6_device_match(net, rt, fl->oif, flags); rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags);
BACKTRACK(net, &fl->fl6_src); BACKTRACK(net, &fl->fl6_src);
out: out:
dst_use(&rt->u.dst, jiffies); dst_use(&rt->u.dst, jiffies);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment