|
@@ -128,43 +128,68 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly;
|
|
|
|
|
|
static int ipip_err(struct sk_buff *skb, u32 info)
|
|
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 net *net = dev_net(skb->dev);
|
|
struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
|
|
struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
|
|
const struct iphdr *iph = (const struct iphdr *)skb->data;
|
|
const struct iphdr *iph = (const struct iphdr *)skb->data;
|
|
- struct ip_tunnel *t;
|
|
|
|
- int err;
|
|
|
|
const int type = icmp_hdr(skb)->type;
|
|
const int type = icmp_hdr(skb)->type;
|
|
const int code = icmp_hdr(skb)->code;
|
|
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,
|
|
t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
|
|
iph->daddr, iph->saddr, 0);
|
|
iph->daddr, iph->saddr, 0);
|
|
- if (!t)
|
|
|
|
|
|
+ if (!t) {
|
|
|
|
+ err = -ENOENT;
|
|
goto out;
|
|
goto out;
|
|
|
|
+ }
|
|
|
|
|
|
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
|
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;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
if (type == ICMP_REDIRECT) {
|
|
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;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- if (t->parms.iph.daddr == 0)
|
|
|
|
|
|
+ if (t->parms.iph.daddr == 0) {
|
|
|
|
+ err = -ENOENT;
|
|
goto out;
|
|
goto out;
|
|
|
|
+ }
|
|
|
|
|
|
- err = 0;
|
|
|
|
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
|
|
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
|
|
goto out;
|
|
goto out;
|
|
|
|
|