Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
[sfrench/cifs-2.6.git] / net / ipv4 / netfilter / nf_nat_helper.c
index 93d8a0a8f03562894b2840032f438dd67c4cf39e..ca57f47bbd255b14f2a6fd9d8c6b04a7918a3ab5 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/netfilter_ipv4.h>
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_protocol.h>
@@ -43,8 +44,7 @@ adjust_tcp_sequence(u32 seq,
        struct nf_nat_seq *this_way, *other_way;
        struct nf_conn_nat *nat = nfct_nat(ct);
 
-       pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n",
-                ntohl(seq), seq);
+       pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n", seq, seq);
 
        dir = CTINFO2DIR(ctinfo);
 
@@ -111,22 +111,14 @@ static void mangle_contents(struct sk_buff *skb,
 }
 
 /* Unusual, but possible case. */
-static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
+static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
 {
-       struct sk_buff *nskb;
-
-       if ((*pskb)->len + extra > 65535)
+       if (skb->len + extra > 65535)
                return 0;
 
-       nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC);
-       if (!nskb)
+       if (pskb_expand_head(skb, 0, extra - skb_tailroom(skb), GFP_ATOMIC))
                return 0;
 
-       /* Transfer socket to new skb. */
-       if ((*pskb)->sk)
-               skb_set_owner_w(nskb, (*pskb)->sk);
-       kfree_skb(*pskb);
-       *pskb = nskb;
        return 1;
 }
 
@@ -139,7 +131,7 @@ static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
  *
  * */
 int
-nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
+nf_nat_mangle_tcp_packet(struct sk_buff *skb,
                         struct nf_conn *ct,
                         enum ip_conntrack_info ctinfo,
                         unsigned int match_offset,
@@ -147,37 +139,37 @@ 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 rtable *rt = (struct rtable *)skb->dst;
        struct iphdr *iph;
        struct tcphdr *tcph;
        int oldlen, datalen;
 
-       if (!skb_make_writable(pskb, (*pskb)->len))
+       if (!skb_make_writable(skb, skb->len))
                return 0;
 
        if (rep_len > match_len &&
-           rep_len - match_len > skb_tailroom(*pskb) &&
-           !enlarge_skb(pskb, rep_len - match_len))
+           rep_len - match_len > skb_tailroom(skb) &&
+           !enlarge_skb(skb, rep_len - match_len))
                return 0;
 
-       SKB_LINEAR_ASSERT(*pskb);
+       SKB_LINEAR_ASSERT(skb);
 
-       iph = ip_hdr(*pskb);
+       iph = ip_hdr(skb);
        tcph = (void *)iph + iph->ihl*4;
 
-       oldlen = (*pskb)->len - iph->ihl*4;
-       mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
+       oldlen = skb->len - iph->ihl*4;
+       mangle_contents(skb, iph->ihl*4 + tcph->doff*4,
                        match_offset, match_len, rep_buffer, rep_len);
 
-       datalen = (*pskb)->len - iph->ihl*4;
-       if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
+       datalen = skb->len - iph->ihl*4;
+       if (skb->ip_summed != CHECKSUM_PARTIAL) {
                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);
+                   skb->dev->features & NETIF_F_V4_CSUM) {
+                       skb->ip_summed = CHECKSUM_PARTIAL;
+                       skb->csum_start = skb_headroom(skb) +
+                                         skb_network_offset(skb) +
+                                         iph->ihl * 4;
+                       skb->csum_offset = offsetof(struct tcphdr, check);
                        tcph->check = ~tcp_v4_check(datalen,
                                                    iph->saddr, iph->daddr, 0);
                } else {
@@ -188,8 +180,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
                                                                datalen, 0));
                }
        } else
