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/