X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fipip.c;h=ea398ee43f28740d6b75eee0efe5ecdcd97c54ee;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=68a78731f7224ba7fd798c4addff5b0b970e055f;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 68a78731f..ea398ee43 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -93,6 +93,7 @@ */ +#include #include #include #include @@ -108,11 +109,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -243,7 +244,7 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c if (dev == NULL) return NULL; - nt = dev->priv; + nt = netdev_priv(dev); SET_MODULE_OWNER(dev); dev->init = ipip_tunnel_init; nt->parms = *parms; @@ -255,7 +256,6 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c dev_hold(dev); ipip_tunnel_link(nt); - /* Do not decrement MOD_USE_COUNT here. */ return nt; failed: @@ -269,11 +269,11 @@ static void ipip_tunnel_uninit(struct net_device *dev) tunnels_wc[0] = NULL; write_unlock_bh(&ipip_lock); } else - ipip_tunnel_unlink((struct ip_tunnel*)dev->priv); + ipip_tunnel_unlink(netdev_priv(dev)); dev_put(dev); } -static void ipip_err(struct sk_buff *skb, void *__unused) +static int ipip_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -285,21 +285,22 @@ static void ipip_err(struct sk_buff *skb, void *__unused) int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct ip_tunnel *t; + int err; switch (type) { default: case ICMP_PARAMETERPROB: - return; + return 0; case ICMP_DEST_UNREACH: switch (code) { case ICMP_SR_FAILED: case ICMP_PORT_UNREACH: /* Impossible event. */ - return; + return 0; case ICMP_FRAG_NEEDED: /* Soft state for pmtu is maintained by IP core. */ - return; + return 0; default: /* All others are translated to HOST_UNREACH. rfc2003 contains "deep thoughts" about NET_UNREACH, @@ -310,14 +311,18 @@ static void ipip_err(struct sk_buff *skb, void *__unused) break; case ICMP_TIME_EXCEEDED: if (code != ICMP_EXC_TTL) - return; + return 0; break; } + err = -ENOENT; + read_lock(&ipip_lock); t = ipip_tunnel_lookup(iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; + + err = 0; if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) goto out; @@ -328,7 +333,7 @@ static void ipip_err(struct sk_buff *skb, void *__unused) t->err_time = jiffies; out: read_unlock(&ipip_lock); - return; + return err; #else struct iphdr *iph = (struct iphdr*)dp; int hlen = iph->ihl<<2; @@ -343,15 +348,15 @@ out: struct rtable *rt; if (len < hlen + sizeof(struct iphdr)) - return; + return 0; eiph = (struct iphdr*)(dp + hlen); switch (type) { default: - return; + return 0; case ICMP_PARAMETERPROB: if (skb->h.icmph->un.gateway < hlen) - return; + return 0; /* So... This guy found something strange INSIDE encapsulated packet. Well, he is fool, but what can we do ? @@ -365,16 +370,16 @@ out: case ICMP_SR_FAILED: case ICMP_PORT_UNREACH: /* Impossible event. */ - return; + return 0; case ICMP_FRAG_NEEDED: /* And it is the only really necessary thing :-) */ rel_info = ntohs(skb->h.icmph->un.frag.mtu); if (rel_info < hlen+68) - return; + return 0; rel_info -= hlen; /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */ if (rel_info > ntohs(eiph->tot_len)) - return; + return 0; break; default: /* All others are translated to HOST_UNREACH. @@ -388,14 +393,14 @@ out: break; case ICMP_TIME_EXCEEDED: if (code != ICMP_EXC_TTL) - return; + return 0; break; } /* Prepare fake skb to feed it to icmp_send */ skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 == NULL) - return; + return 0; dst_release(skb2->dst); skb2->dst = NULL; skb_pull(skb2, skb->data - (u8*)eiph); @@ -408,7 +413,7 @@ out: fl.proto = IPPROTO_IPIP; if (ip_route_output_key(&rt, &key)) { kfree_skb(skb2); - return; + return 0; } skb2->dev = rt->u.dst.dev; @@ -423,14 +428,14 @@ out: rt->u.dst.dev->type != ARPHRD_TUNNEL) { ip_rt_put(rt); kfree_skb(skb2); - return; + return 0; } } else { ip_rt_put(rt); if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) || skb2->dst->dev->type != ARPHRD_TUNNEL) { kfree_skb(skb2); - return; + return 0; } } @@ -438,12 +443,12 @@ out: if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { if (rel_info > dst_mtu(skb2->dst)) { kfree_skb(skb2); - return; + return 0; } skb2->dst->ops->update_pmtu(skb2->dst, rel_info); rel_info = htonl(rel_info); } else if (type == ICMP_TIME_EXCEEDED) { - struct ip_tunnel *t = (struct ip_tunnel*)skb2->dev->priv; + struct ip_tunnel *t = netdev_priv(skb2->dev); if (t->parms.iph.ttl) { rel_type = ICMP_DEST_UNREACH; rel_code = ICMP_HOST_UNREACH; @@ -452,7 +457,7 @@ out: icmp_send(skb2, rel_type, rel_code, rel_info); kfree_skb(skb2); - return; + return 0; #endif } @@ -469,9 +474,6 @@ static int ipip_rcv(struct sk_buff *skb) struct iphdr *iph; struct ip_tunnel *tunnel; - if (!pskb_may_pull(skb, sizeof(struct iphdr))) - goto out; - iph = skb->nh.iph; read_lock(&ipip_lock); @@ -503,7 +505,6 @@ static int ipip_rcv(struct sk_buff *skb) } read_unlock(&ipip_lock); -out: return -1; } @@ -514,7 +515,7 @@ out: static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv; + struct ip_tunnel *tunnel = netdev_priv(dev); struct net_device_stats *stats = &tunnel->stat; struct iphdr *tiph = &tunnel->parms.iph; u8 tos = tunnel->parms.iph.tos; @@ -621,6 +622,8 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) skb->h.raw = skb->nh.raw; skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | + IPSKB_REROUTED); dst_release(skb->dst); skb->dst = &rt->u.dst; @@ -673,7 +676,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) t = ipip_tunnel_locate(&p, 0); } if (t == NULL) - t = (struct ip_tunnel*)dev->priv; + t = netdev_priv(dev); memcpy(&p, &t->parms, sizeof(p)); if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) err = -EFAULT; @@ -710,7 +713,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) err = -EINVAL; break; } - t = (struct ip_tunnel*)dev->priv; + t = netdev_priv(dev); ipip_tunnel_unlink(t); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; @@ -764,7 +767,7 @@ done: static struct net_device_stats *ipip_tunnel_get_stats(struct net_device *dev) { - return &(((struct ip_tunnel*)dev->priv)->stat); + return &(((struct ip_tunnel*)netdev_priv(dev))->stat); } static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu) @@ -787,7 +790,7 @@ static void ipip_tunnel_setup(struct net_device *dev) dev->type = ARPHRD_TUNNEL; dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); - dev->mtu = 1500 - sizeof(struct iphdr); + dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr); dev->flags = IFF_NOARP; dev->iflink = 0; dev->addr_len = 4; @@ -799,7 +802,7 @@ static int ipip_tunnel_init(struct net_device *dev) struct ip_tunnel *tunnel; struct iphdr *iph; - tunnel = (struct ip_tunnel*)dev->priv; + tunnel = netdev_priv(dev); iph = &tunnel->parms.iph; tunnel->dev = dev; @@ -837,7 +840,7 @@ static int ipip_tunnel_init(struct net_device *dev) static int __init ipip_fb_tunnel_init(struct net_device *dev) { - struct ip_tunnel *tunnel = dev->priv; + struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; tunnel->dev = dev; @@ -855,6 +858,7 @@ static int __init ipip_fb_tunnel_init(struct net_device *dev) static struct xfrm_tunnel ipip_handler = { .handler = ipip_rcv, .err_handler = ipip_err, + .priority = 1, }; static char banner[] __initdata = @@ -866,7 +870,7 @@ static int __init ipip_init(void) printk(banner); - if (xfrm4_tunnel_register(&ipip_handler) < 0) { + if (xfrm4_tunnel_register(&ipip_handler)) { printk(KERN_INFO "ipip init: can't register tunnel\n"); return -EAGAIN; } @@ -892,12 +896,29 @@ static int __init ipip_init(void) goto out; } +static void __exit ipip_destroy_tunnels(void) +{ + int prio; + + for (prio = 1; prio < 4; prio++) { + int h; + for (h = 0; h < HASH_SIZE; h++) { + struct ip_tunnel *t; + while ((t = tunnels[prio][h]) != NULL) + unregister_netdevice(t->dev); + } + } +} + static void __exit ipip_fini(void) { - if (xfrm4_tunnel_deregister(&ipip_handler) < 0) + if (xfrm4_tunnel_deregister(&ipip_handler)) printk(KERN_INFO "ipip close: can't deregister tunnel\n"); - unregister_netdev(ipip_fb_tunnel_dev); + rtnl_lock(); + ipip_destroy_tunnels(); + unregister_netdevice(ipip_fb_tunnel_dev); + rtnl_unlock(); } module_init(ipip_init);