1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 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 * 331fdbc7aeSGarrett Wollman * From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94 3498163b98SPoul-Henning Kamp * $Id: tcp_usrreq.c,v 1.18 1995/11/03 22:08:11 olah Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38df8bae1dSRodney W. Grimes #include <sys/systm.h> 39c7a82f90SGarrett Wollman #include <sys/kernel.h> 4098163b98SPoul-Henning Kamp #include <sys/sysctl.h> 41df8bae1dSRodney W. Grimes #include <sys/malloc.h> 42df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 43df8bae1dSRodney W. Grimes #include <sys/socket.h> 44df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 45df8bae1dSRodney W. Grimes #include <sys/protosw.h> 46df8bae1dSRodney W. Grimes #include <sys/errno.h> 47df8bae1dSRodney W. Grimes #include <sys/stat.h> 48b5e8ce9fSBruce Evans #include <vm/vm.h> 49df8bae1dSRodney W. Grimes 50df8bae1dSRodney W. Grimes #include <net/if.h> 51df8bae1dSRodney W. Grimes #include <net/route.h> 52df8bae1dSRodney W. Grimes 53df8bae1dSRodney W. Grimes #include <netinet/in.h> 54df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 55df8bae1dSRodney W. Grimes #include <netinet/ip.h> 56df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 57b5e8ce9fSBruce Evans #include <netinet/in_var.h> 58df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 59df8bae1dSRodney W. Grimes #include <netinet/tcp.h> 60df8bae1dSRodney W. Grimes #include <netinet/tcp_fsm.h> 61df8bae1dSRodney W. Grimes #include <netinet/tcp_seq.h> 62df8bae1dSRodney W. Grimes #include <netinet/tcp_timer.h> 63df8bae1dSRodney W. Grimes #include <netinet/tcp_var.h> 64df8bae1dSRodney W. Grimes #include <netinet/tcpip.h> 65610ee2f9SDavid Greenman #ifdef TCPDEBUG 66df8bae1dSRodney W. Grimes #include <netinet/tcp_debug.h> 67610ee2f9SDavid Greenman #endif 68df8bae1dSRodney W. Grimes 69df8bae1dSRodney W. Grimes /* 70df8bae1dSRodney W. Grimes * TCP protocol interface to socket abstraction. 71df8bae1dSRodney W. Grimes */ 72df8bae1dSRodney W. Grimes extern char *tcpstates[]; 73df8bae1dSRodney W. Grimes 74df8bae1dSRodney W. Grimes /* 75df8bae1dSRodney W. Grimes * Process a TCP user request for TCP tb. If this is a send request 76df8bae1dSRodney W. Grimes * then m is the mbuf chain of send data. If this is a timer expiration 77df8bae1dSRodney W. Grimes * (called from the software clock routine), then timertype tells which timer. 78df8bae1dSRodney W. Grimes */ 79df8bae1dSRodney W. Grimes /*ARGSUSED*/ 80df8bae1dSRodney W. Grimes int 81df8bae1dSRodney W. Grimes tcp_usrreq(so, req, m, nam, control) 82df8bae1dSRodney W. Grimes struct socket *so; 83df8bae1dSRodney W. Grimes int req; 84df8bae1dSRodney W. Grimes struct mbuf *m, *nam, *control; 85df8bae1dSRodney W. Grimes { 86df8bae1dSRodney W. Grimes register struct inpcb *inp; 8726f9a767SRodney W. Grimes register struct tcpcb *tp = 0; 889ee39fc6SGarrett Wollman struct sockaddr_in *sinp; 89df8bae1dSRodney W. Grimes int s; 90df8bae1dSRodney W. Grimes int error = 0; 91a0292f23SGarrett Wollman #ifdef TCPDEBUG 92df8bae1dSRodney W. Grimes int ostate; 93a0292f23SGarrett Wollman #endif 94df8bae1dSRodney W. Grimes 95df8bae1dSRodney W. Grimes if (req == PRU_CONTROL) 96b6e3d50fSGarrett Wollman return (in_control(so, (u_long)m, (caddr_t)nam, 97df8bae1dSRodney W. Grimes (struct ifnet *)control)); 98df8bae1dSRodney W. Grimes if (control && control->m_len) { 99df8bae1dSRodney W. Grimes m_freem(control); 100df8bae1dSRodney W. Grimes if (m) 101df8bae1dSRodney W. Grimes m_freem(m); 102df8bae1dSRodney W. Grimes return (EINVAL); 103df8bae1dSRodney W. Grimes } 104df8bae1dSRodney W. Grimes 105df8bae1dSRodney W. Grimes s = splnet(); 106df8bae1dSRodney W. Grimes inp = sotoinpcb(so); 107df8bae1dSRodney W. Grimes /* 108df8bae1dSRodney W. Grimes * When a TCP is attached to a socket, then there will be 109df8bae1dSRodney W. Grimes * a (struct inpcb) pointed at by the socket, and this 110df8bae1dSRodney W. Grimes * structure will point at a subsidary (struct tcpcb). 111df8bae1dSRodney W. Grimes */ 112df8bae1dSRodney W. Grimes if (inp == 0 && req != PRU_ATTACH) { 113df8bae1dSRodney W. Grimes splx(s); 114b6e3d50fSGarrett Wollman #if 0 115b6e3d50fSGarrett Wollman /* 116b6e3d50fSGarrett Wollman * The following corrects an mbuf leak under rare 117b6e3d50fSGarrett Wollman * circumstances, but has not been fully tested. 118b6e3d50fSGarrett Wollman */ 119b6e3d50fSGarrett Wollman if (m && req != PRU_SENSE) 120b6e3d50fSGarrett Wollman m_freem(m); 121b6e3d50fSGarrett Wollman #else 122b6e3d50fSGarrett Wollman /* safer version of fix for mbuf leak */ 123b6e3d50fSGarrett Wollman if (m && (req == PRU_SEND || req == PRU_SENDOOB)) 124b6e3d50fSGarrett Wollman m_freem(m); 125b6e3d50fSGarrett Wollman #endif 126df8bae1dSRodney W. Grimes return (EINVAL); /* XXX */ 127df8bae1dSRodney W. Grimes } 128df8bae1dSRodney W. Grimes if (inp) { 129df8bae1dSRodney W. Grimes tp = intotcpcb(inp); 130df8bae1dSRodney W. Grimes /* WHAT IF TP IS 0? */ 131df8bae1dSRodney W. Grimes #ifdef KPROF 132df8bae1dSRodney W. Grimes tcp_acounts[tp->t_state][req]++; 133df8bae1dSRodney W. Grimes #endif 134a0292f23SGarrett Wollman #ifdef TCPDEBUG 135df8bae1dSRodney W. Grimes ostate = tp->t_state; 136df8bae1dSRodney W. Grimes } else 137df8bae1dSRodney W. Grimes ostate = 0; 138a0292f23SGarrett Wollman #else /* TCPDEBUG */ 139a0292f23SGarrett Wollman } 140a0292f23SGarrett Wollman #endif /* TCPDEBUG */ 141a0292f23SGarrett Wollman 142df8bae1dSRodney W. Grimes switch (req) { 143df8bae1dSRodney W. Grimes 144df8bae1dSRodney W. Grimes /* 145df8bae1dSRodney W. Grimes * TCP attaches to socket via PRU_ATTACH, reserving space, 146df8bae1dSRodney W. Grimes * and an internet control block. 147df8bae1dSRodney W. Grimes */ 148df8bae1dSRodney W. Grimes case PRU_ATTACH: 149df8bae1dSRodney W. Grimes if (inp) { 150df8bae1dSRodney W. Grimes error = EISCONN; 151df8bae1dSRodney W. Grimes break; 152df8bae1dSRodney W. Grimes } 153df8bae1dSRodney W. Grimes error = tcp_attach(so); 154df8bae1dSRodney W. Grimes if (error) 155df8bae1dSRodney W. Grimes break; 156df8bae1dSRodney W. Grimes if ((so->so_options & SO_LINGER) && so->so_linger == 0) 1571fdbc7aeSGarrett Wollman so->so_linger = TCP_LINGERTIME * hz; 158df8bae1dSRodney W. Grimes tp = sototcpcb(so); 159df8bae1dSRodney W. Grimes break; 160df8bae1dSRodney W. Grimes 161df8bae1dSRodney W. Grimes /* 162df8bae1dSRodney W. Grimes * PRU_DETACH detaches the TCP protocol from the socket. 163df8bae1dSRodney W. Grimes * If the protocol state is non-embryonic, then can't 164df8bae1dSRodney W. Grimes * do this directly: have to initiate a PRU_DISCONNECT, 165df8bae1dSRodney W. Grimes * which may finish later; embryonic TCB's can just 166df8bae1dSRodney W. Grimes * be discarded here. 167df8bae1dSRodney W. Grimes */ 168df8bae1dSRodney W. Grimes case PRU_DETACH: 169df8bae1dSRodney W. Grimes if (tp->t_state > TCPS_LISTEN) 170df8bae1dSRodney W. Grimes tp = tcp_disconnect(tp); 171df8bae1dSRodney W. Grimes else 172df8bae1dSRodney W. Grimes tp = tcp_close(tp); 173df8bae1dSRodney W. Grimes break; 174df8bae1dSRodney W. Grimes 175df8bae1dSRodney W. Grimes /* 176df8bae1dSRodney W. Grimes * Give the socket an address. 177df8bae1dSRodney W. Grimes */ 178df8bae1dSRodney W. Grimes case PRU_BIND: 1799ee39fc6SGarrett Wollman /* 1809ee39fc6SGarrett Wollman * Must check for multicast addresses and disallow binding 1819ee39fc6SGarrett Wollman * to them. 1829ee39fc6SGarrett Wollman */ 1839ee39fc6SGarrett Wollman sinp = mtod(nam, struct sockaddr_in *); 1849ee39fc6SGarrett Wollman if (sinp->sin_family == AF_INET && 1859ee39fc6SGarrett Wollman IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) { 1869ee39fc6SGarrett Wollman error = EAFNOSUPPORT; 1879ee39fc6SGarrett Wollman break; 1889ee39fc6SGarrett Wollman } 189df8bae1dSRodney W. Grimes error = in_pcbbind(inp, nam); 190df8bae1dSRodney W. Grimes if (error) 191df8bae1dSRodney W. Grimes break; 192df8bae1dSRodney W. Grimes break; 193df8bae1dSRodney W. Grimes 194df8bae1dSRodney W. Grimes /* 195df8bae1dSRodney W. Grimes * Prepare to accept connections. 196df8bae1dSRodney W. Grimes */ 197df8bae1dSRodney W. Grimes case PRU_LISTEN: 198df8bae1dSRodney W. Grimes if (inp->inp_lport == 0) 19915bd2b43SDavid Greenman error = in_pcbbind(inp, NULL); 200df8bae1dSRodney W. Grimes if (error == 0) 201df8bae1dSRodney W. Grimes tp->t_state = TCPS_LISTEN; 202df8bae1dSRodney W. Grimes break; 203df8bae1dSRodney W. Grimes 204df8bae1dSRodney W. Grimes /* 205df8bae1dSRodney W. Grimes * Initiate connection to peer. 206df8bae1dSRodney W. Grimes * Create a template for use in transmissions on this connection. 207df8bae1dSRodney W. Grimes * Enter SYN_SENT state, and mark socket as connecting. 208df8bae1dSRodney W. Grimes * Start keep-alive timer, and seed output sequence space. 209df8bae1dSRodney W. Grimes * Send initial segment on connection. 210df8bae1dSRodney W. Grimes */ 211df8bae1dSRodney W. Grimes case PRU_CONNECT: 2129ee39fc6SGarrett Wollman /* 2139ee39fc6SGarrett Wollman * Must disallow TCP ``connections'' to multicast addresses. 2149ee39fc6SGarrett Wollman */ 2159ee39fc6SGarrett Wollman sinp = mtod(nam, struct sockaddr_in *); 2169ee39fc6SGarrett Wollman if (sinp->sin_family == AF_INET 2179ee39fc6SGarrett Wollman && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) { 2189ee39fc6SGarrett Wollman error = EAFNOSUPPORT; 2199ee39fc6SGarrett Wollman break; 2209ee39fc6SGarrett Wollman } 2219ee39fc6SGarrett Wollman 222a0292f23SGarrett Wollman if ((error = tcp_connect(tp, nam)) != 0) 223a0292f23SGarrett Wollman break; 224df8bae1dSRodney W. Grimes error = tcp_output(tp); 225df8bae1dSRodney W. Grimes break; 226df8bae1dSRodney W. Grimes 227df8bae1dSRodney W. Grimes /* 228df8bae1dSRodney W. Grimes * Create a TCP connection between two sockets. 229df8bae1dSRodney W. Grimes */ 230df8bae1dSRodney W. Grimes case PRU_CONNECT2: 231df8bae1dSRodney W. Grimes error = EOPNOTSUPP; 232df8bae1dSRodney W. Grimes break; 233df8bae1dSRodney W. Grimes 234df8bae1dSRodney W. Grimes /* 235df8bae1dSRodney W. Grimes * Initiate disconnect from peer. 236df8bae1dSRodney W. Grimes * If connection never passed embryonic stage, just drop; 237df8bae1dSRodney W. Grimes * else if don't need to let data drain, then can just drop anyways, 238df8bae1dSRodney W. Grimes * else have to begin TCP shutdown process: mark socket disconnecting, 239df8bae1dSRodney W. Grimes * drain unread data, state switch to reflect user close, and 240df8bae1dSRodney W. Grimes * send segment (e.g. FIN) to peer. Socket will be really disconnected 241df8bae1dSRodney W. Grimes * when peer sends FIN and acks ours. 242df8bae1dSRodney W. Grimes * 243df8bae1dSRodney W. Grimes * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 244df8bae1dSRodney W. Grimes */ 245df8bae1dSRodney W. Grimes case PRU_DISCONNECT: 246df8bae1dSRodney W. Grimes tp = tcp_disconnect(tp); 247df8bae1dSRodney W. Grimes break; 248df8bae1dSRodney W. Grimes 249df8bae1dSRodney W. Grimes /* 250df8bae1dSRodney W. Grimes * Accept a connection. Essentially all the work is 251df8bae1dSRodney W. Grimes * done at higher levels; just return the address 252df8bae1dSRodney W. Grimes * of the peer, storing through addr. 253df8bae1dSRodney W. Grimes */ 254df8bae1dSRodney W. Grimes case PRU_ACCEPT: 255df8bae1dSRodney W. Grimes in_setpeeraddr(inp, nam); 256df8bae1dSRodney W. Grimes break; 257df8bae1dSRodney W. Grimes 258df8bae1dSRodney W. Grimes /* 259df8bae1dSRodney W. Grimes * Mark the connection as being incapable of further output. 260df8bae1dSRodney W. Grimes */ 261df8bae1dSRodney W. Grimes case PRU_SHUTDOWN: 262df8bae1dSRodney W. Grimes socantsendmore(so); 263df8bae1dSRodney W. Grimes tp = tcp_usrclosed(tp); 264df8bae1dSRodney W. Grimes if (tp) 265df8bae1dSRodney W. Grimes error = tcp_output(tp); 266df8bae1dSRodney W. Grimes break; 267df8bae1dSRodney W. Grimes 268df8bae1dSRodney W. Grimes /* 269df8bae1dSRodney W. Grimes * After a receive, possibly send window update to peer. 270df8bae1dSRodney W. Grimes */ 271df8bae1dSRodney W. Grimes case PRU_RCVD: 272df8bae1dSRodney W. Grimes (void) tcp_output(tp); 273df8bae1dSRodney W. Grimes break; 274df8bae1dSRodney W. Grimes 275df8bae1dSRodney W. Grimes /* 276df8bae1dSRodney W. Grimes * Do a send by putting data in output queue and updating urgent 277df8bae1dSRodney W. Grimes * marker if URG set. Possibly send more data. 278df8bae1dSRodney W. Grimes */ 279a0292f23SGarrett Wollman case PRU_SEND_EOF: 280df8bae1dSRodney W. Grimes case PRU_SEND: 281df8bae1dSRodney W. Grimes sbappend(&so->so_snd, m); 282a0292f23SGarrett Wollman if (nam && tp->t_state < TCPS_SYN_SENT) { 283a0292f23SGarrett Wollman /* 284a0292f23SGarrett Wollman * Do implied connect if not yet connected, 285a0292f23SGarrett Wollman * initialize window to default value, and 286a0292f23SGarrett Wollman * initialize maxseg/maxopd using peer's cached 287a0292f23SGarrett Wollman * MSS. 288a0292f23SGarrett Wollman */ 289a0292f23SGarrett Wollman error = tcp_connect(tp, nam); 290a0292f23SGarrett Wollman if (error) 291a0292f23SGarrett Wollman break; 292a0292f23SGarrett Wollman tp->snd_wnd = TTCP_CLIENT_SND_WND; 293a0292f23SGarrett Wollman tcp_mss(tp, -1); 294a0292f23SGarrett Wollman } 295a0292f23SGarrett Wollman 296a0292f23SGarrett Wollman if (req == PRU_SEND_EOF) { 297a0292f23SGarrett Wollman /* 298a0292f23SGarrett Wollman * Close the send side of the connection after 299a0292f23SGarrett Wollman * the data is sent. 300a0292f23SGarrett Wollman */ 301a0292f23SGarrett Wollman socantsendmore(so); 302a0292f23SGarrett Wollman tp = tcp_usrclosed(tp); 303a0292f23SGarrett Wollman } 304a0292f23SGarrett Wollman if (tp != NULL) 305df8bae1dSRodney W. Grimes error = tcp_output(tp); 306df8bae1dSRodney W. Grimes break; 307df8bae1dSRodney W. Grimes 308df8bae1dSRodney W. Grimes /* 309df8bae1dSRodney W. Grimes * Abort the TCP. 310df8bae1dSRodney W. Grimes */ 311df8bae1dSRodney W. Grimes case PRU_ABORT: 312df8bae1dSRodney W. Grimes tp = tcp_drop(tp, ECONNABORTED); 313df8bae1dSRodney W. Grimes break; 314df8bae1dSRodney W. Grimes 315df8bae1dSRodney W. Grimes case PRU_SENSE: 316df8bae1dSRodney W. Grimes ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 317df8bae1dSRodney W. Grimes (void) splx(s); 318df8bae1dSRodney W. Grimes return (0); 319df8bae1dSRodney W. Grimes 320df8bae1dSRodney W. Grimes case PRU_RCVOOB: 321df8bae1dSRodney W. Grimes if ((so->so_oobmark == 0 && 322df8bae1dSRodney W. Grimes (so->so_state & SS_RCVATMARK) == 0) || 323df8bae1dSRodney W. Grimes so->so_options & SO_OOBINLINE || 324df8bae1dSRodney W. Grimes tp->t_oobflags & TCPOOB_HADDATA) { 325df8bae1dSRodney W. Grimes error = EINVAL; 326df8bae1dSRodney W. Grimes break; 327df8bae1dSRodney W. Grimes } 328df8bae1dSRodney W. Grimes if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { 329df8bae1dSRodney W. Grimes error = EWOULDBLOCK; 330df8bae1dSRodney W. Grimes break; 331df8bae1dSRodney W. Grimes } 332df8bae1dSRodney W. Grimes m->m_len = 1; 333df8bae1dSRodney W. Grimes *mtod(m, caddr_t) = tp->t_iobc; 334df8bae1dSRodney W. Grimes if (((int)nam & MSG_PEEK) == 0) 335df8bae1dSRodney W. Grimes tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA); 336df8bae1dSRodney W. Grimes break; 337df8bae1dSRodney W. Grimes 338df8bae1dSRodney W. Grimes case PRU_SENDOOB: 339df8bae1dSRodney W. Grimes if (sbspace(&so->so_snd) < -512) { 340df8bae1dSRodney W. Grimes m_freem(m); 341df8bae1dSRodney W. Grimes error = ENOBUFS; 342df8bae1dSRodney W. Grimes break; 343df8bae1dSRodney W. Grimes } 344df8bae1dSRodney W. Grimes /* 345df8bae1dSRodney W. Grimes * According to RFC961 (Assigned Protocols), 346df8bae1dSRodney W. Grimes * the urgent pointer points to the last octet 347df8bae1dSRodney W. Grimes * of urgent data. We continue, however, 348df8bae1dSRodney W. Grimes * to consider it to indicate the first octet 349df8bae1dSRodney W. Grimes * of data past the urgent section. 350df8bae1dSRodney W. Grimes * Otherwise, snd_up should be one lower. 351df8bae1dSRodney W. Grimes */ 352df8bae1dSRodney W. Grimes sbappend(&so->so_snd, m); 353df8bae1dSRodney W. Grimes tp->snd_up = tp->snd_una + so->so_snd.sb_cc; 354df8bae1dSRodney W. Grimes tp->t_force = 1; 355df8bae1dSRodney W. Grimes error = tcp_output(tp); 356df8bae1dSRodney W. Grimes tp->t_force = 0; 357df8bae1dSRodney W. Grimes break; 358df8bae1dSRodney W. Grimes 359df8bae1dSRodney W. Grimes case PRU_SOCKADDR: 360df8bae1dSRodney W. Grimes in_setsockaddr(inp, nam); 361df8bae1dSRodney W. Grimes break; 362df8bae1dSRodney W. Grimes 363df8bae1dSRodney W. Grimes case PRU_PEERADDR: 364df8bae1dSRodney W. Grimes in_setpeeraddr(inp, nam); 365df8bae1dSRodney W. Grimes break; 366df8bae1dSRodney W. Grimes 367df8bae1dSRodney W. Grimes /* 368df8bae1dSRodney W. Grimes * TCP slow timer went off; going through this 369df8bae1dSRodney W. Grimes * routine for tracing's sake. 370df8bae1dSRodney W. Grimes */ 371df8bae1dSRodney W. Grimes case PRU_SLOWTIMO: 372df8bae1dSRodney W. Grimes tp = tcp_timers(tp, (int)nam); 373a0292f23SGarrett Wollman #ifdef TCPDEBUG 374df8bae1dSRodney W. Grimes req |= (int)nam << 8; /* for debug's sake */ 375a0292f23SGarrett Wollman #endif 376df8bae1dSRodney W. Grimes break; 377df8bae1dSRodney W. Grimes 378df8bae1dSRodney W. Grimes default: 379df8bae1dSRodney W. Grimes panic("tcp_usrreq"); 380df8bae1dSRodney W. Grimes } 381610ee2f9SDavid Greenman #ifdef TCPDEBUG 382df8bae1dSRodney W. Grimes if (tp && (so->so_options & SO_DEBUG)) 383df8bae1dSRodney W. Grimes tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); 384610ee2f9SDavid Greenman #endif 385df8bae1dSRodney W. Grimes splx(s); 386df8bae1dSRodney W. Grimes return (error); 387df8bae1dSRodney W. Grimes } 388df8bae1dSRodney W. Grimes 389a0292f23SGarrett Wollman /* 390a0292f23SGarrett Wollman * Common subroutine to open a TCP connection to remote host specified 391a0292f23SGarrett Wollman * by struct sockaddr_in in mbuf *nam. Call in_pcbbind to assign a local 392a0292f23SGarrett Wollman * port number if needed. Call in_pcbladdr to do the routing and to choose 393a0292f23SGarrett Wollman * a local host address (interface). If there is an existing incarnation 394a0292f23SGarrett Wollman * of the same connection in TIME-WAIT state and if the remote host was 395a0292f23SGarrett Wollman * sending CC options and if the connection duration was < MSL, then 396a0292f23SGarrett Wollman * truncate the previous TIME-WAIT state and proceed. 397a0292f23SGarrett Wollman * Initialize connection parameters and enter SYN-SENT state. 398a0292f23SGarrett Wollman */ 399a0292f23SGarrett Wollman int 400a0292f23SGarrett Wollman tcp_connect(tp, nam) 401a0292f23SGarrett Wollman register struct tcpcb *tp; 402a0292f23SGarrett Wollman struct mbuf *nam; 403a0292f23SGarrett Wollman { 404a0292f23SGarrett Wollman struct inpcb *inp = tp->t_inpcb, *oinp; 405a0292f23SGarrett Wollman struct socket *so = inp->inp_socket; 406a0292f23SGarrett Wollman struct tcpcb *otp; 407a0292f23SGarrett Wollman struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 408a0292f23SGarrett Wollman struct sockaddr_in *ifaddr; 409a0292f23SGarrett Wollman int error; 410a45d2726SAndras Olah struct rmxp_tao *taop; 411a45d2726SAndras Olah struct rmxp_tao tao_noncached; 412a0292f23SGarrett Wollman 413a0292f23SGarrett Wollman if (inp->inp_lport == 0) { 414a0292f23SGarrett Wollman error = in_pcbbind(inp, NULL); 415a0292f23SGarrett Wollman if (error) 416a0292f23SGarrett Wollman return error; 417a0292f23SGarrett Wollman } 418a0292f23SGarrett Wollman 419a0292f23SGarrett Wollman /* 420a0292f23SGarrett Wollman * Cannot simply call in_pcbconnect, because there might be an 421a0292f23SGarrett Wollman * earlier incarnation of this same connection still in 422a0292f23SGarrett Wollman * TIME_WAIT state, creating an ADDRINUSE error. 423a0292f23SGarrett Wollman */ 424a0292f23SGarrett Wollman error = in_pcbladdr(inp, nam, &ifaddr); 425d3628763SRodney W. Grimes if (error) 426d3628763SRodney W. Grimes return error; 42715bd2b43SDavid Greenman oinp = in_pcblookup(inp->inp_pcbinfo->listhead, 428a0292f23SGarrett Wollman sin->sin_addr, sin->sin_port, 429a0292f23SGarrett Wollman inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr 430a0292f23SGarrett Wollman : ifaddr->sin_addr, 431a0292f23SGarrett Wollman inp->inp_lport, 0); 432a0292f23SGarrett Wollman if (oinp) { 433a0292f23SGarrett Wollman if (oinp != inp && (otp = intotcpcb(oinp)) != NULL && 434a0292f23SGarrett Wollman otp->t_state == TCPS_TIME_WAIT && 435a0292f23SGarrett Wollman otp->t_duration < TCPTV_MSL && 436a0292f23SGarrett Wollman (otp->t_flags & TF_RCVD_CC)) 437a0292f23SGarrett Wollman otp = tcp_close(otp); 438a0292f23SGarrett Wollman else 439a0292f23SGarrett Wollman return EADDRINUSE; 440a0292f23SGarrett Wollman } 441a0292f23SGarrett Wollman if (inp->inp_laddr.s_addr == INADDR_ANY) 442a0292f23SGarrett Wollman inp->inp_laddr = ifaddr->sin_addr; 443a0292f23SGarrett Wollman inp->inp_faddr = sin->sin_addr; 444a0292f23SGarrett Wollman inp->inp_fport = sin->sin_port; 44515bd2b43SDavid Greenman in_pcbrehash(inp); 446a0292f23SGarrett Wollman 447a0292f23SGarrett Wollman tp->t_template = tcp_template(tp); 448a0292f23SGarrett Wollman if (tp->t_template == 0) { 449a0292f23SGarrett Wollman in_pcbdisconnect(inp); 450a0292f23SGarrett Wollman return ENOBUFS; 451a0292f23SGarrett Wollman } 452a0292f23SGarrett Wollman 453a0292f23SGarrett Wollman /* Compute window scaling to request. */ 454a0292f23SGarrett Wollman while (tp->request_r_scale < TCP_MAX_WINSHIFT && 455a0292f23SGarrett Wollman (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) 456a0292f23SGarrett Wollman tp->request_r_scale++; 457a0292f23SGarrett Wollman 458a0292f23SGarrett Wollman soisconnecting(so); 459a0292f23SGarrett Wollman tcpstat.tcps_connattempt++; 460a0292f23SGarrett Wollman tp->t_state = TCPS_SYN_SENT; 461a0292f23SGarrett Wollman tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; 462a0292f23SGarrett Wollman tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 463a0292f23SGarrett Wollman tcp_sendseqinit(tp); 464a45d2726SAndras Olah 465a45d2726SAndras Olah /* 466a45d2726SAndras Olah * Generate a CC value for this connection and 467a45d2726SAndras Olah * check whether CC or CCnew should be used. 468a45d2726SAndras Olah */ 469a45d2726SAndras Olah if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) { 470a45d2726SAndras Olah taop = &tao_noncached; 471a45d2726SAndras Olah bzero(taop, sizeof(*taop)); 472a45d2726SAndras Olah } 473a45d2726SAndras Olah 474a0292f23SGarrett Wollman tp->cc_send = CC_INC(tcp_ccgen); 475a45d2726SAndras Olah if (taop->tao_ccsent != 0 && 476a45d2726SAndras Olah CC_GEQ(tp->cc_send, taop->tao_ccsent)) { 477a45d2726SAndras Olah taop->tao_ccsent = tp->cc_send; 478a45d2726SAndras Olah } else { 479a45d2726SAndras Olah taop->tao_ccsent = 0; 480a45d2726SAndras Olah tp->t_flags |= TF_SENDCCNEW; 481a45d2726SAndras Olah } 482a0292f23SGarrett Wollman 483a0292f23SGarrett Wollman return 0; 484a0292f23SGarrett Wollman } 485a0292f23SGarrett Wollman 486df8bae1dSRodney W. Grimes int 487df8bae1dSRodney W. Grimes tcp_ctloutput(op, so, level, optname, mp) 488df8bae1dSRodney W. Grimes int op; 489df8bae1dSRodney W. Grimes struct socket *so; 490df8bae1dSRodney W. Grimes int level, optname; 491df8bae1dSRodney W. Grimes struct mbuf **mp; 492df8bae1dSRodney W. Grimes { 493df8bae1dSRodney W. Grimes int error = 0, s; 494df8bae1dSRodney W. Grimes struct inpcb *inp; 495df8bae1dSRodney W. Grimes register struct tcpcb *tp; 496df8bae1dSRodney W. Grimes register struct mbuf *m; 497df8bae1dSRodney W. Grimes register int i; 498df8bae1dSRodney W. Grimes 499df8bae1dSRodney W. Grimes s = splnet(); 500df8bae1dSRodney W. Grimes inp = sotoinpcb(so); 501df8bae1dSRodney W. Grimes if (inp == NULL) { 502df8bae1dSRodney W. Grimes splx(s); 503df8bae1dSRodney W. Grimes if (op == PRCO_SETOPT && *mp) 504df8bae1dSRodney W. Grimes (void) m_free(*mp); 505df8bae1dSRodney W. Grimes return (ECONNRESET); 506df8bae1dSRodney W. Grimes } 507df8bae1dSRodney W. Grimes if (level != IPPROTO_TCP) { 508df8bae1dSRodney W. Grimes error = ip_ctloutput(op, so, level, optname, mp); 509df8bae1dSRodney W. Grimes splx(s); 510df8bae1dSRodney W. Grimes return (error); 511df8bae1dSRodney W. Grimes } 512df8bae1dSRodney W. Grimes tp = intotcpcb(inp); 513df8bae1dSRodney W. Grimes 514df8bae1dSRodney W. Grimes switch (op) { 515df8bae1dSRodney W. Grimes 516df8bae1dSRodney W. Grimes case PRCO_SETOPT: 517df8bae1dSRodney W. Grimes m = *mp; 518df8bae1dSRodney W. Grimes switch (optname) { 519df8bae1dSRodney W. Grimes 520df8bae1dSRodney W. Grimes case TCP_NODELAY: 521df8bae1dSRodney W. Grimes if (m == NULL || m->m_len < sizeof (int)) 522df8bae1dSRodney W. Grimes error = EINVAL; 523df8bae1dSRodney W. Grimes else if (*mtod(m, int *)) 524df8bae1dSRodney W. Grimes tp->t_flags |= TF_NODELAY; 525df8bae1dSRodney W. Grimes else 526df8bae1dSRodney W. Grimes tp->t_flags &= ~TF_NODELAY; 527df8bae1dSRodney W. Grimes break; 528df8bae1dSRodney W. Grimes 529df8bae1dSRodney W. Grimes case TCP_MAXSEG: 530df8bae1dSRodney W. Grimes if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg) 531df8bae1dSRodney W. Grimes tp->t_maxseg = i; 532df8bae1dSRodney W. Grimes else 533df8bae1dSRodney W. Grimes error = EINVAL; 534df8bae1dSRodney W. Grimes break; 535df8bae1dSRodney W. Grimes 536a0292f23SGarrett Wollman case TCP_NOOPT: 537a0292f23SGarrett Wollman if (m == NULL || m->m_len < sizeof (int)) 538a0292f23SGarrett Wollman error = EINVAL; 539a0292f23SGarrett Wollman else if (*mtod(m, int *)) 540a0292f23SGarrett Wollman tp->t_flags |= TF_NOOPT; 541a0292f23SGarrett Wollman else 542a0292f23SGarrett Wollman tp->t_flags &= ~TF_NOOPT; 543a0292f23SGarrett Wollman break; 544a0292f23SGarrett Wollman 545a0292f23SGarrett Wollman case TCP_NOPUSH: 546a0292f23SGarrett Wollman if (m == NULL || m->m_len < sizeof (int)) 547a0292f23SGarrett Wollman error = EINVAL; 548a0292f23SGarrett Wollman else if (*mtod(m, int *)) 549a0292f23SGarrett Wollman tp->t_flags |= TF_NOPUSH; 550a0292f23SGarrett Wollman else 551a0292f23SGarrett Wollman tp->t_flags &= ~TF_NOPUSH; 552a0292f23SGarrett Wollman break; 553a0292f23SGarrett Wollman 554df8bae1dSRodney W. Grimes default: 555df8bae1dSRodney W. Grimes error = ENOPROTOOPT; 556df8bae1dSRodney W. Grimes break; 557df8bae1dSRodney W. Grimes } 558df8bae1dSRodney W. Grimes if (m) 559df8bae1dSRodney W. Grimes (void) m_free(m); 560df8bae1dSRodney W. Grimes break; 561df8bae1dSRodney W. Grimes 562df8bae1dSRodney W. Grimes case PRCO_GETOPT: 563df8bae1dSRodney W. Grimes *mp = m = m_get(M_WAIT, MT_SOOPTS); 564df8bae1dSRodney W. Grimes m->m_len = sizeof(int); 565df8bae1dSRodney W. Grimes 566df8bae1dSRodney W. Grimes switch (optname) { 567df8bae1dSRodney W. Grimes case TCP_NODELAY: 568df8bae1dSRodney W. Grimes *mtod(m, int *) = tp->t_flags & TF_NODELAY; 569df8bae1dSRodney W. Grimes break; 570df8bae1dSRodney W. Grimes case TCP_MAXSEG: 571df8bae1dSRodney W. Grimes *mtod(m, int *) = tp->t_maxseg; 572df8bae1dSRodney W. Grimes break; 573a0292f23SGarrett Wollman case TCP_NOOPT: 574a0292f23SGarrett Wollman *mtod(m, int *) = tp->t_flags & TF_NOOPT; 575a0292f23SGarrett Wollman break; 576a0292f23SGarrett Wollman case TCP_NOPUSH: 577a0292f23SGarrett Wollman *mtod(m, int *) = tp->t_flags & TF_NOPUSH; 578a0292f23SGarrett Wollman break; 579df8bae1dSRodney W. Grimes default: 580df8bae1dSRodney W. Grimes error = ENOPROTOOPT; 581df8bae1dSRodney W. Grimes break; 582df8bae1dSRodney W. Grimes } 583df8bae1dSRodney W. Grimes break; 584df8bae1dSRodney W. Grimes } 585df8bae1dSRodney W. Grimes splx(s); 586df8bae1dSRodney W. Grimes return (error); 587df8bae1dSRodney W. Grimes } 588df8bae1dSRodney W. Grimes 58926e30fbbSDavid Greenman /* 59026e30fbbSDavid Greenman * tcp_sendspace and tcp_recvspace are the default send and receive window 59126e30fbbSDavid Greenman * sizes, respectively. These are obsolescent (this information should 59226e30fbbSDavid Greenman * be set by the route). 59326e30fbbSDavid Greenman */ 59426e30fbbSDavid Greenman u_long tcp_sendspace = 1024*16; 59598163b98SPoul-Henning Kamp SYSCTL_INT(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace, 59698163b98SPoul-Henning Kamp CTLFLAG_RW, &tcp_sendspace , 0, ""); 59726e30fbbSDavid Greenman u_long tcp_recvspace = 1024*16; 59898163b98SPoul-Henning Kamp SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace, 59998163b98SPoul-Henning Kamp CTLFLAG_RW, &tcp_recvspace , 0, ""); 600df8bae1dSRodney W. Grimes 601df8bae1dSRodney W. Grimes /* 602df8bae1dSRodney W. Grimes * Attach TCP protocol to socket, allocating 603df8bae1dSRodney W. Grimes * internet protocol control block, tcp control block, 604df8bae1dSRodney W. Grimes * bufer space, and entering LISTEN state if to accept connections. 605df8bae1dSRodney W. Grimes */ 606df8bae1dSRodney W. Grimes int 607df8bae1dSRodney W. Grimes tcp_attach(so) 608df8bae1dSRodney W. Grimes struct socket *so; 609df8bae1dSRodney W. Grimes { 610df8bae1dSRodney W. Grimes register struct tcpcb *tp; 611df8bae1dSRodney W. Grimes struct inpcb *inp; 612df8bae1dSRodney W. Grimes int error; 613df8bae1dSRodney W. Grimes 614df8bae1dSRodney W. Grimes if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 615df8bae1dSRodney W. Grimes error = soreserve(so, tcp_sendspace, tcp_recvspace); 616df8bae1dSRodney W. Grimes if (error) 617df8bae1dSRodney W. Grimes return (error); 618df8bae1dSRodney W. Grimes } 61915bd2b43SDavid Greenman error = in_pcballoc(so, &tcbinfo); 620df8bae1dSRodney W. Grimes if (error) 621df8bae1dSRodney W. Grimes return (error); 622df8bae1dSRodney W. Grimes inp = sotoinpcb(so); 623df8bae1dSRodney W. Grimes tp = tcp_newtcpcb(inp); 624df8bae1dSRodney W. Grimes if (tp == 0) { 625df8bae1dSRodney W. Grimes int nofd = so->so_state & SS_NOFDREF; /* XXX */ 626df8bae1dSRodney W. Grimes 627df8bae1dSRodney W. Grimes so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */ 628df8bae1dSRodney W. Grimes in_pcbdetach(inp); 629df8bae1dSRodney W. Grimes so->so_state |= nofd; 630df8bae1dSRodney W. Grimes return (ENOBUFS); 631df8bae1dSRodney W. Grimes } 632df8bae1dSRodney W. Grimes tp->t_state = TCPS_CLOSED; 633df8bae1dSRodney W. Grimes return (0); 634df8bae1dSRodney W. Grimes } 635df8bae1dSRodney W. Grimes 636df8bae1dSRodney W. Grimes /* 637df8bae1dSRodney W. Grimes * Initiate (or continue) disconnect. 638df8bae1dSRodney W. Grimes * If embryonic state, just send reset (once). 639df8bae1dSRodney W. Grimes * If in ``let data drain'' option and linger null, just drop. 640df8bae1dSRodney W. Grimes * Otherwise (hard), mark socket disconnecting and drop 641df8bae1dSRodney W. Grimes * current input data; switch states based on user close, and 642df8bae1dSRodney W. Grimes * send segment to peer (with FIN). 643df8bae1dSRodney W. Grimes */ 644df8bae1dSRodney W. Grimes struct tcpcb * 645df8bae1dSRodney W. Grimes tcp_disconnect(tp) 646df8bae1dSRodney W. Grimes register struct tcpcb *tp; 647df8bae1dSRodney W. Grimes { 648df8bae1dSRodney W. Grimes struct socket *so = tp->t_inpcb->inp_socket; 649df8bae1dSRodney W. Grimes 650df8bae1dSRodney W. Grimes if (tp->t_state < TCPS_ESTABLISHED) 651df8bae1dSRodney W. Grimes tp = tcp_close(tp); 652df8bae1dSRodney W. Grimes else if ((so->so_options & SO_LINGER) && so->so_linger == 0) 653df8bae1dSRodney W. Grimes tp = tcp_drop(tp, 0); 654df8bae1dSRodney W. Grimes else { 655df8bae1dSRodney W. Grimes soisdisconnecting(so); 656df8bae1dSRodney W. Grimes sbflush(&so->so_rcv); 657df8bae1dSRodney W. Grimes tp = tcp_usrclosed(tp); 658df8bae1dSRodney W. Grimes if (tp) 659df8bae1dSRodney W. Grimes (void) tcp_output(tp); 660df8bae1dSRodney W. Grimes } 661df8bae1dSRodney W. Grimes return (tp); 662df8bae1dSRodney W. Grimes } 663df8bae1dSRodney W. Grimes 664df8bae1dSRodney W. Grimes /* 665df8bae1dSRodney W. Grimes * User issued close, and wish to trail through shutdown states: 666df8bae1dSRodney W. Grimes * if never received SYN, just forget it. If got a SYN from peer, 667df8bae1dSRodney W. Grimes * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. 668df8bae1dSRodney W. Grimes * If already got a FIN from peer, then almost done; go to LAST_ACK 669df8bae1dSRodney W. Grimes * state. In all other cases, have already sent FIN to peer (e.g. 670df8bae1dSRodney W. Grimes * after PRU_SHUTDOWN), and just have to play tedious game waiting 671df8bae1dSRodney W. Grimes * for peer to send FIN or not respond to keep-alives, etc. 672df8bae1dSRodney W. Grimes * We can let the user exit from the close as soon as the FIN is acked. 673df8bae1dSRodney W. Grimes */ 674df8bae1dSRodney W. Grimes struct tcpcb * 675df8bae1dSRodney W. Grimes tcp_usrclosed(tp) 676df8bae1dSRodney W. Grimes register struct tcpcb *tp; 677df8bae1dSRodney W. Grimes { 678df8bae1dSRodney W. Grimes 679df8bae1dSRodney W. Grimes switch (tp->t_state) { 680df8bae1dSRodney W. Grimes 681df8bae1dSRodney W. Grimes case TCPS_CLOSED: 682df8bae1dSRodney W. Grimes case TCPS_LISTEN: 683df8bae1dSRodney W. Grimes tp->t_state = TCPS_CLOSED; 684df8bae1dSRodney W. Grimes tp = tcp_close(tp); 685df8bae1dSRodney W. Grimes break; 686df8bae1dSRodney W. Grimes 687a0292f23SGarrett Wollman case TCPS_SYN_SENT: 688df8bae1dSRodney W. Grimes case TCPS_SYN_RECEIVED: 689a0292f23SGarrett Wollman tp->t_flags |= TF_NEEDFIN; 690a0292f23SGarrett Wollman break; 691a0292f23SGarrett Wollman 692df8bae1dSRodney W. Grimes case TCPS_ESTABLISHED: 693df8bae1dSRodney W. Grimes tp->t_state = TCPS_FIN_WAIT_1; 694df8bae1dSRodney W. Grimes break; 695df8bae1dSRodney W. Grimes 696df8bae1dSRodney W. Grimes case TCPS_CLOSE_WAIT: 697df8bae1dSRodney W. Grimes tp->t_state = TCPS_LAST_ACK; 698df8bae1dSRodney W. Grimes break; 699df8bae1dSRodney W. Grimes } 700b6239c4aSAndras Olah if (tp && tp->t_state >= TCPS_FIN_WAIT_2) { 701df8bae1dSRodney W. Grimes soisdisconnected(tp->t_inpcb->inp_socket); 702b6239c4aSAndras Olah /* To prevent the connection hanging in FIN_WAIT_2 forever. */ 703b6239c4aSAndras Olah if (tp->t_state == TCPS_FIN_WAIT_2) 704b6239c4aSAndras Olah tp->t_timer[TCPT_2MSL] = tcp_maxidle; 705b6239c4aSAndras Olah } 706df8bae1dSRodney W. Grimes return (tp); 707df8bae1dSRodney W. Grimes } 708a0292f23SGarrett Wollman 709a0292f23SGarrett Wollman /* 710a0292f23SGarrett Wollman * Sysctl for tcp variables. 711a0292f23SGarrett Wollman */ 712a0292f23SGarrett Wollman int 713a0292f23SGarrett Wollman tcp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 714a0292f23SGarrett Wollman int *name; 715a0292f23SGarrett Wollman u_int namelen; 716a0292f23SGarrett Wollman void *oldp; 717a0292f23SGarrett Wollman size_t *oldlenp; 718a0292f23SGarrett Wollman void *newp; 719a0292f23SGarrett Wollman size_t newlen; 720a0292f23SGarrett Wollman { 721a0292f23SGarrett Wollman /* All sysctl names at this level are terminal. */ 722a0292f23SGarrett Wollman if (namelen != 1) 723a0292f23SGarrett Wollman return (ENOTDIR); 724a0292f23SGarrett Wollman 725a0292f23SGarrett Wollman switch (name[0]) { 726a0292f23SGarrett Wollman case TCPCTL_DO_RFC1323: 727a0292f23SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, 728a0292f23SGarrett Wollman &tcp_do_rfc1323)); 729a0292f23SGarrett Wollman case TCPCTL_DO_RFC1644: 730a0292f23SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, 731a0292f23SGarrett Wollman &tcp_do_rfc1644)); 732a0292f23SGarrett Wollman case TCPCTL_MSSDFLT: 733a0292f23SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, 734a0292f23SGarrett Wollman &tcp_mssdflt)); 735f2ea20e6SGarrett Wollman case TCPCTL_STATS: 736f2ea20e6SGarrett Wollman return (sysctl_rdstruct(oldp, oldlenp, newp, &tcpstat, 737f2ea20e6SGarrett Wollman sizeof tcpstat)); 738f2ea20e6SGarrett Wollman case TCPCTL_RTTDFLT: 739f2ea20e6SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, &tcp_rttdflt)); 740f2ea20e6SGarrett Wollman case TCPCTL_KEEPIDLE: 741f2ea20e6SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, 742f2ea20e6SGarrett Wollman &tcp_keepidle)); 743f2ea20e6SGarrett Wollman case TCPCTL_KEEPINTVL: 744f2ea20e6SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, 745f2ea20e6SGarrett Wollman &tcp_keepintvl)); 746f2ea20e6SGarrett Wollman case TCPCTL_SENDSPACE: 747f2ea20e6SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, 748f2ea20e6SGarrett Wollman (int *)&tcp_sendspace)); /* XXX */ 749f2ea20e6SGarrett Wollman case TCPCTL_RECVSPACE: 750f2ea20e6SGarrett Wollman return (sysctl_int(oldp, oldlenp, newp, newlen, 751f2ea20e6SGarrett Wollman (int *)&tcp_recvspace)); /* XXX */ 752a0292f23SGarrett Wollman default: 753a0292f23SGarrett Wollman return (ENOPROTOOPT); 754a0292f23SGarrett Wollman } 755a0292f23SGarrett Wollman /* NOTREACHED */ 756a0292f23SGarrett Wollman } 757