summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/in.h3
-rw-r--r--sys/netinet/ip_output.c76
2 files changed, 54 insertions, 25 deletions
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index bced70a3fbe..25dcd58b73a 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.h,v 1.49 2001/06/23 06:38:10 angelos Exp $ */
+/* $OpenBSD: in.h,v 1.50 2001/06/24 23:33:55 angelos Exp $ */
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
/*
@@ -505,6 +505,7 @@ int in_broadcast __P((struct in_addr, struct ifnet *));
int in_canforward __P((struct in_addr));
int in_cksum __P((struct mbuf *, int));
int in4_cksum __P((struct mbuf *, u_int8_t, int, int));
+void in_delayed_cksum __P((struct mbuf *));
int in_localaddr __P((struct in_addr));
void in_socktrim __P((struct sockaddr_in *));
char *inet_ntoa __P((struct in_addr));
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 441aec3f25e..1df223e972e 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.116 2001/06/24 22:24:30 angelos Exp $ */
+/* $OpenBSD: ip_output.c,v 1.117 2001/06/24 23:33:56 angelos Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -110,7 +110,6 @@ ip_output(m0, va_alist)
struct ip_moptions *imo;
va_list ap;
u_int8_t sproto = 0, donerouting = 0;
- short csums;
#ifdef IPSEC
u_int32_t icmp_mtu = 0;
union sockaddr_union sdst;
@@ -339,22 +338,12 @@ ip_output(m0, va_alist)
/*
* If it needs TCP/UDP hardware-checksumming, do the
* computation now.
- */
- if (m->m_pkthdr.csum & M_TCPV4_CSUM_OUT &&
- !(ifp->if_capabilities & IFCAP_CSUM_TCPv4)) {
- csums = in4_cksum(m, IPPROTO_TCP, 0, m->m_pkthdr.len);
- m_copyback(m, hlen + offsetof(struct tcphdr, th_sum),
- sizeof(short), (caddr_t)&csums);
- m->m_pkthdr.csum &= ~M_TCPV4_CSUM_OUT; /* Clear */
- }
-
- if (m->m_pkthdr.csum & M_UDPV4_CSUM_OUT &&
- !(ifp->if_capabilities & IFCAP_CSUM_UDPv4)) {
- csums = in4_cksum(m, IPPROTO_UDP, 0, m->m_pkthdr.len);
- m_copyback(m, hlen + offsetof(struct udphdr, uh_sum),
- sizeof(short), (caddr_t)&csums);
- m->m_pkthdr.csum &= ~M_UDPV4_CSUM_OUT; /* Clear */
- }
+ */
+ if (m->m_pkthdr.csum & (M_TCPV4_CSUM_OUT | M_UDPV4_CSUM_OUT)) {
+ in_delayed_cksum(m);
+ m->m_pkthdr.csum &=
+ ~(M_UDPV4_CSUM_OUT | M_TCPV4_CSUM_OUT);
+ }
/* If it's not a multicast packet, try to fast-path */
if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
@@ -655,17 +644,13 @@ sendit:
/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
if (m->m_pkthdr.csum & M_TCPV4_CSUM_OUT &&
!(ifp->if_capabilities & IFCAP_CSUM_TCPv4)) {
- csums = in4_cksum(m, IPPROTO_TCP, 0, m->m_pkthdr.len);
- m_copyback(m, hlen + offsetof(struct tcphdr, th_sum),
- sizeof(short), (caddr_t)&csums);
+ in_delayed_cksum(m);
m->m_pkthdr.csum &= ~M_TCPV4_CSUM_OUT; /* Clear */
}
if (m->m_pkthdr.csum & M_UDPV4_CSUM_OUT &&
!(ifp->if_capabilities & IFCAP_CSUM_UDPv4)) {
- csums = in4_cksum(m, IPPROTO_UDP, 0, m->m_pkthdr.len);
- m_copyback(m, hlen + offsetof(struct udphdr, uh_sum),
- sizeof(short), (caddr_t)&csums);
+ in_delayed_cksum(m);
m->m_pkthdr.csum &= ~M_UDPV4_CSUM_OUT; /* Clear */
}
@@ -717,6 +702,15 @@ sendit:
goto bad;
}
+ /*
+ * If we are doing fragmentation, we can't defer TCP/UDP
+ * checksumming; compute the checksum and clear the flag.
+ */
+ if (m->m_pkthdr.csum & (M_TCPV4_CSUM_OUT | M_UDPV4_CSUM_OUT)) {
+ in_delayed_cksum(m);
+ m->m_pkthdr.csum &= ~(M_UDPV4_CSUM_OUT | M_TCPV4_CSUM_OUT);
+ }
+
{
int mhlen, firstlen = len;
struct mbuf **mnext = &m->m_nextpkt;
@@ -1823,3 +1817,37 @@ ip_mloopback(ifp, m, dst)
(void) looutput(ifp, copym, sintosa(dst), NULL);
}
}
+
+/*
+ * Process a delayed payload checksum calculation.
+ */
+void
+in_delayed_cksum(struct mbuf *m)
+{
+ struct ip *ip;
+ u_int16_t csum, offset;
+
+ ip = mtod(m, struct ip *);
+ offset = ip->ip_hl << 2;
+ csum = in4_cksum(m, ip->ip_p, offset, ntohs(ip->ip_len) - offset);
+ if (csum == 0 && ip->ip_p == IPPROTO_UDP)
+ csum = 0xffff;
+
+ switch (ip->ip_p) {
+ case IPPROTO_TCP:
+ offset += offsetof(struct tcphdr, th_sum);
+ break;
+
+ case IPPROTO_UDP:
+ offset += offsetof(struct udphdr, uh_sum);
+ break;
+
+ default:
+ return;
+ }
+
+ if ((offset + sizeof(u_int16_t)) > m->m_len)
+ m_copyback(m, offset, sizeof(csum), (caddr_t) &csum);
+ else
+ *(u_int16_t *)(mtod(m, caddr_t) + offset) = csum;
+}