]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv4/netfilter/nf_nat_helper.c
[NETFILTER]: nf_conntrack_ipv4: fix "Frag of proto ..." messages
[linux-2.6-omap-h63xx.git] / net / ipv4 / netfilter / nf_nat_helper.c
index 49a90c39ffce888de7c0bd664a70a9e279619b83..93d8a0a8f03562894b2840032f438dd67c4cf39e 100644 (file)
 #include <net/netfilter/nf_nat_core.h>
 #include <net/netfilter/nf_nat_helper.h>
 
-#if 0
-#define DEBUGP printk
-#define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos);
-#else
-#define DEBUGP(format, args...)
-#define DUMP_OFFSET(x)
-#endif
+#define DUMP_OFFSET(x) \
+       pr_debug("offset_before=%d, offset_after=%d, correction_pos=%u\n", \
+                x->offset_before, x->offset_after, x->correction_pos);
 
 static DEFINE_SPINLOCK(nf_nat_seqofs_lock);
 
@@ -47,15 +43,15 @@ adjust_tcp_sequence(u32 seq,
        struct nf_nat_seq *this_way, *other_way;
        struct nf_conn_nat *nat = nfct_nat(ct);
 
-       DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n",
-               (*skb)->len, new_size);
+       pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n",
+                ntohl(seq), seq);
 
        dir = CTINFO2DIR(ctinfo);
 
-       this_way = &nat->info.seq[dir];
-       other_way = &nat->info.seq[!dir];
+       this_way = &nat->seq[dir];
+       other_way = &nat->seq[!dir];
 
-       DEBUGP("nf_nat_resize_packet: Seq_offset before: ");
+       pr_debug("nf_nat_resize_packet: Seq_offset before: ");
        DUMP_OFFSET(this_way);
 
        spin_lock_bh(&nf_nat_seqofs_lock);
@@ -72,7 +68,7 @@ adjust_tcp_sequence(u32 seq,
        }
        spin_unlock_bh(&nf_nat_seqofs_lock);
 
-       DEBUGP("nf_nat_resize_packet: Seq_offset after: ");
+       pr_debug("nf_nat_resize_packet: Seq_offset after: ");
        DUMP_OFFSET(this_way);
 }
 
@@ -87,32 +83,31 @@ static void mangle_contents(struct sk_buff *skb,
        unsigned char *data;
 
        BUG_ON(skb_is_nonlinear(skb));
-       data = (unsigned char *)skb->nh.iph + dataoff;
+       data = skb_network_header(skb) + dataoff;
 
        /* move post-replacement */
        memmove(data + match_offset + rep_len,
                data + match_offset + match_len,
-               skb->tail - (data + match_offset + match_len));
+               skb->tail - (skb->network_header + dataoff +
+                            match_offset + match_len));
 
        /* insert data from buffer */
        memcpy(data + match_offset, rep_buffer, rep_len);
 
        /* update skb info */
        if (rep_len > match_len) {
-               DEBUGP("nf_nat_mangle_packet: Extending packet by "
-                      "%u from %u bytes\n", rep_len - match_len,
-                      skb->len);
+               pr_debug("nf_nat_mangle_packet: Extending packet by "
+                        "%u from %u bytes\n", rep_len - match_len, skb->len);
                skb_put(skb, rep_len - match_len);
        } else {
-               DEBUGP("nf_nat_mangle_packet: Shrinking packet from "
-                      "%u from %u bytes\n", match_len - rep_len,
-                      skb->len);
+               pr_debug("nf_nat_mangle_packet: Shrinking packet from "
+                        "%u from %u bytes\n", match_len - rep_len, skb->len);
                __skb_trim(skb, skb->len + rep_len - match_len);
        }
 
        /* fix IP hdr checksum information */
-       skb->nh.iph->tot_len = htons(skb->len);
-       ip_send_check(skb->nh.iph);
+       ip_hdr(skb)->tot_len = htons(skb->len);
+       ip_send_check(ip_hdr(skb));
 }
 
 /* Unusual, but possible case. */
@@ -152,6 +147,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
                         const char *rep_buffer,
                         unsigned int rep_len)
 {
+       struct rtable *rt = (struct rtable *)(*pskb)->dst;
        struct iphdr *iph;
        struct tcphdr *tcph;
        int oldlen, datalen;
@@ -166,7 +162,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
 
        SKB_LINEAR_ASSERT(*pskb);
 
-       iph = (*pskb)->nh.iph;
+       iph = ip_hdr(*pskb);
        tcph = (void *)iph + iph->ihl*4;
 
        oldlen = (*pskb)->len - iph->ihl*4;
@@ -175,11 +171,22 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
 
        datalen = (*pskb)->len - iph->ihl*4;
        if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
-               tcph->check = 0;
-               tcph->check = tcp_v4_check(datalen,
-                                          iph->saddr, iph->daddr,
-                                          csum_partial((char *)tcph,
-                                                       datalen, 0));
+               if (!(rt->rt_flags & RTCF_LOCAL) &&
+                   (*pskb)->dev->features & NETIF_F_V4_CSUM) {
+                       (*pskb)->ip_summed = CHECKSUM_PARTIAL;
+                       (*pskb)->csum_start = skb_headroom(*pskb) +
+                                             skb_network_offset(*pskb) +
+                                             iph->ihl * 4;
+                       (*pskb)->csum_offset = offsetof(struct tcphdr, check);
+                       tcph->check = ~tcp_v4_check(datalen,
+                                                   iph->saddr, iph->daddr, 0);
+               } else {
+                       tcph->check = 0;
+                       tcph->check = tcp_v4_check(datalen,
+                                                  iph->saddr, iph->daddr,
+                                                  csum_partial(tcph,
+                                                               datalen, 0));
+               }
        } else
                nf_proto_csum_replace2(&tcph->check, *pskb,
                                       htons(oldlen), htons(datalen), 1);
