PERFORCE change 143124 for review
Sam Leffler
sam at FreeBSD.org
Sun Jun 8 18:14:24 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=143124
Change 143124 by sam at sam_ebb on 2008/06/08 18:14:11
handle max_linkhdr large enough to force overflow of an
inline mbuf when forming the tcpip hdr
Affected files ...
.. //depot/projects/vap/sys/netinet/tcp_output.c#9 edit
.. //depot/projects/vap/sys/netinet/tcp_subr.c#10 edit
.. //depot/projects/vap/sys/netinet/tcp_syncache.c#10 edit
.. //depot/projects/vap/sys/netinet/tcp_timewait.c#4 edit
.. //depot/projects/vap/sys/sys/mbuf.h#14 edit
Differences ...
==== //depot/projects/vap/sys/netinet/tcp_output.c#9 (text+ko) ====
@@ -735,14 +735,10 @@
}
}
-/*#ifdef DIAGNOSTIC*/
-#ifdef INET6
+#ifdef DIAGNOSTIC
if (max_linkhdr + hdrlen > MCLBYTES)
-#else
- if (max_linkhdr + hdrlen > MHLEN)
+ panic("tcphdr too big");
#endif
- panic("tcphdr too big");
-/*#endif*/
/*
* Grab a header mbuf, attaching a copy of data to
@@ -751,7 +747,7 @@
*/
if (len) {
struct mbuf *mb;
- u_int moff;
+ u_int moff, trailingspace;
if ((tp->t_flags & TF_FORCEDATA) && len == 1)
tcpstat.tcps_sndprobe++;
@@ -775,23 +771,18 @@
m->m_len += hdrlen;
m->m_data -= hdrlen;
#else
- MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (hdrlen + max_linkhdr <= MHLEN) {
+ m = m_gethdr(M_DONTWAIT, MT_DATA);
+ trailingspace = MHLEN - (hdrlen + max_linkhdr);
+ } else {
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ trailingspace = MCLBYTES - (hdrlen + max_linkhdr);
+ }
if (m == NULL) {
SOCKBUF_UNLOCK(&so->so_snd);
error = ENOBUFS;
goto out;
}
-#ifdef INET6
- if (MHLEN < hdrlen + max_linkhdr) {
- MCLGET(m, M_DONTWAIT);
- if ((m->m_flags & M_EXT) == 0) {
- SOCKBUF_UNLOCK(&so->so_snd);
- m_freem(m);
- error = ENOBUFS;
- goto out;
- }
- }
-#endif
m->m_data += max_linkhdr;
m->m_len = hdrlen;
@@ -801,7 +792,7 @@
*/
mb = sbsndptr(&so->so_snd, off, len, &moff);
- if (len <= MHLEN - hdrlen - max_linkhdr) {
+ if (len <= trailingspace) {
m_copydata(mb, moff, (int)len,
mtod(m, caddr_t) + hdrlen);
m->m_len += len;
@@ -834,7 +825,7 @@
tcpstat.tcps_sndurg++;
else
tcpstat.tcps_sndwinup++;
-
+#if 0
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
error = ENOBUFS;
@@ -848,6 +839,21 @@
#endif
m->m_data += max_linkhdr;
m->m_len = hdrlen;
+#else
+ if (hdrlen + max_linkhdr <= MHLEN)
+ m = m_gethdr(M_DONTWAIT, MT_DATA);
+ else
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL) {
+ error = ENOBUFS;
+ goto out;
+ }
+ if (hdrlen + max_linkhdr <= MHLEN)
+ MH_ALIGN(m, hdrlen);
+ else
+ MCL_ALIGN(m, hdrlen);
+ m->m_len = hdrlen;
+#endif
}
SOCKBUF_UNLOCK_ASSERT(&so->so_snd);
m->m_pkthdr.rcvif = (struct ifnet *)0;
==== //depot/projects/vap/sys/netinet/tcp_subr.c#10 (text+ko) ====
@@ -291,7 +291,7 @@
#endif /* INET6 */
if (max_protohdr < TCP_MINPROTOHDR)
max_protohdr = TCP_MINPROTOHDR;
- if (max_linkhdr + TCP_MINPROTOHDR > MHLEN)
+ if (max_linkhdr + TCP_MINPROTOHDR > MCLBYTES)
panic("tcp_init");
#undef TCP_MINPROTOHDR
/*
@@ -412,7 +412,7 @@
tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
tcp_seq ack, tcp_seq seq, int flags)
{
- int tlen;
+ int hdrlen, tlen;
int win = 0;
struct ip *ip;
struct tcphdr *nth;
@@ -446,11 +446,28 @@
}
}
if (m == NULL) {
+#if 0
m = m_gethdr(M_DONTWAIT, MT_DATA);
if (m == NULL)
return;
tlen = 0;
m->m_data += max_linkhdr;
+#else
+#ifdef INET6
+ if (isipv6)
+ hdrlen = sizeof (struct ip6_hdr) +
+ sizeof (struct tcphdr);
+ else
+#endif
+ hdrlen = sizeof (struct tcpiphdr);
+ if (hdrlen + max_linkhdr <= MHLEN)
+ m = m_gethdr(M_DONTWAIT, MT_DATA);
+ else
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL)
+ return;
+ m->m_data += max_linkhdr;
+#endif
#ifdef INET6
if (isipv6) {
bcopy((caddr_t)ip6, mtod(m, caddr_t),
==== //depot/projects/vap/sys/netinet/tcp_syncache.c#10 (text+ko) ====
@@ -1285,12 +1285,19 @@
if (sc->sc_peer_mss)
mssopt = max( min(sc->sc_peer_mss, mssopt), tcp_minmss);
+#if 0
/* XXX: Assume that the entire packet will fit in a header mbuf. */
KASSERT(max_linkhdr + tlen + TCP_MAXOLEN <= MHLEN,
("syncache: mbuf too small"));
/* Create the IP+TCP header from scratch. */
m = m_gethdr(M_DONTWAIT, MT_DATA);
+#else
+ if (max_linkhdr + tlen + TCP_MAXOLEN <= MHLEN)
+ m = m_gethdr(M_DONTWAIT, MT_DATA);
+ else
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+#endif
if (m == NULL)
return (ENOBUFS);
#ifdef MAC
==== //depot/projects/vap/sys/netinet/tcp_timewait.c#4 (text+ko) ====
@@ -534,7 +534,20 @@
INP_WLOCK_ASSERT(inp);
+#ifdef INET6
+ if (isipv6)
+ hdrlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
+ else
+#endif
+ hdrlen = sizeof(struct tcpiphdr);
+#if 0
m = m_gethdr(M_DONTWAIT, MT_DATA);
+#else
+ if (max_linkhdr + hdrlen + TCP_MAXOLEN <= MHLEN)
+ m = m_gethdr(M_DONTWAIT, MT_DATA);
+ else
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+#endif
if (m == NULL)
return (ENOBUFS);
m->m_data += max_linkhdr;
@@ -545,14 +558,12 @@
#ifdef INET6
if (isipv6) {
- hdrlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
ip6 = mtod(m, struct ip6_hdr *);
th = (struct tcphdr *)(ip6 + 1);
tcpip_fillheaders(inp, ip6, th);
} else
#endif
{
- hdrlen = sizeof(struct tcpiphdr);
ip = mtod(m, struct ip *);
th = (struct tcphdr *)(ip + 1);
tcpip_fillheaders(inp, ip, th);
@@ -572,9 +583,9 @@
m->m_len = hdrlen + optlen;
m->m_pkthdr.len = m->m_len;
-
+#if 0
KASSERT(max_linkhdr + m->m_len <= MHLEN, ("tcptw: mbuf too small"));
-
+#endif
th->th_seq = htonl(tw->snd_nxt);
th->th_ack = htonl(tw->rcv_nxt);
th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
==== //depot/projects/vap/sys/sys/mbuf.h#14 (text+ko) ====
@@ -677,6 +677,17 @@
} while (0)
/*
+ * As above, for mbufs allocated with m_getcl.
+ */
+#define MCL_ALIGN(m, len) do { \
+ KASSERT((m)->m_flags & M_PKTHDR && ((m)->m_flags & M_EXT), \
+ ("%s: MCL_ALIGN not PKTHDR cluster", __func__)); \
+ KASSERT((m)->m_data == (m)->m_ext.ext_buf, \
+ ("%s: MCL_ALIGN not a virgin mbuf", __func__)); \
+ (m)->m_data += (MCLBYTES - (len)) & ~(sizeof(long) - 1); \
+} while (0)
+
+/*
* Compute the amount of space available before the current start of data in
* an mbuf.
*
More information about the p4-projects
mailing list