File:  [DragonFly] / src / sys / netinet / tcp_usrreq.c
Revision 1.16: download - view: text, annotated - select for diffs
Tue Apr 20 01:52:28 2004 UTC (10 years, 5 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Revamp the initial lwkt_abortmsg() support to normalize the abstraction.  Now
a message's primary command is always processed by the target even if an
abort is requested before the target has retrieved the message from the
message port.  The message will then be requeued and the abort command copied
into lwkt_msg_t->ms_cmd.  Thus the target is always guarenteed to see the
original message and then a second, abort message (the same message with
ms_cmd = ms_abort) regardless of whether the abort was requested before
or after the target retrieved the original message.

ms_cmd is now an opaque union.  LWKT makes no assumptions as to its contents.
The NET code now stores nm_handler in ms_cmd as a function vector, and
nm_handler has been removed from all netmsg structures.

The ms_cmd function vector support nominally returns an integer error code
which is intended to support synchronous/asynchronous optimizations in the
future (to bypass messaging queueing and dequeueing in those situations
where they can be bypassed, without messing up the messaging abstraction).

The connect() predicate for which signal/abort support was added in the last
commit now uses the new abort mechanism.  Instead of having the handler
function check whether a message represents an abort or not, a different
handler vector is stored in ms_abort and run when an abort is processed
(making for an easy separation of function).

The large netmsg switch has been replaced by individual function vectors
using the new ms_cmd function vector support.  This will soon be removed
entirely in favor of direct assignment of LWKT-aware PRU vectors to the
messages command vector.

NOTE ADDITIONAL: eventually the SYSCALL, VFS, and DEV interfaces will use
the new message opaque ms_cmd 'function vector' support instead of a
command index.

Work by: Matthew Dillon and Jeffrey Hsu

    1: /*
    2:  * Copyright (c) 1982, 1986, 1988, 1993
    3:  *	The Regents of the University of California.  All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  * 3. All advertising materials mentioning features or use of this software
   14:  *    must display the following acknowledgement:
   15:  *	This product includes software developed by the University of
   16:  *	California, Berkeley and its contributors.
   17:  * 4. Neither the name of the University nor the names of its contributors
   18:  *    may be used to endorse or promote products derived from this software
   19:  *    without specific prior written permission.
   20:  *
   21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31:  * SUCH DAMAGE.
   32:  *
   33:  *	From: @(#)tcp_usrreq.c	8.2 (Berkeley) 1/3/94
   34:  * $FreeBSD: src/sys/netinet/tcp_usrreq.c,v 1.51.2.17 2002/10/11 11:46:44 ume Exp $
   35:  * $DragonFly: src/sys/netinet/tcp_usrreq.c,v 1.16 2004/04/20 01:52:28 dillon Exp $
   36:  */
   37: 
   38: #include "opt_ipsec.h"
   39: #include "opt_inet6.h"
   40: #include "opt_tcpdebug.h"
   41: 
   42: #include <sys/param.h>
   43: #include <sys/systm.h>
   44: #include <sys/kernel.h>
   45: #include <sys/malloc.h>
   46: #include <sys/sysctl.h>
   47: #include <sys/globaldata.h>
   48: #include <sys/thread.h>
   49: 
   50: #include <sys/mbuf.h>
   51: #ifdef INET6
   52: #include <sys/domain.h>
   53: #endif /* INET6 */
   54: #include <sys/socket.h>
   55: #include <sys/socketvar.h>
   56: #include <sys/protosw.h>
   57: 
   58: #include <sys/msgport2.h>
   59: 
   60: #include <net/if.h>
   61: #include <net/netisr.h>
   62: #include <net/route.h>
   63: 
   64: #include <netinet/in.h>
   65: #include <netinet/in_systm.h>
   66: #ifdef INET6
   67: #include <netinet/ip6.h>
   68: #endif
   69: #include <netinet/in_pcb.h>
   70: #ifdef INET6
   71: #include <netinet6/in6_pcb.h>
   72: #endif
   73: #include <netinet/in_var.h>
   74: #include <netinet/ip_var.h>
   75: #ifdef INET6
   76: #include <netinet6/ip6_var.h>
   77: #endif
   78: #include <netinet/tcp.h>
   79: #include <netinet/tcp_fsm.h>
   80: #include <netinet/tcp_seq.h>
   81: #include <netinet/tcp_timer.h>
   82: #include <netinet/tcp_var.h>
   83: #include <netinet/tcpip.h>
   84: #ifdef TCPDEBUG
   85: #include <netinet/tcp_debug.h>
   86: #endif
   87: 
   88: #ifdef IPSEC
   89: #include <netinet6/ipsec.h>
   90: #endif /*IPSEC*/
   91: 
   92: /*
   93:  * TCP protocol interface to socket abstraction.
   94:  */
   95: extern	char *tcpstates[];	/* XXX ??? */
   96: 
   97: static int	tcp_attach (struct socket *, struct pru_attach_info *);
   98: static int	tcp_connect (struct tcpcb *, struct sockaddr *, 
   99: 				 struct thread *);
  100: #ifdef INET6
  101: static int	tcp6_connect (struct tcpcb *, struct sockaddr *,
  102: 				 struct thread *);
  103: #endif /* INET6 */
  104: static struct tcpcb *
  105: 		tcp_disconnect (struct tcpcb *);
  106: static struct tcpcb *
  107: 		tcp_usrclosed (struct tcpcb *);
  108: 
  109: #ifdef TCPDEBUG
  110: #define	TCPDEBUG0	int ostate = 0
  111: #define	TCPDEBUG1()	ostate = tp ? tp->t_state : 0
  112: #define	TCPDEBUG2(req)	if (tp && (so->so_options & SO_DEBUG)) \
  113: 				tcp_trace(TA_USER, ostate, tp, 0, 0, req)
  114: #else
  115: #define	TCPDEBUG0
  116: #define	TCPDEBUG1()
  117: #define	TCPDEBUG2(req)
  118: #endif
  119: 
  120: /*
  121:  * TCP attaches to socket via pru_attach(), reserving space,
  122:  * and an internet control block.
  123:  */
  124: static int
  125: tcp_usr_attach(struct socket *so, int proto, struct pru_attach_info *ai)
  126: {
  127: 	int s = splnet();
  128: 	int error;
  129: 	struct inpcb *inp = sotoinpcb(so);
  130: 	struct tcpcb *tp = 0;
  131: 	TCPDEBUG0;
  132: 
  133: 	TCPDEBUG1();
  134: 	if (inp) {
  135: 		error = EISCONN;
  136: 		goto out;
  137: 	}
  138: 
  139: 	error = tcp_attach(so, ai);
  140: 	if (error)
  141: 		goto out;
  142: 
  143: 	if ((so->so_options & SO_LINGER) && so->so_linger == 0)
  144: 		so->so_linger = TCP_LINGERTIME;
  145: 	tp = sototcpcb(so);
  146: out:
  147: 	TCPDEBUG2(PRU_ATTACH);
  148: 	splx(s);
  149: 	return error;
  150: }
  151: 
  152: /*
  153:  * pru_detach() detaches the TCP protocol from the socket.
  154:  * If the protocol state is non-embryonic, then can't
  155:  * do this directly: have to initiate a pru_disconnect(),
  156:  * which may finish later; embryonic TCB's can just
  157:  * be discarded here.
  158:  */
  159: static int
  160: tcp_usr_detach(struct socket *so)
  161: {
  162: 	int s = splnet();
  163: 	int error = 0;
  164: 	struct inpcb *inp = sotoinpcb(so);
  165: 	struct tcpcb *tp;
  166: 	TCPDEBUG0;
  167: 
  168: 	if (inp == 0) {
  169: 		splx(s);
  170: 		return EINVAL;	/* XXX */
  171: 	}
  172: 	tp = intotcpcb(inp);
  173: 	TCPDEBUG1();
  174: 	tp = tcp_disconnect(tp);
  175: 
  176: 	TCPDEBUG2(PRU_DETACH);
  177: 	splx(s);
  178: 	return error;
  179: }
  180: 
  181: #define	COMMON_START()	TCPDEBUG0; \
  182: 			do { \
  183: 				     if (inp == 0) { \
  184: 					     splx(s); \
  185: 					     return EINVAL; \
  186: 				     } \
  187: 				     tp = intotcpcb(inp); \
  188: 				     TCPDEBUG1(); \
  189: 		     } while(0)
  190: 			     
  191: #define COMMON_END(req)	out: TCPDEBUG2(req); splx(s); return error; goto out
  192: 
  193: 
  194: /*
  195:  * Give the socket an address.
  196:  */
  197: static int
  198: tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
  199: {
  200: 	int s = splnet();
  201: 	int error = 0;
  202: 	struct inpcb *inp = sotoinpcb(so);
  203: 	struct tcpcb *tp;
  204: 	struct sockaddr_in *sinp;
  205: 
  206: 	COMMON_START();
  207: 
  208: 	/*
  209: 	 * Must check for multicast addresses and disallow binding
  210: 	 * to them.
  211: 	 */
  212: 	sinp = (struct sockaddr_in *)nam;
  213: 	if (sinp->sin_family == AF_INET &&
  214: 	    IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
  215: 		error = EAFNOSUPPORT;
  216: 		goto out;
  217: 	}
  218: 	error = in_pcbbind(inp, nam, td);
  219: 	if (error)
  220: 		goto out;
  221: 	COMMON_END(PRU_BIND);
  222: 
  223: }
  224: 
  225: #ifdef INET6
  226: static int
  227: tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
  228: {
  229: 	int s = splnet();
  230: 	int error = 0;
  231: 	struct inpcb *inp = sotoinpcb(so);
  232: 	struct tcpcb *tp;
  233: 	struct sockaddr_in6 *sin6p;
  234: 
  235: 	COMMON_START();
  236: 
  237: 	/*
  238: 	 * Must check for multicast addresses and disallow binding
  239: 	 * to them.
  240: 	 */
  241: 	sin6p = (struct sockaddr_in6 *)nam;
  242: 	if (sin6p->sin6_family == AF_INET6 &&
  243: 	    IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
  244: 		error = EAFNOSUPPORT;
  245: 		goto out;
  246: 	}
  247: 	inp->inp_vflag &= ~INP_IPV4;
  248: 	inp->inp_vflag |= INP_IPV6;
  249: 	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
  250: 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr))
  251: 			inp->inp_vflag |= INP_IPV4;
  252: 		else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
  253: 			struct sockaddr_in sin;
  254: 
  255: 			in6_sin6_2_sin(&sin, sin6p);
  256: 			inp->inp_vflag |= INP_IPV4;
  257: 			inp->inp_vflag &= ~INP_IPV6;
  258: 			error = in_pcbbind(inp, (struct sockaddr *)&sin, td);
  259: 			goto out;
  260: 		}
  261: 	}
  262: 	error = in6_pcbbind(inp, nam, td);
  263: 	if (error)
  264: 		goto out;
  265: 	COMMON_END(PRU_BIND);
  266: }
  267: #endif /* INET6 */
  268: 
  269: /*
  270:  * Prepare to accept connections.
  271:  */
  272: static int
  273: tcp_usr_listen(struct socket *so, struct thread *td)
  274: {
  275: 	int s = splnet();
  276: 	int error = 0;
  277: 	struct inpcb *inp = sotoinpcb(so);
  278: 	struct tcpcb *tp;
  279: 
  280: 	COMMON_START();
  281: 	if (inp->inp_lport == 0)
  282: 		error = in_pcbbind(inp, (struct sockaddr *)0, td);
  283: 	if (error == 0) {
  284: 		tp->t_state = TCPS_LISTEN;
  285: 		in_pcbinswildcardhash(inp);
  286: 	}
  287: 	COMMON_END(PRU_LISTEN);
  288: }
  289: 
  290: #ifdef INET6
  291: static int
  292: tcp6_usr_listen(struct socket *so, struct thread *td)
  293: {
  294: 	int s = splnet();
  295: 	int error = 0;
  296: 	struct inpcb *inp = sotoinpcb(so);
  297: 	struct tcpcb *tp;
  298: 
  299: 	COMMON_START();
  300: 	if (inp->inp_lport == 0) {
  301: 		inp->inp_vflag &= ~INP_IPV4;
  302: 		if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
  303: 			inp->inp_vflag |= INP_IPV4;
  304: 		error = in6_pcbbind(inp, (struct sockaddr *)0, td);
  305: 	}
  306: 	if (error == 0)
  307: 		tp->t_state = TCPS_LISTEN;
  308: 	COMMON_END(PRU_LISTEN);
  309: }
  310: #endif /* INET6 */
  311: 
  312: /*
  313:  * Initiate connection to peer.
  314:  * Create a template for use in transmissions on this connection.
  315:  * Enter SYN_SENT state, and mark socket as connecting.
  316:  * Start keep-alive timer, and seed output sequence space.
  317:  * Send initial segment on connection.
  318:  */
  319: static int
  320: tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  321: {
  322: 	int s = splnet();
  323: 	int error = 0;
  324: 	struct inpcb *inp = sotoinpcb(so);
  325: 	struct tcpcb *tp;
  326: 	struct sockaddr_in *sinp;
  327: 
  328: 	COMMON_START();
  329: 
  330: 	/*
  331: 	 * Must disallow TCP ``connections'' to multicast addresses.
  332: 	 */
  333: 	sinp = (struct sockaddr_in *)nam;
  334: 	if (sinp->sin_family == AF_INET
  335: 	    && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
  336: 		error = EAFNOSUPPORT;
  337: 		goto out;
  338: 	}
  339: 
  340: 	prison_remote_ip(td, 0, &sinp->sin_addr.s_addr);
  341: 
  342: 	if ((error = tcp_connect(tp, nam, td)) != 0)
  343: 		goto out;
  344: 	error = tcp_output(tp);
  345: 	COMMON_END(PRU_CONNECT);
  346: }
  347: 
  348: #ifdef INET6
  349: static int
  350: tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  351: {
  352: 	int s = splnet();
  353: 	int error = 0;
  354: 	struct inpcb *inp = sotoinpcb(so);
  355: 	struct tcpcb *tp;
  356: 	struct sockaddr_in6 *sin6p;
  357: 
  358: 	COMMON_START();
  359: 
  360: 	/*
  361: 	 * Must disallow TCP ``connections'' to multicast addresses.
  362: 	 */
  363: 	sin6p = (struct sockaddr_in6 *)nam;
  364: 	if (sin6p->sin6_family == AF_INET6
  365: 	    && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
  366: 		error = EAFNOSUPPORT;
  367: 		goto out;
  368: 	}
  369: 
  370: 	if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
  371: 		struct sockaddr_in sin;
  372: 
  373: 		if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) {
  374: 			error = EINVAL;
  375: 			goto out;
  376: 		}
  377: 
  378: 		in6_sin6_2_sin(&sin, sin6p);
  379: 		inp->inp_vflag |= INP_IPV4;
  380: 		inp->inp_vflag &= ~INP_IPV6;
  381: 		if ((error = tcp_connect(tp, (struct sockaddr *)&sin, td)) != 0)
  382: 			goto out;
  383: 		error = tcp_output(tp);
  384: 		goto out;
  385: 	}
  386: 	inp->inp_vflag &= ~INP_IPV4;
  387: 	inp->inp_vflag |= INP_IPV6;
  388: 	inp->inp_inc.inc_isipv6 = 1;
  389: 	if ((error = tcp6_connect(tp, nam, td)) != 0)
  390: 		goto out;
  391: 	error = tcp_output(tp);
  392: 	COMMON_END(PRU_CONNECT);
  393: }
  394: #endif /* INET6 */
  395: 
  396: /*
  397:  * Initiate disconnect from peer.
  398:  * If connection never passed embryonic stage, just drop;
  399:  * else if don't need to let data drain, then can just drop anyways,
  400:  * else have to begin TCP shutdown process: mark socket disconnecting,
  401:  * drain unread data, state switch to reflect user close, and
  402:  * send segment (e.g. FIN) to peer.  Socket will be really disconnected
  403:  * when peer sends FIN and acks ours.
  404:  *
  405:  * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
  406:  */
  407: static int
  408: tcp_usr_disconnect(struct socket *so)
  409: {
  410: 	int s = splnet();
  411: 	int error = 0;
  412: 	struct inpcb *inp = sotoinpcb(so);
  413: 	struct tcpcb *tp;
  414: 
  415: 	COMMON_START();
  416: 	tp = tcp_disconnect(tp);
  417: 	COMMON_END(PRU_DISCONNECT);
  418: }
  419: 
  420: /*
  421:  * Accept a connection.  Essentially all the work is
  422:  * done at higher levels; just return the address
  423:  * of the peer, storing through addr.
  424:  */
  425: static int
  426: tcp_usr_accept(struct socket *so, struct sockaddr **nam)
  427: {
  428: 	int s = splnet();
  429: 	int error = 0;
  430: 	struct inpcb *inp = sotoinpcb(so);
  431: 	struct tcpcb *tp = NULL;
  432: 	TCPDEBUG0;
  433: 
  434: 	if (so->so_state & SS_ISDISCONNECTED) {
  435: 		error = ECONNABORTED;
  436: 		goto out;
  437: 	}
  438: 	if (inp == 0) {
  439: 		splx(s);
  440: 		return (EINVAL);
  441: 	}
  442: 	tp = intotcpcb(inp);
  443: 	TCPDEBUG1();
  444: 	in_setpeeraddr(so, nam);
  445: 	COMMON_END(PRU_ACCEPT);
  446: }
  447: 
  448: #ifdef INET6
  449: static int
  450: tcp6_usr_accept(struct socket *so, struct sockaddr **nam)
  451: {
  452: 	int s = splnet();
  453: 	int error = 0;
  454: 	struct inpcb *inp = sotoinpcb(so);
  455: 	struct tcpcb *tp = NULL;
  456: 	TCPDEBUG0;
  457: 
  458: 	if (so->so_state & SS_ISDISCONNECTED) {
  459: 		error = ECONNABORTED;
  460: 		goto out;
  461: 	}
  462: 	if (inp == 0) {
  463: 		splx(s);
  464: 		return (EINVAL);
  465: 	}
  466: 	tp = intotcpcb(inp);
  467: 	TCPDEBUG1();
  468: 	in6_mapped_peeraddr(so, nam);
  469: 	COMMON_END(PRU_ACCEPT);
  470: }
  471: #endif /* INET6 */
  472: /*
  473:  * Mark the connection as being incapable of further output.
  474:  */
  475: static int
  476: tcp_usr_shutdown(struct socket *so)
  477: {
  478: 	int s = splnet();
  479: 	int error = 0;
  480: 	struct inpcb *inp = sotoinpcb(so);
  481: 	struct tcpcb *tp;
  482: 
  483: 	COMMON_START();
  484: 	socantsendmore(so);
  485: 	tp = tcp_usrclosed(tp);
  486: 	if (tp)
  487: 		error = tcp_output(tp);
  488: 	COMMON_END(PRU_SHUTDOWN);
  489: }
  490: 
  491: /*
  492:  * After a receive, possibly send window update to peer.
  493:  */
  494: static int
  495: tcp_usr_rcvd(struct socket *so, int flags)
  496: {
  497: 	int s = splnet();
  498: 	int error = 0;
  499: 	struct inpcb *inp = sotoinpcb(so);
  500: 	struct tcpcb *tp;
  501: 
  502: 	COMMON_START();
  503: 	tcp_output(tp);
  504: 	COMMON_END(PRU_RCVD);
  505: }
  506: 
  507: /*
  508:  * Do a send by putting data in output queue and updating urgent
  509:  * marker if URG set.  Possibly send more data.  Unlike the other
  510:  * pru_*() routines, the mbuf chains are our responsibility.  We
  511:  * must either enqueue them or free them.  The other pru_* routines
  512:  * generally are caller-frees.
  513:  */
  514: static int
  515: tcp_usr_send(struct socket *so, int flags, struct mbuf *m, 
  516: 	     struct sockaddr *nam, struct mbuf *control, struct thread *td)
  517: {
  518: 	int s = splnet();
  519: 	int error = 0;
  520: 	struct inpcb *inp = sotoinpcb(so);
  521: 	struct tcpcb *tp;
  522: #ifdef INET6
  523: 	int isipv6;
  524: #endif
  525: 	TCPDEBUG0;
  526: 
  527: 	if (inp == NULL) {
  528: 		/*
  529: 		 * OOPS! we lost a race, the TCP session got reset after
  530: 		 * we checked SS_CANTSENDMORE, eg: while doing uiomove or a
  531: 		 * network interrupt in the non-splnet() section of sosend().
  532: 		 */
  533: 		if (m)
  534: 			m_freem(m);
  535: 		if (control)
  536: 			m_freem(control);
  537: 		error = ECONNRESET;	/* XXX EPIPE? */
  538: 		tp = NULL;
  539: 		TCPDEBUG1();
  540: 		goto out;
  541: 	}
  542: #ifdef INET6
  543: 	isipv6 = nam && nam->sa_family == AF_INET6;
  544: #endif /* INET6 */
  545: 	tp = intotcpcb(inp);
  546: 	TCPDEBUG1();
  547: 	if (control) {
  548: 		/* TCP doesn't do control messages (rights, creds, etc) */
  549: 		if (control->m_len) {
  550: 			m_freem(control);
  551: 			if (m)
  552: 				m_freem(m);
  553: 			error = EINVAL;
  554: 			goto out;
  555: 		}
  556: 		m_freem(control);	/* empty control, just free it */
  557: 	}
  558: 	if(!(flags & PRUS_OOB)) {
  559: 		sbappend(&so->so_snd, m);
  560: 		if (nam && tp->t_state < TCPS_SYN_SENT) {
  561: 			/*
  562: 			 * Do implied connect if not yet connected,
  563: 			 * initialize window to default value, and
  564: 			 * initialize maxseg/maxopd using peer's cached
  565: 			 * MSS.
  566: 			 */
  567: #ifdef INET6
  568: 			if (isipv6)
  569: 				error = tcp6_connect(tp, nam, td);
  570: 			else
  571: #endif /* INET6 */
  572: 			error = tcp_connect(tp, nam, td);
  573: 			if (error)
  574: 				goto out;
  575: 			tp->snd_wnd = TTCP_CLIENT_SND_WND;
  576: 			tcp_mss(tp, -1);
  577: 		}
  578: 
  579: 		if (flags & PRUS_EOF) {
  580: 			/*
  581: 			 * Close the send side of the connection after
  582: 			 * the data is sent.
  583: 			 */
  584: 			socantsendmore(so);
  585: 			tp = tcp_usrclosed(tp);
  586: 		}
  587: 		if (tp != NULL) {
  588: 			if (flags & PRUS_MORETOCOME)
  589: 				tp->t_flags |= TF_MORETOCOME;
  590: 			error = tcp_output(tp);
  591: 			if (flags & PRUS_MORETOCOME)
  592: 				tp->t_flags &= ~TF_MORETOCOME;
  593: 		}
  594: 	} else {
  595: 		if (sbspace(&so->so_snd) < -512) {
  596: 			m_freem(m);
  597: 			error = ENOBUFS;
  598: 			goto out;
  599: 		}
  600: 		/*
  601: 		 * According to RFC961 (Assigned Protocols),
  602: 		 * the urgent pointer points to the last octet
  603: 		 * of urgent data.  We continue, however,
  604: 		 * to consider it to indicate the first octet
  605: 		 * of data past the urgent section.
  606: 		 * Otherwise, snd_up should be one lower.
  607: 		 */
  608: 		sbappend(&so->so_snd, m);
  609: 		if (nam && tp->t_state < TCPS_SYN_SENT) {
  610: 			/*
  611: 			 * Do implied connect if not yet connected,
  612: 			 * initialize window to default value, and
  613: 			 * initialize maxseg/maxopd using peer's cached
  614: 			 * MSS.
  615: 			 */
  616: #ifdef INET6
  617: 			if (isipv6)
  618: 				error = tcp6_connect(tp, nam, td);
  619: 			else
  620: #endif /* INET6 */
  621: 			error = tcp_connect(tp, nam, td);
  622: 			if (error)
  623: 				goto out;
  624: 			tp->snd_wnd = TTCP_CLIENT_SND_WND;
  625: 			tcp_mss(tp, -1);
  626: 		}
  627: 		tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
  628: 		tp->t_force = 1;
  629: 		error = tcp_output(tp);
  630: 		tp->t_force = 0;
  631: 	}
  632: 	COMMON_END((flags & PRUS_OOB) ? PRU_SENDOOB : 
  633: 		   ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
  634: }
  635: 
  636: /*
  637:  * Abort the TCP.
  638:  */
  639: static int
  640: tcp_usr_abort(struct socket *so)
  641: {
  642: 	int s = splnet();
  643: 	int error = 0;
  644: 	struct inpcb *inp = sotoinpcb(so);
  645: 	struct tcpcb *tp;
  646: 
  647: 	COMMON_START();
  648: 	tp = tcp_drop(tp, ECONNABORTED);
  649: 	COMMON_END(PRU_ABORT);
  650: }
  651: 
  652: /*
  653:  * Receive out-of-band data.
  654:  */
  655: static int
  656: tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
  657: {
  658: 	int s = splnet();
  659: 	int error = 0;
  660: 	struct inpcb *inp = sotoinpcb(so);
  661: 	struct tcpcb *tp;
  662: 
  663: 	COMMON_START();
  664: 	if ((so->so_oobmark == 0 &&
  665: 	     (so->so_state & SS_RCVATMARK) == 0) ||
  666: 	    so->so_options & SO_OOBINLINE ||
  667: 	    tp->t_oobflags & TCPOOB_HADDATA) {
  668: 		error = EINVAL;
  669: 		goto out;
  670: 	}
  671: 	if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
  672: 		error = EWOULDBLOCK;
  673: 		goto out;
  674: 	}
  675: 	m->m_len = 1;
  676: 	*mtod(m, caddr_t) = tp->t_iobc;
  677: 	if ((flags & MSG_PEEK) == 0)
  678: 		tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
  679: 	COMMON_END(PRU_RCVOOB);
  680: }
  681: 
  682: /* xxx - should be const */
  683: struct pr_usrreqs tcp_usrreqs = {
  684: 	tcp_usr_abort, tcp_usr_accept, tcp_usr_attach, tcp_usr_bind,
  685: 	tcp_usr_connect, pru_connect2_notsupp, in_control, tcp_usr_detach,
  686: 	tcp_usr_disconnect, tcp_usr_listen, in_setpeeraddr, tcp_usr_rcvd,
  687: 	tcp_usr_rcvoob, tcp_usr_send, pru_sense_null, tcp_usr_shutdown,
  688: 	in_setsockaddr, sosend, soreceive, sopoll
  689: };
  690: 
  691: #ifdef INET6
  692: struct pr_usrreqs tcp6_usrreqs = {
  693: 	tcp_usr_abort, tcp6_usr_accept, tcp_usr_attach, tcp6_usr_bind,
  694: 	tcp6_usr_connect, pru_connect2_notsupp, in6_control, tcp_usr_detach,
  695: 	tcp_usr_disconnect, tcp6_usr_listen, in6_mapped_peeraddr, tcp_usr_rcvd,
  696: 	tcp_usr_rcvoob, tcp_usr_send, pru_sense_null, tcp_usr_shutdown,
  697: 	in6_mapped_sockaddr, sosend, soreceive, sopoll
  698: };
  699: #endif /* INET6 */
  700: 
  701: struct netmsg_tcp_connect {
  702: 	struct lwkt_msg		nm_lmsg;
  703: 	struct tcpcb		*nm_tp;
  704: 	struct sockaddr_in	*nm_sin;
  705: 	struct sockaddr_in	*nm_ifsin;
  706: };
  707: 
  708: static int
  709: tcp_connect_oncpu(struct tcpcb *tp, struct sockaddr_in *sin,
  710: 		  struct sockaddr_in *if_sin)
  711: {
  712: 	struct inpcb *inp = tp->t_inpcb, *oinp;
  713: 	struct socket *so = inp->inp_socket;
  714: 	struct tcpcb *otp;
  715: 	struct rmxp_tao *taop;
  716: 	struct rmxp_tao tao_noncached;
  717: 
  718: 	oinp = in_pcblookup_hash(&tcbinfo[mycpu->gd_cpuid],
  719: 	    sin->sin_addr, sin->sin_port,
  720: 	    inp->inp_laddr.s_addr != INADDR_ANY ?
  721: 	        inp->inp_laddr : if_sin->sin_addr,
  722: 	    inp->inp_lport, 0, NULL);
  723: 	if (oinp != NULL) {
  724: 		if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
  725: 		    otp->t_state == TCPS_TIME_WAIT &&
  726: 		    (ticks - otp->t_starttime) < tcp_msl &&
  727: 		    (otp->t_flags & TF_RCVD_CC))
  728: 			(void) tcp_close(otp);
  729: 		else
  730: 			return (EADDRINUSE);
  731: 	}
  732: 	if (inp->inp_laddr.s_addr == INADDR_ANY)
  733: 		inp->inp_laddr = if_sin->sin_addr;
  734: 	inp->inp_faddr = sin->sin_addr;
  735: 	inp->inp_fport = sin->sin_port;
  736: 	inp->inp_cpcbinfo = &tcbinfo[mycpu->gd_cpuid];
  737: 	in_pcbinsconnhash(inp);
  738: 
  739: 	/* Compute window scaling to request.  */
  740: 	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
  741: 	    (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
  742: 		tp->request_r_scale++;
  743: 
  744: 	soisconnecting(so);
  745: 	tcpstat.tcps_connattempt++;
  746: 	tp->t_state = TCPS_SYN_SENT;
  747: 	callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp);
  748: 	tp->iss = tcp_new_isn(tp);
  749: 	tp->t_bw_rtseq = tp->iss;
  750: 	tcp_sendseqinit(tp);
  751: 
  752: 	/*
  753: 	 * Generate a CC value for this connection and
  754: 	 * check whether CC or CCnew should be used.
  755: 	 */
  756: 	if ((taop = tcp_gettaocache(&tp->t_inpcb->inp_inc)) == NULL) {
  757: 		taop = &tao_noncached;
  758: 		bzero(taop, sizeof(*taop));
  759: 	}
  760: 
  761: 	tp->cc_send = CC_INC(tcp_ccgen);
  762: 	if (taop->tao_ccsent != 0 &&
  763: 	    CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
  764: 		taop->tao_ccsent = tp->cc_send;
  765: 	} else {
  766: 		taop->tao_ccsent = 0;
  767: 		tp->t_flags |= TF_SENDCCNEW;
  768: 	}
  769: 
  770: 	return (0);
  771: }
  772: 
  773: #if defined(SMP)
  774: 
  775: static int
  776: tcp_connect_handler(lwkt_msg_t lmsg)
  777: {
  778: 	struct netmsg_tcp_connect *msg = (void *)lmsg;
  779: 	int error;
  780: 
  781: 	error = tcp_connect_oncpu(msg->nm_tp, msg->nm_sin, msg->nm_ifsin);
  782: 	lwkt_replymsg(lmsg, error);
  783: 	return(EASYNC);
  784: }
  785: 
  786: #endif
  787: 
  788: /*
  789:  * Common subroutine to open a TCP connection to remote host specified
  790:  * by struct sockaddr_in in mbuf *nam.  Call in_pcbbind to assign a local
  791:  * port number if needed.  Call in_pcbladdr to do the routing and to choose
  792:  * a local host address (interface).  If there is an existing incarnation
  793:  * of the same connection in TIME-WAIT state and if the remote host was
  794:  * sending CC options and if the connection duration was < MSL, then
  795:  * truncate the previous TIME-WAIT state and proceed.
  796:  * Initialize connection parameters and enter SYN-SENT state.
  797:  */
  798: static int
  799: tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
  800: {
  801: 	struct inpcb *inp = tp->t_inpcb;
  802: 	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
  803: 	struct sockaddr_in *if_sin;
  804: 	int error;
  805: 	boolean_t didbind = FALSE;
  806: #if defined(SMP)
  807: 	lwkt_port_t port;
  808: #endif
  809: 
  810: 	if (inp->inp_lport == 0) {
  811: 		error = in_pcbbind(inp, (struct sockaddr *)NULL, td);
  812: 		if (error)
  813: 			return (error);
  814: 		didbind = TRUE;
  815: 	}
  816: 
  817: 	/*
  818: 	 * Cannot simply call in_pcbconnect, because there might be an
  819: 	 * earlier incarnation of this same connection still in
  820: 	 * TIME_WAIT state, creating an ADDRINUSE error.
  821: 	 */
  822: 	error = in_pcbladdr(inp, nam, &if_sin);
  823: 	if (error)
  824: 		return (error);
  825: 
  826: #if defined(SMP)
  827: 	port = tcp_addrport(sin->sin_addr.s_addr, sin->sin_port,
  828: 	    inp->inp_laddr.s_addr ?
  829: 		inp->inp_laddr.s_addr : if_sin->sin_addr.s_addr,
  830: 	    inp->inp_lport);
  831: 
  832: 	if (port->mp_td != curthread) {
  833: 		struct netmsg_tcp_connect *msg;
  834: 
  835: 		msg = malloc(sizeof(struct netmsg_tcp_connect), M_LWKTMSG,
  836: 		    M_NOWAIT);
  837: 		if (msg == NULL) {
  838: 			if (didbind) {	/* need to unwind bind */
  839: 				inp->inp_lport = 0;
  840: 				inp->inp_laddr.s_addr = INADDR_ANY;
  841: 				in_pcbremwildcardhash(inp);
  842: 			}
  843: 			return (ENOMEM);
  844: 		}
  845: 		lwkt_initmsg(&msg->nm_lmsg, &curthread->td_msgport, 0,
  846: 			lwkt_cmd_func(tcp_connect_handler),
  847: 			lwkt_cmd_op_none);
  848: 		msg->nm_tp = tp;
  849: 		msg->nm_sin = sin;
  850: 		msg->nm_ifsin = if_sin;
  851: 		error = lwkt_domsg(port, &msg->nm_lmsg);
  852: 	} else
  853: #endif
  854: 		error = tcp_connect_oncpu(tp, sin, if_sin);
  855: 
  856: 	return (error);
  857: }
  858: 
  859: #ifdef INET6
  860: static int
  861: tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
  862: {
  863: 	struct inpcb *inp = tp->t_inpcb, *oinp;
  864: 	struct socket *so = inp->inp_socket;
  865: 	struct tcpcb *otp;
  866: 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
  867: 	struct in6_addr *addr6;
  868: 	struct rmxp_tao *taop;
  869: 	struct rmxp_tao tao_noncached;
  870: 	int error;
  871: 
  872: 	if (inp->inp_lport == 0) {
  873: 		error = in6_pcbbind(inp, (struct sockaddr *)0, td);
  874: 		if (error)
  875: 			return error;
  876: 	}
  877: 
  878: 	/*
  879: 	 * Cannot simply call in_pcbconnect, because there might be an
  880: 	 * earlier incarnation of this same connection still in
  881: 	 * TIME_WAIT state, creating an ADDRINUSE error.
  882: 	 */
  883: 	error = in6_pcbladdr(inp, nam, &addr6);
  884: 	if (error)
  885: 		return error;
  886: 	oinp = in6_pcblookup_hash(inp->inp_cpcbinfo,
  887: 				  &sin6->sin6_addr, sin6->sin6_port,
  888: 				  IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) ?
  889: 				      addr6 : &inp->in6p_laddr,
  890: 				  inp->inp_lport,  0, NULL);
  891: 	if (oinp) {
  892: 		if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
  893: 		    otp->t_state == TCPS_TIME_WAIT &&
  894: 		    (ticks - otp->t_starttime) < tcp_msl &&
  895: 		    (otp->t_flags & TF_RCVD_CC))
  896: 			otp = tcp_close(otp);
  897: 		else
  898: 			return (EADDRINUSE);
  899: 	}
  900: 	if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
  901: 		inp->in6p_laddr = *addr6;
  902: 	inp->in6p_faddr = sin6->sin6_addr;
  903: 	inp->inp_fport = sin6->sin6_port;
  904: 	if ((sin6->sin6_flowinfo & IPV6_FLOWINFO_MASK) != NULL)
  905: 		inp->in6p_flowinfo = sin6->sin6_flowinfo;
  906: 	in_pcbinsconnhash(inp);
  907: 
  908: 	/* Compute window scaling to request.  */
  909: 	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
  910: 	    (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
  911: 		tp->request_r_scale++;
  912: 
  913: 	soisconnecting(so);
  914: 	tcpstat.tcps_connattempt++;
  915: 	tp->t_state = TCPS_SYN_SENT;
  916: 	callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp);
  917: 	tp->iss = tcp_new_isn(tp);
  918: 	tp->t_bw_rtseq = tp->iss;
  919: 	tcp_sendseqinit(tp);
  920: 
  921: 	/*
  922: 	 * Generate a CC value for this connection and
  923: 	 * check whether CC or CCnew should be used.
  924: 	 */
  925: 	if ((taop = tcp_gettaocache(&tp->t_inpcb->inp_inc)) == NULL) {
  926: 		taop = &tao_noncached;
  927: 		bzero(taop, sizeof(*taop));
  928: 	}
  929: 
  930: 	tp->cc_send = CC_INC(tcp_ccgen);
  931: 	if (taop->tao_ccsent != 0 &&
  932: 	    CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
  933: 		taop->tao_ccsent = tp->cc_send;
  934: 	} else {
  935: 		taop->tao_ccsent = 0;
  936: 		tp->t_flags |= TF_SENDCCNEW;
  937: 	}
  938: 
  939: 	return (0);
  940: }
  941: #endif /* INET6 */
  942: 
  943: /*
  944:  * The new sockopt interface makes it possible for us to block in the
  945:  * copyin/out step (if we take a page fault).  Taking a page fault at
  946:  * splnet() is probably a Bad Thing.  (Since sockets and pcbs both now
  947:  * use TSM, there probably isn't any need for this function to run at
  948:  * splnet() any more.  This needs more examination.)
  949:  */
  950: int
  951: tcp_ctloutput(so, sopt)
  952: 	struct socket *so;
  953: 	struct sockopt *sopt;
  954: {
  955: 	int	error, opt, optval, s;
  956: 	struct	inpcb *inp;
  957: 	struct	tcpcb *tp;
  958: 
  959: 	error = 0;
  960: 	s = splnet();		/* XXX */
  961: 	inp = sotoinpcb(so);
  962: 	if (inp == NULL) {
  963: 		splx(s);
  964: 		return (ECONNRESET);
  965: 	}
  966: 	if (sopt->sopt_level != IPPROTO_TCP) {
  967: #ifdef INET6
  968: 		if (INP_CHECK_SOCKAF(so, AF_INET6))
  969: 			error = ip6_ctloutput(so, sopt);
  970: 		else
  971: #endif /* INET6 */
  972: 		error = ip_ctloutput(so, sopt);
  973: 		splx(s);
  974: 		return (error);
  975: 	}
  976: 	tp = intotcpcb(inp);
  977: 
  978: 	switch (sopt->sopt_dir) {
  979: 	case SOPT_SET:
  980: 		switch (sopt->sopt_name) {
  981: 		case TCP_NODELAY:
  982: 		case TCP_NOOPT:
  983: 			error = sooptcopyin(sopt, &optval, sizeof optval,
  984: 					    sizeof optval);
  985: 			if (error)
  986: 				break;
  987: 
  988: 			switch (sopt->sopt_name) {
  989: 			case TCP_NODELAY:
  990: 				opt = TF_NODELAY;
  991: 				break;
  992: 			case TCP_NOOPT:
  993: 				opt = TF_NOOPT;
  994: 				break;
  995: 			default:
  996: 				opt = 0; /* dead code to fool gcc */
  997: 				break;
  998: 			}
  999: 
 1000: 			if (optval)
 1001: 				tp->t_flags |= opt;
 1002: 			else
 1003: 				tp->t_flags &= ~opt;
 1004: 			break;
 1005: 
 1006: 		case TCP_NOPUSH:
 1007: 			error = sooptcopyin(sopt, &optval, sizeof optval,
 1008: 					    sizeof optval);
 1009: 			if (error)
 1010: 				break;
 1011: 
 1012: 			if (optval)
 1013: 				tp->t_flags |= TF_NOPUSH;
 1014: 			else {
 1015: 				tp->t_flags &= ~TF_NOPUSH;
 1016: 				error = tcp_output(tp);
 1017: 			}
 1018: 			break;
 1019: 
 1020: 		case TCP_MAXSEG:
 1021: 			error = sooptcopyin(sopt, &optval, sizeof optval,
 1022: 					    sizeof optval);
 1023: 			if (error)
 1024: 				break;
 1025: 
 1026: 			if (optval > 0 && optval <= tp->t_maxseg)
 1027: 				tp->t_maxseg = optval;
 1028: 			else
 1029: 				error = EINVAL;
 1030: 			break;
 1031: 
 1032: 		default:
 1033: 			error = ENOPROTOOPT;
 1034: 			break;
 1035: 		}
 1036: 		break;
 1037: 
 1038: 	case SOPT_GET:
 1039: 		switch (sopt->sopt_name) {
 1040: 		case TCP_NODELAY:
 1041: 			optval = tp->t_flags & TF_NODELAY;
 1042: 			break;
 1043: 		case TCP_MAXSEG:
 1044: 			optval = tp->t_maxseg;
 1045: 			break;
 1046: 		case TCP_NOOPT:
 1047: 			optval = tp->t_flags & TF_NOOPT;
 1048: 			break;
 1049: 		case TCP_NOPUSH:
 1050: 			optval = tp->t_flags & TF_NOPUSH;
 1051: 			break;
 1052: 		default:
 1053: 			error = ENOPROTOOPT;
 1054: 			break;
 1055: 		}
 1056: 		if (error == 0)
 1057: 			error = sooptcopyout(sopt, &optval, sizeof optval);
 1058: 		break;
 1059: 	}
 1060: 	splx(s);
 1061: 	return (error);
 1062: }
 1063: 
 1064: /*
 1065:  * tcp_sendspace and tcp_recvspace are the default send and receive window
 1066:  * sizes, respectively.  These are obsolescent (this information should
 1067:  * be set by the route).
 1068:  */
 1069: u_long	tcp_sendspace = 1024*32;
 1070: SYSCTL_INT(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace, CTLFLAG_RW, 
 1071:     &tcp_sendspace , 0, "Maximum outgoing TCP datagram size");
 1072: u_long	tcp_recvspace = 57344;	/* largest multiple of PAGE_SIZE < 64k */
 1073: SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace, CTLFLAG_RW, 
 1074:     &tcp_recvspace , 0, "Maximum incoming TCP datagram size");
 1075: 
 1076: /*
 1077:  * Attach TCP protocol to socket, allocating
 1078:  * internet protocol control block, tcp control block,
 1079:  * bufer space, and entering LISTEN state if to accept connections.
 1080:  */
 1081: static int
 1082: tcp_attach(struct socket *so, struct pru_attach_info *ai)
 1083: {
 1084: 	struct tcpcb *tp;
 1085: 	struct inpcb *inp;
 1086: 	int error;
 1087: 	int cpu;
 1088: #ifdef INET6
 1089: 	int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6) != NULL;
 1090: #endif
 1091: 
 1092: 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
 1093: 		error = soreserve(so, tcp_sendspace, tcp_recvspace,
 1094: 				  ai->sb_rlimit);
 1095: 		if (error)
 1096: 			return (error);
 1097: 	}
 1098: 	cpu = mycpu->gd_cpuid;
 1099: 	error = in_pcballoc(so, &tcbinfo[cpu]);
 1100: 	if (error)
 1101: 		return (error);
 1102: 	inp = sotoinpcb(so);
 1103: #ifdef INET6
 1104: 	if (isipv6) {
 1105: 		inp->inp_vflag |= INP_IPV6;
 1106: 		inp->in6p_hops = -1;	/* use kernel default */
 1107: 	}
 1108: 	else
 1109: #endif
 1110: 	inp->inp_vflag |= INP_IPV4;
 1111: 	tp = tcp_newtcpcb(inp);
 1112: 	if (tp == 0) {
 1113: 		int nofd = so->so_state & SS_NOFDREF;	/* XXX */
 1114: 
 1115: 		so->so_state &= ~SS_NOFDREF;	/* don't free the socket yet */
 1116: #ifdef INET6
 1117: 		if (isipv6)
 1118: 			in6_pcbdetach(inp);
 1119: 		else
 1120: #endif
 1121: 		in_pcbdetach(inp);
 1122: 		so->so_state |= nofd;
 1123: 		return (ENOBUFS);
 1124: 	}
 1125: 	tp->t_state = TCPS_CLOSED;
 1126: 	return (0);
 1127: }
 1128: 
 1129: /*
 1130:  * Initiate (or continue) disconnect.
 1131:  * If embryonic state, just send reset (once).
 1132:  * If in ``let data drain'' option and linger null, just drop.
 1133:  * Otherwise (hard), mark socket disconnecting and drop
 1134:  * current input data; switch states based on user close, and
 1135:  * send segment to peer (with FIN).
 1136:  */
 1137: static struct tcpcb *
 1138: tcp_disconnect(tp)
 1139: 	struct tcpcb *tp;
 1140: {
 1141: 	struct socket *so = tp->t_inpcb->inp_socket;
 1142: 
 1143: 	if (tp->t_state < TCPS_ESTABLISHED)
 1144: 		tp = tcp_close(tp);
 1145: 	else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
 1146: 		tp = tcp_drop(tp, 0);
 1147: 	else {
 1148: 		soisdisconnecting(so);
 1149: 		sbflush(&so->so_rcv);
 1150: 		tp = tcp_usrclosed(tp);
 1151: 		if (tp)
 1152: 			(void) tcp_output(tp);
 1153: 	}
 1154: 	return (tp);
 1155: }
 1156: 
 1157: /*
 1158:  * User issued close, and wish to trail through shutdown states:
 1159:  * if never received SYN, just forget it.  If got a SYN from peer,
 1160:  * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
 1161:  * If already got a FIN from peer, then almost done; go to LAST_ACK
 1162:  * state.  In all other cases, have already sent FIN to peer (e.g.
 1163:  * after PRU_SHUTDOWN), and just have to play tedious game waiting
 1164:  * for peer to send FIN or not respond to keep-alives, etc.
 1165:  * We can let the user exit from the close as soon as the FIN is acked.
 1166:  */
 1167: static struct tcpcb *
 1168: tcp_usrclosed(tp)
 1169: 	struct tcpcb *tp;
 1170: {
 1171: 
 1172: 	switch (tp->t_state) {
 1173: 
 1174: 	case TCPS_CLOSED:
 1175: 	case TCPS_LISTEN:
 1176: 		tp->t_state = TCPS_CLOSED;
 1177: 		tp = tcp_close(tp);
 1178: 		break;
 1179: 
 1180: 	case TCPS_SYN_SENT:
 1181: 	case TCPS_SYN_RECEIVED:
 1182: 		tp->t_flags |= TF_NEEDFIN;
 1183: 		break;
 1184: 
 1185: 	case TCPS_ESTABLISHED:
 1186: 		tp->t_state = TCPS_FIN_WAIT_1;
 1187: 		break;
 1188: 
 1189: 	case TCPS_CLOSE_WAIT:
 1190: 		tp->t_state = TCPS_LAST_ACK;
 1191: 		break;
 1192: 	}
 1193: 	if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
 1194: 		soisdisconnected(tp->t_inpcb->inp_socket);
 1195: 		/* To prevent the connection hanging in FIN_WAIT_2 forever. */
 1196: 		if (tp->t_state == TCPS_FIN_WAIT_2)
 1197: 			callout_reset(tp->tt_2msl, tcp_maxidle,
 1198: 				      tcp_timer_2msl, tp);
 1199: 	}
 1200: 	return (tp);
 1201: }
 1202: