[NET]: netfilter checksum annotations
Al Viro [Wed, 15 Nov 2006 05:43:23 +0000 (21:43 -0800)]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>

13 files changed:
include/linux/netfilter.h
include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
net/ipv4/netfilter/ip_nat_core.c
net/ipv4/netfilter/ip_nat_helper.c
net/ipv4/netfilter/ip_nat_proto_gre.c
net/ipv4/netfilter/ip_nat_proto_icmp.c
net/ipv4/netfilter/ip_nat_proto_tcp.c
net/ipv4/netfilter/ip_nat_proto_udp.c
net/ipv4/netfilter/ipt_ECN.c
net/ipv4/netfilter/ipt_TCPMSS.c
net/ipv4/netfilter/ipt_TOS.c
net/ipv4/netfilter/ipt_TTL.c
net/netfilter/core.c

index 707bb2e..6ab5e2d 100644 (file)
@@ -282,11 +282,27 @@ extern void nf_invalidate_cache(int pf);
    Returns true or false. */
 extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
 
-extern u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval,
-                               u_int32_t csum);
-extern u_int16_t nf_proto_csum_update(struct sk_buff *skb,
-                                     u_int32_t oldval, u_int32_t newval,
-                                     u_int16_t csum, int pseudohdr);
+static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
+{
+       __be32 diff[] = { ~from, to };
+
+       *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
+}
+
+static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
+{
+       nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
+}
+
+extern void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
+                                     __be32 from, __be32 to, int pseudohdr);
+
+static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
+                                     __be16 from, __be16 to, int pseudohdr)
+{
+       nf_proto_csum_replace4(sum, skb, (__force __be32)from,
+                               (__force __be32)to, pseudohdr);
+}
 
 struct nf_afinfo {
        unsigned short  family;
index 1d853aa..e371e0f 100644 (file)
@@ -102,11 +102,11 @@ static inline __be32 *gre_key(struct gre_hdr *greh)
 }
 
 /* get pointer ot gre csum, if present */
-static inline u_int16_t *gre_csum(struct gre_hdr *greh)
+static inline __sum16 *gre_csum(struct gre_hdr *greh)
 {
        if (!greh->csum)
                return NULL;
-       return (u_int16_t *) (greh+sizeof(*greh));
+       return (__sum16 *) (greh+sizeof(*greh));
 }
 
 #endif /* __KERNEL__ */
index 4b6260a..9d1a517 100644 (file)
@@ -362,12 +362,10 @@ manip_pkt(u_int16_t proto,
        iph = (void *)(*pskb)->data + iphdroff;
 
        if (maniptype == IP_NAT_MANIP_SRC) {
-               iph->check = nf_csum_update(~iph->saddr, target->src.ip,
-                                           iph->check);
+               nf_csum_replace4(&iph->check, iph->saddr, target->src.ip);
                iph->saddr = target->src.ip;
        } else {
-               iph->check = nf_csum_update(~iph->daddr, target->dst.ip,
-                                           iph->check);
+               nf_csum_replace4(&iph->check, iph->daddr, target->dst.ip);
                iph->daddr = target->dst.ip;
        }
        return 1;
index 3e7fd64..ee80feb 100644 (file)
@@ -188,10 +188,8 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
                                           csum_partial((char *)tcph,
                                                        datalen, 0));
        } else
-               tcph->check = nf_proto_csum_update(*pskb,
-                                                  htons(oldlen) ^ htons(0xFFFF),
-                                                  htons(datalen),
-                                                  tcph->check, 1);
+               nf_proto_csum_replace2(&tcph->check, *pskb,
+                                       htons(oldlen), htons(datalen), 1);
 
        if (rep_len != match_len) {
                set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
@@ -266,10 +264,8 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb,
                if (!udph->check)
                        udph->check = CSUM_MANGLED_0;
        } else
-               udph->check = nf_proto_csum_update(*pskb,
-                                                  htons(oldlen) ^ htons(0xFFFF),
-                                                  htons(datalen),
-                                                  udph->check, 1);
+               nf_proto_csum_replace2(&udph->check, *pskb,
+                                       htons(oldlen), htons(datalen), 1);
        return 1;
 }
 EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
@@ -307,14 +303,10 @@ sack_adjust(struct sk_buff *skb,
                        ntohl(sack->start_seq), new_start_seq,
                        ntohl(sack->end_seq), new_end_seq);
 
