after just 15 months i got this finally working.

basically moving us to the assumption that there is some cksum offload
engine in each an every output path, calling the software engine very
late if we figure there is none. foremost this adds this logic to the
alternate output pathes like bridge, the regular already followed that
model.
stop the cksum fucku^Wfixup in pf. just set the damn flags to indicate
the packets needs to be re-checksummed. and since some stupid cards
incorporated the terrible pseudo header checksum hack in hardware we
have to fill that in as well.

for now, this will have a little performance penalty since right now
proto cksum offloading is disabled due to a bug in the pf<->cksum<->hw
interaction that this change happens to eliminate, so we'll be able to
turn on proto csum offloading in the drivers (which will lead to fun
with silicone bugs, but that's another topic).

i started hacking on that in iceland and touched it on every hackathon
since... the horror.
in6_proto_csum_out written by krw.

Index: net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.193
diff -u -p -r1.193 if_bridge.c
--- net/if_bridge.c     4 Jul 2011 06:54:49 -0000       1.193
+++ net/if_bridge.c     10 Jul 2012 10:23:33 -0000
@@ -1061,15 +1061,6 @@ bridge_output(struct ifnet *ifp, struct 
                        return (0);
                }
 #endif /* IPSEC */
-
-               /* Catch packets that need TCP/UDP hardware checksumming */
-               if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT ||
-                   m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) {
-                       m_freem(m);
-                       splx(s);
-                       return (0);
-               }
-
                bridge_span(sc, NULL, m);
 
                LIST_FOREACH(p, &sc->sc_iflist, next) {
@@ -2458,6 +2449,12 @@ bridge_ipsec(struct bridge_softc *sc, st
                        }
                        if (m == NULL)
                                return (1);
+                       else if (af == AF_INET)
+                               in_proto_cksum_out(m, encif);
+#ifdef INET6
+                       else if (af == AF_INET6)
+                               in6_proto_cksum_out(m, encif);
+#endif /* INET6 */
 #endif /* NPF */
 
                        ip = mtod(m, struct ip *);
@@ -2610,6 +2607,7 @@ bridge_ip(struct bridge_softc *sc, int d
                        return (NULL);
                if (m->m_len < sizeof(struct ip))
                        goto dropit;
+               in_proto_cksum_out(m, ifp);
                ip = mtod(m, struct ip *);
                ip->ip_sum = 0;
                if (0 && (ifp->if_capabilities & IFCAP_CSUM_IPv4)) {
@@ -2655,6 +2653,7 @@ bridge_ip(struct bridge_softc *sc, int d
                if (m == NULL)
                        return (NULL);
 #endif /* NPF > 0 */
+               in6_proto_cksum_out(m, ifp);
 
                break;
        }
Index: net/if_pflog.c
===================================================================
RCS file: /cvs/src/sys/net/if_pflog.c,v
retrieving revision 1.50
diff -u -p -r1.50 if_pflog.c
--- net/if_pflog.c      8 Jul 2012 07:58:09 -0000       1.50
+++ net/if_pflog.c      10 Jul 2012 10:18:29 -0000
@@ -443,7 +443,7 @@ pflog_bpfcopy(const void *src_arg, void 
        if (pd.virtual_proto != PF_VPROTO_FRAGMENT &&
            (pfloghdr->rewritten = pf_translate(&pd, &pfloghdr->saddr,
            pfloghdr->sport, &pfloghdr->daddr, pfloghdr->dport, 0,
-           pfloghdr->dir))) {
+           pfloghdr->dir, pd.m))) {
                m_copyback(pd.m, pd.off, min(pd.m->m_len - pd.off, pd.hdrlen),
                    pd.hdr.any, M_NOWAIT);
 #if INET && INET6
Index: net/pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.808
diff -u -p -r1.808 pf.c
--- net/pf.c    10 Jul 2012 17:33:48 -0000      1.808
+++ net/pf.c    13 Jul 2012 10:52:40 -0000
@@ -2,7 +2,7 @@
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
- * Copyright (c) 2002 - 2010 Henning Brauer
+ * Copyright (c) 2002 - 2012 Henning Brauer <henn...@openbsd.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -148,18 +148,16 @@ void                       pf_add_threshold(struct 
pf_thres
 int                     pf_check_threshold(struct pf_threshold *);
 
 void                    pf_change_ap(struct pf_addr *, u_int16_t *,
-                           u_int16_t *, struct pf_addr *, u_int16_t,
-                           u_int8_t, sa_family_t, sa_family_t);
+                           struct pf_addr *, u_int16_t, sa_family_t,
+                           sa_family_t);
 int                     pf_modulate_sack(struct pf_pdesc *,
                            struct pf_state_peer *);
-void                    pf_change_a6(struct pf_addr *, u_int16_t *,
-                           struct pf_addr *, u_int8_t);
+void                    pf_change_a6(struct pf_addr *a, struct pf_addr *an);
 int                     pf_icmp_mapping(struct pf_pdesc *, u_int8_t, int *,
                            int *, u_int16_t *, u_int16_t *);
 void                    pf_change_icmp(struct pf_addr *, u_int16_t *,
                            struct pf_addr *, struct pf_addr *, u_int16_t,
-                           u_int16_t *, u_int16_t *, u_int16_t *,
-                           u_int8_t, sa_family_t);
+                           sa_family_t);
 int                     pf_change_icmp_af(struct mbuf *, int,
                            struct pf_pdesc *, struct pf_pdesc *,
                            struct pf_addr *, struct pf_addr *, sa_family_t,
@@ -1649,137 +1647,27 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw
        }
 }
 
-u_int16_t
-pf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
-{
-       u_int32_t       l;
-
-       if (udp && !cksum)
-               return (0x0000);
-       l = cksum + old - new;
-       l = (l >> 16) + (l & 65535);
-       l = l & 65535;
-       if (udp && !l)
-               return (0xFFFF);
-       return (l);
-}
-
 void
-pf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *pc,
-    struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af,
-    sa_family_t naf)
+pf_change_ap(struct pf_addr *a, u_int16_t *p, struct pf_addr *an,
+    u_int16_t pn, sa_family_t af, sa_family_t naf)
 {
-       struct pf_addr  ao;
-       u_int16_t       po = *p;
-
-       PF_ACPY(&ao, a, af);
        if (af == naf)
                PF_ACPY(a, an, naf);
-
        *p = pn;
-
-       switch (af) {
-#ifdef INET
-       case AF_INET:
-               switch (naf) {
-               case AF_INET:
-                       *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
-                           ao.addr16[0], an->addr16[0], u),
-                           ao.addr16[1], an->addr16[1], u),
-                           po, pn, u);
-                       break;
-#ifdef INET6
-               case AF_INET6:
-                       *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                           pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                           pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
-                           ao.addr16[0], an->addr16[0], u),
-                           ao.addr16[1], an->addr16[1], u),
-                           0,            an->addr16[2], u),
-                           0,            an->addr16[3], u),
-                           0,            an->addr16[4], u),
-                           0,            an->addr16[5], u),
-                           0,            an->addr16[6], u),
-                           0,            an->addr16[7], u),
-                           po, pn, u);
-                       break;
-#endif /* INET6 */
-               }
-               break;
-#endif /* INET */
-#ifdef INET6
-       case AF_INET6:
-               switch (naf) {
-#ifdef INET
-               case AF_INET:
-                       *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                           pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                           pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
-                           ao.addr16[0], an->addr16[0], u),
-                           ao.addr16[1], an->addr16[1], u),
-                           ao.addr16[2], 0,             u),
-                           ao.addr16[3], 0,             u),
-                           ao.addr16[4], 0,             u),
-                           ao.addr16[5], 0,             u),
-                           ao.addr16[6], 0,             u),
-                           ao.addr16[7], 0,             u),
-                           po, pn, u);
-                       break;
-#endif /* INET */
-               case AF_INET6:
-                       *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                           pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                           pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
-                           ao.addr16[0], an->addr16[0], u),
-                           ao.addr16[1], an->addr16[1], u),
-                           ao.addr16[2], an->addr16[2], u),
-                           ao.addr16[3], an->addr16[3], u),
-                           ao.addr16[4], an->addr16[4], u),
-                           ao.addr16[5], an->addr16[5], u),
-                           ao.addr16[6], an->addr16[6], u),
-                           ao.addr16[7], an->addr16[7], u),
-                           po, pn, u);
-                       break;
-               }
-               break;
-#endif /* INET6 */
-       }
 }
 
 /* Changes a u_int32_t.  Uses a void * so there are no align restrictions */
 void
