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 341e4ad9ceSGarrett Wollman * $Id: uipc_socket2.c,v 1.10 1996/06/12 05:07:35 gpalmer 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++; 189df8bae1dSRodney W. Grimes if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH, 190df8bae1dSRodney W. Grimes (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)) { 191be24e9e8SDavid Greenman if (so->so_state & SS_COMP) { 192be24e9e8SDavid Greenman TAILQ_REMOVE(&head->so_comp, so, so_list); 193be24e9e8SDavid Greenman } else { 194be24e9e8SDavid Greenman TAILQ_REMOVE(&head->so_incomp, so, so_list); 195be24e9e8SDavid Greenman } 196be24e9e8SDavid Greenman head->so_qlen--; 197df8bae1dSRodney W. Grimes (void) free((caddr_t)so, M_SOCKET); 198df8bae1dSRodney W. Grimes return ((struct socket *)0); 199df8bae1dSRodney W. Grimes } 200df8bae1dSRodney W. Grimes if (connstatus) { 201df8bae1dSRodney W. Grimes sorwakeup(head); 202df8bae1dSRodney W. Grimes wakeup((caddr_t)&head->so_timeo); 203df8bae1dSRodney W. Grimes so->so_state |= connstatus; 204df8bae1dSRodney W. Grimes } 205df8bae1dSRodney W. Grimes return (so); 206df8bae1dSRodney W. Grimes } 207df8bae1dSRodney W. Grimes 208df8bae1dSRodney W. Grimes /* 209df8bae1dSRodney W. Grimes * Socantsendmore indicates that no more data will be sent on the 210df8bae1dSRodney W. Grimes * socket; it would normally be applied to a socket when the user 211df8bae1dSRodney W. Grimes * informs the system that no more data is to be sent, by the protocol 212df8bae1dSRodney W. Grimes * code (in case PRU_SHUTDOWN). Socantrcvmore indicates that no more data 213df8bae1dSRodney W. Grimes * will be received, and will normally be applied to the socket by a 214df8bae1dSRodney W. Grimes * protocol when it detects that the peer will send no more data. 215df8bae1dSRodney W. Grimes * Data queued for reading in the socket may yet be read. 216df8bae1dSRodney W. Grimes */ 217df8bae1dSRodney W. Grimes 21826f9a767SRodney W. Grimes void 219df8bae1dSRodney W. Grimes socantsendmore(so) 220df8bae1dSRodney W. Grimes struct socket *so; 221df8bae1dSRodney W. Grimes { 222df8bae1dSRodney W. Grimes 223df8bae1dSRodney W. Grimes so->so_state |= SS_CANTSENDMORE; 224df8bae1dSRodney W. Grimes sowwakeup(so); 225df8bae1dSRodney W. Grimes } 226df8bae1dSRodney W. Grimes 22726f9a767SRodney W. Grimes void 228df8bae1dSRodney W. Grimes socantrcvmore(so) 229df8bae1dSRodney W. Grimes struct socket *so; 230df8bae1dSRodney W. Grimes { 231df8bae1dSRodney W. Grimes 232df8bae1dSRodney W. Grimes so->so_state |= SS_CANTRCVMORE; 233df8bae1dSRodney W. Grimes sorwakeup(so); 234df8bae1dSRodney W. Grimes } 235df8bae1dSRodney W. Grimes 236df8bae1dSRodney W. Grimes /* 237df8bae1dSRodney W. Grimes * Wait for data to arrive at/drain from a socket buffer. 238df8bae1dSRodney W. Grimes */ 23926f9a767SRodney W. Grimes int 240df8bae1dSRodney W. Grimes sbwait(sb) 241df8bae1dSRodney W. Grimes struct sockbuf *sb; 242df8bae1dSRodney W. Grimes { 243df8bae1dSRodney W. Grimes 244df8bae1dSRodney W. Grimes sb->sb_flags |= SB_WAIT; 245df8bae1dSRodney W. Grimes return (tsleep((caddr_t)&sb->sb_cc, 24647daf5d5SBruce Evans (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait", 247df8bae1dSRodney W. Grimes sb->sb_timeo)); 248df8bae1dSRodney W. Grimes } 249df8bae1dSRodney W. Grimes 250df8bae1dSRodney W. Grimes /* 251df8bae1dSRodney W. Grimes * Lock a sockbuf already known to be locked; 252df8bae1dSRodney W. Grimes * return any error returned from sleep (EINTR). 253df8bae1dSRodney W. Grimes */ 25426f9a767SRodney W. Grimes int 255df8bae1dSRodney W. Grimes sb_lock(sb) 256df8bae1dSRodney W. Grimes register struct sockbuf *sb; 257df8bae1dSRodney W. Grimes { 258df8bae1dSRodney W. Grimes int error; 259df8bae1dSRodney W. Grimes 260df8bae1dSRodney W. Grimes while (sb->sb_flags & SB_LOCK) { 261df8bae1dSRodney W. Grimes sb->sb_flags |= SB_WANT; 262797f2d22SPoul-Henning Kamp error = tsleep((caddr_t)&sb->sb_flags, 263df8bae1dSRodney W. Grimes (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK|PCATCH, 26447daf5d5SBruce Evans "sblock", 0); 265797f2d22SPoul-Henning Kamp if (error) 266df8bae1dSRodney W. Grimes return (error); 267df8bae1dSRodney W. Grimes } 268df8bae1dSRodney W. Grimes sb->sb_flags |= SB_LOCK; 269df8bae1dSRodney W. Grimes return (0); 270df8bae1dSRodney W. Grimes } 271df8bae1dSRodney W. Grimes 272df8bae1dSRodney W. Grimes /* 273df8bae1dSRodney W. Grimes * Wakeup processes waiting on a socket buffer. 274df8bae1dSRodney W. Grimes * Do asynchronous notification via SIGIO 275df8bae1dSRodney W. Grimes * if the socket has the SS_ASYNC flag set. 276df8bae1dSRodney W. Grimes */ 27726f9a767SRodney W. Grimes void 278df8bae1dSRodney W. Grimes sowakeup(so, sb) 279df8bae1dSRodney W. Grimes register struct socket *so; 280df8bae1dSRodney W. Grimes register struct sockbuf *sb; 281df8bae1dSRodney W. Grimes { 282df8bae1dSRodney W. Grimes struct proc *p; 283df8bae1dSRodney W. Grimes 284df8bae1dSRodney W. Grimes selwakeup(&sb->sb_sel); 285df8bae1dSRodney W. Grimes sb->sb_flags &= ~SB_SEL; 286df8bae1dSRodney W. Grimes if (sb->sb_flags & SB_WAIT) { 287df8bae1dSRodney W. Grimes sb->sb_flags &= ~SB_WAIT; 288df8bae1dSRodney W. Grimes wakeup((caddr_t)&sb->sb_cc); 289df8bae1dSRodney W. Grimes } 290df8bae1dSRodney W. Grimes if (so->so_state & SS_ASYNC) { 291df8bae1dSRodney W. Grimes if (so->so_pgid < 0) 292df8bae1dSRodney W. Grimes gsignal(-so->so_pgid, SIGIO); 293df8bae1dSRodney W. Grimes else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 294df8bae1dSRodney W. Grimes psignal(p, SIGIO); 295df8bae1dSRodney W. Grimes } 296df8bae1dSRodney W. Grimes } 297df8bae1dSRodney W. Grimes 298df8bae1dSRodney W. Grimes /* 299df8bae1dSRodney W. Grimes * Socket buffer (struct sockbuf) utility routines. 300df8bae1dSRodney W. Grimes * 301df8bae1dSRodney W. Grimes * Each socket contains two socket buffers: one for sending data and 302df8bae1dSRodney W. Grimes * one for receiving data. Each buffer contains a queue of mbufs, 303df8bae1dSRodney W. Grimes * information about the number of mbufs and amount of data in the 304df8bae1dSRodney W. Grimes * queue, and other fields allowing select() statements and notification 305df8bae1dSRodney W. Grimes * on data availability to be implemented. 306df8bae1dSRodney W. Grimes * 307df8bae1dSRodney W. Grimes * Data stored in a socket buffer is maintained as a list of records. 308df8bae1dSRodney W. Grimes * Each record is a list of mbufs chained together with the m_next 309df8bae1dSRodney W. Grimes * field. Records are chained together with the m_nextpkt field. The upper 310df8bae1dSRodney W. Grimes * level routine soreceive() expects the following conventions to be 311df8bae1dSRodney W. Grimes * observed when placing information in the receive buffer: 312df8bae1dSRodney W. Grimes * 313df8bae1dSRodney W. Grimes * 1. If the protocol requires each message be preceded by the sender's 314df8bae1dSRodney W. Grimes * name, then a record containing that name must be present before 315df8bae1dSRodney W. Grimes * any associated data (mbuf's must be of type MT_SONAME). 316df8bae1dSRodney W. Grimes * 2. If the protocol supports the exchange of ``access rights'' (really 317df8bae1dSRodney W. Grimes * just additional data associated with the message), and there are 318df8bae1dSRodney W. Grimes * ``rights'' to be received, then a record containing this data 319df8bae1dSRodney W. Grimes * should be present (mbuf's must be of type MT_RIGHTS). 320df8bae1dSRodney W. Grimes * 3. If a name or rights record exists, then it must be followed by 321df8bae1dSRodney W. Grimes * a data record, perhaps of zero length. 322df8bae1dSRodney W. Grimes * 323df8bae1dSRodney W. Grimes * Before using a new socket structure it is first necessary to reserve 324df8bae1dSRodney W. Grimes * buffer space to the socket, by calling sbreserve(). This should commit 325df8bae1dSRodney W. Grimes * some of the available buffer space in the system buffer pool for the 326df8bae1dSRodney W. Grimes * socket (currently, it does nothing but enforce limits). The space 327df8bae1dSRodney W. Grimes * should be released by calling sbrelease() when the socket is destroyed. 328df8bae1dSRodney W. Grimes */ 329df8bae1dSRodney W. Grimes 33026f9a767SRodney W. Grimes int 331df8bae1dSRodney W. Grimes soreserve(so, sndcc, rcvcc) 332df8bae1dSRodney W. Grimes register struct socket *so; 333df8bae1dSRodney W. Grimes u_long sndcc, rcvcc; 334df8bae1dSRodney W. Grimes { 335df8bae1dSRodney W. Grimes 336df8bae1dSRodney W. Grimes if (sbreserve(&so->so_snd, sndcc) == 0) 337df8bae1dSRodney W. Grimes goto bad; 338df8bae1dSRodney W. Grimes if (sbreserve(&so->so_rcv, rcvcc) == 0) 339df8bae1dSRodney W. Grimes goto bad2; 340df8bae1dSRodney W. Grimes if (so->so_rcv.sb_lowat == 0) 341df8bae1dSRodney W. Grimes so->so_rcv.sb_lowat = 1; 342df8bae1dSRodney W. Grimes if (so->so_snd.sb_lowat == 0) 343df8bae1dSRodney W. Grimes so->so_snd.sb_lowat = MCLBYTES; 344df8bae1dSRodney W. Grimes if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat) 345df8bae1dSRodney W. Grimes so->so_snd.sb_lowat = so->so_snd.sb_hiwat; 346df8bae1dSRodney W. Grimes return (0); 347df8bae1dSRodney W. Grimes bad2: 348df8bae1dSRodney W. Grimes sbrelease(&so->so_snd); 349df8bae1dSRodney W. Grimes bad: 350df8bae1dSRodney W. Grimes return (ENOBUFS); 351df8bae1dSRodney W. Grimes } 352df8bae1dSRodney W. Grimes 353df8bae1dSRodney W. Grimes /* 354df8bae1dSRodney W. Grimes * Allot mbufs to a sockbuf. 355df8bae1dSRodney W. Grimes * Attempt to scale mbmax so that mbcnt doesn't become limiting 356df8bae1dSRodney W. Grimes * if buffering efficiency is near the normal case. 357df8bae1dSRodney W. Grimes */ 35826f9a767SRodney W. Grimes int 359df8bae1dSRodney W. Grimes sbreserve(sb, cc) 360df8bae1dSRodney W. Grimes struct sockbuf *sb; 361df8bae1dSRodney W. Grimes u_long cc; 362df8bae1dSRodney W. Grimes { 363df8bae1dSRodney W. Grimes 364df8bae1dSRodney W. Grimes if (cc > sb_max * MCLBYTES / (MSIZE + MCLBYTES)) 365df8bae1dSRodney W. Grimes return (0); 366df8bae1dSRodney W. Grimes sb->sb_hiwat = cc; 3674b29bc4fSGarrett Wollman sb->sb_mbmax = min(cc * sb_efficiency, sb_max); 368df8bae1dSRodney W. Grimes if (sb->sb_lowat > sb->sb_hiwat) 369df8bae1dSRodney W. Grimes sb->sb_lowat = sb->sb_hiwat; 370df8bae1dSRodney W. Grimes return (1); 371df8bae1dSRodney W. Grimes } 372df8bae1dSRodney W. Grimes 373df8bae1dSRodney W. Grimes /* 374df8bae1dSRodney W. Grimes * Free mbufs held by a socket, and reserved mbuf space. 375df8bae1dSRodney W. Grimes */ 37626f9a767SRodney W. Grimes void 377df8bae1dSRodney W. Grimes sbrelease(sb) 378df8bae1dSRodney W. Grimes struct sockbuf *sb; 379df8bae1dSRodney W. Grimes { 380df8bae1dSRodney W. Grimes 381df8bae1dSRodney W. Grimes sbflush(sb); 382df8bae1dSRodney W. Grimes sb->sb_hiwat = sb->sb_mbmax = 0; 383df8bae1dSRodney W. Grimes } 384df8bae1dSRodney W. Grimes 385df8bae1dSRodney W. Grimes /* 386df8bae1dSRodney W. Grimes * Routines to add and remove 387df8bae1dSRodney W. Grimes * data from an mbuf queue. 388df8bae1dSRodney W. Grimes * 389df8bae1dSRodney W. Grimes * The routines sbappend() or sbappendrecord() are normally called to 390df8bae1dSRodney W. Grimes * append new mbufs to a socket buffer, after checking that adequate 391df8bae1dSRodney W. Grimes * space is available, comparing the function sbspace() with the amount 392df8bae1dSRodney W. Grimes * of data to be added. sbappendrecord() differs from sbappend() in 393df8bae1dSRodney W. Grimes * that data supplied is treated as the beginning of a new record. 394df8bae1dSRodney W. Grimes * To place a sender's address, optional access rights, and data in a 395df8bae1dSRodney W. Grimes * socket receive buffer, sbappendaddr() should be used. To place 396df8bae1dSRodney W. Grimes * access rights and data in a socket receive buffer, sbappendrights() 397df8bae1dSRodney W. Grimes * should be used. In either case, the new data begins a new record. 398df8bae1dSRodney W. Grimes * Note that unlike sbappend() and sbappendrecord(), these routines check 399df8bae1dSRodney W. Grimes * for the caller that there will be enough space to store the data. 400df8bae1dSRodney W. Grimes * Each fails if there is not enough space, or if it cannot find mbufs 401df8bae1dSRodney W. Grimes * to store additional information in. 402df8bae1dSRodney W. Grimes * 403df8bae1dSRodney W. Grimes * Reliable protocols may use the socket send buffer to hold data 404df8bae1dSRodney W. Grimes * awaiting acknowledgement. Data is normally copied from a socket 405df8bae1dSRodney W. Grimes * send buffer in a protocol with m_copy for output to a peer, 406df8bae1dSRodney W. Grimes * and then removing the data from the socket buffer with sbdrop() 407df8bae1dSRodney W. Grimes * or sbdroprecord() when the data is acknowledged by the peer. 408df8bae1dSRodney W. Grimes */ 409df8bae1dSRodney W. Grimes 410df8bae1dSRodney W. Grimes /* 411df8bae1dSRodney W. Grimes * Append mbuf chain m to the last record in the 412df8bae1dSRodney W. Grimes * socket buffer sb. The additional space associated 413df8bae1dSRodney W. Grimes * the mbuf chain is recorded in sb. Empty mbufs are 414df8bae1dSRodney W. Grimes * discarded and mbufs are compacted where possible. 415df8bae1dSRodney W. Grimes */ 41626f9a767SRodney W. Grimes void 417df8bae1dSRodney W. Grimes sbappend(sb, m) 418df8bae1dSRodney W. Grimes struct sockbuf *sb; 419df8bae1dSRodney W. Grimes struct mbuf *m; 420df8bae1dSRodney W. Grimes { 421df8bae1dSRodney W. Grimes register struct mbuf *n; 422df8bae1dSRodney W. Grimes 423df8bae1dSRodney W. Grimes if (m == 0) 424df8bae1dSRodney W. Grimes return; 425797f2d22SPoul-Henning Kamp n = sb->sb_mb; 426797f2d22SPoul-Henning Kamp if (n) { 427df8bae1dSRodney W. Grimes while (n->m_nextpkt) 428df8bae1dSRodney W. Grimes n = n->m_nextpkt; 429df8bae1dSRodney W. Grimes do { 430df8bae1dSRodney W. Grimes if (n->m_flags & M_EOR) { 431df8bae1dSRodney W. Grimes sbappendrecord(sb, m); /* XXXXXX!!!! */ 432df8bae1dSRodney W. Grimes return; 433df8bae1dSRodney W. Grimes } 434df8bae1dSRodney W. Grimes } while (n->m_next && (n = n->m_next)); 435df8bae1dSRodney W. Grimes } 436df8bae1dSRodney W. Grimes sbcompress(sb, m, n); 437df8bae1dSRodney W. Grimes } 438df8bae1dSRodney W. Grimes 439df8bae1dSRodney W. Grimes #ifdef SOCKBUF_DEBUG 44026f9a767SRodney W. Grimes void 441df8bae1dSRodney W. Grimes sbcheck(sb) 442df8bae1dSRodney W. Grimes register struct sockbuf *sb; 443df8bae1dSRodney W. Grimes { 444df8bae1dSRodney W. Grimes register struct mbuf *m; 445df8bae1dSRodney W. Grimes register int len = 0, mbcnt = 0; 446df8bae1dSRodney W. Grimes 447df8bae1dSRodney W. Grimes for (m = sb->sb_mb; m; m = m->m_next) { 448df8bae1dSRodney W. Grimes len += m->m_len; 449df8bae1dSRodney W. Grimes mbcnt += MSIZE; 450df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) 451df8bae1dSRodney W. Grimes mbcnt += m->m_ext.ext_size; 452df8bae1dSRodney W. Grimes if (m->m_nextpkt) 453df8bae1dSRodney W. Grimes panic("sbcheck nextpkt"); 454df8bae1dSRodney W. Grimes } 455df8bae1dSRodney W. Grimes if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { 456df8bae1dSRodney W. Grimes printf("cc %d != %d || mbcnt %d != %d\n", len, sb->sb_cc, 457df8bae1dSRodney W. Grimes mbcnt, sb->sb_mbcnt); 458df8bae1dSRodney W. Grimes panic("sbcheck"); 459df8bae1dSRodney W. Grimes } 460df8bae1dSRodney W. Grimes } 461df8bae1dSRodney W. Grimes #endif 462df8bae1dSRodney W. Grimes 463df8bae1dSRodney W. Grimes /* 464df8bae1dSRodney W. Grimes * As above, except the mbuf chain 465df8bae1dSRodney W. Grimes * begins a new record. 466df8bae1dSRodney W. Grimes */ 46726f9a767SRodney W. Grimes void 468df8bae1dSRodney W. Grimes sbappendrecord(sb, m0) 469df8bae1dSRodney W. Grimes register struct sockbuf *sb; 470df8bae1dSRodney W. Grimes register struct mbuf *m0; 471df8bae1dSRodney W. Grimes { 472df8bae1dSRodney W. Grimes register struct mbuf *m; 473df8bae1dSRodney W. Grimes 474df8bae1dSRodney W. Grimes if (m0 == 0) 475df8bae1dSRodney W. Grimes return; 476797f2d22SPoul-Henning Kamp m = sb->sb_mb; 477797f2d22SPoul-Henning Kamp if (m) 478df8bae1dSRodney W. Grimes while (m->m_nextpkt) 479df8bae1dSRodney W. Grimes m = m->m_nextpkt; 480df8bae1dSRodney W. Grimes /* 481df8bae1dSRodney W. Grimes * Put the first mbuf on the queue. 482df8bae1dSRodney W. Grimes * Note this permits zero length records. 483df8bae1dSRodney W. Grimes */ 484df8bae1dSRodney W. Grimes sballoc(sb, m0); 485df8bae1dSRodney W. Grimes if (m) 486df8bae1dSRodney W. Grimes m->m_nextpkt = m0; 487df8bae1dSRodney W. Grimes else 488df8bae1dSRodney W. Grimes sb->sb_mb = m0; 489df8bae1dSRodney W. Grimes m = m0->m_next; 490df8bae1dSRodney W. Grimes m0->m_next = 0; 491df8bae1dSRodney W. Grimes if (m && (m0->m_flags & M_EOR)) { 492df8bae1dSRodney W. Grimes m0->m_flags &= ~M_EOR; 493df8bae1dSRodney W. Grimes m->m_flags |= M_EOR; 494df8bae1dSRodney W. Grimes } 495df8bae1dSRodney W. Grimes sbcompress(sb, m, m0); 496df8bae1dSRodney W. Grimes } 497df8bae1dSRodney W. Grimes 498df8bae1dSRodney W. Grimes /* 499df8bae1dSRodney W. Grimes * As above except that OOB data 500df8bae1dSRodney W. Grimes * is inserted at the beginning of the sockbuf, 501df8bae1dSRodney W. Grimes * but after any other OOB data. 502df8bae1dSRodney W. Grimes */ 50326f9a767SRodney W. Grimes void 504df8bae1dSRodney W. Grimes sbinsertoob(sb, m0) 505df8bae1dSRodney W. Grimes register struct sockbuf *sb; 506df8bae1dSRodney W. Grimes register struct mbuf *m0; 507df8bae1dSRodney W. Grimes { 508df8bae1dSRodney W. Grimes register struct mbuf *m; 509df8bae1dSRodney W. Grimes register struct mbuf **mp; 510df8bae1dSRodney W. Grimes 511df8bae1dSRodney W. Grimes if (m0 == 0) 512df8bae1dSRodney W. Grimes return; 513797f2d22SPoul-Henning Kamp for (mp = &sb->sb_mb; *mp ; mp = &((*mp)->m_nextpkt)) { 514797f2d22SPoul-Henning Kamp m = *mp; 515df8bae1dSRodney W. Grimes again: 516df8bae1dSRodney W. Grimes switch (m->m_type) { 517df8bae1dSRodney W. Grimes 518df8bae1dSRodney W. Grimes case MT_OOBDATA: 519df8bae1dSRodney W. Grimes continue; /* WANT next train */ 520df8bae1dSRodney W. Grimes 521df8bae1dSRodney W. Grimes case MT_CONTROL: 522797f2d22SPoul-Henning Kamp m = m->m_next; 523797f2d22SPoul-Henning Kamp if (m) 524df8bae1dSRodney W. Grimes goto again; /* inspect THIS train further */ 525df8bae1dSRodney W. Grimes } 526df8bae1dSRodney W. Grimes break; 527df8bae1dSRodney W. Grimes } 528df8bae1dSRodney W. Grimes /* 529df8bae1dSRodney W. Grimes * Put the first mbuf on the queue. 530df8bae1dSRodney W. Grimes * Note this permits zero length records. 531df8bae1dSRodney W. Grimes */ 532df8bae1dSRodney W. Grimes sballoc(sb, m0); 533df8bae1dSRodney W. Grimes m0->m_nextpkt = *mp; 534df8bae1dSRodney W. Grimes *mp = m0; 535df8bae1dSRodney W. Grimes m = m0->m_next; 536df8bae1dSRodney W. Grimes m0->m_next = 0; 537df8bae1dSRodney W. Grimes if (m && (m0->m_flags & M_EOR)) { 538df8bae1dSRodney W. Grimes m0->m_flags &= ~M_EOR; 539df8bae1dSRodney W. Grimes m->m_flags |= M_EOR; 540df8bae1dSRodney W. Grimes } 541df8bae1dSRodney W. Grimes sbcompress(sb, m, m0); 542df8bae1dSRodney W. Grimes } 543df8bae1dSRodney W. Grimes 544df8bae1dSRodney W. Grimes /* 545df8bae1dSRodney W. Grimes * Append address and data, and optionally, control (ancillary) data 546df8bae1dSRodney W. Grimes * to the receive queue of a socket. If present, 547df8bae1dSRodney W. Grimes * m0 must include a packet header with total length. 548df8bae1dSRodney W. Grimes * Returns 0 if no space in sockbuf or insufficient mbufs. 549df8bae1dSRodney W. Grimes */ 55026f9a767SRodney W. Grimes int 551df8bae1dSRodney W. Grimes sbappendaddr(sb, asa, m0, control) 552df8bae1dSRodney W. Grimes register struct sockbuf *sb; 553df8bae1dSRodney W. Grimes struct sockaddr *asa; 554df8bae1dSRodney W. Grimes struct mbuf *m0, *control; 555df8bae1dSRodney W. Grimes { 556df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 557df8bae1dSRodney W. Grimes int space = asa->sa_len; 558df8bae1dSRodney W. Grimes 559df8bae1dSRodney W. Grimes if (m0 && (m0->m_flags & M_PKTHDR) == 0) 560df8bae1dSRodney W. Grimes panic("sbappendaddr"); 561df8bae1dSRodney W. Grimes if (m0) 562df8bae1dSRodney W. Grimes space += m0->m_pkthdr.len; 563df8bae1dSRodney W. Grimes for (n = control; n; n = n->m_next) { 564df8bae1dSRodney W. Grimes space += n->m_len; 565df8bae1dSRodney W. Grimes if (n->m_next == 0) /* keep pointer to last control buf */ 566df8bae1dSRodney W. Grimes break; 567df8bae1dSRodney W. Grimes } 568df8bae1dSRodney W. Grimes if (space > sbspace(sb)) 569df8bae1dSRodney W. Grimes return (0); 570df8bae1dSRodney W. Grimes if (asa->sa_len > MLEN) 571df8bae1dSRodney W. Grimes return (0); 572df8bae1dSRodney W. Grimes MGET(m, M_DONTWAIT, MT_SONAME); 573df8bae1dSRodney W. Grimes if (m == 0) 574df8bae1dSRodney W. Grimes return (0); 575df8bae1dSRodney W. Grimes m->m_len = asa->sa_len; 576df8bae1dSRodney W. Grimes bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len); 577df8bae1dSRodney W. Grimes if (n) 578df8bae1dSRodney W. Grimes n->m_next = m0; /* concatenate data to control */ 579df8bae1dSRodney W. Grimes else 580df8bae1dSRodney W. Grimes control = m0; 581df8bae1dSRodney W. Grimes m->m_next = control; 582df8bae1dSRodney W. Grimes for (n = m; n; n = n->m_next) 583df8bae1dSRodney W. Grimes sballoc(sb, n); 584797f2d22SPoul-Henning Kamp n = sb->sb_mb; 585797f2d22SPoul-Henning Kamp if (n) { 586df8bae1dSRodney W. Grimes while (n->m_nextpkt) 587df8bae1dSRodney W. Grimes n = n->m_nextpkt; 588df8bae1dSRodney W. Grimes n->m_nextpkt = m; 589df8bae1dSRodney W. Grimes } else 590df8bae1dSRodney W. Grimes sb->sb_mb = m; 591df8bae1dSRodney W. Grimes return (1); 592df8bae1dSRodney W. Grimes } 593df8bae1dSRodney W. Grimes 59426f9a767SRodney W. Grimes int 595df8bae1dSRodney W. Grimes sbappendcontrol(sb, m0, control) 596df8bae1dSRodney W. Grimes struct sockbuf *sb; 597df8bae1dSRodney W. Grimes struct mbuf *control, *m0; 598df8bae1dSRodney W. Grimes { 599df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 600df8bae1dSRodney W. Grimes int space = 0; 601df8bae1dSRodney W. Grimes 602df8bae1dSRodney W. Grimes if (control == 0) 603df8bae1dSRodney W. Grimes panic("sbappendcontrol"); 604df8bae1dSRodney W. Grimes for (m = control; ; m = m->m_next) { 605df8bae1dSRodney W. Grimes space += m->m_len; 606df8bae1dSRodney W. Grimes if (m->m_next == 0) 607df8bae1dSRodney W. Grimes break; 608df8bae1dSRodney W. Grimes } 609df8bae1dSRodney W. Grimes n = m; /* save pointer to last control buffer */ 610df8bae1dSRodney W. Grimes for (m = m0; m; m = m->m_next) 611df8bae1dSRodney W. Grimes space += m->m_len; 612df8bae1dSRodney W. Grimes if (space > sbspace(sb)) 613df8bae1dSRodney W. Grimes return (0); 614df8bae1dSRodney W. Grimes n->m_next = m0; /* concatenate data to control */ 615df8bae1dSRodney W. Grimes for (m = control; m; m = m->m_next) 616df8bae1dSRodney W. Grimes sballoc(sb, m); 617797f2d22SPoul-Henning Kamp n = sb->sb_mb; 618797f2d22SPoul-Henning Kamp if (n) { 619df8bae1dSRodney W. Grimes while (n->m_nextpkt) 620df8bae1dSRodney W. Grimes n = n->m_nextpkt; 621df8bae1dSRodney W. Grimes n->m_nextpkt = control; 622df8bae1dSRodney W. Grimes } else 623df8bae1dSRodney W. Grimes sb->sb_mb = control; 624df8bae1dSRodney W. Grimes return (1); 625df8bae1dSRodney W. Grimes } 626df8bae1dSRodney W. Grimes 627df8bae1dSRodney W. Grimes /* 628df8bae1dSRodney W. Grimes * Compress mbuf chain m into the socket 629df8bae1dSRodney W. Grimes * buffer sb following mbuf n. If n 630df8bae1dSRodney W. Grimes * is null, the buffer is presumed empty. 631df8bae1dSRodney W. Grimes */ 63226f9a767SRodney W. Grimes void 633df8bae1dSRodney W. Grimes sbcompress(sb, m, n) 634df8bae1dSRodney W. Grimes register struct sockbuf *sb; 635df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 636df8bae1dSRodney W. Grimes { 637df8bae1dSRodney W. Grimes register int eor = 0; 638df8bae1dSRodney W. Grimes register struct mbuf *o; 639df8bae1dSRodney W. Grimes 640df8bae1dSRodney W. Grimes while (m) { 641df8bae1dSRodney W. Grimes eor |= m->m_flags & M_EOR; 642df8bae1dSRodney W. Grimes if (m->m_len == 0 && 643df8bae1dSRodney W. Grimes (eor == 0 || 644df8bae1dSRodney W. Grimes (((o = m->m_next) || (o = n)) && 645df8bae1dSRodney W. Grimes o->m_type == m->m_type))) { 646df8bae1dSRodney W. Grimes m = m_free(m); 647df8bae1dSRodney W. Grimes continue; 648df8bae1dSRodney W. Grimes } 649df8bae1dSRodney W. Grimes if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 && 650df8bae1dSRodney W. Grimes (n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] && 651df8bae1dSRodney W. Grimes n->m_type == m->m_type) { 652df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len, 653df8bae1dSRodney W. Grimes (unsigned)m->m_len); 654df8bae1dSRodney W. Grimes n->m_len += m->m_len; 655df8bae1dSRodney W. Grimes sb->sb_cc += m->m_len; 656df8bae1dSRodney W. Grimes m = m_free(m); 657df8bae1dSRodney W. Grimes continue; 658df8bae1dSRodney W. Grimes } 659df8bae1dSRodney W. Grimes if (n) 660df8bae1dSRodney W. Grimes n->m_next = m; 661df8bae1dSRodney W. Grimes else 662df8bae1dSRodney W. Grimes sb->sb_mb = m; 663df8bae1dSRodney W. Grimes sballoc(sb, m); 664df8bae1dSRodney W. Grimes n = m; 665df8bae1dSRodney W. Grimes m->m_flags &= ~M_EOR; 666df8bae1dSRodney W. Grimes m = m->m_next; 667df8bae1dSRodney W. Grimes n->m_next = 0; 668df8bae1dSRodney W. Grimes } 669df8bae1dSRodney W. Grimes if (eor) { 670df8bae1dSRodney W. Grimes if (n) 671df8bae1dSRodney W. Grimes n->m_flags |= eor; 672df8bae1dSRodney W. Grimes else 673df8bae1dSRodney W. Grimes printf("semi-panic: sbcompress\n"); 674df8bae1dSRodney W. Grimes } 675df8bae1dSRodney W. Grimes } 676df8bae1dSRodney W. Grimes 677df8bae1dSRodney W. Grimes /* 678df8bae1dSRodney W. Grimes * Free all mbufs in a sockbuf. 679df8bae1dSRodney W. Grimes * Check that all resources are reclaimed. 680df8bae1dSRodney W. Grimes */ 68126f9a767SRodney W. Grimes void 682df8bae1dSRodney W. Grimes sbflush(sb) 683df8bae1dSRodney W. Grimes register struct sockbuf *sb; 684df8bae1dSRodney W. Grimes { 685df8bae1dSRodney W. Grimes 686df8bae1dSRodney W. Grimes if (sb->sb_flags & SB_LOCK) 687df8bae1dSRodney W. Grimes panic("sbflush"); 688df8bae1dSRodney W. Grimes while (sb->sb_mbcnt) 689df8bae1dSRodney W. Grimes sbdrop(sb, (int)sb->sb_cc); 690df8bae1dSRodney W. Grimes if (sb->sb_cc || sb->sb_mb) 691df8bae1dSRodney W. Grimes panic("sbflush 2"); 692df8bae1dSRodney W. Grimes } 693df8bae1dSRodney W. Grimes 694df8bae1dSRodney W. Grimes /* 695df8bae1dSRodney W. Grimes * Drop data from (the front of) a sockbuf. 696df8bae1dSRodney W. Grimes */ 69726f9a767SRodney W. Grimes void 698df8bae1dSRodney W. Grimes sbdrop(sb, len) 699df8bae1dSRodney W. Grimes register struct sockbuf *sb; 700df8bae1dSRodney W. Grimes register int len; 701df8bae1dSRodney W. Grimes { 702df8bae1dSRodney W. Grimes register struct mbuf *m, *mn; 703df8bae1dSRodney W. Grimes struct mbuf *next; 704df8bae1dSRodney W. Grimes 705df8bae1dSRodney W. Grimes next = (m = sb->sb_mb) ? m->m_nextpkt : 0; 706df8bae1dSRodney W. Grimes while (len > 0) { 707df8bae1dSRodney W. Grimes if (m == 0) { 708df8bae1dSRodney W. Grimes if (next == 0) 709df8bae1dSRodney W. Grimes panic("sbdrop"); 710df8bae1dSRodney W. Grimes m = next; 711df8bae1dSRodney W. Grimes next = m->m_nextpkt; 712df8bae1dSRodney W. Grimes continue; 713df8bae1dSRodney W. Grimes } 714df8bae1dSRodney W. Grimes if (m->m_len > len) { 715df8bae1dSRodney W. Grimes m->m_len -= len; 716df8bae1dSRodney W. Grimes m->m_data += len; 717df8bae1dSRodney W. Grimes sb->sb_cc -= len; 718df8bae1dSRodney W. Grimes break; 719df8bae1dSRodney W. Grimes } 720df8bae1dSRodney W. Grimes len -= m->m_len; 721df8bae1dSRodney W. Grimes sbfree(sb, m); 722df8bae1dSRodney W. Grimes MFREE(m, mn); 723df8bae1dSRodney W. Grimes m = mn; 724df8bae1dSRodney W. Grimes } 725df8bae1dSRodney W. Grimes while (m && m->m_len == 0) { 726df8bae1dSRodney W. Grimes sbfree(sb, m); 727df8bae1dSRodney W. Grimes MFREE(m, mn); 728df8bae1dSRodney W. Grimes m = mn; 729df8bae1dSRodney W. Grimes } 730df8bae1dSRodney W. Grimes if (m) { 731df8bae1dSRodney W. Grimes sb->sb_mb = m; 732df8bae1dSRodney W. Grimes m->m_nextpkt = next; 733df8bae1dSRodney W. Grimes } else 734df8bae1dSRodney W. Grimes sb->sb_mb = next; 735df8bae1dSRodney W. Grimes } 736df8bae1dSRodney W. Grimes 737df8bae1dSRodney W. Grimes /* 738df8bae1dSRodney W. Grimes * Drop a record off the front of a sockbuf 739df8bae1dSRodney W. Grimes * and move the next record to the front. 740df8bae1dSRodney W. Grimes */ 74126f9a767SRodney W. Grimes void 742df8bae1dSRodney W. Grimes sbdroprecord(sb) 743df8bae1dSRodney W. Grimes register struct sockbuf *sb; 744df8bae1dSRodney W. Grimes { 745df8bae1dSRodney W. Grimes register struct mbuf *m, *mn; 746df8bae1dSRodney W. Grimes 747df8bae1dSRodney W. Grimes m = sb->sb_mb; 748df8bae1dSRodney W. Grimes if (m) { 749df8bae1dSRodney W. Grimes sb->sb_mb = m->m_nextpkt; 750df8bae1dSRodney W. Grimes do { 751df8bae1dSRodney W. Grimes sbfree(sb, m); 752df8bae1dSRodney W. Grimes MFREE(m, mn); 753797f2d22SPoul-Henning Kamp m = mn; 754797f2d22SPoul-Henning Kamp } while (m); 755df8bae1dSRodney W. Grimes } 756df8bae1dSRodney W. Grimes } 7571e4ad9ceSGarrett Wollman 7581e4ad9ceSGarrett Wollman #ifdef PRU_OLDSTYLE 7591e4ad9ceSGarrett Wollman /* 7601e4ad9ceSGarrett Wollman * The following routines mediate between the old-style `pr_usrreq' 7611e4ad9ceSGarrett Wollman * protocol implementations and the new-style `struct pr_usrreqs' 7621e4ad9ceSGarrett Wollman * calling convention. 7631e4ad9ceSGarrett Wollman */ 7641e4ad9ceSGarrett Wollman 7651e4ad9ceSGarrett Wollman /* syntactic sugar */ 7661e4ad9ceSGarrett Wollman #define nomb (struct mbuf *)0 7671e4ad9ceSGarrett Wollman 7681e4ad9ceSGarrett Wollman static int 7691e4ad9ceSGarrett Wollman old_abort(struct socket *so) 7701e4ad9ceSGarrett Wollman { 7711e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(so, PRU_ABORT, nomb, nomb, nomb); 7721e4ad9ceSGarrett Wollman } 7731e4ad9ceSGarrett Wollman 7741e4ad9ceSGarrett Wollman static int 7751e4ad9ceSGarrett Wollman old_accept(struct socket *so, struct mbuf *nam) 7761e4ad9ceSGarrett Wollman { 7771e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(so, PRU_ACCEPT, nomb, nam, nomb); 7781e4ad9ceSGarrett Wollman } 7791e4ad9ceSGarrett Wollman 7801e4ad9ceSGarrett Wollman static int 7811e4ad9ceSGarrett Wollman old_attach(struct socket *so, int proto) 7821e4ad9ceSGarrett Wollman { 7831e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(so, PRU_ATTACH, nomb, 7841e4ad9ceSGarrett Wollman (struct mbuf *)proto, /* XXX */ 7851e4ad9ceSGarrett Wollman nomb); 7861e4ad9ceSGarrett Wollman } 7871e4ad9ceSGarrett Wollman 7881e4ad9ceSGarrett Wollman static int 7891e4ad9ceSGarrett Wollman old_bind(struct socket *so, struct mbuf *nam) 7901e4ad9ceSGarrett Wollman { 7911e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(so, PRU_BIND, nomb, nam, nomb); 7921e4ad9ceSGarrett Wollman } 7931e4ad9ceSGarrett Wollman 7941e4ad9ceSGarrett Wollman static int 7951e4ad9ceSGarrett Wollman old_connect(struct socket *so, struct mbuf *nam) 7961e4ad9ceSGarrett Wollman { 7971e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(so, PRU_CONNECT, nomb, nam, nomb); 7981e4ad9ceSGarrett Wollman } 7991e4ad9ceSGarrett Wollman 8001e4ad9ceSGarrett Wollman static int 8011e4ad9ceSGarrett Wollman old_connect2(struct socket *so1, struct socket *so2) 8021e4ad9ceSGarrett Wollman { 8031e4ad9ceSGarrett Wollman return so1->so_proto->pr_usrreq(so1, PRU_CONNECT2, nomb, 8041e4ad9ceSGarrett Wollman (struct mbuf *)so2, nomb); 8051e4ad9ceSGarrett Wollman } 8061e4ad9ceSGarrett Wollman 8071e4ad9ceSGarrett Wollman static int 8081e4ad9ceSGarrett Wollman old_control(struct socket *so, int cmd, caddr_t data) 8091e4ad9ceSGarrett Wollman { 8101e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(so, PRU_CONTROL, (struct mbuf *)cmd, 8111e4ad9ceSGarrett Wollman (struct mbuf *)data, nomb); 8121e4ad9ceSGarrett Wollman } 8131e4ad9ceSGarrett Wollman 8141e4ad9ceSGarrett Wollman static int 8151e4ad9ceSGarrett Wollman old_detach(struct socket *so) 8161e4ad9ceSGarrett Wollman { 8171e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(so, PRU_DETACH, nomb, nomb, nomb); 8181e4ad9ceSGarrett Wollman } 8191e4ad9ceSGarrett Wollman 8201e4ad9ceSGarrett Wollman static int 8211e4ad9ceSGarrett Wollman old_disconnect(struct socket *so) 8221e4ad9ceSGarrett Wollman { 8231e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(so, PRU_DISCONNECT, nomb, nomb, nomb); 8241e4ad9ceSGarrett Wollman } 8251e4ad9ceSGarrett Wollman 8261e4ad9ceSGarrett Wollman static int 8271e4ad9ceSGarrett Wollman old_listen(struct socket *so) 8281e4ad9ceSGarrett Wollman { 8291e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(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 { 8351e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(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 { 8411e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(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 { 8491e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(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 } 8671e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(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 { 8731e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(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 { 8801e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(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 { 8861e4ad9ceSGarrett Wollman return so->so_proto->pr_usrreq(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 8961e4ad9ceSGarrett Wollman /* 8971e4ad9ceSGarrett Wollman * This function is glue going the other way. It is present to allow 8981e4ad9ceSGarrett Wollman * for this interface to be actively developed from both directions 8991e4ad9ceSGarrett Wollman * (i.e., work on the kernel and protocol stacks proceeds simultaneously). 9001e4ad9ceSGarrett Wollman * It is expected that this function will probably cease to exist much 9011e4ad9ceSGarrett Wollman * sooner than the pru_oldstyle interface, above, will, because once the 9021e4ad9ceSGarrett Wollman * all of the high-kernel use of pr_usrreq() is removed the function is 9031e4ad9ceSGarrett Wollman * no longer needed. 9041e4ad9ceSGarrett Wollman */ 9051e4ad9ceSGarrett Wollman int 9061e4ad9ceSGarrett Wollman pr_newstyle_usrreq(struct socket *so, int req, struct mbuf *m, 9071e4ad9ceSGarrett Wollman struct mbuf *nam, struct mbuf *control) 9081e4ad9ceSGarrett Wollman { 9091e4ad9ceSGarrett Wollman struct pr_usrreqs *pru = so->so_proto->pr_usrreqs; 9101e4ad9ceSGarrett Wollman 9111e4ad9ceSGarrett Wollman switch(req) { 9121e4ad9ceSGarrett Wollman case PRU_ABORT: 9131e4ad9ceSGarrett Wollman return pru->pru_abort(so); 9141e4ad9ceSGarrett Wollman 9151e4ad9ceSGarrett Wollman case PRU_ACCEPT: 9161e4ad9ceSGarrett Wollman return pru->pru_accept(so, nam); 9171e4ad9ceSGarrett Wollman 9181e4ad9ceSGarrett Wollman case PRU_ATTACH: 9191e4ad9ceSGarrett Wollman return pru->pru_attach(so, (int)nam); 9201e4ad9ceSGarrett Wollman 9211e4ad9ceSGarrett Wollman case PRU_BIND: 9221e4ad9ceSGarrett Wollman return pru->pru_bind(so, nam); 9231e4ad9ceSGarrett Wollman 9241e4ad9ceSGarrett Wollman case PRU_CONNECT: 9251e4ad9ceSGarrett Wollman return pru->pru_connect(so, nam); 9261e4ad9ceSGarrett Wollman 9271e4ad9ceSGarrett Wollman case PRU_CONNECT2: 9281e4ad9ceSGarrett Wollman return pru->pru_connect2(so, (struct socket *)nam); 9291e4ad9ceSGarrett Wollman 9301e4ad9ceSGarrett Wollman case PRU_CONTROL: 9311e4ad9ceSGarrett Wollman return pru->pru_control(so, (int)m, (caddr_t)nam); 9321e4ad9ceSGarrett Wollman 9331e4ad9ceSGarrett Wollman case PRU_DETACH: 9341e4ad9ceSGarrett Wollman return pru->pru_detach(so); 9351e4ad9ceSGarrett Wollman 9361e4ad9ceSGarrett Wollman case PRU_DISCONNECT: 9371e4ad9ceSGarrett Wollman return pru->pru_disconnect(so); 9381e4ad9ceSGarrett Wollman 9391e4ad9ceSGarrett Wollman case PRU_LISTEN: 9401e4ad9ceSGarrett Wollman return pru->pru_listen(so); 9411e4ad9ceSGarrett Wollman 9421e4ad9ceSGarrett Wollman case PRU_PEERADDR: 9431e4ad9ceSGarrett Wollman return pru->pru_peeraddr(so, nam); 9441e4ad9ceSGarrett Wollman 9451e4ad9ceSGarrett Wollman case PRU_RCVD: 9461e4ad9ceSGarrett Wollman return pru->pru_rcvd(so, (int)nam); 9471e4ad9ceSGarrett Wollman 9481e4ad9ceSGarrett Wollman case PRU_RCVOOB: 9491e4ad9ceSGarrett Wollman return pru->pru_rcvoob(so, m, (int)nam); 9501e4ad9ceSGarrett Wollman 9511e4ad9ceSGarrett Wollman case PRU_SEND: 9521e4ad9ceSGarrett Wollman return pru->pru_send(so, 0, m, nam, control); 9531e4ad9ceSGarrett Wollman 9541e4ad9ceSGarrett Wollman case PRU_SENDOOB: 9551e4ad9ceSGarrett Wollman return pru->pru_send(so, PRUS_OOB, m, nam, control); 9561e4ad9ceSGarrett Wollman 9571e4ad9ceSGarrett Wollman case PRU_SEND_EOF: 9581e4ad9ceSGarrett Wollman return pru->pru_send(so, PRUS_EOF, m, nam, control); 9591e4ad9ceSGarrett Wollman 9601e4ad9ceSGarrett Wollman case PRU_SENSE: 9611e4ad9ceSGarrett Wollman return pru->pru_sense(so, (struct stat *)m); 9621e4ad9ceSGarrett Wollman 9631e4ad9ceSGarrett Wollman case PRU_SHUTDOWN: 9641e4ad9ceSGarrett Wollman return pru->pru_shutdown(so); 9651e4ad9ceSGarrett Wollman 9661e4ad9ceSGarrett Wollman case PRU_SOCKADDR: 9671e4ad9ceSGarrett Wollman return pru->pru_sockaddr(so, nam); 9681e4ad9ceSGarrett Wollman 9691e4ad9ceSGarrett Wollman } 9701e4ad9ceSGarrett Wollman 9711e4ad9ceSGarrett Wollman panic("pru_newstyle_usrreq: unhandled request %d", req); 9721e4ad9ceSGarrett Wollman } 9731e4ad9ceSGarrett Wollman 9741e4ad9ceSGarrett Wollman #endif /* PRU_OLDSTYLE */ 975