Subject: checksum handling
To: None <tech-net@netbsd.org>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-net
Date: 12/18/2004 21:21:14
--NextPart-20041218211932-0831101
Content-Type: Text/Plain; charset=us-ascii
hi,
if no one objects,
i'll factor out input checksum handling code as the attached diffs
so that packet filters can use it.
YAMAMOTO Takashi
--NextPart-20041218211932-0831101
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="csum.diff"
Index: netinet/udp_var.h
===================================================================
--- netinet/udp_var.h (revision 990)
+++ netinet/udp_var.h (working copy)
@@ -100,6 +100,8 @@ int udp_output(struct mbuf *, ...);
int udp_sysctl(int *, u_int, void *, size_t *, void *, size_t);
int udp_usrreq(struct socket *,
int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *);
+
+int udp4_input_checksum(struct mbuf *, const struct udphdr *, int, int);
#endif
#endif /* _NETINET_UDP_VAR_H_ */
Index: netinet/tcp_input.c
===================================================================
--- netinet/tcp_input.c (revision 991)
+++ netinet/tcp_input.c (working copy)
@@ -779,6 +779,87 @@ tcp6_log_refused(ip6, th)
#endif
/*
+ * Checksum extended TCP header and data.
+ */
+int
+tcp_input_checksum(int af, struct mbuf *m, const struct tcphdr *th, int toff,
+ int off, int tlen)
+{
+
+ /*
+ * XXX it's better to record and check if this mbuf is
+ * already checked.
+ */
+
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ switch (m->m_pkthdr.csum_flags &
+ ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_TCPv4) |
+ M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) {
+ case M_CSUM_TCPv4|M_CSUM_TCP_UDP_BAD:
+ TCP_CSUM_COUNTER_INCR(&tcp_hwcsum_bad);
+ goto badcsum;
+
+ case M_CSUM_TCPv4|M_CSUM_DATA: {
+ u_int32_t hw_csum = m->m_pkthdr.csum_data;
+
+ TCP_CSUM_COUNTER_INCR(&tcp_hwcsum_data);
+ if (m->m_pkthdr.csum_flags & M_CSUM_NO_PSEUDOHDR) {
+ const struct ip *ip =
+ mtod(m, const struct ip *);
+
+ hw_csum = in_cksum_phdr(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr,
+ htons(hw_csum + tlen + off + IPPROTO_TCP));
+ }
+ if ((hw_csum ^ 0xffff) != 0)
+ goto badcsum;
+ break;
+ }
+
+ case M_CSUM_TCPv4:
+ /* Checksum was okay. */
+ TCP_CSUM_COUNTER_INCR(&tcp_hwcsum_ok);
+ break;
+
+ default:
+ /*
+ * Must compute it ourselves. Maybe skip checksum
+ * on loopback interfaces.
+ */
+ if (__predict_true(!(m->m_pkthdr.rcvif->if_flags &
+ IFF_LOOPBACK) ||
+ tcp_do_loopback_cksum)) {
+ TCP_CSUM_COUNTER_INCR(&tcp_swcsum);
+ if (in4_cksum(m, IPPROTO_TCP, toff,
+ tlen + off) != 0)
+ goto badcsum;
+ }
+ break;
+ }
+ break;
+#endif /* INET4 */
+
+#ifdef INET6
+ case AF_INET6:
+ if (__predict_true((m->m_flags & M_LOOP) == 0 ||
+ tcp_do_loopback_cksum)) {
+ if (in6_cksum(m, IPPROTO_TCP, toff, tlen + off) != 0)
+ goto badcsum;
+ }
+ break;
+#endif /* INET6 */
+ }
+
+ return 0;
+
+badcsum:
+ tcpstat.tcps_rcvbadsum++;
+ return -1;
+}
+
+/*
* TCP input routine, follows pages 65-76 of the
* protocol specification dated September, 1981 very closely.
*/
@@ -1106,63 +1187,9 @@ findpcb:
/*
* Checksum extended TCP header and data.
*/
- switch (af) {
-#ifdef INET
- case AF_INET:
- switch (m->m_pkthdr.csum_flags &
- ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_TCPv4) |
- M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) {
- case M_CSUM_TCPv4|M_CSUM_TCP_UDP_BAD:
- TCP_CSUM_COUNTER_INCR(&tcp_hwcsum_bad);
- goto badcsum;
+ if (tcp_input_checksum(af, m, th, toff, off, tlen))
+ goto badcsum;
- case M_CSUM_TCPv4|M_CSUM_DATA: {
- u_int32_t hw_csum = m->m_pkthdr.csum_data;
- TCP_CSUM_COUNTER_INCR(&tcp_hwcsum_data);
- if (m->m_pkthdr.csum_flags & M_CSUM_NO_PSEUDOHDR) {
- hw_csum = in_cksum_phdr(ip->ip_src.s_addr,
- ip->ip_dst.s_addr,
- htons(hw_csum + tlen + off + IPPROTO_TCP));
- }
- if ((hw_csum ^ 0xffff) != 0)
- goto badcsum;
- break;
- }
-
- case M_CSUM_TCPv4:
- /* Checksum was okay. */
- TCP_CSUM_COUNTER_INCR(&tcp_hwcsum_ok);
- break;
-
- default:
- /*
- * Must compute it ourselves. Maybe skip checksum
- * on loopback interfaces.
- */
- if (__predict_true(!(m->m_pkthdr.rcvif->if_flags &
- IFF_LOOPBACK) ||
- tcp_do_loopback_cksum)) {
- TCP_CSUM_COUNTER_INCR(&tcp_swcsum);
- if (in4_cksum(m, IPPROTO_TCP, toff,
- tlen + off) != 0)
- goto badcsum;
- }
- break;
- }
- break;
-#endif /* INET4 */
-
-#ifdef INET6
- case AF_INET6:
- if (__predict_true((m->m_flags & M_LOOP) == 0 ||
- tcp_do_loopback_cksum)) {
- if (in6_cksum(m, IPPROTO_TCP, toff, tlen + off) != 0)
- goto badcsum;
- }
- break;
-#endif /* INET6 */
- }
-
TCP_FIELDS_TO_HOST(th);
/* Unscale the window into a 32-bit value. */
@@ -2549,7 +2576,6 @@ dropwithreset:
return;
badcsum:
- tcpstat.tcps_rcvbadsum++;
drop:
/*
* Drop space held by incoming segment and return.
Index: netinet/tcp_var.h
===================================================================
--- netinet/tcp_var.h (revision 990)
+++ netinet/tcp_var.h (working copy)
@@ -822,7 +822,10 @@ int syn_cache_respond(struct syn_cache
void syn_cache_timer(void *);
void syn_cache_cleanup(struct tcpcb *);
-int tcp_newreno(struct tcpcb *, struct tcphdr *);
+int tcp_newreno(struct tcpcb *, struct tcphdr *);
+
+int tcp_input_checksum(int, struct mbuf *, const struct tcphdr *, int, int,
+ int);
#endif
#endif /* _NETINET_TCP_VAR_H_ */
Index: netinet/udp_usrreq.c
===================================================================
--- netinet/udp_usrreq.c (revision 990)
+++ netinet/udp_usrreq.c (working copy)
@@ -210,6 +210,75 @@ udp_init(void)
}
#ifdef INET
+
+/*
+ * Checksum extended UDP header and data.
+ */
+
+int
+udp4_input_checksum(struct mbuf *m, const struct udphdr *uh,
+ int iphlen, int len)
+{
+
+ /*
+ * XXX it's better to record and check if this mbuf is
+ * already checked.
+ */
+
+ if (uh->uh_sum == 0)
+ return 0;
+
+ switch (m->m_pkthdr.csum_flags &
+ ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_UDPv4) |
+ M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) {
+ case M_CSUM_UDPv4|M_CSUM_TCP_UDP_BAD:
+ UDP_CSUM_COUNTER_INCR(&udp_hwcsum_bad);
+ goto badcsum;
+
+ case M_CSUM_UDPv4|M_CSUM_DATA: {
+ u_int32_t hw_csum = m->m_pkthdr.csum_data;
+
+ UDP_CSUM_COUNTER_INCR(&udp_hwcsum_data);
+ if (m->m_pkthdr.csum_flags & M_CSUM_NO_PSEUDOHDR) {
+ const struct ip *ip =
+ mtod(m, const struct ip *);
+
+ hw_csum = in_cksum_phdr(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr,
+ htons(hw_csum + len + IPPROTO_UDP));
+ }
+ if ((hw_csum ^ 0xffff) != 0)
+ goto badcsum;
+ break;
+ }
+
+ case M_CSUM_UDPv4:
+ /* Checksum was okay. */
+ UDP_CSUM_COUNTER_INCR(&udp_hwcsum_ok);
+ break;
+
+ default:
+ /*
+ * Need to compute it ourselves. Maybe skip checksum
+ * on loopback interfaces.
+ */
+ if (__predict_true(!(m->m_pkthdr.rcvif->if_flags &
+ IFF_LOOPBACK) ||
+ udp_do_loopback_cksum)) {
+ UDP_CSUM_COUNTER_INCR(&udp_swcsum);
+ if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0)
+ goto badcsum;
+ }
+ break;
+ }
+
+ return 0;
+
+badcsum:
+ udpstat.udps_badsum++;
+ return -1;
+}
+
void
udp_input(struct mbuf *m, ...)
{
@@ -262,47 +331,9 @@ udp_input(struct mbuf *m, ...)
/*
* Checksum extended UDP header and data.
*/
- if (uh->uh_sum) {
- switch (m->m_pkthdr.csum_flags &
- ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_UDPv4) |
- M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) {
- case M_CSUM_UDPv4|M_CSUM_TCP_UDP_BAD:
- UDP_CSUM_COUNTER_INCR(&udp_hwcsum_bad);
- goto badcsum;
+ if (udp4_input_checksum(m, uh, iphlen, len))
+ goto badcsum;
- case M_CSUM_UDPv4|M_CSUM_DATA: {
- u_int32_t hw_csum = m->m_pkthdr.csum_data;
- UDP_CSUM_COUNTER_INCR(&udp_hwcsum_data);
- if (m->m_pkthdr.csum_flags & M_CSUM_NO_PSEUDOHDR)
- hw_csum = in_cksum_phdr(ip->ip_src.s_addr,
- ip->ip_dst.s_addr,
- htons(hw_csum + len + IPPROTO_UDP));
- if ((hw_csum ^ 0xffff) != 0)
- goto badcsum;
- break;
- }
-
- case M_CSUM_UDPv4:
- /* Checksum was okay. */
- UDP_CSUM_COUNTER_INCR(&udp_hwcsum_ok);
- break;
-
- default:
- /*
- * Need to compute it ourselves. Maybe skip checksum
- * on loopback interfaces.
- */
- if (__predict_true(!(m->m_pkthdr.rcvif->if_flags &
- IFF_LOOPBACK) ||
- udp_do_loopback_cksum)) {
- UDP_CSUM_COUNTER_INCR(&udp_swcsum);
- if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0)
- goto badcsum;
- }
- break;
- }
- }
-
/* construct source and dst sockaddrs. */
bzero(&src, sizeof(src));
src.sin_family = AF_INET;
@@ -367,7 +398,6 @@ bad:
badcsum:
m_freem(m);
- udpstat.udps_badsum++;
}
#endif
--NextPart-20041218211932-0831101
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="csum.pf.diff"
Index: dist/pf/net/pf.c
===================================================================
--- dist/pf/net/pf.c (revision 976)
+++ dist/pf/net/pf.c (working copy)
@@ -5423,7 +5423,31 @@ pf_check_proto_cksum(struct mbuf *m, int
return (1);
if (m->m_pkthdr.len < off + len)
return (1);
- switch (af) {
+#ifdef __NetBSD__
+ switch (p) {
+ case IPPROTO_TCP: {
+ struct tcphdr th; /* XXX */
+ int thlen;
+
+ m_copydata(m, off, sizeof(th), &th); /* XXX */
+ thlen = th.th_off << 2;
+ return tcp_input_checksum(af, m, &th, off,
+ thlen, len - thlen) != 0;
+ }
+
+ case IPPROTO_UDP:
+#ifdef INET
+ if (af == AF_INET) {
+ struct udphdr uh; /* XXX */
+
+ m_copydata(m, off, sizeof(uh), &uh); /* XXX */
+ return udp4_input_checksum(m, &uh, off, len) != 0;
+ }
+#endif
+ break;
+ }
+#endif /* __NetBSD__ */
+ switch (af) {
#ifdef INET
case AF_INET:
if (p == IPPROTO_ICMP) {
--NextPart-20041218211932-0831101--