Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 20 Nov 2012 17:04:53 +0000 (UTC)
From:      Andre Oppermann <andre@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r243344 - user/andre/tcp_workqueue/sys/kern
Message-ID:  <201211201704.qAKH4r8c059671@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: andre
Date: Tue Nov 20 17:04:52 2012
New Revision: 243344
URL: http://svnweb.freebsd.org/changeset/base/243344

Log:
  Add CSUM flags checking to m_sanity() to test for flags and parameter
  integrity.
  
  Advanced protocol specific tests for header length validation are not
  yet complete and commented out.

Modified:
  user/andre/tcp_workqueue/sys/kern/uipc_mbuf.c

Modified: user/andre/tcp_workqueue/sys/kern/uipc_mbuf.c
==============================================================================
--- user/andre/tcp_workqueue/sys/kern/uipc_mbuf.c	Tue Nov 20 17:02:33 2012	(r243343)
+++ user/andre/tcp_workqueue/sys/kern/uipc_mbuf.c	Tue Nov 20 17:04:52 2012	(r243344)
@@ -420,6 +420,220 @@ m_sanity(struct mbuf *m0, int sanitize)
 		else
 			M_SANITY_ACTION("m_pkthdr.len != mbuf chain length");
 	}
+
+	/*
+	 * Verify the integrity of the checksum and offload parameters.
+	 */
+	if (m->m_pkthdr.csum_flags) {
+		int cflags = m->m_pkthdr.csum_flags;
+
+		/* Mixing of in and outboud flags is not permitted. */
+		if (MCSUM_INFLAGS(m) && MCSUM_OUTFLAGS(m))
+			M_SANITY_ACTION("in and outbound csum flags present");
+
+		/* The inbound checksum flags must be consistent. */
+		if ((cflags & (CSUM_L3_CALC|CSUM_L3_VALID)) == CSUM_L3_VALID)
+			M_SANITY_ACTION("CSUM_L3_VALID but not CSUM_L3_CALC");
+		if ((cflags & (CSUM_L4_CALC|CSUM_L4_VALID)) == CSUM_L4_VALID)
+			M_SANITY_ACTION("CSUM_L4_VALID but not CSUM_L4_CALC");
+
+		/*
+		 * Validate the l[2-4]hlen fields against first mbuf length.
+		 * The headers must be present and contiguous in the first
+		 * mbuf when offload capabilities are used.
+		 */
+		if (MCSUM_OUTFLAGS(m)) {
+			/*
+			 * When seg/fragmentation offload is specified the
+			 * segment size of the resulting packets is required.
+			 */
+			if (cflags & (CSUM_IP_UFO|CSUM_IP_TSO|CSUM_IP_SCO|
+			    CSUM_IP6_UFO|CSUM_IP6_TSO|CSUM_IP6_SCO)) {
+				if (m->m_pkthdr.tso_segsz == 0)
+					M_SANITY_ACTION("unspecified tso_segsz");
+				if (m->m_pkthdr.tso_segsz >= m->m_pkthdr.len)
+					M_SANITY_ACTION("tso_segsz >= pkthdr.len");
+			}
+			/* The headers must be in the first mbuf. */
+			if (m->m_len < m->m_pkthdr.csum_l2hlen)
+				M_SANITY_ACTION("csum_l2hlen > m_len");
+			if (m->m_len < m->m_pkthdr.csum_l2hlen +
+			    m->m_pkthdr.csum_l3hlen)
+				M_SANITY_ACTION("csum_l{2+3}hlen > m_len");
+			if (m->m_len < m->m_pkthdr.csum_l2hlen +
+			    m->m_pkthdr.csum_l3hlen + m->m_pkthdr.csum_l3hlen)
+				M_SANITY_ACTION("csum_l{2+3+4}hlen > m_len");
+		}
+
+		/* Layer 4 capabilities depend on lower layers. */
+		if (cflags & (CSUM_IP_UFO|CSUM_IP_TSO|CSUM_IP_SCO)) {
+			if (!(cflags & CSUM_IP))
+				M_SANITY_ACTION("IP offload w/o IP hdr csum");
+			if ((cflags & (CSUM_IP_UFO|CSUM_IP_UDP)) !=
+			    (CSUM_IP_UFO|CSUM_IP_UDP))
+				M_SANITY_ACTION("UDP frag offload w/o UDP csum");
+			if ((cflags & (CSUM_IP_TSO|CSUM_IP_TCP)) !=
+			    (CSUM_IP_TSO|CSUM_IP_TCP))
+				M_SANITY_ACTION("TCP seg offload w/o TCP csum");
+			if ((cflags & (CSUM_IP_SCO|CSUM_IP_SCTP)) !=
+			    (CSUM_IP_SCO|CSUM_IP_SCTP))
+				M_SANITY_ACTION("SCTP chunk offl w/o SCTP csum");
+		}
+		if (cflags & (CSUM_IP6_UFO|CSUM_IP6_TSO|CSUM_IP6_SCO)) {
+			if ((cflags & (CSUM_IP6_UFO|CSUM_IP6_UDP)) !=
+			    (CSUM_IP6_UFO|CSUM_IP6_UDP))
+				M_SANITY_ACTION("UDP frag offload w/o UDP csum");
+			if ((cflags & (CSUM_IP6_TSO|CSUM_IP6_TCP)) !=
+			    (CSUM_IP6_TSO|CSUM_IP6_TCP))
+				M_SANITY_ACTION("TCP seg offload w/o TCP csum");
+			if ((cflags & (CSUM_IP6_SCO|CSUM_IP6_SCTP)) !=
+			    (CSUM_IP_SCO|CSUM_IP6_SCTP))
+				M_SANITY_ACTION("SCTP chunk offl w/o SCTP csum");
+		}
+		/* IP and IP6 flags may not be combined. */
+		if ((cflags & (CSUM_IP|CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP)) &&
+		    (cflags & (CSUM_IP6|CSUM_IP6_UDP|CSUM_IP6_TCP|CSUM_IP6_SCTP)))
+			M_SANITY_ACTION("IPv4 and IPv6 csum flags present");
+
+#ifdef notyet
+		/*
+		 * For now offload capabilities are only supported
+		 * on ethernet NICs so we can assume an ethernet header.
+		 */
+		if (m->m_pkthdr.csum_l2hlen > 0) {
+			struct ether_vlan_header *evh;
+			int l2hlen = 0;
+
+			evh = mtodo(m, l2hlen);
+			l3proto = ntonh(evh->evl_encap_proto);
+
+			switch (l3proto) {
+			case ETHERTYPE_IP:
+			case ETHERTYPE_IPV6:
+				l2hlen += sizeof(struct ether_header);
+				break;
+			case ETHERTYPE_VLAN:
+				/* XXXAO: VLAN header stacking. */
+				l2hlen += sizeof(struct ether_vlan_header);
+				l3proto = ntohs(evh->evl_proto);
+				break;
+			default:
+				break;
+			}
+			if (l2hlen != m->m_pkthdr.csum_l2hlen)
+				M_SANITY_ACTION("l2hlen != csum_l2hlen");
+			if (l3proto != ETHERTYPE_IP &&
+			    l3proto != ETHERTYPE_IPV6)
+				M_SANITY_ACTION("unsupported l3 protocol");
+		}
+
+		/*
+		 * Check layer 3 headers and length.
+		 */
+		if (m->m_pkthdr.csum_l3hlen > 0) {
+			int l3hlen = 0;
+
+			switch (cflags & (CSUM_IP|CSUM_IP6)) {
+			case CSUM_IP: {
+				struct ip *ip;
+
+				ip = mtodo(m, l2hlen);
+				if (ip->ip_v != IPVERSION)
+					M_SANITY_ACTION("");
+				if (ip->ip_hl << 2 != sizeof(struct ip))
+					M_SANITY_ACTION("");
+				l3hlen += (ip->ip_hl << 2);
+
+				if (m->m_pkthdr.len != ntohs(ip->ip_len) +
+				    m->m_pkthdr.csum_l2hlen)
+					M_SANITY_ACTION("");
+				l4proto = ip->ip_p;
+			    }
+				break;
+			case CSUM_IP6: {
+				struct ip6_hdr *ip6;
+
+				if ((ip6->ip6_vfc & IPV6_VERSION_MASK) !=
+				    IPV6_VERSION)
+					M_SANITY_ACTION("");
+				do {
+					ip6 = mtodo(m, l2hlen);
+					l4proto = ip6->ip6_nxt;
+				} while (extension headers);
+
+				if (m->m_pkthdr.len != ntohs() +
+				    m->m_pkthdr.csum_l2hlen)
+					M_SANITY_ACTION("");
+			    }
+				break;
+			default:
+				break;
+			}
+			if (l3hlen != m->m_pkthdr.csum_l3hlen)
+				M_SANITY_ACTION("");
+			if (l4proto != IPPROTO_UDP &&
+			    l4proto != IPPROTO_TCP &&
+			    l4proto != IPPROTO_SCTP)
+				M_SANITY_ACTION("");
+		}
+
+		/*
+		 * Check layer 4 headers and length.
+		 */
+		if (m->m_pkthdr.csum_l4hlen > 0) {
+
+			switch (cflags & (CSUM_IP_UFO|CSUM_IP6_UFO|
+					  CSUM_IP_TSO|CSUM_IP6_TSO|
+					  CSUM_IP_SCTP|CSUM_IP6_SCTP)) {
+			case CSUM_IP_UFO:
+			case CSUM_IP6_UFO: {
+				struct udphdr *udp;
+
+				udp = mtodo(m, l2hlen + l3hlen);
+				/* Check pseudo csum. */
+				sum = ip_pseudo();
+				if (sum != th->th_sum)
+					M_SANITY_ACTION();
+
+				l4hlen = sizeof(struct udphdr);
+			    }
+				break;
+			case CSUM_IP_TSO:
+			case CSUM_IP6_TSO: {
+				struct tcphdr *th;
+
+				th = mtodo(m, l2hlen + l3hlen);
+				/* Check pseudo csum. */
+				sum = ip_pseudo();
+				if (sum != th->th_sum)
+					M_SANITY_ACTION();
+
+				l4hlen = th->th_off << 2;
+			    }
+				break;
+			case CSUM_IP_SCTP:
+			case CSUM_IP6_SCTP: {
+				struct sctphdr *sctp;
+				struct sctp_chunkhdr *sctp_ch;
+
+				sctp = mtodo(m, l2hlen + l3hlen);
+				/* Thankfully SCTP doesn't have a pseudo hdr. */
+				l4hlen = sizeof(struct sctphdr);
+			    }
+				break;
+			default:
+				M_SANITY_ACTION();
+				break;
+			}
+			if (l4hlen != m->m_pkthdr.csum_l4hlen)
+				M_SANITY_ACTION("");
+
+		} else if (cflags & (CSUM_IP_UFO|CSUM_IP6_UFO|
+				     CSUM_IP_TSO|CSUM_IP6_TSO|
+				     CSUM_IP_SCTP|CSUM_IP6_SCTP))
+			M_SANITY_ACTION("l4 offload w/o l4hlen");
+#endif
+	}
 	return 1;
 
 #undef	M_SANITY_ACTION



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201211201704.qAKH4r8c059671>