-               tcph->check = nf_proto_csum_update(skb,
-                                                  ~sack->start_seq,
-                                                  new_start_seq,
-                                                  tcph->check, 0);
-               tcph->check = nf_proto_csum_update(skb,
-                                                  ~sack->end_seq,
-                                                  new_end_seq,
-                                                  tcph->check, 0);
+               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);
                sack->start_seq = new_start_seq;
                sack->end_seq = new_end_seq;
                sackoff += sizeof(*sack);
@@ -397,10 +389,8 @@ ip_nat_seq_adjust(struct sk_buff **pskb,
        else
                newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
 
-       tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq,
-                                          tcph->check, 0);
-       tcph->check = nf_proto_csum_update(*pskb, ~tcph->ack_seq, newack,
-                                          tcph->check, 0);
+       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),
index bf91f93..9581020 100644 (file)
@@ -129,11 +129,9 @@ gre_manip_pkt(struct sk_buff **pskb,
                        }
                        if (greh->csum) {
                                /* FIXME: Never tested this code... */
-                               *(gre_csum(greh)) =
-                                       nf_proto_csum_update(*pskb,
-                                                       ~*(gre_key(greh)),
-                                                       tuple->dst.u.gre.key,
-                                                       *(gre_csum(greh)), 0);
+                               nf_proto_csum_replace4(gre_csum(greh), *pskb,
+                                                       *(gre_key(greh)),
+                                                       tuple->dst.u.gre.key, 0);
                        }
                        *(gre_key(greh)) = tuple->dst.u.gre.key;
                        break;
index 3f6efc1..75266fe 100644 (file)
@@ -66,10 +66,8 @@ icmp_manip_pkt(struct sk_buff **pskb,
                return 0;
 
        hdr = (struct icmphdr *)((*pskb)->data + hdroff);
-       hdr->checksum = nf_proto_csum_update(*pskb,
-                                            hdr->un.echo.id ^ htons(0xFFFF),
-                                            tuple->src.u.icmp.id,
-                                            hdr->checksum, 0);
+       nf_proto_csum_replace2(&hdr->checksum, *pskb,
+                              hdr->un.echo.id, tuple->src.u.icmp.id, 0);
        hdr->un.echo.id = tuple->src.u.icmp.id;
        return 1;
 }
index 12deb13..b586d18 100644 (file)
@@ -129,9 +129,8 @@ tcp_manip_pkt(struct sk_buff **pskb,
        if (hdrsize < sizeof(*hdr))
                return 1;
 
-       hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1);
-       hdr->check = nf_proto_csum_update(*pskb, oldport ^ htons(0xFFFF), newport,
-                                         hdr->check, 0);
+       nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
+       nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0);
        return 1;
 }
 
index 82f8a6a..5ced087 100644 (file)
@@ -115,11 +115,8 @@ udp_manip_pkt(struct sk_buff **pskb,
        }
 
        if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) {
-               hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip,
-                                                 hdr->check, 1);
-               hdr->check = nf_proto_csum_update(*pskb,
-                                                 *portptr ^ htons(0xFFFF), newport,
-                                                 hdr->check, 0);
+               nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
+               nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 0);
                if (!hdr->check)
                        hdr->check = CSUM_MANGLED_0;
        }
index 1aa4517..b55d670 100644 (file)
@@ -28,17 +28,16 @@ static inline int
 set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
 {
        struct iphdr *iph = (*pskb)->nh.iph;
-       u_int16_t oldtos;
 
        if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
+               __u8 oldtos;
                if (!skb_make_writable(pskb, sizeof(struct iphdr)))
                        return 0;
                iph = (*pskb)->nh.iph;
                oldtos = iph->tos;
                iph->tos &= ~IPT_ECN_IP_MASK;
                iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
-               iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF),
-                                           htons(iph->tos), iph->check);
+               nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos));
        } 
        return 1;
 }
@@ -72,10 +71,8 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
        if (einfo->operation & IPT_ECN_OP_SET_CWR)
                tcph->cwr = einfo->proto.tcp.cwr;
 
-       tcph->check = nf_proto_csum_update((*pskb),
-                                          oldval ^ htons(0xFFFF),
-                                          ((__be16 *)tcph)[6],
-                                          tcph->check, 0);
+       nf_proto_csum_replace2(&tcph->check, *pskb,
+                               oldval, ((__be16 *)tcph)[6], 0);
        return 1;
 }
 
index 108b6b7..93eb5c3 100644 (file)
@@ -97,10 +97,8 @@ ipt_tcpmss_target(struct sk_buff **pskb,
                        opt[i+2] = (newmss & 0xff00) >> 8;
                        opt[i+3] = (newmss & 0x00ff);
 
-                       tcph->check = nf_proto_csum_update(*pskb,
-                                                          htons(oldmss)^htons(0xFFFF),
-                                                          htons(newmss),
-                                                          tcph->check, 0);
+                       nf_proto_csum_replace2(&tcph->check, *pskb,
+                                               htons(oldmss), htons(newmss), 0);
                        return IPT_CONTINUE;
                }
        }