-pf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
+pf_change_a(void *a, u_int32_t an)
 {
-       u_int32_t       ao;
-
-       memcpy(&ao, a, sizeof(ao));
        memcpy(a, &an, sizeof(u_int32_t));
-       if (c != NULL)
-               *c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536,
-                   u), ao % 65536, an % 65536, u);
 }
 
 #ifdef INET6
 void
-pf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
+pf_change_a6(struct pf_addr *a, struct pf_addr *an)
 {
-       struct pf_addr  ao;
-
-       PF_ACPY(&ao, a, AF_INET6);
        PF_ACPY(a, an, AF_INET6);
-
-       if (c)
-               *c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                   pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                   pf_cksum_fixup(pf_cksum_fixup(*c,
-                   ao.addr16[0], an->addr16[0], u),
-                   ao.addr16[1], an->addr16[1], u),
-                   ao.addr16[2], an->addr16[2], u),
-                   ao.addr16[3], an->addr16[3], u),
-                   ao.addr16[4], an->addr16[4], u),
-                   ao.addr16[5], an->addr16[5], u),
-                   ao.addr16[6], an->addr16[6], u),
-                   ao.addr16[7], an->addr16[7], u);
 }
 #endif /* INET6 */
 
@@ -1968,81 +1856,18 @@ pf_icmp_mapping(struct pf_pdesc *pd, u_i
 
 void
 pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
-    struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
-    u_int16_t *ic, u_int8_t u, sa_family_t af)
+    struct pf_addr *na, u_int16_t np, sa_family_t af)
 {
-       struct pf_addr  oia, ooa;
-
-       PF_ACPY(&oia, ia, af);
-       if (oa)
-               PF_ACPY(&ooa, oa, af);
-
-       /* Change inner protocol port, fix inner protocol checksum. */
-       if (ip != NULL) {
-               u_int16_t       oip = *ip;
-               u_int32_t       opc;
-
-               if (pc != NULL)
-                       opc = *pc;
+       /* Change inner protocol port */
+       if (ip != NULL)
                *ip = np;
-               if (pc != NULL)
-                       *pc = pf_cksum_fixup(*pc, oip, *ip, u);
-               *ic = pf_cksum_fixup(*ic, oip, *ip, 0);
-               if (pc != NULL)
-                       *ic = pf_cksum_fixup(*ic, opc, *pc, 0);
-       }
-       /* Change inner ip address, fix inner ip and icmp checksums. */
+
+       /* Change inner ip address */
        PF_ACPY(ia, na, af);
-       switch (af) {
-#ifdef INET
-       case AF_INET: {
-               u_int32_t        oh2c = *h2c;
 
-               /* XXX just in_cksum() */
-               *h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
-                   oia.addr16[0], ia->addr16[0], 0),
-                   oia.addr16[1], ia->addr16[1], 0);
-               *ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
-                   oia.addr16[0], ia->addr16[0], 0),
-                   oia.addr16[1], ia->addr16[1], 0);
-               *ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
-               break;
-       }
-#endif /* INET */
-#ifdef INET6
-       case AF_INET6:
-               *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                   pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                   pf_cksum_fixup(pf_cksum_fixup(*ic,
-                   oia.addr16[0], ia->addr16[0], u),
-                   oia.addr16[1], ia->addr16[1], u),
-                   oia.addr16[2], ia->addr16[2], u),
-                   oia.addr16[3], ia->addr16[3], u),
-                   oia.addr16[4], ia->addr16[4], u),
-                   oia.addr16[5], ia->addr16[5], u),
-                   oia.addr16[6], ia->addr16[6], u),
-                   oia.addr16[7], ia->addr16[7], u);
-               break;
-#endif /* INET6 */
-       }
        /* Outer ip address, fix outer icmpv6 checksum, if necessary. */
-       if (oa) {
+       if (oa)
                PF_ACPY(oa, na, af);
-#ifdef INET6
-               if (af == AF_INET6)
-                       *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                           pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
-                           pf_cksum_fixup(pf_cksum_fixup(*ic,
-                           ooa.addr16[0], oa->addr16[0], u),
-                           ooa.addr16[1], oa->addr16[1], u),
-                           ooa.addr16[2], oa->addr16[2], u),
-                           ooa.addr16[3], oa->addr16[3], u),
-                           ooa.addr16[4], oa->addr16[4], u),
-                           ooa.addr16[5], oa->addr16[5], u),
-                           ooa.addr16[6], oa->addr16[6], u),
-                           ooa.addr16[7], oa->addr16[7], u);
-#endif /* INET6 */
-       }
 }
 
 #if INET && INET6
@@ -2286,28 +2111,12 @@ pf_translate_icmp_af(int af, void *arg)
                default:
                        return (-1);
                }
-               if (icmp6->icmp6_type != type) {
-                       icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum,
-                           icmp6->icmp6_type, type, 0);
-                       icmp6->icmp6_type = type;
-               }
-               if (icmp6->icmp6_code != code) {
-                       icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum,
-                           icmp6->icmp6_code, code, 0);
-                       icmp6->icmp6_code = code;
-               }
-               if (icmp6->icmp6_mtu != htonl(mtu)) {
-                       icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum,
-                           htons(ntohl(icmp6->icmp6_mtu)), htons(mtu), 0);
-                       /* aligns well with a icmpv4 nextmtu */
-                       icmp6->icmp6_mtu = htonl(mtu);
-               }
-               if (ptr >= 0 && icmp6->icmp6_pptr != htonl(ptr)) {
-                       icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum,
-                           htons(ntohl(icmp6->icmp6_pptr)), htons(ptr), 0);
-                       /* icmpv4 pptr is a one most significant byte */
-                       icmp6->icmp6_pptr = htonl(ptr << 24);
-               }
+               icmp6->icmp6_type = type;
+               icmp6->icmp6_code = code;
+               /* aligns well with a icmpv4 nextmtu */
+               icmp6->icmp6_mtu = htonl(mtu);
+               /* icmpv4 pptr is a one most significant byte */
+               icmp6->icmp6_pptr = htonl(ptr << 24);
                break;
        case AF_INET6:
                icmp4 = arg;
