diff options
author | jlemon <jlemon@FreeBSD.org> | 2000-03-27 19:14:27 +0000 |
---|---|---|
committer | jlemon <jlemon@FreeBSD.org> | 2000-03-27 19:14:27 +0000 |
commit | 0dcc5bc0d1cca22e0204f9b9da39474b95100992 (patch) | |
tree | fdc282a4f19987ce5808bccd77c32b1078a9a4b5 /sys/netinet | |
parent | 4fe2aa11ba3f87e4844a6632f6c84b866f178126 (diff) | |
download | FreeBSD-src-0dcc5bc0d1cca22e0204f9b9da39474b95100992.zip FreeBSD-src-0dcc5bc0d1cca22e0204f9b9da39474b95100992.tar.gz |
Add support for offloading IP/TCP/UDP checksums to NIC hardware which
supports them.
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/ip_input.c | 17 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 104 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 32 | ||||
-rw-r--r-- | sys/netinet/tcp_output.c | 19 | ||||
-rw-r--r-- | sys/netinet/tcp_reass.c | 32 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 41 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 41 | ||||
-rw-r--r-- | sys/netinet/udp_usrreq.c | 35 |
8 files changed, 219 insertions, 102 deletions
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 5d1bff3..0d9273d 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -324,10 +324,14 @@ ip_input(struct mbuf *m) } ip = mtod(m, struct ip *); } - if (hlen == sizeof(struct ip)) { - sum = in_cksum_hdr(ip); + if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { + sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); } else { - sum = in_cksum(m, hlen); + if (hlen == sizeof(struct ip)) { + sum = in_cksum_hdr(ip); + } else { + sum = in_cksum(m, hlen); + } } if (sum) { ipstat.ips_badsum++; @@ -841,6 +845,9 @@ ip_reass(m, fp, where) * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us, otherwise * stick new segment in the proper place. + * + * If some of the data is dropped from the the preceding + * segment, then it's checksum is invalidated. */ if (p) { i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; @@ -848,6 +855,7 @@ ip_reass(m, fp, where) if (i >= ip->ip_len) goto dropfrag; m_adj(m, i); + m->m_pkthdr.csum_flags = 0; ip->ip_off += i; ip->ip_len -= i; } @@ -870,6 +878,7 @@ ip_reass(m, fp, where) GETIP(q)->ip_len -= i; GETIP(q)->ip_off += i; m_adj(q, i); + q->m_pkthdr.csum_flags = 0; break; } nq = q->m_nextpkt; @@ -927,6 +936,8 @@ inserted: nq = q->m_nextpkt; q->m_nextpkt = NULL; m_cat(m, q); + m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; + m->m_pkthdr.csum_data += q->m_pkthdr.csum_data; } #ifdef IPDIVERT diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index ee361ce..b44765f 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -96,6 +96,7 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); u_short ip_id; +static void in_delayed_cksum(struct mbuf *m); static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); static void ip_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int)); @@ -132,7 +133,7 @@ ip_output(m0, opt, ro, flags, imo) int len, off, error = 0; struct sockaddr_in *dst; struct in_ifaddr *ia; - int isbroadcast; + int isbroadcast, sw_csum; #ifdef IPSEC struct route iproute; struct socket *so = NULL; @@ -692,6 +693,15 @@ pass: state.ro = ro; state.dst = (struct sockaddr *)dst; + /* + * XXX + * delayed checksums are not currently compatible with IPsec + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } + error = ipsec4_output(&state, sp, flags); m = state.m; @@ -754,17 +764,29 @@ pass: skip_ipsec: #endif /*IPSEC*/ + sw_csum = m->m_pkthdr.csum_flags | CSUM_IP; + m->m_pkthdr.csum_flags = sw_csum & ifp->if_hwassist; + sw_csum &= ~ifp->if_hwassist; + if (sw_csum & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + sw_csum &= ~CSUM_DELAY_DATA; + } + /* - * If small enough for interface, can just send directly. + * If small enough for interface, or the interface will take + * care of the fragmentation for us, can just send directly. */ - if ((u_short)ip->ip_len <= ifp->if_mtu) { + if ((u_short)ip->ip_len <= ifp->if_mtu || + ifp->if_hwassist & CSUM_FRAGMENT) { ip->ip_len = htons((u_short)ip->ip_len); ip->ip_off = htons((u_short)ip->ip_off); ip->ip_sum = 0; - if (ip->ip_vhl == IP_VHL_BORING) { - ip->ip_sum = in_cksum_hdr(ip); - } else { - ip->ip_sum = in_cksum(m, hlen); + if (sw_csum & CSUM_DELAY_IP) { + if (ip->ip_vhl == IP_VHL_BORING) { + ip->ip_sum = in_cksum_hdr(ip); + } else { + ip->ip_sum = in_cksum(m, hlen); + } } error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); @@ -797,9 +819,20 @@ skip_ipsec: goto bad; } + /* + * if the interface will not calculate checksums on + * fragmented packets, then do it here. + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA && + (ifp->if_hwassist & CSUM_IP_FRAGS) == 0) { + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } + { int mhlen, firstlen = len; struct mbuf **mnext = &m->m_nextpkt; + int nfrags = 1; /* * Loop through length of segment after first fragment, @@ -814,7 +847,7 @@ skip_ipsec: ipstat.ips_odropped++; goto sendorfree; } - m->m_flags |= (m0->m_flags & M_MCAST); + m->m_flags |= (m0->m_flags & M_MCAST) | M_FRAG; m->m_data += max_linkhdr; mhip = mtod(m, struct ip *); *mhip = *ip; @@ -840,17 +873,27 @@ skip_ipsec: } m->m_pkthdr.len = mhlen + len; m->m_pkthdr.rcvif = (struct ifnet *)0; + m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags; mhip->ip_off = htons((u_short)mhip->ip_off); mhip->ip_sum = 0; - if (mhip->ip_vhl == IP_VHL_BORING) { - mhip->ip_sum = in_cksum_hdr(mhip); - } else { - mhip->ip_sum = in_cksum(m, mhlen); + if (sw_csum & CSUM_DELAY_IP) { + if (mhip->ip_vhl == IP_VHL_BORING) { + mhip->ip_sum = in_cksum_hdr(mhip); + } else { + mhip->ip_sum = in_cksum(m, mhlen); + } } *mnext = m; mnext = &m->m_nextpkt; - ipstat.ips_ofragments++; + nfrags++; } + ipstat.ips_ofragments += nfrags; + + /* set first/last markers for fragment chain */ + m->m_flags |= M_LASTFRAG; + m0->m_flags |= M_FIRSTFRAG | M_FRAG; + m0->m_pkthdr.csum_data = nfrags; + /* * Update first fragment by trimming what's been copied out * and updating header, then send each fragment (in order). @@ -861,10 +904,12 @@ skip_ipsec: ip->ip_len = htons((u_short)m->m_pkthdr.len); ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); ip->ip_sum = 0; - if (ip->ip_vhl == IP_VHL_BORING) { - ip->ip_sum = in_cksum_hdr(ip); - } else { - ip->ip_sum = in_cksum(m, hlen); + if (sw_csum & CSUM_DELAY_IP) { + if (ip->ip_vhl == IP_VHL_BORING) { + ip->ip_sum = in_cksum_hdr(ip); + } else { + ip->ip_sum = in_cksum(m, hlen); + } } sendorfree: for (m = m0; m; m = m0) { @@ -898,6 +943,31 @@ bad: goto done; } +static void +in_delayed_cksum(struct mbuf *m) +{ + struct ip *ip; + u_short csum, offset; + + ip = mtod(m, struct ip *); + offset = IP_VHL_HL(ip->ip_vhl) << 2 ; + csum = in_cksum_skip(m, ip->ip_len, offset); + offset += m->m_pkthdr.csum_data; /* checksum offset */ + + if (offset + sizeof(u_short) > m->m_len) { + printf("delayed m_pullup, m->len: %d off: %d p: %d\n", + m->m_len, offset, ip->ip_p); + /* + * XXX + * this shouldn't happen, but if it does, the + * correct behavior may be to insert the checksum + * in the existing chain instead of rearranging it. + */ + m = m_pullup(m, offset + sizeof(u_short)); + } + *(u_short *)(m->m_data + offset) = csum; +} + /* * Insert IP options into preformed packet. * Adjust IP destination as required for IP source routing, diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 1d2d8c3..dc8ba3c 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -100,6 +100,8 @@ struct tcphdr tcp_savetcp; #include <netkey/key.h> #endif /*IPSEC*/ +#include <machine/in_cksum.h> + MALLOC_DEFINE(M_TSEGQ, "tseg_qent", "TCP segment queue entry"); static int tcprexmtthresh = 3; @@ -425,17 +427,27 @@ tcp_input(m, off0, proto) } ip = mtod(m, struct ip *); ipov = (struct ipovly *)ip; - - /* - * Checksum extended TCP header and data. - */ - tlen = ip->ip_len; - len = sizeof (struct ip) + tlen; - bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); - ipov->ih_len = (u_short)tlen; - HTONS(ipov->ih_len); th = (struct tcphdr *)((caddr_t)ip + off0); - th->th_sum = in_cksum(m, len); + tlen = ip->ip_len; + + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { + if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) + th->th_sum = m->m_pkthdr.csum_data; + else + th->th_sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htonl(m->m_pkthdr.csum_data + + ip->ip_len + IPPROTO_TCP)); + th->th_sum ^= 0xffff; + } else { + /* + * Checksum extended TCP header and data. + */ + len = sizeof (struct ip) + tlen; + bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); + ipov->ih_len = (u_short)tlen; + HTONS(ipov->ih_len); + th->th_sum = in_cksum(m, len); + } if (th->th_sum) { tcpstat.tcps_rcvbadsum++; goto drop; diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index ae85e84..238d25a 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -80,6 +80,8 @@ #include <netinet6/ipsec.h> #endif /*IPSEC*/ +#include <machine/in_cksum.h> + #ifdef notyet extern struct mbuf *m_copypack(); #endif @@ -645,6 +647,7 @@ send: ip = mtod(m, struct ip *); ipov = (struct ipovly *)ip; th = (struct tcphdr *)(ip + 1); + /* this picks up the pseudo header (w/o the length) */ bcopy((caddr_t)tp->t_template->tt_ipgen, (caddr_t)ip, sizeof(struct ip)); bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, @@ -722,15 +725,15 @@ send: else #endif /* INET6 */ { + m->m_pkthdr.csum_flags = CSUM_TCP; + m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); if (len + optlen) - ipov->ih_len = htons((u_short)(sizeof (struct tcphdr) + - optlen + len)); - th->th_sum = in_cksum(m, (int)(hdrlen + len)); -#ifdef INET6 - /* Re-initialization for later version check */ - ip->ip_v = IPVERSION; - -#endif /* INET6 */ + th->th_sum = in_addword(th->th_sum, + htons((u_short)(optlen + len))); + + /* IP version must be set here for ipv4/ipv6 checking later */ + KASSERT(ip->ip_v == IPVERSION, + ("%s: IP version incorrect: %d", __FUNCTION__, ip->ip_v)); } /* diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 1d2d8c3..dc8ba3c 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -100,6 +100,8 @@ struct tcphdr tcp_savetcp; #include <netkey/key.h> #endif /*IPSEC*/ +#include <machine/in_cksum.h> + MALLOC_DEFINE(M_TSEGQ, "tseg_qent", "TCP segment queue entry"); static int tcprexmtthresh = 3; @@ -425,17 +427,27 @@ tcp_input(m, off0, proto) } ip = mtod(m, struct ip *); ipov = (struct ipovly *)ip; - - /* - * Checksum extended TCP header and data. - */ - tlen = ip->ip_len; - len = sizeof (struct ip) + tlen; - bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); - ipov->ih_len = (u_short)tlen; - HTONS(ipov->ih_len); th = (struct tcphdr *)((caddr_t)ip + off0); - th->th_sum = in_cksum(m, len); + tlen = ip->ip_len; + + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { + if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) + th->th_sum = m->m_pkthdr.csum_data; + else + th->th_sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htonl(m->m_pkthdr.csum_data + + ip->ip_len + IPPROTO_TCP)); + th->th_sum ^= 0xffff; + } else { + /* + * Checksum extended TCP header and data. + */ + len = sizeof (struct ip) + tlen; + bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); + ipov->ih_len = (u_short)tlen; + HTONS(ipov->ih_len); + th->th_sum = in_cksum(m, len); + } if (th->th_sum) { tcpstat.tcps_rcvbadsum++; goto drop; diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index ee62998..d4c552f 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -39,6 +39,7 @@ #include "opt_ipsec.h" #include "opt_tcpdebug.h" +#include <stddef.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/callout.h> @@ -93,6 +94,8 @@ #include <netinet6/ipsec.h> #endif /*IPSEC*/ +#include <machine/in_cksum.h> + int tcp_mssdflt = TCP_MSS; SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, CTLFLAG_RW, &tcp_mssdflt , 0, "Default TCP Maximum Segment Size"); @@ -242,17 +245,19 @@ tcp_template(tp) ip6->ip6_plen = sizeof(struct tcphdr); ip6->ip6_src = inp->in6p_laddr; ip6->ip6_dst = inp->in6p_faddr; + n->tt_t.th_sum = 0; } else #endif { - register struct ipovly *ipov; - - ipov = (struct ipovly *)n->tt_ipgen; - bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); - ipov->ih_pr = IPPROTO_TCP; - ipov->ih_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); - ipov->ih_src = inp->inp_laddr; - ipov->ih_dst = inp->inp_faddr; + struct ip *ip = (struct ip *)n->tt_ipgen; + + bzero(ip, sizeof(struct ip)); /* XXX overkill? */ + ip->ip_vhl = IP_VHL_BORING; + ip->ip_p = IPPROTO_TCP; + ip->ip_src = inp->inp_laddr; + ip->ip_dst = inp->inp_faddr; + n->tt_t.th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htons(sizeof(struct tcphdr) + IPPROTO_TCP)); } n->tt_t.th_sport = inp->inp_lport; n->tt_t.th_dport = inp->inp_fport; @@ -262,7 +267,6 @@ tcp_template(tp) n->tt_t.th_off = 5; n->tt_t.th_flags = 0; n->tt_t.th_win = 0; - n->tt_t.th_sum = 0; n->tt_t.th_urp = 0; return (n); } @@ -296,7 +300,6 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) struct route *ro = 0; struct route sro; struct ip *ip; - struct ipovly *ipov; struct tcphdr *nth; #ifdef INET6 struct route_in6 *ro6 = 0; @@ -311,7 +314,6 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) ip6 = ipgen; #endif /* INET6 */ ip = ipgen; - ipov = ipgen; if (tp) { if (!(flags & TH_RST)) { @@ -358,7 +360,6 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) { bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); ip = mtod(m, struct ip *); - ipov = mtod(m, struct ipovly *); nth = (struct tcphdr *)(ip + 1); } bcopy((caddr_t)th, (caddr_t)nth, sizeof(struct tcphdr)); @@ -400,8 +401,9 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) } else #endif { - ipov->ih_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); tlen += sizeof (struct tcpiphdr); + ip->ip_len = tlen; + ip->ip_ttl = ip_defttl; } m->m_len = tlen; m->m_pkthdr.len = tlen; @@ -416,7 +418,6 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) else nth->th_win = htons((u_short)win); nth->th_urp = 0; - nth->th_sum = 0; #ifdef INET6 if (isipv6) { nth->th_sum = in6_cksum(m, IPPROTO_TCP, @@ -429,14 +430,10 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) } else #endif /* INET6 */ { - bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); - nth->th_sum = in_cksum(m, tlen); -#ifdef INET6 - /* Re-initialization for later version check */ - ip->ip_vhl = IP_MAKE_VHL(IPVERSION, 0); -#endif /* INET6 */ - ip->ip_len = tlen; - ip->ip_ttl = ip_defttl; + nth->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htons((u_short)(tlen - sizeof(struct ip) + ip->ip_p))); + m->m_pkthdr.csum_flags = CSUM_TCP; + m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); } #ifdef TCPDEBUG if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index ee62998..d4c552f 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -39,6 +39,7 @@ #include "opt_ipsec.h" #include "opt_tcpdebug.h" +#include <stddef.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/callout.h> @@ -93,6 +94,8 @@ #include <netinet6/ipsec.h> #endif /*IPSEC*/ +#include <machine/in_cksum.h> + int tcp_mssdflt = TCP_MSS; SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, CTLFLAG_RW, &tcp_mssdflt , 0, "Default TCP Maximum Segment Size"); @@ -242,17 +245,19 @@ tcp_template(tp) ip6->ip6_plen = sizeof(struct tcphdr); ip6->ip6_src = inp->in6p_laddr; ip6->ip6_dst = inp->in6p_faddr; + n->tt_t.th_sum = 0; } else #endif { - register struct ipovly *ipov; - - ipov = (struct ipovly *)n->tt_ipgen; - bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); - ipov->ih_pr = IPPROTO_TCP; - ipov->ih_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); - ipov->ih_src = inp->inp_laddr; - ipov->ih_dst = inp->inp_faddr; + struct ip *ip = (struct ip *)n->tt_ipgen; + + bzero(ip, sizeof(struct ip)); /* XXX overkill? */ + ip->ip_vhl = IP_VHL_BORING; + ip->ip_p = IPPROTO_TCP; + ip->ip_src = inp->inp_laddr; + ip->ip_dst = inp->inp_faddr; + n->tt_t.th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htons(sizeof(struct tcphdr) + IPPROTO_TCP)); } n->tt_t.th_sport = inp->inp_lport; n->tt_t.th_dport = inp->inp_fport; @@ -262,7 +267,6 @@ tcp_template(tp) n->tt_t.th_off = 5; n->tt_t.th_flags = 0; n->tt_t.th_win = 0; - n->tt_t.th_sum = 0; n->tt_t.th_urp = 0; return (n); } @@ -296,7 +300,6 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) struct route *ro = 0; struct route sro; struct ip *ip; - struct ipovly *ipov; struct tcphdr *nth; #ifdef INET6 struct route_in6 *ro6 = 0; @@ -311,7 +314,6 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) ip6 = ipgen; #endif /* INET6 */ ip = ipgen; - ipov = ipgen; if (tp) { if (!(flags & TH_RST)) { @@ -358,7 +360,6 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) { bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); ip = mtod(m, struct ip *); - ipov = mtod(m, struct ipovly *); nth = (struct tcphdr *)(ip + 1); } bcopy((caddr_t)th, (caddr_t)nth, sizeof(struct tcphdr)); @@ -400,8 +401,9 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) } else #endif { - ipov->ih_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); tlen += sizeof (struct tcpiphdr); + ip->ip_len = tlen; + ip->ip_ttl = ip_defttl; } m->m_len = tlen; m->m_pkthdr.len = tlen; @@ -416,7 +418,6 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) else nth->th_win = htons((u_short)win); nth->th_urp = 0; - nth->th_sum = 0; #ifdef INET6 if (isipv6) { nth->th_sum = in6_cksum(m, IPPROTO_TCP, @@ -429,14 +430,10 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) } else #endif /* INET6 */ { - bzero(ipov->ih_x1, sizeof(ipov->ih_x1)); - nth->th_sum = in_cksum(m, tlen); -#ifdef INET6 - /* Re-initialization for later version check */ - ip->ip_vhl = IP_MAKE_VHL(IPVERSION, 0); -#endif /* INET6 */ - ip->ip_len = tlen; - ip->ip_ttl = ip_defttl; + nth->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htons((u_short)(tlen - sizeof(struct ip) + ip->ip_p))); + m->m_pkthdr.csum_flags = CSUM_TCP; + m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); } #ifdef TCPDEBUG if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 2ed9a36..b8700de 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -37,6 +37,7 @@ #include "opt_ipsec.h" #include "opt_inet6.h" +#include <stddef.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -76,6 +77,8 @@ #include <netinet6/ipsec.h> #endif /*IPSEC*/ +#include <machine/in_cksum.h> + /* * UDP protocol implementation. * Per RFC 768, August, 1980. @@ -208,9 +211,19 @@ udp_input(m, off, proto) * Checksum extended UDP header and data. */ if (uh->uh_sum) { - bzero(((struct ipovly *)ip)->ih_x1, 9); - ((struct ipovly *)ip)->ih_len = uh->uh_ulen; - uh->uh_sum = in_cksum(m, len + sizeof (struct ip)); + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { + if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) + uh->uh_sum = m->m_pkthdr.csum_data; + else + uh->uh_sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htonl(ip->ip_len + + m->m_pkthdr.csum_data + IPPROTO_UDP)); + uh->uh_sum ^= 0xffff; + } else { + bzero(((struct ipovly *)ip)->ih_x1, 9); + ((struct ipovly *)ip)->ih_len = uh->uh_ulen; + uh->uh_sum = in_cksum(m, len + sizeof (struct ip)); + } if (uh->uh_sum) { udpstat.udps_badsum++; m_freem(m); @@ -679,22 +692,24 @@ udp_output(inp, m, addr, control, p) * and addresses and length put into network format. */ ui = mtod(m, struct udpiphdr *); - bzero(ui->ui_x1, sizeof(ui->ui_x1)); + bzero(ui->ui_x1, sizeof(ui->ui_x1)); /* XXX still needed? */ ui->ui_pr = IPPROTO_UDP; - ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); ui->ui_src = inp->inp_laddr; ui->ui_dst = inp->inp_faddr; ui->ui_sport = inp->inp_lport; ui->ui_dport = inp->inp_fport; - ui->ui_ulen = ui->ui_len; + ui->ui_ulen = htons((u_short)len + sizeof(struct udphdr)); /* - * Stuff checksum and output datagram. + * Set up checksum and output datagram. */ - ui->ui_sum = 0; if (udpcksum) { - if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) - ui->ui_sum = 0xffff; + ui->ui_sum = in_pseudo(ui->ui_src.s_addr, ui->ui_dst.s_addr, + htons((u_short)len + sizeof(struct udphdr) + IPPROTO_UDP)); + m->m_pkthdr.csum_flags = CSUM_UDP; + m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); + } else { + ui->ui_sum = 0; } ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ |