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*3807631bSJohn Baldwin * Compress M_NOTREADY mbufs after they have been readied by sbready(). 93*3807631bSJohn Baldwin * 94*3807631bSJohn Baldwin * sbcompress() skips M_NOTREADY mbufs since the data is not available to 95*3807631bSJohn Baldwin * be copied at the time of sbcompress(). This function combines small 96*3807631bSJohn Baldwin * mbufs similar to sbcompress() once mbufs are ready. 'm0' is the first 97*3807631bSJohn Baldwin * mbuf sbready() marked ready, and 'end' is the first mbuf still not 98*3807631bSJohn Baldwin * ready. 99*3807631bSJohn Baldwin */ 100*3807631bSJohn Baldwin static void 101*3807631bSJohn Baldwin sbready_compress(struct sockbuf *sb, struct mbuf *m0, struct mbuf *end) 102*3807631bSJohn Baldwin { 103*3807631bSJohn Baldwin struct mbuf *m, *n; 104*3807631bSJohn Baldwin int ext_size; 105*3807631bSJohn Baldwin 106*3807631bSJohn Baldwin SOCKBUF_LOCK_ASSERT(sb); 107*3807631bSJohn Baldwin 108*3807631bSJohn Baldwin if ((sb->sb_flags & SB_NOCOALESCE) != 0) 109*3807631bSJohn Baldwin return; 110*3807631bSJohn Baldwin 111*3807631bSJohn Baldwin for (m = m0; m != end; m = m->m_next) { 112*3807631bSJohn Baldwin MPASS((m->m_flags & M_NOTREADY) == 0); 113*3807631bSJohn Baldwin 114*3807631bSJohn Baldwin /* Compress small unmapped mbufs into plain mbufs. */ 115*3807631bSJohn Baldwin if ((m->m_flags & M_NOMAP) && m->m_len <= MLEN) { 116*3807631bSJohn Baldwin MPASS(m->m_flags & M_EXT); 117*3807631bSJohn Baldwin ext_size = m->m_ext.ext_size; 118*3807631bSJohn Baldwin if (mb_unmapped_compress(m) == 0) { 119*3807631bSJohn Baldwin sb->sb_mbcnt -= ext_size; 120*3807631bSJohn Baldwin sb->sb_ccnt -= 1; 121*3807631bSJohn Baldwin } 122*3807631bSJohn Baldwin } 123*3807631bSJohn Baldwin 124*3807631bSJohn Baldwin /* 125*3807631bSJohn Baldwin * NB: In sbcompress(), 'n' is the last mbuf in the 126*3807631bSJohn Baldwin * socket buffer and 'm' is the new mbuf being copied 127*3807631bSJohn Baldwin * into the trailing space of 'n'. Here, the roles 128*3807631bSJohn Baldwin * are reversed and 'n' is the next mbuf after 'm' 129*3807631bSJohn Baldwin * that is being copied into the trailing space of 130*3807631bSJohn Baldwin * 'm'. 131*3807631bSJohn Baldwin */ 132*3807631bSJohn Baldwin n = m->m_next; 133*3807631bSJohn Baldwin while ((n != NULL) && (n != end) && (m->m_flags & M_EOR) == 0 && 134*3807631bSJohn Baldwin M_WRITABLE(m) && 135*3807631bSJohn Baldwin (m->m_flags & M_NOMAP) == 0 && 136*3807631bSJohn Baldwin n->m_len <= MCLBYTES / 4 && /* XXX: Don't copy too much */ 137*3807631bSJohn Baldwin n->m_len <= M_TRAILINGSPACE(m) && 138*3807631bSJohn Baldwin m->m_type == n->m_type) { 139*3807631bSJohn Baldwin KASSERT(sb->sb_lastrecord != n, 140*3807631bSJohn Baldwin ("%s: merging start of record (%p) into previous mbuf (%p)", 141*3807631bSJohn Baldwin __func__, n, m)); 142*3807631bSJohn Baldwin m_copydata(n, 0, n->m_len, mtodo(m, m->m_len)); 143*3807631bSJohn Baldwin m->m_len += n->m_len; 144*3807631bSJohn Baldwin m->m_next = n->m_next; 145*3807631bSJohn Baldwin m->m_flags |= n->m_flags & M_EOR; 146*3807631bSJohn Baldwin if (sb->sb_mbtail == n) 147*3807631bSJohn Baldwin sb->sb_mbtail = m; 148*3807631bSJohn Baldwin 149*3807631bSJohn Baldwin sb->sb_mbcnt -= MSIZE; 150*3807631bSJohn Baldwin sb->sb_mcnt -= 1; 151*3807631bSJohn Baldwin if (n->m_flags & M_EXT) { 152*3807631bSJohn Baldwin sb->sb_mbcnt -= n->m_ext.ext_size; 153*3807631bSJohn Baldwin sb->sb_ccnt -= 1; 154*3807631bSJohn Baldwin } 155*3807631bSJohn Baldwin m_free(n); 156*3807631bSJohn Baldwin n = m->m_next; 157*3807631bSJohn Baldwin } 158*3807631bSJohn Baldwin } 159*3807631bSJohn Baldwin SBLASTRECORDCHK(sb); 160*3807631bSJohn Baldwin SBLASTMBUFCHK(sb); 161*3807631bSJohn Baldwin } 162*3807631bSJohn Baldwin 163*3807631bSJohn Baldwin /* 16482334850SJohn Baldwin * Mark ready "count" units of I/O starting with "m". Most mbufs 16582334850SJohn Baldwin * count as a single unit of I/O except for EXT_PGS-backed mbufs which 16682334850SJohn Baldwin * can be backed by multiple pages. 1670f9d0a73SGleb Smirnoff */ 1680f9d0a73SGleb Smirnoff int 16982334850SJohn Baldwin sbready(struct sockbuf *sb, struct mbuf *m0, int count) 1700f9d0a73SGleb Smirnoff { 17182334850SJohn Baldwin struct mbuf *m; 1720f9d0a73SGleb Smirnoff u_int blocker; 1730f9d0a73SGleb Smirnoff 1740f9d0a73SGleb Smirnoff SOCKBUF_LOCK_ASSERT(sb); 1750f9d0a73SGleb Smirnoff KASSERT(sb->sb_fnrdy != NULL, ("%s: sb %p NULL fnrdy", __func__, sb)); 17682334850SJohn Baldwin KASSERT(count > 0, ("%s: invalid count %d", __func__, count)); 1770f9d0a73SGleb Smirnoff 17882334850SJohn Baldwin m = m0; 1790f9d0a73SGleb Smirnoff blocker = (sb->sb_fnrdy == m) ? M_BLOCKED : 0; 1800f9d0a73SGleb Smirnoff 18182334850SJohn Baldwin while (count > 0) { 1820f9d0a73SGleb Smirnoff KASSERT(m->m_flags & M_NOTREADY, 1830f9d0a73SGleb Smirnoff ("%s: m %p !M_NOTREADY", __func__, m)); 18482334850SJohn Baldwin if ((m->m_flags & M_EXT) != 0 && 18582334850SJohn Baldwin m->m_ext.ext_type == EXT_PGS) { 18682334850SJohn Baldwin if (count < m->m_ext.ext_pgs->nrdy) { 18782334850SJohn Baldwin m->m_ext.ext_pgs->nrdy -= count; 18882334850SJohn Baldwin count = 0; 18982334850SJohn Baldwin break; 19082334850SJohn Baldwin } 19182334850SJohn Baldwin count -= m->m_ext.ext_pgs->nrdy; 19282334850SJohn Baldwin m->m_ext.ext_pgs->nrdy = 0; 19382334850SJohn Baldwin } else 19482334850SJohn Baldwin count--; 19582334850SJohn Baldwin 1960f9d0a73SGleb Smirnoff m->m_flags &= ~(M_NOTREADY | blocker); 1970f9d0a73SGleb Smirnoff if (blocker) 1980f9d0a73SGleb Smirnoff sb->sb_acc += m->m_len; 19982334850SJohn Baldwin m = m->m_next; 2000f9d0a73SGleb Smirnoff } 2010f9d0a73SGleb Smirnoff 20282334850SJohn Baldwin /* 20382334850SJohn Baldwin * If the first mbuf is still not fully ready because only 20482334850SJohn Baldwin * some of its backing pages were readied, no further progress 20582334850SJohn Baldwin * can be made. 20682334850SJohn Baldwin */ 20782334850SJohn Baldwin if (m0 == m) { 20882334850SJohn Baldwin MPASS(m->m_flags & M_NOTREADY); 2090f9d0a73SGleb Smirnoff return (EINPROGRESS); 21082334850SJohn Baldwin } 21182334850SJohn Baldwin 21282334850SJohn Baldwin if (!blocker) { 213*3807631bSJohn Baldwin sbready_compress(sb, m0, m); 21482334850SJohn Baldwin return (EINPROGRESS); 21582334850SJohn Baldwin } 2160f9d0a73SGleb Smirnoff 2170f9d0a73SGleb Smirnoff /* This one was blocking all the queue. */ 2180f9d0a73SGleb Smirnoff for (; m && (m->m_flags & M_NOTREADY) == 0; m = m->m_next) { 2190f9d0a73SGleb Smirnoff KASSERT(m->m_flags & M_BLOCKED, 2200f9d0a73SGleb Smirnoff ("%s: m %p !M_BLOCKED", __func__, m)); 2210f9d0a73SGleb Smirnoff m->m_flags &= ~M_BLOCKED; 2220f9d0a73SGleb Smirnoff sb->sb_acc += m->m_len; 2230f9d0a73SGleb Smirnoff } 2240f9d0a73SGleb Smirnoff 2250f9d0a73SGleb Smirnoff sb->sb_fnrdy = m; 226*3807631bSJohn Baldwin sbready_compress(sb, m0, m); 2270f9d0a73SGleb Smirnoff 2280f9d0a73SGleb Smirnoff return (0); 2290f9d0a73SGleb Smirnoff } 2300f9d0a73SGleb Smirnoff 2310f9d0a73SGleb Smirnoff /* 2328967b220SGleb Smirnoff * Adjust sockbuf state reflecting allocation of m. 2338967b220SGleb Smirnoff */ 2348967b220SGleb Smirnoff void 2358967b220SGleb Smirnoff sballoc(struct sockbuf *sb, struct mbuf *m) 2368967b220SGleb Smirnoff { 2378967b220SGleb Smirnoff 2388967b220SGleb Smirnoff SOCKBUF_LOCK_ASSERT(sb); 2398967b220SGleb Smirnoff 2400f9d0a73SGleb Smirnoff sb->sb_ccc += m->m_len; 2410f9d0a73SGleb Smirnoff 2420f9d0a73SGleb Smirnoff if (sb->sb_fnrdy == NULL) { 2430f9d0a73SGleb Smirnoff if (m->m_flags & M_NOTREADY) 2440f9d0a73SGleb Smirnoff sb->sb_fnrdy = m; 2450f9d0a73SGleb Smirnoff else 2460f9d0a73SGleb Smirnoff sb->sb_acc += m->m_len; 2470f9d0a73SGleb Smirnoff } else 2480f9d0a73SGleb Smirnoff m->m_flags |= M_BLOCKED; 2498967b220SGleb Smirnoff 2508967b220SGleb Smirnoff if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA) 2518967b220SGleb Smirnoff sb->sb_ctl += m->m_len; 2528967b220SGleb Smirnoff 2538967b220SGleb Smirnoff sb->sb_mbcnt += MSIZE; 2548967b220SGleb Smirnoff sb->sb_mcnt += 1; 2558967b220SGleb Smirnoff 2568967b220SGleb Smirnoff if (m->m_flags & M_EXT) { 2578967b220SGleb Smirnoff sb->sb_mbcnt += m->m_ext.ext_size; 2588967b220SGleb Smirnoff sb->sb_ccnt += 1; 2598967b220SGleb Smirnoff } 2608967b220SGleb Smirnoff } 2618967b220SGleb Smirnoff 2628967b220SGleb Smirnoff /* 2638967b220SGleb Smirnoff * Adjust sockbuf state reflecting freeing of m. 2648967b220SGleb Smirnoff */ 2658967b220SGleb Smirnoff void 2668967b220SGleb Smirnoff sbfree(struct sockbuf *sb, struct mbuf *m) 2678967b220SGleb Smirnoff { 2688967b220SGleb Smirnoff 2698967b220SGleb Smirnoff #if 0 /* XXX: not yet: soclose() call path comes here w/o lock. */ 2708967b220SGleb Smirnoff SOCKBUF_LOCK_ASSERT(sb); 2718967b220SGleb Smirnoff #endif 2728967b220SGleb Smirnoff 2730f9d0a73SGleb Smirnoff sb->sb_ccc -= m->m_len; 2740f9d0a73SGleb Smirnoff 2750f9d0a73SGleb Smirnoff if (!(m->m_flags & M_NOTAVAIL)) 2760f9d0a73SGleb Smirnoff sb->sb_acc -= m->m_len; 2770f9d0a73SGleb Smirnoff 2780f9d0a73SGleb Smirnoff if (m == sb->sb_fnrdy) { 2790f9d0a73SGleb Smirnoff struct mbuf *n; 2800f9d0a73SGleb Smirnoff 2810f9d0a73SGleb Smirnoff KASSERT(m->m_flags & M_NOTREADY, 2820f9d0a73SGleb Smirnoff ("%s: m %p !M_NOTREADY", __func__, m)); 2830f9d0a73SGleb Smirnoff 2840f9d0a73SGleb Smirnoff n = m->m_next; 2850f9d0a73SGleb Smirnoff while (n != NULL && !(n->m_flags & M_NOTREADY)) { 2860f9d0a73SGleb Smirnoff n->m_flags &= ~M_BLOCKED; 2870f9d0a73SGleb Smirnoff sb->sb_acc += n->m_len; 2880f9d0a73SGleb Smirnoff n = n->m_next; 2890f9d0a73SGleb Smirnoff } 2900f9d0a73SGleb Smirnoff sb->sb_fnrdy = n; 2910f9d0a73SGleb Smirnoff } 2928967b220SGleb Smirnoff 2938967b220SGleb Smirnoff if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA) 2948967b220SGleb Smirnoff sb->sb_ctl -= m->m_len; 2958967b220SGleb Smirnoff 2968967b220SGleb Smirnoff sb->sb_mbcnt -= MSIZE; 2978967b220SGleb Smirnoff sb->sb_mcnt -= 1; 2988967b220SGleb Smirnoff if (m->m_flags & M_EXT) { 2998967b220SGleb Smirnoff sb->sb_mbcnt -= m->m_ext.ext_size; 3008967b220SGleb Smirnoff sb->sb_ccnt -= 1; 3018967b220SGleb Smirnoff } 3028967b220SGleb Smirnoff 3038967b220SGleb Smirnoff if (sb->sb_sndptr == m) { 3048967b220SGleb Smirnoff sb->sb_sndptr = NULL; 3058967b220SGleb Smirnoff sb->sb_sndptroff = 0; 3068967b220SGleb Smirnoff } 3078967b220SGleb Smirnoff if (sb->sb_sndptroff != 0) 3088967b220SGleb Smirnoff sb->sb_sndptroff -= m->m_len; 3098967b220SGleb Smirnoff } 3108967b220SGleb Smirnoff 3118967b220SGleb Smirnoff /* 312050ac265SRobert Watson * Socantsendmore indicates that no more data will be sent on the socket; it 313050ac265SRobert Watson * would normally be applied to a socket when the user informs the system 314050ac265SRobert Watson * that no more data is to be sent, by the protocol code (in case 315050ac265SRobert Watson * PRU_SHUTDOWN). Socantrcvmore indicates that no more data will be 316050ac265SRobert Watson * received, and will normally be applied to the socket by a protocol when it 317050ac265SRobert Watson * detects that the peer will send no more data. Data queued for reading in 318050ac265SRobert Watson * the socket may yet be read. 319df8bae1dSRodney W. Grimes */ 320a34b7046SRobert Watson void 321050ac265SRobert Watson socantsendmore_locked(struct socket *so) 322a34b7046SRobert Watson { 323a34b7046SRobert Watson 324a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(&so->so_snd); 325a34b7046SRobert Watson 326a34b7046SRobert Watson so->so_snd.sb_state |= SBS_CANTSENDMORE; 327a34b7046SRobert Watson sowwakeup_locked(so); 328a34b7046SRobert Watson mtx_assert(SOCKBUF_MTX(&so->so_snd), MA_NOTOWNED); 329a34b7046SRobert Watson } 330df8bae1dSRodney W. Grimes 33126f9a767SRodney W. Grimes void 332050ac265SRobert Watson socantsendmore(struct socket *so) 333df8bae1dSRodney W. Grimes { 334df8bae1dSRodney W. Grimes 335a34b7046SRobert Watson SOCKBUF_LOCK(&so->so_snd); 336a34b7046SRobert Watson socantsendmore_locked(so); 337a34b7046SRobert Watson mtx_assert(SOCKBUF_MTX(&so->so_snd), MA_NOTOWNED); 338a34b7046SRobert Watson } 339a34b7046SRobert Watson 340a34b7046SRobert Watson void 341050ac265SRobert Watson socantrcvmore_locked(struct socket *so) 342a34b7046SRobert Watson { 343a34b7046SRobert Watson 344a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(&so->so_rcv); 345a34b7046SRobert Watson 346a34b7046SRobert Watson so->so_rcv.sb_state |= SBS_CANTRCVMORE; 347a34b7046SRobert Watson sorwakeup_locked(so); 348a34b7046SRobert Watson mtx_assert(SOCKBUF_MTX(&so->so_rcv), MA_NOTOWNED); 349df8bae1dSRodney W. Grimes } 350df8bae1dSRodney W. Grimes 35126f9a767SRodney W. Grimes void 352050ac265SRobert Watson socantrcvmore(struct socket *so) 353df8bae1dSRodney W. Grimes { 354df8bae1dSRodney W. Grimes 355a34b7046SRobert Watson SOCKBUF_LOCK(&so->so_rcv); 356a34b7046SRobert Watson socantrcvmore_locked(so); 357a34b7046SRobert Watson mtx_assert(SOCKBUF_MTX(&so->so_rcv), MA_NOTOWNED); 358df8bae1dSRodney W. Grimes } 359df8bae1dSRodney W. Grimes 360df8bae1dSRodney W. Grimes /* 361df8bae1dSRodney W. Grimes * Wait for data to arrive at/drain from a socket buffer. 362df8bae1dSRodney W. Grimes */ 36326f9a767SRodney W. Grimes int 364050ac265SRobert Watson sbwait(struct sockbuf *sb) 365df8bae1dSRodney W. Grimes { 366df8bae1dSRodney W. Grimes 36731f555a1SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 36831f555a1SRobert Watson 369df8bae1dSRodney W. Grimes sb->sb_flags |= SB_WAIT; 3700f9d0a73SGleb Smirnoff return (msleep_sbt(&sb->sb_acc, &sb->sb_mtx, 37147daf5d5SBruce Evans (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait", 3727729cbf1SDavide Italiano sb->sb_timeo, 0, 0)); 373df8bae1dSRodney W. Grimes } 374df8bae1dSRodney W. Grimes 37526f9a767SRodney W. Grimes int 3767abab911SRobert Watson sblock(struct sockbuf *sb, int flags) 377df8bae1dSRodney W. Grimes { 378df8bae1dSRodney W. Grimes 379265de5bbSRobert Watson KASSERT((flags & SBL_VALID) == flags, 380265de5bbSRobert Watson ("sblock: flags invalid (0x%x)", flags)); 381265de5bbSRobert Watson 382265de5bbSRobert Watson if (flags & SBL_WAIT) { 383265de5bbSRobert Watson if ((sb->sb_flags & SB_NOINTR) || 384265de5bbSRobert Watson (flags & SBL_NOINTR)) { 3857abab911SRobert Watson sx_xlock(&sb->sb_sx); 386df8bae1dSRodney W. Grimes return (0); 387049c3b6cSRobert Watson } 388049c3b6cSRobert Watson return (sx_xlock_sig(&sb->sb_sx)); 3897abab911SRobert Watson } else { 3907abab911SRobert Watson if (sx_try_xlock(&sb->sb_sx) == 0) 3917abab911SRobert Watson return (EWOULDBLOCK); 3927abab911SRobert Watson return (0); 3937abab911SRobert Watson } 3947abab911SRobert Watson } 3957abab911SRobert Watson 3967abab911SRobert Watson void 3977abab911SRobert Watson sbunlock(struct sockbuf *sb) 3987abab911SRobert Watson { 3997abab911SRobert Watson 4007abab911SRobert Watson sx_xunlock(&sb->sb_sx); 401df8bae1dSRodney W. Grimes } 402df8bae1dSRodney W. Grimes 403df8bae1dSRodney W. Grimes /* 404050ac265SRobert Watson * Wakeup processes waiting on a socket buffer. Do asynchronous notification 405050ac265SRobert Watson * via SIGIO if the socket has the SS_ASYNC flag set. 406a34b7046SRobert Watson * 407a34b7046SRobert Watson * Called with the socket buffer lock held; will release the lock by the end 408a34b7046SRobert Watson * of the function. This allows the caller to acquire the socket buffer lock 409a34b7046SRobert Watson * while testing for the need for various sorts of wakeup and hold it through 410a34b7046SRobert Watson * to the point where it's no longer required. We currently hold the lock 411a34b7046SRobert Watson * through calls out to other subsystems (with the exception of kqueue), and 412a34b7046SRobert Watson * then release it to avoid lock order issues. It's not clear that's 413a34b7046SRobert Watson * correct. 414df8bae1dSRodney W. Grimes */ 41526f9a767SRodney W. Grimes void 416050ac265SRobert Watson sowakeup(struct socket *so, struct sockbuf *sb) 417df8bae1dSRodney W. Grimes { 41874fb0ba7SJohn Baldwin int ret; 419d48d4b25SSeigo Tanimura 420a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 421a34b7046SRobert Watson 422779f106aSGleb Smirnoff selwakeuppri(sb->sb_sel, PSOCK); 423779f106aSGleb Smirnoff if (!SEL_WAITING(sb->sb_sel)) 424df8bae1dSRodney W. Grimes sb->sb_flags &= ~SB_SEL; 425df8bae1dSRodney W. Grimes if (sb->sb_flags & SB_WAIT) { 426df8bae1dSRodney W. Grimes sb->sb_flags &= ~SB_WAIT; 4270f9d0a73SGleb Smirnoff wakeup(&sb->sb_acc); 428df8bae1dSRodney W. Grimes } 429779f106aSGleb Smirnoff KNOTE_LOCKED(&sb->sb_sel->si_note, 0); 43098c92369SNavdeep Parhar if (sb->sb_upcall != NULL) { 431eb1b1807SGleb Smirnoff ret = sb->sb_upcall(so, sb->sb_upcallarg, M_NOWAIT); 43274fb0ba7SJohn Baldwin if (ret == SU_ISCONNECTED) { 43374fb0ba7SJohn Baldwin KASSERT(sb == &so->so_rcv, 43474fb0ba7SJohn Baldwin ("SO_SND upcall returned SU_ISCONNECTED")); 43574fb0ba7SJohn Baldwin soupcall_clear(so, SO_RCV); 43674fb0ba7SJohn Baldwin } 43774fb0ba7SJohn Baldwin } else 43874fb0ba7SJohn Baldwin ret = SU_OK; 4394cc20ab1SSeigo Tanimura if (sb->sb_flags & SB_AIO) 440f3215338SJohn Baldwin sowakeup_aio(so, sb); 44174fb0ba7SJohn Baldwin SOCKBUF_UNLOCK(sb); 442555b3e2fSGleb Smirnoff if (ret == SU_ISCONNECTED) 44374fb0ba7SJohn Baldwin soisconnected(so); 44474fb0ba7SJohn Baldwin if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL) 44574fb0ba7SJohn Baldwin pgsigio(&so->so_sigio, SIGIO, 0); 446a34b7046SRobert Watson mtx_assert(SOCKBUF_MTX(sb), MA_NOTOWNED); 447df8bae1dSRodney W. Grimes } 448df8bae1dSRodney W. Grimes 449df8bae1dSRodney W. Grimes /* 450df8bae1dSRodney W. Grimes * Socket buffer (struct sockbuf) utility routines. 451df8bae1dSRodney W. Grimes * 452050ac265SRobert Watson * Each socket contains two socket buffers: one for sending data and one for 453050ac265SRobert Watson * receiving data. Each buffer contains a queue of mbufs, information about 454050ac265SRobert Watson * the number of mbufs and amount of data in the queue, and other fields 455050ac265SRobert Watson * allowing select() statements and notification on data availability to be 456050ac265SRobert Watson * implemented. 457df8bae1dSRodney W. Grimes * 458050ac265SRobert Watson * Data stored in a socket buffer is maintained as a list of records. Each 459050ac265SRobert Watson * record is a list of mbufs chained together with the m_next field. Records 460050ac265SRobert Watson * are chained together with the m_nextpkt field. The upper level routine 461050ac265SRobert Watson * soreceive() expects the following conventions to be observed when placing 462050ac265SRobert Watson * information in the receive buffer: 463df8bae1dSRodney W. Grimes * 464050ac265SRobert Watson * 1. If the protocol requires each message be preceded by the sender's name, 465050ac265SRobert Watson * then a record containing that name must be present before any 466050ac265SRobert Watson * associated data (mbuf's must be of type MT_SONAME). 467050ac265SRobert Watson * 2. If the protocol supports the exchange of ``access rights'' (really just 468050ac265SRobert Watson * additional data associated with the message), and there are ``rights'' 469050ac265SRobert Watson * to be received, then a record containing this data should be present 470050ac265SRobert Watson * (mbuf's must be of type MT_RIGHTS). 471050ac265SRobert Watson * 3. If a name or rights record exists, then it must be followed by a data 472050ac265SRobert Watson * record, perhaps of zero length. 473df8bae1dSRodney W. Grimes * 474df8bae1dSRodney W. Grimes * Before using a new socket structure it is first necessary to reserve 475df8bae1dSRodney W. Grimes * buffer space to the socket, by calling sbreserve(). This should commit 476df8bae1dSRodney W. Grimes * some of the available buffer space in the system buffer pool for the 477050ac265SRobert Watson * socket (currently, it does nothing but enforce limits). The space should 478050ac265SRobert Watson * be released by calling sbrelease() when the socket is destroyed. 479df8bae1dSRodney W. Grimes */ 48026f9a767SRodney W. Grimes int 481050ac265SRobert Watson soreserve(struct socket *so, u_long sndcc, u_long rcvcc) 482df8bae1dSRodney W. Grimes { 483b40ce416SJulian Elischer struct thread *td = curthread; 484df8bae1dSRodney W. Grimes 4853f11a2f3SRobert Watson SOCKBUF_LOCK(&so->so_snd); 4869535efc0SRobert Watson SOCKBUF_LOCK(&so->so_rcv); 4873f11a2f3SRobert Watson if (sbreserve_locked(&so->so_snd, sndcc, so, td) == 0) 4883f11a2f3SRobert Watson goto bad; 4893f11a2f3SRobert Watson if (sbreserve_locked(&so->so_rcv, rcvcc, so, td) == 0) 4903f11a2f3SRobert Watson goto bad2; 491df8bae1dSRodney W. Grimes if (so->so_rcv.sb_lowat == 0) 492df8bae1dSRodney W. Grimes so->so_rcv.sb_lowat = 1; 493df8bae1dSRodney W. Grimes if (so->so_snd.sb_lowat == 0) 494df8bae1dSRodney W. Grimes so->so_snd.sb_lowat = MCLBYTES; 495df8bae1dSRodney W. Grimes if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat) 496df8bae1dSRodney W. Grimes so->so_snd.sb_lowat = so->so_snd.sb_hiwat; 4973f11a2f3SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 4989535efc0SRobert Watson SOCKBUF_UNLOCK(&so->so_snd); 499df8bae1dSRodney W. Grimes return (0); 500df8bae1dSRodney W. Grimes bad2: 5013f11a2f3SRobert Watson sbrelease_locked(&so->so_snd, so); 502df8bae1dSRodney W. Grimes bad: 5033f11a2f3SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 5043f11a2f3SRobert Watson SOCKBUF_UNLOCK(&so->so_snd); 505df8bae1dSRodney W. Grimes return (ENOBUFS); 506df8bae1dSRodney W. Grimes } 507df8bae1dSRodney W. Grimes 50879cb7eb4SDavid Greenman static int 50979cb7eb4SDavid Greenman sysctl_handle_sb_max(SYSCTL_HANDLER_ARGS) 51079cb7eb4SDavid Greenman { 51179cb7eb4SDavid Greenman int error = 0; 51286a93d51SJohn Baldwin u_long tmp_sb_max = sb_max; 51379cb7eb4SDavid Greenman 51486a93d51SJohn Baldwin error = sysctl_handle_long(oidp, &tmp_sb_max, arg2, req); 51579cb7eb4SDavid Greenman if (error || !req->newptr) 51679cb7eb4SDavid Greenman return (error); 51786a93d51SJohn Baldwin if (tmp_sb_max < MSIZE + MCLBYTES) 51879cb7eb4SDavid Greenman return (EINVAL); 51986a93d51SJohn Baldwin sb_max = tmp_sb_max; 52079cb7eb4SDavid Greenman sb_max_adj = (u_quad_t)sb_max * MCLBYTES / (MSIZE + MCLBYTES); 52179cb7eb4SDavid Greenman return (0); 52279cb7eb4SDavid Greenman } 52379cb7eb4SDavid Greenman 524df8bae1dSRodney W. Grimes /* 525050ac265SRobert Watson * Allot mbufs to a sockbuf. Attempt to scale mbmax so that mbcnt doesn't 526050ac265SRobert Watson * become limiting if buffering efficiency is near the normal case. 527df8bae1dSRodney W. Grimes */ 52826f9a767SRodney W. Grimes int 529050ac265SRobert Watson sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so, 530050ac265SRobert Watson struct thread *td) 531df8bae1dSRodney W. Grimes { 53291d5354aSJohn Baldwin rlim_t sbsize_limit; 533ecf72308SBrian Feldman 5343f11a2f3SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 5353f11a2f3SRobert Watson 536ecf72308SBrian Feldman /* 5377978014dSRobert Watson * When a thread is passed, we take into account the thread's socket 5387978014dSRobert Watson * buffer size limit. The caller will generally pass curthread, but 5397978014dSRobert Watson * in the TCP input path, NULL will be passed to indicate that no 5407978014dSRobert Watson * appropriate thread resource limits are available. In that case, 5417978014dSRobert Watson * we don't apply a process limit. 542ecf72308SBrian Feldman */ 54379cb7eb4SDavid Greenman if (cc > sb_max_adj) 544df8bae1dSRodney W. Grimes return (0); 54591d5354aSJohn Baldwin if (td != NULL) { 546f6f6d240SMateusz Guzik sbsize_limit = lim_cur(td, RLIMIT_SBSIZE); 54791d5354aSJohn Baldwin } else 54891d5354aSJohn Baldwin sbsize_limit = RLIM_INFINITY; 549f535380cSDon Lewis if (!chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, cc, 55091d5354aSJohn Baldwin sbsize_limit)) 551ecf72308SBrian Feldman return (0); 5524b29bc4fSGarrett Wollman sb->sb_mbmax = min(cc * sb_efficiency, sb_max); 553df8bae1dSRodney W. Grimes if (sb->sb_lowat > sb->sb_hiwat) 554df8bae1dSRodney W. Grimes sb->sb_lowat = sb->sb_hiwat; 555df8bae1dSRodney W. Grimes return (1); 556df8bae1dSRodney W. Grimes } 557df8bae1dSRodney W. Grimes 5583f11a2f3SRobert Watson int 55964290befSGleb Smirnoff sbsetopt(struct socket *so, int cmd, u_long cc) 5603f11a2f3SRobert Watson { 56164290befSGleb Smirnoff struct sockbuf *sb; 56264290befSGleb Smirnoff short *flags; 56364290befSGleb Smirnoff u_int *hiwat, *lowat; 5643f11a2f3SRobert Watson int error; 5653f11a2f3SRobert Watson 566b2037136SMatt Macy sb = NULL; 56764290befSGleb Smirnoff SOCK_LOCK(so); 56864290befSGleb Smirnoff if (SOLISTENING(so)) { 56964290befSGleb Smirnoff switch (cmd) { 57064290befSGleb Smirnoff case SO_SNDLOWAT: 57164290befSGleb Smirnoff case SO_SNDBUF: 57264290befSGleb Smirnoff lowat = &so->sol_sbsnd_lowat; 57364290befSGleb Smirnoff hiwat = &so->sol_sbsnd_hiwat; 57464290befSGleb Smirnoff flags = &so->sol_sbsnd_flags; 57564290befSGleb Smirnoff break; 57664290befSGleb Smirnoff case SO_RCVLOWAT: 57764290befSGleb Smirnoff case SO_RCVBUF: 57864290befSGleb Smirnoff lowat = &so->sol_sbrcv_lowat; 57964290befSGleb Smirnoff hiwat = &so->sol_sbrcv_hiwat; 58064290befSGleb Smirnoff flags = &so->sol_sbrcv_flags; 58164290befSGleb Smirnoff break; 58264290befSGleb Smirnoff } 58364290befSGleb Smirnoff } else { 58464290befSGleb Smirnoff switch (cmd) { 58564290befSGleb Smirnoff case SO_SNDLOWAT: 58664290befSGleb Smirnoff case SO_SNDBUF: 58764290befSGleb Smirnoff sb = &so->so_snd; 58864290befSGleb Smirnoff break; 58964290befSGleb Smirnoff case SO_RCVLOWAT: 59064290befSGleb Smirnoff case SO_RCVBUF: 59164290befSGleb Smirnoff sb = &so->so_rcv; 59264290befSGleb Smirnoff break; 59364290befSGleb Smirnoff } 59464290befSGleb Smirnoff flags = &sb->sb_flags; 59564290befSGleb Smirnoff hiwat = &sb->sb_hiwat; 59664290befSGleb Smirnoff lowat = &sb->sb_lowat; 5973f11a2f3SRobert Watson SOCKBUF_LOCK(sb); 59864290befSGleb Smirnoff } 59964290befSGleb Smirnoff 60064290befSGleb Smirnoff error = 0; 60164290befSGleb Smirnoff switch (cmd) { 60264290befSGleb Smirnoff case SO_SNDBUF: 60364290befSGleb Smirnoff case SO_RCVBUF: 60464290befSGleb Smirnoff if (SOLISTENING(so)) { 60564290befSGleb Smirnoff if (cc > sb_max_adj) { 60664290befSGleb Smirnoff error = ENOBUFS; 60764290befSGleb Smirnoff break; 60864290befSGleb Smirnoff } 60964290befSGleb Smirnoff *hiwat = cc; 61064290befSGleb Smirnoff if (*lowat > *hiwat) 61164290befSGleb Smirnoff *lowat = *hiwat; 61264290befSGleb Smirnoff } else { 61364290befSGleb Smirnoff if (!sbreserve_locked(sb, cc, so, curthread)) 61464290befSGleb Smirnoff error = ENOBUFS; 61564290befSGleb Smirnoff } 61664290befSGleb Smirnoff if (error == 0) 61764290befSGleb Smirnoff *flags &= ~SB_AUTOSIZE; 61864290befSGleb Smirnoff break; 61964290befSGleb Smirnoff case SO_SNDLOWAT: 62064290befSGleb Smirnoff case SO_RCVLOWAT: 62164290befSGleb Smirnoff /* 62264290befSGleb Smirnoff * Make sure the low-water is never greater than the 62364290befSGleb Smirnoff * high-water. 62464290befSGleb Smirnoff */ 62564290befSGleb Smirnoff *lowat = (cc > *hiwat) ? *hiwat : cc; 62664290befSGleb Smirnoff break; 62764290befSGleb Smirnoff } 62864290befSGleb Smirnoff 62964290befSGleb Smirnoff if (!SOLISTENING(so)) 6303f11a2f3SRobert Watson SOCKBUF_UNLOCK(sb); 63164290befSGleb Smirnoff SOCK_UNLOCK(so); 6323f11a2f3SRobert Watson return (error); 6333f11a2f3SRobert Watson } 6343f11a2f3SRobert Watson 635df8bae1dSRodney W. Grimes /* 636df8bae1dSRodney W. Grimes * Free mbufs held by a socket, and reserved mbuf space. 637df8bae1dSRodney W. Grimes */ 6383f0bfcccSRobert Watson void 639050ac265SRobert Watson sbrelease_internal(struct sockbuf *sb, struct socket *so) 640eaa6dfbcSRobert Watson { 641eaa6dfbcSRobert Watson 642eaa6dfbcSRobert Watson sbflush_internal(sb); 643eaa6dfbcSRobert Watson (void)chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, 0, 644eaa6dfbcSRobert Watson RLIM_INFINITY); 645eaa6dfbcSRobert Watson sb->sb_mbmax = 0; 646eaa6dfbcSRobert Watson } 647eaa6dfbcSRobert Watson 64826f9a767SRodney W. Grimes void 649050ac265SRobert Watson sbrelease_locked(struct sockbuf *sb, struct socket *so) 650df8bae1dSRodney W. Grimes { 651df8bae1dSRodney W. Grimes 652a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 653a34b7046SRobert Watson 654eaa6dfbcSRobert Watson sbrelease_internal(sb, so); 655df8bae1dSRodney W. Grimes } 656df8bae1dSRodney W. Grimes 657a34b7046SRobert Watson void 658050ac265SRobert Watson sbrelease(struct sockbuf *sb, struct socket *so) 659a34b7046SRobert Watson { 660a34b7046SRobert Watson 661a34b7046SRobert Watson SOCKBUF_LOCK(sb); 662a34b7046SRobert Watson sbrelease_locked(sb, so); 663a34b7046SRobert Watson SOCKBUF_UNLOCK(sb); 664a34b7046SRobert Watson } 665eaa6dfbcSRobert Watson 666eaa6dfbcSRobert Watson void 667050ac265SRobert Watson sbdestroy(struct sockbuf *sb, struct socket *so) 668eaa6dfbcSRobert Watson { 669eaa6dfbcSRobert Watson 670eaa6dfbcSRobert Watson sbrelease_internal(sb, so); 671eaa6dfbcSRobert Watson } 672eaa6dfbcSRobert Watson 673df8bae1dSRodney W. Grimes /* 674050ac265SRobert Watson * Routines to add and remove data from an mbuf queue. 675df8bae1dSRodney W. Grimes * 676050ac265SRobert Watson * The routines sbappend() or sbappendrecord() are normally called to append 677050ac265SRobert Watson * new mbufs to a socket buffer, after checking that adequate space is 678050ac265SRobert Watson * available, comparing the function sbspace() with the amount of data to be 679050ac265SRobert Watson * added. sbappendrecord() differs from sbappend() in that data supplied is 680050ac265SRobert Watson * treated as the beginning of a new record. To place a sender's address, 681050ac265SRobert Watson * optional access rights, and data in a socket receive buffer, 682050ac265SRobert Watson * sbappendaddr() should be used. To place access rights and data in a 683050ac265SRobert Watson * socket receive buffer, sbappendrights() should be used. In either case, 684050ac265SRobert Watson * the new data begins a new record. Note that unlike sbappend() and 685050ac265SRobert Watson * sbappendrecord(), these routines check for the caller that there will be 686050ac265SRobert Watson * enough space to store the data. Each fails if there is not enough space, 687050ac265SRobert Watson * or if it cannot find mbufs to store additional information in. 688df8bae1dSRodney W. Grimes * 689050ac265SRobert Watson * Reliable protocols may use the socket send buffer to hold data awaiting 690050ac265SRobert Watson * acknowledgement. Data is normally copied from a socket send buffer in a 691050ac265SRobert Watson * protocol with m_copy for output to a peer, and then removing the data from 692050ac265SRobert Watson * the socket buffer with sbdrop() or sbdroprecord() when the data is 693050ac265SRobert Watson * acknowledged by the peer. 694df8bae1dSRodney W. Grimes */ 695395bb186SSam Leffler #ifdef SOCKBUF_DEBUG 696395bb186SSam Leffler void 697395bb186SSam Leffler sblastrecordchk(struct sockbuf *sb, const char *file, int line) 698395bb186SSam Leffler { 699395bb186SSam Leffler struct mbuf *m = sb->sb_mb; 700395bb186SSam Leffler 701a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 702a34b7046SRobert Watson 703395bb186SSam Leffler while (m && m->m_nextpkt) 704395bb186SSam Leffler m = m->m_nextpkt; 705395bb186SSam Leffler 706395bb186SSam Leffler if (m != sb->sb_lastrecord) { 707395bb186SSam Leffler printf("%s: sb_mb %p sb_lastrecord %p last %p\n", 708395bb186SSam Leffler __func__, sb->sb_mb, sb->sb_lastrecord, m); 709395bb186SSam Leffler printf("packet chain:\n"); 710395bb186SSam Leffler for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt) 711395bb186SSam Leffler printf("\t%p\n", m); 712395bb186SSam Leffler panic("%s from %s:%u", __func__, file, line); 713395bb186SSam Leffler } 714395bb186SSam Leffler } 715395bb186SSam Leffler 716395bb186SSam Leffler void 717395bb186SSam Leffler sblastmbufchk(struct sockbuf *sb, const char *file, int line) 718395bb186SSam Leffler { 719395bb186SSam Leffler struct mbuf *m = sb->sb_mb; 720395bb186SSam Leffler struct mbuf *n; 721395bb186SSam Leffler 722a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 723a34b7046SRobert Watson 724395bb186SSam Leffler while (m && m->m_nextpkt) 725395bb186SSam Leffler m = m->m_nextpkt; 726395bb186SSam Leffler 727395bb186SSam Leffler while (m && m->m_next) 728395bb186SSam Leffler m = m->m_next; 729395bb186SSam Leffler 730395bb186SSam Leffler if (m != sb->sb_mbtail) { 731395bb186SSam Leffler printf("%s: sb_mb %p sb_mbtail %p last %p\n", 732395bb186SSam Leffler __func__, sb->sb_mb, sb->sb_mbtail, m); 733395bb186SSam Leffler printf("packet tree:\n"); 734395bb186SSam Leffler for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt) { 735395bb186SSam Leffler printf("\t"); 736395bb186SSam Leffler for (n = m; n != NULL; n = n->m_next) 737395bb186SSam Leffler printf("%p ", n); 738395bb186SSam Leffler printf("\n"); 739395bb186SSam Leffler } 740395bb186SSam Leffler panic("%s from %s:%u", __func__, file, line); 741395bb186SSam Leffler } 742395bb186SSam Leffler } 743395bb186SSam Leffler #endif /* SOCKBUF_DEBUG */ 744395bb186SSam Leffler 745395bb186SSam Leffler #define SBLINKRECORD(sb, m0) do { \ 746a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); \ 747395bb186SSam Leffler if ((sb)->sb_lastrecord != NULL) \ 748395bb186SSam Leffler (sb)->sb_lastrecord->m_nextpkt = (m0); \ 749395bb186SSam Leffler else \ 750395bb186SSam Leffler (sb)->sb_mb = (m0); \ 751395bb186SSam Leffler (sb)->sb_lastrecord = (m0); \ 752395bb186SSam Leffler } while (/*CONSTCOND*/0) 753395bb186SSam Leffler 754df8bae1dSRodney W. Grimes /* 755050ac265SRobert Watson * Append mbuf chain m to the last record in the socket buffer sb. The 756050ac265SRobert Watson * additional space associated the mbuf chain is recorded in sb. Empty mbufs 757050ac265SRobert Watson * are discarded and mbufs are compacted where possible. 758df8bae1dSRodney W. Grimes */ 75926f9a767SRodney W. Grimes void 760829fae90SGleb Smirnoff sbappend_locked(struct sockbuf *sb, struct mbuf *m, int flags) 761df8bae1dSRodney W. Grimes { 762050ac265SRobert Watson struct mbuf *n; 763df8bae1dSRodney W. Grimes 764a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 765a34b7046SRobert Watson 766b85f65afSPedro F. Giffuni if (m == NULL) 767df8bae1dSRodney W. Grimes return; 768829fae90SGleb Smirnoff sbm_clrprotoflags(m, flags); 769395bb186SSam Leffler SBLASTRECORDCHK(sb); 770797f2d22SPoul-Henning Kamp n = sb->sb_mb; 771797f2d22SPoul-Henning Kamp if (n) { 772df8bae1dSRodney W. Grimes while (n->m_nextpkt) 773df8bae1dSRodney W. Grimes n = n->m_nextpkt; 774df8bae1dSRodney W. Grimes do { 775df8bae1dSRodney W. Grimes if (n->m_flags & M_EOR) { 776a34b7046SRobert Watson sbappendrecord_locked(sb, m); /* XXXXXX!!!! */ 777df8bae1dSRodney W. Grimes return; 778df8bae1dSRodney W. Grimes } 779df8bae1dSRodney W. Grimes } while (n->m_next && (n = n->m_next)); 780395bb186SSam Leffler } else { 781395bb186SSam Leffler /* 782395bb186SSam Leffler * XXX Would like to simply use sb_mbtail here, but 783395bb186SSam Leffler * XXX I need to verify that I won't miss an EOR that 784395bb186SSam Leffler * XXX way. 785395bb186SSam Leffler */ 786395bb186SSam Leffler if ((n = sb->sb_lastrecord) != NULL) { 787395bb186SSam Leffler do { 788395bb186SSam Leffler if (n->m_flags & M_EOR) { 789a34b7046SRobert Watson sbappendrecord_locked(sb, m); /* XXXXXX!!!! */ 790395bb186SSam Leffler return; 791395bb186SSam Leffler } 792395bb186SSam Leffler } while (n->m_next && (n = n->m_next)); 793395bb186SSam Leffler } else { 794395bb186SSam Leffler /* 795395bb186SSam Leffler * If this is the first record in the socket buffer, 796395bb186SSam Leffler * it's also the last record. 797395bb186SSam Leffler */ 798395bb186SSam Leffler sb->sb_lastrecord = m; 799395bb186SSam Leffler } 800df8bae1dSRodney W. Grimes } 801df8bae1dSRodney W. Grimes sbcompress(sb, m, n); 802395bb186SSam Leffler SBLASTRECORDCHK(sb); 803395bb186SSam Leffler } 804395bb186SSam Leffler 805395bb186SSam Leffler /* 806050ac265SRobert Watson * Append mbuf chain m to the last record in the socket buffer sb. The 807050ac265SRobert Watson * additional space associated the mbuf chain is recorded in sb. Empty mbufs 808050ac265SRobert Watson * are discarded and mbufs are compacted where possible. 809a34b7046SRobert Watson */ 810a34b7046SRobert Watson void 811829fae90SGleb Smirnoff sbappend(struct sockbuf *sb, struct mbuf *m, int flags) 812a34b7046SRobert Watson { 813a34b7046SRobert Watson 814a34b7046SRobert Watson SOCKBUF_LOCK(sb); 815829fae90SGleb Smirnoff sbappend_locked(sb, m, flags); 816a34b7046SRobert Watson SOCKBUF_UNLOCK(sb); 817a34b7046SRobert Watson } 818a34b7046SRobert Watson 819a34b7046SRobert Watson /* 820050ac265SRobert Watson * This version of sbappend() should only be used when the caller absolutely 821050ac265SRobert Watson * knows that there will never be more than one record in the socket buffer, 822050ac265SRobert Watson * that is, a stream protocol (such as TCP). 823395bb186SSam Leffler */ 824395bb186SSam Leffler void 825651e4e6aSGleb Smirnoff sbappendstream_locked(struct sockbuf *sb, struct mbuf *m, int flags) 826395bb186SSam Leffler { 827a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 828395bb186SSam Leffler 829395bb186SSam Leffler KASSERT(m->m_nextpkt == NULL,("sbappendstream 0")); 830395bb186SSam Leffler KASSERT(sb->sb_mb == sb->sb_lastrecord,("sbappendstream 1")); 831395bb186SSam Leffler 832395bb186SSam Leffler SBLASTMBUFCHK(sb); 833395bb186SSam Leffler 834844cacd1SGleb Smirnoff /* Remove all packet headers and mbuf tags to get a pure data chain. */ 835651e4e6aSGleb Smirnoff m_demote(m, 1, flags & PRUS_NOTREADY ? M_NOTREADY : 0); 836844cacd1SGleb Smirnoff 837395bb186SSam Leffler sbcompress(sb, m, sb->sb_mbtail); 838395bb186SSam Leffler 839395bb186SSam Leffler sb->sb_lastrecord = sb->sb_mb; 840395bb186SSam Leffler SBLASTRECORDCHK(sb); 841df8bae1dSRodney W. Grimes } 842df8bae1dSRodney W. Grimes 843a34b7046SRobert Watson /* 844050ac265SRobert Watson * This version of sbappend() should only be used when the caller absolutely 845050ac265SRobert Watson * knows that there will never be more than one record in the socket buffer, 846050ac265SRobert Watson * that is, a stream protocol (such as TCP). 847a34b7046SRobert Watson */ 848a34b7046SRobert Watson void 849651e4e6aSGleb Smirnoff sbappendstream(struct sockbuf *sb, struct mbuf *m, int flags) 850a34b7046SRobert Watson { 851a34b7046SRobert Watson 852a34b7046SRobert Watson SOCKBUF_LOCK(sb); 853651e4e6aSGleb Smirnoff sbappendstream_locked(sb, m, flags); 854a34b7046SRobert Watson SOCKBUF_UNLOCK(sb); 855a34b7046SRobert Watson } 856a34b7046SRobert Watson 857df8bae1dSRodney W. Grimes #ifdef SOCKBUF_DEBUG 85826f9a767SRodney W. Grimes void 85957f43a45SGleb Smirnoff sbcheck(struct sockbuf *sb, const char *file, int line) 860df8bae1dSRodney W. Grimes { 8610f9d0a73SGleb Smirnoff struct mbuf *m, *n, *fnrdy; 8620f9d0a73SGleb Smirnoff u_long acc, ccc, mbcnt; 863df8bae1dSRodney W. Grimes 864a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 865a34b7046SRobert Watson 8660f9d0a73SGleb Smirnoff acc = ccc = mbcnt = 0; 8670f9d0a73SGleb Smirnoff fnrdy = NULL; 86857f43a45SGleb Smirnoff 8690931333fSBill Fenner for (m = sb->sb_mb; m; m = n) { 8700931333fSBill Fenner n = m->m_nextpkt; 8710931333fSBill Fenner for (; m; m = m->m_next) { 87257f43a45SGleb Smirnoff if (m->m_len == 0) { 87357f43a45SGleb Smirnoff printf("sb %p empty mbuf %p\n", sb, m); 87457f43a45SGleb Smirnoff goto fail; 87557f43a45SGleb Smirnoff } 8760f9d0a73SGleb Smirnoff if ((m->m_flags & M_NOTREADY) && fnrdy == NULL) { 8770f9d0a73SGleb Smirnoff if (m != sb->sb_fnrdy) { 8780f9d0a73SGleb Smirnoff printf("sb %p: fnrdy %p != m %p\n", 8790f9d0a73SGleb Smirnoff sb, sb->sb_fnrdy, m); 8800f9d0a73SGleb Smirnoff goto fail; 8810f9d0a73SGleb Smirnoff } 8820f9d0a73SGleb Smirnoff fnrdy = m; 8830f9d0a73SGleb Smirnoff } 8840f9d0a73SGleb Smirnoff if (fnrdy) { 8850f9d0a73SGleb Smirnoff if (!(m->m_flags & M_NOTAVAIL)) { 8860f9d0a73SGleb Smirnoff printf("sb %p: fnrdy %p, m %p is avail\n", 8870f9d0a73SGleb Smirnoff sb, sb->sb_fnrdy, m); 8880f9d0a73SGleb Smirnoff goto fail; 8890f9d0a73SGleb Smirnoff } 8900f9d0a73SGleb Smirnoff } else 8910f9d0a73SGleb Smirnoff acc += m->m_len; 8920f9d0a73SGleb Smirnoff ccc += m->m_len; 893df8bae1dSRodney W. Grimes mbcnt += MSIZE; 894313861b8SJulian Elischer if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */ 895df8bae1dSRodney W. Grimes mbcnt += m->m_ext.ext_size; 8960931333fSBill Fenner } 897df8bae1dSRodney W. Grimes } 8980f9d0a73SGleb Smirnoff if (acc != sb->sb_acc || ccc != sb->sb_ccc || mbcnt != sb->sb_mbcnt) { 8990f9d0a73SGleb Smirnoff printf("acc %ld/%u ccc %ld/%u mbcnt %ld/%u\n", 9000f9d0a73SGleb Smirnoff acc, sb->sb_acc, ccc, sb->sb_ccc, mbcnt, sb->sb_mbcnt); 90157f43a45SGleb Smirnoff goto fail; 902df8bae1dSRodney W. Grimes } 90357f43a45SGleb Smirnoff return; 90457f43a45SGleb Smirnoff fail: 90557f43a45SGleb Smirnoff panic("%s from %s:%u", __func__, file, line); 906df8bae1dSRodney W. Grimes } 907df8bae1dSRodney W. Grimes #endif 908df8bae1dSRodney W. Grimes 909df8bae1dSRodney W. Grimes /* 910050ac265SRobert Watson * As above, except the mbuf chain begins a new record. 911df8bae1dSRodney W. Grimes */ 91226f9a767SRodney W. Grimes void 913050ac265SRobert Watson sbappendrecord_locked(struct sockbuf *sb, struct mbuf *m0) 914df8bae1dSRodney W. Grimes { 915050ac265SRobert Watson struct mbuf *m; 916df8bae1dSRodney W. Grimes 917a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 918a34b7046SRobert Watson 919b85f65afSPedro F. Giffuni if (m0 == NULL) 920df8bae1dSRodney W. Grimes return; 92153b680caSGleb Smirnoff m_clrprotoflags(m0); 922df8bae1dSRodney W. Grimes /* 923050ac265SRobert Watson * Put the first mbuf on the queue. Note this permits zero length 924050ac265SRobert Watson * records. 925df8bae1dSRodney W. Grimes */ 926df8bae1dSRodney W. Grimes sballoc(sb, m0); 927395bb186SSam Leffler SBLASTRECORDCHK(sb); 928395bb186SSam Leffler SBLINKRECORD(sb, m0); 929e72a94adSMaksim Yevmenkin sb->sb_mbtail = m0; 930df8bae1dSRodney W. Grimes m = m0->m_next; 931df8bae1dSRodney W. Grimes m0->m_next = 0; 932df8bae1dSRodney W. Grimes if (m && (m0->m_flags & M_EOR)) { 933df8bae1dSRodney W. Grimes m0->m_flags &= ~M_EOR; 934df8bae1dSRodney W. Grimes m->m_flags |= M_EOR; 935df8bae1dSRodney W. Grimes } 936e72a94adSMaksim Yevmenkin /* always call sbcompress() so it can do SBLASTMBUFCHK() */ 937df8bae1dSRodney W. Grimes sbcompress(sb, m, m0); 938df8bae1dSRodney W. Grimes } 939df8bae1dSRodney W. Grimes 940df8bae1dSRodney W. Grimes /* 941050ac265SRobert Watson * As above, except the mbuf chain begins a new record. 942a34b7046SRobert Watson */ 943a34b7046SRobert Watson void 944050ac265SRobert Watson sbappendrecord(struct sockbuf *sb, struct mbuf *m0) 945a34b7046SRobert Watson { 946a34b7046SRobert Watson 947a34b7046SRobert Watson SOCKBUF_LOCK(sb); 948a34b7046SRobert Watson sbappendrecord_locked(sb, m0); 949a34b7046SRobert Watson SOCKBUF_UNLOCK(sb); 950a34b7046SRobert Watson } 951a34b7046SRobert Watson 9528de34a88SAlan Somers /* Helper routine that appends data, control, and address to a sockbuf. */ 9538de34a88SAlan Somers static int 9548de34a88SAlan Somers sbappendaddr_locked_internal(struct sockbuf *sb, const struct sockaddr *asa, 9558de34a88SAlan Somers struct mbuf *m0, struct mbuf *control, struct mbuf *ctrl_last) 956df8bae1dSRodney W. Grimes { 957395bb186SSam Leffler struct mbuf *m, *n, *nlast; 958c43cad1aSScott Long #if MSIZE <= 256 959df8bae1dSRodney W. Grimes if (asa->sa_len > MLEN) 960df8bae1dSRodney W. Grimes return (0); 961c43cad1aSScott Long #endif 962c8b59ea7SGleb Smirnoff m = m_get(M_NOWAIT, MT_SONAME); 963c8b59ea7SGleb Smirnoff if (m == NULL) 964df8bae1dSRodney W. Grimes return (0); 965df8bae1dSRodney W. Grimes m->m_len = asa->sa_len; 96680208239SAlfred Perlstein bcopy(asa, mtod(m, caddr_t), asa->sa_len); 967c33a2313SAndrey V. Elsukov if (m0) { 96853b680caSGleb Smirnoff m_clrprotoflags(m0); 96957386f5dSAndrey V. Elsukov m_tag_delete_chain(m0, NULL); 970c33a2313SAndrey V. Elsukov /* 971c33a2313SAndrey V. Elsukov * Clear some persistent info from pkthdr. 972c33a2313SAndrey V. Elsukov * We don't use m_demote(), because some netgraph consumers 973c33a2313SAndrey V. Elsukov * expect M_PKTHDR presence. 974c33a2313SAndrey V. Elsukov */ 975c33a2313SAndrey V. Elsukov m0->m_pkthdr.rcvif = NULL; 976c33a2313SAndrey V. Elsukov m0->m_pkthdr.flowid = 0; 977c33a2313SAndrey V. Elsukov m0->m_pkthdr.csum_flags = 0; 978c33a2313SAndrey V. Elsukov m0->m_pkthdr.fibnum = 0; 979c33a2313SAndrey V. Elsukov m0->m_pkthdr.rsstype = 0; 980c33a2313SAndrey V. Elsukov } 9818de34a88SAlan Somers if (ctrl_last) 9828de34a88SAlan Somers ctrl_last->m_next = m0; /* concatenate data to control */ 983df8bae1dSRodney W. Grimes else 984df8bae1dSRodney W. Grimes control = m0; 985df8bae1dSRodney W. Grimes m->m_next = control; 986395bb186SSam Leffler for (n = m; n->m_next != NULL; n = n->m_next) 987df8bae1dSRodney W. Grimes sballoc(sb, n); 988395bb186SSam Leffler sballoc(sb, n); 989395bb186SSam Leffler nlast = n; 990395bb186SSam Leffler SBLINKRECORD(sb, m); 991395bb186SSam Leffler 992395bb186SSam Leffler sb->sb_mbtail = nlast; 993395bb186SSam Leffler SBLASTMBUFCHK(sb); 994395bb186SSam Leffler 995395bb186SSam Leffler SBLASTRECORDCHK(sb); 996df8bae1dSRodney W. Grimes return (1); 997df8bae1dSRodney W. Grimes } 998df8bae1dSRodney W. Grimes 999a34b7046SRobert Watson /* 1000050ac265SRobert Watson * Append address and data, and optionally, control (ancillary) data to the 1001050ac265SRobert Watson * receive queue of a socket. If present, m0 must include a packet header 1002050ac265SRobert Watson * with total length. Returns 0 if no space in sockbuf or insufficient 1003050ac265SRobert Watson * mbufs. 1004a34b7046SRobert Watson */ 100526f9a767SRodney W. Grimes int 10068de34a88SAlan Somers sbappendaddr_locked(struct sockbuf *sb, const struct sockaddr *asa, 10078de34a88SAlan Somers struct mbuf *m0, struct mbuf *control) 10088de34a88SAlan Somers { 10098de34a88SAlan Somers struct mbuf *ctrl_last; 10108de34a88SAlan Somers int space = asa->sa_len; 10118de34a88SAlan Somers 10128de34a88SAlan Somers SOCKBUF_LOCK_ASSERT(sb); 10138de34a88SAlan Somers 10148de34a88SAlan Somers if (m0 && (m0->m_flags & M_PKTHDR) == 0) 10158de34a88SAlan Somers panic("sbappendaddr_locked"); 10168de34a88SAlan Somers if (m0) 10178de34a88SAlan Somers space += m0->m_pkthdr.len; 10188de34a88SAlan Somers space += m_length(control, &ctrl_last); 10198de34a88SAlan Somers 10208de34a88SAlan Somers if (space > sbspace(sb)) 10218de34a88SAlan Somers return (0); 10228de34a88SAlan Somers return (sbappendaddr_locked_internal(sb, asa, m0, control, ctrl_last)); 10238de34a88SAlan Somers } 10248de34a88SAlan Somers 10258de34a88SAlan Somers /* 10268de34a88SAlan Somers * Append address and data, and optionally, control (ancillary) data to the 10278de34a88SAlan Somers * receive queue of a socket. If present, m0 must include a packet header 10288de34a88SAlan Somers * with total length. Returns 0 if insufficient mbufs. Does not validate space 10298de34a88SAlan Somers * on the receiving sockbuf. 10308de34a88SAlan Somers */ 10318de34a88SAlan Somers int 10328de34a88SAlan Somers sbappendaddr_nospacecheck_locked(struct sockbuf *sb, const struct sockaddr *asa, 10338de34a88SAlan Somers struct mbuf *m0, struct mbuf *control) 10348de34a88SAlan Somers { 10358de34a88SAlan Somers struct mbuf *ctrl_last; 10368de34a88SAlan Somers 10378de34a88SAlan Somers SOCKBUF_LOCK_ASSERT(sb); 10388de34a88SAlan Somers 10398de34a88SAlan Somers ctrl_last = (control == NULL) ? NULL : m_last(control); 10408de34a88SAlan Somers return (sbappendaddr_locked_internal(sb, asa, m0, control, ctrl_last)); 10418de34a88SAlan Somers } 10428de34a88SAlan Somers 10438de34a88SAlan Somers /* 10448de34a88SAlan Somers * Append address and data, and optionally, control (ancillary) data to the 10458de34a88SAlan Somers * receive queue of a socket. If present, m0 must include a packet header 10468de34a88SAlan Somers * with total length. Returns 0 if no space in sockbuf or insufficient 10478de34a88SAlan Somers * mbufs. 10488de34a88SAlan Somers */ 10498de34a88SAlan Somers int 1050050ac265SRobert Watson sbappendaddr(struct sockbuf *sb, const struct sockaddr *asa, 1051050ac265SRobert Watson struct mbuf *m0, struct mbuf *control) 1052a34b7046SRobert Watson { 1053a34b7046SRobert Watson int retval; 1054a34b7046SRobert Watson 1055a34b7046SRobert Watson SOCKBUF_LOCK(sb); 1056a34b7046SRobert Watson retval = sbappendaddr_locked(sb, asa, m0, control); 1057a34b7046SRobert Watson SOCKBUF_UNLOCK(sb); 1058a34b7046SRobert Watson return (retval); 1059a34b7046SRobert Watson } 1060a34b7046SRobert Watson 10615b0480f2SMark Johnston void 1062050ac265SRobert Watson sbappendcontrol_locked(struct sockbuf *sb, struct mbuf *m0, 1063050ac265SRobert Watson struct mbuf *control) 1064df8bae1dSRodney W. Grimes { 10655b0480f2SMark Johnston struct mbuf *m, *mlast; 1066df8bae1dSRodney W. Grimes 106753b680caSGleb Smirnoff m_clrprotoflags(m0); 10685b0480f2SMark Johnston m_last(control)->m_next = m0; 1069395bb186SSam Leffler 1070395bb186SSam Leffler SBLASTRECORDCHK(sb); 1071395bb186SSam Leffler 1072395bb186SSam Leffler for (m = control; m->m_next; m = m->m_next) 1073df8bae1dSRodney W. Grimes sballoc(sb, m); 1074395bb186SSam Leffler sballoc(sb, m); 1075395bb186SSam Leffler mlast = m; 1076395bb186SSam Leffler SBLINKRECORD(sb, control); 1077395bb186SSam Leffler 1078395bb186SSam Leffler sb->sb_mbtail = mlast; 1079395bb186SSam Leffler SBLASTMBUFCHK(sb); 1080395bb186SSam Leffler 1081395bb186SSam Leffler SBLASTRECORDCHK(sb); 1082df8bae1dSRodney W. Grimes } 1083df8bae1dSRodney W. Grimes 10845b0480f2SMark Johnston void 1085050ac265SRobert Watson sbappendcontrol(struct sockbuf *sb, struct mbuf *m0, struct mbuf *control) 1086a34b7046SRobert Watson { 1087a34b7046SRobert Watson 1088a34b7046SRobert Watson SOCKBUF_LOCK(sb); 10895b0480f2SMark Johnston sbappendcontrol_locked(sb, m0, control); 1090a34b7046SRobert Watson SOCKBUF_UNLOCK(sb); 1091a34b7046SRobert Watson } 1092a34b7046SRobert Watson 1093df8bae1dSRodney W. Grimes /* 10947da7362bSRobert Watson * Append the data in mbuf chain (m) into the socket buffer sb following mbuf 10957da7362bSRobert Watson * (n). If (n) is NULL, the buffer is presumed empty. 10967da7362bSRobert Watson * 10977da7362bSRobert Watson * When the data is compressed, mbufs in the chain may be handled in one of 10987da7362bSRobert Watson * three ways: 10997da7362bSRobert Watson * 11007da7362bSRobert Watson * (1) The mbuf may simply be dropped, if it contributes nothing (no data, no 11017da7362bSRobert Watson * record boundary, and no change in data type). 11027da7362bSRobert Watson * 11037da7362bSRobert Watson * (2) The mbuf may be coalesced -- i.e., data in the mbuf may be copied into 11047da7362bSRobert Watson * an mbuf already in the socket buffer. This can occur if an 11050f9d0a73SGleb Smirnoff * appropriate mbuf exists, there is room, both mbufs are not marked as 11060f9d0a73SGleb Smirnoff * not ready, and no merging of data types will occur. 11077da7362bSRobert Watson * 11087da7362bSRobert Watson * (3) The mbuf may be appended to the end of the existing mbuf chain. 11097da7362bSRobert Watson * 11107da7362bSRobert Watson * If any of the new mbufs is marked as M_EOR, mark the last mbuf appended as 11117da7362bSRobert Watson * end-of-record. 1112df8bae1dSRodney W. Grimes */ 111326f9a767SRodney W. Grimes void 1114050ac265SRobert Watson sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n) 1115df8bae1dSRodney W. Grimes { 1116050ac265SRobert Watson int eor = 0; 1117050ac265SRobert Watson struct mbuf *o; 1118df8bae1dSRodney W. Grimes 1119a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 1120a34b7046SRobert Watson 1121df8bae1dSRodney W. Grimes while (m) { 1122df8bae1dSRodney W. Grimes eor |= m->m_flags & M_EOR; 1123df8bae1dSRodney W. Grimes if (m->m_len == 0 && 1124df8bae1dSRodney W. Grimes (eor == 0 || 1125df8bae1dSRodney W. Grimes (((o = m->m_next) || (o = n)) && 1126df8bae1dSRodney W. Grimes o->m_type == m->m_type))) { 1127395bb186SSam Leffler if (sb->sb_lastrecord == m) 1128395bb186SSam Leffler sb->sb_lastrecord = m->m_next; 1129df8bae1dSRodney W. Grimes m = m_free(m); 1130df8bae1dSRodney W. Grimes continue; 1131df8bae1dSRodney W. Grimes } 113232af0d74SDavid Malone if (n && (n->m_flags & M_EOR) == 0 && 113332af0d74SDavid Malone M_WRITABLE(n) && 11345e0f5cfaSKip Macy ((sb->sb_flags & SB_NOCOALESCE) == 0) && 11350f9d0a73SGleb Smirnoff !(m->m_flags & M_NOTREADY) && 113682334850SJohn Baldwin !(n->m_flags & (M_NOTREADY | M_NOMAP)) && 113732af0d74SDavid Malone m->m_len <= MCLBYTES / 4 && /* XXX: Don't copy too much */ 113832af0d74SDavid Malone m->m_len <= M_TRAILINGSPACE(n) && 1139df8bae1dSRodney W. Grimes n->m_type == m->m_type) { 114082334850SJohn Baldwin m_copydata(m, 0, m->m_len, mtodo(n, n->m_len)); 1141df8bae1dSRodney W. Grimes n->m_len += m->m_len; 11420f9d0a73SGleb Smirnoff sb->sb_ccc += m->m_len; 11430f9d0a73SGleb Smirnoff if (sb->sb_fnrdy == NULL) 11440f9d0a73SGleb Smirnoff sb->sb_acc += m->m_len; 114534333b16SAndre Oppermann if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA) 1146b3f1af6bSTim J. Robbins /* XXX: Probably don't need.*/ 114704ac9b97SKelly Yancey sb->sb_ctl += m->m_len; 1148df8bae1dSRodney W. Grimes m = m_free(m); 1149df8bae1dSRodney W. Grimes continue; 1150df8bae1dSRodney W. Grimes } 115182334850SJohn Baldwin if (m->m_len <= MLEN && (m->m_flags & M_NOMAP) && 115282334850SJohn Baldwin (m->m_flags & M_NOTREADY) == 0) 115382334850SJohn Baldwin (void)mb_unmapped_compress(m); 1154df8bae1dSRodney W. Grimes if (n) 1155df8bae1dSRodney W. Grimes n->m_next = m; 1156df8bae1dSRodney W. Grimes else 1157df8bae1dSRodney W. Grimes sb->sb_mb = m; 1158395bb186SSam Leffler sb->sb_mbtail = m; 1159df8bae1dSRodney W. Grimes sballoc(sb, m); 1160df8bae1dSRodney W. Grimes n = m; 1161df8bae1dSRodney W. Grimes m->m_flags &= ~M_EOR; 1162df8bae1dSRodney W. Grimes m = m->m_next; 1163df8bae1dSRodney W. Grimes n->m_next = 0; 1164df8bae1dSRodney W. Grimes } 1165df8bae1dSRodney W. Grimes if (eor) { 11667da7362bSRobert Watson KASSERT(n != NULL, ("sbcompress: eor && n == NULL")); 1167df8bae1dSRodney W. Grimes n->m_flags |= eor; 1168df8bae1dSRodney W. Grimes } 1169395bb186SSam Leffler SBLASTMBUFCHK(sb); 1170df8bae1dSRodney W. Grimes } 1171df8bae1dSRodney W. Grimes 1172df8bae1dSRodney W. Grimes /* 1173050ac265SRobert Watson * Free all mbufs in a sockbuf. Check that all resources are reclaimed. 1174df8bae1dSRodney W. Grimes */ 1175eaa6dfbcSRobert Watson static void 1176050ac265SRobert Watson sbflush_internal(struct sockbuf *sb) 1177df8bae1dSRodney W. Grimes { 1178df8bae1dSRodney W. Grimes 117923f84772SPierre Beyssac while (sb->sb_mbcnt) { 118023f84772SPierre Beyssac /* 1181761a9a1fSGleb Smirnoff * Don't call sbcut(sb, 0) if the leading mbuf is non-empty: 118223f84772SPierre Beyssac * we would loop forever. Panic instead. 118323f84772SPierre Beyssac */ 11840f9d0a73SGleb Smirnoff if (sb->sb_ccc == 0 && (sb->sb_mb == NULL || sb->sb_mb->m_len)) 118523f84772SPierre Beyssac break; 11860f9d0a73SGleb Smirnoff m_freem(sbcut_internal(sb, (int)sb->sb_ccc)); 118723f84772SPierre Beyssac } 11880f9d0a73SGleb Smirnoff KASSERT(sb->sb_ccc == 0 && sb->sb_mb == 0 && sb->sb_mbcnt == 0, 11890f9d0a73SGleb Smirnoff ("%s: ccc %u mb %p mbcnt %u", __func__, 11900f9d0a73SGleb Smirnoff sb->sb_ccc, (void *)sb->sb_mb, sb->sb_mbcnt)); 1191a34b7046SRobert Watson } 1192a34b7046SRobert Watson 1193a34b7046SRobert Watson void 1194050ac265SRobert Watson sbflush_locked(struct sockbuf *sb) 1195eaa6dfbcSRobert Watson { 1196eaa6dfbcSRobert Watson 1197eaa6dfbcSRobert Watson SOCKBUF_LOCK_ASSERT(sb); 1198eaa6dfbcSRobert Watson sbflush_internal(sb); 1199eaa6dfbcSRobert Watson } 1200eaa6dfbcSRobert Watson 1201eaa6dfbcSRobert Watson void 1202050ac265SRobert Watson sbflush(struct sockbuf *sb) 1203a34b7046SRobert Watson { 1204a34b7046SRobert Watson 1205a34b7046SRobert Watson SOCKBUF_LOCK(sb); 1206a34b7046SRobert Watson sbflush_locked(sb); 1207a34b7046SRobert Watson SOCKBUF_UNLOCK(sb); 1208df8bae1dSRodney W. Grimes } 1209df8bae1dSRodney W. Grimes 1210df8bae1dSRodney W. Grimes /* 12111d2df300SGleb Smirnoff * Cut data from (the front of) a sockbuf. 1212df8bae1dSRodney W. Grimes */ 12131d2df300SGleb Smirnoff static struct mbuf * 12141d2df300SGleb Smirnoff sbcut_internal(struct sockbuf *sb, int len) 1215df8bae1dSRodney W. Grimes { 12160f9d0a73SGleb Smirnoff struct mbuf *m, *next, *mfree; 1217df8bae1dSRodney W. Grimes 1218f41b2de7SHiren Panchasara KASSERT(len >= 0, ("%s: len is %d but it is supposed to be >= 0", 1219b5b023b9SHiren Panchasara __func__, len)); 1220b5b023b9SHiren Panchasara KASSERT(len <= sb->sb_ccc, ("%s: len: %d is > ccc: %u", 1221b5b023b9SHiren Panchasara __func__, len, sb->sb_ccc)); 1222b5b023b9SHiren Panchasara 1223df8bae1dSRodney W. Grimes next = (m = sb->sb_mb) ? m->m_nextpkt : 0; 12241d2df300SGleb Smirnoff mfree = NULL; 12251d2df300SGleb Smirnoff 1226df8bae1dSRodney W. Grimes while (len > 0) { 12278146bcfeSGleb Smirnoff if (m == NULL) { 12288146bcfeSGleb Smirnoff KASSERT(next, ("%s: no next, len %d", __func__, len)); 1229df8bae1dSRodney W. Grimes m = next; 1230df8bae1dSRodney W. Grimes next = m->m_nextpkt; 1231df8bae1dSRodney W. Grimes } 1232df8bae1dSRodney W. Grimes if (m->m_len > len) { 12330f9d0a73SGleb Smirnoff KASSERT(!(m->m_flags & M_NOTAVAIL), 12340f9d0a73SGleb Smirnoff ("%s: m %p M_NOTAVAIL", __func__, m)); 1235df8bae1dSRodney W. Grimes m->m_len -= len; 1236df8bae1dSRodney W. Grimes m->m_data += len; 12370f9d0a73SGleb Smirnoff sb->sb_ccc -= len; 12380f9d0a73SGleb Smirnoff sb->sb_acc -= len; 12394e023759SAndre Oppermann if (sb->sb_sndptroff != 0) 12404e023759SAndre Oppermann sb->sb_sndptroff -= len; 124134333b16SAndre Oppermann if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA) 124204ac9b97SKelly Yancey sb->sb_ctl -= len; 1243df8bae1dSRodney W. Grimes break; 1244df8bae1dSRodney W. Grimes } 1245df8bae1dSRodney W. Grimes len -= m->m_len; 1246df8bae1dSRodney W. Grimes sbfree(sb, m); 12470f9d0a73SGleb Smirnoff /* 12480f9d0a73SGleb Smirnoff * Do not put M_NOTREADY buffers to the free list, they 12490f9d0a73SGleb Smirnoff * are referenced from outside. 12500f9d0a73SGleb Smirnoff */ 12510f9d0a73SGleb Smirnoff if (m->m_flags & M_NOTREADY) 12520f9d0a73SGleb Smirnoff m = m->m_next; 12530f9d0a73SGleb Smirnoff else { 12540f9d0a73SGleb Smirnoff struct mbuf *n; 12550f9d0a73SGleb Smirnoff 12561d2df300SGleb Smirnoff n = m->m_next; 12571d2df300SGleb Smirnoff m->m_next = mfree; 12581d2df300SGleb Smirnoff mfree = m; 12591d2df300SGleb Smirnoff m = n; 1260df8bae1dSRodney W. Grimes } 12610f9d0a73SGleb Smirnoff } 1262e834a840SGleb Smirnoff /* 1263e834a840SGleb Smirnoff * Free any zero-length mbufs from the buffer. 1264e834a840SGleb Smirnoff * For SOCK_DGRAM sockets such mbufs represent empty records. 1265e834a840SGleb Smirnoff * XXX: For SOCK_STREAM sockets such mbufs can appear in the buffer, 1266e834a840SGleb Smirnoff * when sosend_generic() needs to send only control data. 1267e834a840SGleb Smirnoff */ 1268e834a840SGleb Smirnoff while (m && m->m_len == 0) { 1269e834a840SGleb Smirnoff struct mbuf *n; 1270e834a840SGleb Smirnoff 1271e834a840SGleb Smirnoff sbfree(sb, m); 1272e834a840SGleb Smirnoff n = m->m_next; 1273e834a840SGleb Smirnoff m->m_next = mfree; 1274e834a840SGleb Smirnoff mfree = m; 1275e834a840SGleb Smirnoff m = n; 1276e834a840SGleb Smirnoff } 1277df8bae1dSRodney W. Grimes if (m) { 1278df8bae1dSRodney W. Grimes sb->sb_mb = m; 1279df8bae1dSRodney W. Grimes m->m_nextpkt = next; 1280df8bae1dSRodney W. Grimes } else 1281df8bae1dSRodney W. Grimes sb->sb_mb = next; 1282395bb186SSam Leffler /* 1283050ac265SRobert Watson * First part is an inline SB_EMPTY_FIXUP(). Second part makes sure 1284050ac265SRobert Watson * sb_lastrecord is up-to-date if we dropped part of the last record. 1285395bb186SSam Leffler */ 1286395bb186SSam Leffler m = sb->sb_mb; 1287395bb186SSam Leffler if (m == NULL) { 1288395bb186SSam Leffler sb->sb_mbtail = NULL; 1289395bb186SSam Leffler sb->sb_lastrecord = NULL; 1290395bb186SSam Leffler } else if (m->m_nextpkt == NULL) { 1291395bb186SSam Leffler sb->sb_lastrecord = m; 1292395bb186SSam Leffler } 12931d2df300SGleb Smirnoff 12941d2df300SGleb Smirnoff return (mfree); 1295df8bae1dSRodney W. Grimes } 1296df8bae1dSRodney W. Grimes 1297df8bae1dSRodney W. Grimes /* 1298a34b7046SRobert Watson * Drop data from (the front of) a sockbuf. 1299a34b7046SRobert Watson */ 1300a34b7046SRobert Watson void 1301050ac265SRobert Watson sbdrop_locked(struct sockbuf *sb, int len) 1302eaa6dfbcSRobert Watson { 1303eaa6dfbcSRobert Watson 1304eaa6dfbcSRobert Watson SOCKBUF_LOCK_ASSERT(sb); 13051d2df300SGleb Smirnoff m_freem(sbcut_internal(sb, len)); 13061d2df300SGleb Smirnoff } 1307eaa6dfbcSRobert Watson 13081d2df300SGleb Smirnoff /* 13091d2df300SGleb Smirnoff * Drop data from (the front of) a sockbuf, 13101d2df300SGleb Smirnoff * and return it to caller. 13111d2df300SGleb Smirnoff */ 13121d2df300SGleb Smirnoff struct mbuf * 13131d2df300SGleb Smirnoff sbcut_locked(struct sockbuf *sb, int len) 13141d2df300SGleb Smirnoff { 13151d2df300SGleb Smirnoff 13161d2df300SGleb Smirnoff SOCKBUF_LOCK_ASSERT(sb); 13171d2df300SGleb Smirnoff return (sbcut_internal(sb, len)); 1318eaa6dfbcSRobert Watson } 1319eaa6dfbcSRobert Watson 1320eaa6dfbcSRobert Watson void 1321050ac265SRobert Watson sbdrop(struct sockbuf *sb, int len) 1322a34b7046SRobert Watson { 13231d2df300SGleb Smirnoff struct mbuf *mfree; 1324a34b7046SRobert Watson 1325a34b7046SRobert Watson SOCKBUF_LOCK(sb); 13261d2df300SGleb Smirnoff mfree = sbcut_internal(sb, len); 1327a34b7046SRobert Watson SOCKBUF_UNLOCK(sb); 13281d2df300SGleb Smirnoff 13291d2df300SGleb Smirnoff m_freem(mfree); 1330a34b7046SRobert Watson } 1331a34b7046SRobert Watson 133289e560f4SRandall Stewart struct mbuf * 133389e560f4SRandall Stewart sbsndptr_noadv(struct sockbuf *sb, uint32_t off, uint32_t *moff) 133489e560f4SRandall Stewart { 133589e560f4SRandall Stewart struct mbuf *m; 133689e560f4SRandall Stewart 133789e560f4SRandall Stewart KASSERT(sb->sb_mb != NULL, ("%s: sb_mb is NULL", __func__)); 133889e560f4SRandall Stewart if (sb->sb_sndptr == NULL || sb->sb_sndptroff > off) { 133989e560f4SRandall Stewart *moff = off; 134089e560f4SRandall Stewart if (sb->sb_sndptr == NULL) { 134189e560f4SRandall Stewart sb->sb_sndptr = sb->sb_mb; 134289e560f4SRandall Stewart sb->sb_sndptroff = 0; 134389e560f4SRandall Stewart } 134489e560f4SRandall Stewart return (sb->sb_mb); 134589e560f4SRandall Stewart } else { 134689e560f4SRandall Stewart m = sb->sb_sndptr; 134789e560f4SRandall Stewart off -= sb->sb_sndptroff; 134889e560f4SRandall Stewart } 134989e560f4SRandall Stewart *moff = off; 135089e560f4SRandall Stewart return (m); 135189e560f4SRandall Stewart } 135289e560f4SRandall Stewart 135389e560f4SRandall Stewart void 135489e560f4SRandall Stewart sbsndptr_adv(struct sockbuf *sb, struct mbuf *mb, uint32_t len) 135589e560f4SRandall Stewart { 135689e560f4SRandall Stewart /* 135789e560f4SRandall Stewart * A small copy was done, advance forward the sb_sbsndptr to cover 135889e560f4SRandall Stewart * it. 135989e560f4SRandall Stewart */ 136089e560f4SRandall Stewart struct mbuf *m; 136189e560f4SRandall Stewart 136289e560f4SRandall Stewart if (mb != sb->sb_sndptr) { 136389e560f4SRandall Stewart /* Did not copyout at the same mbuf */ 136489e560f4SRandall Stewart return; 136589e560f4SRandall Stewart } 136689e560f4SRandall Stewart m = mb; 136789e560f4SRandall Stewart while (m && (len > 0)) { 136889e560f4SRandall Stewart if (len >= m->m_len) { 136989e560f4SRandall Stewart len -= m->m_len; 137089e560f4SRandall Stewart if (m->m_next) { 137189e560f4SRandall Stewart sb->sb_sndptroff += m->m_len; 137289e560f4SRandall Stewart sb->sb_sndptr = m->m_next; 137389e560f4SRandall Stewart } 137489e560f4SRandall Stewart m = m->m_next; 137589e560f4SRandall Stewart } else { 137689e560f4SRandall Stewart len = 0; 137789e560f4SRandall Stewart } 137889e560f4SRandall Stewart } 137989e560f4SRandall Stewart } 138089e560f4SRandall Stewart 1381a34b7046SRobert Watson /* 13829fd573c3SHans Petter Selasky * Return the first mbuf and the mbuf data offset for the provided 13839fd573c3SHans Petter Selasky * send offset without changing the "sb_sndptroff" field. 13849fd573c3SHans Petter Selasky */ 13859fd573c3SHans Petter Selasky struct mbuf * 13869fd573c3SHans Petter Selasky sbsndmbuf(struct sockbuf *sb, u_int off, u_int *moff) 13879fd573c3SHans Petter Selasky { 13889fd573c3SHans Petter Selasky struct mbuf *m; 13899fd573c3SHans Petter Selasky 13909fd573c3SHans Petter Selasky KASSERT(sb->sb_mb != NULL, ("%s: sb_mb is NULL", __func__)); 13919fd573c3SHans Petter Selasky 13929fd573c3SHans Petter Selasky /* 13939fd573c3SHans Petter Selasky * If the "off" is below the stored offset, which happens on 13949fd573c3SHans Petter Selasky * retransmits, just use "sb_mb": 13959fd573c3SHans Petter Selasky */ 13969fd573c3SHans Petter Selasky if (sb->sb_sndptr == NULL || sb->sb_sndptroff > off) { 13979fd573c3SHans Petter Selasky m = sb->sb_mb; 13989fd573c3SHans Petter Selasky } else { 13999fd573c3SHans Petter Selasky m = sb->sb_sndptr; 14009fd573c3SHans Petter Selasky off -= sb->sb_sndptroff; 14019fd573c3SHans Petter Selasky } 14029fd573c3SHans Petter Selasky while (off > 0 && m != NULL) { 14039fd573c3SHans Petter Selasky if (off < m->m_len) 14049fd573c3SHans Petter Selasky break; 14059fd573c3SHans Petter Selasky off -= m->m_len; 14069fd573c3SHans Petter Selasky m = m->m_next; 14079fd573c3SHans Petter Selasky } 14089fd573c3SHans Petter Selasky *moff = off; 14099fd573c3SHans Petter Selasky return (m); 14109fd573c3SHans Petter Selasky } 14119fd573c3SHans Petter Selasky 14129fd573c3SHans Petter Selasky /* 1413050ac265SRobert Watson * Drop a record off the front of a sockbuf and move the next record to the 1414050ac265SRobert Watson * front. 1415df8bae1dSRodney W. Grimes */ 141626f9a767SRodney W. Grimes void 1417050ac265SRobert Watson sbdroprecord_locked(struct sockbuf *sb) 1418df8bae1dSRodney W. Grimes { 1419050ac265SRobert Watson struct mbuf *m; 1420df8bae1dSRodney W. Grimes 1421a34b7046SRobert Watson SOCKBUF_LOCK_ASSERT(sb); 1422a34b7046SRobert Watson 1423df8bae1dSRodney W. Grimes m = sb->sb_mb; 1424df8bae1dSRodney W. Grimes if (m) { 1425df8bae1dSRodney W. Grimes sb->sb_mb = m->m_nextpkt; 1426df8bae1dSRodney W. Grimes do { 1427df8bae1dSRodney W. Grimes sbfree(sb, m); 1428ecde8f7cSMatthew Dillon m = m_free(m); 1429797f2d22SPoul-Henning Kamp } while (m); 1430df8bae1dSRodney W. Grimes } 1431395bb186SSam Leffler SB_EMPTY_FIXUP(sb); 1432df8bae1dSRodney W. Grimes } 14331e4ad9ceSGarrett Wollman 143482c23ebaSBill Fenner /* 1435050ac265SRobert Watson * Drop a record off the front of a sockbuf and move the next record to the 1436050ac265SRobert Watson * front. 1437a34b7046SRobert Watson */ 1438a34b7046SRobert Watson void 1439050ac265SRobert Watson sbdroprecord(struct sockbuf *sb) 1440a34b7046SRobert Watson { 1441a34b7046SRobert Watson 1442a34b7046SRobert Watson SOCKBUF_LOCK(sb); 1443a34b7046SRobert Watson sbdroprecord_locked(sb); 1444a34b7046SRobert Watson SOCKBUF_UNLOCK(sb); 1445a34b7046SRobert Watson } 1446a34b7046SRobert Watson 144720d9e5e8SRobert Watson /* 14488c799760SRobert Watson * Create a "control" mbuf containing the specified data with the specified 14498c799760SRobert Watson * type for presentation on a socket buffer. 145020d9e5e8SRobert Watson */ 145120d9e5e8SRobert Watson struct mbuf * 1452d19e16a7SRobert Watson sbcreatecontrol(caddr_t p, int size, int type, int level) 145320d9e5e8SRobert Watson { 1454d19e16a7SRobert Watson struct cmsghdr *cp; 145520d9e5e8SRobert Watson struct mbuf *m; 145620d9e5e8SRobert Watson 145720d9e5e8SRobert Watson if (CMSG_SPACE((u_int)size) > MCLBYTES) 145820d9e5e8SRobert Watson return ((struct mbuf *) NULL); 145920d9e5e8SRobert Watson if (CMSG_SPACE((u_int)size) > MLEN) 1460eb1b1807SGleb Smirnoff m = m_getcl(M_NOWAIT, MT_CONTROL, 0); 146120d9e5e8SRobert Watson else 1462eb1b1807SGleb Smirnoff m = m_get(M_NOWAIT, MT_CONTROL); 146320d9e5e8SRobert Watson if (m == NULL) 146420d9e5e8SRobert Watson return ((struct mbuf *) NULL); 146520d9e5e8SRobert Watson cp = mtod(m, struct cmsghdr *); 146620d9e5e8SRobert Watson m->m_len = 0; 146720d9e5e8SRobert Watson KASSERT(CMSG_SPACE((u_int)size) <= M_TRAILINGSPACE(m), 146820d9e5e8SRobert Watson ("sbcreatecontrol: short mbuf")); 14692827952eSXin LI /* 14702827952eSXin LI * Don't leave the padding between the msg header and the 14712827952eSXin LI * cmsg data and the padding after the cmsg data un-initialized. 14722827952eSXin LI */ 14732827952eSXin LI bzero(cp, CMSG_SPACE((u_int)size)); 147420d9e5e8SRobert Watson if (p != NULL) 147520d9e5e8SRobert Watson (void)memcpy(CMSG_DATA(cp), p, size); 147620d9e5e8SRobert Watson m->m_len = CMSG_SPACE(size); 147720d9e5e8SRobert Watson cp->cmsg_len = CMSG_LEN(size); 147820d9e5e8SRobert Watson cp->cmsg_level = level; 147920d9e5e8SRobert Watson cp->cmsg_type = type; 148020d9e5e8SRobert Watson return (m); 148120d9e5e8SRobert Watson } 148220d9e5e8SRobert Watson 148320d9e5e8SRobert Watson /* 14848c799760SRobert Watson * This does the same for socket buffers that sotoxsocket does for sockets: 14858c799760SRobert Watson * generate an user-format data structure describing the socket buffer. Note 14868c799760SRobert Watson * that the xsockbuf structure, since it is always embedded in a socket, does 14878c799760SRobert Watson * not include a self pointer nor a length. We make this entry point public 14888c799760SRobert Watson * in case some other mechanism needs it. 148920d9e5e8SRobert Watson */ 149020d9e5e8SRobert Watson void 149120d9e5e8SRobert Watson sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb) 149220d9e5e8SRobert Watson { 1493d19e16a7SRobert Watson 14940f9d0a73SGleb Smirnoff xsb->sb_cc = sb->sb_ccc; 149520d9e5e8SRobert Watson xsb->sb_hiwat = sb->sb_hiwat; 149620d9e5e8SRobert Watson xsb->sb_mbcnt = sb->sb_mbcnt; 149749f287f8SGeorge V. Neville-Neil xsb->sb_mcnt = sb->sb_mcnt; 149849f287f8SGeorge V. Neville-Neil xsb->sb_ccnt = sb->sb_ccnt; 149920d9e5e8SRobert Watson xsb->sb_mbmax = sb->sb_mbmax; 150020d9e5e8SRobert Watson xsb->sb_lowat = sb->sb_lowat; 150120d9e5e8SRobert Watson xsb->sb_flags = sb->sb_flags; 150220d9e5e8SRobert Watson xsb->sb_timeo = sb->sb_timeo; 150320d9e5e8SRobert Watson } 150420d9e5e8SRobert Watson 1505639acc13SGarrett Wollman /* This takes the place of kern.maxsockbuf, which moved to kern.ipc. */ 1506639acc13SGarrett Wollman static int dummy; 1507639acc13SGarrett Wollman SYSCTL_INT(_kern, KERN_DUMMY, dummy, CTLFLAG_RW, &dummy, 0, ""); 15081b978d45SHartmut Brandt SYSCTL_OID(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLTYPE_ULONG|CTLFLAG_RW, 15091b978d45SHartmut Brandt &sb_max, 0, sysctl_handle_sb_max, "LU", "Maximum socket buffer size"); 15101b978d45SHartmut Brandt SYSCTL_ULONG(_kern_ipc, KIPC_SOCKBUF_WASTE, sockbuf_waste_factor, CTLFLAG_RW, 15113eb9ab52SEitan Adler &sb_efficiency, 0, "Socket buffer size waste factor"); 1512