-               nf_proto_csum_replace2(&tcph->check, *pskb,
-                                      htons(oldlen), htons(datalen), 1);
+               inet_proto_csum_replace2(&tcph->check, skb,
+                                        htons(oldlen), htons(datalen), 1);
 
        if (rep_len != match_len) {
                set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
@@ -197,8 +189,10 @@ 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, ip_hdrlen(*pskb),
+               nf_conntrack_tcp_update(skb, ip_hdrlen(skb),
                                        ct, CTINFO2DIR(ctinfo));
+
+               nf_conntrack_event_cache(IPCT_NATSEQADJ, skb);
        }
        return 1;
 }
@@ -215,7 +209,7 @@ EXPORT_SYMBOL(nf_nat_mangle_tcp_packet);
  *       should be fairly easy to do.
  */
 int
-nf_nat_mangle_udp_packet(struct sk_buff **pskb,
+nf_nat_mangle_udp_packet(struct sk_buff *skb,
                         struct nf_conn *ct,
                         enum ip_conntrack_info ctinfo,
                         unsigned int match_offset,
@@ -223,48 +217,48 @@ 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 rtable *rt = (struct rtable *)skb->dst;
        struct iphdr *iph;
        struct udphdr *udph;
        int datalen, oldlen;
 
        /* UDP helpers might accidentally mangle the wrong packet */
-       iph = ip_hdr(*pskb);
-       if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) +
+       iph = ip_hdr(skb);
+       if (skb->len < iph->ihl*4 + sizeof(*udph) +
                               match_offset + match_len)
                return 0;
 
-       if (!skb_make_writable(pskb, (*pskb)->len))
+       if (!skb_make_writable(skb, skb->len))
                return 0;
 
        if (rep_len > match_len &&
-           rep_len - match_len > skb_tailroom(*pskb) &&
-           !enlarge_skb(pskb, rep_len - match_len))
+           rep_len - match_len > skb_tailroom(skb) &&
+           !enlarge_skb(skb, rep_len - match_len))
                return 0;
 
-       iph = ip_hdr(*pskb);
+       iph = ip_hdr(skb);
        udph = (void *)iph + iph->ihl*4;
 
-       oldlen = (*pskb)->len - iph->ihl*4;
-       mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph),
+       oldlen = skb->len - iph->ihl*4;
+       mangle_contents(skb, iph->ihl*4 + sizeof(*udph),
                        match_offset, match_len, rep_buffer, rep_len);
 
        /* update the length of the UDP packet */
-       datalen = (*pskb)->len - iph->ihl*4;
+       datalen = skb->len - iph->ihl*4;
        udph->len = htons(datalen);
 
        /* fix udp checksum if udp checksum was previously calculated */
-       if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL)
+       if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
                return 1;
 
-       if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
+       if (skb->ip_summed != CHECKSUM_PARTIAL) {
                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);
+                   skb->dev->features & NETIF_F_V4_CSUM) {
+                       skb->ip_summed = CHECKSUM_PARTIAL;
+                       skb->csum_start = skb_headroom(skb) +
+                                         skb_network_offset(skb) +
+                                         iph->ihl * 4;
+                       skb->csum_offset = offsetof(struct udphdr, check);
                        udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
                                                         datalen, IPPROTO_UDP,
                                                         0);
@@ -278,8 +272,8 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
                                udph->check = CSUM_MANGLED_0;
                }
        } else
-               nf_proto_csum_replace2(&udph->check, *pskb,
-                                      htons(oldlen), htons(datalen), 1);
+               inet_proto_csum_replace2(&udph->check, skb,
+                                        htons(oldlen), htons(datalen), 1);
 
        return 1;
 }
@@ -318,10 +312,10 @@ sack_adjust(struct sk_buff *skb,
                         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);
-               nf_proto_csum_replace4(&tcph->check, skb,
-                                      sack->end_seq, new_end_seq, 0);
+               inet_proto_csum_replace4(&tcph->check, skb,
+                                        sack->start_seq, new_start_seq, 0);
+               inet_proto_csum_replace4(&tcph->check, skb,
+                                        sack->end_seq, new_end_seq, 0);
                sack->start_seq = new_start_seq;
                sack->end_seq = new_end_seq;
                sackoff += sizeof(*sack);
