From owner-svn-src-user@FreeBSD.ORG Tue Nov 20 17:04:53 2012 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 8B53E8A6; Tue, 20 Nov 2012 17:04:53 +0000 (UTC) (envelope-from andre@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 666F78FC0C; Tue, 20 Nov 2012 17:04:53 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id qAKH4rPA059672; Tue, 20 Nov 2012 17:04:53 GMT (envelope-from andre@svn.freebsd.org) Received: (from andre@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id qAKH4r8c059671; Tue, 20 Nov 2012 17:04:53 GMT (envelope-from andre@svn.freebsd.org) Message-Id: <201211201704.qAKH4r8c059671@svn.freebsd.org> From: Andre Oppermann Date: Tue, 20 Nov 2012 17:04:53 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r243344 - user/andre/tcp_workqueue/sys/kern X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 20 Nov 2012 17:04:53 -0000 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