summaryrefslogtreecommitdiff
path: root/sys/netinet6
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/in6.h3
-rw-r--r--sys/netinet6/ip6_divert.c5
-rw-r--r--sys/netinet6/ip6_forward.c5
-rw-r--r--sys/netinet6/ip6_input.c5
-rw-r--r--sys/netinet6/ip6_output.c65
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 */
+ }
+}