diff options
Diffstat (limited to 'net/ipv4/ipip.c')
| -rw-r--r-- | net/ipv4/ipip.c | 59 | 
1 files changed, 42 insertions, 17 deletions
| diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index fb1ad22b5e29..cdd627355ed1 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -128,43 +128,68 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly;  static int ipip_err(struct sk_buff *skb, u32 info)  { - -/* All the routers (except for Linux) return only -   8 bytes of packet payload. It means, that precise relaying of -   ICMP in the real Internet is absolutely infeasible. - */ +	/* All the routers (except for Linux) return only +	 * 8 bytes of packet payload. It means, that precise relaying of +	 * ICMP in the real Internet is absolutely infeasible. +	 */  	struct net *net = dev_net(skb->dev);  	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);  	const struct iphdr *iph = (const struct iphdr *)skb->data; -	struct ip_tunnel *t; -	int err;  	const int type = icmp_hdr(skb)->type;  	const int code = icmp_hdr(skb)->code; +	struct ip_tunnel *t; +	int err = 0; + +	switch (type) { +	case ICMP_DEST_UNREACH: +		switch (code) { +		case ICMP_SR_FAILED: +			/* Impossible event. */ +			goto out; +		default: +			/* All others are translated to HOST_UNREACH. +			 * rfc2003 contains "deep thoughts" about NET_UNREACH, +			 * I believe they are just ether pollution. --ANK +			 */ +			break; +		} +		break; + +	case ICMP_TIME_EXCEEDED: +		if (code != ICMP_EXC_TTL) +			goto out; +		break; + +	case ICMP_REDIRECT: +		break; + +	default: +		goto out; +	} -	err = -ENOENT;  	t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,  			     iph->daddr, iph->saddr, 0); -	if (!t) +	if (!t) { +		err = -ENOENT;  		goto out; +	}  	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { -		ipv4_update_pmtu(skb, dev_net(skb->dev), info, -				 t->parms.link, 0, iph->protocol, 0); -		err = 0; +		ipv4_update_pmtu(skb, net, info, t->parms.link, 0, +				 iph->protocol, 0);  		goto out;  	}  	if (type == ICMP_REDIRECT) { -		ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, -			      iph->protocol, 0); -		err = 0; +		ipv4_redirect(skb, net, t->parms.link, 0, iph->protocol, 0);  		goto out;  	} -	if (t->parms.iph.daddr == 0) +	if (t->parms.iph.daddr == 0) { +		err = -ENOENT;  		goto out; +	} -	err = 0;  	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)  		goto out; |