diff options
Diffstat (limited to 'sys/netinet6')
-rw-r--r-- | sys/netinet6/in6.h | 3 | ||||
-rw-r--r-- | sys/netinet6/ip6_divert.c | 5 | ||||
-rw-r--r-- | sys/netinet6/ip6_forward.c | 5 | ||||
-rw-r--r-- | sys/netinet6/ip6_input.c | 5 | ||||
-rw-r--r-- | sys/netinet6/ip6_output.c | 65 |
5 files changed, 77 insertions, 6 deletions
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 9bbec7df68d..ad01de151cb 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in6.h,v 1.59 2012/09/17 20:01:26 yasuoka Exp $ */ +/* $OpenBSD: in6.h,v 1.60 2012/11/01 07:55:56 henning Exp $ */ /* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */ /* @@ -758,6 +758,7 @@ struct ip6_mtuinfo { struct cmsghdr; int in6_cksum(struct mbuf *, u_int8_t, u_int32_t, u_int32_t); +extern void in6_proto_cksum_out(struct mbuf *, struct ifnet *); int in6_localaddr(struct in6_addr *); int in6_addrscope(struct in6_addr *); struct in6_ifaddr *in6_ifawithscope(struct ifnet *, struct in6_addr *, u_int); diff --git a/sys/netinet6/ip6_divert.c b/sys/netinet6/ip6_divert.c index fbc6d9551f5..603c7995625 100644 --- a/sys/netinet6/ip6_divert.c +++ b/sys/netinet6/ip6_divert.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_divert.c,v 1.6 2012/10/21 13:06:03 benno Exp $ */ +/* $OpenBSD: ip6_divert.c,v 1.7 2012/11/01 07:55:56 henning Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -188,6 +188,9 @@ divert6_packet(struct mbuf *m, int dir) break; } } + /* force checksum calculation */ + if (dir == PF_OUT) + in6_proto_cksum_out(m, NULL); if (inp != CIRCLEQ_END(&divb6table.inpt_queue)) { sa = inp->inp_socket; diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 3c63ac1c6df..f5e6754f4b4 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_forward.c,v 1.54 2012/07/16 18:05:36 markus Exp $ */ +/* $OpenBSD: ip6_forward.c,v 1.55 2012/11/01 07:55:56 henning Exp $ */ /* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */ /* @@ -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)) { diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 6adf9bc17ce..3cbd344b3da 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_input.c,v 1.103 2012/04/03 15:03:08 mikeb Exp $ */ +/* $OpenBSD: ip6_input.c,v 1.104 2012/11/01 07:55:56 henning Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -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 *); /* diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index fb31a691399..f12ea0e3fa3 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_output.c,v 1.128 2012/10/16 08:09:09 bluhm Exp $ */ +/* $OpenBSD: ip6_output.c,v 1.129 2012/11/01 07:55:56 henning Exp $ */ /* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */ /* @@ -134,6 +134,8 @@ int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *); 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)) { @@ -3214,3 +3218,62 @@ 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_TCPv6) || + ifp->if_bridgeport != 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_UDPv6) || + ifp->if_bridgeport != 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 */ + } +} |