svn commit: r300764 - head/sys/netinet
John Baldwin
jhb at FreeBSD.org
Thu May 26 18:35:38 UTC 2016
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);
More information about the svn-src-all
mailing list