@@ -190,7 +197,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
                                    (int)rep_len - (int)match_len,
                                    ct, ctinfo);
                /* Tell TCP window tracking about seq change */
-               nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4,
+               nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb),
                                        ct, CTINFO2DIR(ctinfo));
        }
        return 1;
@@ -216,12 +223,13 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
                         const char *rep_buffer,
                         unsigned int rep_len)
 {
+       struct rtable *rt = (struct rtable *)(*pskb)->dst;
        struct iphdr *iph;
        struct udphdr *udph;
        int datalen, oldlen;
 
        /* UDP helpers might accidentally mangle the wrong packet */
-       iph = (*pskb)->nh.iph;
+       iph = ip_hdr(*pskb);
        if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) +
                               match_offset + match_len)
                return 0;
@@ -234,7 +242,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
            !enlarge_skb(pskb, rep_len - match_len))
                return 0;
 
-       iph = (*pskb)->nh.iph;
+       iph = ip_hdr(*pskb);
        udph = (void *)iph + iph->ihl*4;
 
        oldlen = (*pskb)->len - iph->ihl*4;
@@ -250,13 +258,25 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
                return 1;
 
        if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
-               udph->check = 0;
-               udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
-                                               datalen, IPPROTO_UDP,
-                                               csum_partial((char *)udph,
-                                                            datalen, 0));
-               if (!udph->check)
-                       udph->check = CSUM_MANGLED_0;
+               if (!(rt->rt_flags & RTCF_LOCAL) &&
+                   (*pskb)->dev->features & NETIF_F_V4_CSUM) {
+                       (*pskb)->ip_summed = CHECKSUM_PARTIAL;
+                       (*pskb)->csum_start = skb_headroom(*pskb) +
+                                             skb_network_offset(*pskb) +
+                                             iph->ihl * 4;
+                       (*pskb)->csum_offset = offsetof(struct udphdr, check);
+                       udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                                        datalen, IPPROTO_UDP,
+                                                        0);
+               } else {
+                       udph->check = 0;
+                       udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                                       datalen, IPPROTO_UDP,
+                                                       csum_partial(udph,
+                                                                    datalen, 0));
+                       if (!udph->check)
+                               udph->check = CSUM_MANGLED_0;
+               }
        } else
                nf_proto_csum_replace2(&udph->check, *pskb,
                                       htons(oldlen), htons(datalen), 1);
@@ -294,9 +314,9 @@ sack_adjust(struct sk_buff *skb,
                        new_end_seq = htonl(ntohl(sack->end_seq)
                                      - natseq->offset_before);
 
-               DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
-                       ntohl(sack->start_seq), new_start_seq,
-                       ntohl(sack->end_seq), new_end_seq);
+               pr_debug("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
+                        ntohl(sack->start_seq), new_start_seq,
+                        ntohl(sack->end_seq), new_end_seq);
 
                nf_proto_csum_replace4(&tcph->check, skb,
                                       sack->start_seq, new_start_seq, 0);
@@ -318,8 +338,8 @@ nf_nat_sack_adjust(struct sk_buff **pskb,
        unsigned int dir, optoff, optend;
        struct nf_conn_nat *nat = nfct_nat(ct);
 
-       optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr);
-       optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4;
+       optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr);
+       optend = ip_hdrlen(*pskb) + tcph->doff * 4;
 
        if (!skb_make_writable(pskb, optend))
                return 0;
@@ -346,8 +366,7 @@ nf_nat_sack_adjust(struct sk_buff **pskb,
                            op[1] >= 2+TCPOLEN_SACK_PERBLOCK &&
                            ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
                                sack_adjust(*pskb, tcph, optoff+2,
-                                           optoff+op[1],
-                                           &nat->info.seq[!dir]);
+                                           optoff+op[1], &nat->seq[!dir]);
                        optoff += op[1];
                }
        }
@@ -368,13 +387,13 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
 
        dir = CTINFO2DIR(ctinfo);
 
-       this_way = &nat->info.seq[dir];
-       other_way = &nat->info.seq[!dir];
+       this_way = &nat->seq[dir];
+       other_way = &nat->seq[!dir];
 
-       if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
+       if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
                return 0;
 
-       tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
+       tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb);
        if (after(ntohl(tcph->seq), this_way->correction_pos))
                newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
        else
@@ -389,9 +408,9 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
        nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0);
        nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0);
 
-       DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n",
-               ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
-               ntohl(newack));
+       pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n",
+                ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
+                ntohl(newack));
 
        tcph->seq = newseq;
        tcph->ack_seq = newack;
@@ -399,7 +418,7 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
        if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo))
                return 0;
 
-       nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, ct, dir);
+       nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb), ct, dir);
 
        return 1;
 }