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>
This commit is contained in:
parent
f6d460cf0e
commit
b42835dbe8
117
net/ipv6/icmp.c
117
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)
|
||||
dst = icmpv6_route_lookup(net, skb, sk, &fl);
|
||||
if (IS_ERR(dst))
|
||||
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:
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue