1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 1990, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93 34313861b8SJulian Elischer * $Id: uipc_socket2.c,v 1.12 1996/07/11 16:31:59 wollman Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38df8bae1dSRodney W. Grimes #include <sys/systm.h> 39ff5c09daSGarrett Wollman #include <sys/kernel.h> 40df8bae1dSRodney W. Grimes #include <sys/proc.h> 41df8bae1dSRodney W. Grimes #include <sys/file.h> 42df8bae1dSRodney W. Grimes #include <sys/buf.h> 43df8bae1dSRodney W. Grimes #include <sys/malloc.h> 44df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 45df8bae1dSRodney W. Grimes #include <sys/protosw.h> 46797f2d22SPoul-Henning Kamp #include <sys/stat.h> 47df8bae1dSRodney W. Grimes #include <sys/socket.h> 48df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 49797f2d22SPoul-Henning Kamp #include <sys/signalvar.h> 50ff5c09daSGarrett Wollman #include <sys/sysctl.h> 5126f9a767SRodney W. Grimes 52df8bae1dSRodney W. Grimes /* 53df8bae1dSRodney W. Grimes * Primitive routines for operating on sockets and socket buffers 54df8bae1dSRodney W. Grimes */ 55df8bae1dSRodney W. Grimes 56ff5c09daSGarrett Wollman u_long sb_max = SB_MAX; /* XXX should be static */ 57ff5c09daSGarrett Wollman SYSCTL_INT(_kern, KERN_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW, &sb_max, 0, "") 58df8bae1dSRodney W. Grimes 594b29bc4fSGarrett Wollman static u_long sb_efficiency = 8; /* parameter for sbreserve() */ 604b29bc4fSGarrett Wollman SYSCTL_INT(_kern, OID_AUTO, sockbuf_waste_factor, CTLFLAG_RW, &sb_efficiency, 614b29bc4fSGarrett Wollman 0, ""); 624b29bc4fSGarrett Wollman 63df8bae1dSRodney W. Grimes /* 64df8bae1dSRodney W. Grimes * Procedures to manipulate state flags of socket 65df8bae1dSRodney W. Grimes * and do appropriate wakeups. Normal sequence from the 66df8bae1dSRodney W. Grimes * active (originating) side is that soisconnecting() is 67df8bae1dSRodney W. Grimes * called during processing of connect() call, 68df8bae1dSRodney W. Grimes * resulting in an eventual call to soisconnected() if/when the 69df8bae1dSRodney W. Grimes * connection is established. When the connection is torn down 70df8bae1dSRodney W. Grimes * soisdisconnecting() is called during processing of disconnect() call, 71df8bae1dSRodney W. Grimes * and soisdisconnected() is called when the connection to the peer 72df8bae1dSRodney W. Grimes * is totally severed. The semantics of these routines are such that 73df8bae1dSRodney W. Grimes * connectionless protocols can call soisconnected() and soisdisconnected() 74df8bae1dSRodney W. Grimes * only, bypassing the in-progress calls when setting up a ``connection'' 75df8bae1dSRodney W. Grimes * takes no time. 76df8bae1dSRodney W. Grimes * 77df8bae1dSRodney W. Grimes * From the passive side, a socket is created with 78df8bae1dSRodney W. Grimes * two queues of sockets: so_q0 for connections in progress 79df8bae1dSRodney W. Grimes * and so_q for connections already made and awaiting user acceptance. 80df8bae1dSRodney W. Grimes * As a protocol is preparing incoming connections, it creates a socket 81df8bae1dSRodney W. Grimes * structure queued on so_q0 by calling sonewconn(). When the connection 82df8bae1dSRodney W. Grimes * is established, soisconnected() is called, and transfers the 83df8bae1dSRodney W. Grimes * socket structure to so_q, making it available to accept(). 84df8bae1dSRodney W. Grimes * 85df8bae1dSRodney W. Grimes * If a socket is closed with sockets on either 86df8bae1dSRodney W. Grimes * so_q0 or so_q, these sockets are dropped. 87df8bae1dSRodney W. Grimes * 88df8bae1dSRodney W. Grimes * If higher level protocols are implemented in 89df8bae1dSRodney W. Grimes * the kernel, the wakeups done here will sometimes 90df8bae1dSRodney W. Grimes * cause software-interrupt process scheduling. 91df8bae1dSRodney W. Grimes */ 92df8bae1dSRodney W. Grimes 9326f9a767SRodney W. Grimes void 94df8bae1dSRodney W. Grimes soisconnecting(so) 95df8bae1dSRodney W. Grimes register struct socket *so; 96df8bae1dSRodney W. Grimes { 97df8bae1dSRodney W. Grimes 98df8bae1dSRodney W. Grimes so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); 99df8bae1dSRodney W. Grimes so->so_state |= SS_ISCONNECTING; 100df8bae1dSRodney W. Grimes } 101df8bae1dSRodney W. Grimes 10226f9a767SRodney W. Grimes void 103df8bae1dSRodney W. Grimes soisconnected(so) 104df8bae1dSRodney W. Grimes register struct socket *so; 105df8bae1dSRodney W. Grimes { 106df8bae1dSRodney W. Grimes register struct socket *head = so->so_head; 107df8bae1dSRodney W. Grimes 108df8bae1dSRodney W. Grimes so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); 109df8bae1dSRodney W. Grimes so->so_state |= SS_ISCONNECTED; 110be24e9e8SDavid Greenman if (head && (so->so_state & SS_INCOMP)) { 111be24e9e8SDavid Greenman TAILQ_REMOVE(&head->so_incomp, so, so_list); 112be24e9e8SDavid Greenman so->so_state &= ~SS_INCOMP; 113be24e9e8SDavid Greenman TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); 114be24e9e8SDavid Greenman so->so_state |= SS_COMP; 115df8bae1dSRodney W. Grimes sorwakeup(head); 116df8bae1dSRodney W. Grimes wakeup((caddr_t)&head->so_timeo); 117df8bae1dSRodney W. Grimes } else { 118df8bae1dSRodney W. Grimes wakeup((caddr_t)&so->so_timeo); 119df8bae1dSRodney W. Grimes sorwakeup(so); 120df8bae1dSRodney W. Grimes sowwakeup(so); 121df8bae1dSRodney W. Grimes } 122df8bae1dSRodney W. Grimes } 123df8bae1dSRodney W. Grimes 12426f9a767SRodney W. Grimes void 125df8bae1dSRodney W. Grimes soisdisconnecting(so) 126df8bae1dSRodney W. Grimes register struct socket *so; 127df8bae1dSRodney W. Grimes { 128df8bae1dSRodney W. Grimes 129df8bae1dSRodney W. Grimes so->so_state &= ~SS_ISCONNECTING; 130df8bae1dSRodney W. Grimes so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); 131df8bae1dSRodney W. Grimes wakeup((caddr_t)&so->so_timeo); 132df8bae1dSRodney W. Grimes sowwakeup(so); 133df8bae1dSRodney W. Grimes sorwakeup(so); 134df8bae1dSRodney W. Grimes } 135df8bae1dSRodney W. Grimes 13626f9a767SRodney W. Grimes void 137df8bae1dSRodney W. Grimes soisdisconnected(so) 138df8bae1dSRodney W. Grimes register struct socket *so; 139df8bae1dSRodney W. Grimes { 140df8bae1dSRodney W. Grimes 141df8bae1dSRodney W. Grimes so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); 142df8bae1dSRodney W. Grimes so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); 143df8bae1dSRodney W. Grimes wakeup((caddr_t)&so->so_timeo); 144df8bae1dSRodney W. Grimes sowwakeup(so); 145df8bae1dSRodney W. Grimes sorwakeup(so); 146df8bae1dSRodney W. Grimes } 147df8bae1dSRodney W. Grimes 148df8bae1dSRodney W. Grimes /* 149df8bae1dSRodney W. Grimes * When an attempt at a new connection is noted on a socket 150df8bae1dSRodney W. Grimes * which accepts connections, sonewconn is called. If the 151df8bae1dSRodney W. Grimes * connection is possible (subject to space constraints, etc.) 152df8bae1dSRodney W. Grimes * then we allocate a new structure, propoerly linked into the 153df8bae1dSRodney W. Grimes * data structure of the original socket, and return this. 154df8bae1dSRodney W. Grimes * Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED. 155df8bae1dSRodney W. Grimes * 156df8bae1dSRodney W. Grimes * Currently, sonewconn() is defined as sonewconn1() in socketvar.h 157df8bae1dSRodney W. Grimes * to catch calls that are missing the (new) second parameter. 158df8bae1dSRodney W. Grimes */ 159df8bae1dSRodney W. Grimes struct socket * 160df8bae1dSRodney W. Grimes sonewconn1(head, connstatus) 161df8bae1dSRodney W. Grimes register struct socket *head; 162df8bae1dSRodney W. Grimes int connstatus; 163df8bae1dSRodney W. Grimes { 164df8bae1dSRodney W. Grimes register struct socket *so; 165df8bae1dSRodney W. Grimes 166be24e9e8SDavid Greenman if (head->so_qlen > 3 * head->so_qlimit / 2) 167df8bae1dSRodney W. Grimes return ((struct socket *)0); 168df8bae1dSRodney W. Grimes MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_DONTWAIT); 169df8bae1dSRodney W. Grimes if (so == NULL) 170df8bae1dSRodney W. Grimes return ((struct socket *)0); 171df8bae1dSRodney W. Grimes bzero((caddr_t)so, sizeof(*so)); 172be24e9e8SDavid Greenman so->so_head = head; 173df8bae1dSRodney W. Grimes so->so_type = head->so_type; 174df8bae1dSRodney W. Grimes so->so_options = head->so_options &~ SO_ACCEPTCONN; 175df8bae1dSRodney W. Grimes so->so_linger = head->so_linger; 176df8bae1dSRodney W. Grimes so->so_state = head->so_state | SS_NOFDREF; 177df8bae1dSRodney W. Grimes so->so_proto = head->so_proto; 178df8bae1dSRodney W. Grimes so->so_timeo = head->so_timeo; 179df8bae1dSRodney W. Grimes so->so_pgid = head->so_pgid; 180df8bae1dSRodney W. Grimes (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); 181be24e9e8SDavid Greenman if (connstatus) { 182be24e9e8SDavid Greenman TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); 183be24e9e8SDavid Greenman so->so_state |= SS_COMP; 184be24e9e8SDavid Greenman } else { 185be24e9e8SDavid Greenman TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list); 186be24e9e8SDavid Greenman so->so_state |= SS_INCOMP; 187be24e9e8SDavid Greenman } 188be24e9e8SDavid Greenman head->so_qlen++; 1892c37256eSGarrett Wollman if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0)) { 190be24e9e8SDavid Greenman if (so->so_state & SS_COMP) { 191be24e9e8SDavid Greenman TAILQ_REMOVE(&head->so_comp, so, so_list); 192be24e9e8SDavid Greenman } else { 193be24e9e8SDavid Greenman TAILQ_REMOVE(&head->so_incomp, so, so_list); 194be24e9e8SDavid Greenman } 195be24e9e8SDavid Greenman head->so_qlen--; 196df8bae1dSRodney W. Grimes (void) free((caddr_t)so, M_SOCKET); 197df8bae1dSRodney W. Grimes return ((struct socket *)0); 198df8bae1dSRodney W. Grimes } 199df8bae1dSRodney W. Grimes if (connstatus) { 200df8bae1dSRodney W. Grimes sorwakeup(head); 201df8bae1dSRodney W. Grimes wakeup((caddr_t)&head->so_timeo); 202df8bae1dSRodney W. Grimes so->so_state |= connstatus; 203df8bae1dSRodney W. Grimes } 204df8bae1dSRodney W. Grimes return (so); 205df8bae1dSRodney W. Grimes } 206df8bae1dSRodney W. Grimes 207df8bae1dSRodney W. Grimes /* 208df8bae1dSRodney W. Grimes * Socantsendmore indicates that no more data will be sent on the 209df8bae1dSRodney W. Grimes * socket; it would normally be applied to a socket when the user 210df8bae1dSRodney W. Grimes * informs the system that no more data is to be sent, by the protocol 211df8bae1dSRodney W. Grimes * code (in case PRU_SHUTDOWN). Socantrcvmore indicates that no more data 212df8bae1dSRodney W. Grimes * will be received, and will normally be applied to the socket by a 213df8bae1dSRodney W. Grimes * protocol when it detects that the peer will send no more data. 214df8bae1dSRodney W. Grimes * Data queued for reading in the socket may yet be read. 215df8bae1dSRodney W. Grimes */ 216df8bae1dSRodney W. Grimes 21726f9a767SRodney W. Grimes void 218df8bae1dSRodney W. Grimes socantsendmore(so) 219df8bae1dSRodney W. Grimes struct socket *so; 220df8bae1dSRodney W. Grimes { 221df8bae1dSRodney W. Grimes 222df8bae1dSRodney W. Grimes so->so_state |= SS_CANTSENDMORE; 223df8bae1dSRodney W. Grimes sowwakeup(so); 224df8bae1dSRodney W. Grimes } 225df8bae1dSRodney W. Grimes 22626f9a767SRodney W. Grimes void 227df8bae1dSRodney W. Grimes socantrcvmore(so) 228df8bae1dSRodney W. Grimes struct socket *so; 229df8bae1dSRodney W. Grimes { 230df8bae1dSRodney W. Grimes 231df8bae1dSRodney W. Grimes so->so_state |= SS_CANTRCVMORE; 232df8bae1dSRodney W. Grimes sorwakeup(so); 233df8bae1dSRodney W. Grimes } 234df8bae1dSRodney W. Grimes 235df8bae1dSRodney W. Grimes /* 236df8bae1dSRodney W. Grimes * Wait for data to arrive at/drain from a socket buffer. 237df8bae1dSRodney W. Grimes */ 23826f9a767SRodney W. Grimes int 239df8bae1dSRodney W. Grimes sbwait(sb) 240df8bae1dSRodney W. Grimes struct sockbuf *sb; 241df8bae1dSRodney W. Grimes { 242df8bae1dSRodney W. Grimes 243df8bae1dSRodney W. Grimes sb->sb_flags |= SB_WAIT; 244df8bae1dSRodney W. Grimes return (tsleep((caddr_t)&sb->sb_cc, 24547daf5d5SBruce Evans (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait", 246df8bae1dSRodney W. Grimes sb->sb_timeo)); 247df8bae1dSRodney W. Grimes } 248df8bae1dSRodney W. Grimes 249df8bae1dSRodney W. Grimes /* 250df8bae1dSRodney W. Grimes * Lock a sockbuf already known to be locked; 251df8bae1dSRodney W. Grimes * return any error returned from sleep (EINTR). 252df8bae1dSRodney W. Grimes */ 25326f9a767SRodney W. Grimes int 254df8bae1dSRodney W. Grimes sb_lock(sb) 255df8bae1dSRodney W. Grimes register struct sockbuf *sb; 256df8bae1dSRodney W. Grimes { 257df8bae1dSRodney W. Grimes int error; 258df8bae1dSRodney W. Grimes 259df8bae1dSRodney W. Grimes while (sb->sb_flags & SB_LOCK) { 260df8bae1dSRodney W. Grimes sb->sb_flags |= SB_WANT; 261797f2d22SPoul-Henning Kamp error = tsleep((caddr_t)&sb->sb_flags, 262df8bae1dSRodney W. Grimes (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK|PCATCH, 26347daf5d5SBruce Evans "sblock", 0); 264797f2d22SPoul-Henning Kamp if (error) 265df8bae1dSRodney W. Grimes return (error); 266df8bae1dSRodney W. Grimes } 267df8bae1dSRodney W. Grimes sb->sb_flags |= SB_LOCK; 268df8bae1dSRodney W. Grimes return (0); 269df8bae1dSRodney W. Grimes } 270df8bae1dSRodney W. Grimes 271df8bae1dSRodney W. Grimes /* 272df8bae1dSRodney W. Grimes * Wakeup processes waiting on a socket buffer. 273df8bae1dSRodney W. Grimes * Do asynchronous notification via SIGIO 274df8bae1dSRodney W. Grimes * if the socket has the SS_ASYNC flag set. 275df8bae1dSRodney W. Grimes */ 27626f9a767SRodney W. Grimes void 277df8bae1dSRodney W. Grimes sowakeup(so, sb) 278df8bae1dSRodney W. Grimes register struct socket *so; 279df8bae1dSRodney W. Grimes register struct sockbuf *sb; 280df8bae1dSRodney W. Grimes { 281df8bae1dSRodney W. Grimes struct proc *p; 282df8bae1dSRodney W. Grimes 283df8bae1dSRodney W. Grimes selwakeup(&sb->sb_sel); 284df8bae1dSRodney W. Grimes sb->sb_flags &= ~SB_SEL; 285df8bae1dSRodney W. Grimes if (sb->sb_flags & SB_WAIT) { 286df8bae1dSRodney W. Grimes sb->sb_flags &= ~SB_WAIT; 287df8bae1dSRodney W. Grimes wakeup((caddr_t)&sb->sb_cc); 288df8bae1dSRodney W. Grimes } 289df8bae1dSRodney W. Grimes if (so->so_state & SS_ASYNC) { 290df8bae1dSRodney W. Grimes if (so->so_pgid < 0) 291df8bae1dSRodney W. Grimes gsignal(-so->so_pgid, SIGIO); 292df8bae1dSRodney W. Grimes else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 293df8bae1dSRodney W. Grimes psignal(p, SIGIO); 294df8bae1dSRodney W. Grimes } 295df8bae1dSRodney W. Grimes } 296df8bae1dSRodney W. Grimes 297df8bae1dSRodney W. Grimes /* 298df8bae1dSRodney W. Grimes * Socket buffer (struct sockbuf) utility routines. 299df8bae1dSRodney W. Grimes * 300df8bae1dSRodney W. Grimes * Each socket contains two socket buffers: one for sending data and 301df8bae1dSRodney W. Grimes * one for receiving data. Each buffer contains a queue of mbufs, 302df8bae1dSRodney W. Grimes * information about the number of mbufs and amount of data in the 303df8bae1dSRodney W. Grimes * queue, and other fields allowing select() statements and notification 304df8bae1dSRodney W. Grimes * on data availability to be implemented. 305df8bae1dSRodney W. Grimes * 306df8bae1dSRodney W. Grimes * Data stored in a socket buffer is maintained as a list of records. 307df8bae1dSRodney W. Grimes * Each record is a list of mbufs chained together with the m_next 308df8bae1dSRodney W. Grimes * field. Records are chained together with the m_nextpkt field. The upper 309df8bae1dSRodney W. Grimes * level routine soreceive() expects the following conventions to be 310df8bae1dSRodney W. Grimes * observed when placing information in the receive buffer: 311df8bae1dSRodney W. Grimes * 312df8bae1dSRodney W. Grimes * 1. If the protocol requires each message be preceded by the sender's 313df8bae1dSRodney W. Grimes * name, then a record containing that name must be present before 314df8bae1dSRodney W. Grimes * any associated data (mbuf's must be of type MT_SONAME). 315df8bae1dSRodney W. Grimes * 2. If the protocol supports the exchange of ``access rights'' (really 316df8bae1dSRodney W. Grimes * just additional data associated with the message), and there are 317df8bae1dSRodney W. Grimes * ``rights'' to be received, then a record containing this data 318df8bae1dSRodney W. Grimes * should be present (mbuf's must be of type MT_RIGHTS). 319df8bae1dSRodney W. Grimes * 3. If a name or rights record exists, then it must be followed by 320df8bae1dSRodney W. Grimes * a data record, perhaps of zero length. 321df8bae1dSRodney W. Grimes * 322df8bae1dSRodney W. Grimes * Before using a new socket structure it is first necessary to reserve 323df8bae1dSRodney W. Grimes * buffer space to the socket, by calling sbreserve(). This should commit 324df8bae1dSRodney W. Grimes * some of the available buffer space in the system buffer pool for the 325df8bae1dSRodney W. Grimes * socket (currently, it does nothing but enforce limits). The space 326df8bae1dSRodney W. Grimes * should be released by calling sbrelease() when the socket is destroyed. 327df8bae1dSRodney W. Grimes */ 328df8bae1dSRodney W. Grimes 32926f9a767SRodney W. Grimes int 330df8bae1dSRodney W. Grimes soreserve(so, sndcc, rcvcc) 331df8bae1dSRodney W. Grimes register struct socket *so; 332df8bae1dSRodney W. Grimes u_long sndcc, rcvcc; 333df8bae1dSRodney W. Grimes { 334df8bae1dSRodney W. Grimes 335df8bae1dSRodney W. Grimes if (sbreserve(&so->so_snd, sndcc) == 0) 336df8bae1dSRodney W. Grimes goto bad; 337df8bae1dSRodney W. Grimes if (sbreserve(&so->so_rcv, rcvcc) == 0) 338df8bae1dSRodney W. Grimes goto bad2; 339df8bae1dSRodney W. Grimes if (so->so_rcv.sb_lowat == 0) 340df8bae1dSRodney W. Grimes so->so_rcv.sb_lowat = 1; 341df8bae1dSRodney W. Grimes if (so->so_snd.sb_lowat == 0) 342df8bae1dSRodney W. Grimes so->so_snd.sb_lowat = MCLBYTES; 343df8bae1dSRodney W. Grimes if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat) 344df8bae1dSRodney W. Grimes so->so_snd.sb_lowat = so->so_snd.sb_hiwat; 345df8bae1dSRodney W. Grimes return (0); 346df8bae1dSRodney W. Grimes bad2: 347df8bae1dSRodney W. Grimes sbrelease(&so->so_snd); 348df8bae1dSRodney W. Grimes bad: 349df8bae1dSRodney W. Grimes return (ENOBUFS); 350df8bae1dSRodney W. Grimes } 351df8bae1dSRodney W. Grimes 352df8bae1dSRodney W. Grimes /* 353df8bae1dSRodney W. Grimes * Allot mbufs to a sockbuf. 354df8bae1dSRodney W. Grimes * Attempt to scale mbmax so that mbcnt doesn't become limiting 355df8bae1dSRodney W. Grimes * if buffering efficiency is near the normal case. 356df8bae1dSRodney W. Grimes */ 35726f9a767SRodney W. Grimes int 358df8bae1dSRodney W. Grimes sbreserve(sb, cc) 359df8bae1dSRodney W. Grimes struct sockbuf *sb; 360df8bae1dSRodney W. Grimes u_long cc; 361df8bae1dSRodney W. Grimes { 362df8bae1dSRodney W. Grimes 363df8bae1dSRodney W. Grimes if (cc > sb_max * MCLBYTES / (MSIZE + MCLBYTES)) 364df8bae1dSRodney W. Grimes return (0); 365df8bae1dSRodney W. Grimes sb->sb_hiwat = cc; 3664b29bc4fSGarrett Wollman sb->sb_mbmax = min(cc * sb_efficiency, sb_max); 367df8bae1dSRodney W. Grimes if (sb->sb_lowat > sb->sb_hiwat) 368df8bae1dSRodney W. Grimes sb->sb_lowat = sb->sb_hiwat; 369df8bae1dSRodney W. Grimes return (1); 370df8bae1dSRodney W. Grimes } 371df8bae1dSRodney W. Grimes 372df8bae1dSRodney W. Grimes /* 373df8bae1dSRodney W. Grimes * Free mbufs held by a socket, and reserved mbuf space. 374df8bae1dSRodney W. Grimes */ 37526f9a767SRodney W. Grimes void 376df8bae1dSRodney W. Grimes sbrelease(sb) 377df8bae1dSRodney W. Grimes struct sockbuf *sb; 378df8bae1dSRodney W. Grimes { 379df8bae1dSRodney W. Grimes 380df8bae1dSRodney W. Grimes sbflush(sb); 381df8bae1dSRodney W. Grimes sb->sb_hiwat = sb->sb_mbmax = 0; 382df8bae1dSRodney W. Grimes } 383df8bae1dSRodney W. Grimes 384df8bae1dSRodney W. Grimes /* 385df8bae1dSRodney W. Grimes * Routines to add and remove 386df8bae1dSRodney W. Grimes * data from an mbuf queue. 387df8bae1dSRodney W. Grimes * 388df8bae1dSRodney W. Grimes * The routines sbappend() or sbappendrecord() are normally called to 389df8bae1dSRodney W. Grimes * append new mbufs to a socket buffer, after checking that adequate 390df8bae1dSRodney W. Grimes * space is available, comparing the function sbspace() with the amount 391df8bae1dSRodney W. Grimes * of data to be added. sbappendrecord() differs from sbappend() in 392df8bae1dSRodney W. Grimes * that data supplied is treated as the beginning of a new record. 393df8bae1dSRodney W. Grimes * To place a sender's address, optional access rights, and data in a 394df8bae1dSRodney W. Grimes * socket receive buffer, sbappendaddr() should be used. To place 395df8bae1dSRodney W. Grimes * access rights and data in a socket receive buffer, sbappendrights() 396df8bae1dSRodney W. Grimes * should be used. In either case, the new data begins a new record. 397df8bae1dSRodney W. Grimes * Note that unlike sbappend() and sbappendrecord(), these routines check 398df8bae1dSRodney W. Grimes * for the caller that there will be enough space to store the data. 399df8bae1dSRodney W. Grimes * Each fails if there is not enough space, or if it cannot find mbufs 400df8bae1dSRodney W. Grimes * to store additional information in. 401df8bae1dSRodney W. Grimes * 402df8bae1dSRodney W. Grimes * Reliable protocols may use the socket send buffer to hold data 403df8bae1dSRodney W. Grimes * awaiting acknowledgement. Data is normally copied from a socket 404df8bae1dSRodney W. Grimes * send buffer in a protocol with m_copy for output to a peer, 405df8bae1dSRodney W. Grimes * and then removing the data from the socket buffer with sbdrop() 406df8bae1dSRodney W. Grimes * or sbdroprecord() when the data is acknowledged by the peer. 407df8bae1dSRodney W. Grimes */ 408df8bae1dSRodney W. Grimes 409df8bae1dSRodney W. Grimes /* 410df8bae1dSRodney W. Grimes * Append mbuf chain m to the last record in the 411df8bae1dSRodney W. Grimes * socket buffer sb. The additional space associated 412df8bae1dSRodney W. Grimes * the mbuf chain is recorded in sb. Empty mbufs are 413df8bae1dSRodney W. Grimes * discarded and mbufs are compacted where possible. 414df8bae1dSRodney W. Grimes */ 41526f9a767SRodney W. Grimes void 416df8bae1dSRodney W. Grimes sbappend(sb, m) 417df8bae1dSRodney W. Grimes struct sockbuf *sb; 418df8bae1dSRodney W. Grimes struct mbuf *m; 419df8bae1dSRodney W. Grimes { 420df8bae1dSRodney W. Grimes register struct mbuf *n; 421df8bae1dSRodney W. Grimes 422df8bae1dSRodney W. Grimes if (m == 0) 423df8bae1dSRodney W. Grimes return; 424797f2d22SPoul-Henning Kamp n = sb->sb_mb; 425797f2d22SPoul-Henning Kamp if (n) { 426df8bae1dSRodney W. Grimes while (n->m_nextpkt) 427df8bae1dSRodney W. Grimes n = n->m_nextpkt; 428df8bae1dSRodney W. Grimes do { 429df8bae1dSRodney W. Grimes if (n->m_flags & M_EOR) { 430df8bae1dSRodney W. Grimes sbappendrecord(sb, m); /* XXXXXX!!!! */ 431df8bae1dSRodney W. Grimes return; 432df8bae1dSRodney W. Grimes } 433df8bae1dSRodney W. Grimes } while (n->m_next && (n = n->m_next)); 434df8bae1dSRodney W. Grimes } 435df8bae1dSRodney W. Grimes sbcompress(sb, m, n); 436df8bae1dSRodney W. Grimes } 437df8bae1dSRodney W. Grimes 438df8bae1dSRodney W. Grimes #ifdef SOCKBUF_DEBUG 43926f9a767SRodney W. Grimes void 440df8bae1dSRodney W. Grimes sbcheck(sb) 441df8bae1dSRodney W. Grimes register struct sockbuf *sb; 442df8bae1dSRodney W. Grimes { 443df8bae1dSRodney W. Grimes register struct mbuf *m; 444df8bae1dSRodney W. Grimes register int len = 0, mbcnt = 0; 445df8bae1dSRodney W. Grimes 446df8bae1dSRodney W. Grimes for (m = sb->sb_mb; m; m = m->m_next) { 447df8bae1dSRodney W. Grimes len += m->m_len; 448df8bae1dSRodney W. Grimes mbcnt += MSIZE; 449313861b8SJulian Elischer if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */ 450df8bae1dSRodney W. Grimes mbcnt += m->m_ext.ext_size; 451df8bae1dSRodney W. Grimes if (m->m_nextpkt) 452df8bae1dSRodney W. Grimes panic("sbcheck nextpkt"); 453df8bae1dSRodney W. Grimes } 454df8bae1dSRodney W. Grimes if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { 455df8bae1dSRodney W. Grimes printf("cc %d != %d || mbcnt %d != %d\n", len, sb->sb_cc, 456df8bae1dSRodney W. Grimes mbcnt, sb->sb_mbcnt); 457df8bae1dSRodney W. Grimes panic("sbcheck"); 458df8bae1dSRodney W. Grimes } 459df8bae1dSRodney W. Grimes } 460df8bae1dSRodney W. Grimes #endif 461df8bae1dSRodney W. Grimes 462df8bae1dSRodney W. Grimes /* 463df8bae1dSRodney W. Grimes * As above, except the mbuf chain 464df8bae1dSRodney W. Grimes * begins a new record. 465df8bae1dSRodney W. Grimes */ 46626f9a767SRodney W. Grimes void 467df8bae1dSRodney W. Grimes sbappendrecord(sb, m0) 468df8bae1dSRodney W. Grimes register struct sockbuf *sb; 469df8bae1dSRodney W. Grimes register struct mbuf *m0; 470df8bae1dSRodney W. Grimes { 471df8bae1dSRodney W. Grimes register struct mbuf *m; 472df8bae1dSRodney W. Grimes 473df8bae1dSRodney W. Grimes if (m0 == 0) 474df8bae1dSRodney W. Grimes return; 475797f2d22SPoul-Henning Kamp m = sb->sb_mb; 476797f2d22SPoul-Henning Kamp if (m) 477df8bae1dSRodney W. Grimes while (m->m_nextpkt) 478df8bae1dSRodney W. Grimes m = m->m_nextpkt; 479df8bae1dSRodney W. Grimes /* 480df8bae1dSRodney W. Grimes * Put the first mbuf on the queue. 481df8bae1dSRodney W. Grimes * Note this permits zero length records. 482df8bae1dSRodney W. Grimes */ 483df8bae1dSRodney W. Grimes sballoc(sb, m0); 484df8bae1dSRodney W. Grimes if (m) 485df8bae1dSRodney W. Grimes m->m_nextpkt = m0; 486df8bae1dSRodney W. Grimes else 487df8bae1dSRodney W. Grimes sb->sb_mb = m0; 488df8bae1dSRodney W. Grimes m = m0->m_next; 489df8bae1dSRodney W. Grimes m0->m_next = 0; 490df8bae1dSRodney W. Grimes if (m && (m0->m_flags & M_EOR)) { 491df8bae1dSRodney W. Grimes m0->m_flags &= ~M_EOR; 492df8bae1dSRodney W. Grimes m->m_flags |= M_EOR; 493df8bae1dSRodney W. Grimes } 494df8bae1dSRodney W. Grimes sbcompress(sb, m, m0); 495df8bae1dSRodney W. Grimes } 496df8bae1dSRodney W. Grimes 497df8bae1dSRodney W. Grimes /* 498df8bae1dSRodney W. Grimes * As above except that OOB data 499df8bae1dSRodney W. Grimes * is inserted at the beginning of the sockbuf, 500df8bae1dSRodney W. Grimes * but after any other OOB data. 501df8bae1dSRodney W. Grimes */ 50226f9a767SRodney W. Grimes void 503df8bae1dSRodney W. Grimes sbinsertoob(sb, m0) 504df8bae1dSRodney W. Grimes register struct sockbuf *sb; 505df8bae1dSRodney W. Grimes register struct mbuf *m0; 506df8bae1dSRodney W. Grimes { 507df8bae1dSRodney W. Grimes register struct mbuf *m; 508df8bae1dSRodney W. Grimes register struct mbuf **mp; 509df8bae1dSRodney W. Grimes 510df8bae1dSRodney W. Grimes if (m0 == 0) 511df8bae1dSRodney W. Grimes return; 512797f2d22SPoul-Henning Kamp for (mp = &sb->sb_mb; *mp ; mp = &((*mp)->m_nextpkt)) { 513797f2d22SPoul-Henning Kamp m = *mp; 514df8bae1dSRodney W. Grimes again: 515df8bae1dSRodney W. Grimes switch (m->m_type) { 516df8bae1dSRodney W. Grimes 517df8bae1dSRodney W. Grimes case MT_OOBDATA: 518df8bae1dSRodney W. Grimes continue; /* WANT next train */ 519df8bae1dSRodney W. Grimes 520df8bae1dSRodney W. Grimes case MT_CONTROL: 521797f2d22SPoul-Henning Kamp m = m->m_next; 522797f2d22SPoul-Henning Kamp if (m) 523df8bae1dSRodney W. Grimes goto again; /* inspect THIS train further */ 524df8bae1dSRodney W. Grimes } 525df8bae1dSRodney W. Grimes break; 526df8bae1dSRodney W. Grimes } 527df8bae1dSRodney W. Grimes /* 528df8bae1dSRodney W. Grimes * Put the first mbuf on the queue. 529df8bae1dSRodney W. Grimes * Note this permits zero length records. 530df8bae1dSRodney W. Grimes */ 531df8bae1dSRodney W. Grimes sballoc(sb, m0); 532df8bae1dSRodney W. Grimes m0->m_nextpkt = *mp; 533df8bae1dSRodney W. Grimes *mp = m0; 534df8bae1dSRodney W. Grimes m = m0->m_next; 535df8bae1dSRodney W. Grimes m0->m_next = 0; 536df8bae1dSRodney W. Grimes if (m && (m0->m_flags & M_EOR)) { 537df8bae1dSRodney W. Grimes m0->m_flags &= ~M_EOR; 538df8bae1dSRodney W. Grimes m->m_flags |= M_EOR; 539df8bae1dSRodney W. Grimes } 540df8bae1dSRodney W. Grimes sbcompress(sb, m, m0); 541df8bae1dSRodney W. Grimes } 542df8bae1dSRodney W. Grimes 543df8bae1dSRodney W. Grimes /* 544df8bae1dSRodney W. Grimes * Append address and data, and optionally, control (ancillary) data 545df8bae1dSRodney W. Grimes * to the receive queue of a socket. If present, 546df8bae1dSRodney W. Grimes * m0 must include a packet header with total length. 547df8bae1dSRodney W. Grimes * Returns 0 if no space in sockbuf or insufficient mbufs. 548df8bae1dSRodney W. Grimes */ 54926f9a767SRodney W. Grimes int 550df8bae1dSRodney W. Grimes sbappendaddr(sb, asa, m0, control) 551df8bae1dSRodney W. Grimes register struct sockbuf *sb; 552df8bae1dSRodney W. Grimes struct sockaddr *asa; 553df8bae1dSRodney W. Grimes struct mbuf *m0, *control; 554df8bae1dSRodney W. Grimes { 555df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 556df8bae1dSRodney W. Grimes int space = asa->sa_len; 557df8bae1dSRodney W. Grimes 558df8bae1dSRodney W. Grimes if (m0 && (m0->m_flags & M_PKTHDR) == 0) 559df8bae1dSRodney W. Grimes panic("sbappendaddr"); 560df8bae1dSRodney W. Grimes if (m0) 561df8bae1dSRodney W. Grimes space += m0->m_pkthdr.len; 562df8bae1dSRodney W. Grimes for (n = control; n; n = n->m_next) { 563df8bae1dSRodney W. Grimes space += n->m_len; 564df8bae1dSRodney W. Grimes if (n->m_next == 0) /* keep pointer to last control buf */ 565df8bae1dSRodney W. Grimes break; 566df8bae1dSRodney W. Grimes } 567df8bae1dSRodney W. Grimes if (space > sbspace(sb)) 568df8bae1dSRodney W. Grimes return (0); 569df8bae1dSRodney W. Grimes if (asa->sa_len > MLEN) 570df8bae1dSRodney W. Grimes return (0); 571df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, MT_SONAME); 572df8bae1dSRodney W. Grimes if (m == 0) 573df8bae1dSRodney W. Grimes return (0); 574df8bae1dSRodney W. Grimes m->m_len = asa->sa_len; 575df8bae1dSRodney W. Grimes bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len); 576df8bae1dSRodney W. Grimes if (n) 577df8bae1dSRodney W. Grimes n->m_next = m0; /* concatenate data to control */ 578df8bae1dSRodney W. Grimes else 579df8bae1dSRodney W. Grimes control = m0; 580df8bae1dSRodney W. Grimes m->m_next = control; 581df8bae1dSRodney W. Grimes for (n = m; n; n = n->m_next) 582df8bae1dSRodney W. Grimes sballoc(sb, n); 583797f2d22SPoul-Henning Kamp n = sb->sb_mb; 584797f2d22SPoul-Henning Kamp if (n) { 585df8bae1dSRodney W. Grimes while (n->m_nextpkt) 586df8bae1dSRodney W. Grimes n = n->m_nextpkt; 587df8bae1dSRodney W. Grimes n->m_nextpkt = m; 588df8bae1dSRodney W. Grimes } else 589df8bae1dSRodney W. Grimes sb->sb_mb = m; 590df8bae1dSRodney W. Grimes return (1); 591df8bae1dSRodney W. Grimes } 592df8bae1dSRodney W. Grimes 59326f9a767SRodney W. Grimes int 594df8bae1dSRodney W. Grimes sbappendcontrol(sb, m0, control) 595df8bae1dSRodney W. Grimes struct sockbuf *sb; 596df8bae1dSRodney W. Grimes struct mbuf *control, *m0; 597df8bae1dSRodney W. Grimes { 598df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 599df8bae1dSRodney W. Grimes int space = 0; 600df8bae1dSRodney W. Grimes 601df8bae1dSRodney W. Grimes if (control == 0) 602df8bae1dSRodney W. Grimes panic("sbappendcontrol"); 603df8bae1dSRodney W. Grimes for (m = control; ; m = m->m_next) { 604df8bae1dSRodney W. Grimes space += m->m_len; 605df8bae1dSRodney W. Grimes if (m->m_next == 0) 606df8bae1dSRodney W. Grimes break; 607df8bae1dSRodney W. Grimes } 608df8bae1dSRodney W. Grimes n = m; /* save pointer to last control buffer */ 609df8bae1dSRodney W. Grimes for (m = m0; m; m = m->m_next) 610df8bae1dSRodney W. Grimes space += m->m_len; 611df8bae1dSRodney W. Grimes if (space > sbspace(sb)) 612df8bae1dSRodney W. Grimes return (0); 613df8bae1dSRodney W. Grimes n->m_next = m0; /* concatenate data to control */ 614df8bae1dSRodney W. Grimes for (m = control; m; m = m->m_next) 615df8bae1dSRodney W. Grimes sballoc(sb, m); 616797f2d22SPoul-Henning Kamp n = sb->sb_mb; 617797f2d22SPoul-Henning Kamp if (n) { 618df8bae1dSRodney W. Grimes while (n->m_nextpkt) 619df8bae1dSRodney W. Grimes n = n->m_nextpkt; 620df8bae1dSRodney W. Grimes n->m_nextpkt = control; 621df8bae1dSRodney W. Grimes } else 622df8bae1dSRodney W. Grimes sb->sb_mb = control; 623df8bae1dSRodney W. Grimes return (1); 624df8bae1dSRodney W. Grimes } 625df8bae1dSRodney W. Grimes 626df8bae1dSRodney W. Grimes /* 627df8bae1dSRodney W. Grimes * Compress mbuf chain m into the socket 628df8bae1dSRodney W. Grimes * buffer sb following mbuf n. If n 629df8bae1dSRodney W. Grimes * is null, the buffer is presumed empty. 630df8bae1dSRodney W. Grimes */ 63126f9a767SRodney W. Grimes void 632df8bae1dSRodney W. Grimes sbcompress(sb, m, n) 633df8bae1dSRodney W. Grimes register struct sockbuf *sb; 634df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 635df8bae1dSRodney W. Grimes { 636df8bae1dSRodney W. Grimes register int eor = 0; 637df8bae1dSRodney W. Grimes register struct mbuf *o; 638df8bae1dSRodney W. Grimes 639df8bae1dSRodney W. Grimes while (m) { 640df8bae1dSRodney W. Grimes eor |= m->m_flags & M_EOR; 641df8bae1dSRodney W. Grimes if (m->m_len == 0 && 642df8bae1dSRodney W. Grimes (eor == 0 || 643df8bae1dSRodney W. Grimes (((o = m->m_next) || (o = n)) && 644df8bae1dSRodney W. Grimes o->m_type == m->m_type))) { 645df8bae1dSRodney W. Grimes m = m_free(m); 646df8bae1dSRodney W. Grimes continue; 647df8bae1dSRodney W. Grimes } 648df8bae1dSRodney W. Grimes if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 && 649df8bae1dSRodney W. Grimes (n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] && 650df8bae1dSRodney W. Grimes n->m_type == m->m_type) { 651df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len, 652df8bae1dSRodney W. Grimes (unsigned)m->m_len); 653df8bae1dSRodney W. Grimes n->m_len += m->m_len; 654df8bae1dSRodney W. Grimes sb->sb_cc += m->m_len; 655df8bae1dSRodney W. Grimes m = m_free(m); 656df8bae1dSRodney W. Grimes continue; 657df8bae1dSRodney W. Grimes } 658df8bae1dSRodney W. Grimes if (n) 659df8bae1dSRodney W. Grimes n->m_next = m; 660df8bae1dSRodney W. Grimes else 661df8bae1dSRodney W. Grimes sb->sb_mb = m; 662df8bae1dSRodney W. Grimes sballoc(sb, m); 663df8bae1dSRodney W. Grimes n = m; 664df8bae1dSRodney W. Grimes m->m_flags &= ~M_EOR; 665df8bae1dSRodney W. Grimes m = m->m_next; 666df8bae1dSRodney W. Grimes n->m_next = 0; 667df8bae1dSRodney W. Grimes } 668df8bae1dSRodney W. Grimes if (eor) { 669df8bae1dSRodney W. Grimes if (n) 670df8bae1dSRodney W. Grimes n->m_flags |= eor; 671df8bae1dSRodney W. Grimes else 672df8bae1dSRodney W. Grimes printf("semi-panic: sbcompress\n"); 673df8bae1dSRodney W. Grimes } 674df8bae1dSRodney W. Grimes } 675df8bae1dSRodney W. Grimes 676df8bae1dSRodney W. Grimes /* 677df8bae1dSRodney W. Grimes * Free all mbufs in a sockbuf. 678df8bae1dSRodney W. Grimes * Check that all resources are reclaimed. 679df8bae1dSRodney W. Grimes */ 68026f9a767SRodney W. Grimes void 681df8bae1dSRodney W. Grimes sbflush(sb) 682df8bae1dSRodney W. Grimes register struct sockbuf *sb; 683df8bae1dSRodney W. Grimes { 684df8bae1dSRodney W. Grimes 685df8bae1dSRodney W. Grimes if (sb->sb_flags & SB_LOCK) 686df8bae1dSRodney W. Grimes panic("sbflush"); 687df8bae1dSRodney W. Grimes while (sb->sb_mbcnt) 688df8bae1dSRodney W. Grimes sbdrop(sb, (int)sb->sb_cc); 689df8bae1dSRodney W. Grimes if (sb->sb_cc || sb->sb_mb) 690df8bae1dSRodney W. Grimes panic("sbflush 2"); 691df8bae1dSRodney W. Grimes } 692df8bae1dSRodney W. Grimes 693df8bae1dSRodney W. Grimes /* 694df8bae1dSRodney W. Grimes * Drop data from (the front of) a sockbuf. 695df8bae1dSRodney W. Grimes */ 69626f9a767SRodney W. Grimes void 697df8bae1dSRodney W. Grimes sbdrop(sb, len) 698df8bae1dSRodney W. Grimes register struct sockbuf *sb; 699df8bae1dSRodney W. Grimes register int len; 700df8bae1dSRodney W. Grimes { 701df8bae1dSRodney W. Grimes register struct mbuf *m, *mn; 702df8bae1dSRodney W. Grimes struct mbuf *next; 703df8bae1dSRodney W. Grimes 704df8bae1dSRodney W. Grimes next = (m = sb->sb_mb) ? m->m_nextpkt : 0; 705df8bae1dSRodney W. Grimes while (len > 0) { 706df8bae1dSRodney W. Grimes if (m == 0) { 707df8bae1dSRodney W. Grimes if (next == 0) 708df8bae1dSRodney W. Grimes panic("sbdrop"); 709df8bae1dSRodney W. Grimes m = next; 710df8bae1dSRodney W. Grimes next = m->m_nextpkt; 711df8bae1dSRodney W. Grimes continue; 712df8bae1dSRodney W. Grimes } 713df8bae1dSRodney W. Grimes if (m->m_len > len) { 714df8bae1dSRodney W. Grimes m->m_len -= len; 715df8bae1dSRodney W. Grimes m->m_data += len; 716df8bae1dSRodney W. Grimes sb->sb_cc -= len; 717df8bae1dSRodney W. Grimes break; 718df8bae1dSRodney W. Grimes } 719df8bae1dSRodney W. Grimes len -= m->m_len; 720df8bae1dSRodney W. Grimes sbfree(sb, m); 721df8bae1dSRodney W. Grimes MFREE(m, mn); 722df8bae1dSRodney W. Grimes m = mn; 723df8bae1dSRodney W. Grimes } 724df8bae1dSRodney W. Grimes while (m && m->m_len == 0) { 725df8bae1dSRodney W. Grimes sbfree(sb, m); 726df8bae1dSRodney W. Grimes MFREE(m, mn); 727df8bae1dSRodney W. Grimes m = mn; 728df8bae1dSRodney W. Grimes } 729df8bae1dSRodney W. Grimes if (m) { 730df8bae1dSRodney W. Grimes sb->sb_mb = m; 731df8bae1dSRodney W. Grimes m->m_nextpkt = next; 732df8bae1dSRodney W. Grimes } else 733df8bae1dSRodney W. Grimes sb->sb_mb = next; 734df8bae1dSRodney W. Grimes } 735df8bae1dSRodney W. Grimes 736df8bae1dSRodney W. Grimes /* 737df8bae1dSRodney W. Grimes * Drop a record off the front of a sockbuf 738df8bae1dSRodney W. Grimes * and move the next record to the front. 739df8bae1dSRodney W. Grimes */ 74026f9a767SRodney W. Grimes void 741df8bae1dSRodney W. Grimes sbdroprecord(sb) 742df8bae1dSRodney W. Grimes register struct sockbuf *sb; 743df8bae1dSRodney W. Grimes { 744df8bae1dSRodney W. Grimes register struct mbuf *m, *mn; 745df8bae1dSRodney W. Grimes 746df8bae1dSRodney W. Grimes m = sb->sb_mb; 747df8bae1dSRodney W. Grimes if (m) { 748df8bae1dSRodney W. Grimes sb->sb_mb = m->m_nextpkt; 749df8bae1dSRodney W. Grimes do { 750df8bae1dSRodney W. Grimes sbfree(sb, m); 751df8bae1dSRodney W. Grimes MFREE(m, mn); 752797f2d22SPoul-Henning Kamp m = mn; 753797f2d22SPoul-Henning Kamp } while (m); 754df8bae1dSRodney W. Grimes } 755df8bae1dSRodney W. Grimes } 7561e4ad9ceSGarrett Wollman 7571e4ad9ceSGarrett Wollman #ifdef PRU_OLDSTYLE 7581e4ad9ceSGarrett Wollman /* 7591e4ad9ceSGarrett Wollman * The following routines mediate between the old-style `pr_usrreq' 7601e4ad9ceSGarrett Wollman * protocol implementations and the new-style `struct pr_usrreqs' 7611e4ad9ceSGarrett Wollman * calling convention. 7621e4ad9ceSGarrett Wollman */ 7631e4ad9ceSGarrett Wollman 7641e4ad9ceSGarrett Wollman /* syntactic sugar */ 7651e4ad9ceSGarrett Wollman #define nomb (struct mbuf *)0 7661e4ad9ceSGarrett Wollman 7671e4ad9ceSGarrett Wollman static int 7681e4ad9ceSGarrett Wollman old_abort(struct socket *so) 7691e4ad9ceSGarrett Wollman { 7702c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_ABORT, nomb, nomb, nomb); 7711e4ad9ceSGarrett Wollman } 7721e4ad9ceSGarrett Wollman 7731e4ad9ceSGarrett Wollman static int 7741e4ad9ceSGarrett Wollman old_accept(struct socket *so, struct mbuf *nam) 7751e4ad9ceSGarrett Wollman { 7762c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_ACCEPT, nomb, nam, nomb); 7771e4ad9ceSGarrett Wollman } 7781e4ad9ceSGarrett Wollman 7791e4ad9ceSGarrett Wollman static int 7801e4ad9ceSGarrett Wollman old_attach(struct socket *so, int proto) 7811e4ad9ceSGarrett Wollman { 7822c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_ATTACH, nomb, 7831e4ad9ceSGarrett Wollman (struct mbuf *)proto, /* XXX */ 7841e4ad9ceSGarrett Wollman nomb); 7851e4ad9ceSGarrett Wollman } 7861e4ad9ceSGarrett Wollman 7871e4ad9ceSGarrett Wollman static int 7881e4ad9ceSGarrett Wollman old_bind(struct socket *so, struct mbuf *nam) 7891e4ad9ceSGarrett Wollman { 7902c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_BIND, nomb, nam, nomb); 7911e4ad9ceSGarrett Wollman } 7921e4ad9ceSGarrett Wollman 7931e4ad9ceSGarrett Wollman static int 7941e4ad9ceSGarrett Wollman old_connect(struct socket *so, struct mbuf *nam) 7951e4ad9ceSGarrett Wollman { 7962c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_CONNECT, nomb, nam, nomb); 7971e4ad9ceSGarrett Wollman } 7981e4ad9ceSGarrett Wollman 7991e4ad9ceSGarrett Wollman static int 8001e4ad9ceSGarrett Wollman old_connect2(struct socket *so1, struct socket *so2) 8011e4ad9ceSGarrett Wollman { 8022c37256eSGarrett Wollman return so1->so_proto->pr_ousrreq(so1, PRU_CONNECT2, nomb, 8031e4ad9ceSGarrett Wollman (struct mbuf *)so2, nomb); 8041e4ad9ceSGarrett Wollman } 8051e4ad9ceSGarrett Wollman 8061e4ad9ceSGarrett Wollman static int 8072c37256eSGarrett Wollman old_control(struct socket *so, int cmd, caddr_t data, struct ifnet *ifp) 8081e4ad9ceSGarrett Wollman { 8092c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_CONTROL, (struct mbuf *)cmd, 8102c37256eSGarrett Wollman (struct mbuf *)data, 8112c37256eSGarrett Wollman (struct mbuf *)ifp); 8121e4ad9ceSGarrett Wollman } 8131e4ad9ceSGarrett Wollman 8141e4ad9ceSGarrett Wollman static int 8151e4ad9ceSGarrett Wollman old_detach(struct socket *so) 8161e4ad9ceSGarrett Wollman { 8172c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_DETACH, nomb, nomb, nomb); 8181e4ad9ceSGarrett Wollman } 8191e4ad9ceSGarrett Wollman 8201e4ad9ceSGarrett Wollman static int 8211e4ad9ceSGarrett Wollman old_disconnect(struct socket *so) 8221e4ad9ceSGarrett Wollman { 8232c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_DISCONNECT, nomb, nomb, nomb); 8241e4ad9ceSGarrett Wollman } 8251e4ad9ceSGarrett Wollman 8261e4ad9ceSGarrett Wollman static int 8271e4ad9ceSGarrett Wollman old_listen(struct socket *so) 8281e4ad9ceSGarrett Wollman { 8292c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_LISTEN, nomb, nomb, nomb); 8301e4ad9ceSGarrett Wollman } 8311e4ad9ceSGarrett Wollman 8321e4ad9ceSGarrett Wollman static int 8331e4ad9ceSGarrett Wollman old_peeraddr(struct socket *so, struct mbuf *nam) 8341e4ad9ceSGarrett Wollman { 8352c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_PEERADDR, nomb, nam, nomb); 8361e4ad9ceSGarrett Wollman } 8371e4ad9ceSGarrett Wollman 8381e4ad9ceSGarrett Wollman static int 8391e4ad9ceSGarrett Wollman old_rcvd(struct socket *so, int flags) 8401e4ad9ceSGarrett Wollman { 8412c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_RCVD, nomb, 8421e4ad9ceSGarrett Wollman (struct mbuf *)flags, /* XXX */ 8431e4ad9ceSGarrett Wollman nomb); 8441e4ad9ceSGarrett Wollman } 8451e4ad9ceSGarrett Wollman 8461e4ad9ceSGarrett Wollman static int 8471e4ad9ceSGarrett Wollman old_rcvoob(struct socket *so, struct mbuf *m, int flags) 8481e4ad9ceSGarrett Wollman { 8492c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_RCVOOB, m, 8501e4ad9ceSGarrett Wollman (struct mbuf *)flags, /* XXX */ 8511e4ad9ceSGarrett Wollman nomb); 8521e4ad9ceSGarrett Wollman } 8531e4ad9ceSGarrett Wollman 8541e4ad9ceSGarrett Wollman static int 8551e4ad9ceSGarrett Wollman old_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *addr, 8561e4ad9ceSGarrett Wollman struct mbuf *control) 8571e4ad9ceSGarrett Wollman { 8581e4ad9ceSGarrett Wollman int req; 8591e4ad9ceSGarrett Wollman 8601e4ad9ceSGarrett Wollman if (flags & PRUS_OOB) { 8611e4ad9ceSGarrett Wollman req = PRU_SENDOOB; 8621e4ad9ceSGarrett Wollman } else if(flags & PRUS_EOF) { 8631e4ad9ceSGarrett Wollman req = PRU_SEND_EOF; 8641e4ad9ceSGarrett Wollman } else { 8651e4ad9ceSGarrett Wollman req = PRU_SEND; 8661e4ad9ceSGarrett Wollman } 8672c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, req, m, addr, control); 8681e4ad9ceSGarrett Wollman } 8691e4ad9ceSGarrett Wollman 8701e4ad9ceSGarrett Wollman static int 8711e4ad9ceSGarrett Wollman old_sense(struct socket *so, struct stat *sb) 8721e4ad9ceSGarrett Wollman { 8732c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_SENSE, (struct mbuf *)sb, 8741e4ad9ceSGarrett Wollman nomb, nomb); 8751e4ad9ceSGarrett Wollman } 8761e4ad9ceSGarrett Wollman 8771e4ad9ceSGarrett Wollman static int 8781e4ad9ceSGarrett Wollman old_shutdown(struct socket *so) 8791e4ad9ceSGarrett Wollman { 8802c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_SHUTDOWN, nomb, nomb, nomb); 8811e4ad9ceSGarrett Wollman } 8821e4ad9ceSGarrett Wollman 8831e4ad9ceSGarrett Wollman static int 8841e4ad9ceSGarrett Wollman old_sockaddr(struct socket *so, struct mbuf *nam) 8851e4ad9ceSGarrett Wollman { 8862c37256eSGarrett Wollman return so->so_proto->pr_ousrreq(so, PRU_SOCKADDR, nomb, nam, nomb); 8871e4ad9ceSGarrett Wollman } 8881e4ad9ceSGarrett Wollman 8891e4ad9ceSGarrett Wollman struct pr_usrreqs pru_oldstyle = { 8901e4ad9ceSGarrett Wollman old_abort, old_accept, old_attach, old_bind, old_connect, 8911e4ad9ceSGarrett Wollman old_connect2, old_control, old_detach, old_disconnect, 8921e4ad9ceSGarrett Wollman old_listen, old_peeraddr, old_rcvd, old_rcvoob, old_send, 8931e4ad9ceSGarrett Wollman old_sense, old_shutdown, old_sockaddr 8941e4ad9ceSGarrett Wollman }; 8951e4ad9ceSGarrett Wollman 8962c37256eSGarrett Wollman #endif /* PRU_OLDSTYLE */ 8972c37256eSGarrett Wollman 8981e4ad9ceSGarrett Wollman /* 8992c37256eSGarrett Wollman * Some routines that return EOPNOTSUPP for entry points that are not 9002c37256eSGarrett Wollman * supported by a protocol. Fill in as needed. 9011e4ad9ceSGarrett Wollman */ 9021e4ad9ceSGarrett Wollman int 9032c37256eSGarrett Wollman pru_connect2_notsupp(struct socket *so1, struct socket *so2) 9041e4ad9ceSGarrett Wollman { 9052c37256eSGarrett Wollman return EOPNOTSUPP; 9061e4ad9ceSGarrett Wollman } 907