@@ -126,28 +124,22 @@ ipt_tcpmss_target(struct sk_buff **pskb,
        opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
        memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
 
-       tcph->check = nf_proto_csum_update(*pskb,
-                                          htons(tcplen) ^ htons(0xFFFF),
-                                          htons(tcplen + TCPOLEN_MSS),
-                                          tcph->check, 1);
+       nf_proto_csum_replace2(&tcph->check, *pskb,
+                               htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
        opt[0] = TCPOPT_MSS;
        opt[1] = TCPOLEN_MSS;
        opt[2] = (newmss & 0xff00) >> 8;
        opt[3] = (newmss & 0x00ff);
 
-       tcph->check = nf_proto_csum_update(*pskb, htonl(~0), *((__be32 *)opt),
-                                          tcph->check, 0);
+       nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0);
 
        oldval = ((__be16 *)tcph)[6];
        tcph->doff += TCPOLEN_MSS/4;
-       tcph->check = nf_proto_csum_update(*pskb,
-                                          oldval ^ htons(0xFFFF),
-                                          ((__be16 *)tcph)[6],
-                                          tcph->check, 0);
+       nf_proto_csum_replace2(&tcph->check, *pskb,
+                               oldval, ((__be16 *)tcph)[6], 0);
 
        newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
-       iph->check = nf_csum_update(iph->tot_len ^ htons(0xFFFF),
-                                   newtotlen, iph->check);
+       nf_csum_replace2(&iph->check, iph->tot_len, newtotlen);
        iph->tot_len = newtotlen;
        return IPT_CONTINUE;
 }
index 83b80b3..18e74ac 100644 (file)
@@ -30,16 +30,15 @@ target(struct sk_buff **pskb,
 {
        const struct ipt_tos_target_info *tosinfo = targinfo;
        struct iphdr *iph = (*pskb)->nh.iph;
-       u_int16_t oldtos;
 
        if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
+               __u8 oldtos;
                if (!skb_make_writable(pskb, sizeof(struct iphdr)))
                        return NF_DROP;
                iph = (*pskb)->nh.iph;
                oldtos = iph->tos;
                iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
-               iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF),
-                                           htons(iph->tos), iph->check);
+               nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos));
        }
        return IPT_CONTINUE;
 }
index ac9517d..fffe5ca 100644 (file)
@@ -54,9 +54,8 @@ ipt_ttl_target(struct sk_buff **pskb,
        }
 
        if (new_ttl != iph->ttl) {
-               iph->check = nf_csum_update(htons((iph->ttl << 8)) ^ htons(0xFFFF),
-                                           htons(new_ttl << 8),
-                                           iph->check);
+               nf_csum_replace2(&iph->check, htons(iph->ttl << 8),
+                                             htons(new_ttl << 8));
                iph->ttl = new_ttl;
        }
 
index d80b935..17f9e1c 100644 (file)
@@ -222,28 +222,21 @@ copy_skb:
 }
 EXPORT_SYMBOL(skb_make_writable);
 
-u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval, u_int32_t csum)
-{
-       u_int32_t diff[] = { oldval, newval };
-
-       return csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum));
-}
-EXPORT_SYMBOL(nf_csum_update);
-
-u_int16_t nf_proto_csum_update(struct sk_buff *skb,
-                              u_int32_t oldval, u_int32_t newval,
-                              u_int16_t csum, int pseudohdr)
+void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
+                           __be32 from, __be32 to, int pseudohdr)
 {
+       __be32 diff[] = { ~from, to };
        if (skb->ip_summed != CHECKSUM_PARTIAL) {
-               csum = nf_csum_update(oldval, newval, csum);
+               *sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
+                               ~csum_unfold(*sum)));
                if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
-                       skb->csum = nf_csum_update(oldval, newval, skb->csum);
+                       skb->csum = ~csum_partial((char *)diff, sizeof(diff),
+                                               ~skb->csum);
        } else if (pseudohdr)
-               csum = ~nf_csum_update(oldval, newval, ~csum);
-
-       return csum;
+               *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff),
+                               csum_unfold(*sum)));
 }
-EXPORT_SYMBOL(nf_proto_csum_update);
+EXPORT_SYMBOL(nf_proto_csum_replace4);
 
 /* This does not belong here, but locally generated errors need it if connection
    tracking in use: without this, connection may not be in hash table, and hence