diff options
| author | David S. Miller <davem@davemloft.net> | 2011-03-01 22:06:22 -0800 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-03-01 22:07:37 -0800 | 
| commit | b42835dbe83d725198c7ab0bbe726d6dfd92a634 (patch) | |
| tree | 8728dccb3fa9bb54dba53a0a00c6e2818b843a91 | |
| parent | f6d460cf0ed16d35aec48f823685e7a0e0283d84 (diff) | |
| download | olio-linux-3.10-b42835dbe83d725198c7ab0bbe726d6dfd92a634.tar.xz olio-linux-3.10-b42835dbe83d725198c7ab0bbe726d6dfd92a634.zip  | |
ipv6: Make icmp route lookup code a bit clearer.
The route lookup code in icmpv6_send() is slightly tricky as a result of
having to handle all of the requirements of RFC 4301 host relookups.
Pull the route resolution into a seperate function, so that the error
handling and route reference counting is hopefully easier to see and
contained wholly within this new routine.
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | net/ipv6/icmp.c | 117 | 
1 files changed, 66 insertions, 51 deletions
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index a31d91b04c8..e332bae104e 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -300,6 +300,70 @@ static void mip6_addr_swap(struct sk_buff *skb)  static inline void mip6_addr_swap(struct sk_buff *skb) {}  #endif +static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb, +					     struct sock *sk, struct flowi *fl) +{ +	struct dst_entry *dst, *dst2; +	struct flowi fl2; +	int err; + +	err = ip6_dst_lookup(sk, &dst, fl); +	if (err) +		return ERR_PTR(err); + +	/* +	 * We won't send icmp if the destination is known +	 * anycast. +	 */ +	if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { +		LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n"); +		dst_release(dst); +		return ERR_PTR(-EINVAL); +	} + +	/* No need to clone since we're just using its address. */ +	dst2 = dst; + +	err = xfrm_lookup(net, &dst, fl, sk, 0); +	switch (err) { +	case 0: +		if (dst != dst2) +			return dst; +		break; +	case -EPERM: +		dst = NULL; +		break; +	default: +		return ERR_PTR(err); +	} + +	err = xfrm_decode_session_reverse(skb, &fl2, AF_INET6); +	if (err) +		goto relookup_failed; + +	err = ip6_dst_lookup(sk, &dst2, &fl2); +	if (err) +		goto relookup_failed; + +	err = xfrm_lookup(net, &dst2, &fl2, sk, XFRM_LOOKUP_ICMP); +	switch (err) { +	case 0: +		dst_release(dst); +		dst = dst2; +		break; +	case -EPERM: +		dst_release(dst); +		return ERR_PTR(err); +	default: +		goto relookup_failed; +	} + +relookup_failed: +	if (dst) +		return dst; +	return ERR_PTR(err); +} +  /*   *	Send an ICMP message in response to a packet in error   */ @@ -312,10 +376,8 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)  	struct ipv6_pinfo *np;  	struct in6_addr *saddr = NULL;  	struct dst_entry *dst; -	struct dst_entry *dst2;  	struct icmp6hdr tmp_hdr;  	struct flowi fl; -	struct flowi fl2;  	struct icmpv6_msg msg;  	int iif = 0;  	int addr_type = 0; @@ -408,57 +470,10 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)  	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))  		fl.oif = np->mcast_oif; -	err = ip6_dst_lookup(sk, &dst, &fl); -	if (err) -		goto out; - -	/* -	 * We won't send icmp if the destination is known -	 * anycast. -	 */ -	if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { -		LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n"); -		goto out_dst_release; -	} - -	/* No need to clone since we're just using its address. */ -	dst2 = dst; - -	err = xfrm_lookup(net, &dst, &fl, sk, 0); -	switch (err) { -	case 0: -		if (dst != dst2) -			goto route_done; -		break; -	case -EPERM: -		dst = NULL; -		break; -	default: +	dst = icmpv6_route_lookup(net, skb, sk, &fl); +	if (IS_ERR(dst))  		goto out; -	} - -	if (xfrm_decode_session_reverse(skb, &fl2, AF_INET6)) -		goto relookup_failed; - -	if (ip6_dst_lookup(sk, &dst2, &fl2)) -		goto relookup_failed; - -	err = xfrm_lookup(net, &dst2, &fl2, sk, XFRM_LOOKUP_ICMP); -	switch (err) { -	case 0: -		dst_release(dst); -		dst = dst2; -		break; -	case -EPERM: -		goto out_dst_release; -	default: -relookup_failed: -		if (!dst) -			goto out; -		break; -	} -route_done:  	if (ipv6_addr_is_multicast(&fl.fl6_dst))  		hlimit = np->mcast_hops;  	else  |