@@ -2396,26 +2205,10 @@ pf_translate_icmp_af(int af, void *arg)
                default:
                        return (-1);
                }
-               if (icmp4->icmp_type != type) {
-                       icmp4->icmp_cksum = pf_cksum_fixup(icmp4->icmp_cksum,
-                           icmp4->icmp_type, type, 0);
-                       icmp4->icmp_type = type;
-               }
-               if (icmp4->icmp_code != code) {
-                       icmp4->icmp_cksum = pf_cksum_fixup(icmp4->icmp_cksum,
-                           icmp4->icmp_code, code, 0);
-                       icmp4->icmp_code = code;
-               }
-               if (icmp4->icmp_nextmtu != htons(mtu)) {
-                       icmp4->icmp_cksum = pf_cksum_fixup(icmp4->icmp_cksum,
-                           icmp4->icmp_nextmtu, htons(mtu), 0);
-                       icmp4->icmp_nextmtu = htons(mtu);
-               }
-               if (ptr >= 0 && icmp4->icmp_void != ptr) {
-                       icmp4->icmp_cksum = pf_cksum_fixup(icmp4->icmp_cksum,
-                           htons(icmp4->icmp_pptr), htons(ptr), 0);
-                       icmp4->icmp_void = htonl(ptr);
-               }
+               icmp4->icmp_type = type;
+               icmp4->icmp_code = code;
+               icmp4->icmp_nextmtu = htons(mtu);
+               icmp4->icmp_void = htonl(ptr);
                break;
        }
 
@@ -2457,12 +2250,12 @@ pf_modulate_sack(struct pf_pdesc *pd, st
                                for (i = 2; i + TCPOLEN_SACK <= olen;
                                    i += TCPOLEN_SACK) {
                                        memcpy(&sack, &opt[i], sizeof(sack));
-                                       pf_change_a(&sack.start, &th->th_sum,
+                                       pf_change_a(&sack.start,
                                            htonl(ntohl(sack.start) -
-                                           dst->seqdiff), 0);
-                                       pf_change_a(&sack.end, &th->th_sum,
+                                           dst->seqdiff));
+                                       pf_change_a(&sack.end,
                                            htonl(ntohl(sack.end) -
-                                           dst->seqdiff), 0);
+                                           dst->seqdiff));
                                        memcpy(&opt[i], &sack, sizeof(sack));
                                }
                                copyback = 1;
@@ -3615,7 +3408,7 @@ pf_test_rule(struct pf_pdesc *pd, struct
                            sk->port[pd->af == pd->naf ? pd->sidx : pd->didx],
                            &sk->addr[pd->af == pd->naf ? pd->didx : pd->sidx],
                            sk->port[pd->af == pd->naf ? pd->didx : pd->sidx],
-                           virtual_type, icmp_dir);
+                           virtual_type, icmp_dir, pd->m);
                }
        } else {
                while ((ri = SLIST_FIRST(&rules))) {
@@ -3624,9 +3417,11 @@ pf_test_rule(struct pf_pdesc *pd, struct
                }
        }
 
-       /* copy back packet headers if we performed NAT operations */
-       if (rewrite && pd->hdrlen)
+       /* copy back packet headers if needed */
+       if (rewrite && pd->hdrlen) {
+               pf_cksum(pd, pd->m);
                m_copyback(pd->m, pd->off, pd->hdrlen, pd->hdr.any, M_NOWAIT);
+       }
 
 #if NPFSYNC > 0
        if (*sm != NULL && !ISSET((*sm)->state_flags, PFSTATE_NOSYNC) &&
@@ -3720,8 +3515,8 @@ pf_create_state(struct pf_pdesc *pd, str
                        if ((s->src.seqdiff = pf_tcp_iss(pd) - s->src.seqlo) ==
                            0)
                                s->src.seqdiff = 1;
-                       pf_change_a(&th->th_seq, &th->th_sum,
-                           htonl(s->src.seqlo + s->src.seqdiff), 0);
+                       pf_change_a(&th->th_seq,
+                           htonl(s->src.seqlo + s->src.seqdiff));
                        *rewrite = 1;
                } else
                        s->src.seqdiff = 0;
@@ -3858,7 +3653,7 @@ csfailed:
 int
 pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport,
     struct pf_addr *daddr, u_int16_t dport, u_int16_t virtual_type,
-    int icmp_dir)
+    int icmp_dir, struct mbuf *m)
 {
        /*
         * when called from bpf_mtap_pflog, there are extra constraints:
@@ -3875,14 +3670,14 @@ pf_translate(struct pf_pdesc *pd, struct
        case IPPROTO_TCP:
                if (afto || PF_ANEQ(saddr, pd->src, pd->af) ||
                    *pd->sport != sport) {
-                       pf_change_ap(pd->src, pd->sport, &pd->hdr.tcp->th_sum,
-                           saddr, sport, 0, pd->af, pd->naf);
+                       pf_change_ap(pd->src, pd->sport, saddr, sport, pd->af,
+                           pd->naf);
                        rewrite = 1;
                }
                if (afto || PF_ANEQ(daddr, pd->dst, pd->af) ||
                    *pd->dport != dport) {
-                       pf_change_ap(pd->dst, pd->dport, &pd->hdr.tcp->th_sum,
-                           daddr, dport, 0, pd->af, pd->naf);
+                       pf_change_ap(pd->dst, pd->dport, daddr, dport, pd->af,
+                           pd->naf);
                        rewrite = 1;
                }
                break;
@@ -3890,14 +3685,14 @@ pf_translate(struct pf_pdesc *pd, struct
        case IPPROTO_UDP:
                if (afto || PF_ANEQ(saddr, pd->src, pd->af) ||
                    *pd->sport != sport) {
-                       pf_change_ap(pd->src, pd->sport, &pd->hdr.udp->uh_sum,
-                           saddr, sport, 1, pd->af, pd->naf);
+                       pf_change_ap(pd->src, pd->sport, saddr, sport, pd->af,
+                           pd->naf);
                        rewrite = 1;
                }
                if (afto || PF_ANEQ(daddr, pd->dst, pd->af) ||
                    *pd->dport != dport) {
-                       pf_change_ap(pd->dst, pd->dport, &pd->hdr.udp->uh_sum,
-                           daddr, dport, 1, pd->af, pd->naf);
+                       pf_change_ap(pd->dst, pd->dport, daddr, dport, pd->af,
+                           pd->naf);
                        rewrite = 1;
                }
                break;
@@ -3917,13 +3712,13 @@ pf_translate(struct pf_pdesc *pd, struct
 #endif /* INET6 */
                } else {
                        if (PF_ANEQ(saddr, pd->src, pd->af)) {
-                               pf_change_a(&pd->src->v4.s_addr, NULL,
-                                   saddr->v4.s_addr, 0);
+                               pf_change_a(&pd->src->v4.s_addr,
+                                   saddr->v4.s_addr);
                                rewrite = 1;
                        }
                        if (PF_ANEQ(daddr, pd->dst, pd->af)) {
-                               pf_change_a(&pd->dst->v4.s_addr, NULL,
-                                   daddr->v4.s_addr, 0);
+                               pf_change_a(&pd->dst->v4.s_addr,
+                                   daddr->v4.s_addr);
                                rewrite = 1;
                        }
                }
