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