diff options
author | David S. Miller <davem@davemloft.net> | 2008-07-03 06:07:58 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-03 06:07:58 -0400 |
commit | 44d28ab19c64d095314ac66f765d0c747519f4ed (patch) | |
tree | 20da263762645b5218936324b5cf9475ef1312b1 | |
parent | 40b215e594b65a3488576c9d24b367548e18902a (diff) | |
parent | e0835f8fa56d2d308486f8a34cf1c4480cd27f4e (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.txt | 11 | ||||
-rw-r--r-- | include/linux/igmp.h | 1 | ||||
-rw-r--r-- | include/linux/ipv6.h | 4 | ||||
-rw-r--r-- | include/linux/mroute.h | 28 | ||||
-rw-r--r-- | include/linux/mroute6.h | 35 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 5 | ||||
-rw-r--r-- | net/ipv4/ipmr.c | 28 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 53 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 11 | ||||
-rw-r--r-- | net/ipv6/ip6_input.c | 3 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 10 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 38 | ||||
-rw-r--r-- | net/ipv6/route.c | 22 |
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 | ||
1028 | disable_ipv6 - BOOLEAN | ||
1029 | Disable IPv6 operation. | ||
1030 | Default: FALSE (enable IPv6 operation) | ||
1031 | |||
1032 | accept_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 | |||
1028 | icmp/*: | 1039 | icmp/*: |
1029 | ratelimit - INTEGER | 1040 | ratelimit - 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, | |||
228 | extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | 228 | extern 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); |
230 | extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif); | 230 | extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif); |
231 | extern void ip_mr_init(void); | ||
232 | extern void ip_mc_init_dev(struct in_device *); | 231 | extern void ip_mc_init_dev(struct in_device *); |
233 | extern void ip_mc_destroy_dev(struct in_device *); | 232 | extern void ip_mc_destroy_dev(struct in_device *); |
234 | extern void ip_mc_up(struct in_device *); | 233 | extern 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 | ||
147 | extern int ip_mroute_setsockopt(struct sock *, int, char __user *, int); | 148 | extern int ip_mroute_setsockopt(struct sock *, int, char __user *, int); |
148 | extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *); | 149 | extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *); |
149 | extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg); | 150 | extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg); |
150 | extern void ip_mr_init(void); | 151 | extern int ip_mr_init(void); |
152 | #else | ||
153 | static inline | ||
154 | int ip_mroute_setsockopt(struct sock *sock, | ||
155 | int optname, char __user *optval, int optlen) | ||
156 | { | ||
157 | return -ENOPROTOOPT; | ||
158 | } | ||
159 | |||
160 | static inline | ||
161 | int ip_mroute_getsockopt(struct sock *sock, | ||
162 | int optname, char __user *optval, int __user *optlen) | ||
163 | { | ||
164 | return -ENOPROTOOPT; | ||
165 | } | ||
151 | 166 | ||
167 | static inline | ||
168 | int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) | ||
169 | { | ||
170 | return -ENOIOCTLCMD; | ||
171 | } | ||
172 | |||
173 | static inline int ip_mr_init(void) | ||
174 | { | ||
175 | return 0; | ||
176 | } | ||
177 | #endif | ||
152 | 178 | ||
153 | struct vif_device | 179 | struct 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 | ||
132 | struct sock; | 132 | struct sock; |
133 | 133 | ||
134 | #ifdef CONFIG_IPV6_MROUTE | ||
134 | extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int); | 135 | extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int); |
135 | extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *); | 136 | extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *); |
136 | extern int ip6_mr_input(struct sk_buff *skb); | 137 | extern int ip6_mr_input(struct sk_buff *skb); |
137 | extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg); | 138 | extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg); |
138 | extern void ip6_mr_init(void); | 139 | extern int ip6_mr_init(void); |
140 | extern void ip6_mr_cleanup(void); | ||
141 | #else | ||
142 | static inline | ||
143 | int ip6_mroute_setsockopt(struct sock *sock, | ||
144 | int optname, char __user *optval, int optlen) | ||
145 | { | ||
146 | return -ENOPROTOOPT; | ||
147 | } | ||
148 | |||
149 | static inline | ||
150 | int ip6_mroute_getsockopt(struct sock *sock, | ||
151 | int optname, char __user *optval, int __user *optlen) | ||
152 | { | ||
153 | return -ENOPROTOOPT; | ||
154 | } | ||
155 | |||
156 | static inline | ||
157 | int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) | ||
158 | { | ||
159 | return -ENOIOCTLCMD; | ||
160 | } | ||
161 | |||
162 | static inline int ip6_mr_init(void) | ||
163 | { | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static inline void ip6_mr_cleanup(void) | ||
168 | { | ||
169 | return; | ||
170 | } | ||
171 | #endif | ||
139 | 172 | ||
140 | struct mif_device | 173 | struct 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 | ||
1881 | void __init ip_mr_init(void) | 1881 | int __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; | ||
1904 | reg_notif_fail: | ||
1905 | kmem_cache_destroy(mrt_cachep); | ||
1906 | #ifdef CONFIG_PROC_FS | ||
1907 | proc_vif_fail: | ||
1908 | unregister_netdevice_notifier(&ip_mr_notifier); | ||
1909 | proc_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); | |||
119 | static int desync_factor = MAX_DESYNC_FACTOR * HZ; | 119 | static int desync_factor = MAX_DESYNC_FACTOR * HZ; |
120 | #endif | 120 | #endif |
121 | 121 | ||
122 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); | ||
122 | static int ipv6_count_addresses(struct inet6_dev *idev); | 123 | static 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 | ||
188 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | 191 | static 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 | ||
1413 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | 1428 | void 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 | ||
3655 | static inline size_t inet6_if_nlmsg_size(void) | 3692 | static 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 | ||
66 | MODULE_AUTHOR("Cast of dozens"); | 64 | MODULE_AUTHOR("Cast of dozens"); |
67 | MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); | 65 | MODULE_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: | |||
1057 | igmp_fail: | 1055 | igmp_fail: |
1058 | ndisc_cleanup(); | 1056 | ndisc_cleanup(); |
1059 | ndisc_fail: | 1057 | ndisc_fail: |
1058 | ip6_mr_cleanup(); | ||
1059 | ipmr_fail: | ||
1060 | icmpv6_cleanup(); | 1060 | icmpv6_cleanup(); |
1061 | icmp_fail: | 1061 | icmp_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 | ||
174 | int ip6_output(struct sk_buff *skb) | 174 | int 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 | ||
951 | void __init ip6_mr_init(void) | 951 | int __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; | ||
975 | reg_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); | 978 | proc_vif_fail: |
964 | proc_net_fops_create(&init_net, "ip6_mr_cache", 0, &ip6mr_mfc_fops); | 979 | unregister_netdevice_notifier(&ip6_mr_notifier); |
980 | proc_cache_fail: | ||
981 | proc_net_remove(&init_net, "ip6_mr_vif"); | ||
965 | #endif | 982 | #endif |
983 | return err; | ||
966 | } | 984 | } |
967 | 985 | ||
986 | void 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 | ||
969 | static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) | 997 | static 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) | |||
228 | static inline int rt6_need_strict(struct in6_addr *daddr) | 228 | static 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 | ||
238 | static inline struct rt6_info *rt6_device_match(struct net *net, | 238 | static 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 | } |
281 | out: | ||
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); |
540 | restart: | 552 | restart: |
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); |
544 | out: | 556 | out: |
545 | dst_use(&rt->u.dst, jiffies); | 557 | dst_use(&rt->u.dst, jiffies); |