@@ -3931,9 +3726,6 @@ pf_translate(struct pf_pdesc *pd, struct
                        u_int16_t icmpid = (icmp_dir == PF_IN) ? sport : dport;
 
                        if (icmpid != pd->hdr.icmp->icmp_id) {
-                               pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
-                                   pd->hdr.icmp->icmp_cksum,
-                                   pd->hdr.icmp->icmp_id, icmpid, 0);
                                pd->hdr.icmp->icmp_id = icmpid;
                                rewrite = 1;
                        }
@@ -3957,13 +3749,11 @@ pf_translate(struct pf_pdesc *pd, struct
 #endif /* INET */
                } else {
                        if (PF_ANEQ(saddr, pd->src, pd->af)) {
-                               pf_change_a6(pd->src,
-                                   &pd->hdr.icmp6->icmp6_cksum, saddr, 0);
+                               pf_change_a6(pd->src, saddr);
                                rewrite = 1;
                        }
                        if (PF_ANEQ(daddr, pd->dst, pd->af)) {
-                               pf_change_a6(pd->dst,
-                                   &pd->hdr.icmp6->icmp6_cksum, daddr, 0);
+                               pf_change_a6(pd->dst, daddr);
                                rewrite = 1;
                        }
                }
@@ -3975,25 +3765,25 @@ pf_translate(struct pf_pdesc *pd, struct
 #ifdef INET
                case AF_INET:
                        if (!afto && PF_ANEQ(saddr, pd->src, pd->af)) {
-                               pf_change_a(&pd->src->v4.s_addr, NULL,
-                                   saddr->v4.s_addr, 0);
+                               pf_change_a(&pd->src->v4.s_addr,
+                                   saddr->v4.s_addr);
                                rewrite = 1;
                        }
-                       if (!afto && PF_ANEQ(daddr, pd->dst, pd->af)) {
-                               pf_change_a(&pd->dst->v4.s_addr, NULL,
-                                   daddr->v4.s_addr, 0);
+                       if (!afto || PF_ANEQ(daddr, pd->dst, pd->af)) {
+                               pf_change_a(&pd->dst->v4.s_addr,
+                                   daddr->v4.s_addr);
                                rewrite = 1;
                        }
                        break;
 #endif /* INET */
 #ifdef INET6
                case AF_INET6:
-                       if (!afto && PF_ANEQ(saddr, pd->src, pd->af)) {
-                               pf_change_a6(pd->src, NULL, saddr, 0);
+                       if (!afto || PF_ANEQ(saddr, pd->src, pd->af)) {
+                               pf_change_a6(pd->src, saddr);
                                rewrite = 1;
                        }
                        if (!afto && PF_ANEQ(daddr, pd->dst, pd->af)) {
-                               pf_change_a6(pd->dst, NULL, daddr, 0);
+                               pf_change_a6(pd->dst, daddr);
                                rewrite = 1;
                        }
                        break;
@@ -4044,9 +3834,8 @@ pf_tcp_track_full(struct pf_pdesc *pd, s
                        while ((src->seqdiff = arc4random() - seq) == 0)
                                ;
                        ack = ntohl(th->th_ack) - dst->seqdiff;
-                       pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
-                           src->seqdiff), 0);
-                       pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
+                       pf_change_a(&th->th_seq, htonl(seq + src->seqdiff));
+                       pf_change_a(&th->th_ack, htonl(ack));
                        *copyback = 1;
                } else {
                        ack = ntohl(th->th_ack);
@@ -4095,9 +3884,8 @@ pf_tcp_track_full(struct pf_pdesc *pd, s
                ack = ntohl(th->th_ack) - dst->seqdiff;
                if (src->seqdiff) {
                        /* Modulate sequence numbers */
-                       pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
-                           src->seqdiff), 0);
-                       pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
+                       pf_change_a(&th->th_seq, htonl(seq + src->seqdiff));
+                       pf_change_a(&th->th_ack, htonl(ack));
                        *copyback = 1;
                }
                end = seq + pd->p_len;
@@ -4557,17 +4345,14 @@ pf_test_state_tcp(struct pf_pdesc *pd, s
 
                if (afto || PF_ANEQ(pd->src, &nk->addr[sidx], pd->af) ||
                    nk->port[sidx] != th->th_sport)
-                       pf_change_ap(pd->src, &th->th_sport, &th->th_sum,
-                           &nk->addr[sidx], nk->port[sidx], 0, pd->af, nk->af);
+                       pf_change_ap(pd->src, &th->th_sport,
+                           &nk->addr[sidx], nk->port[sidx], pd->af, nk->af);
 
                if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) ||
-                   pd->rdomain != nk->rdomain)
-                       pd->destchg = 1;
-               if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) ||
                    nk->port[didx] != th->th_dport)
-                       pf_change_ap(pd->dst, &th->th_dport, &th->th_sum,
-                           &nk->addr[didx], nk->port[didx], 0, pd->af,
-                           nk->af);
+                       pf_change_ap(pd->dst, &th->th_dport,
+                           &nk->addr[didx], nk->port[didx], pd->af, nk->af);
+
                pd->m->m_pkthdr.rdomain = nk->rdomain;
 
 #if INET && INET6
@@ -4583,9 +4368,10 @@ pf_test_state_tcp(struct pf_pdesc *pd, s
        }
 
        /* Copyback sequence modulation or stateful scrub changes if needed */
-       if (copyback)
+       if (copyback) {
+               pf_cksum(pd, pd->m);
                m_copyback(pd->m, pd->off, sizeof(*th), th, M_NOWAIT);
-
+       }
        return (action);
 }
 
@@ -4644,17 +4430,13 @@ pf_test_state_udp(struct pf_pdesc *pd, s
 
                if (afto || PF_ANEQ(pd->src, &nk->addr[sidx], pd->af) ||
                    nk->port[sidx] != uh->uh_sport)
-                       pf_change_ap(pd->src, &uh->uh_sport, &uh->uh_sum,
-                           &nk->addr[sidx], nk->port[sidx], 1, pd->af, nk->af);
+                       pf_change_ap(pd->src, &uh->uh_sport,
+                           &nk->addr[sidx], nk->port[sidx], pd->af, nk->af);
 
                if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) ||
-                   pd->rdomain != nk->rdomain)
-                       pd->destchg = 1;
-               if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) ||
                    nk->port[didx] != uh->uh_dport)
