diff options
Diffstat (limited to 'net/ipv6/icmp.c')
| -rw-r--r-- | net/ipv6/icmp.c | 63 | 
1 files changed, 28 insertions, 35 deletions
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index eef8d945b36..f6c84a6eb23 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -67,6 +67,7 @@  #include <net/icmp.h>  #include <net/xfrm.h>  #include <net/inet_common.h> +#include <net/dsfield.h>  #include <asm/uaccess.h> @@ -315,8 +316,10 @@ static void mip6_addr_swap(struct sk_buff *skb)  static inline void mip6_addr_swap(struct sk_buff *skb) {}  #endif -struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb, -				      struct sock *sk, struct flowi6 *fl6) +static struct dst_entry *icmpv6_route_lookup(struct net *net, +					     struct sk_buff *skb, +					     struct sock *sk, +					     struct flowi6 *fl6)  {  	struct dst_entry *dst, *dst2;  	struct flowi6 fl2; @@ -397,6 +400,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)  	int len;  	int hlimit;  	int err = 0; +	u32 mark = IP6_REPLY_MARK(net, skb->mark);  	if ((u8 *)hdr < skb->head ||  	    (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) @@ -410,7 +414,8 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)  	 */  	addr_type = ipv6_addr_type(&hdr->daddr); -	if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0)) +	if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) || +	    ipv6_chk_acast_addr_src(net, skb->dev, &hdr->daddr))  		saddr = &hdr->daddr;  	/* @@ -462,6 +467,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)  	fl6.daddr = hdr->saddr;  	if (saddr)  		fl6.saddr = *saddr; +	fl6.flowi6_mark = mark;  	fl6.flowi6_oif = iif;  	fl6.fl6_icmp_type = type;  	fl6.fl6_icmp_code = code; @@ -470,6 +476,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)  	sk = icmpv6_xmit_lock(net);  	if (sk == NULL)  		return; +	sk->sk_mark = mark;  	np = inet6_sk(sk);  	if (!icmpv6_xrlim_allow(sk, type, &fl6)) @@ -489,12 +496,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)  	if (IS_ERR(dst))  		goto out; -	if (ipv6_addr_is_multicast(&fl6.daddr)) -		hlimit = np->mcast_hops; -	else -		hlimit = np->hop_limit; -	if (hlimit < 0) -		hlimit = ip6_dst_hoplimit(dst); +	hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);  	msg.skb = skb;  	msg.offset = skb_network_offset(skb); @@ -516,7 +518,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)  			      np->tclass, NULL, &fl6, (struct rt6_info *)dst,  			      MSG_DONTWAIT, np->dontfrag);  	if (err) { -		ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS); +		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);  		ip6_flush_pending_frames(sk);  	} else {  		err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, @@ -551,10 +553,14 @@ static void icmpv6_echo_reply(struct sk_buff *skb)  	struct dst_entry *dst;  	int err = 0;  	int hlimit; +	u8 tclass; +	u32 mark = IP6_REPLY_MARK(net, skb->mark);  	saddr = &ipv6_hdr(skb)->daddr; -	if (!ipv6_unicast_destination(skb)) +	if (!ipv6_unicast_destination(skb) && +	    !(net->ipv6.sysctl.anycast_src_echo_reply && +	      ipv6_anycast_destination(skb)))  		saddr = NULL;  	memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr)); @@ -567,11 +573,13 @@ static void icmpv6_echo_reply(struct sk_buff *skb)  		fl6.saddr = *saddr;  	fl6.flowi6_oif = skb->dev->ifindex;  	fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; +	fl6.flowi6_mark = mark;  	security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));  	sk = icmpv6_xmit_lock(net);  	if (sk == NULL)  		return; +	sk->sk_mark = mark;  	np = inet6_sk(sk);  	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) @@ -586,12 +594,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)  	if (IS_ERR(dst))  		goto out; -	if (ipv6_addr_is_multicast(&fl6.daddr)) -		hlimit = np->mcast_hops; -	else -		hlimit = np->hop_limit; -	if (hlimit < 0) -		hlimit = ip6_dst_hoplimit(dst); +	hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);  	idev = __in6_dev_get(skb->dev); @@ -599,8 +602,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb)  	msg.offset = 0;  	msg.type = ICMPV6_ECHO_REPLY; +	tclass = ipv6_get_dsfield(ipv6_hdr(skb));  	err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), -				sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl6, +				sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl6,  				(struct rt6_info *)dst, MSG_DONTWAIT,  				np->dontfrag); @@ -694,22 +698,11 @@ static int icmpv6_rcv(struct sk_buff *skb)  	saddr = &ipv6_hdr(skb)->saddr;  	daddr = &ipv6_hdr(skb)->daddr; -	/* Perform checksum. */ -	switch (skb->ip_summed) { -	case CHECKSUM_COMPLETE: -		if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, -				     skb->csum)) -			break; -		/* fall through */ -	case CHECKSUM_NONE: -		skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len, -					     IPPROTO_ICMPV6, 0)); -		if (__skb_checksum_complete(skb)) { -			LIMIT_NETDEBUG(KERN_DEBUG -				       "ICMPv6 checksum failed [%pI6c > %pI6c]\n", -				       saddr, daddr); -			goto csum_error; -		} +	if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { +		LIMIT_NETDEBUG(KERN_DEBUG +			       "ICMPv6 checksum failed [%pI6c > %pI6c]\n", +			       saddr, daddr); +		goto csum_error;  	}  	if (!pskb_pull(skb, sizeof(*hdr))) @@ -984,7 +977,7 @@ int icmpv6_err_convert(u8 type, u8 code, int *err)  EXPORT_SYMBOL(icmpv6_err_convert);  #ifdef CONFIG_SYSCTL -struct ctl_table ipv6_icmp_table_template[] = { +static struct ctl_table ipv6_icmp_table_template[] = {  	{  		.procname	= "ratelimit",  		.data		= &init_net.ipv6.sysctl.icmpv6_time,  | 
