xref: /freebsd/sys/kern/uipc_sockbuf.c (revision 82334850ea451f7f6903be20e4836118e6a77460)
19454b2d8SWarner Losh /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
4df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1988, 1990, 1993
5df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
6df8bae1dSRodney W. Grimes  *
7df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
8df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
9df8bae1dSRodney W. Grimes  * are met:
10df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
12df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
13df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
14df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
1569a28758SEd Maste  * 3. Neither the name of the University nor the names of its contributors
16df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
17df8bae1dSRodney W. Grimes  *    without specific prior written permission.
18df8bae1dSRodney W. Grimes  *
19df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
30df8bae1dSRodney W. Grimes  *
31df8bae1dSRodney W. Grimes  *	@(#)uipc_socket2.c	8.1 (Berkeley) 6/10/93
32df8bae1dSRodney W. Grimes  */
33df8bae1dSRodney W. Grimes 
34677b542eSDavid E. O'Brien #include <sys/cdefs.h>
35677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
36677b542eSDavid E. O'Brien 
375b86eac4SJesper Skriver #include "opt_param.h"
38335654d7SRobert Watson 
39df8bae1dSRodney W. Grimes #include <sys/param.h>
40960ed29cSSeigo Tanimura #include <sys/aio.h> /* for aio_swake proto */
41ff5c09daSGarrett Wollman #include <sys/kernel.h>
42fb919e4dSMark Murray #include <sys/lock.h>
438ec07310SGleb Smirnoff #include <sys/malloc.h>
44df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
45960ed29cSSeigo Tanimura #include <sys/mutex.h>
46fb919e4dSMark Murray #include <sys/proc.h>
47df8bae1dSRodney W. Grimes #include <sys/protosw.h>
482f9a2132SBrian Feldman #include <sys/resourcevar.h>
49960ed29cSSeigo Tanimura #include <sys/signalvar.h>
50df8bae1dSRodney W. Grimes #include <sys/socket.h>
51df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
527abab911SRobert Watson #include <sys/sx.h>
53ff5c09daSGarrett Wollman #include <sys/sysctl.h>
5426f9a767SRodney W. Grimes 
55f14cce87SRobert Watson /*
56f14cce87SRobert Watson  * Function pointer set by the AIO routines so that the socket buffer code
57f14cce87SRobert Watson  * can call back into the AIO module if it is loaded.
58f14cce87SRobert Watson  */
5921d56e9cSAlfred Perlstein void	(*aio_swake)(struct socket *, struct sockbuf *);
6021d56e9cSAlfred Perlstein 
61df8bae1dSRodney W. Grimes /*
62f14cce87SRobert Watson  * Primitive routines for operating on socket buffers
63df8bae1dSRodney W. Grimes  */
64df8bae1dSRodney W. Grimes 
6579cb7eb4SDavid Greenman u_long	sb_max = SB_MAX;
6658d14daeSMohan Srinivasan u_long sb_max_adj =
67b233773bSBjoern A. Zeeb        (quad_t)SB_MAX * MCLBYTES / (MSIZE + MCLBYTES); /* adjusted sb_max */
68df8bae1dSRodney W. Grimes 
694b29bc4fSGarrett Wollman static	u_long sb_efficiency = 8;	/* parameter for sbreserve() */
704b29bc4fSGarrett Wollman 
711d2df300SGleb Smirnoff static struct mbuf	*sbcut_internal(struct sockbuf *sb, int len);
72050ac265SRobert Watson static void	sbflush_internal(struct sockbuf *sb);
73eaa6dfbcSRobert Watson 
74df8bae1dSRodney W. Grimes /*
75829fae90SGleb Smirnoff  * Our own version of m_clrprotoflags(), that can preserve M_NOTREADY.
76829fae90SGleb Smirnoff  */
77829fae90SGleb Smirnoff static void
78829fae90SGleb Smirnoff sbm_clrprotoflags(struct mbuf *m, int flags)
79829fae90SGleb Smirnoff {
80829fae90SGleb Smirnoff 	int mask;
81829fae90SGleb Smirnoff 
82829fae90SGleb Smirnoff 	mask = ~M_PROTOFLAGS;
83829fae90SGleb Smirnoff 	if (flags & PRUS_NOTREADY)
84829fae90SGleb Smirnoff 		mask |= M_NOTREADY;
85829fae90SGleb Smirnoff 	while (m) {
86829fae90SGleb Smirnoff 		m->m_flags &= mask;
87829fae90SGleb Smirnoff 		m = m->m_next;
88829fae90SGleb Smirnoff 	}
89829fae90SGleb Smirnoff }
90829fae90SGleb Smirnoff 
91829fae90SGleb Smirnoff /*
92*82334850SJohn Baldwin  * Mark ready "count" units of I/O starting with "m".  Most mbufs
93*82334850SJohn Baldwin  * count as a single unit of I/O except for EXT_PGS-backed mbufs which
94*82334850SJohn Baldwin  * can be backed by multiple pages.
950f9d0a73SGleb Smirnoff  */
960f9d0a73SGleb Smirnoff int
97*82334850SJohn Baldwin sbready(struct sockbuf *sb, struct mbuf *m0, int count)
980f9d0a73SGleb Smirnoff {
99*82334850SJohn Baldwin 	struct mbuf *m;
1000f9d0a73SGleb Smirnoff 	u_int blocker;
1010f9d0a73SGleb Smirnoff 
1020f9d0a73SGleb Smirnoff 	SOCKBUF_LOCK_ASSERT(sb);
1030f9d0a73SGleb Smirnoff 	KASSERT(sb->sb_fnrdy != NULL, ("%s: sb %p NULL fnrdy", __func__, sb));
104*82334850SJohn Baldwin 	KASSERT(count > 0, ("%s: invalid count %d", __func__, count));
1050f9d0a73SGleb Smirnoff 
106*82334850SJohn Baldwin 	m = m0;
1070f9d0a73SGleb Smirnoff 	blocker = (sb->sb_fnrdy == m) ? M_BLOCKED : 0;
1080f9d0a73SGleb Smirnoff 
109*82334850SJohn Baldwin 	while (count > 0) {
1100f9d0a73SGleb Smirnoff 		KASSERT(m->m_flags & M_NOTREADY,
1110f9d0a73SGleb Smirnoff 		    ("%s: m %p !M_NOTREADY", __func__, m));
112*82334850SJohn Baldwin 		if ((m->m_flags & M_EXT) != 0 &&
113*82334850SJohn Baldwin 		    m->m_ext.ext_type == EXT_PGS) {
114*82334850SJohn Baldwin 			if (count < m->m_ext.ext_pgs->nrdy) {
115*82334850SJohn Baldwin 				m->m_ext.ext_pgs->nrdy -= count;
116*82334850SJohn Baldwin 				count = 0;
117*82334850SJohn Baldwin 				break;
118*82334850SJohn Baldwin 			}
119*82334850SJohn Baldwin 			count -= m->m_ext.ext_pgs->nrdy;
120*82334850SJohn Baldwin 			m->m_ext.ext_pgs->nrdy = 0;
121*82334850SJohn Baldwin 		} else
122*82334850SJohn Baldwin 			count--;
123*82334850SJohn Baldwin 
1240f9d0a73SGleb Smirnoff 		m->m_flags &= ~(M_NOTREADY | blocker);
1250f9d0a73SGleb Smirnoff 		if (blocker)
1260f9d0a73SGleb Smirnoff 			sb->sb_acc += m->m_len;
127*82334850SJohn Baldwin 		m = m->m_next;
1280f9d0a73SGleb Smirnoff 	}
1290f9d0a73SGleb Smirnoff 
130*82334850SJohn Baldwin 	/*
131*82334850SJohn Baldwin 	 * If the first mbuf is still not fully ready because only
132*82334850SJohn Baldwin 	 * some of its backing pages were readied, no further progress
133*82334850SJohn Baldwin 	 * can be made.
134*82334850SJohn Baldwin 	 */
135*82334850SJohn Baldwin 	if (m0 == m) {
136*82334850SJohn Baldwin 		MPASS(m->m_flags & M_NOTREADY);
1370f9d0a73SGleb Smirnoff 		return (EINPROGRESS);
138*82334850SJohn Baldwin 	}
139*82334850SJohn Baldwin 
140*82334850SJohn Baldwin 	if (!blocker) {
141*82334850SJohn Baldwin 		return (EINPROGRESS);
142*82334850SJohn Baldwin 	}
1430f9d0a73SGleb Smirnoff 
1440f9d0a73SGleb Smirnoff 	/* This one was blocking all the queue. */
1450f9d0a73SGleb Smirnoff 	for (; m && (m->m_flags & M_NOTREADY) == 0; m = m->m_next) {
1460f9d0a73SGleb Smirnoff 		KASSERT(m->m_flags & M_BLOCKED,
1470f9d0a73SGleb Smirnoff 		    ("%s: m %p !M_BLOCKED", __func__, m));
1480f9d0a73SGleb Smirnoff 		m->m_flags &= ~M_BLOCKED;
1490f9d0a73SGleb Smirnoff 		sb->sb_acc += m->m_len;
1500f9d0a73SGleb Smirnoff 	}
1510f9d0a73SGleb Smirnoff 
1520f9d0a73SGleb Smirnoff 	sb->sb_fnrdy = m;
1530f9d0a73SGleb Smirnoff 
1540f9d0a73SGleb Smirnoff 	return (0);
1550f9d0a73SGleb Smirnoff }
1560f9d0a73SGleb Smirnoff 
1570f9d0a73SGleb Smirnoff /*
1588967b220SGleb Smirnoff  * Adjust sockbuf state reflecting allocation of m.
1598967b220SGleb Smirnoff  */
1608967b220SGleb Smirnoff void
1618967b220SGleb Smirnoff sballoc(struct sockbuf *sb, struct mbuf *m)
1628967b220SGleb Smirnoff {
1638967b220SGleb Smirnoff 
1648967b220SGleb Smirnoff 	SOCKBUF_LOCK_ASSERT(sb);
1658967b220SGleb Smirnoff 
1660f9d0a73SGleb Smirnoff 	sb->sb_ccc += m->m_len;
1670f9d0a73SGleb Smirnoff 
1680f9d0a73SGleb Smirnoff 	if (sb->sb_fnrdy == NULL) {
1690f9d0a73SGleb Smirnoff 		if (m->m_flags & M_NOTREADY)
1700f9d0a73SGleb Smirnoff 			sb->sb_fnrdy = m;
1710f9d0a73SGleb Smirnoff 		else
1720f9d0a73SGleb Smirnoff 			sb->sb_acc += m->m_len;
1730f9d0a73SGleb Smirnoff 	} else
1740f9d0a73SGleb Smirnoff 		m->m_flags |= M_BLOCKED;
1758967b220SGleb Smirnoff 
1768967b220SGleb Smirnoff 	if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
1778967b220SGleb Smirnoff 		sb->sb_ctl += m->m_len;
1788967b220SGleb Smirnoff 
1798967b220SGleb Smirnoff 	sb->sb_mbcnt += MSIZE;
1808967b220SGleb Smirnoff 	sb->sb_mcnt += 1;
1818967b220SGleb Smirnoff 
1828967b220SGleb Smirnoff 	if (m->m_flags & M_EXT) {
1838967b220SGleb Smirnoff 		sb->sb_mbcnt += m->m_ext.ext_size;
1848967b220SGleb Smirnoff 		sb->sb_ccnt += 1;
1858967b220SGleb Smirnoff 	}
1868967b220SGleb Smirnoff }
1878967b220SGleb Smirnoff 
1888967b220SGleb Smirnoff /*
1898967b220SGleb Smirnoff  * Adjust sockbuf state reflecting freeing of m.
1908967b220SGleb Smirnoff  */
1918967b220SGleb Smirnoff void
1928967b220SGleb Smirnoff sbfree(struct sockbuf *sb, struct mbuf *m)
1938967b220SGleb Smirnoff {
1948967b220SGleb Smirnoff 
1958967b220SGleb Smirnoff #if 0	/* XXX: not yet: soclose() call path comes here w/o lock. */
1968967b220SGleb Smirnoff 	SOCKBUF_LOCK_ASSERT(sb);
1978967b220SGleb Smirnoff #endif
1988967b220SGleb Smirnoff 
1990f9d0a73SGleb Smirnoff 	sb->sb_ccc -= m->m_len;
2000f9d0a73SGleb Smirnoff 
2010f9d0a73SGleb Smirnoff 	if (!(m->m_flags & M_NOTAVAIL))
2020f9d0a73SGleb Smirnoff 		sb->sb_acc -= m->m_len;
2030f9d0a73SGleb Smirnoff 
2040f9d0a73SGleb Smirnoff 	if (m == sb->sb_fnrdy) {
2050f9d0a73SGleb Smirnoff 		struct mbuf *n;
2060f9d0a73SGleb Smirnoff 
2070f9d0a73SGleb Smirnoff 		KASSERT(m->m_flags & M_NOTREADY,
2080f9d0a73SGleb Smirnoff 		    ("%s: m %p !M_NOTREADY", __func__, m));
2090f9d0a73SGleb Smirnoff 
2100f9d0a73SGleb Smirnoff 		n = m->m_next;
2110f9d0a73SGleb Smirnoff 		while (n != NULL && !(n->m_flags & M_NOTREADY)) {
2120f9d0a73SGleb Smirnoff 			n->m_flags &= ~M_BLOCKED;
2130f9d0a73SGleb Smirnoff 			sb->sb_acc += n->m_len;
2140f9d0a73SGleb Smirnoff 			n = n->m_next;
2150f9d0a73SGleb Smirnoff 		}
2160f9d0a73SGleb Smirnoff 		sb->sb_fnrdy = n;
2170f9d0a73SGleb Smirnoff 	}
2188967b220SGleb Smirnoff 
2198967b220SGleb Smirnoff 	if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
2208967b220SGleb Smirnoff 		sb->sb_ctl -= m->m_len;
2218967b220SGleb Smirnoff 
2228967b220SGleb Smirnoff 	sb->sb_mbcnt -= MSIZE;
2238967b220SGleb Smirnoff 	sb->sb_mcnt -= 1;
2248967b220SGleb Smirnoff 	if (m->m_flags & M_EXT) {
2258967b220SGleb Smirnoff 		sb->sb_mbcnt -= m->m_ext.ext_size;
2268967b220SGleb Smirnoff 		sb->sb_ccnt -= 1;
2278967b220SGleb Smirnoff 	}
2288967b220SGleb Smirnoff 
2298967b220SGleb Smirnoff 	if (sb->sb_sndptr == m) {
2308967b220SGleb Smirnoff 		sb->sb_sndptr = NULL;
2318967b220SGleb Smirnoff 		sb->sb_sndptroff = 0;
2328967b220SGleb Smirnoff 	}
2338967b220SGleb Smirnoff 	if (sb->sb_sndptroff != 0)
2348967b220SGleb Smirnoff 		sb->sb_sndptroff -= m->m_len;
2358967b220SGleb Smirnoff }
2368967b220SGleb Smirnoff 
2378967b220SGleb Smirnoff /*
238050ac265SRobert Watson  * Socantsendmore indicates that no more data will be sent on the socket; it
239050ac265SRobert Watson  * would normally be applied to a socket when the user informs the system
240050ac265SRobert Watson  * that no more data is to be sent, by the protocol code (in case
241050ac265SRobert Watson  * PRU_SHUTDOWN).  Socantrcvmore indicates that no more data will be
242050ac265SRobert Watson  * received, and will normally be applied to the socket by a protocol when it
243050ac265SRobert Watson  * detects that the peer will send no more data.  Data queued for reading in
244050ac265SRobert Watson  * the socket may yet be read.
245df8bae1dSRodney W. Grimes  */
246a34b7046SRobert Watson void
247050ac265SRobert Watson socantsendmore_locked(struct socket *so)
248a34b7046SRobert Watson {
249a34b7046SRobert Watson 
250a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(&so->so_snd);
251a34b7046SRobert Watson 
252a34b7046SRobert Watson 	so->so_snd.sb_state |= SBS_CANTSENDMORE;
253a34b7046SRobert Watson 	sowwakeup_locked(so);
254a34b7046SRobert Watson 	mtx_assert(SOCKBUF_MTX(&so->so_snd), MA_NOTOWNED);
255a34b7046SRobert Watson }
256df8bae1dSRodney W. Grimes 
25726f9a767SRodney W. Grimes void
258050ac265SRobert Watson socantsendmore(struct socket *so)
259df8bae1dSRodney W. Grimes {
260df8bae1dSRodney W. Grimes 
261a34b7046SRobert Watson 	SOCKBUF_LOCK(&so->so_snd);
262a34b7046SRobert Watson 	socantsendmore_locked(so);
263a34b7046SRobert Watson 	mtx_assert(SOCKBUF_MTX(&so->so_snd), MA_NOTOWNED);
264a34b7046SRobert Watson }
265a34b7046SRobert Watson 
266a34b7046SRobert Watson void
267050ac265SRobert Watson socantrcvmore_locked(struct socket *so)
268a34b7046SRobert Watson {
269a34b7046SRobert Watson 
270a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(&so->so_rcv);
271a34b7046SRobert Watson 
272a34b7046SRobert Watson 	so->so_rcv.sb_state |= SBS_CANTRCVMORE;
273a34b7046SRobert Watson 	sorwakeup_locked(so);
274a34b7046SRobert Watson 	mtx_assert(SOCKBUF_MTX(&so->so_rcv), MA_NOTOWNED);
275df8bae1dSRodney W. Grimes }
276df8bae1dSRodney W. Grimes 
27726f9a767SRodney W. Grimes void
278050ac265SRobert Watson socantrcvmore(struct socket *so)
279df8bae1dSRodney W. Grimes {
280df8bae1dSRodney W. Grimes 
281a34b7046SRobert Watson 	SOCKBUF_LOCK(&so->so_rcv);
282a34b7046SRobert Watson 	socantrcvmore_locked(so);
283a34b7046SRobert Watson 	mtx_assert(SOCKBUF_MTX(&so->so_rcv), MA_NOTOWNED);
284df8bae1dSRodney W. Grimes }
285df8bae1dSRodney W. Grimes 
286df8bae1dSRodney W. Grimes /*
287df8bae1dSRodney W. Grimes  * Wait for data to arrive at/drain from a socket buffer.
288df8bae1dSRodney W. Grimes  */
28926f9a767SRodney W. Grimes int
290050ac265SRobert Watson sbwait(struct sockbuf *sb)
291df8bae1dSRodney W. Grimes {
292df8bae1dSRodney W. Grimes 
29331f555a1SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
29431f555a1SRobert Watson 
295df8bae1dSRodney W. Grimes 	sb->sb_flags |= SB_WAIT;
2960f9d0a73SGleb Smirnoff 	return (msleep_sbt(&sb->sb_acc, &sb->sb_mtx,
29747daf5d5SBruce Evans 	    (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait",
2987729cbf1SDavide Italiano 	    sb->sb_timeo, 0, 0));
299df8bae1dSRodney W. Grimes }
300df8bae1dSRodney W. Grimes 
30126f9a767SRodney W. Grimes int
3027abab911SRobert Watson sblock(struct sockbuf *sb, int flags)
303df8bae1dSRodney W. Grimes {
304df8bae1dSRodney W. Grimes 
305265de5bbSRobert Watson 	KASSERT((flags & SBL_VALID) == flags,
306265de5bbSRobert Watson 	    ("sblock: flags invalid (0x%x)", flags));
307265de5bbSRobert Watson 
308265de5bbSRobert Watson 	if (flags & SBL_WAIT) {
309265de5bbSRobert Watson 		if ((sb->sb_flags & SB_NOINTR) ||
310265de5bbSRobert Watson 		    (flags & SBL_NOINTR)) {
3117abab911SRobert Watson 			sx_xlock(&sb->sb_sx);
312df8bae1dSRodney W. Grimes 			return (0);
313049c3b6cSRobert Watson 		}
314049c3b6cSRobert Watson 		return (sx_xlock_sig(&sb->sb_sx));
3157abab911SRobert Watson 	} else {
3167abab911SRobert Watson 		if (sx_try_xlock(&sb->sb_sx) == 0)
3177abab911SRobert Watson 			return (EWOULDBLOCK);
3187abab911SRobert Watson 		return (0);
3197abab911SRobert Watson 	}
3207abab911SRobert Watson }
3217abab911SRobert Watson 
3227abab911SRobert Watson void
3237abab911SRobert Watson sbunlock(struct sockbuf *sb)
3247abab911SRobert Watson {
3257abab911SRobert Watson 
3267abab911SRobert Watson 	sx_xunlock(&sb->sb_sx);
327df8bae1dSRodney W. Grimes }
328df8bae1dSRodney W. Grimes 
329df8bae1dSRodney W. Grimes /*
330050ac265SRobert Watson  * Wakeup processes waiting on a socket buffer.  Do asynchronous notification
331050ac265SRobert Watson  * via SIGIO if the socket has the SS_ASYNC flag set.
332a34b7046SRobert Watson  *
333a34b7046SRobert Watson  * Called with the socket buffer lock held; will release the lock by the end
334a34b7046SRobert Watson  * of the function.  This allows the caller to acquire the socket buffer lock
335a34b7046SRobert Watson  * while testing for the need for various sorts of wakeup and hold it through
336a34b7046SRobert Watson  * to the point where it's no longer required.  We currently hold the lock
337a34b7046SRobert Watson  * through calls out to other subsystems (with the exception of kqueue), and
338a34b7046SRobert Watson  * then release it to avoid lock order issues.  It's not clear that's
339a34b7046SRobert Watson  * correct.
340df8bae1dSRodney W. Grimes  */
34126f9a767SRodney W. Grimes void
342050ac265SRobert Watson sowakeup(struct socket *so, struct sockbuf *sb)
343df8bae1dSRodney W. Grimes {
34474fb0ba7SJohn Baldwin 	int ret;
345d48d4b25SSeigo Tanimura 
346a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
347a34b7046SRobert Watson 
348779f106aSGleb Smirnoff 	selwakeuppri(sb->sb_sel, PSOCK);
349779f106aSGleb Smirnoff 	if (!SEL_WAITING(sb->sb_sel))
350df8bae1dSRodney W. Grimes 		sb->sb_flags &= ~SB_SEL;
351df8bae1dSRodney W. Grimes 	if (sb->sb_flags & SB_WAIT) {
352df8bae1dSRodney W. Grimes 		sb->sb_flags &= ~SB_WAIT;
3530f9d0a73SGleb Smirnoff 		wakeup(&sb->sb_acc);
354df8bae1dSRodney W. Grimes 	}
355779f106aSGleb Smirnoff 	KNOTE_LOCKED(&sb->sb_sel->si_note, 0);
35698c92369SNavdeep Parhar 	if (sb->sb_upcall != NULL) {
357eb1b1807SGleb Smirnoff 		ret = sb->sb_upcall(so, sb->sb_upcallarg, M_NOWAIT);
35874fb0ba7SJohn Baldwin 		if (ret == SU_ISCONNECTED) {
35974fb0ba7SJohn Baldwin 			KASSERT(sb == &so->so_rcv,
36074fb0ba7SJohn Baldwin 			    ("SO_SND upcall returned SU_ISCONNECTED"));
36174fb0ba7SJohn Baldwin 			soupcall_clear(so, SO_RCV);
36274fb0ba7SJohn Baldwin 		}
36374fb0ba7SJohn Baldwin 	} else
36474fb0ba7SJohn Baldwin 		ret = SU_OK;
3654cc20ab1SSeigo Tanimura 	if (sb->sb_flags & SB_AIO)
366f3215338SJohn Baldwin 		sowakeup_aio(so, sb);
36774fb0ba7SJohn Baldwin 	SOCKBUF_UNLOCK(sb);
368555b3e2fSGleb Smirnoff 	if (ret == SU_ISCONNECTED)
36974fb0ba7SJohn Baldwin 		soisconnected(so);
37074fb0ba7SJohn Baldwin 	if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL)
37174fb0ba7SJohn Baldwin 		pgsigio(&so->so_sigio, SIGIO, 0);
372a34b7046SRobert Watson 	mtx_assert(SOCKBUF_MTX(sb), MA_NOTOWNED);
373df8bae1dSRodney W. Grimes }
374df8bae1dSRodney W. Grimes 
375df8bae1dSRodney W. Grimes /*
376df8bae1dSRodney W. Grimes  * Socket buffer (struct sockbuf) utility routines.
377df8bae1dSRodney W. Grimes  *
378050ac265SRobert Watson  * Each socket contains two socket buffers: one for sending data and one for
379050ac265SRobert Watson  * receiving data.  Each buffer contains a queue of mbufs, information about
380050ac265SRobert Watson  * the number of mbufs and amount of data in the queue, and other fields
381050ac265SRobert Watson  * allowing select() statements and notification on data availability to be
382050ac265SRobert Watson  * implemented.
383df8bae1dSRodney W. Grimes  *
384050ac265SRobert Watson  * Data stored in a socket buffer is maintained as a list of records.  Each
385050ac265SRobert Watson  * record is a list of mbufs chained together with the m_next field.  Records
386050ac265SRobert Watson  * are chained together with the m_nextpkt field. The upper level routine
387050ac265SRobert Watson  * soreceive() expects the following conventions to be observed when placing
388050ac265SRobert Watson  * information in the receive buffer:
389df8bae1dSRodney W. Grimes  *
390050ac265SRobert Watson  * 1. If the protocol requires each message be preceded by the sender's name,
391050ac265SRobert Watson  *    then a record containing that name must be present before any
392050ac265SRobert Watson  *    associated data (mbuf's must be of type MT_SONAME).
393050ac265SRobert Watson  * 2. If the protocol supports the exchange of ``access rights'' (really just
394050ac265SRobert Watson  *    additional data associated with the message), and there are ``rights''
395050ac265SRobert Watson  *    to be received, then a record containing this data should be present
396050ac265SRobert Watson  *    (mbuf's must be of type MT_RIGHTS).
397050ac265SRobert Watson  * 3. If a name or rights record exists, then it must be followed by a data
398050ac265SRobert Watson  *    record, perhaps of zero length.
399df8bae1dSRodney W. Grimes  *
400df8bae1dSRodney W. Grimes  * Before using a new socket structure it is first necessary to reserve
401df8bae1dSRodney W. Grimes  * buffer space to the socket, by calling sbreserve().  This should commit
402df8bae1dSRodney W. Grimes  * some of the available buffer space in the system buffer pool for the
403050ac265SRobert Watson  * socket (currently, it does nothing but enforce limits).  The space should
404050ac265SRobert Watson  * be released by calling sbrelease() when the socket is destroyed.
405df8bae1dSRodney W. Grimes  */
40626f9a767SRodney W. Grimes int
407050ac265SRobert Watson soreserve(struct socket *so, u_long sndcc, u_long rcvcc)
408df8bae1dSRodney W. Grimes {
409b40ce416SJulian Elischer 	struct thread *td = curthread;
410df8bae1dSRodney W. Grimes 
4113f11a2f3SRobert Watson 	SOCKBUF_LOCK(&so->so_snd);
4129535efc0SRobert Watson 	SOCKBUF_LOCK(&so->so_rcv);
4133f11a2f3SRobert Watson 	if (sbreserve_locked(&so->so_snd, sndcc, so, td) == 0)
4143f11a2f3SRobert Watson 		goto bad;
4153f11a2f3SRobert Watson 	if (sbreserve_locked(&so->so_rcv, rcvcc, so, td) == 0)
4163f11a2f3SRobert Watson 		goto bad2;
417df8bae1dSRodney W. Grimes 	if (so->so_rcv.sb_lowat == 0)
418df8bae1dSRodney W. Grimes 		so->so_rcv.sb_lowat = 1;
419df8bae1dSRodney W. Grimes 	if (so->so_snd.sb_lowat == 0)
420df8bae1dSRodney W. Grimes 		so->so_snd.sb_lowat = MCLBYTES;
421df8bae1dSRodney W. Grimes 	if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat)
422df8bae1dSRodney W. Grimes 		so->so_snd.sb_lowat = so->so_snd.sb_hiwat;
4233f11a2f3SRobert Watson 	SOCKBUF_UNLOCK(&so->so_rcv);
4249535efc0SRobert Watson 	SOCKBUF_UNLOCK(&so->so_snd);
425df8bae1dSRodney W. Grimes 	return (0);
426df8bae1dSRodney W. Grimes bad2:
4273f11a2f3SRobert Watson 	sbrelease_locked(&so->so_snd, so);
428df8bae1dSRodney W. Grimes bad:
4293f11a2f3SRobert Watson 	SOCKBUF_UNLOCK(&so->so_rcv);
4303f11a2f3SRobert Watson 	SOCKBUF_UNLOCK(&so->so_snd);
431df8bae1dSRodney W. Grimes 	return (ENOBUFS);
432df8bae1dSRodney W. Grimes }
433df8bae1dSRodney W. Grimes 
43479cb7eb4SDavid Greenman static int
43579cb7eb4SDavid Greenman sysctl_handle_sb_max(SYSCTL_HANDLER_ARGS)
43679cb7eb4SDavid Greenman {
43779cb7eb4SDavid Greenman 	int error = 0;
43886a93d51SJohn Baldwin 	u_long tmp_sb_max = sb_max;
43979cb7eb4SDavid Greenman 
44086a93d51SJohn Baldwin 	error = sysctl_handle_long(oidp, &tmp_sb_max, arg2, req);
44179cb7eb4SDavid Greenman 	if (error || !req->newptr)
44279cb7eb4SDavid Greenman 		return (error);
44386a93d51SJohn Baldwin 	if (tmp_sb_max < MSIZE + MCLBYTES)
44479cb7eb4SDavid Greenman 		return (EINVAL);
44586a93d51SJohn Baldwin 	sb_max = tmp_sb_max;
44679cb7eb4SDavid Greenman 	sb_max_adj = (u_quad_t)sb_max * MCLBYTES / (MSIZE + MCLBYTES);
44779cb7eb4SDavid Greenman 	return (0);
44879cb7eb4SDavid Greenman }
44979cb7eb4SDavid Greenman 
450df8bae1dSRodney W. Grimes /*
451050ac265SRobert Watson  * Allot mbufs to a sockbuf.  Attempt to scale mbmax so that mbcnt doesn't
452050ac265SRobert Watson  * become limiting if buffering efficiency is near the normal case.
453df8bae1dSRodney W. Grimes  */
45426f9a767SRodney W. Grimes int
455050ac265SRobert Watson sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so,
456050ac265SRobert Watson     struct thread *td)
457df8bae1dSRodney W. Grimes {
45891d5354aSJohn Baldwin 	rlim_t sbsize_limit;
459ecf72308SBrian Feldman 
4603f11a2f3SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
4613f11a2f3SRobert Watson 
462ecf72308SBrian Feldman 	/*
4637978014dSRobert Watson 	 * When a thread is passed, we take into account the thread's socket
4647978014dSRobert Watson 	 * buffer size limit.  The caller will generally pass curthread, but
4657978014dSRobert Watson 	 * in the TCP input path, NULL will be passed to indicate that no
4667978014dSRobert Watson 	 * appropriate thread resource limits are available.  In that case,
4677978014dSRobert Watson 	 * we don't apply a process limit.
468ecf72308SBrian Feldman 	 */
46979cb7eb4SDavid Greenman 	if (cc > sb_max_adj)
470df8bae1dSRodney W. Grimes 		return (0);
47191d5354aSJohn Baldwin 	if (td != NULL) {
472f6f6d240SMateusz Guzik 		sbsize_limit = lim_cur(td, RLIMIT_SBSIZE);
47391d5354aSJohn Baldwin 	} else
47491d5354aSJohn Baldwin 		sbsize_limit = RLIM_INFINITY;
475f535380cSDon Lewis 	if (!chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, cc,
47691d5354aSJohn Baldwin 	    sbsize_limit))
477ecf72308SBrian Feldman 		return (0);
4784b29bc4fSGarrett Wollman 	sb->sb_mbmax = min(cc * sb_efficiency, sb_max);
479df8bae1dSRodney W. Grimes 	if (sb->sb_lowat > sb->sb_hiwat)
480df8bae1dSRodney W. Grimes 		sb->sb_lowat = sb->sb_hiwat;
481df8bae1dSRodney W. Grimes 	return (1);
482df8bae1dSRodney W. Grimes }
483df8bae1dSRodney W. Grimes 
4843f11a2f3SRobert Watson int
48564290befSGleb Smirnoff sbsetopt(struct socket *so, int cmd, u_long cc)
4863f11a2f3SRobert Watson {
48764290befSGleb Smirnoff 	struct sockbuf *sb;
48864290befSGleb Smirnoff 	short *flags;
48964290befSGleb Smirnoff 	u_int *hiwat, *lowat;
4903f11a2f3SRobert Watson 	int error;
4913f11a2f3SRobert Watson 
492b2037136SMatt Macy 	sb = NULL;
49364290befSGleb Smirnoff 	SOCK_LOCK(so);
49464290befSGleb Smirnoff 	if (SOLISTENING(so)) {
49564290befSGleb Smirnoff 		switch (cmd) {
49664290befSGleb Smirnoff 			case SO_SNDLOWAT:
49764290befSGleb Smirnoff 			case SO_SNDBUF:
49864290befSGleb Smirnoff 				lowat = &so->sol_sbsnd_lowat;
49964290befSGleb Smirnoff 				hiwat = &so->sol_sbsnd_hiwat;
50064290befSGleb Smirnoff 				flags = &so->sol_sbsnd_flags;
50164290befSGleb Smirnoff 				break;
50264290befSGleb Smirnoff 			case SO_RCVLOWAT:
50364290befSGleb Smirnoff 			case SO_RCVBUF:
50464290befSGleb Smirnoff 				lowat = &so->sol_sbrcv_lowat;
50564290befSGleb Smirnoff 				hiwat = &so->sol_sbrcv_hiwat;
50664290befSGleb Smirnoff 				flags = &so->sol_sbrcv_flags;
50764290befSGleb Smirnoff 				break;
50864290befSGleb Smirnoff 		}
50964290befSGleb Smirnoff 	} else {
51064290befSGleb Smirnoff 		switch (cmd) {
51164290befSGleb Smirnoff 			case SO_SNDLOWAT:
51264290befSGleb Smirnoff 			case SO_SNDBUF:
51364290befSGleb Smirnoff 				sb = &so->so_snd;
51464290befSGleb Smirnoff 				break;
51564290befSGleb Smirnoff 			case SO_RCVLOWAT:
51664290befSGleb Smirnoff 			case SO_RCVBUF:
51764290befSGleb Smirnoff 				sb = &so->so_rcv;
51864290befSGleb Smirnoff 				break;
51964290befSGleb Smirnoff 		}
52064290befSGleb Smirnoff 		flags = &sb->sb_flags;
52164290befSGleb Smirnoff 		hiwat = &sb->sb_hiwat;
52264290befSGleb Smirnoff 		lowat = &sb->sb_lowat;
5233f11a2f3SRobert Watson 		SOCKBUF_LOCK(sb);
52464290befSGleb Smirnoff 	}
52564290befSGleb Smirnoff 
52664290befSGleb Smirnoff 	error = 0;
52764290befSGleb Smirnoff 	switch (cmd) {
52864290befSGleb Smirnoff 	case SO_SNDBUF:
52964290befSGleb Smirnoff 	case SO_RCVBUF:
53064290befSGleb Smirnoff 		if (SOLISTENING(so)) {
53164290befSGleb Smirnoff 			if (cc > sb_max_adj) {
53264290befSGleb Smirnoff 				error = ENOBUFS;
53364290befSGleb Smirnoff 				break;
53464290befSGleb Smirnoff 			}
53564290befSGleb Smirnoff 			*hiwat = cc;
53664290befSGleb Smirnoff 			if (*lowat > *hiwat)
53764290befSGleb Smirnoff 				*lowat = *hiwat;
53864290befSGleb Smirnoff 		} else {
53964290befSGleb Smirnoff 			if (!sbreserve_locked(sb, cc, so, curthread))
54064290befSGleb Smirnoff 				error = ENOBUFS;
54164290befSGleb Smirnoff 		}
54264290befSGleb Smirnoff 		if (error == 0)
54364290befSGleb Smirnoff 			*flags &= ~SB_AUTOSIZE;
54464290befSGleb Smirnoff 		break;
54564290befSGleb Smirnoff 	case SO_SNDLOWAT:
54664290befSGleb Smirnoff 	case SO_RCVLOWAT:
54764290befSGleb Smirnoff 		/*
54864290befSGleb Smirnoff 		 * Make sure the low-water is never greater than the
54964290befSGleb Smirnoff 		 * high-water.
55064290befSGleb Smirnoff 		 */
55164290befSGleb Smirnoff 		*lowat = (cc > *hiwat) ? *hiwat : cc;
55264290befSGleb Smirnoff 		break;
55364290befSGleb Smirnoff 	}
55464290befSGleb Smirnoff 
55564290befSGleb Smirnoff 	if (!SOLISTENING(so))
5563f11a2f3SRobert Watson 		SOCKBUF_UNLOCK(sb);
55764290befSGleb Smirnoff 	SOCK_UNLOCK(so);
5583f11a2f3SRobert Watson 	return (error);
5593f11a2f3SRobert Watson }
5603f11a2f3SRobert Watson 
561df8bae1dSRodney W. Grimes /*
562df8bae1dSRodney W. Grimes  * Free mbufs held by a socket, and reserved mbuf space.
563df8bae1dSRodney W. Grimes  */
5643f0bfcccSRobert Watson void
565050ac265SRobert Watson sbrelease_internal(struct sockbuf *sb, struct socket *so)
566eaa6dfbcSRobert Watson {
567eaa6dfbcSRobert Watson 
568eaa6dfbcSRobert Watson 	sbflush_internal(sb);
569eaa6dfbcSRobert Watson 	(void)chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, 0,
570eaa6dfbcSRobert Watson 	    RLIM_INFINITY);
571eaa6dfbcSRobert Watson 	sb->sb_mbmax = 0;
572eaa6dfbcSRobert Watson }
573eaa6dfbcSRobert Watson 
57426f9a767SRodney W. Grimes void
575050ac265SRobert Watson sbrelease_locked(struct sockbuf *sb, struct socket *so)
576df8bae1dSRodney W. Grimes {
577df8bae1dSRodney W. Grimes 
578a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
579a34b7046SRobert Watson 
580eaa6dfbcSRobert Watson 	sbrelease_internal(sb, so);
581df8bae1dSRodney W. Grimes }
582df8bae1dSRodney W. Grimes 
583a34b7046SRobert Watson void
584050ac265SRobert Watson sbrelease(struct sockbuf *sb, struct socket *so)
585a34b7046SRobert Watson {
586a34b7046SRobert Watson 
587a34b7046SRobert Watson 	SOCKBUF_LOCK(sb);
588a34b7046SRobert Watson 	sbrelease_locked(sb, so);
589a34b7046SRobert Watson 	SOCKBUF_UNLOCK(sb);
590a34b7046SRobert Watson }
591eaa6dfbcSRobert Watson 
592eaa6dfbcSRobert Watson void
593050ac265SRobert Watson sbdestroy(struct sockbuf *sb, struct socket *so)
594eaa6dfbcSRobert Watson {
595eaa6dfbcSRobert Watson 
596eaa6dfbcSRobert Watson 	sbrelease_internal(sb, so);
597eaa6dfbcSRobert Watson }
598eaa6dfbcSRobert Watson 
599df8bae1dSRodney W. Grimes /*
600050ac265SRobert Watson  * Routines to add and remove data from an mbuf queue.
601df8bae1dSRodney W. Grimes  *
602050ac265SRobert Watson  * The routines sbappend() or sbappendrecord() are normally called to append
603050ac265SRobert Watson  * new mbufs to a socket buffer, after checking that adequate space is
604050ac265SRobert Watson  * available, comparing the function sbspace() with the amount of data to be
605050ac265SRobert Watson  * added.  sbappendrecord() differs from sbappend() in that data supplied is
606050ac265SRobert Watson  * treated as the beginning of a new record.  To place a sender's address,
607050ac265SRobert Watson  * optional access rights, and data in a socket receive buffer,
608050ac265SRobert Watson  * sbappendaddr() should be used.  To place access rights and data in a
609050ac265SRobert Watson  * socket receive buffer, sbappendrights() should be used.  In either case,
610050ac265SRobert Watson  * the new data begins a new record.  Note that unlike sbappend() and
611050ac265SRobert Watson  * sbappendrecord(), these routines check for the caller that there will be
612050ac265SRobert Watson  * enough space to store the data.  Each fails if there is not enough space,
613050ac265SRobert Watson  * or if it cannot find mbufs to store additional information in.
614df8bae1dSRodney W. Grimes  *
615050ac265SRobert Watson  * Reliable protocols may use the socket send buffer to hold data awaiting
616050ac265SRobert Watson  * acknowledgement.  Data is normally copied from a socket send buffer in a
617050ac265SRobert Watson  * protocol with m_copy for output to a peer, and then removing the data from
618050ac265SRobert Watson  * the socket buffer with sbdrop() or sbdroprecord() when the data is
619050ac265SRobert Watson  * acknowledged by the peer.
620df8bae1dSRodney W. Grimes  */
621395bb186SSam Leffler #ifdef SOCKBUF_DEBUG
622395bb186SSam Leffler void
623395bb186SSam Leffler sblastrecordchk(struct sockbuf *sb, const char *file, int line)
624395bb186SSam Leffler {
625395bb186SSam Leffler 	struct mbuf *m = sb->sb_mb;
626395bb186SSam Leffler 
627a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
628a34b7046SRobert Watson 
629395bb186SSam Leffler 	while (m && m->m_nextpkt)
630395bb186SSam Leffler 		m = m->m_nextpkt;
631395bb186SSam Leffler 
632395bb186SSam Leffler 	if (m != sb->sb_lastrecord) {
633395bb186SSam Leffler 		printf("%s: sb_mb %p sb_lastrecord %p last %p\n",
634395bb186SSam Leffler 			__func__, sb->sb_mb, sb->sb_lastrecord, m);
635395bb186SSam Leffler 		printf("packet chain:\n");
636395bb186SSam Leffler 		for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt)
637395bb186SSam Leffler 			printf("\t%p\n", m);
638395bb186SSam Leffler 		panic("%s from %s:%u", __func__, file, line);
639395bb186SSam Leffler 	}
640395bb186SSam Leffler }
641395bb186SSam Leffler 
642395bb186SSam Leffler void
643395bb186SSam Leffler sblastmbufchk(struct sockbuf *sb, const char *file, int line)
644395bb186SSam Leffler {
645395bb186SSam Leffler 	struct mbuf *m = sb->sb_mb;
646395bb186SSam Leffler 	struct mbuf *n;
647395bb186SSam Leffler 
648a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
649a34b7046SRobert Watson 
650395bb186SSam Leffler 	while (m && m->m_nextpkt)
651395bb186SSam Leffler 		m = m->m_nextpkt;
652395bb186SSam Leffler 
653395bb186SSam Leffler 	while (m && m->m_next)
654395bb186SSam Leffler 		m = m->m_next;
655395bb186SSam Leffler 
656395bb186SSam Leffler 	if (m != sb->sb_mbtail) {
657395bb186SSam Leffler 		printf("%s: sb_mb %p sb_mbtail %p last %p\n",
658395bb186SSam Leffler 			__func__, sb->sb_mb, sb->sb_mbtail, m);
659395bb186SSam Leffler 		printf("packet tree:\n");
660395bb186SSam Leffler 		for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt) {
661395bb186SSam Leffler 			printf("\t");
662395bb186SSam Leffler 			for (n = m; n != NULL; n = n->m_next)
663395bb186SSam Leffler 				printf("%p ", n);
664395bb186SSam Leffler 			printf("\n");
665395bb186SSam Leffler 		}
666395bb186SSam Leffler 		panic("%s from %s:%u", __func__, file, line);
667395bb186SSam Leffler 	}
668395bb186SSam Leffler }
669395bb186SSam Leffler #endif /* SOCKBUF_DEBUG */
670395bb186SSam Leffler 
671395bb186SSam Leffler #define SBLINKRECORD(sb, m0) do {					\
672a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);					\
673395bb186SSam Leffler 	if ((sb)->sb_lastrecord != NULL)				\
674395bb186SSam Leffler 		(sb)->sb_lastrecord->m_nextpkt = (m0);			\
675395bb186SSam Leffler 	else								\
676395bb186SSam Leffler 		(sb)->sb_mb = (m0);					\
677395bb186SSam Leffler 	(sb)->sb_lastrecord = (m0);					\
678395bb186SSam Leffler } while (/*CONSTCOND*/0)
679395bb186SSam Leffler 
680df8bae1dSRodney W. Grimes /*
681050ac265SRobert Watson  * Append mbuf chain m to the last record in the socket buffer sb.  The
682050ac265SRobert Watson  * additional space associated the mbuf chain is recorded in sb.  Empty mbufs
683050ac265SRobert Watson  * are discarded and mbufs are compacted where possible.
684df8bae1dSRodney W. Grimes  */
68526f9a767SRodney W. Grimes void
686829fae90SGleb Smirnoff sbappend_locked(struct sockbuf *sb, struct mbuf *m, int flags)
687df8bae1dSRodney W. Grimes {
688050ac265SRobert Watson 	struct mbuf *n;
689df8bae1dSRodney W. Grimes 
690a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
691a34b7046SRobert Watson 
692b85f65afSPedro F. Giffuni 	if (m == NULL)
693df8bae1dSRodney W. Grimes 		return;
694829fae90SGleb Smirnoff 	sbm_clrprotoflags(m, flags);
695395bb186SSam Leffler 	SBLASTRECORDCHK(sb);
696797f2d22SPoul-Henning Kamp 	n = sb->sb_mb;
697797f2d22SPoul-Henning Kamp 	if (n) {
698df8bae1dSRodney W. Grimes 		while (n->m_nextpkt)
699df8bae1dSRodney W. Grimes 			n = n->m_nextpkt;
700df8bae1dSRodney W. Grimes 		do {
701df8bae1dSRodney W. Grimes 			if (n->m_flags & M_EOR) {
702a34b7046SRobert Watson 				sbappendrecord_locked(sb, m); /* XXXXXX!!!! */
703df8bae1dSRodney W. Grimes 				return;
704df8bae1dSRodney W. Grimes 			}
705df8bae1dSRodney W. Grimes 		} while (n->m_next && (n = n->m_next));
706395bb186SSam Leffler 	} else {
707395bb186SSam Leffler 		/*
708395bb186SSam Leffler 		 * XXX Would like to simply use sb_mbtail here, but
709395bb186SSam Leffler 		 * XXX I need to verify that I won't miss an EOR that
710395bb186SSam Leffler 		 * XXX way.
711395bb186SSam Leffler 		 */
712395bb186SSam Leffler 		if ((n = sb->sb_lastrecord) != NULL) {
713395bb186SSam Leffler 			do {
714395bb186SSam Leffler 				if (n->m_flags & M_EOR) {
715a34b7046SRobert Watson 					sbappendrecord_locked(sb, m); /* XXXXXX!!!! */
716395bb186SSam Leffler 					return;
717395bb186SSam Leffler 				}
718395bb186SSam Leffler 			} while (n->m_next && (n = n->m_next));
719395bb186SSam Leffler 		} else {
720395bb186SSam Leffler 			/*
721395bb186SSam Leffler 			 * If this is the first record in the socket buffer,
722395bb186SSam Leffler 			 * it's also the last record.
723395bb186SSam Leffler 			 */
724395bb186SSam Leffler 			sb->sb_lastrecord = m;
725395bb186SSam Leffler 		}
726df8bae1dSRodney W. Grimes 	}
727df8bae1dSRodney W. Grimes 	sbcompress(sb, m, n);
728395bb186SSam Leffler 	SBLASTRECORDCHK(sb);
729395bb186SSam Leffler }
730395bb186SSam Leffler 
731395bb186SSam Leffler /*
732050ac265SRobert Watson  * Append mbuf chain m to the last record in the socket buffer sb.  The
733050ac265SRobert Watson  * additional space associated the mbuf chain is recorded in sb.  Empty mbufs
734050ac265SRobert Watson  * are discarded and mbufs are compacted where possible.
735a34b7046SRobert Watson  */
736a34b7046SRobert Watson void
737829fae90SGleb Smirnoff sbappend(struct sockbuf *sb, struct mbuf *m, int flags)
738a34b7046SRobert Watson {
739a34b7046SRobert Watson 
740a34b7046SRobert Watson 	SOCKBUF_LOCK(sb);
741829fae90SGleb Smirnoff 	sbappend_locked(sb, m, flags);
742a34b7046SRobert Watson 	SOCKBUF_UNLOCK(sb);
743a34b7046SRobert Watson }
744a34b7046SRobert Watson 
745a34b7046SRobert Watson /*
746050ac265SRobert Watson  * This version of sbappend() should only be used when the caller absolutely
747050ac265SRobert Watson  * knows that there will never be more than one record in the socket buffer,
748050ac265SRobert Watson  * that is, a stream protocol (such as TCP).
749395bb186SSam Leffler  */
750395bb186SSam Leffler void
751651e4e6aSGleb Smirnoff sbappendstream_locked(struct sockbuf *sb, struct mbuf *m, int flags)
752395bb186SSam Leffler {
753a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
754395bb186SSam Leffler 
755395bb186SSam Leffler 	KASSERT(m->m_nextpkt == NULL,("sbappendstream 0"));
756395bb186SSam Leffler 	KASSERT(sb->sb_mb == sb->sb_lastrecord,("sbappendstream 1"));
757395bb186SSam Leffler 
758395bb186SSam Leffler 	SBLASTMBUFCHK(sb);
759395bb186SSam Leffler 
760844cacd1SGleb Smirnoff 	/* Remove all packet headers and mbuf tags to get a pure data chain. */
761651e4e6aSGleb Smirnoff 	m_demote(m, 1, flags & PRUS_NOTREADY ? M_NOTREADY : 0);
762844cacd1SGleb Smirnoff 
763395bb186SSam Leffler 	sbcompress(sb, m, sb->sb_mbtail);
764395bb186SSam Leffler 
765395bb186SSam Leffler 	sb->sb_lastrecord = sb->sb_mb;
766395bb186SSam Leffler 	SBLASTRECORDCHK(sb);
767df8bae1dSRodney W. Grimes }
768df8bae1dSRodney W. Grimes 
769a34b7046SRobert Watson /*
770050ac265SRobert Watson  * This version of sbappend() should only be used when the caller absolutely
771050ac265SRobert Watson  * knows that there will never be more than one record in the socket buffer,
772050ac265SRobert Watson  * that is, a stream protocol (such as TCP).
773a34b7046SRobert Watson  */
774a34b7046SRobert Watson void
775651e4e6aSGleb Smirnoff sbappendstream(struct sockbuf *sb, struct mbuf *m, int flags)
776a34b7046SRobert Watson {
777a34b7046SRobert Watson 
778a34b7046SRobert Watson 	SOCKBUF_LOCK(sb);
779651e4e6aSGleb Smirnoff 	sbappendstream_locked(sb, m, flags);
780a34b7046SRobert Watson 	SOCKBUF_UNLOCK(sb);
781a34b7046SRobert Watson }
782a34b7046SRobert Watson 
783df8bae1dSRodney W. Grimes #ifdef SOCKBUF_DEBUG
78426f9a767SRodney W. Grimes void
78557f43a45SGleb Smirnoff sbcheck(struct sockbuf *sb, const char *file, int line)
786df8bae1dSRodney W. Grimes {
7870f9d0a73SGleb Smirnoff 	struct mbuf *m, *n, *fnrdy;
7880f9d0a73SGleb Smirnoff 	u_long acc, ccc, mbcnt;
789df8bae1dSRodney W. Grimes 
790a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
791a34b7046SRobert Watson 
7920f9d0a73SGleb Smirnoff 	acc = ccc = mbcnt = 0;
7930f9d0a73SGleb Smirnoff 	fnrdy = NULL;
79457f43a45SGleb Smirnoff 
7950931333fSBill Fenner 	for (m = sb->sb_mb; m; m = n) {
7960931333fSBill Fenner 	    n = m->m_nextpkt;
7970931333fSBill Fenner 	    for (; m; m = m->m_next) {
79857f43a45SGleb Smirnoff 		if (m->m_len == 0) {
79957f43a45SGleb Smirnoff 			printf("sb %p empty mbuf %p\n", sb, m);
80057f43a45SGleb Smirnoff 			goto fail;
80157f43a45SGleb Smirnoff 		}
8020f9d0a73SGleb Smirnoff 		if ((m->m_flags & M_NOTREADY) && fnrdy == NULL) {
8030f9d0a73SGleb Smirnoff 			if (m != sb->sb_fnrdy) {
8040f9d0a73SGleb Smirnoff 				printf("sb %p: fnrdy %p != m %p\n",
8050f9d0a73SGleb Smirnoff 				    sb, sb->sb_fnrdy, m);
8060f9d0a73SGleb Smirnoff 				goto fail;
8070f9d0a73SGleb Smirnoff 			}
8080f9d0a73SGleb Smirnoff 			fnrdy = m;
8090f9d0a73SGleb Smirnoff 		}
8100f9d0a73SGleb Smirnoff 		if (fnrdy) {
8110f9d0a73SGleb Smirnoff 			if (!(m->m_flags & M_NOTAVAIL)) {
8120f9d0a73SGleb Smirnoff 				printf("sb %p: fnrdy %p, m %p is avail\n",
8130f9d0a73SGleb Smirnoff 				    sb, sb->sb_fnrdy, m);
8140f9d0a73SGleb Smirnoff 				goto fail;
8150f9d0a73SGleb Smirnoff 			}
8160f9d0a73SGleb Smirnoff 		} else
8170f9d0a73SGleb Smirnoff 			acc += m->m_len;
8180f9d0a73SGleb Smirnoff 		ccc += m->m_len;
819df8bae1dSRodney W. Grimes 		mbcnt += MSIZE;
820313861b8SJulian Elischer 		if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */
821df8bae1dSRodney W. Grimes 			mbcnt += m->m_ext.ext_size;
8220931333fSBill Fenner 	    }
823df8bae1dSRodney W. Grimes 	}
8240f9d0a73SGleb Smirnoff 	if (acc != sb->sb_acc || ccc != sb->sb_ccc || mbcnt != sb->sb_mbcnt) {
8250f9d0a73SGleb Smirnoff 		printf("acc %ld/%u ccc %ld/%u mbcnt %ld/%u\n",
8260f9d0a73SGleb Smirnoff 		    acc, sb->sb_acc, ccc, sb->sb_ccc, mbcnt, sb->sb_mbcnt);
82757f43a45SGleb Smirnoff 		goto fail;
828df8bae1dSRodney W. Grimes 	}
82957f43a45SGleb Smirnoff 	return;
83057f43a45SGleb Smirnoff fail:
83157f43a45SGleb Smirnoff 	panic("%s from %s:%u", __func__, file, line);
832df8bae1dSRodney W. Grimes }
833df8bae1dSRodney W. Grimes #endif
834df8bae1dSRodney W. Grimes 
835df8bae1dSRodney W. Grimes /*
836050ac265SRobert Watson  * As above, except the mbuf chain begins a new record.
837df8bae1dSRodney W. Grimes  */
83826f9a767SRodney W. Grimes void
839050ac265SRobert Watson sbappendrecord_locked(struct sockbuf *sb, struct mbuf *m0)
840df8bae1dSRodney W. Grimes {
841050ac265SRobert Watson 	struct mbuf *m;
842df8bae1dSRodney W. Grimes 
843a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
844a34b7046SRobert Watson 
845b85f65afSPedro F. Giffuni 	if (m0 == NULL)
846df8bae1dSRodney W. Grimes 		return;
84753b680caSGleb Smirnoff 	m_clrprotoflags(m0);
848df8bae1dSRodney W. Grimes 	/*
849050ac265SRobert Watson 	 * Put the first mbuf on the queue.  Note this permits zero length
850050ac265SRobert Watson 	 * records.
851df8bae1dSRodney W. Grimes 	 */
852df8bae1dSRodney W. Grimes 	sballoc(sb, m0);
853395bb186SSam Leffler 	SBLASTRECORDCHK(sb);
854395bb186SSam Leffler 	SBLINKRECORD(sb, m0);
855e72a94adSMaksim Yevmenkin 	sb->sb_mbtail = m0;
856df8bae1dSRodney W. Grimes 	m = m0->m_next;
857df8bae1dSRodney W. Grimes 	m0->m_next = 0;
858df8bae1dSRodney W. Grimes 	if (m && (m0->m_flags & M_EOR)) {
859df8bae1dSRodney W. Grimes 		m0->m_flags &= ~M_EOR;
860df8bae1dSRodney W. Grimes 		m->m_flags |= M_EOR;
861df8bae1dSRodney W. Grimes 	}
862e72a94adSMaksim Yevmenkin 	/* always call sbcompress() so it can do SBLASTMBUFCHK() */
863df8bae1dSRodney W. Grimes 	sbcompress(sb, m, m0);
864df8bae1dSRodney W. Grimes }
865df8bae1dSRodney W. Grimes 
866df8bae1dSRodney W. Grimes /*
867050ac265SRobert Watson  * As above, except the mbuf chain begins a new record.
868a34b7046SRobert Watson  */
869a34b7046SRobert Watson void
870050ac265SRobert Watson sbappendrecord(struct sockbuf *sb, struct mbuf *m0)
871a34b7046SRobert Watson {
872a34b7046SRobert Watson 
873a34b7046SRobert Watson 	SOCKBUF_LOCK(sb);
874a34b7046SRobert Watson 	sbappendrecord_locked(sb, m0);
875a34b7046SRobert Watson 	SOCKBUF_UNLOCK(sb);
876a34b7046SRobert Watson }
877a34b7046SRobert Watson 
8788de34a88SAlan Somers /* Helper routine that appends data, control, and address to a sockbuf. */
8798de34a88SAlan Somers static int
8808de34a88SAlan Somers sbappendaddr_locked_internal(struct sockbuf *sb, const struct sockaddr *asa,
8818de34a88SAlan Somers     struct mbuf *m0, struct mbuf *control, struct mbuf *ctrl_last)
882df8bae1dSRodney W. Grimes {
883395bb186SSam Leffler 	struct mbuf *m, *n, *nlast;
884c43cad1aSScott Long #if MSIZE <= 256
885df8bae1dSRodney W. Grimes 	if (asa->sa_len > MLEN)
886df8bae1dSRodney W. Grimes 		return (0);
887c43cad1aSScott Long #endif
888c8b59ea7SGleb Smirnoff 	m = m_get(M_NOWAIT, MT_SONAME);
889c8b59ea7SGleb Smirnoff 	if (m == NULL)
890df8bae1dSRodney W. Grimes 		return (0);
891df8bae1dSRodney W. Grimes 	m->m_len = asa->sa_len;
89280208239SAlfred Perlstein 	bcopy(asa, mtod(m, caddr_t), asa->sa_len);
893c33a2313SAndrey V. Elsukov 	if (m0) {
89453b680caSGleb Smirnoff 		m_clrprotoflags(m0);
89557386f5dSAndrey V. Elsukov 		m_tag_delete_chain(m0, NULL);
896c33a2313SAndrey V. Elsukov 		/*
897c33a2313SAndrey V. Elsukov 		 * Clear some persistent info from pkthdr.
898c33a2313SAndrey V. Elsukov 		 * We don't use m_demote(), because some netgraph consumers
899c33a2313SAndrey V. Elsukov 		 * expect M_PKTHDR presence.
900c33a2313SAndrey V. Elsukov 		 */
901c33a2313SAndrey V. Elsukov 		m0->m_pkthdr.rcvif = NULL;
902c33a2313SAndrey V. Elsukov 		m0->m_pkthdr.flowid = 0;
903c33a2313SAndrey V. Elsukov 		m0->m_pkthdr.csum_flags = 0;
904c33a2313SAndrey V. Elsukov 		m0->m_pkthdr.fibnum = 0;
905c33a2313SAndrey V. Elsukov 		m0->m_pkthdr.rsstype = 0;
906c33a2313SAndrey V. Elsukov 	}
9078de34a88SAlan Somers 	if (ctrl_last)
9088de34a88SAlan Somers 		ctrl_last->m_next = m0;	/* concatenate data to control */
909df8bae1dSRodney W. Grimes 	else
910df8bae1dSRodney W. Grimes 		control = m0;
911df8bae1dSRodney W. Grimes 	m->m_next = control;
912395bb186SSam Leffler 	for (n = m; n->m_next != NULL; n = n->m_next)
913df8bae1dSRodney W. Grimes 		sballoc(sb, n);
914395bb186SSam Leffler 	sballoc(sb, n);
915395bb186SSam Leffler 	nlast = n;
916395bb186SSam Leffler 	SBLINKRECORD(sb, m);
917395bb186SSam Leffler 
918395bb186SSam Leffler 	sb->sb_mbtail = nlast;
919395bb186SSam Leffler 	SBLASTMBUFCHK(sb);
920395bb186SSam Leffler 
921395bb186SSam Leffler 	SBLASTRECORDCHK(sb);
922df8bae1dSRodney W. Grimes 	return (1);
923df8bae1dSRodney W. Grimes }
924df8bae1dSRodney W. Grimes 
925a34b7046SRobert Watson /*
926050ac265SRobert Watson  * Append address and data, and optionally, control (ancillary) data to the
927050ac265SRobert Watson  * receive queue of a socket.  If present, m0 must include a packet header
928050ac265SRobert Watson  * with total length.  Returns 0 if no space in sockbuf or insufficient
929050ac265SRobert Watson  * mbufs.
930a34b7046SRobert Watson  */
93126f9a767SRodney W. Grimes int
9328de34a88SAlan Somers sbappendaddr_locked(struct sockbuf *sb, const struct sockaddr *asa,
9338de34a88SAlan Somers     struct mbuf *m0, struct mbuf *control)
9348de34a88SAlan Somers {
9358de34a88SAlan Somers 	struct mbuf *ctrl_last;
9368de34a88SAlan Somers 	int space = asa->sa_len;
9378de34a88SAlan Somers 
9388de34a88SAlan Somers 	SOCKBUF_LOCK_ASSERT(sb);
9398de34a88SAlan Somers 
9408de34a88SAlan Somers 	if (m0 && (m0->m_flags & M_PKTHDR) == 0)
9418de34a88SAlan Somers 		panic("sbappendaddr_locked");
9428de34a88SAlan Somers 	if (m0)
9438de34a88SAlan Somers 		space += m0->m_pkthdr.len;
9448de34a88SAlan Somers 	space += m_length(control, &ctrl_last);
9458de34a88SAlan Somers 
9468de34a88SAlan Somers 	if (space > sbspace(sb))
9478de34a88SAlan Somers 		return (0);
9488de34a88SAlan Somers 	return (sbappendaddr_locked_internal(sb, asa, m0, control, ctrl_last));
9498de34a88SAlan Somers }
9508de34a88SAlan Somers 
9518de34a88SAlan Somers /*
9528de34a88SAlan Somers  * Append address and data, and optionally, control (ancillary) data to the
9538de34a88SAlan Somers  * receive queue of a socket.  If present, m0 must include a packet header
9548de34a88SAlan Somers  * with total length.  Returns 0 if insufficient mbufs.  Does not validate space
9558de34a88SAlan Somers  * on the receiving sockbuf.
9568de34a88SAlan Somers  */
9578de34a88SAlan Somers int
9588de34a88SAlan Somers sbappendaddr_nospacecheck_locked(struct sockbuf *sb, const struct sockaddr *asa,
9598de34a88SAlan Somers     struct mbuf *m0, struct mbuf *control)
9608de34a88SAlan Somers {
9618de34a88SAlan Somers 	struct mbuf *ctrl_last;
9628de34a88SAlan Somers 
9638de34a88SAlan Somers 	SOCKBUF_LOCK_ASSERT(sb);
9648de34a88SAlan Somers 
9658de34a88SAlan Somers 	ctrl_last = (control == NULL) ? NULL : m_last(control);
9668de34a88SAlan Somers 	return (sbappendaddr_locked_internal(sb, asa, m0, control, ctrl_last));
9678de34a88SAlan Somers }
9688de34a88SAlan Somers 
9698de34a88SAlan Somers /*
9708de34a88SAlan Somers  * Append address and data, and optionally, control (ancillary) data to the
9718de34a88SAlan Somers  * receive queue of a socket.  If present, m0 must include a packet header
9728de34a88SAlan Somers  * with total length.  Returns 0 if no space in sockbuf or insufficient
9738de34a88SAlan Somers  * mbufs.
9748de34a88SAlan Somers  */
9758de34a88SAlan Somers int
976050ac265SRobert Watson sbappendaddr(struct sockbuf *sb, const struct sockaddr *asa,
977050ac265SRobert Watson     struct mbuf *m0, struct mbuf *control)
978a34b7046SRobert Watson {
979a34b7046SRobert Watson 	int retval;
980a34b7046SRobert Watson 
981a34b7046SRobert Watson 	SOCKBUF_LOCK(sb);
982a34b7046SRobert Watson 	retval = sbappendaddr_locked(sb, asa, m0, control);
983a34b7046SRobert Watson 	SOCKBUF_UNLOCK(sb);
984a34b7046SRobert Watson 	return (retval);
985a34b7046SRobert Watson }
986a34b7046SRobert Watson 
9875b0480f2SMark Johnston void
988050ac265SRobert Watson sbappendcontrol_locked(struct sockbuf *sb, struct mbuf *m0,
989050ac265SRobert Watson     struct mbuf *control)
990df8bae1dSRodney W. Grimes {
9915b0480f2SMark Johnston 	struct mbuf *m, *mlast;
992df8bae1dSRodney W. Grimes 
99353b680caSGleb Smirnoff 	m_clrprotoflags(m0);
9945b0480f2SMark Johnston 	m_last(control)->m_next = m0;
995395bb186SSam Leffler 
996395bb186SSam Leffler 	SBLASTRECORDCHK(sb);
997395bb186SSam Leffler 
998395bb186SSam Leffler 	for (m = control; m->m_next; m = m->m_next)
999df8bae1dSRodney W. Grimes 		sballoc(sb, m);
1000395bb186SSam Leffler 	sballoc(sb, m);
1001395bb186SSam Leffler 	mlast = m;
1002395bb186SSam Leffler 	SBLINKRECORD(sb, control);
1003395bb186SSam Leffler 
1004395bb186SSam Leffler 	sb->sb_mbtail = mlast;
1005395bb186SSam Leffler 	SBLASTMBUFCHK(sb);
1006395bb186SSam Leffler 
1007395bb186SSam Leffler 	SBLASTRECORDCHK(sb);
1008df8bae1dSRodney W. Grimes }
1009df8bae1dSRodney W. Grimes 
10105b0480f2SMark Johnston void
1011050ac265SRobert Watson sbappendcontrol(struct sockbuf *sb, struct mbuf *m0, struct mbuf *control)
1012a34b7046SRobert Watson {
1013a34b7046SRobert Watson 
1014a34b7046SRobert Watson 	SOCKBUF_LOCK(sb);
10155b0480f2SMark Johnston 	sbappendcontrol_locked(sb, m0, control);
1016a34b7046SRobert Watson 	SOCKBUF_UNLOCK(sb);
1017a34b7046SRobert Watson }
1018a34b7046SRobert Watson 
1019df8bae1dSRodney W. Grimes /*
10207da7362bSRobert Watson  * Append the data in mbuf chain (m) into the socket buffer sb following mbuf
10217da7362bSRobert Watson  * (n).  If (n) is NULL, the buffer is presumed empty.
10227da7362bSRobert Watson  *
10237da7362bSRobert Watson  * When the data is compressed, mbufs in the chain may be handled in one of
10247da7362bSRobert Watson  * three ways:
10257da7362bSRobert Watson  *
10267da7362bSRobert Watson  * (1) The mbuf may simply be dropped, if it contributes nothing (no data, no
10277da7362bSRobert Watson  *     record boundary, and no change in data type).
10287da7362bSRobert Watson  *
10297da7362bSRobert Watson  * (2) The mbuf may be coalesced -- i.e., data in the mbuf may be copied into
10307da7362bSRobert Watson  *     an mbuf already in the socket buffer.  This can occur if an
10310f9d0a73SGleb Smirnoff  *     appropriate mbuf exists, there is room, both mbufs are not marked as
10320f9d0a73SGleb Smirnoff  *     not ready, and no merging of data types will occur.
10337da7362bSRobert Watson  *
10347da7362bSRobert Watson  * (3) The mbuf may be appended to the end of the existing mbuf chain.
10357da7362bSRobert Watson  *
10367da7362bSRobert Watson  * If any of the new mbufs is marked as M_EOR, mark the last mbuf appended as
10377da7362bSRobert Watson  * end-of-record.
1038df8bae1dSRodney W. Grimes  */
103926f9a767SRodney W. Grimes void
1040050ac265SRobert Watson sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n)
1041df8bae1dSRodney W. Grimes {
1042050ac265SRobert Watson 	int eor = 0;
1043050ac265SRobert Watson 	struct mbuf *o;
1044df8bae1dSRodney W. Grimes 
1045a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
1046a34b7046SRobert Watson 
1047df8bae1dSRodney W. Grimes 	while (m) {
1048df8bae1dSRodney W. Grimes 		eor |= m->m_flags & M_EOR;
1049df8bae1dSRodney W. Grimes 		if (m->m_len == 0 &&
1050df8bae1dSRodney W. Grimes 		    (eor == 0 ||
1051df8bae1dSRodney W. Grimes 		     (((o = m->m_next) || (o = n)) &&
1052df8bae1dSRodney W. Grimes 		      o->m_type == m->m_type))) {
1053395bb186SSam Leffler 			if (sb->sb_lastrecord == m)
1054395bb186SSam Leffler 				sb->sb_lastrecord = m->m_next;
1055df8bae1dSRodney W. Grimes 			m = m_free(m);
1056df8bae1dSRodney W. Grimes 			continue;
1057df8bae1dSRodney W. Grimes 		}
105832af0d74SDavid Malone 		if (n && (n->m_flags & M_EOR) == 0 &&
105932af0d74SDavid Malone 		    M_WRITABLE(n) &&
10605e0f5cfaSKip Macy 		    ((sb->sb_flags & SB_NOCOALESCE) == 0) &&
10610f9d0a73SGleb Smirnoff 		    !(m->m_flags & M_NOTREADY) &&
1062*82334850SJohn Baldwin 		    !(n->m_flags & (M_NOTREADY | M_NOMAP)) &&
106332af0d74SDavid Malone 		    m->m_len <= MCLBYTES / 4 && /* XXX: Don't copy too much */
106432af0d74SDavid Malone 		    m->m_len <= M_TRAILINGSPACE(n) &&
1065df8bae1dSRodney W. Grimes 		    n->m_type == m->m_type) {
1066*82334850SJohn Baldwin 			m_copydata(m, 0, m->m_len, mtodo(n, n->m_len));
1067df8bae1dSRodney W. Grimes 			n->m_len += m->m_len;
10680f9d0a73SGleb Smirnoff 			sb->sb_ccc += m->m_len;
10690f9d0a73SGleb Smirnoff 			if (sb->sb_fnrdy == NULL)
10700f9d0a73SGleb Smirnoff 				sb->sb_acc += m->m_len;
107134333b16SAndre Oppermann 			if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
1072b3f1af6bSTim J. Robbins 				/* XXX: Probably don't need.*/
107304ac9b97SKelly Yancey 				sb->sb_ctl += m->m_len;
1074df8bae1dSRodney W. Grimes 			m = m_free(m);
1075df8bae1dSRodney W. Grimes 			continue;
1076df8bae1dSRodney W. Grimes 		}
1077*82334850SJohn Baldwin 		if (m->m_len <= MLEN && (m->m_flags & M_NOMAP) &&
1078*82334850SJohn Baldwin 		    (m->m_flags & M_NOTREADY) == 0)
1079*82334850SJohn Baldwin 			(void)mb_unmapped_compress(m);
1080df8bae1dSRodney W. Grimes 		if (n)
1081df8bae1dSRodney W. Grimes 			n->m_next = m;
1082df8bae1dSRodney W. Grimes 		else
1083df8bae1dSRodney W. Grimes 			sb->sb_mb = m;
1084395bb186SSam Leffler 		sb->sb_mbtail = m;
1085df8bae1dSRodney W. Grimes 		sballoc(sb, m);
1086df8bae1dSRodney W. Grimes 		n = m;
1087df8bae1dSRodney W. Grimes 		m->m_flags &= ~M_EOR;
1088df8bae1dSRodney W. Grimes 		m = m->m_next;
1089df8bae1dSRodney W. Grimes 		n->m_next = 0;
1090df8bae1dSRodney W. Grimes 	}
1091df8bae1dSRodney W. Grimes 	if (eor) {
10927da7362bSRobert Watson 		KASSERT(n != NULL, ("sbcompress: eor && n == NULL"));
1093df8bae1dSRodney W. Grimes 		n->m_flags |= eor;
1094df8bae1dSRodney W. Grimes 	}
1095395bb186SSam Leffler 	SBLASTMBUFCHK(sb);
1096df8bae1dSRodney W. Grimes }
1097df8bae1dSRodney W. Grimes 
1098df8bae1dSRodney W. Grimes /*
1099050ac265SRobert Watson  * Free all mbufs in a sockbuf.  Check that all resources are reclaimed.
1100df8bae1dSRodney W. Grimes  */
1101eaa6dfbcSRobert Watson static void
1102050ac265SRobert Watson sbflush_internal(struct sockbuf *sb)
1103df8bae1dSRodney W. Grimes {
1104df8bae1dSRodney W. Grimes 
110523f84772SPierre Beyssac 	while (sb->sb_mbcnt) {
110623f84772SPierre Beyssac 		/*
1107761a9a1fSGleb Smirnoff 		 * Don't call sbcut(sb, 0) if the leading mbuf is non-empty:
110823f84772SPierre Beyssac 		 * we would loop forever. Panic instead.
110923f84772SPierre Beyssac 		 */
11100f9d0a73SGleb Smirnoff 		if (sb->sb_ccc == 0 && (sb->sb_mb == NULL || sb->sb_mb->m_len))
111123f84772SPierre Beyssac 			break;
11120f9d0a73SGleb Smirnoff 		m_freem(sbcut_internal(sb, (int)sb->sb_ccc));
111323f84772SPierre Beyssac 	}
11140f9d0a73SGleb Smirnoff 	KASSERT(sb->sb_ccc == 0 && sb->sb_mb == 0 && sb->sb_mbcnt == 0,
11150f9d0a73SGleb Smirnoff 	    ("%s: ccc %u mb %p mbcnt %u", __func__,
11160f9d0a73SGleb Smirnoff 	    sb->sb_ccc, (void *)sb->sb_mb, sb->sb_mbcnt));
1117a34b7046SRobert Watson }
1118a34b7046SRobert Watson 
1119a34b7046SRobert Watson void
1120050ac265SRobert Watson sbflush_locked(struct sockbuf *sb)
1121eaa6dfbcSRobert Watson {
1122eaa6dfbcSRobert Watson 
1123eaa6dfbcSRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
1124eaa6dfbcSRobert Watson 	sbflush_internal(sb);
1125eaa6dfbcSRobert Watson }
1126eaa6dfbcSRobert Watson 
1127eaa6dfbcSRobert Watson void
1128050ac265SRobert Watson sbflush(struct sockbuf *sb)
1129a34b7046SRobert Watson {
1130a34b7046SRobert Watson 
1131a34b7046SRobert Watson 	SOCKBUF_LOCK(sb);
1132a34b7046SRobert Watson 	sbflush_locked(sb);
1133a34b7046SRobert Watson 	SOCKBUF_UNLOCK(sb);
1134df8bae1dSRodney W. Grimes }
1135df8bae1dSRodney W. Grimes 
1136df8bae1dSRodney W. Grimes /*
11371d2df300SGleb Smirnoff  * Cut data from (the front of) a sockbuf.
1138df8bae1dSRodney W. Grimes  */
11391d2df300SGleb Smirnoff static struct mbuf *
11401d2df300SGleb Smirnoff sbcut_internal(struct sockbuf *sb, int len)
1141df8bae1dSRodney W. Grimes {
11420f9d0a73SGleb Smirnoff 	struct mbuf *m, *next, *mfree;
1143df8bae1dSRodney W. Grimes 
1144f41b2de7SHiren Panchasara 	KASSERT(len >= 0, ("%s: len is %d but it is supposed to be >= 0",
1145b5b023b9SHiren Panchasara 	    __func__, len));
1146b5b023b9SHiren Panchasara 	KASSERT(len <= sb->sb_ccc, ("%s: len: %d is > ccc: %u",
1147b5b023b9SHiren Panchasara 	    __func__, len, sb->sb_ccc));
1148b5b023b9SHiren Panchasara 
1149df8bae1dSRodney W. Grimes 	next = (m = sb->sb_mb) ? m->m_nextpkt : 0;
11501d2df300SGleb Smirnoff 	mfree = NULL;
11511d2df300SGleb Smirnoff 
1152df8bae1dSRodney W. Grimes 	while (len > 0) {
11538146bcfeSGleb Smirnoff 		if (m == NULL) {
11548146bcfeSGleb Smirnoff 			KASSERT(next, ("%s: no next, len %d", __func__, len));
1155df8bae1dSRodney W. Grimes 			m = next;
1156df8bae1dSRodney W. Grimes 			next = m->m_nextpkt;
1157df8bae1dSRodney W. Grimes 		}
1158df8bae1dSRodney W. Grimes 		if (m->m_len > len) {
11590f9d0a73SGleb Smirnoff 			KASSERT(!(m->m_flags & M_NOTAVAIL),
11600f9d0a73SGleb Smirnoff 			    ("%s: m %p M_NOTAVAIL", __func__, m));
1161df8bae1dSRodney W. Grimes 			m->m_len -= len;
1162df8bae1dSRodney W. Grimes 			m->m_data += len;
11630f9d0a73SGleb Smirnoff 			sb->sb_ccc -= len;
11640f9d0a73SGleb Smirnoff 			sb->sb_acc -= len;
11654e023759SAndre Oppermann 			if (sb->sb_sndptroff != 0)
11664e023759SAndre Oppermann 				sb->sb_sndptroff -= len;
116734333b16SAndre Oppermann 			if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
116804ac9b97SKelly Yancey 				sb->sb_ctl -= len;
1169df8bae1dSRodney W. Grimes 			break;
1170df8bae1dSRodney W. Grimes 		}
1171df8bae1dSRodney W. Grimes 		len -= m->m_len;
1172df8bae1dSRodney W. Grimes 		sbfree(sb, m);
11730f9d0a73SGleb Smirnoff 		/*
11740f9d0a73SGleb Smirnoff 		 * Do not put M_NOTREADY buffers to the free list, they
11750f9d0a73SGleb Smirnoff 		 * are referenced from outside.
11760f9d0a73SGleb Smirnoff 		 */
11770f9d0a73SGleb Smirnoff 		if (m->m_flags & M_NOTREADY)
11780f9d0a73SGleb Smirnoff 			m = m->m_next;
11790f9d0a73SGleb Smirnoff 		else {
11800f9d0a73SGleb Smirnoff 			struct mbuf *n;
11810f9d0a73SGleb Smirnoff 
11821d2df300SGleb Smirnoff 			n = m->m_next;
11831d2df300SGleb Smirnoff 			m->m_next = mfree;
11841d2df300SGleb Smirnoff 			mfree = m;
11851d2df300SGleb Smirnoff 			m = n;
1186df8bae1dSRodney W. Grimes 		}
11870f9d0a73SGleb Smirnoff 	}
1188e834a840SGleb Smirnoff 	/*
1189e834a840SGleb Smirnoff 	 * Free any zero-length mbufs from the buffer.
1190e834a840SGleb Smirnoff 	 * For SOCK_DGRAM sockets such mbufs represent empty records.
1191e834a840SGleb Smirnoff 	 * XXX: For SOCK_STREAM sockets such mbufs can appear in the buffer,
1192e834a840SGleb Smirnoff 	 * when sosend_generic() needs to send only control data.
1193e834a840SGleb Smirnoff 	 */
1194e834a840SGleb Smirnoff 	while (m && m->m_len == 0) {
1195e834a840SGleb Smirnoff 		struct mbuf *n;
1196e834a840SGleb Smirnoff 
1197e834a840SGleb Smirnoff 		sbfree(sb, m);
1198e834a840SGleb Smirnoff 		n = m->m_next;
1199e834a840SGleb Smirnoff 		m->m_next = mfree;
1200e834a840SGleb Smirnoff 		mfree = m;
1201e834a840SGleb Smirnoff 		m = n;
1202e834a840SGleb Smirnoff 	}
1203df8bae1dSRodney W. Grimes 	if (m) {
1204df8bae1dSRodney W. Grimes 		sb->sb_mb = m;
1205df8bae1dSRodney W. Grimes 		m->m_nextpkt = next;
1206df8bae1dSRodney W. Grimes 	} else
1207df8bae1dSRodney W. Grimes 		sb->sb_mb = next;
1208395bb186SSam Leffler 	/*
1209050ac265SRobert Watson 	 * First part is an inline SB_EMPTY_FIXUP().  Second part makes sure
1210050ac265SRobert Watson 	 * sb_lastrecord is up-to-date if we dropped part of the last record.
1211395bb186SSam Leffler 	 */
1212395bb186SSam Leffler 	m = sb->sb_mb;
1213395bb186SSam Leffler 	if (m == NULL) {
1214395bb186SSam Leffler 		sb->sb_mbtail = NULL;
1215395bb186SSam Leffler 		sb->sb_lastrecord = NULL;
1216395bb186SSam Leffler 	} else if (m->m_nextpkt == NULL) {
1217395bb186SSam Leffler 		sb->sb_lastrecord = m;
1218395bb186SSam Leffler 	}
12191d2df300SGleb Smirnoff 
12201d2df300SGleb Smirnoff 	return (mfree);
1221df8bae1dSRodney W. Grimes }
1222df8bae1dSRodney W. Grimes 
1223df8bae1dSRodney W. Grimes /*
1224a34b7046SRobert Watson  * Drop data from (the front of) a sockbuf.
1225a34b7046SRobert Watson  */
1226a34b7046SRobert Watson void
1227050ac265SRobert Watson sbdrop_locked(struct sockbuf *sb, int len)
1228eaa6dfbcSRobert Watson {
1229eaa6dfbcSRobert Watson 
1230eaa6dfbcSRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
12311d2df300SGleb Smirnoff 	m_freem(sbcut_internal(sb, len));
12321d2df300SGleb Smirnoff }
1233eaa6dfbcSRobert Watson 
12341d2df300SGleb Smirnoff /*
12351d2df300SGleb Smirnoff  * Drop data from (the front of) a sockbuf,
12361d2df300SGleb Smirnoff  * and return it to caller.
12371d2df300SGleb Smirnoff  */
12381d2df300SGleb Smirnoff struct mbuf *
12391d2df300SGleb Smirnoff sbcut_locked(struct sockbuf *sb, int len)
12401d2df300SGleb Smirnoff {
12411d2df300SGleb Smirnoff 
12421d2df300SGleb Smirnoff 	SOCKBUF_LOCK_ASSERT(sb);
12431d2df300SGleb Smirnoff 	return (sbcut_internal(sb, len));
1244eaa6dfbcSRobert Watson }
1245eaa6dfbcSRobert Watson 
1246eaa6dfbcSRobert Watson void
1247050ac265SRobert Watson sbdrop(struct sockbuf *sb, int len)
1248a34b7046SRobert Watson {
12491d2df300SGleb Smirnoff 	struct mbuf *mfree;
1250a34b7046SRobert Watson 
1251a34b7046SRobert Watson 	SOCKBUF_LOCK(sb);
12521d2df300SGleb Smirnoff 	mfree = sbcut_internal(sb, len);
1253a34b7046SRobert Watson 	SOCKBUF_UNLOCK(sb);
12541d2df300SGleb Smirnoff 
12551d2df300SGleb Smirnoff 	m_freem(mfree);
1256a34b7046SRobert Watson }
1257a34b7046SRobert Watson 
125889e560f4SRandall Stewart struct mbuf *
125989e560f4SRandall Stewart sbsndptr_noadv(struct sockbuf *sb, uint32_t off, uint32_t *moff)
126089e560f4SRandall Stewart {
126189e560f4SRandall Stewart 	struct mbuf *m;
126289e560f4SRandall Stewart 
126389e560f4SRandall Stewart 	KASSERT(sb->sb_mb != NULL, ("%s: sb_mb is NULL", __func__));
126489e560f4SRandall Stewart 	if (sb->sb_sndptr == NULL || sb->sb_sndptroff > off) {
126589e560f4SRandall Stewart 		*moff = off;
126689e560f4SRandall Stewart 		if (sb->sb_sndptr == NULL) {
126789e560f4SRandall Stewart 			sb->sb_sndptr = sb->sb_mb;
126889e560f4SRandall Stewart 			sb->sb_sndptroff = 0;
126989e560f4SRandall Stewart 		}
127089e560f4SRandall Stewart 		return (sb->sb_mb);
127189e560f4SRandall Stewart 	} else {
127289e560f4SRandall Stewart 		m = sb->sb_sndptr;
127389e560f4SRandall Stewart 		off -= sb->sb_sndptroff;
127489e560f4SRandall Stewart 	}
127589e560f4SRandall Stewart 	*moff = off;
127689e560f4SRandall Stewart 	return (m);
127789e560f4SRandall Stewart }
127889e560f4SRandall Stewart 
127989e560f4SRandall Stewart void
128089e560f4SRandall Stewart sbsndptr_adv(struct sockbuf *sb, struct mbuf *mb, uint32_t len)
128189e560f4SRandall Stewart {
128289e560f4SRandall Stewart 	/*
128389e560f4SRandall Stewart 	 * A small copy was done, advance forward the sb_sbsndptr to cover
128489e560f4SRandall Stewart 	 * it.
128589e560f4SRandall Stewart 	 */
128689e560f4SRandall Stewart 	struct mbuf *m;
128789e560f4SRandall Stewart 
128889e560f4SRandall Stewart 	if (mb != sb->sb_sndptr) {
128989e560f4SRandall Stewart 		/* Did not copyout at the same mbuf */
129089e560f4SRandall Stewart 		return;
129189e560f4SRandall Stewart 	}
129289e560f4SRandall Stewart 	m = mb;
129389e560f4SRandall Stewart 	while (m && (len > 0)) {
129489e560f4SRandall Stewart 		if (len >= m->m_len) {
129589e560f4SRandall Stewart 			len -= m->m_len;
129689e560f4SRandall Stewart 			if (m->m_next) {
129789e560f4SRandall Stewart 				sb->sb_sndptroff += m->m_len;
129889e560f4SRandall Stewart 				sb->sb_sndptr = m->m_next;
129989e560f4SRandall Stewart 			}
130089e560f4SRandall Stewart 			m = m->m_next;
130189e560f4SRandall Stewart 		} else {
130289e560f4SRandall Stewart 			len = 0;
130389e560f4SRandall Stewart 		}
130489e560f4SRandall Stewart 	}
130589e560f4SRandall Stewart }
130689e560f4SRandall Stewart 
1307a34b7046SRobert Watson /*
13089fd573c3SHans Petter Selasky  * Return the first mbuf and the mbuf data offset for the provided
13099fd573c3SHans Petter Selasky  * send offset without changing the "sb_sndptroff" field.
13109fd573c3SHans Petter Selasky  */
13119fd573c3SHans Petter Selasky struct mbuf *
13129fd573c3SHans Petter Selasky sbsndmbuf(struct sockbuf *sb, u_int off, u_int *moff)
13139fd573c3SHans Petter Selasky {
13149fd573c3SHans Petter Selasky 	struct mbuf *m;
13159fd573c3SHans Petter Selasky 
13169fd573c3SHans Petter Selasky 	KASSERT(sb->sb_mb != NULL, ("%s: sb_mb is NULL", __func__));
13179fd573c3SHans Petter Selasky 
13189fd573c3SHans Petter Selasky 	/*
13199fd573c3SHans Petter Selasky 	 * If the "off" is below the stored offset, which happens on
13209fd573c3SHans Petter Selasky 	 * retransmits, just use "sb_mb":
13219fd573c3SHans Petter Selasky 	 */
13229fd573c3SHans Petter Selasky 	if (sb->sb_sndptr == NULL || sb->sb_sndptroff > off) {
13239fd573c3SHans Petter Selasky 		m = sb->sb_mb;
13249fd573c3SHans Petter Selasky 	} else {
13259fd573c3SHans Petter Selasky 		m = sb->sb_sndptr;
13269fd573c3SHans Petter Selasky 		off -= sb->sb_sndptroff;
13279fd573c3SHans Petter Selasky 	}
13289fd573c3SHans Petter Selasky 	while (off > 0 && m != NULL) {
13299fd573c3SHans Petter Selasky 		if (off < m->m_len)
13309fd573c3SHans Petter Selasky 			break;
13319fd573c3SHans Petter Selasky 		off -= m->m_len;
13329fd573c3SHans Petter Selasky 		m = m->m_next;
13339fd573c3SHans Petter Selasky 	}
13349fd573c3SHans Petter Selasky 	*moff = off;
13359fd573c3SHans Petter Selasky 	return (m);
13369fd573c3SHans Petter Selasky }
13379fd573c3SHans Petter Selasky 
13389fd573c3SHans Petter Selasky /*
1339050ac265SRobert Watson  * Drop a record off the front of a sockbuf and move the next record to the
1340050ac265SRobert Watson  * front.
1341df8bae1dSRodney W. Grimes  */
134226f9a767SRodney W. Grimes void
1343050ac265SRobert Watson sbdroprecord_locked(struct sockbuf *sb)
1344df8bae1dSRodney W. Grimes {
1345050ac265SRobert Watson 	struct mbuf *m;
1346df8bae1dSRodney W. Grimes 
1347a34b7046SRobert Watson 	SOCKBUF_LOCK_ASSERT(sb);
1348a34b7046SRobert Watson 
1349df8bae1dSRodney W. Grimes 	m = sb->sb_mb;
1350df8bae1dSRodney W. Grimes 	if (m) {
1351df8bae1dSRodney W. Grimes 		sb->sb_mb = m->m_nextpkt;
1352df8bae1dSRodney W. Grimes 		do {
1353df8bae1dSRodney W. Grimes 			sbfree(sb, m);
1354ecde8f7cSMatthew Dillon 			m = m_free(m);
1355797f2d22SPoul-Henning Kamp 		} while (m);
1356df8bae1dSRodney W. Grimes 	}
1357395bb186SSam Leffler 	SB_EMPTY_FIXUP(sb);
1358df8bae1dSRodney W. Grimes }
13591e4ad9ceSGarrett Wollman 
136082c23ebaSBill Fenner /*
1361050ac265SRobert Watson  * Drop a record off the front of a sockbuf and move the next record to the
1362050ac265SRobert Watson  * front.
1363a34b7046SRobert Watson  */
1364a34b7046SRobert Watson void
1365050ac265SRobert Watson sbdroprecord(struct sockbuf *sb)
1366a34b7046SRobert Watson {
1367a34b7046SRobert Watson 
1368a34b7046SRobert Watson 	SOCKBUF_LOCK(sb);
1369a34b7046SRobert Watson 	sbdroprecord_locked(sb);
1370a34b7046SRobert Watson 	SOCKBUF_UNLOCK(sb);
1371a34b7046SRobert Watson }
1372a34b7046SRobert Watson 
137320d9e5e8SRobert Watson /*
13748c799760SRobert Watson  * Create a "control" mbuf containing the specified data with the specified
13758c799760SRobert Watson  * type for presentation on a socket buffer.
137620d9e5e8SRobert Watson  */
137720d9e5e8SRobert Watson struct mbuf *
1378d19e16a7SRobert Watson sbcreatecontrol(caddr_t p, int size, int type, int level)
137920d9e5e8SRobert Watson {
1380d19e16a7SRobert Watson 	struct cmsghdr *cp;
138120d9e5e8SRobert Watson 	struct mbuf *m;
138220d9e5e8SRobert Watson 
138320d9e5e8SRobert Watson 	if (CMSG_SPACE((u_int)size) > MCLBYTES)
138420d9e5e8SRobert Watson 		return ((struct mbuf *) NULL);
138520d9e5e8SRobert Watson 	if (CMSG_SPACE((u_int)size) > MLEN)
1386eb1b1807SGleb Smirnoff 		m = m_getcl(M_NOWAIT, MT_CONTROL, 0);
138720d9e5e8SRobert Watson 	else
1388eb1b1807SGleb Smirnoff 		m = m_get(M_NOWAIT, MT_CONTROL);
138920d9e5e8SRobert Watson 	if (m == NULL)
139020d9e5e8SRobert Watson 		return ((struct mbuf *) NULL);
139120d9e5e8SRobert Watson 	cp = mtod(m, struct cmsghdr *);
139220d9e5e8SRobert Watson 	m->m_len = 0;
139320d9e5e8SRobert Watson 	KASSERT(CMSG_SPACE((u_int)size) <= M_TRAILINGSPACE(m),
139420d9e5e8SRobert Watson 	    ("sbcreatecontrol: short mbuf"));
13952827952eSXin LI 	/*
13962827952eSXin LI 	 * Don't leave the padding between the msg header and the
13972827952eSXin LI 	 * cmsg data and the padding after the cmsg data un-initialized.
13982827952eSXin LI 	 */
13992827952eSXin LI 	bzero(cp, CMSG_SPACE((u_int)size));
140020d9e5e8SRobert Watson 	if (p != NULL)
140120d9e5e8SRobert Watson 		(void)memcpy(CMSG_DATA(cp), p, size);
140220d9e5e8SRobert Watson 	m->m_len = CMSG_SPACE(size);
140320d9e5e8SRobert Watson 	cp->cmsg_len = CMSG_LEN(size);
140420d9e5e8SRobert Watson 	cp->cmsg_level = level;
140520d9e5e8SRobert Watson 	cp->cmsg_type = type;
140620d9e5e8SRobert Watson 	return (m);
140720d9e5e8SRobert Watson }
140820d9e5e8SRobert Watson 
140920d9e5e8SRobert Watson /*
14108c799760SRobert Watson  * This does the same for socket buffers that sotoxsocket does for sockets:
14118c799760SRobert Watson  * generate an user-format data structure describing the socket buffer.  Note
14128c799760SRobert Watson  * that the xsockbuf structure, since it is always embedded in a socket, does
14138c799760SRobert Watson  * not include a self pointer nor a length.  We make this entry point public
14148c799760SRobert Watson  * in case some other mechanism needs it.
141520d9e5e8SRobert Watson  */
141620d9e5e8SRobert Watson void
141720d9e5e8SRobert Watson sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb)
141820d9e5e8SRobert Watson {
1419d19e16a7SRobert Watson 
14200f9d0a73SGleb Smirnoff 	xsb->sb_cc = sb->sb_ccc;
142120d9e5e8SRobert Watson 	xsb->sb_hiwat = sb->sb_hiwat;
142220d9e5e8SRobert Watson 	xsb->sb_mbcnt = sb->sb_mbcnt;
142349f287f8SGeorge V. Neville-Neil 	xsb->sb_mcnt = sb->sb_mcnt;
142449f287f8SGeorge V. Neville-Neil 	xsb->sb_ccnt = sb->sb_ccnt;
142520d9e5e8SRobert Watson 	xsb->sb_mbmax = sb->sb_mbmax;
142620d9e5e8SRobert Watson 	xsb->sb_lowat = sb->sb_lowat;
142720d9e5e8SRobert Watson 	xsb->sb_flags = sb->sb_flags;
142820d9e5e8SRobert Watson 	xsb->sb_timeo = sb->sb_timeo;
142920d9e5e8SRobert Watson }
143020d9e5e8SRobert Watson 
1431639acc13SGarrett Wollman /* This takes the place of kern.maxsockbuf, which moved to kern.ipc. */
1432639acc13SGarrett Wollman static int dummy;
1433639acc13SGarrett Wollman SYSCTL_INT(_kern, KERN_DUMMY, dummy, CTLFLAG_RW, &dummy, 0, "");
14341b978d45SHartmut Brandt SYSCTL_OID(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLTYPE_ULONG|CTLFLAG_RW,
14351b978d45SHartmut Brandt     &sb_max, 0, sysctl_handle_sb_max, "LU", "Maximum socket buffer size");
14361b978d45SHartmut Brandt SYSCTL_ULONG(_kern_ipc, KIPC_SOCKBUF_WASTE, sockbuf_waste_factor, CTLFLAG_RW,
14373eb9ab52SEitan Adler     &sb_efficiency, 0, "Socket buffer size waste factor");
1438