-                       pf_change_ap(pd->dst, &uh->uh_dport, &uh->uh_sum,
-                           &nk->addr[didx], nk->port[didx], 1, pd->af, nk->af);
-               pd->m->m_pkthdr.rdomain = nk->rdomain;
+                       pf_change_ap(pd->dst, &uh->uh_dport,
+                           &nk->addr[didx], nk->port[didx], pd->af, nk->af);
 
 #if INET && INET6
                if (afto) {
@@ -4665,6 +4447,8 @@ pf_test_state_udp(struct pf_pdesc *pd, s
                }
 #endif /* INET && INET6 */
 
+               pd->m->m_pkthdr.rdomain = nk->rdomain;
+               pf_cksum(pd, pd->m);
                m_copyback(pd->m, pd->off, sizeof(*uh), uh, M_NOWAIT);
        }
 
@@ -4725,7 +4509,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
        struct pf_addr  *saddr = pd->src, *daddr = pd->dst;
        u_int16_t       *icmpsum, virtual_id, virtual_type;
        u_int8_t         icmptype;
-       int              icmp_dir, iidx, ret, multi;
+       int              icmp_dir, iidx, ret, multi, copyback = 0;
+
        struct pf_state_key_cmp key;
 
        switch (pd->proto) {
@@ -4799,28 +4584,22 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
 #endif /* INET6 */
                                if (!afto && PF_ANEQ(pd->src,
                                    &nk->addr[sidx], AF_INET))
-                                       pf_change_a(&saddr->v4.s_addr, NULL,
-                                           nk->addr[sidx].v4.s_addr, 0);
+                                       pf_change_a(&saddr->v4.s_addr,
+                                           nk->addr[sidx].v4.s_addr);
 
                                if (!afto && PF_ANEQ(pd->dst,
                                    &nk->addr[didx], AF_INET)) {
-                                       pf_change_a(&daddr->v4.s_addr, NULL,
-                                           nk->addr[didx].v4.s_addr, 0);
+                                       pf_change_a(&daddr->v4.s_addr,
+                                           nk->addr[didx].v4.s_addr);
                                        pd->destchg = 1;
                                }
 
-                               if (nk->port[iidx] !=
-                                   pd->hdr.icmp->icmp_id) {
-                                       pd->hdr.icmp->icmp_cksum =
-                                           pf_cksum_fixup(
-                                           pd->hdr.icmp->icmp_cksum,
-                                            pd->hdr.icmp->icmp_id,
-                                           nk->port[iidx], 0);
+                               if (nk->port[iidx] !=  pd->hdr.icmp->icmp_id)
                                        pd->hdr.icmp->icmp_id = nk->port[iidx];
-                               }
 
                                m_copyback(pd->m, pd->off, ICMP_MINLEN,
                                    pd->hdr.icmp, M_NOWAIT);
+                               copyback = 1;
                                break;
 #endif /* INET */
 #ifdef INET6
@@ -4836,14 +4615,12 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                if (!afto && PF_ANEQ(pd->src,
                                    &nk->addr[sidx], AF_INET6))
                                        pf_change_a6(saddr,
-                                           &pd->hdr.icmp6->icmp6_cksum,
-                                           &nk->addr[sidx], 0);
+                                           &nk->addr[pd->sidx]);
 
                                if (!afto && PF_ANEQ(pd->dst,
                                    &nk->addr[didx], AF_INET6)) {
                                        pf_change_a6(daddr,
-                                           &pd->hdr.icmp6->icmp6_cksum,
-                                           &nk->addr[didx], 0);
+                                           &nk->addr[pd->didx]);
                                        pd->destchg = 1;
                                }
 
@@ -4854,6 +4631,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                m_copyback(pd->m, pd->off,
                                    sizeof(struct icmp6_hdr), pd->hdr.icmp6,
                                    M_NOWAIT);
+                               copyback = 1;
                                break;
 #endif /* INET6 */
                        }
@@ -4866,8 +4644,6 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                        }
 #endif /* INET && INET6 */
                }
-               return (PF_PASS);
-
        } else {
                /*
                 * ICMP error message in response to a TCP/UDP packet.
@@ -4954,7 +4730,6 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                        u_int32_t                seq;
                        struct pf_state_peer    *src, *dst;
                        u_int8_t                 dws;
-                       int                      copyback = 0;
 
                        /*
                         * Only the first 8 bytes of the TCP header can be
@@ -5004,8 +4779,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                        /* Demodulate sequence number */
                        seq = ntohl(th.th_seq) - src->seqdiff;
                        if (src->seqdiff) {
-                               pf_change_a(&th.th_seq, icmpsum,
-                                   htonl(seq), 0);
+                               pf_change_a(&th.th_seq, htonl(seq));
                                copyback = 1;
                        }
 
@@ -5089,8 +4863,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                    nk->port[pd2.sidx] != th.th_sport)
                                        pf_change_icmp(pd2.src, &th.th_sport,
                                            daddr, &nk->addr[pd2.sidx],
-                                           nk->port[pd2.sidx], NULL,
-                                           ipsum2, icmpsum, 0, pd2.af);
+                                           nk->port[pd2.sidx], pd2.af);
 
                                if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx],
                                    pd2.af) || pd2.rdomain != nk->rdomain)
@@ -5102,8 +4875,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                    nk->port[pd2.didx] != th.th_dport)
                                        pf_change_icmp(pd2.dst, &th.th_dport,
                                            saddr, &nk->addr[pd2.didx],
-                                           nk->port[pd2.didx], NULL,
-                                           ipsum2, icmpsum, 0, pd2.af);
+                                           nk->port[pd2.didx], pd2.af);
                                copyback = 1;
                        }
 
@@ -5129,8 +4901,6 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                }
                                m_copyback(pd2.m, pd2.off, 8, &th, M_NOWAIT);
                        }
-
-                       return (PF_PASS);
                        break;
                }
                case IPPROTO_UDP: {
@@ -5184,12 +4954,12 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                                pd->proto = IPPROTO_ICMP;
                                        else
                                                pd->proto = IPPROTO_ICMPV6;
-                                       pf_change_ap(pd2.src, &uh.uh_sport,
+                                       pf_change_ap(pd2.src,
                                            &uh.uh_sum, &nk->addr[pd2.sidx],
-                                           nk->port[sidx], 1, pd->af, nk->af);
-                                       pf_change_ap(pd2.dst, &uh.uh_dport,
+                                           nk->port[sidx], pd->af, nk->af);
+                                       pf_change_ap(pd2.dst,
                                            &uh.uh_sum, &nk->addr[pd2.didx],
-                                           nk->port[didx], 1, pd->af, nk->af);
+                                           nk->port[didx], pd->af, nk->af);
                                        m_copyback(pd2.m, pd2.off, sizeof(uh),
                                            &uh, M_NOWAIT);
                                        pd->m->m_pkthdr.rdomain = nk->rdomain;
@@ -5208,8 +4978,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                    nk->port[pd2.sidx] != uh.uh_sport)
                                        pf_change_icmp(pd2.src, &uh.uh_sport,
                                            daddr, &nk->addr[pd2.sidx],
-                                           nk->port[pd2.sidx], &uh.uh_sum,
-                                           ipsum2, icmpsum, 1, pd2.af);
+                                           nk->port[pd2.sidx], pd2.af);
 
                                if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx],
                                    pd2.af) || pd2.rdomain != nk->rdomain)
@@ -5221,8 +4990,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                    nk->port[pd2.didx] != uh.uh_dport)
                                        pf_change_icmp(pd2.dst, &uh.uh_dport,
                                            saddr, &nk->addr[pd2.didx],
-                                           nk->port[pd2.didx], &uh.uh_sum,
-                                           ipsum2, icmpsum, 1, pd2.af);
+                                           nk->port[pd2.didx], pd2.af);
 
                                switch (pd2.af) {
 #ifdef INET
@@ -5243,10 +5011,11 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                        break;
 #endif /* INET6 */
                                }
+                               uh.uh_sum = 0;
                                m_copyback(pd2.m, pd2.off, sizeof(uh), &uh,
                                    M_NOWAIT);
+                               copyback = 1;
                        }
-                       return (PF_PASS);
                        break;
                }
 #ifdef INET
@@ -5333,8 +5102,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                            &iih.icmp_id : NULL,
                                            daddr, &nk->addr[pd2.sidx],
                                            (virtual_type == htons(ICMP_ECHO)) ?
-                                           nk->port[iidx] : 0, NULL,
-                                           ipsum2, icmpsum, 0, AF_INET);
+                                           nk->port[iidx] : 0, AF_INET);
 
                                if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx],
                                    pd2.af) || pd2.rdomain != nk->rdomain)
@@ -5344,8 +5112,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                if (PF_ANEQ(pd2.dst,
                                    &nk->addr[pd2.didx], pd2.af))
                                        pf_change_icmp(pd2.dst, NULL, saddr,
-                                           &nk->addr[pd2.didx], 0, NULL,
-                                           ipsum2, icmpsum, 0, AF_INET);
+                                           &nk->addr[pd2.didx], 0, AF_INET);
 
                                m_copyback(pd->m, pd->off, ICMP_MINLEN,
                                    pd->hdr.icmp, M_NOWAIT);
@@ -5353,8 +5120,8 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                    M_NOWAIT);
                                m_copyback(pd2.m, pd2.off, ICMP_MINLEN, &iih,
                                    M_NOWAIT);
+                               copyback = 1;
                        }
-                       return (PF_PASS);
                        break;
                }
 #endif /* INET */
@@ -5455,8 +5222,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                            daddr, &nk->addr[pd2.sidx],
                                            (virtual_type ==
                                            htons(ICMP6_ECHO_REQUEST))
-                                           ? nk->port[iidx] : 0, NULL,
-                                           ipsum2, icmpsum, 0, AF_INET6);
+                                           ? nk->port[iidx] : 0, AF_INET6);
 
                                if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx],
                                    pd2.af) || pd2.rdomain != nk->rdomain)
@@ -5466,18 +5232,15 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                if (PF_ANEQ(pd2.dst,
                                    &nk->addr[pd2.didx], pd2.af))
                                        pf_change_icmp(pd2.dst, NULL, saddr,
-                                           &nk->addr[pd2.didx], 0, NULL,
-                                           ipsum2, icmpsum, 0, AF_INET6);
+                                           &nk->addr[pd2.didx], 0, AF_INET6);
 
                                m_copyback(pd->m, pd->off,
                                    sizeof(struct icmp6_hdr), pd->hdr.icmp6,
                                    M_NOWAIT);
-                               m_copyback(pd2.m, ipoff2, sizeof(h2_6), &h2_6,
-                                   M_NOWAIT);
-                               m_copyback(pd2.m, pd2.off,
+                               m_copyback(pd->m, pd2.off,
                                    sizeof(struct icmp6_hdr), &iih, M_NOWAIT);
+                               copyback = 1;
                        }
-                       return (PF_PASS);
                        break;
                }
 #endif /* INET6 */
@@ -5500,8 +5263,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                if (PF_ANEQ(pd2.src,
                                    &nk->addr[pd2.sidx], pd2.af))
                                        pf_change_icmp(pd2.src, NULL, daddr,
-                                           &nk->addr[pd2.sidx], 0, NULL,
-                                           ipsum2, icmpsum, 0, pd2.af);
+                                           &nk->addr[pd2.sidx], 0, pd2.af);
 
                                if (PF_ANEQ(pd2.dst, &nk->addr[pd2.didx],
                                    pd2.af) || pd2.rdomain != nk->rdomain)
@@ -5511,8 +5273,7 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                if (PF_ANEQ(pd2.dst,
                                    &nk->addr[pd2.didx], pd2.af))
                                        pf_change_icmp(pd2.dst, NULL, saddr,
-                                           &nk->addr[pd2.didx], 0, NULL,
-                                           ipsum2, icmpsum, 0, pd2.af);
+                                           &nk->addr[pd2.didx], 0, pd2.af);
 
                                switch (pd2.af) {
 #ifdef INET
@@ -5533,12 +5294,16 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                        break;
 #endif /* INET6 */
                                }
+                               copyback = 1;
                        }
-                       return (PF_PASS);
                        break;
                }
                }
        }
+       if (copyback)
+               pf_cksum(pd, pd->m);
+
+       return (PF_PASS);
 }
 
 int
@@ -5600,14 +5365,12 @@ pf_test_state_other(struct pf_pdesc *pd,
                case AF_INET:
                        if (!afto &&
                            PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET))
-                               pf_change_a(&pd->src->v4.s_addr, NULL,
-                                   nk->addr[pd->sidx].v4.s_addr,
-                                   0);
+                               pf_change_a(&pd->src->v4.s_addr,
+                                   nk->addr[pd->sidx].v4.s_addr);
                        if (!afto &&
                            PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) {
-                               pf_change_a(&pd->dst->v4.s_addr, NULL,
-                                   nk->addr[pd->didx].v4.s_addr,
-                                   0);
+                               pf_change_a(&pd->dst->v4.s_addr,
+                                   nk->addr[pd->didx].v4.s_addr);
                                pd->destchg = 1;
                        }
                        break;
@@ -7041,6 +6804,38 @@ pf_check_congestion(struct ifqueue *ifq)
                return (1);
        else
                return (0);
