netfilter: nf_nat: add nf_nat_csum()
authorChangli Gao <xiaosuo@gmail.com>
Wed, 15 Sep 2010 17:24:50 +0000 (19:24 +0200)
committerPatrick McHardy <kaber@trash.net>
Wed, 15 Sep 2010 17:24:50 +0000 (19:24 +0200)
Add a static function nf_nat_csum() to replace the duplicate code in
nf_nat_mangle_udp_packet() and __nf_nat_mangle_tcp_packet().

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
net/ipv4/netfilter/nf_nat_helper.c

index 4a0c6b548eee22f1dfc0e6d01187f209319f10d7..31427fb57aa8abdc299bc1a2c1ab2ebc3929b543 100644 (file)
@@ -153,6 +153,35 @@ void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
 }
 EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
 
+static void nf_nat_csum(struct sk_buff *skb, struct iphdr *iph, void *data,
+                       int datalen, __sum16 *check, int oldlen)
+{
+       struct rtable *rt = skb_rtable(skb);
+
+       if (skb->ip_summed != CHECKSUM_PARTIAL) {
+               if (!(rt->rt_flags & RTCF_LOCAL) &&
+                   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 = (void *)check - data;
+                       *check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                                   datalen, iph->protocol, 0);
+               } else {
+                       *check = 0;
+                       *check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                                  datalen, iph->protocol,
+                                                  csum_partial(data, datalen,
+                                                               0));
+                       if (iph->protocol == IPPROTO_UDP && !*check)
+                               *check = CSUM_MANGLED_0;
+               }
+       } else
+               inet_proto_csum_replace2(check, skb,
+                                        htons(oldlen), htons(datalen), 1);
+}
+
 /* Generic function for mangling variable-length address changes inside
  * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
  * command in FTP).
@@ -169,7 +198,6 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
                               const char *rep_buffer,
                               unsigned int rep_len, bool adjust)
 {
-       struct rtable *rt = skb_rtable(skb);
        struct iphdr *iph;
        struct tcphdr *tcph;
        int oldlen, datalen;
@@ -192,26 +220,7 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
                        match_offset, match_len, rep_buffer, rep_len);
 
        datalen = skb->len - iph->ihl*4;
-       if (skb->ip_summed != CHECKSUM_PARTIAL) {
-               if (!(rt->rt_flags & RTCF_LOCAL) &&
-                   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 {
-                       tcph->check = 0;
-                       tcph->check = tcp_v4_check(datalen,
-                                                  iph->saddr, iph->daddr,
-                                                  csum_partial(tcph,
-                                                               datalen, 0));
-               }
-       } else
-               inet_proto_csum_replace2(&tcph->check, skb,
-                                        htons(oldlen), htons(datalen), 1);
+       nf_nat_csum(skb, iph, tcph, datalen, &tcph->check, oldlen);
 
        if (adjust && rep_len != match_len)
                nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,
@@ -240,7 +249,6 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
                         const char *rep_buffer,
                         unsigned int rep_len)
 {
-       struct rtable *rt = skb_rtable(skb);
        struct iphdr *iph;
        struct udphdr *udph;
        int datalen, oldlen;
@@ -274,29 +282,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
        if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
                return 1;
 
-       if (skb->ip_summed != CHECKSUM_PARTIAL) {
-               if (!(rt->rt_flags & RTCF_LOCAL) &&
-                   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);
-               } 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
-               inet_proto_csum_replace2(&udph->check, skb,
-                                        htons(oldlen), htons(datalen), 1);
+       nf_nat_csum(skb, iph, udph, datalen, &udph->check, oldlen);
 
        return 1;
 }