diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/in.h | 3 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 76 |
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; +} |