+}
+
+void
+pf_cksum(struct pf_pdesc *pd, struct mbuf *m)
+{
+       switch (pd->proto) {
+       case IPPROTO_TCP:
+               pd->hdr.tcp->th_sum = 0;
+               if (pd->af == AF_INET) {
+                       pd->hdr.tcp->th_sum = in_cksum_phdr(pd->src->v4.s_addr,
+                           pd->dst->v4.s_addr, htons(pd->tot_len -
+                           pd->off + IPPROTO_TCP));
+               }
+               m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT;
+               break;
+       case IPPROTO_UDP:
+               pd->hdr.udp->uh_sum = 0;
+               if (pd->af == AF_INET) {
+                       pd->hdr.udp->uh_sum = in_cksum_phdr(pd->src->v4.s_addr,
+                           pd->dst->v4.s_addr, htons(pd->tot_len -
+                           pd->off + IPPROTO_UDP));
+               }
+               m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
+               break;
+       case IPPROTO_ICMP:
+       case IPPROTO_ICMPV6:
+               m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
+               break;
+       default:
+               /* nothing */
+               break;
+       }
 }
 
 /*
Index: net/pf_norm.c
===================================================================
RCS file: /cvs/src/sys/net/pf_norm.c,v
retrieving revision 1.154
diff -u -p -r1.154 pf_norm.c
--- net/pf_norm.c       12 May 2012 13:08:48 -0000      1.154
+++ net/pf_norm.c       29 May 2012 12:13:52 -0000
@@ -2,7 +2,7 @@
 
 /*
  * Copyright 2001 Niels Provos <pro...@citi.umich.edu>
- * Copyright 2009 Henning Brauer <henn...@openbsd.org>
+ * Copyright 2009 - 2011 Henning Brauer <henn...@openbsd.org>
  * Copyright 2011 Alexander Bluhm <bl...@openbsd.org>
  * All rights reserved.
  *
@@ -869,20 +869,20 @@ pf_normalize_tcp(struct pf_pdesc *pd)
                th->th_x2 = 0;
                nv = *(u_int16_t *)(&th->th_ack + 1);
 
-               th->th_sum = pf_cksum_fixup(th->th_sum, ov, nv, 0);
                rewrite = 1;
        }
 
        /* Remove urgent pointer, if TH_URG is not set */
        if (!(flags & TH_URG) && th->th_urp) {
-               th->th_sum = pf_cksum_fixup(th->th_sum, th->th_urp, 0, 0);
                th->th_urp = 0;
                rewrite = 1;
        }
 
        /* copy back packet headers if we sanitized */
-       if (rewrite)
+       if (rewrite) {
+               pf_cksum(pd, pd->m);
                m_copyback(pd->m, pd->off, sizeof(*th), th, M_NOWAIT);
+       }
 
        return (PF_PASS);
 
@@ -1075,10 +1075,8 @@ pf_normalize_tcp_stateful(struct pf_pdes
                                            PFSS_TIMESTAMP)) {
                                                tsval = ntohl(tsval);
                                                pf_change_a(&opt[2],
-                                                   &th->th_sum,
                                                    htonl(tsval +
-                                                   src->scrub->pfss_ts_mod),
-                                                   0);
+                                                   src->scrub->pfss_ts_mod));
                                                copyback = 1;
                                        }
 
@@ -1091,8 +1089,7 @@ pf_normalize_tcp_stateful(struct pf_pdes
                                                tsecr = ntohl(tsecr)
                                                    - dst->scrub->pfss_ts_mod;
                                                pf_change_a(&opt[6],
-                                                   &th->th_sum, htonl(tsecr),
-                                                   0);
+                                                   htonl(tsecr));
                                                copyback = 1;
                                        }
                                        got_ts = 1;
@@ -1110,6 +1107,7 @@ pf_normalize_tcp_stateful(struct pf_pdes
                        m_copyback(pd->m, pd->off + sizeof(struct tcphdr),
                            (th->th_off << 2) - sizeof(struct tcphdr), hdr +
                            sizeof(struct tcphdr), M_NOWAIT);
+                       pd->m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT;
                }
        }
 
@@ -1422,12 +1420,11 @@ pf_normalize_mss(struct pf_pdesc *pd, u_
                case TCPOPT_MAXSEG:
                        bcopy((caddr_t)(optp + 2), (caddr_t)&mss, 2);
                        if (ntohs(mss) > maxmss) {
-                               th->th_sum = pf_cksum_fixup(th->th_sum,
-                                   mss, htons(maxmss), 0);
                                mss = htons(maxmss);
                                m_copyback(pd->m,
                                    pd->off + sizeof(*th) + optp + 2 - opts,
                                    2, &mss, M_NOWAIT);
+                               pf_cksum(pd, pd->m);
                                m_copyback(pd->m, pd->off, sizeof(*th), th,
                                    M_NOWAIT);
                        }
@@ -1436,8 +1433,6 @@ pf_normalize_mss(struct pf_pdesc *pd, u_
                        break;
                }
        }
-
-
 
        return (0);
 }
Index: net/pfvar.h
===================================================================
RCS file: /cvs/src/sys/net/pfvar.h,v
retrieving revision 1.365
diff -u -p -r1.365 pfvar.h
--- net/pfvar.h 10 Jul 2012 09:38:22 -0000      1.365
+++ net/pfvar.h 11 Jul 2012 11:29:30 -0000
@@ -1770,8 +1767,6 @@ extern void                        pf_state_export(struct 
pf
                                    struct pf_state *);
 extern void                     pf_print_state(struct pf_state *);
 extern void                     pf_print_flags(u_int8_t);
-extern u_int16_t                pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t,
-                                   u_int8_t);
 
 extern struct ifnet            *sync_ifp;
 extern struct pf_rule           pf_default_rule;
@@ -1795,7 +1790,7 @@ void      pf_addr_inc(struct pf_addr *, sa_fa
 
 void   *pf_pull_hdr(struct mbuf *, int, void *, int, u_short *, u_short *,
            sa_family_t);
-void   pf_change_a(void *, u_int16_t *, u_int32_t, u_int8_t);
+void   pf_change_a(void *, u_int32_t);
 int    pflog_packet(struct pf_pdesc *, u_int8_t, struct pf_rule *,
            struct pf_rule *, struct pf_ruleset *);
 void   pf_send_deferred_syn(struct pf_state *);
@@ -1833,7 +1828,7 @@ struct pf_state_key *pf_alloc_state_key(
 void   pf_pkt_addr_changed(struct mbuf *);
 int    pf_state_key_attach(struct pf_state_key *, struct pf_state *, int);
 int    pf_translate(struct pf_pdesc *, struct pf_addr *, u_int16_t,
-           struct pf_addr *, u_int16_t, u_int16_t, int);
+           struct pf_addr *, u_int16_t, u_int16_t, int, struct mbuf *);
 int    pf_translate_af(struct pf_pdesc *);
 void   pf_route(struct mbuf **, struct pf_rule *, int,
            struct ifnet *, struct pf_state *);
@@ -1987,6 +1982,8 @@ int                        pf_map_addr(sa_family_t, 
struct p
                            struct pf_pool *, enum pf_sn_types);
 
 int                     pf_postprocess_addr(struct pf_state *);
+
+void                    pf_cksum(struct pf_pdesc *, struct mbuf *);
 
 #endif /* _KERNEL */
 
Index: netinet/ip_input.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.195
diff -u -p -r1.195 ip_input.c
--- netinet/ip_input.c  6 Jul 2011 02:42:28 -0000       1.195
+++ netinet/ip_input.c  9 Jul 2011 04:43:56 -0000
@@ -500,6 +500,9 @@ ipv4_input(struct mbuf *m)
        return;
 
 ours:
+       /* pf might have modified stuff, might have to chksum */
+       in_proto_cksum_out(m, NULL);
+
        /*
         * If offset or IP_MF are set, must reassemble.
         * Otherwise, nothing need be done.
Index: netinet/ip_output.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.229
diff -u -p -r1.229 ip_output.c
--- netinet/ip_output.c 13 Apr 2012 09:38:32 -0000      1.229
+++ netinet/ip_output.c 29 May 2012 12:13:52 -0000
@@ -615,6 +615,7 @@ sendit:
                        splx(s);
                        goto done;
                }
+               in_proto_cksum_out(m, encif);
                ip = mtod(m, struct ip *);
                hlen = ip->ip_hl << 2;
                /*
@@ -695,8 +696,6 @@ sendit:
        }
 #endif /* IPSEC */
 
-       in_proto_cksum_out(m, ifp);
-
        /*
         * Packet filter
         */
@@ -708,6 +707,7 @@ sendit:
        }
        if (m == NULL)
                goto done;
