diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 4 | ||||
-rw-r--r-- | net/ipv6/ah6.c | 2 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 8 | ||||
-rw-r--r-- | net/ipv6/fib6_rules.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 9 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 12 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 3 | ||||
-rw-r--r-- | net/ipv6/raw.c | 8 | ||||
-rw-r--r-- | net/ipv6/route.c | 65 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 10 | ||||
-rw-r--r-- | net/ipv6/udp.c | 29 | ||||
-rw-r--r-- | net/ipv6/udp_impl.h | 2 | ||||
-rw-r--r-- | net/ipv6/udplite.c | 2 | ||||
-rw-r--r-- | net/ipv6/xfrm6_input.c | 6 | ||||
-rw-r--r-- | net/ipv6/xfrm6_mode_tunnel.c | 1 |
15 files changed, 108 insertions, 55 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index c7ea248fae2e..f96ed76d8fa4 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2259,7 +2259,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, switch(event) { case NETDEV_REGISTER: - if (!idev) { + if (!idev && dev->mtu >= IPV6_MIN_MTU) { idev = ipv6_add_dev(dev); if (!idev) printk(KERN_WARNING "IPv6: add_dev failed for %s\n", @@ -2979,7 +2979,7 @@ static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local) return pfx; } -static struct nla_policy ifa_ipv6_policy[IFA_MAX+1] __read_mostly = { +static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = { [IFA_ADDRESS] = { .len = sizeof(struct in6_addr) }, [IFA_LOCAL] = { .len = sizeof(struct in6_addr) }, [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index b696c8401200..128f94c79c64 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -247,7 +247,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(tmp_base, top_iph, sizeof(tmp_base)); tmp_ext = NULL; - extlen = skb_transport_offset(skb) + sizeof(struct ipv6hdr); + extlen = skb_transport_offset(skb) - sizeof(struct ipv6hdr); if (extlen) { extlen += sizeof(*tmp_ext); tmp_ext = kmalloc(extlen, GFP_ATOMIC); diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 403eee66b9c5..b1fe7ac5dc90 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -177,8 +177,12 @@ ipv4_connected: if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) - goto out; + if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto out; + } /* source address lookup done in ip6_dst_lookup */ diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index fc3882c90604..53b3998a486c 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -157,7 +157,7 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) return 1; } -static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = { +static const struct nla_policy fib6_rule_policy[FRA_MAX+1] = { FRA_GENERIC_POLICY, }; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index ca08ee88d07f..662a7d9681fd 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -619,14 +619,6 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, ins = &fn->leaf; - if (fn->fn_flags&RTN_TL_ROOT && - fn->leaf == &ip6_null_entry && - !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ){ - fn->leaf = rt; - rt->u.dst.rt6_next = NULL; - goto out; - } - for (iter = fn->leaf; iter; iter=iter->u.dst.rt6_next) { /* * Search for duplicates @@ -666,7 +658,6 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, * insert node */ -out: rt->u.dst.rt6_next = iter; *ins = rt; rt->rt6i_node = fn; diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 6d2a08205111..1b1797f1f33d 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -160,6 +160,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum, { struct nf_conn *ct; struct nf_conn_help *help; + struct nf_conntrack_helper *helper; enum ip_conntrack_info ctinfo; unsigned int ret, protoff; unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data; @@ -172,18 +173,21 @@ static unsigned int ipv6_confirm(unsigned int hooknum, goto out; help = nfct_help(ct); - if (!help || !help->helper) + if (!help) + goto out; + /* rcu_read_lock()ed by nf_hook_slow */ + helper = rcu_dereference(help->helper); + if (!helper) goto out; protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, (*pskb)->len - extoff); - if (protoff < 0 || protoff > (*pskb)->len || - pnum == NEXTHDR_FRAGMENT) { + if (protoff > (*pskb)->len || pnum == NEXTHDR_FRAGMENT) { DEBUGP("proto header not found\n"); return NF_ACCEPT; } - ret = help->helper->help(pskb, protoff, ct, ctinfo); + ret = helper->help(pskb, protoff, ct, ctinfo); if (ret != NF_ACCEPT) return ret; out: diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 0be790d250f9..8814b95b2326 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -168,8 +168,7 @@ icmpv6_error_message(struct sk_buff *skb, skb->len - inip6off - sizeof(struct ipv6hdr)); - if ((inprotoff < 0) || (inprotoff > skb->len) || - (inprotonum == NEXTHDR_FRAGMENT)) { + if ((inprotoff > skb->len) || (inprotonum == NEXTHDR_FRAGMENT)) { DEBUGP("icmpv6_error: Can't get protocol header in ICMPv6 payload.\n"); return -NF_ACCEPT; } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 009a1047fc3f..a58459a76684 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -818,8 +818,12 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) - goto out; + if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto out; + } if (hlimit < 0) { if (ipv6_addr_is_multicast(&fl.fl6_dst)) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b46ad53044ba..fe8d9837f9f8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -119,6 +119,19 @@ static struct dst_ops ip6_dst_ops = { .entry_size = sizeof(struct rt6_info), }; +static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) +{ +} + +static struct dst_ops ip6_dst_blackhole_ops = { + .family = AF_INET6, + .protocol = __constant_htons(ETH_P_IPV6), + .destroy = ip6_dst_destroy, + .check = ip6_dst_check, + .update_pmtu = ip6_rt_blackhole_update_pmtu, + .entry_size = sizeof(struct rt6_info), +}; + struct rt6_info ip6_null_entry = { .u = { .dst = { @@ -833,6 +846,54 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) EXPORT_SYMBOL(ip6_route_output); +static int ip6_blackhole_output(struct sk_buff *skb) +{ + kfree_skb(skb); + return 0; +} + +int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl) +{ + struct rt6_info *ort = (struct rt6_info *) *dstp; + struct rt6_info *rt = (struct rt6_info *) + dst_alloc(&ip6_dst_blackhole_ops); + struct dst_entry *new = NULL; + + if (rt) { + new = &rt->u.dst; + + atomic_set(&new->__refcnt, 1); + new->__use = 1; + new->input = ip6_blackhole_output; + new->output = ip6_blackhole_output; + + memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); + new->dev = ort->u.dst.dev; + if (new->dev) + dev_hold(new->dev); + rt->rt6i_idev = ort->rt6i_idev; + if (rt->rt6i_idev) + in6_dev_hold(rt->rt6i_idev); + rt->rt6i_expires = 0; + + ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway); + rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES; + rt->rt6i_metric = 0; + + memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); +#ifdef CONFIG_IPV6_SUBTREES + memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); +#endif + + dst_free(new); + } + + dst_release(*dstp); + *dstp = new; + return (new ? 0 : -ENOMEM); +} +EXPORT_SYMBOL_GPL(ip6_dst_blackhole); + /* * Destination cache support functions */ @@ -1938,7 +1999,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned mtu) fib6_clean_all(rt6_mtu_change_route, 0, &arg); } -static struct nla_policy rtm_ipv6_policy[RTA_MAX+1] __read_mostly = { +static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) }, [RTA_OIF] = { .type = NLA_U32 }, [RTA_IIF] = { .type = NLA_U32 }, @@ -2495,6 +2556,8 @@ void __init ip6_route_init(void) ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; + fib6_init(); #ifdef CONFIG_PROC_FS p = proc_net_create("ipv6_route", 0, rt6_proc_info); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index e2f25ea43b68..193d9d60bb7a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -265,8 +265,12 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) - goto failure; + if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto failure; + } if (saddr == NULL) { saddr = &fl.fl6_src; @@ -586,6 +590,7 @@ static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer, kfree(newkey); return -ENOMEM; } + sk->sk_route_caps &= ~NETIF_F_GSO_MASK; } tcp_alloc_md5sig_pool(); if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) { @@ -720,6 +725,7 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, return -ENOMEM; tp->md5sig_info = p; + sk->sk_route_caps &= ~NETIF_F_GSO_MASK; } newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index a7ae59c954d5..4210951edb6e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -52,28 +52,9 @@ DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; -static int ipv6_rcv_saddr_any(const struct sock *sk) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - - return ipv6_addr_any(&np->rcv_saddr); -} - -static unsigned int ipv6_hash_port_and_rcv_saddr(__u16 port, - const struct sock *sk) -{ - return port; -} - -const struct udp_get_port_ops udp_ipv6_ops = { - .saddr_cmp = ipv6_rcv_saddr_equal, - .saddr_any = ipv6_rcv_saddr_any, - .hash_port_and_rcv_saddr = ipv6_hash_port_and_rcv_saddr, -}; - static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) { - return udp_get_port(sk, snum, &udp_ipv6_ops); + return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); } static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, @@ -767,8 +748,12 @@ do_udp_sendmsg: if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) - goto out; + if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto out; + } if (hlimit < 0) { if (ipv6_addr_is_multicast(&fl.fl6_dst)) diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 36b0c11a28a3..6e252f318f7c 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h @@ -6,8 +6,6 @@ #include <net/addrconf.h> #include <net/inet_common.h> -extern const struct udp_get_port_ops udp_ipv6_ops; - extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int ); extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, int , int , int , __be32 , struct hlist_head []); diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index c40a51362f89..f54016a55004 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -37,7 +37,7 @@ static struct inet6_protocol udplitev6_protocol = { static int udplite_v6_get_port(struct sock *sk, unsigned short snum) { - return udplite_get_port(sk, snum, &udp_ipv6_ops); + return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); } struct proto udplitev6_prot = { diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index d7ed8aa56ec1..c858537cec4b 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -104,10 +104,8 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) nf_reset(skb); if (decaps) { - if (!(skb->dev->flags&IFF_LOOPBACK)) { - dst_release(skb->dst); - skb->dst = NULL; - } + dst_release(skb->dst); + skb->dst = NULL; netif_rx(skb); return -1; } else { diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index a6c0cdf46ad6..9fc95bc6509f 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -80,6 +80,7 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT); ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); + skb->protocol = htons(ETH_P_IPV6); return 0; } |