@@ -330,7 +324,7 @@ sack_adjust(struct sk_buff *skb,
 
 /* TCP SACK sequence number adjustment */
 static inline unsigned int
-nf_nat_sack_adjust(struct sk_buff **pskb,
+nf_nat_sack_adjust(struct sk_buff *skb,
                   struct tcphdr *tcph,
                   struct nf_conn *ct,
                   enum ip_conntrack_info ctinfo)
@@ -338,17 +332,17 @@ nf_nat_sack_adjust(struct sk_buff **pskb,
        unsigned int dir, optoff, optend;
        struct nf_conn_nat *nat = nfct_nat(ct);
 
-       optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr);
-       optend = ip_hdrlen(*pskb) + tcph->doff * 4;
+       optoff = ip_hdrlen(skb) + sizeof(struct tcphdr);
+       optend = ip_hdrlen(skb) + tcph->doff * 4;
 
-       if (!skb_make_writable(pskb, optend))
+       if (!skb_make_writable(skb, optend))
                return 0;
 
        dir = CTINFO2DIR(ctinfo);
 
        while (optoff < optend) {
                /* Usually: option, length. */
-               unsigned char *op = (*pskb)->data + optoff;
+               unsigned char *op = skb->data + optoff;
 
                switch (op[0]) {
                case TCPOPT_EOL:
@@ -365,7 +359,7 @@ nf_nat_sack_adjust(struct sk_buff **pskb,
                        if (op[0] == TCPOPT_SACK &&
                            op[1] >= 2+TCPOLEN_SACK_PERBLOCK &&
                            ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
-                               sack_adjust(*pskb, tcph, optoff+2,
+                               sack_adjust(skb, tcph, optoff+2,
                                            optoff+op[1], &nat->seq[!dir]);
                        optoff += op[1];
                }
@@ -375,7 +369,7 @@ nf_nat_sack_adjust(struct sk_buff **pskb,
 
 /* TCP sequence number adjustment.  Returns 1 on success, 0 on failure */
 int
-nf_nat_seq_adjust(struct sk_buff **pskb,
+nf_nat_seq_adjust(struct sk_buff *skb,
                  struct nf_conn *ct,
                  enum ip_conntrack_info ctinfo)
 {
@@ -390,10 +384,10 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
        this_way = &nat->seq[dir];
        other_way = &nat->seq[!dir];
 
-       if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
+       if (!skb_make_writable(skb, ip_hdrlen(skb) + sizeof(*tcph)))
                return 0;
 
-       tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb);
+       tcph = (void *)skb->data + ip_hdrlen(skb);
        if (after(ntohl(tcph->seq), this_way->correction_pos))
                newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
        else
@@ -405,8 +399,8 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
        else
                newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
 
-       nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0);
-       nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0);
+       inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0);
+       inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0);
 
        pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n",
                 ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
@@ -415,10 +409,10 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
        tcph->seq = newseq;
        tcph->ack_seq = newack;
 
-       if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo))
+       if (!nf_nat_sack_adjust(skb, tcph, ct, ctinfo))
                return 0;
 
-       nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb), ct, dir);
+       nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir);
 
        return 1;
 }
@@ -438,15 +432,13 @@ void nf_nat_follow_master(struct nf_conn *ct,
        range.flags = IP_NAT_RANGE_MAP_IPS;
        range.min_ip = range.max_ip
                = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
-       /* hook doesn't matter, but it has to do source manip */
-       nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
+       nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
 
        /* For DST manip, map port here to where it's expected. */
        range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
        range.min = range.max = exp->saved_proto;
        range.min_ip = range.max_ip
                = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip;
-       /* hook doesn't matter, but it has to do destination manip */
-       nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
+       nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
 }
 EXPORT_SYMBOL(nf_nat_follow_master);