+       in_proto_cksum_out(m, ifp);
        ip = mtod(m, struct ip *);
        hlen = ip->ip_hl << 2;
        if ((m->m_pkthdr.pf.flags & (PF_TAG_REROUTE | PF_TAG_GENERATED)) ==
Index: netinet6/in6.h
===================================================================
RCS file: /cvs/src/sys/netinet6/in6.h,v
retrieving revision 1.57
diff -u -p -r1.57 in6.h
--- netinet6/in6.h      10 Jul 2012 11:49:42 -0000      1.57
+++ netinet6/in6.h      10 Jul 2012 13:10:16 -0000
@@ -810,6 +810,7 @@ extern int inet6_rth_add(void *, const s
 extern int inet6_rth_reverse(const void *, void *);
 extern int inet6_rth_segments(const void *);
 extern struct in6_addr *inet6_rth_getaddr(const void *, int);
+extern void in6_proto_cksum_out(struct mbuf *, struct ifnet *);
 __END_DECLS
 #endif /* __BSD_VISIBLE */
 
Index: netinet6/ip6_forward.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_forward.c,v
retrieving revision 1.53
diff -u -p -r1.53 ip6_forward.c
--- netinet6/ip6_forward.c      4 Jul 2011 06:54:49 -0000       1.53
+++ netinet6/ip6_forward.c      9 Jul 2011 04:43:56 -0000
@@ -361,6 +361,7 @@ reroute:
                        splx(s);
                        goto senderr;
                }
+               in6_proto_cksum_out(m, encif);
                ip6 = mtod(m, struct ip6_hdr *);
                /*
                 * PF_TAG_REROUTE handling or not...
@@ -470,7 +471,7 @@ reroute:
        }
        if (m == NULL)
                goto senderr;
-
+       in6_proto_cksum_out(m, rt->rt_ifp);
        ip6 = mtod(m, struct ip6_hdr *);
        if ((m->m_pkthdr.pf.flags & (PF_TAG_REROUTE | PF_TAG_GENERATED)) ==
            (PF_TAG_REROUTE | PF_TAG_GENERATED)) {
Index: netinet6/ip6_input.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.103
diff -u -p -r1.103 ip6_input.c
--- netinet6/ip6_input.c        3 Apr 2012 15:03:08 -0000       1.103
+++ netinet6/ip6_input.c        29 May 2012 12:13:52 -0000
@@ -670,6 +670,9 @@ ip6_input(struct mbuf *m)
                return;
        }       
 
+       /* pf might have changed things */
+       in6_proto_cksum_out(m, NULL);
+
        ip6 = mtod(m, struct ip6_hdr *);
 
        /*
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.124
diff -u -p -r1.124 ip6_output.c
--- netinet6/ip6_output.c       13 Apr 2012 09:38:32 -0000      1.124
+++ netinet6/ip6_output.c       29 May 2012 12:13:52 -0000
@@ -134,6 +134,8 @@ int ip6_splithdr(struct mbuf *, struct i
 int ip6_getpmtu(struct route_in6 *, struct route_in6 *,
        struct ifnet *, struct in6_addr *, u_long *, int *);
 int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
+void in6_delayed_cksum(struct mbuf *, u_int8_t);
+void in6_proto_cksum_out(struct mbuf *, struct ifnet *);
 
 /* Context for non-repeating IDs */
 struct idgen32_ctx ip6_id_ctx;
@@ -532,6 +534,7 @@ reroute:
                        splx(s);
                        goto done;
                }
+               in6_proto_cksum_out(m, encif);
                ip6 = mtod(m, struct ip6_hdr *);
                /*
                 * PF_TAG_REROUTE handling or not...
@@ -803,6 +806,7 @@ reroute:
        }
        if (m == NULL)
                goto done;
+       in6_proto_cksum_out(m, ifp);
        ip6 = mtod(m, struct ip6_hdr *);
        if ((m->m_pkthdr.pf.flags & (PF_TAG_REROUTE | PF_TAG_GENERATED)) ==
            (PF_TAG_REROUTE | PF_TAG_GENERATED)) {
@@ -3204,4 +3208,63 @@ void
 ip6_randomid_init(void)
 {
        idgen32_init(&ip6_id_ctx);
+}
+
+/*
+ * Process a delayed payload checksum calculation.
+ */
+void
+in6_delayed_cksum(struct mbuf *m, u_int8_t nxt)
+{
+       int nxtp, offset;
+       u_int16_t csum;
+
+       offset = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxtp); 
+       if (offset <= 0 || nxtp != nxt)
+               /* If the desired next protocol isn't found, punt. */
+               return;
+
+       csum = (u_int16_t)(in6_cksum(m, nxt, offset, m->m_pkthdr.len - offset));
+
+       switch (nxt) {
+       case IPPROTO_TCP:
+               offset += offsetof(struct tcphdr, th_sum);
+               break;
+
+       case IPPROTO_UDP:
+               offset += offsetof(struct udphdr, uh_sum);
+               if (csum == 0)
+                       csum = 0xffff;
+               break;
+
+       case IPPROTO_ICMPV6:
+               offset += offsetof(struct icmp6_hdr, icmp6_cksum);
+               break;
+       }
+
+       if ((offset + sizeof(u_int16_t)) > m->m_len)
+               m_copyback(m, offset, sizeof(csum), &csum, M_NOWAIT);
+       else
+               *(u_int16_t *)(mtod(m, caddr_t) + offset) = csum;
+}
+
+void
+in6_proto_cksum_out(struct mbuf *m, struct ifnet *ifp)
+{
+       if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) {
+               if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
+                   ifp->if_bridge != NULL) {
+                       in6_delayed_cksum(m, IPPROTO_TCP);
+                       m->m_pkthdr.csum_flags &= ~M_TCP_CSUM_OUT; /* Clear */
+               }
+       } else if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) {
+               if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
+                   ifp->if_bridge != NULL) {
+                       in6_delayed_cksum(m, IPPROTO_UDP);
+                       m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_OUT; /* Clear */
+               }
+       } else if (m->m_pkthdr.csum_flags & M_ICMP_CSUM_OUT) {
+               in6_delayed_cksum(m, IPPROTO_ICMPV6);
+               m->m_pkthdr.csum_flags &= ~M_ICMP_CSUM_OUT; /* Clear */
+       }
 }



-- 
Henning Brauer, h...@bsws.de, henn...@openbsd.org
BS Web Services, http://bsws.de, Full-Service ISP
Secure Hosting, Mail and DNS Services. Dedicated Servers, Root to Fully Managed
Henning Brauer Consulting, http://henningbrauer.com/

Reply via email to