Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 26 May 2016 18:35:37 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r300764 - head/sys/netinet
Message-ID:  <201605261835.u4QIZblp066704@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Thu May 26 18:35:37 2016
New Revision: 300764
URL: https://svnweb.freebsd.org/changeset/base/300764

Log:
  Don't reuse the source mbuf in tcp_respond() if it is not writable.
  
  Not all mbufs passed up from device drivers are M_WRITABLE().  In
  particular, the Chelsio T4/T5 driver uses a feature called "buffer packing"
  to receive multiple frames in a single receive buffer.  The mbufs for
  these frames all share the same external storage so are treated as
  read-only by the rest of the stack when multiple frames are in flight.
  Previously tcp_respond() would blindly overwrite read-only mbufs when
  INVARIANTS was disabled or panic with an assertion failure if INVARIANTS
  was enabled.  Note that the new case is a bit of a mix of the two other
  cases in tcp_respond().  The TCP and IP headers must be copied explicitly
  into the new mbuf instead of being inherited (similar to the m == NULL
  case), but the addresses and ports must be swapped in the reply (similar
  to the m != NULL case).
  
  Reviewed by:	glebius

Modified:
  head/sys/netinet/tcp_subr.c

Modified: head/sys/netinet/tcp_subr.c
==============================================================================
--- head/sys/netinet/tcp_subr.c	Thu May 26 18:28:10 2016	(r300763)
+++ head/sys/netinet/tcp_subr.c	Thu May 26 18:35:37 2016	(r300764)
@@ -934,16 +934,54 @@ tcp_respond(struct tcpcb *tp, void *ipge
 		}
 		bcopy((caddr_t)th, (caddr_t)nth, sizeof(struct tcphdr));
 		flags = TH_ACK;
+	} else if (!M_WRITABLE(m)) {
+		struct mbuf *n;
+
+		/* Can't reuse 'm', allocate a new mbuf. */
+		n = m_gethdr(M_NOWAIT, MT_DATA);
+		if (n == NULL) {
+			m_freem(m);
+			return;
+		}
+
+		if (!m_dup_pkthdr(n, m, M_NOWAIT)) {
+			m_freem(m);
+			m_freem(n);
+			return;
+		}
+
+		n->m_data += max_linkhdr;
+		/* m_len is set later */
+#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
+#ifdef INET6
+		if (isipv6) {
+			bcopy((caddr_t)ip6, mtod(n, caddr_t),
+			      sizeof(struct ip6_hdr));
+			ip6 = mtod(n, struct ip6_hdr *);
+			xchg(ip6->ip6_dst, ip6->ip6_src, struct in6_addr);
+			nth = (struct tcphdr *)(ip6 + 1);
+		} else
+#endif /* INET6 */
+		{
+			bcopy((caddr_t)ip, mtod(n, caddr_t), sizeof(struct ip));
+			ip = mtod(n, struct ip *);
+			xchg(ip->ip_dst.s_addr, ip->ip_src.s_addr, uint32_t);
+			nth = (struct tcphdr *)(ip + 1);
+		}
+		bcopy((caddr_t)th, (caddr_t)nth, sizeof(struct tcphdr));
+		xchg(nth->th_dport, nth->th_sport, uint16_t);
+		th = nth;
+		m_freem(m);
+		m = n;
 	} else {
 		/*
 		 *  reuse the mbuf. 
-		 * XXX MRT We inherrit the FIB, which is lucky.
+		 * XXX MRT We inherit the FIB, which is lucky.
 		 */
 		m_freem(m->m_next);
 		m->m_next = NULL;
 		m->m_data = (caddr_t)ipgen;
 		/* m_len is set later */
-#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
 #ifdef INET6
 		if (isipv6) {
 			xchg(ip6->ip6_dst, ip6->ip6_src, struct in6_addr);



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