extern int             ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
 extern int             ip_do_nat(struct sk_buff *skb);
 extern void            ip_send_check(struct iphdr *ip);
+extern int             __ip_local_out(struct sk_buff *skb);
+extern int             ip_local_out(struct sk_buff *skb);
 extern int             ip_queue_xmit(struct sk_buff *skb, int ipfragok);
 extern void            ip_init(void);
 extern int             ip_append_data(struct sock *sk,
 
 #define __NET_IPIP_H 1
 
 #include <linux/if_tunnel.h>
+#include <net/ip.h>
 
 /* Keep error state on tunnel for 30 sec */
 #define IPTUNNEL_ERR_TIMEO     (30*HZ)
        int pkt_len = skb->len;                                         \
                                                                        \
        skb->ip_summed = CHECKSUM_NONE;                                 \
-       iph->tot_len = htons(skb->len);                                 \
        ip_select_ident(iph, &rt->u.dst, NULL);                         \
-       ip_send_check(iph);                                             \
                                                                        \
-       err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output);\
+       err = ip_local_out(skb);                                        \
        if (net_xmit_eval(err) == 0) {                                  \
                stats->tx_bytes += pkt_len;                             \
                stats->tx_packets++;                                    \
 
 
 static int igmpv3_sendpack(struct sk_buff *skb)
 {
-       struct iphdr *pip = ip_hdr(skb);
        struct igmphdr *pig = igmp_hdr(skb);
-       const int iplen = skb->tail - skb->network_header;
        const int igmplen = skb->tail - skb->transport_header;
 
-       pip->tot_len = htons(iplen);
-       ip_send_check(pip);
        pig->csum = ip_compute_csum(igmp_hdr(skb), igmplen);
 
-       return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dev,
-                      dst_output);
+       return ip_local_out(skb);
 }
 
 static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel)
        iph->daddr    = dst;
        iph->saddr    = rt->rt_src;
        iph->protocol = IPPROTO_IGMP;
-       iph->tot_len  = htons(IGMP_SIZE);
        ip_select_ident(iph, &rt->u.dst, NULL);
        ((u8*)&iph[1])[0] = IPOPT_RA;
        ((u8*)&iph[1])[1] = 4;
        ((u8*)&iph[1])[2] = 0;
        ((u8*)&iph[1])[3] = 0;
-       ip_send_check(iph);
 
        ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
        ih->type=type;
        ih->group=group;
        ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
 
-       return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-                      dst_output);
+       return ip_local_out(skb);
 }
 
 static void igmp_gq_timer_expire(unsigned long data)
 
        iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 }
 
+int __ip_local_out(struct sk_buff *skb)
+{
+       struct iphdr *iph = ip_hdr(skb);
+
+       iph->tot_len = htons(skb->len);
+       ip_send_check(iph);
+       return nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dst->dev,
+                      dst_output);
+}
+
+int ip_local_out(struct sk_buff *skb)
+{
+       int err;
+
+       err = __ip_local_out(skb);
+       if (likely(err == 1))
+               err = dst_output(skb);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(ip_local_out);
+
 /* dev_loopback_xmit for use with netfilter. */
 static int ip_dev_loopback_xmit(struct sk_buff *newskb)
 {
        iph->daddr    = rt->rt_dst;
        iph->saddr    = rt->rt_src;
        iph->protocol = sk->sk_protocol;
-       iph->tot_len  = htons(skb->len);
        ip_select_ident(iph, &rt->u.dst, sk);
 
        if (opt && opt->optlen) {
                iph->ihl += opt->optlen>>2;
                ip_options_build(skb, opt, daddr, rt, 0);
        }
-       ip_send_check(iph);
 
        skb->priority = sk->sk_priority;
 
        /* Send it out. */
-       return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-                      dst_output);
+       return ip_local_out(skb);
 }
 
 EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
        skb_reset_network_header(skb);
        iph = ip_hdr(skb);
        *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
-       iph->tot_len = htons(skb->len);
        if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
                iph->frag_off = htons(IP_DF);
        else
        ip_select_ident_more(iph, &rt->u.dst, sk,
                             (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 
-       /* Add an IP checksum. */
-       ip_send_check(iph);
-
        skb->priority = sk->sk_priority;
 
-       return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-                      dst_output);
+       return ip_local_out(skb);
 
 no_route:
        IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
                ip_options_build(skb, opt, inet->cork.addr, rt, 0);
        }
        iph->tos = inet->tos;
-       iph->tot_len = htons(skb->len);
        iph->frag_off = df;
        ip_select_ident(iph, &rt->u.dst, sk);
        iph->ttl = ttl;
        iph->protocol = sk->sk_protocol;
        iph->saddr = rt->rt_src;
        iph->daddr = rt->rt_dst;
-       ip_send_check(iph);
 
        skb->priority = sk->sk_priority;
        skb->dst = dst_clone(&rt->u.dst);
                        skb_transport_header(skb))->type);
 
        /* Netfilter gets whole the not fragmented skb. */
-       err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
-                     skb->dst->dev, dst_output);
+       err = ip_local_out(skb);
        if (err) {
                if (err > 0)
                        err = inet->recverr ? net_xmit_errno(err) : 0;
 
  */
 
 #include <linux/kernel.h>
-#include <linux/ip.h>
 #include <linux/tcp.h>                  /* for tcphdr */
+#include <net/ip.h>
 #include <net/tcp.h>                    /* for csum_tcpudp_magic */
 #include <net/udp.h>
 #include <net/icmp.h>                   /* for icmp_send */
        iph->daddr              =       rt->rt_dst;
        iph->saddr              =       rt->rt_src;
        iph->ttl                =       old_iph->ttl;
-       iph->tot_len            =       htons(skb->len);
        ip_select_ident(iph, &rt->u.dst, NULL);
-       ip_send_check(iph);
 
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
 
-       IP_VS_XMIT(skb, rt);
+       ip_local_out(skb);
 
        LeaveFunction(10);
 
 
        /* Truncate to length (no data) */
        tcph->doff = sizeof(struct tcphdr)/4;
        skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
-       niph->tot_len = htons(nskb->len);
 
        if (tcph->ack) {
                needs_ack = 0;
        /* Adjust IP TTL */
        niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
 
-       /* Adjust IP checksum */
-       niph->check = 0;
-       niph->check = ip_fast_csum(skb_network_header(nskb), niph->ihl);
-
        /* "Never happens" */
        if (nskb->len > dst_mtu(nskb->dst))
                goto free_nskb;
 
        nf_ct_attach(nskb, oldskb);
 
-       NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
-               dst_output);
+       ip_local_out(nskb);
        return;
 
  free_nskb:
 
 
 static inline int xfrm4_output_one(struct sk_buff *skb)
 {
-       struct iphdr *iph;
        int err;
 
        err = xfrm_output(skb);
        if (err)
                goto error_nolock;
 
-       iph = ip_hdr(skb);
-       iph->tot_len = htons(skb->len);
-       ip_send_check(iph);
-
        IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
        err = 0;
 
        while (likely((err = xfrm4_output_one(skb)) == 0)) {
                nf_reset(skb);
 
-               err = nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
-                             skb->dst->dev, dst_output);
+               err = __ip_local_out(skb);
                if (unlikely(err != 1))
                        break;