aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-07-03 06:07:58 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-03 06:07:58 -0400
commit44d28ab19c64d095314ac66f765d0c747519f4ed (patch)
tree20da263762645b5218936324b5cf9475ef1312b1
parent40b215e594b65a3488576c9d24b367548e18902a (diff)
parente0835f8fa56d2d308486f8a34cf1c4480cd27f4e (diff)
Merge branch 'net-next-2.6-v6ready-20080703' of git://git.linux-ipv6.org/gitroot/yoshfuji/linux-2.6-next
-rw-r--r--Documentation/networking/ip-sysctl.txt11
-rw-r--r--include/linux/igmp.h1
-rw-r--r--include/linux/ipv6.h4
-rw-r--r--include/linux/mroute.h28
-rw-r--r--include/linux/mroute6.h35
-rw-r--r--net/ipv4/af_inet.c5
-rw-r--r--net/ipv4/ipmr.c28
-rw-r--r--net/ipv6/addrconf.c53
-rw-r--r--net/ipv6/af_inet6.c11
-rw-r--r--net/ipv6/ip6_input.c3
-rw-r--r--net/ipv6/ip6_output.c10
-rw-r--r--net/ipv6/ip6mr.c38
-rw-r--r--net/ipv6/route.c22
13 files changed, 223 insertions, 26 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 71c7bea97160..72f6d52e52e6 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1025,6 +1025,17 @@ max_addresses - INTEGER
1025 autoconfigured addresses. 1025 autoconfigured addresses.
1026 Default: 16 1026 Default: 16
1027 1027
1028disable_ipv6 - BOOLEAN
1029 Disable IPv6 operation.
1030 Default: FALSE (enable IPv6 operation)
1031
1032accept_dad - INTEGER
1033 Whether to accept DAD (Duplicate Address Detection).
1034 0: Disable DAD
1035 1: Enable DAD (default)
1036 2: Enable DAD, and disable IPv6 operation if MAC-based duplicate
1037 link-local address has been found.
1038
1028icmp/*: 1039icmp/*:
1029ratelimit - INTEGER 1040ratelimit - INTEGER
1030 Limit the maximal rates for sending ICMPv6 packets. 1041 Limit the maximal rates for sending ICMPv6 packets.
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index f5a1a0db2e8e..7bb3c095c15b 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -228,7 +228,6 @@ extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
228extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, 228extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
229 struct group_filter __user *optval, int __user *optlen); 229 struct group_filter __user *optval, int __user *optlen);
230extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif); 230extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif);
231extern void ip_mr_init(void);
232extern void ip_mc_init_dev(struct in_device *); 231extern void ip_mc_init_dev(struct in_device *);
233extern void ip_mc_destroy_dev(struct in_device *); 232extern void ip_mc_destroy_dev(struct in_device *);
234extern void ip_mc_up(struct in_device *); 233extern void ip_mc_up(struct in_device *);
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index cde056e08181..391ad0843a46 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -163,6 +163,8 @@ struct ipv6_devconf {
163#ifdef CONFIG_IPV6_MROUTE 163#ifdef CONFIG_IPV6_MROUTE
164 __s32 mc_forwarding; 164 __s32 mc_forwarding;
165#endif 165#endif
166 __s32 disable_ipv6;
167 __s32 accept_dad;
166 void *sysctl; 168 void *sysctl;
167}; 169};
168 170
@@ -194,6 +196,8 @@ enum {
194 DEVCONF_OPTIMISTIC_DAD, 196 DEVCONF_OPTIMISTIC_DAD,
195 DEVCONF_ACCEPT_SOURCE_ROUTE, 197 DEVCONF_ACCEPT_SOURCE_ROUTE,
196 DEVCONF_MC_FORWARDING, 198 DEVCONF_MC_FORWARDING,
199 DEVCONF_DISABLE_IPV6,
200 DEVCONF_ACCEPT_DAD,
197 DEVCONF_MAX 201 DEVCONF_MAX
198}; 202};
199 203
diff --git a/include/linux/mroute.h b/include/linux/mroute.h
index de4decfa1bfc..07112ee9293a 100644
--- a/include/linux/mroute.h
+++ b/include/linux/mroute.h
@@ -144,11 +144,37 @@ static inline int ip_mroute_opt(int opt)
144} 144}
145#endif 145#endif
146 146
147#ifdef CONFIG_IP_MROUTE
147extern int ip_mroute_setsockopt(struct sock *, int, char __user *, int); 148extern int ip_mroute_setsockopt(struct sock *, int, char __user *, int);
148extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *); 149extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
149extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg); 150extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);
150extern void ip_mr_init(void); 151extern int ip_mr_init(void);
152#else
153static inline
154int ip_mroute_setsockopt(struct sock *sock,
155 int optname, char __user *optval, int optlen)
156{
157 return -ENOPROTOOPT;
158}
159
160static inline
161int ip_mroute_getsockopt(struct sock *sock,
162 int optname, char __user *optval, int __user *optlen)
163{
164 return -ENOPROTOOPT;
165}
151 166
167static inline
168int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
169{
170 return -ENOIOCTLCMD;
171}
172
173static inline int ip_mr_init(void)
174{
175 return 0;
176}
177#endif
152 178
153struct vif_device 179struct vif_device
154{ 180{
diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h
index e7989593142b..5cf50473a10f 100644
--- a/include/linux/mroute6.h
+++ b/include/linux/mroute6.h
@@ -131,11 +131,44 @@ static inline int ip6_mroute_opt(int opt)
131 131
132struct sock; 132struct sock;
133 133
134#ifdef CONFIG_IPV6_MROUTE
134extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int); 135extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int);
135extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *); 136extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
136extern int ip6_mr_input(struct sk_buff *skb); 137extern int ip6_mr_input(struct sk_buff *skb);
137extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg); 138extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg);
138extern void ip6_mr_init(void); 139extern int ip6_mr_init(void);
140extern void ip6_mr_cleanup(void);
141#else
142static inline
143int ip6_mroute_setsockopt(struct sock *sock,
144 int optname, char __user *optval, int optlen)
145{
146 return -ENOPROTOOPT;
147}
148
149static inline
150int ip6_mroute_getsockopt(struct sock *sock,
151 int optname, char __user *optval, int __user *optlen)
152{
153 return -ENOPROTOOPT;
154}
155
156static inline
157int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
158{
159 return -ENOIOCTLCMD;
160}
161
162static inline int ip6_mr_init(void)
163{
164 return 0;
165}
166
167static inline void ip6_mr_cleanup(void)
168{
169 return;
170}
171#endif
139 172
140struct mif_device 173struct mif_device
141{ 174{
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 42bd24b64b57..dc411335c14f 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1479,14 +1479,15 @@ static int __init inet_init(void)
1479 * Initialise the multicast router 1479 * Initialise the multicast router
1480 */ 1480 */
1481#if defined(CONFIG_IP_MROUTE) 1481#if defined(CONFIG_IP_MROUTE)
1482 ip_mr_init(); 1482 if (ip_mr_init())
1483 printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n");
1483#endif 1484#endif
1484 /* 1485 /*
1485 * Initialise per-cpu ipv4 mibs 1486 * Initialise per-cpu ipv4 mibs
1486 */ 1487 */
1487 1488
1488 if (init_ipv4_mibs()) 1489 if (init_ipv4_mibs())
1489 printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ; 1490 printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n");
1490 1491
1491 ipv4_proc_init(); 1492 ipv4_proc_init();
1492 1493
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 300ab0c2919e..438fab9c62a0 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1878,16 +1878,36 @@ static struct net_protocol pim_protocol = {
1878 * Setup for IP multicast routing 1878 * Setup for IP multicast routing
1879 */ 1879 */
1880 1880
1881void __init ip_mr_init(void) 1881int __init ip_mr_init(void)
1882{ 1882{
1883 int err;
1884
1883 mrt_cachep = kmem_cache_create("ip_mrt_cache", 1885 mrt_cachep = kmem_cache_create("ip_mrt_cache",
1884 sizeof(struct mfc_cache), 1886 sizeof(struct mfc_cache),
1885 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, 1887 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
1886 NULL); 1888 NULL);
1889 if (!mrt_cachep)
1890 return -ENOMEM;
1891
1887 setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); 1892 setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
1888 register_netdevice_notifier(&ip_mr_notifier); 1893 err = register_netdevice_notifier(&ip_mr_notifier);
1894 if (err)
1895 goto reg_notif_fail;
1889#ifdef CONFIG_PROC_FS 1896#ifdef CONFIG_PROC_FS
1890 proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops); 1897 err = -ENOMEM;
1891 proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops); 1898 if (!proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops))
1899 goto proc_vif_fail;
1900 if (!proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops))
1901 goto proc_cache_fail;
1892#endif 1902#endif
1903 return 0;
1904reg_notif_fail:
1905 kmem_cache_destroy(mrt_cachep);
1906#ifdef CONFIG_PROC_FS
1907proc_vif_fail:
1908 unregister_netdevice_notifier(&ip_mr_notifier);
1909proc_cache_fail:
1910 proc_net_remove(&init_net, "ip_mr_vif");
1911#endif
1912 return err;
1893} 1913}
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 84127d854cfc..2ec73e62202c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -119,6 +119,7 @@ static void ipv6_regen_rndid(unsigned long data);
119static int desync_factor = MAX_DESYNC_FACTOR * HZ; 119static int desync_factor = MAX_DESYNC_FACTOR * HZ;
120#endif 120#endif
121 121
122static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
122static int ipv6_count_addresses(struct inet6_dev *idev); 123static int ipv6_count_addresses(struct inet6_dev *idev);
123 124
124/* 125/*
@@ -183,6 +184,8 @@ struct ipv6_devconf ipv6_devconf __read_mostly = {
183#endif 184#endif
184 .proxy_ndp = 0, 185 .proxy_ndp = 0,
185 .accept_source_route = 0, /* we do not accept RH0 by default. */ 186 .accept_source_route = 0, /* we do not accept RH0 by default. */
187 .disable_ipv6 = 0,
188 .accept_dad = 1,
186}; 189};
187 190
188static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { 191static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -215,6 +218,8 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
215#endif 218#endif
216 .proxy_ndp = 0, 219 .proxy_ndp = 0,
217 .accept_source_route = 0, /* we do not accept RH0 by default. */ 220 .accept_source_route = 0, /* we do not accept RH0 by default. */
221 .disable_ipv6 = 0,
222 .accept_dad = 1,
218}; 223};
219 224
220/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ 225/* 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 */ 383 */
379 in6_dev_hold(ndev); 384 in6_dev_hold(ndev);
380 385
386 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
387 ndev->cnf.accept_dad = -1;
388
381#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) 389#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
382 if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { 390 if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {
383 printk(KERN_INFO 391 printk(KERN_INFO
@@ -578,6 +586,13 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
578 struct rt6_info *rt; 586 struct rt6_info *rt;
579 int hash; 587 int hash;
580 int err = 0; 588 int err = 0;
589 int addr_type = ipv6_addr_type(addr);
590
591 if (addr_type == IPV6_ADDR_ANY ||
592 addr_type & IPV6_ADDR_MULTICAST ||
593 (!(idev->dev->flags & IFF_LOOPBACK) &&
594 addr_type & IPV6_ADDR_LOOPBACK))
595 return ERR_PTR(-EADDRNOTAVAIL);
581 596
582 rcu_read_lock_bh(); 597 rcu_read_lock_bh();
583 if (idev->dead) { 598 if (idev->dead) {
@@ -1412,6 +1427,20 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
1412 1427
1413void addrconf_dad_failure(struct inet6_ifaddr *ifp) 1428void addrconf_dad_failure(struct inet6_ifaddr *ifp)
1414{ 1429{
1430 struct inet6_dev *idev = ifp->idev;
1431 if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
1432 struct in6_addr addr;
1433
1434 addr.s6_addr32[0] = htonl(0xfe800000);
1435 addr.s6_addr32[1] = 0;
1436
1437 if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) &&
1438 ipv6_addr_equal(&ifp->addr, &addr)) {
1439 /* DAD failed for link-local based on MAC address */
1440 idev->cnf.disable_ipv6 = 1;
1441 }
1442 }
1443
1415 if (net_ratelimit()) 1444 if (net_ratelimit())
1416 printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); 1445 printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
1417 addrconf_dad_stop(ifp); 1446 addrconf_dad_stop(ifp);
@@ -2744,6 +2773,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
2744 spin_lock_bh(&ifp->lock); 2773 spin_lock_bh(&ifp->lock);
2745 2774
2746 if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || 2775 if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
2776 idev->cnf.accept_dad < 1 ||
2747 !(ifp->flags&IFA_F_TENTATIVE) || 2777 !(ifp->flags&IFA_F_TENTATIVE) ||
2748 ifp->flags & IFA_F_NODAD) { 2778 ifp->flags & IFA_F_NODAD) {
2749 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); 2779 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
@@ -2791,6 +2821,11 @@ static void addrconf_dad_timer(unsigned long data)
2791 read_unlock_bh(&idev->lock); 2821 read_unlock_bh(&idev->lock);
2792 goto out; 2822 goto out;
2793 } 2823 }
2824 if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
2825 read_unlock_bh(&idev->lock);
2826 addrconf_dad_failure(ifp);
2827 return;
2828 }
2794 spin_lock_bh(&ifp->lock); 2829 spin_lock_bh(&ifp->lock);
2795 if (ifp->probes == 0) { 2830 if (ifp->probes == 0) {
2796 /* 2831 /*
@@ -3650,6 +3685,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
3650#ifdef CONFIG_IPV6_MROUTE 3685#ifdef CONFIG_IPV6_MROUTE
3651 array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; 3686 array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
3652#endif 3687#endif
3688 array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
3689 array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
3653} 3690}
3654 3691
3655static inline size_t inet6_if_nlmsg_size(void) 3692static inline size_t inet6_if_nlmsg_size(void)
@@ -4209,6 +4246,22 @@ static struct addrconf_sysctl_table
4209 }, 4246 },
4210#endif 4247#endif
4211 { 4248 {
4249 .ctl_name = CTL_UNNUMBERED,
4250 .procname = "disable_ipv6",
4251 .data = &ipv6_devconf.disable_ipv6,
4252 .maxlen = sizeof(int),
4253 .mode = 0644,
4254 .proc_handler = &proc_dointvec,
4255 },
4256 {
4257 .ctl_name = CTL_UNNUMBERED,
4258 .procname = "accept_dad",
4259 .data = &ipv6_devconf.accept_dad,
4260 .maxlen = sizeof(int),
4261 .mode = 0644,
4262 .proc_handler = &proc_dointvec,
4263 },
4264 {
4212 .ctl_name = 0, /* sentinel */ 4265 .ctl_name = 0, /* sentinel */
4213 } 4266 }
4214 }, 4267 },
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 3ce8d2f318c6..3d828bc4b1cf 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -59,9 +59,7 @@
59 59
60#include <asm/uaccess.h> 60#include <asm/uaccess.h>
61#include <asm/system.h> 61#include <asm/system.h>
62#ifdef CONFIG_IPV6_MROUTE
63#include <linux/mroute6.h> 62#include <linux/mroute6.h>
64#endif
65 63
66MODULE_AUTHOR("Cast of dozens"); 64MODULE_AUTHOR("Cast of dozens");
67MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); 65MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
@@ -952,9 +950,9 @@ static int __init inet6_init(void)
952 err = icmpv6_init(); 950 err = icmpv6_init();
953 if (err) 951 if (err)
954 goto icmp_fail; 952 goto icmp_fail;
955#ifdef CONFIG_IPV6_MROUTE 953 err = ip6_mr_init();
956 ip6_mr_init(); 954 if (err)
957#endif 955 goto ipmr_fail;
958 err = ndisc_init(); 956 err = ndisc_init();
959 if (err) 957 if (err)
960 goto ndisc_fail; 958 goto ndisc_fail;
@@ -1057,6 +1055,8 @@ netfilter_fail:
1057igmp_fail: 1055igmp_fail:
1058 ndisc_cleanup(); 1056 ndisc_cleanup();
1059ndisc_fail: 1057ndisc_fail:
1058 ip6_mr_cleanup();
1059ipmr_fail:
1060 icmpv6_cleanup(); 1060 icmpv6_cleanup();
1061icmp_fail: 1061icmp_fail:
1062 unregister_pernet_subsys(&inet6_net_ops); 1062 unregister_pernet_subsys(&inet6_net_ops);
@@ -1111,6 +1111,7 @@ static void __exit inet6_exit(void)
1111 ipv6_netfilter_fini(); 1111 ipv6_netfilter_fini();
1112 igmp6_cleanup(); 1112 igmp6_cleanup();
1113 ndisc_cleanup(); 1113 ndisc_cleanup();
1114 ip6_mr_cleanup();
1114 icmpv6_cleanup(); 1115 icmpv6_cleanup();
1115 rawv6_exit(); 1116 rawv6_exit();
1116 1117
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 34e5a96623ae..ea81c614dde2 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -71,7 +71,8 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
71 71
72 IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES); 72 IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES);
73 73
74 if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { 74 if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
75 !idev || unlikely(idev->cnf.disable_ipv6)) {
75 IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS); 76 IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
76 rcu_read_unlock(); 77 rcu_read_unlock();
77 goto out; 78 goto out;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index fd7cd1bfe151..0981c1ef3057 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -173,6 +173,13 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
173 173
174int ip6_output(struct sk_buff *skb) 174int ip6_output(struct sk_buff *skb)
175{ 175{
176 struct inet6_dev *idev = ip6_dst_idev(skb->dst);
177 if (unlikely(idev->cnf.disable_ipv6)) {
178 IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
179 kfree_skb(skb);
180 return 0;
181 }
182
176 if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || 183 if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
177 dst_allfrag(skb->dst)) 184 dst_allfrag(skb->dst))
178 return ip6_fragment(skb, ip6_output2); 185 return ip6_fragment(skb, ip6_output2);
@@ -498,7 +505,8 @@ int ip6_forward(struct sk_buff *skb)
498 int addrtype = ipv6_addr_type(&hdr->saddr); 505 int addrtype = ipv6_addr_type(&hdr->saddr);
499 506
500 /* This check is security critical. */ 507 /* This check is security critical. */
501 if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK)) 508 if (addrtype == IPV6_ADDR_ANY ||
509 addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK))
502 goto error; 510 goto error;
503 if (addrtype & IPV6_ADDR_LINKLOCAL) { 511 if (addrtype & IPV6_ADDR_LINKLOCAL) {
504 icmpv6_send(skb, ICMPV6_DEST_UNREACH, 512 icmpv6_send(skb, ICMPV6_DEST_UNREACH,
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 90e763073dc5..cfac26d674ed 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -948,23 +948,51 @@ static struct notifier_block ip6_mr_notifier = {
948 * Setup for IP multicast routing 948 * Setup for IP multicast routing
949 */ 949 */
950 950
951void __init ip6_mr_init(void) 951int __init ip6_mr_init(void)
952{ 952{
953 int err;
954
953 mrt_cachep = kmem_cache_create("ip6_mrt_cache", 955 mrt_cachep = kmem_cache_create("ip6_mrt_cache",
954 sizeof(struct mfc6_cache), 956 sizeof(struct mfc6_cache),
955 0, SLAB_HWCACHE_ALIGN, 957 0, SLAB_HWCACHE_ALIGN,
956 NULL); 958 NULL);
957 if (!mrt_cachep) 959 if (!mrt_cachep)
958 panic("cannot allocate ip6_mrt_cache"); 960 return -ENOMEM;
959 961
960 setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); 962 setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
961 register_netdevice_notifier(&ip6_mr_notifier); 963 err = register_netdevice_notifier(&ip6_mr_notifier);
964 if (err)
965 goto reg_notif_fail;
966#ifdef CONFIG_PROC_FS
967 err = -ENOMEM;
968 if (!proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops))
969 goto proc_vif_fail;
970 if (!proc_net_fops_create(&init_net, "ip6_mr_cache",
971 0, &ip6mr_mfc_fops))
972 goto proc_cache_fail;
973#endif
974 return 0;
975reg_notif_fail:
976 kmem_cache_destroy(mrt_cachep);
962#ifdef CONFIG_PROC_FS 977#ifdef CONFIG_PROC_FS
963 proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops); 978proc_vif_fail:
964 proc_net_fops_create(&init_net, "ip6_mr_cache", 0, &ip6mr_mfc_fops); 979 unregister_netdevice_notifier(&ip6_mr_notifier);
980proc_cache_fail:
981 proc_net_remove(&init_net, "ip6_mr_vif");
965#endif 982#endif
983 return err;
966} 984}
967 985
986void ip6_mr_cleanup(void)
987{
988#ifdef CONFIG_PROC_FS
989 proc_net_remove(&init_net, "ip6_mr_cache");
990 proc_net_remove(&init_net, "ip6_mr_vif");
991#endif
992 unregister_netdevice_notifier(&ip6_mr_notifier);
993 del_timer(&ipmr_expire_timer);
994 kmem_cache_destroy(mrt_cachep);
995}
968 996
969static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) 997static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock)
970{ 998{
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 751e98f9b8b4..5d6c166dfbb6 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -228,7 +228,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt)
228static inline int rt6_need_strict(struct in6_addr *daddr) 228static inline int rt6_need_strict(struct in6_addr *daddr)
229{ 229{
230 return (ipv6_addr_type(daddr) & 230 return (ipv6_addr_type(daddr) &
231 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); 231 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK));
232} 232}
233 233
234/* 234/*
@@ -237,15 +237,20 @@ static inline int rt6_need_strict(struct in6_addr *daddr)
237 237
238static inline struct rt6_info *rt6_device_match(struct net *net, 238static inline struct rt6_info *rt6_device_match(struct net *net,
239 struct rt6_info *rt, 239 struct rt6_info *rt,
240 struct in6_addr *saddr,
240 int oif, 241 int oif,
241 int flags) 242 int flags)
242{ 243{
243 struct rt6_info *local = NULL; 244 struct rt6_info *local = NULL;
244 struct rt6_info *sprt; 245 struct rt6_info *sprt;
245 246
246 if (oif) { 247 if (!oif && ipv6_addr_any(saddr))
247 for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) { 248 goto out;
248 struct net_device *dev = sprt->rt6i_dev; 249
250 for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) {
251 struct net_device *dev = sprt->rt6i_dev;
252
253 if (oif) {
249 if (dev->ifindex == oif) 254 if (dev->ifindex == oif)
250 return sprt; 255 return sprt;
251 if (dev->flags & IFF_LOOPBACK) { 256 if (dev->flags & IFF_LOOPBACK) {
@@ -259,14 +264,21 @@ static inline struct rt6_info *rt6_device_match(struct net *net,
259 } 264 }
260 local = sprt; 265 local = sprt;
261 } 266 }
267 } else {
268 if (ipv6_chk_addr(net, saddr, dev,
269 flags & RT6_LOOKUP_F_IFACE))
270 return sprt;
262 } 271 }
272 }
263 273
274 if (oif) {
264 if (local) 275 if (local)
265 return local; 276 return local;
266 277
267 if (flags & RT6_LOOKUP_F_IFACE) 278 if (flags & RT6_LOOKUP_F_IFACE)
268 return net->ipv6.ip6_null_entry; 279 return net->ipv6.ip6_null_entry;
269 } 280 }
281out:
270 return rt; 282 return rt;
271} 283}
272 284
@@ -539,7 +551,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
539 fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); 551 fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
540restart: 552restart:
541 rt = fn->leaf; 553 rt = fn->leaf;
542 rt = rt6_device_match(net, rt, fl->oif, flags); 554 rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags);
543 BACKTRACK(net, &fl->fl6_src); 555 BACKTRACK(net, &fl->fl6_src);
544out: 556out:
545 dst_use(&rt->u.dst, jiffies); 557 dst_use(&rt->u.dst, jiffies);