tcp_usrreq.c revision 186141
133965Sjdp/*-
278828Sobrien * Copyright (c) 1982, 1986, 1988, 1993
3218822Sdim *	The Regents of the University of California.
438889Sjdp * Copyright (c) 2006-2007 Robert N. M. Watson
533965Sjdp * All rights reserved.
633965Sjdp *
733965Sjdp * Redistribution and use in source and binary forms, with or without
833965Sjdp * modification, are permitted provided that the following conditions
933965Sjdp * are met:
1033965Sjdp * 1. Redistributions of source code must retain the above copyright
1133965Sjdp *    notice, this list of conditions and the following disclaimer.
1233965Sjdp * 2. Redistributions in binary form must reproduce the above copyright
1333965Sjdp *    notice, this list of conditions and the following disclaimer in the
1433965Sjdp *    documentation and/or other materials provided with the distribution.
1533965Sjdp * 4. Neither the name of the University nor the names of its contributors
1633965Sjdp *    may be used to endorse or promote products derived from this software
1733965Sjdp *    without specific prior written permission.
1833965Sjdp *
1933965Sjdp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20218822Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21218822Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2233965Sjdp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23218822Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2433965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2533965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2633965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2733965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28218822Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2933965Sjdp * SUCH DAMAGE.
3061843Sobrien *
31130561Sobrien *	From: @(#)tcp_usrreq.c	8.2 (Berkeley) 1/3/94
32130561Sobrien */
3333965Sjdp
34218822Sdim#include <sys/cdefs.h>
3533965Sjdp__FBSDID("$FreeBSD: head/sys/netinet/tcp_usrreq.c 186141 2008-12-15 21:50:54Z bz $");
3638889Sjdp
3738889Sjdp#include "opt_ddb.h"
3838889Sjdp#include "opt_inet.h"
39104834Sobrien#include "opt_inet6.h"
4038889Sjdp#include "opt_tcpdebug.h"
4138889Sjdp
4238889Sjdp#include <sys/param.h>
4338889Sjdp#include <sys/systm.h>
4438889Sjdp#include <sys/malloc.h>
4538889Sjdp#include <sys/kernel.h>
4638889Sjdp#include <sys/sysctl.h>
4760484Sobrien#include <sys/mbuf.h>
4860484Sobrien#ifdef INET6
4960484Sobrien#include <sys/domain.h>
5060484Sobrien#endif /* INET6 */
5160484Sobrien#include <sys/socket.h>
5260484Sobrien#include <sys/socketvar.h>
5360484Sobrien#include <sys/protosw.h>
5460484Sobrien#include <sys/proc.h>
5589857Sobrien#include <sys/jail.h>
5689857Sobrien#include <sys/vimage.h>
5789857Sobrien
5889857Sobrien#ifdef DDB
5989857Sobrien#include <ddb/ddb.h>
6089857Sobrien#endif
6189857Sobrien
6289857Sobrien#include <net/if.h>
6389857Sobrien#include <net/route.h>
6489857Sobrien
65130561Sobrien#include <netinet/in.h>
6689857Sobrien#include <netinet/in_systm.h>
6760484Sobrien#ifdef INET6
6833965Sjdp#include <netinet/ip6.h>
69130561Sobrien#endif
70130561Sobrien#include <netinet/in_pcb.h>
7133965Sjdp#ifdef INET6
7233965Sjdp#include <netinet6/in6_pcb.h>
7333965Sjdp#endif
7433965Sjdp#include <netinet/in_var.h>
7533965Sjdp#include <netinet/ip_var.h>
76130561Sobrien#ifdef INET6
77130561Sobrien#include <netinet6/ip6_var.h>
7833965Sjdp#include <netinet6/scope6_var.h>
7933965Sjdp#endif
8033965Sjdp#include <netinet/tcp.h>
8133965Sjdp#include <netinet/tcp_fsm.h>
8260484Sobrien#include <netinet/tcp_seq.h>
83130561Sobrien#include <netinet/tcp_timer.h>
84130561Sobrien#include <netinet/tcp_var.h>
85130561Sobrien#include <netinet/tcpip.h>
86130561Sobrien#ifdef TCPDEBUG
87130561Sobrien#include <netinet/tcp_debug.h>
8833965Sjdp#endif
8933965Sjdp#include <netinet/tcp_offload.h>
90104834Sobrien#include <netinet/vinet.h>
9133965Sjdp
9233965Sjdp/*
9333965Sjdp * TCP protocol interface to socket abstraction.
9433965Sjdp */
9560484Sobrienstatic int	tcp_attach(struct socket *);
96130561Sobrienstatic int	tcp_connect(struct tcpcb *, struct sockaddr *,
97130561Sobrien		    struct thread *td);
9833965Sjdp#ifdef INET6
9933965Sjdpstatic int	tcp6_connect(struct tcpcb *, struct sockaddr *,
10060484Sobrien		    struct thread *td);
10133965Sjdp#endif /* INET6 */
10233965Sjdpstatic void	tcp_disconnect(struct tcpcb *);
10360484Sobrienstatic void	tcp_usrclosed(struct tcpcb *);
10460484Sobrienstatic void	tcp_fill_info(struct tcpcb *, struct tcp_info *);
10560484Sobrien
10660484Sobrien#ifdef TCPDEBUG
10760484Sobrien#define	TCPDEBUG0	int ostate = 0
10860484Sobrien#define	TCPDEBUG1()	ostate = tp ? tp->t_state : 0
10960484Sobrien#define	TCPDEBUG2(req)	if (tp && (so->so_options & SO_DEBUG)) \
11060484Sobrien				tcp_trace(TA_USER, ostate, tp, 0, 0, req)
11133965Sjdp#else
11233965Sjdp#define	TCPDEBUG0
11333965Sjdp#define	TCPDEBUG1()
114130561Sobrien#define	TCPDEBUG2(req)
115130561Sobrien#endif
116130561Sobrien
117130561Sobrien/*
118130561Sobrien * TCP attaches to socket via pru_attach(), reserving space,
119130561Sobrien * and an internet control block.
120130561Sobrien */
121130561Sobrienstatic int
122130561Sobrientcp_usr_attach(struct socket *so, int proto, struct thread *td)
123130561Sobrien{
124130561Sobrien	struct inpcb *inp;
12533965Sjdp	struct tcpcb *tp = NULL;
12633965Sjdp	int error;
12760484Sobrien	TCPDEBUG0;
12889857Sobrien
129130561Sobrien	inp = sotoinpcb(so);
130130561Sobrien	KASSERT(inp == NULL, ("tcp_usr_attach: inp != NULL"));
13189857Sobrien	TCPDEBUG1();
132130561Sobrien
133130561Sobrien	error = tcp_attach(so);
13433965Sjdp	if (error)
13560484Sobrien		goto out;
13660484Sobrien
137130561Sobrien	if ((so->so_options & SO_LINGER) && so->so_linger == 0)
13833965Sjdp		so->so_linger = TCP_LINGERTIME;
13933965Sjdp
14060484Sobrien	inp = sotoinpcb(so);
14160484Sobrien	tp = intotcpcb(inp);
14233965Sjdpout:
14333965Sjdp	TCPDEBUG2(PRU_ATTACH);
144130561Sobrien	return error;
14533965Sjdp}
14633965Sjdp
14733965Sjdp/*
148130561Sobrien * tcp_detach is called when the socket layer loses its final reference
14933965Sjdp * to the socket, be it a file descriptor reference, a reference from TCP,
15033965Sjdp * etc.  At this point, there is only one case in which we will keep around
151218822Sdim * inpcb state: time wait.
152218822Sdim *
15389857Sobrien * This function can probably be re-absorbed back into tcp_usr_detach() now
154130561Sobrien * that there is a single detach path.
155130561Sobrien */
156130561Sobrienstatic void
157130561Sobrientcp_detach(struct socket *so, struct inpcb *inp)
15833965Sjdp{
15933965Sjdp	struct tcpcb *tp;
16033965Sjdp#ifdef INVARIANTS
16133965Sjdp	INIT_VNET_INET(so->so_vnet);
16233965Sjdp#endif
16333965Sjdp
16433965Sjdp	INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
16533965Sjdp	INP_WLOCK_ASSERT(inp);
16633965Sjdp
16733965Sjdp	KASSERT(so->so_pcb == inp, ("tcp_detach: so_pcb != inp"));
16833965Sjdp	KASSERT(inp->inp_socket == so, ("tcp_detach: inp_socket != so"));
16933965Sjdp
17033965Sjdp	tp = intotcpcb(inp);
17133965Sjdp
17233965Sjdp	if (inp->inp_vflag & INP_TIMEWAIT) {
17333965Sjdp		/*
17433965Sjdp		 * There are two cases to handle: one in which the time wait
17589857Sobrien		 * state is being discarded (INP_DROPPED), and one in which
17633965Sjdp		 * this connection will remain in timewait.  In the former,
17733965Sjdp		 * it is time to discard all state (except tcptw, which has
178130561Sobrien		 * already been discarded by the timewait close code, which
179130561Sobrien		 * should be further up the call stack somewhere).  In the
180130561Sobrien		 * latter case, we detach from the socket, but leave the pcb
181130561Sobrien		 * present until timewait ends.
18233965Sjdp		 *
183130561Sobrien		 * XXXRW: Would it be cleaner to free the tcptw here?
18433965Sjdp		 */
18533965Sjdp		if (inp->inp_vflag & INP_DROPPED) {
186130561Sobrien			KASSERT(tp == NULL, ("tcp_detach: INP_TIMEWAIT && "
18733965Sjdp			    "INP_DROPPED && tp != NULL"));
18833965Sjdp			in_pcbdetach(inp);
189130561Sobrien			in_pcbfree(inp);
19033965Sjdp		} else {
191130561Sobrien			in_pcbdetach(inp);
192130561Sobrien			INP_WUNLOCK(inp);
193130561Sobrien		}
194218822Sdim	} else {
195218822Sdim		/*
196218822Sdim		 * If the connection is not in timewait, we consider two
19778828Sobrien		 * two conditions: one in which no further processing is
19878828Sobrien		 * necessary (dropped || embryonic), and one in which TCP is
19938889Sjdp		 * not yet done, but no longer requires the socket, so the
200218822Sdim		 * pcb will persist for the time being.
20138889Sjdp		 *
20238889Sjdp		 * XXXRW: Does the second case still occur?
203218822Sdim		 */
20478828Sobrien		if (inp->inp_vflag & INP_DROPPED ||
20538889Sjdp		    tp->t_state < TCPS_SYN_SENT) {
20660484Sobrien			tcp_discardcb(tp);
20738889Sjdp			in_pcbdetach(inp);
208130561Sobrien			in_pcbfree(inp);
209130561Sobrien		} else
21038889Sjdp			in_pcbdetach(inp);
211218822Sdim	}
212218822Sdim}
213218822Sdim
214130561Sobrien/*
215130561Sobrien * pru_detach() detaches the TCP protocol from the socket.
216130561Sobrien * If the protocol state is non-embryonic, then can't
217130561Sobrien * do this directly: have to initiate a pru_disconnect(),
218130561Sobrien * which may finish later; embryonic TCB's can just
219218822Sdim * be discarded here.
220218822Sdim */
221218822Sdimstatic void
222218822Sdimtcp_usr_detach(struct socket *so)
223218822Sdim{
224218822Sdim	INIT_VNET_INET(so->so_vnet);
225218822Sdim	struct inpcb *inp;
226218822Sdim
22733965Sjdp	inp = sotoinpcb(so);
228130561Sobrien	KASSERT(inp != NULL, ("tcp_usr_detach: inp == NULL"));
229130561Sobrien	INP_INFO_WLOCK(&V_tcbinfo);
230130561Sobrien	INP_WLOCK(inp);
231130561Sobrien	KASSERT(inp->inp_socket != NULL,
232130561Sobrien	    ("tcp_usr_detach: inp_socket == NULL"));
233130561Sobrien	tcp_detach(so, inp);
234130561Sobrien	INP_INFO_WUNLOCK(&V_tcbinfo);
235130561Sobrien}
236130561Sobrien
237130561Sobrien/*
238130561Sobrien * Give the socket an address.
239130561Sobrien */
240130561Sobrienstatic int
241130561Sobrientcp_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
242130561Sobrien{
243130561Sobrien	INIT_VNET_INET(so->so_vnet);
244130561Sobrien	int error = 0;
245130561Sobrien	struct inpcb *inp;
246130561Sobrien	struct tcpcb *tp = NULL;
247130561Sobrien	struct sockaddr_in *sinp;
248130561Sobrien
249130561Sobrien	sinp = (struct sockaddr_in *)nam;
250130561Sobrien	if (nam->sa_len != sizeof (*sinp))
251130561Sobrien		return (EINVAL);
252218822Sdim	/*
253218822Sdim	 * Must check for multicast addresses and disallow binding
254130561Sobrien	 * to them.
255218822Sdim	 */
256130561Sobrien	if (sinp->sin_family == AF_INET &&
257218822Sdim	    IN_MULTICAST(ntohl(sinp->sin_addr.s_addr)))
258218822Sdim		return (EAFNOSUPPORT);
259130561Sobrien
260130561Sobrien	TCPDEBUG0;
261130561Sobrien	INP_INFO_WLOCK(&V_tcbinfo);
262130561Sobrien	inp = sotoinpcb(so);
263130561Sobrien	KASSERT(inp != NULL, ("tcp_usr_bind: inp == NULL"));
264130561Sobrien	INP_WLOCK(inp);
265130561Sobrien	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
266130561Sobrien		error = EINVAL;
267130561Sobrien		goto out;
268130561Sobrien	}
269218822Sdim	tp = intotcpcb(inp);
270130561Sobrien	TCPDEBUG1();
271130561Sobrien	error = in_pcbbind(inp, nam, td->td_ucred);
272130561Sobrienout:
273218822Sdim	TCPDEBUG2(PRU_BIND);
274218822Sdim	INP_WUNLOCK(inp);
275218822Sdim	INP_INFO_WUNLOCK(&V_tcbinfo);
276130561Sobrien
27733965Sjdp	return (error);
27833965Sjdp}
27933965Sjdp
28033965Sjdp#ifdef INET6
28133965Sjdpstatic int
28233965Sjdptcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
28333965Sjdp{
28433965Sjdp	INIT_VNET_INET(so->so_vnet);
28533965Sjdp	int error = 0;
286130561Sobrien	struct inpcb *inp;
28733965Sjdp	struct tcpcb *tp = NULL;
28833965Sjdp	struct sockaddr_in6 *sin6p;
289218822Sdim
29033965Sjdp	sin6p = (struct sockaddr_in6 *)nam;
291130561Sobrien	if (nam->sa_len != sizeof (*sin6p))
29233965Sjdp		return (EINVAL);
29333965Sjdp	/*
29480016Sobrien	 * Must check for multicast addresses and disallow binding
29533965Sjdp	 * to them.
29633965Sjdp	 */
29733965Sjdp	if (sin6p->sin6_family == AF_INET6 &&
29833965Sjdp	    IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
29933965Sjdp		return (EAFNOSUPPORT);
30033965Sjdp
30133965Sjdp	TCPDEBUG0;
30233965Sjdp	INP_INFO_WLOCK(&V_tcbinfo);
30333965Sjdp	inp = sotoinpcb(so);
304130561Sobrien	KASSERT(inp != NULL, ("tcp6_usr_bind: inp == NULL"));
30533965Sjdp	INP_WLOCK(inp);
30633965Sjdp	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
30733965Sjdp		error = EINVAL;
30833965Sjdp		goto out;
30933965Sjdp	}
31033965Sjdp	tp = intotcpcb(inp);
31133965Sjdp	TCPDEBUG1();
312130561Sobrien	inp->inp_vflag &= ~INP_IPV4;
31333965Sjdp	inp->inp_vflag |= INP_IPV6;
31460484Sobrien	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
31560484Sobrien		if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr))
31660484Sobrien			inp->inp_vflag |= INP_IPV4;
31760484Sobrien		else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
318130561Sobrien			struct sockaddr_in sin;
31989857Sobrien
32033965Sjdp			in6_sin6_2_sin(&sin, sin6p);
32160484Sobrien			inp->inp_vflag |= INP_IPV4;
32233965Sjdp			inp->inp_vflag &= ~INP_IPV6;
32360484Sobrien			error = in_pcbbind(inp, (struct sockaddr *)&sin,
32460484Sobrien			    td->td_ucred);
32560484Sobrien			goto out;
32660484Sobrien		}
32760484Sobrien	}
32833965Sjdp	error = in6_pcbbind(inp, nam, td->td_ucred);
32933965Sjdpout:
33033965Sjdp	TCPDEBUG2(PRU_BIND);
331218822Sdim	INP_WUNLOCK(inp);
33233965Sjdp	INP_INFO_WUNLOCK(&V_tcbinfo);
33333965Sjdp	return (error);
334218822Sdim}
335218822Sdim#endif /* INET6 */
33633965Sjdp
337130561Sobrien/*
338130561Sobrien * Prepare to accept connections.
33933965Sjdp */
34033965Sjdpstatic int
34133965Sjdptcp_usr_listen(struct socket *so, int backlog, struct thread *td)
342218822Sdim{
343130561Sobrien	INIT_VNET_INET(so->so_vnet);
344130561Sobrien	int error = 0;
34533965Sjdp	struct inpcb *inp;
346130561Sobrien	struct tcpcb *tp = NULL;
347218822Sdim
348130561Sobrien	TCPDEBUG0;
349130561Sobrien	INP_INFO_WLOCK(&V_tcbinfo);
35060484Sobrien	inp = sotoinpcb(so);
35160484Sobrien	KASSERT(inp != NULL, ("tcp_usr_listen: inp == NULL"));
352130561Sobrien	INP_WLOCK(inp);
353130561Sobrien	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
35433965Sjdp		error = EINVAL;
35533965Sjdp		goto out;
35633965Sjdp	}
357130561Sobrien	tp = intotcpcb(inp);
358130561Sobrien	TCPDEBUG1();
359130561Sobrien	SOCK_LOCK(so);
36033965Sjdp	error = solisten_proto_check(so);
361130561Sobrien	if (error == 0 && inp->inp_lport == 0)
362130561Sobrien		error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
363130561Sobrien	if (error == 0) {
364130561Sobrien		tp->t_state = TCPS_LISTEN;
36533965Sjdp		solisten_proto(so, backlog);
36633965Sjdp		tcp_offload_listen_open(tp);
36789857Sobrien	}
368218822Sdim	SOCK_UNLOCK(so);
36933965Sjdp
37033965Sjdpout:
371130561Sobrien	TCPDEBUG2(PRU_LISTEN);
372130561Sobrien	INP_WUNLOCK(inp);
37333965Sjdp	INP_INFO_WUNLOCK(&V_tcbinfo);
37433965Sjdp	return (error);
37533965Sjdp}
376218822Sdim
377218822Sdim#ifdef INET6
37833965Sjdpstatic int
379130561Sobrientcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
38033965Sjdp{
38133965Sjdp	INIT_VNET_INET(so->so_vnet);
38233965Sjdp	int error = 0;
38333965Sjdp	struct inpcb *inp;
38438889Sjdp	struct tcpcb *tp = NULL;
38578828Sobrien
386130561Sobrien	TCPDEBUG0;
387130561Sobrien	INP_INFO_WLOCK(&V_tcbinfo);
38833965Sjdp	inp = sotoinpcb(so);
38933965Sjdp	KASSERT(inp != NULL, ("tcp6_usr_listen: inp == NULL"));
39033965Sjdp	INP_WLOCK(inp);
39133965Sjdp	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
39233965Sjdp		error = EINVAL;
39333965Sjdp		goto out;
39433965Sjdp	}
39533965Sjdp	tp = intotcpcb(inp);
396104834Sobrien	TCPDEBUG1();
39733965Sjdp	SOCK_LOCK(so);
39833965Sjdp	error = solisten_proto_check(so);
39977298Sobrien	if (error == 0 && inp->inp_lport == 0) {
40077298Sobrien		inp->inp_vflag &= ~INP_IPV4;
40177298Sobrien		if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
40233965Sjdp			inp->inp_vflag |= INP_IPV4;
40377298Sobrien		error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
40477298Sobrien	}
40577298Sobrien	if (error == 0) {
406130561Sobrien		tp->t_state = TCPS_LISTEN;
40777298Sobrien		solisten_proto(so, backlog);
408130561Sobrien	}
409130561Sobrien	SOCK_UNLOCK(so);
410130561Sobrien
411130561Sobrienout:
41289857Sobrien	TCPDEBUG2(PRU_LISTEN);
413130561Sobrien	INP_WUNLOCK(inp);
414130561Sobrien	INP_INFO_WUNLOCK(&V_tcbinfo);
415218822Sdim	return (error);
416130561Sobrien}
417130561Sobrien#endif /* INET6 */
418130561Sobrien
419130561Sobrien/*
420130561Sobrien * Initiate connection to peer.
421130561Sobrien * Create a template for use in transmissions on this connection.
42289857Sobrien * Enter SYN_SENT state, and mark socket as connecting.
42333965Sjdp * Start keep-alive timer, and seed output sequence space.
424130561Sobrien * Send initial segment on connection.
42533965Sjdp */
42689857Sobrienstatic int
42789857Sobrientcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
42889857Sobrien{
42960484Sobrien	INIT_VNET_INET(so->so_vnet);
43060484Sobrien	int error = 0;
43160484Sobrien	struct inpcb *inp;
43289857Sobrien	struct tcpcb *tp = NULL;
43360484Sobrien	struct sockaddr_in *sinp;
43460484Sobrien
43560484Sobrien	sinp = (struct sockaddr_in *)nam;
43660484Sobrien	if (nam->sa_len != sizeof (*sinp))
437130561Sobrien		return (EINVAL);
43860484Sobrien	/*
43960484Sobrien	 * Must disallow TCP ``connections'' to multicast addresses.
440130561Sobrien	 */
44160484Sobrien	if (sinp->sin_family == AF_INET
44260484Sobrien	    && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr)))
443218822Sdim		return (EAFNOSUPPORT);
444218822Sdim	if (prison_remote_ip4(td->td_ucred, &sinp->sin_addr) != 0)
445218822Sdim		return (EINVAL);
446130561Sobrien
447218822Sdim	TCPDEBUG0;
448218822Sdim	INP_INFO_WLOCK(&V_tcbinfo);
449218822Sdim	inp = sotoinpcb(so);
450218822Sdim	KASSERT(inp != NULL, ("tcp_usr_connect: inp == NULL"));
45160484Sobrien	INP_WLOCK(inp);
452218822Sdim	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
45378828Sobrien		error = EINVAL;
45460484Sobrien		goto out;
45560484Sobrien	}
456218822Sdim	tp = intotcpcb(inp);
45760484Sobrien	TCPDEBUG1();
45860484Sobrien	if ((error = tcp_connect(tp, nam, td)) != 0)
45960484Sobrien		goto out;
46060484Sobrien	error = tcp_output_connect(so, nam);
46160484Sobrienout:
46260484Sobrien	TCPDEBUG2(PRU_CONNECT);
46360484Sobrien	INP_WUNLOCK(inp);
46460484Sobrien	INP_INFO_WUNLOCK(&V_tcbinfo);
46560484Sobrien	return (error);
46660484Sobrien}
46760484Sobrien
46860484Sobrien#ifdef INET6
46960484Sobrienstatic int
47060484Sobrientcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
47160484Sobrien{
47260484Sobrien	INIT_VNET_INET(so->so_vnet);
47360484Sobrien	int error = 0;
47460484Sobrien	struct inpcb *inp;
47560484Sobrien	struct tcpcb *tp = NULL;
47660484Sobrien	struct sockaddr_in6 *sin6p;
47760484Sobrien
47860484Sobrien	TCPDEBUG0;
47989857Sobrien
48060484Sobrien	sin6p = (struct sockaddr_in6 *)nam;
48160484Sobrien	if (nam->sa_len != sizeof (*sin6p))
482218822Sdim		return (EINVAL);
48360484Sobrien	/*
484130561Sobrien	 * Must disallow TCP ``connections'' to multicast addresses.
485130561Sobrien	 */
48677298Sobrien	if (sin6p->sin6_family == AF_INET6
48777298Sobrien	    && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
48878828Sobrien		return (EAFNOSUPPORT);
489218822Sdim
490218822Sdim	INP_INFO_WLOCK(&V_tcbinfo);
491218822Sdim	inp = sotoinpcb(so);
49278828Sobrien	KASSERT(inp != NULL, ("tcp6_usr_connect: inp == NULL"));
49378828Sobrien	INP_WLOCK(inp);
494218822Sdim	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
49578828Sobrien		error = EINVAL;
49678828Sobrien		goto out;
497218822Sdim	}
498130561Sobrien	tp = intotcpcb(inp);
499130561Sobrien	TCPDEBUG1();
500130561Sobrien	if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
501130561Sobrien		struct sockaddr_in sin;
502130561Sobrien
503130561Sobrien		if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) {
504130561Sobrien			error = EINVAL;
505130561Sobrien			goto out;
506130561Sobrien		}
50760484Sobrien
508218822Sdim		in6_sin6_2_sin(&sin, sin6p);
50960484Sobrien		inp->inp_vflag |= INP_IPV4;
51060484Sobrien		inp->inp_vflag &= ~INP_IPV6;
511130561Sobrien		if (prison_remote_ip4(td->td_ucred, &sin.sin_addr) != 0) {
51260484Sobrien			error = EINVAL;
51333965Sjdp			goto out;
514218822Sdim		}
51560484Sobrien		if ((error = tcp_connect(tp, (struct sockaddr *)&sin, td)) != 0)
51633965Sjdp			goto out;
51733965Sjdp		error = tcp_output_connect(so, nam);
51833965Sjdp		goto out;
51933965Sjdp	}
520130561Sobrien	inp->inp_vflag &= ~INP_IPV4;
52133965Sjdp	inp->inp_vflag |= INP_IPV6;
52289857Sobrien	inp->inp_inc.inc_isipv6 = 1;
52389857Sobrien	if (prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr) != 0) {
52489857Sobrien		error = EINVAL;
52560484Sobrien		goto out;
52689857Sobrien	}
52789857Sobrien	if ((error = tcp6_connect(tp, nam, td)) != 0)
52889857Sobrien		goto out;
52960484Sobrien	error = tcp_output_connect(so, nam);
53089857Sobrien
53160484Sobrienout:
532130561Sobrien	TCPDEBUG2(PRU_CONNECT);
53360484Sobrien	INP_WUNLOCK(inp);
534130561Sobrien	INP_INFO_WUNLOCK(&V_tcbinfo);
53589857Sobrien	return (error);
536218822Sdim}
537218822Sdim#endif /* INET6 */
538218822Sdim
53960484Sobrien/*
54060484Sobrien * Initiate disconnect from peer.
54160484Sobrien * If connection never passed embryonic stage, just drop;
54260484Sobrien * else if don't need to let data drain, then can just drop anyways,
54360484Sobrien * else have to begin TCP shutdown process: mark socket disconnecting,
544130561Sobrien * drain unread data, state switch to reflect user close, and
54560484Sobrien * send segment (e.g. FIN) to peer.  Socket will be really disconnected
54660484Sobrien * when peer sends FIN and acks ours.
54760484Sobrien *
54833965Sjdp * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
549218822Sdim */
55060484Sobrienstatic int
55133965Sjdptcp_usr_disconnect(struct socket *so)
55233965Sjdp{
55333965Sjdp	INIT_VNET_INET(so->so_vnet);
55433965Sjdp	struct inpcb *inp;
55533965Sjdp	struct tcpcb *tp = NULL;
55633965Sjdp	int error = 0;
55733965Sjdp
558130561Sobrien	TCPDEBUG0;
55933965Sjdp	INP_INFO_WLOCK(&V_tcbinfo);
56033965Sjdp	inp = sotoinpcb(so);
56133965Sjdp	KASSERT(inp != NULL, ("tcp_usr_disconnect: inp == NULL"));
56233965Sjdp	INP_WLOCK(inp);
56333965Sjdp	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
56433965Sjdp		error = ECONNRESET;
56533965Sjdp		goto out;
56633965Sjdp	}
56733965Sjdp	tp = intotcpcb(inp);
56833965Sjdp	TCPDEBUG1();
56933965Sjdp	tcp_disconnect(tp);
57033965Sjdpout:
57133965Sjdp	TCPDEBUG2(PRU_DISCONNECT);
57233965Sjdp	INP_WUNLOCK(inp);
57333965Sjdp	INP_INFO_WUNLOCK(&V_tcbinfo);
57433965Sjdp	return (error);
57533965Sjdp}
57633965Sjdp
57738889Sjdp/*
57838889Sjdp * Accept a connection.  Essentially all the work is
57938889Sjdp * done at higher levels; just return the address
58033965Sjdp * of the peer, storing through addr.
58133965Sjdp */
58260484Sobrienstatic int
58333965Sjdptcp_usr_accept(struct socket *so, struct sockaddr **nam)
58460484Sobrien{
58533965Sjdp	INIT_VNET_INET(so->so_vnet);
58633965Sjdp	int error = 0;
58733965Sjdp	struct inpcb *inp = NULL;
588218822Sdim	struct tcpcb *tp = NULL;
58938889Sjdp	struct in_addr addr;
59033965Sjdp	in_port_t port = 0;
59138889Sjdp	TCPDEBUG0;
59238889Sjdp
59338889Sjdp	if (so->so_state & SS_ISDISCONNECTED)
59433965Sjdp		return (ECONNABORTED);
59538889Sjdp
59638889Sjdp	inp = sotoinpcb(so);
59738889Sjdp	KASSERT(inp != NULL, ("tcp_usr_accept: inp == NULL"));
59860484Sobrien	INP_INFO_RLOCK(&V_tcbinfo);
59960484Sobrien	INP_WLOCK(inp);
60060484Sobrien	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
60138889Sjdp		error = ECONNABORTED;
60238889Sjdp		goto out;
60333965Sjdp	}
60433965Sjdp	tp = intotcpcb(inp);
60533965Sjdp	TCPDEBUG1();
60633965Sjdp
60733965Sjdp	/*
60833965Sjdp	 * We inline in_getpeeraddr and COMMON_END here, so that we can
60933965Sjdp	 * copy the data of interest and defer the malloc until after we
61060484Sobrien	 * release the lock.
61133965Sjdp	 */
61233965Sjdp	port = inp->inp_fport;
613130561Sobrien	addr = inp->inp_faddr;
61433965Sjdp
615130561Sobrienout:
61633965Sjdp	TCPDEBUG2(PRU_ACCEPT);
61760484Sobrien	INP_WUNLOCK(inp);
61833965Sjdp	INP_INFO_RUNLOCK(&V_tcbinfo);
61933965Sjdp	if (error == 0)
62033965Sjdp		*nam = in_sockaddr(port, &addr);
62133965Sjdp	return error;
62233965Sjdp}
62333965Sjdp
624130561Sobrien#ifdef INET6
62533965Sjdpstatic int
626130561Sobrientcp6_usr_accept(struct socket *so, struct sockaddr **nam)
627130561Sobrien{
628130561Sobrien	struct inpcb *inp = NULL;
62960484Sobrien	int error = 0;
63060484Sobrien	struct tcpcb *tp = NULL;
63160484Sobrien	struct in_addr addr;
63260484Sobrien	struct in6_addr addr6;
633130561Sobrien	in_port_t port = 0;
63433965Sjdp	int v4 = 0;
63533965Sjdp	TCPDEBUG0;
63660484Sobrien
63760484Sobrien	if (so->so_state & SS_ISDISCONNECTED)
63833965Sjdp		return (ECONNABORTED);
63933965Sjdp
64033965Sjdp	inp = sotoinpcb(so);
64133965Sjdp	KASSERT(inp != NULL, ("tcp6_usr_accept: inp == NULL"));
64233965Sjdp	INP_WLOCK(inp);
64333965Sjdp	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
64460484Sobrien		error = ECONNABORTED;
645130561Sobrien		goto out;
64633965Sjdp	}
64733965Sjdp	tp = intotcpcb(inp);
64833965Sjdp	TCPDEBUG1();
649130561Sobrien
65033965Sjdp	/*
65138889Sjdp	 * We inline in6_mapped_peeraddr and COMMON_END here, so that we can
65238889Sjdp	 * copy the data of interest and defer the malloc until after we
65333965Sjdp	 * release the lock.
65433965Sjdp	 */
655104834Sobrien	if (inp->inp_vflag & INP_IPV4) {
65678828Sobrien		v4 = 1;
65778828Sobrien		port = inp->inp_fport;
65878828Sobrien		addr = inp->inp_faddr;
65978828Sobrien	} else {
66078828Sobrien		port = inp->inp_fport;
661130561Sobrien		addr6 = inp->in6p_faddr;
66278828Sobrien	}
663130561Sobrien
66478828Sobrienout:
66578828Sobrien	TCPDEBUG2(PRU_ACCEPT);
66678828Sobrien	INP_WUNLOCK(inp);
66778828Sobrien	if (error == 0) {
668104834Sobrien		if (v4)
669130561Sobrien			*nam = in6_v4mapsin6_sockaddr(port, &addr);
670130561Sobrien		else
671218822Sdim			*nam = in6_sockaddr(port, &addr6);
672218822Sdim	}
673218822Sdim	return error;
674218822Sdim}
67578828Sobrien#endif /* INET6 */
676130561Sobrien
67778828Sobrien/*
67878828Sobrien * Mark the connection as being incapable of further output.
679130561Sobrien */
68078828Sobrienstatic int
681130561Sobrientcp_usr_shutdown(struct socket *so)
68278828Sobrien{
68378828Sobrien	INIT_VNET_INET(so->so_vnet);
68478828Sobrien	int error = 0;
685130561Sobrien	struct inpcb *inp;
686130561Sobrien	struct tcpcb *tp = NULL;
68778828Sobrien
68878828Sobrien	TCPDEBUG0;
689104834Sobrien	INP_INFO_WLOCK(&V_tcbinfo);
69078828Sobrien	inp = sotoinpcb(so);
69178828Sobrien	KASSERT(inp != NULL, ("inp == NULL"));
69278828Sobrien	INP_WLOCK(inp);
69378828Sobrien	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
69478828Sobrien		error = ECONNRESET;
695130561Sobrien		goto out;
69678828Sobrien	}
69778828Sobrien	tp = intotcpcb(inp);
69878828Sobrien	TCPDEBUG1();
69978828Sobrien	socantsendmore(so);
70078828Sobrien	tcp_usrclosed(tp);
70178828Sobrien	error = tcp_output_disconnect(tp);
70278828Sobrien
70378828Sobrienout:
70478828Sobrien	TCPDEBUG2(PRU_SHUTDOWN);
70578828Sobrien	INP_WUNLOCK(inp);
706130561Sobrien	INP_INFO_WUNLOCK(&V_tcbinfo);
70778828Sobrien
708104834Sobrien	return (error);
70978828Sobrien}
71078828Sobrien
71178828Sobrien/*
71278828Sobrien * After a receive, possibly send window update to peer.
71378828Sobrien */
714130561Sobrienstatic int
71578828Sobrientcp_usr_rcvd(struct socket *so, int flags)
716104834Sobrien{
71778828Sobrien	struct inpcb *inp;
718130561Sobrien	struct tcpcb *tp = NULL;
71978828Sobrien	int error = 0;
720104834Sobrien
72178828Sobrien	TCPDEBUG0;
72278828Sobrien	inp = sotoinpcb(so);
72378828Sobrien	KASSERT(inp != NULL, ("tcp_usr_rcvd: inp == NULL"));
72478828Sobrien	INP_WLOCK(inp);
72578828Sobrien	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
72678828Sobrien		error = ECONNRESET;
727104834Sobrien		goto out;
72878828Sobrien	}
72978828Sobrien	tp = intotcpcb(inp);
73078828Sobrien	TCPDEBUG1();
73178828Sobrien	tcp_output_rcvd(tp);
73278828Sobrien
73378828Sobrienout:
73478828Sobrien	TCPDEBUG2(PRU_RCVD);
73578828Sobrien	INP_WUNLOCK(inp);
73678828Sobrien	return (error);
73778828Sobrien}
73878828Sobrien
73978828Sobrien/*
74078828Sobrien * Do a send by putting data in output queue and updating urgent
74178828Sobrien * marker if URG set.  Possibly send more data.  Unlike the other
74278828Sobrien * pru_*() routines, the mbuf chains are our responsibility.  We
74378828Sobrien * must either enqueue them or free them.  The other pru_* routines
744104834Sobrien * generally are caller-frees.
745104834Sobrien */
74678828Sobrienstatic int
74778828Sobrientcp_usr_send(struct socket *so, int flags, struct mbuf *m,
74878828Sobrien    struct sockaddr *nam, struct mbuf *control, struct thread *td)
74978828Sobrien{
75078828Sobrien	INIT_VNET_INET(so->so_vnet);
75178828Sobrien	int error = 0;
75278828Sobrien	struct inpcb *inp;
75378828Sobrien	struct tcpcb *tp = NULL;
75478828Sobrien	int headlocked = 0;
755218822Sdim#ifdef INET6
756218822Sdim	int isipv6;
75778828Sobrien#endif
758104834Sobrien	TCPDEBUG0;
75978828Sobrien
76078828Sobrien	/*
76178828Sobrien	 * We require the pcbinfo lock in two cases:
76278828Sobrien	 *
76378828Sobrien	 * (1) An implied connect is taking place, which can result in
76478828Sobrien	 *     binding IPs and ports and hence modification of the pcb hash
76578828Sobrien	 *     chains.
76678828Sobrien	 *
76778828Sobrien	 * (2) PRUS_EOF is set, resulting in explicit close on the send.
76878828Sobrien	 */
76978828Sobrien	if ((nam != NULL) || (flags & PRUS_EOF)) {
77078828Sobrien		INP_INFO_WLOCK(&V_tcbinfo);
77133965Sjdp		headlocked = 1;
77233965Sjdp	}
77333965Sjdp	inp = sotoinpcb(so);
774130561Sobrien	KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL"));
775130561Sobrien	INP_WLOCK(inp);
77633965Sjdp	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
77733965Sjdp		if (control)
77833965Sjdp			m_freem(control);
779130561Sobrien		if (m)
780130561Sobrien			m_freem(m);
781130561Sobrien		error = ECONNRESET;
782130561Sobrien		goto out;
783130561Sobrien	}
784130561Sobrien#ifdef INET6
785130561Sobrien	isipv6 = nam && nam->sa_family == AF_INET6;
786130561Sobrien#endif /* INET6 */
787130561Sobrien	tp = intotcpcb(inp);
788130561Sobrien	TCPDEBUG1();
789130561Sobrien	if (control) {
790130561Sobrien		/* TCP doesn't do control messages (rights, creds, etc) */
791130561Sobrien		if (control->m_len) {
792130561Sobrien			m_freem(control);
793130561Sobrien			if (m)
794130561Sobrien				m_freem(m);
795130561Sobrien			error = EINVAL;
796130561Sobrien			goto out;
797130561Sobrien		}
798130561Sobrien		m_freem(control);	/* empty control, just free it */
79989857Sobrien	}
800130561Sobrien	if (!(flags & PRUS_OOB)) {
80133965Sjdp		sbappendstream(&so->so_snd, m);
80233965Sjdp		if (nam && tp->t_state < TCPS_SYN_SENT) {
803218822Sdim			/*
804218822Sdim			 * Do implied connect if not yet connected,
805218822Sdim			 * initialize window to default value, and
806218822Sdim			 * initialize maxseg/maxopd using peer's cached
807218822Sdim			 * MSS.
808218822Sdim			 */
809218822Sdim			INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
810218822Sdim#ifdef INET6
811218822Sdim			if (isipv6)
812218822Sdim				error = tcp6_connect(tp, nam, td);
813218822Sdim			else
814218822Sdim#endif /* INET6 */
815218822Sdim			error = tcp_connect(tp, nam, td);
816218822Sdim			if (error)
817218822Sdim				goto out;
818218822Sdim			tp->snd_wnd = TTCP_CLIENT_SND_WND;
819218822Sdim			tcp_mss(tp, -1);
820218822Sdim		}
821218822Sdim		if (flags & PRUS_EOF) {
822218822Sdim			/*
823218822Sdim			 * Close the send side of the connection after
824218822Sdim			 * the data is sent.
825218822Sdim			 */
826218822Sdim			INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
82733965Sjdp			socantsendmore(so);
82833965Sjdp			tcp_usrclosed(tp);
829130561Sobrien		}
830130561Sobrien		if (headlocked) {
83133965Sjdp			INP_INFO_WUNLOCK(&V_tcbinfo);
832130561Sobrien			headlocked = 0;
833130561Sobrien		}
834130561Sobrien		if (tp != NULL) {
83533965Sjdp			if (flags & PRUS_MORETOCOME)
836130561Sobrien				tp->t_flags |= TF_MORETOCOME;
837130561Sobrien			error = tcp_output_send(tp);
838130561Sobrien			if (flags & PRUS_MORETOCOME)
839130561Sobrien				tp->t_flags &= ~TF_MORETOCOME;
840130561Sobrien		}
841130561Sobrien	} else {
842130561Sobrien		/*
843130561Sobrien		 * XXXRW: PRUS_EOF not implemented with PRUS_OOB?
844130561Sobrien		 */
845130561Sobrien		SOCKBUF_LOCK(&so->so_snd);
846130561Sobrien		if (sbspace(&so->so_snd) < -512) {
84760484Sobrien			SOCKBUF_UNLOCK(&so->so_snd);
84860484Sobrien			m_freem(m);
84960484Sobrien			error = ENOBUFS;
850130561Sobrien			goto out;
851130561Sobrien		}
85233965Sjdp		/*
853130561Sobrien		 * According to RFC961 (Assigned Protocols),
854130561Sobrien		 * the urgent pointer points to the last octet
855130561Sobrien		 * of urgent data.  We continue, however,
85660484Sobrien		 * to consider it to indicate the first octet
857218822Sdim		 * of data past the urgent section.
858218822Sdim		 * Otherwise, snd_up should be one lower.
859218822Sdim		 */
860218822Sdim		sbappendstream_locked(&so->so_snd, m);
861218822Sdim		SOCKBUF_UNLOCK(&so->so_snd);
862218822Sdim		if (nam && tp->t_state < TCPS_SYN_SENT) {
863218822Sdim			/*
864218822Sdim			 * Do implied connect if not yet connected,
865218822Sdim			 * initialize window to default value, and
866218822Sdim			 * initialize maxseg/maxopd using peer's cached
867218822Sdim			 * MSS.
868218822Sdim			 */
869218822Sdim			INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
870218822Sdim#ifdef INET6
871218822Sdim			if (isipv6)
872218822Sdim				error = tcp6_connect(tp, nam, td);
873218822Sdim			else
874218822Sdim#endif /* INET6 */
875218822Sdim			error = tcp_connect(tp, nam, td);
876218822Sdim			if (error)
877218822Sdim				goto out;
878218822Sdim			tp->snd_wnd = TTCP_CLIENT_SND_WND;
879218822Sdim			tcp_mss(tp, -1);
880218822Sdim			INP_INFO_WUNLOCK(&V_tcbinfo);
881218822Sdim			headlocked = 0;
882130561Sobrien		} else if (nam) {
88333965Sjdp			INP_INFO_WUNLOCK(&V_tcbinfo);
88433965Sjdp			headlocked = 0;
885218822Sdim		}
886218822Sdim		tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
887218822Sdim		tp->t_flags |= TF_FORCEDATA;
888218822Sdim		error = tcp_output_send(tp);
889218822Sdim		tp->t_flags &= ~TF_FORCEDATA;
890218822Sdim	}
891218822Sdimout:
892218822Sdim	TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB :
893218822Sdim		  ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
894218822Sdim	INP_WUNLOCK(inp);
895218822Sdim	if (headlocked)
896218822Sdim		INP_INFO_WUNLOCK(&V_tcbinfo);
897218822Sdim	return (error);
898218822Sdim}
899218822Sdim
900218822Sdim/*
901218822Sdim * Abort the TCP.  Drop the connection abruptly.
902218822Sdim */
90333965Sjdpstatic void
90433965Sjdptcp_usr_abort(struct socket *so)
90533965Sjdp{
90633965Sjdp	INIT_VNET_INET(so->so_vnet);
90733965Sjdp	struct inpcb *inp;
908130561Sobrien	struct tcpcb *tp = NULL;
909130561Sobrien	TCPDEBUG0;
91033965Sjdp
911130561Sobrien	inp = sotoinpcb(so);
91233965Sjdp	KASSERT(inp != NULL, ("tcp_usr_abort: inp == NULL"));
913218822Sdim
91433965Sjdp	INP_INFO_WLOCK(&V_tcbinfo);
91533965Sjdp	INP_WLOCK(inp);
91633965Sjdp	KASSERT(inp->inp_socket != NULL,
91733965Sjdp	    ("tcp_usr_abort: inp_socket == NULL"));
91833965Sjdp
919130561Sobrien	/*
920218822Sdim	 * If we still have full TCP state, and we're not dropped, drop.
921218822Sdim	 */
922130561Sobrien	if (!(inp->inp_vflag & INP_TIMEWAIT) &&
923130561Sobrien	    !(inp->inp_vflag & INP_DROPPED)) {
924130561Sobrien		tp = intotcpcb(inp);
92533965Sjdp		TCPDEBUG1();
926130561Sobrien		tcp_drop(tp, ECONNABORTED);
927130561Sobrien		TCPDEBUG2(PRU_ABORT);
92860484Sobrien	}
92960484Sobrien	if (!(inp->inp_vflag & INP_DROPPED)) {
930130561Sobrien		SOCK_LOCK(so);
93160484Sobrien		so->so_state |= SS_PROTOREF;
932130561Sobrien		SOCK_UNLOCK(so);
933130561Sobrien		inp->inp_vflag |= INP_SOCKREF;
934130561Sobrien	}
935130561Sobrien	INP_WUNLOCK(inp);
93660484Sobrien	INP_INFO_WUNLOCK(&V_tcbinfo);
93760484Sobrien}
938130561Sobrien
939130561Sobrien/*
940130561Sobrien * TCP socket is closed.  Start friendly disconnect.
941130561Sobrien */
942130561Sobrienstatic void
943130561Sobrientcp_usr_close(struct socket *so)
944130561Sobrien{
945130561Sobrien	INIT_VNET_INET(so->so_vnet);
94633965Sjdp	struct inpcb *inp;
947130561Sobrien	struct tcpcb *tp = NULL;
948130561Sobrien	TCPDEBUG0;
949130561Sobrien
950130561Sobrien	inp = sotoinpcb(so);
951130561Sobrien	KASSERT(inp != NULL, ("tcp_usr_close: inp == NULL"));
952130561Sobrien
95333965Sjdp	INP_INFO_WLOCK(&V_tcbinfo);
954130561Sobrien	INP_WLOCK(inp);
955130561Sobrien	KASSERT(inp->inp_socket != NULL,
956130561Sobrien	    ("tcp_usr_close: inp_socket == NULL"));
957130561Sobrien
958130561Sobrien	/*
959130561Sobrien	 * If we still have full TCP state, and we're not dropped, initiate
960130561Sobrien	 * a disconnect.
961130561Sobrien	 */
96289857Sobrien	if (!(inp->inp_vflag & INP_TIMEWAIT) &&
963130561Sobrien	    !(inp->inp_vflag & INP_DROPPED)) {
964130561Sobrien		tp = intotcpcb(inp);
965130561Sobrien		TCPDEBUG1();
96633965Sjdp		tcp_disconnect(tp);
967130561Sobrien		TCPDEBUG2(PRU_CLOSE);
968130561Sobrien	}
969130561Sobrien	if (!(inp->inp_vflag & INP_DROPPED)) {
970130561Sobrien		SOCK_LOCK(so);
971130561Sobrien		so->so_state |= SS_PROTOREF;
972130561Sobrien		SOCK_UNLOCK(so);
973130561Sobrien		inp->inp_vflag |= INP_SOCKREF;
974130561Sobrien	}
975130561Sobrien	INP_WUNLOCK(inp);
976130561Sobrien	INP_INFO_WUNLOCK(&V_tcbinfo);
977130561Sobrien}
978130561Sobrien
979130561Sobrien/*
980130561Sobrien * Receive out-of-band data.
981130561Sobrien */
982130561Sobrienstatic int
983130561Sobrientcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
984130561Sobrien{
985130561Sobrien	int error = 0;
986130561Sobrien	struct inpcb *inp;
987130561Sobrien	struct tcpcb *tp = NULL;
98860484Sobrien
989218822Sdim	TCPDEBUG0;
99060484Sobrien	inp = sotoinpcb(so);
99160484Sobrien	KASSERT(inp != NULL, ("tcp_usr_rcvoob: inp == NULL"));
99260484Sobrien	INP_WLOCK(inp);
99360484Sobrien	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
994218822Sdim		error = ECONNRESET;
995218822Sdim		goto out;
996218822Sdim	}
997218822Sdim	tp = intotcpcb(inp);
998104834Sobrien	TCPDEBUG1();
99977298Sobrien	if ((so->so_oobmark == 0 &&
1000218822Sdim	     (so->so_rcv.sb_state & SBS_RCVATMARK) == 0) ||
100178828Sobrien	    so->so_options & SO_OOBINLINE ||
100278828Sobrien	    tp->t_oobflags & TCPOOB_HADDATA) {
1003130561Sobrien		error = EINVAL;
100478828Sobrien		goto out;
100578828Sobrien	}
1006218822Sdim	if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
100733965Sjdp		error = EWOULDBLOCK;
100833965Sjdp		goto out;
100989857Sobrien	}
101033965Sjdp	m->m_len = 1;
101160484Sobrien	*mtod(m, caddr_t) = tp->t_iobc;
101233965Sjdp	if ((flags & MSG_PEEK) == 0)
101360484Sobrien		tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
101460484Sobrien
101533965Sjdpout:
1016218822Sdim	TCPDEBUG2(PRU_RCVOOB);
101780016Sobrien	INP_WUNLOCK(inp);
101880016Sobrien	return (error);
1019218822Sdim}
102033965Sjdp
102160484Sobrienstruct pr_usrreqs tcp_usrreqs = {
102260484Sobrien	.pru_abort =		tcp_usr_abort,
102360484Sobrien	.pru_accept =		tcp_usr_accept,
102433965Sjdp	.pru_attach =		tcp_usr_attach,
102533965Sjdp	.pru_bind =		tcp_usr_bind,
102638889Sjdp	.pru_connect =		tcp_usr_connect,
1027218822Sdim	.pru_control =		in_control,
1028218822Sdim	.pru_detach =		tcp_usr_detach,
1029218822Sdim	.pru_disconnect =	tcp_usr_disconnect,
1030218822Sdim	.pru_listen =		tcp_usr_listen,
1031218822Sdim	.pru_peeraddr =		in_getpeeraddr,
1032218822Sdim	.pru_rcvd =		tcp_usr_rcvd,
1033218822Sdim	.pru_rcvoob =		tcp_usr_rcvoob,
1034218822Sdim	.pru_send =		tcp_usr_send,
1035218822Sdim	.pru_shutdown =		tcp_usr_shutdown,
1036218822Sdim	.pru_sockaddr =		in_getsockaddr,
1037218822Sdim	.pru_sosetlabel =	in_pcbsosetlabel,
1038218822Sdim	.pru_close =		tcp_usr_close,
1039218822Sdim};
1040218822Sdim
1041218822Sdim#ifdef INET6
1042218822Sdimstruct pr_usrreqs tcp6_usrreqs = {
1043218822Sdim	.pru_abort =		tcp_usr_abort,
1044218822Sdim	.pru_accept =		tcp6_usr_accept,
1045218822Sdim	.pru_attach =		tcp_usr_attach,
1046218822Sdim	.pru_bind =		tcp6_usr_bind,
1047218822Sdim	.pru_connect =		tcp6_usr_connect,
1048218822Sdim	.pru_control =		in6_control,
104933965Sjdp	.pru_detach =		tcp_usr_detach,
1050218822Sdim	.pru_disconnect =	tcp_usr_disconnect,
105133965Sjdp	.pru_listen =		tcp6_usr_listen,
1052218822Sdim	.pru_peeraddr =		in6_mapped_peeraddr,
105333965Sjdp	.pru_rcvd =		tcp_usr_rcvd,
1054218822Sdim	.pru_rcvoob =		tcp_usr_rcvoob,
1055218822Sdim	.pru_send =		tcp_usr_send,
1056218822Sdim	.pru_shutdown =		tcp_usr_shutdown,
1057218822Sdim	.pru_sockaddr =		in6_mapped_sockaddr,
1058218822Sdim 	.pru_sosetlabel =	in_pcbsosetlabel,
1059218822Sdim	.pru_close =		tcp_usr_close,
1060218822Sdim};
1061218822Sdim#endif /* INET6 */
1062218822Sdim
1063218822Sdim/*
1064218822Sdim * Common subroutine to open a TCP connection to remote host specified
1065218822Sdim * by struct sockaddr_in in mbuf *nam.  Call in_pcbbind to assign a local
1066218822Sdim * port number if needed.  Call in_pcbconnect_setup to do the routing and
1067218822Sdim * to choose a local host address (interface).  If there is an existing
1068218822Sdim * incarnation of the same connection in TIME-WAIT state and if the remote
1069218822Sdim * host was sending CC options and if the connection duration was < MSL, then
1070218822Sdim * truncate the previous TIME-WAIT state and proceed.
1071218822Sdim * Initialize connection parameters and enter SYN-SENT state.
1072218822Sdim */
1073218822Sdimstatic int
1074218822Sdimtcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
1075218822Sdim{
1076218822Sdim	struct inpcb *inp = tp->t_inpcb, *oinp;
1077218822Sdim	struct socket *so = inp->inp_socket;
1078218822Sdim	INIT_VNET_INET(so->so_vnet);
1079218822Sdim	struct in_addr laddr;
1080218822Sdim	u_short lport;
108133965Sjdp	int error;
108233965Sjdp
108333965Sjdp	INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
108433965Sjdp	INP_WLOCK_ASSERT(inp);
108533965Sjdp
108633965Sjdp	if (inp->inp_lport == 0) {
108733965Sjdp		error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
108833965Sjdp		if (error)
108989857Sobrien			return error;
109089857Sobrien	}
109160484Sobrien
1092130561Sobrien	/*
109360484Sobrien	 * Cannot simply call in_pcbconnect, because there might be an
109460484Sobrien	 * earlier incarnation of this same connection still in
109560484Sobrien	 * TIME_WAIT state, creating an ADDRINUSE error.
109689857Sobrien	 */
109789857Sobrien	laddr = inp->inp_laddr;
109889857Sobrien	lport = inp->inp_lport;
109960484Sobrien	error = in_pcbconnect_setup(inp, nam, &laddr.s_addr, &lport,
110089857Sobrien	    &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, td->td_ucred);
110160484Sobrien	if (error && oinp == NULL)
110260484Sobrien		return error;
110389857Sobrien	if (oinp)
110460484Sobrien		return EADDRINUSE;
110560484Sobrien	inp->inp_laddr = laddr;
1106130561Sobrien	in_pcbrehash(inp);
110760484Sobrien
110860484Sobrien	/*
110960484Sobrien	 * Compute window scaling to request:
111060484Sobrien	 * Scale to fit into sweet spot.  See tcp_syncache.c.
111160484Sobrien	 * XXX: This should move to tcp_output().
111260484Sobrien	 */
111360484Sobrien	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
111460484Sobrien	    (TCP_MAXWIN << tp->request_r_scale) < sb_max)
111589857Sobrien		tp->request_r_scale++;
1116130561Sobrien
111760484Sobrien	soisconnecting(so);
111860484Sobrien	V_tcpstat.tcps_connattempt++;
111989857Sobrien	tp->t_state = TCPS_SYN_SENT;
1120130561Sobrien	tcp_timer_activate(tp, TT_KEEP, tcp_keepinit);
112160484Sobrien	tp->iss = tcp_new_isn(tp);
112260484Sobrien	tp->t_bw_rtseq = tp->iss;
1123130561Sobrien	tcp_sendseqinit(tp);
112460484Sobrien
112560484Sobrien	return 0;
112660484Sobrien}
112760484Sobrien
112860484Sobrien#ifdef INET6
112960484Sobrienstatic int
113060484Sobrientcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
113160484Sobrien{
1132130561Sobrien	struct inpcb *inp = tp->t_inpcb, *oinp;
1133130561Sobrien	struct socket *so = inp->inp_socket;
113433965Sjdp	INIT_VNET_INET(so->so_vnet);
113533965Sjdp	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
1136130561Sobrien	struct in6_addr *addr6;
113733965Sjdp	int error;
1138130561Sobrien
1139130561Sobrien	INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
1140130561Sobrien	INP_WLOCK_ASSERT(inp);
1141130561Sobrien
1142130561Sobrien	if (inp->inp_lport == 0) {
1143130561Sobrien		error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
114433965Sjdp		if (error)
1145130561Sobrien			return error;
1146130561Sobrien	}
1147130561Sobrien
1148130561Sobrien	/*
114989857Sobrien	 * Cannot simply call in_pcbconnect, because there might be an
1150130561Sobrien	 * earlier incarnation of this same connection still in
1151130561Sobrien	 * TIME_WAIT state, creating an ADDRINUSE error.
1152130561Sobrien	 * in6_pcbladdr() also handles scope zone IDs.
1153130561Sobrien	 */
1154130561Sobrien	error = in6_pcbladdr(inp, nam, &addr6);
1155130561Sobrien	if (error)
1156130561Sobrien		return error;
1157130561Sobrien	oinp = in6_pcblookup_hash(inp->inp_pcbinfo,
1158130561Sobrien				  &sin6->sin6_addr, sin6->sin6_port,
1159130561Sobrien				  IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
1160130561Sobrien				  ? addr6
1161130561Sobrien				  : &inp->in6p_laddr,
1162130561Sobrien				  inp->inp_lport,  0, NULL);
1163130561Sobrien	if (oinp)
1164130561Sobrien		return EADDRINUSE;
1165130561Sobrien	if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
1166130561Sobrien		inp->in6p_laddr = *addr6;
1167130561Sobrien	inp->in6p_faddr = sin6->sin6_addr;
1168130561Sobrien	inp->inp_fport = sin6->sin6_port;
1169130561Sobrien	/* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */
1170130561Sobrien	inp->inp_flow &= ~IPV6_FLOWLABEL_MASK;
1171130561Sobrien	if (inp->inp_flags & IN6P_AUTOFLOWLABEL)
1172130561Sobrien		inp->inp_flow |=
1173130561Sobrien		    (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
1174130561Sobrien	in_pcbrehash(inp);
1175130561Sobrien
1176130561Sobrien	/* Compute window scaling to request.  */
1177130561Sobrien	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
1178130561Sobrien	    (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
1179130561Sobrien		tp->request_r_scale++;
1180130561Sobrien
1181130561Sobrien	soisconnecting(so);
1182130561Sobrien	V_tcpstat.tcps_connattempt++;
1183130561Sobrien	tp->t_state = TCPS_SYN_SENT;
1184130561Sobrien	tcp_timer_activate(tp, TT_KEEP, tcp_keepinit);
1185130561Sobrien	tp->iss = tcp_new_isn(tp);
1186130561Sobrien	tp->t_bw_rtseq = tp->iss;
1187130561Sobrien	tcp_sendseqinit(tp);
1188130561Sobrien
1189130561Sobrien	return 0;
1190130561Sobrien}
1191130561Sobrien#endif /* INET6 */
1192130561Sobrien
1193130561Sobrien/*
1194130561Sobrien * Export TCP internal state information via a struct tcp_info, based on the
1195130561Sobrien * Linux 2.6 API.  Not ABI compatible as our constants are mapped differently
1196130561Sobrien * (TCP state machine, etc).  We export all information using FreeBSD-native
1197130561Sobrien * constants -- for example, the numeric values for tcpi_state will differ
1198130561Sobrien * from Linux.
1199130561Sobrien */
1200130561Sobrienstatic void
1201130561Sobrientcp_fill_info(struct tcpcb *tp, struct tcp_info *ti)
1202130561Sobrien{
1203130561Sobrien
1204130561Sobrien	INP_WLOCK_ASSERT(tp->t_inpcb);
1205130561Sobrien	bzero(ti, sizeof(*ti));
1206130561Sobrien
1207130561Sobrien	ti->tcpi_state = tp->t_state;
1208130561Sobrien	if ((tp->t_flags & TF_REQ_TSTMP) && (tp->t_flags & TF_RCVD_TSTMP))
1209130561Sobrien		ti->tcpi_options |= TCPI_OPT_TIMESTAMPS;
1210130561Sobrien	if (tp->t_flags & TF_SACK_PERMIT)
1211130561Sobrien		ti->tcpi_options |= TCPI_OPT_SACK;
1212130561Sobrien	if ((tp->t_flags & TF_REQ_SCALE) && (tp->t_flags & TF_RCVD_SCALE)) {
1213130561Sobrien		ti->tcpi_options |= TCPI_OPT_WSCALE;
1214130561Sobrien		ti->tcpi_snd_wscale = tp->snd_scale;
1215130561Sobrien		ti->tcpi_rcv_wscale = tp->rcv_scale;
1216218822Sdim	}
1217130561Sobrien
1218130561Sobrien	ti->tcpi_rtt = ((u_int64_t)tp->t_srtt * tick) >> TCP_RTT_SHIFT;
1219130561Sobrien	ti->tcpi_rttvar = ((u_int64_t)tp->t_rttvar * tick) >> TCP_RTTVAR_SHIFT;
1220130561Sobrien
1221130561Sobrien	ti->tcpi_snd_ssthresh = tp->snd_ssthresh;
1222130561Sobrien	ti->tcpi_snd_cwnd = tp->snd_cwnd;
1223130561Sobrien
1224130561Sobrien	/*
1225218822Sdim	 * FreeBSD-specific extension fields for tcp_info.
1226130561Sobrien	 */
1227130561Sobrien	ti->tcpi_rcv_space = tp->rcv_wnd;
1228218822Sdim	ti->tcpi_rcv_nxt = tp->rcv_nxt;
1229130561Sobrien	ti->tcpi_snd_wnd = tp->snd_wnd;
1230130561Sobrien	ti->tcpi_snd_bwnd = tp->snd_bwnd;
1231130561Sobrien	ti->tcpi_snd_nxt = tp->snd_nxt;
1232130561Sobrien	ti->__tcpi_snd_mss = tp->t_maxseg;
1233130561Sobrien	ti->__tcpi_rcv_mss = tp->t_maxseg;
1234130561Sobrien	if (tp->t_flags & TF_TOE)
1235130561Sobrien		ti->tcpi_options |= TCPI_OPT_TOE;
1236130561Sobrien}
1237130561Sobrien
1238218822Sdim/*
1239130561Sobrien * tcp_ctloutput() must drop the inpcb lock before performing copyin on
1240130561Sobrien * socket option arguments.  When it re-acquires the lock after the copy, it
124133965Sjdp * has to revalidate that the connection is still valid for the socket
124233965Sjdp * option.
1243218822Sdim */
1244218822Sdim#define INP_WLOCK_RECHECK(inp) do {					\
1245218822Sdim	INP_WLOCK(inp);							\
1246218822Sdim	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {		\
1247218822Sdim		INP_WUNLOCK(inp);					\
1248218822Sdim		return (ECONNRESET);					\
1249218822Sdim	}								\
1250218822Sdim	tp = intotcpcb(inp);						\
1251218822Sdim} while(0)
1252218822Sdim
1253218822Sdimint
1254218822Sdimtcp_ctloutput(struct socket *so, struct sockopt *sopt)
1255218822Sdim{
1256218822Sdim	INIT_VNET_INET(so->so_vnet);
1257218822Sdim	int	error, opt, optval;
1258218822Sdim	struct	inpcb *inp;
1259218822Sdim	struct	tcpcb *tp;
1260218822Sdim	struct	tcp_info ti;
1261218822Sdim
1262218822Sdim	error = 0;
1263218822Sdim	inp = sotoinpcb(so);
1264218822Sdim	KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL"));
1265218822Sdim	INP_WLOCK(inp);
1266218822Sdim	if (sopt->sopt_level != IPPROTO_TCP) {
1267218822Sdim#ifdef INET6
1268218822Sdim		if (inp->inp_vflag & INP_IPV6PROTO) {
1269218822Sdim			INP_WUNLOCK(inp);
1270218822Sdim			error = ip6_ctloutput(so, sopt);
1271218822Sdim		} else {
1272218822Sdim#endif /* INET6 */
1273218822Sdim			INP_WUNLOCK(inp);
1274218822Sdim			error = ip_ctloutput(so, sopt);
1275218822Sdim#ifdef INET6
1276218822Sdim		}
1277218822Sdim#endif
1278218822Sdim		return (error);
1279218822Sdim	}
1280218822Sdim	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
1281218822Sdim		INP_WUNLOCK(inp);
1282218822Sdim		return (ECONNRESET);
1283218822Sdim	}
1284218822Sdim
1285218822Sdim	switch (sopt->sopt_dir) {
1286218822Sdim	case SOPT_SET:
1287218822Sdim		switch (sopt->sopt_name) {
1288218822Sdim#ifdef TCP_SIGNATURE
1289218822Sdim		case TCP_MD5SIG:
1290218822Sdim			INP_WUNLOCK(inp);
1291218822Sdim			error = sooptcopyin(sopt, &optval, sizeof optval,
1292218822Sdim			    sizeof optval);
1293218822Sdim			if (error)
1294218822Sdim				return (error);
1295218822Sdim
1296218822Sdim			INP_WLOCK_RECHECK(inp);
1297218822Sdim			if (optval > 0)
1298218822Sdim				tp->t_flags |= TF_SIGNATURE;
1299218822Sdim			else
1300218822Sdim				tp->t_flags &= ~TF_SIGNATURE;
1301218822Sdim			INP_WUNLOCK(inp);
1302218822Sdim			break;
1303218822Sdim#endif /* TCP_SIGNATURE */
1304218822Sdim		case TCP_NODELAY:
1305218822Sdim		case TCP_NOOPT:
1306218822Sdim			INP_WUNLOCK(inp);
1307218822Sdim			error = sooptcopyin(sopt, &optval, sizeof optval,
1308218822Sdim			    sizeof optval);
1309218822Sdim			if (error)
1310218822Sdim				return (error);
1311130561Sobrien
1312130561Sobrien			INP_WLOCK_RECHECK(inp);
131333965Sjdp			switch (sopt->sopt_name) {
1314130561Sobrien			case TCP_NODELAY:
1315130561Sobrien				opt = TF_NODELAY;
131633965Sjdp				break;
131733965Sjdp			case TCP_NOOPT:
131833965Sjdp				opt = TF_NOOPT;
131933965Sjdp				break;
1320130561Sobrien			default:
132133965Sjdp				opt = 0; /* dead code to fool gcc */
132233965Sjdp				break;
132360484Sobrien			}
1324130561Sobrien
1325130561Sobrien			if (optval)
1326130561Sobrien				tp->t_flags |= opt;
132733965Sjdp			else
132877298Sobrien				tp->t_flags &= ~opt;
132977298Sobrien			INP_WUNLOCK(inp);
133077298Sobrien			break;
1331130561Sobrien
1332130561Sobrien		case TCP_NOPUSH:
1333130561Sobrien			INP_WUNLOCK(inp);
133477298Sobrien			error = sooptcopyin(sopt, &optval, sizeof optval,
1335130561Sobrien			    sizeof optval);
1336130561Sobrien			if (error)
133777298Sobrien				return (error);
133860484Sobrien
133933965Sjdp			INP_WLOCK_RECHECK(inp);
1340218822Sdim			if (optval)
1341218822Sdim				tp->t_flags |= TF_NOPUSH;
134260484Sobrien			else {
134333965Sjdp				tp->t_flags &= ~TF_NOPUSH;
1344218822Sdim				error = tcp_output(tp);
1345218822Sdim			}
134633965Sjdp			INP_WUNLOCK(inp);
1347218822Sdim			break;
1348218822Sdim
1349218822Sdim		case TCP_MAXSEG:
1350218822Sdim			INP_WUNLOCK(inp);
1351218822Sdim			error = sooptcopyin(sopt, &optval, sizeof optval,
1352218822Sdim			    sizeof optval);
1353218822Sdim			if (error)
135433965Sjdp				return (error);
1355104834Sobrien
1356104834Sobrien			INP_WLOCK_RECHECK(inp);
135789857Sobrien			if (optval > 0 && optval <= tp->t_maxseg &&
135889857Sobrien			    optval + 40 >= V_tcp_minmss)
1359130561Sobrien				tp->t_maxseg = optval;
1360130561Sobrien			else
1361130561Sobrien				error = EINVAL;
1362130561Sobrien			INP_WUNLOCK(inp);
1363130561Sobrien			break;
1364130561Sobrien
1365130561Sobrien		case TCP_INFO:
136689857Sobrien			INP_WUNLOCK(inp);
1367130561Sobrien			error = EINVAL;
1368130561Sobrien			break;
1369218822Sdim
1370130561Sobrien		default:
1371130561Sobrien			INP_WUNLOCK(inp);
137289857Sobrien			error = ENOPROTOOPT;
137333965Sjdp			break;
137489857Sobrien		}
1375130561Sobrien		break;
1376130561Sobrien
1377130561Sobrien	case SOPT_GET:
1378130561Sobrien		tp = intotcpcb(inp);
1379130561Sobrien		switch (sopt->sopt_name) {
1380130561Sobrien#ifdef TCP_SIGNATURE
1381130561Sobrien		case TCP_MD5SIG:
1382218822Sdim			optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0;
1383218822Sdim			INP_WUNLOCK(inp);
1384130561Sobrien			error = sooptcopyout(sopt, &optval, sizeof optval);
1385218822Sdim			break;
1386218822Sdim#endif
1387218822Sdim
1388218822Sdim		case TCP_NODELAY:
1389130561Sobrien			optval = tp->t_flags & TF_NODELAY;
139060484Sobrien			INP_WUNLOCK(inp);
139133965Sjdp			error = sooptcopyout(sopt, &optval, sizeof optval);
1392130561Sobrien			break;
1393218822Sdim		case TCP_MAXSEG:
1394130561Sobrien			optval = tp->t_maxseg;
1395130561Sobrien			INP_WUNLOCK(inp);
139633965Sjdp			error = sooptcopyout(sopt, &optval, sizeof optval);
139733965Sjdp			break;
139833965Sjdp		case TCP_NOOPT:
139960484Sobrien			optval = tp->t_flags & TF_NOOPT;
140033965Sjdp			INP_WUNLOCK(inp);
140133965Sjdp			error = sooptcopyout(sopt, &optval, sizeof optval);
140233965Sjdp			break;
1403218822Sdim		case TCP_NOPUSH:
1404218822Sdim			optval = tp->t_flags & TF_NOPUSH;
1405218822Sdim			INP_WUNLOCK(inp);
1406218822Sdim			error = sooptcopyout(sopt, &optval, sizeof optval);
1407218822Sdim			break;
1408218822Sdim		case TCP_INFO:
1409218822Sdim			tcp_fill_info(tp, &ti);
1410218822Sdim			INP_WUNLOCK(inp);
1411218822Sdim			error = sooptcopyout(sopt, &ti, sizeof ti);
1412218822Sdim			break;
1413218822Sdim		default:
1414218822Sdim			INP_WUNLOCK(inp);
1415218822Sdim			error = ENOPROTOOPT;
1416218822Sdim			break;
1417218822Sdim		}
1418218822Sdim		break;
1419218822Sdim	}
1420218822Sdim	return (error);
142160484Sobrien}
142233965Sjdp#undef INP_WLOCK_RECHECK
1423130561Sobrien
142433965Sjdp/*
1425218822Sdim * tcp_sendspace and tcp_recvspace are the default send and receive window
1426218822Sdim * sizes, respectively.  These are obsolescent (this information should
142733965Sjdp * be set by the route).
142833965Sjdp */
142933965Sjdpu_long	tcp_sendspace = 1024*32;
143033965SjdpSYSCTL_ULONG(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace, CTLFLAG_RW,
143133965Sjdp    &tcp_sendspace , 0, "Maximum outgoing TCP datagram size");
143233965Sjdpu_long	tcp_recvspace = 1024*64;
143333965SjdpSYSCTL_ULONG(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
1434130561Sobrien    &tcp_recvspace , 0, "Maximum incoming TCP datagram size");
1435130561Sobrien
1436130561Sobrien/*
1437130561Sobrien * Attach TCP protocol to socket, allocating
1438130561Sobrien * internet protocol control block, tcp control block,
143933965Sjdp * bufer space, and entering LISTEN state if to accept connections.
1440218822Sdim */
1441130561Sobrienstatic int
1442130561Sobrientcp_attach(struct socket *so)
1443218822Sdim{
1444218822Sdim	INIT_VNET_INET(so->so_vnet);
1445218822Sdim	struct tcpcb *tp;
1446218822Sdim	struct inpcb *inp;
1447218822Sdim	int error;
1448218822Sdim
1449218822Sdim	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
1450218822Sdim		error = soreserve(so, tcp_sendspace, tcp_recvspace);
1451130561Sobrien		if (error)
1452218822Sdim			return (error);
1453218822Sdim	}
1454218822Sdim	so->so_rcv.sb_flags |= SB_AUTOSIZE;
1455218822Sdim	so->so_snd.sb_flags |= SB_AUTOSIZE;
1456218822Sdim	INP_INFO_WLOCK(&V_tcbinfo);
1457218822Sdim	error = in_pcballoc(so, &V_tcbinfo);
1458218822Sdim	if (error) {
1459218822Sdim		INP_INFO_WUNLOCK(&V_tcbinfo);
1460218822Sdim		return (error);
146133965Sjdp	}
1462218822Sdim	inp = sotoinpcb(so);
1463130561Sobrien#ifdef INET6
1464130561Sobrien	if (inp->inp_vflag & INP_IPV6PROTO) {
1465130561Sobrien		inp->inp_vflag |= INP_IPV6;
1466130561Sobrien		inp->in6p_hops = -1;	/* use kernel default */
146760484Sobrien	}
1468130561Sobrien	else
1469130561Sobrien#endif
1470130561Sobrien	inp->inp_vflag |= INP_IPV4;
1471130561Sobrien	tp = tcp_newtcpcb(inp);
1472130561Sobrien	if (tp == NULL) {
1473130561Sobrien		in_pcbdetach(inp);
1474130561Sobrien		in_pcbfree(inp);
1475130561Sobrien		INP_INFO_WUNLOCK(&V_tcbinfo);
1476130561Sobrien		return (ENOBUFS);
147733965Sjdp	}
1478130561Sobrien	tp->t_state = TCPS_CLOSED;
147933965Sjdp	INP_WUNLOCK(inp);
1480130561Sobrien	INP_INFO_WUNLOCK(&V_tcbinfo);
148160484Sobrien	return (0);
1482130561Sobrien}
1483130561Sobrien
1484130561Sobrien/*
148560484Sobrien * Initiate (or continue) disconnect.
1486130561Sobrien * If embryonic state, just send reset (once).
1487130561Sobrien * If in ``let data drain'' option and linger null, just drop.
148860484Sobrien * Otherwise (hard), mark socket disconnecting and drop
148933965Sjdp * current input data; switch states based on user close, and
149033965Sjdp * send segment to peer (with FIN).
149133965Sjdp */
149233965Sjdpstatic void
149333965Sjdptcp_disconnect(struct tcpcb *tp)
1494130561Sobrien{
1495130561Sobrien	struct inpcb *inp = tp->t_inpcb;
1496130561Sobrien	struct socket *so = inp->inp_socket;
1497130561Sobrien#ifdef INVARIANTS
1498130561Sobrien	INIT_VNET_INET(so->so_vnet);
1499130561Sobrien#endif
1500130561Sobrien
1501130561Sobrien	INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
1502130561Sobrien	INP_WLOCK_ASSERT(inp);
1503130561Sobrien
1504130561Sobrien	/*
1505218822Sdim	 * Neither tcp_close() nor tcp_drop() should return NULL, as the
1506218822Sdim	 * socket is still open.
1507218822Sdim	 */
1508218822Sdim	if (tp->t_state < TCPS_ESTABLISHED) {
1509218822Sdim		tp = tcp_close(tp);
1510218822Sdim		KASSERT(tp != NULL,
1511218822Sdim		    ("tcp_disconnect: tcp_close() returned NULL"));
1512218822Sdim	} else if ((so->so_options & SO_LINGER) && so->so_linger == 0) {
1513218822Sdim		tp = tcp_drop(tp, 0);
1514218822Sdim		KASSERT(tp != NULL,
1515218822Sdim		    ("tcp_disconnect: tcp_drop() returned NULL"));
1516218822Sdim	} else {
1517218822Sdim		soisdisconnecting(so);
1518218822Sdim		sbflush(&so->so_rcv);
1519218822Sdim		tcp_usrclosed(tp);
1520218822Sdim		if (!(inp->inp_vflag & INP_DROPPED))
1521218822Sdim			tcp_output_disconnect(tp);
1522218822Sdim	}
1523218822Sdim}
1524218822Sdim
1525218822Sdim/*
1526218822Sdim * User issued close, and wish to trail through shutdown states:
1527218822Sdim * if never received SYN, just forget it.  If got a SYN from peer,
1528218822Sdim * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
1529218822Sdim * If already got a FIN from peer, then almost done; go to LAST_ACK
1530218822Sdim * state.  In all other cases, have already sent FIN to peer (e.g.
1531218822Sdim * after PRU_SHUTDOWN), and just have to play tedious game waiting
1532218822Sdim * for peer to send FIN or not respond to keep-alives, etc.
1533218822Sdim * We can let the user exit from the close as soon as the FIN is acked.
1534218822Sdim */
1535218822Sdimstatic void
1536218822Sdimtcp_usrclosed(struct tcpcb *tp)
1537218822Sdim{
1538218822Sdim#ifdef INVARIANTS
1539218822Sdim	INIT_VNET_INET(tp->t_inpcb->inp_vnet);
1540218822Sdim#endif
1541218822Sdim
1542218822Sdim	INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
1543218822Sdim	INP_WLOCK_ASSERT(tp->t_inpcb);
1544218822Sdim
1545222204Sbenl	switch (tp->t_state) {
1546222204Sbenl	case TCPS_LISTEN:
1547218822Sdim		tcp_offload_listen_close(tp);
1548130561Sobrien		/* FALLTHROUGH */
1549130561Sobrien	case TCPS_CLOSED:
1550218822Sdim		tp->t_state = TCPS_CLOSED;
1551218822Sdim		tp = tcp_close(tp);
155233965Sjdp		/*
155333965Sjdp		 * tcp_close() should never return NULL here as the socket is
155433965Sjdp		 * still open.
155533965Sjdp		 */
155633965Sjdp		KASSERT(tp != NULL,
155733965Sjdp		    ("tcp_usrclosed: tcp_close() returned NULL"));
155833965Sjdp		break;
155933965Sjdp
156033965Sjdp	case TCPS_SYN_SENT:
156133965Sjdp	case TCPS_SYN_RECEIVED:
156233965Sjdp		tp->t_flags |= TF_NEEDFIN;
1563130561Sobrien		break;
156433965Sjdp
1565130561Sobrien	case TCPS_ESTABLISHED:
156633965Sjdp		tp->t_state = TCPS_FIN_WAIT_1;
156738889Sjdp		break;
156833965Sjdp
1569130561Sobrien	case TCPS_CLOSE_WAIT:
157033965Sjdp		tp->t_state = TCPS_LAST_ACK;
157133965Sjdp		break;
157233965Sjdp	}
157333965Sjdp	if (tp->t_state >= TCPS_FIN_WAIT_2) {
157433965Sjdp		soisdisconnected(tp->t_inpcb->inp_socket);
157533965Sjdp		/* Prevent the connection hanging in FIN_WAIT_2 forever. */
157633965Sjdp		if (tp->t_state == TCPS_FIN_WAIT_2) {
157733965Sjdp			int timeout;
157833965Sjdp
157933965Sjdp			timeout = (tcp_fast_finwait2_recycle) ?
158033965Sjdp			    tcp_finwait2_timeout : tcp_maxidle;
158133965Sjdp			tcp_timer_activate(tp, TT_2MSL, timeout);
158233965Sjdp		}
158333965Sjdp	}
158433965Sjdp}
158533965Sjdp
158638889Sjdp#ifdef DDB
158738889Sjdpstatic void
158833965Sjdpdb_print_indent(int indent)
158933965Sjdp{
159033965Sjdp	int i;
159133965Sjdp
159233965Sjdp	for (i = 0; i < indent; i++)
159360484Sobrien		db_printf(" ");
1594104834Sobrien}
1595104834Sobrien
159633965Sjdpstatic void
159733965Sjdpdb_print_tstate(int t_state)
159833965Sjdp{
159933965Sjdp
160033965Sjdp	switch (t_state) {
160133965Sjdp	case TCPS_CLOSED:
160233965Sjdp		db_printf("TCPS_CLOSED");
160333965Sjdp		return;
160433965Sjdp
160533965Sjdp	case TCPS_LISTEN:
160633965Sjdp		db_printf("TCPS_LISTEN");
160733965Sjdp		return;
160838889Sjdp
160933965Sjdp	case TCPS_SYN_SENT:
161033965Sjdp		db_printf("TCPS_SYN_SENT");
161138889Sjdp		return;
161233965Sjdp
161338889Sjdp	case TCPS_SYN_RECEIVED:
161433965Sjdp		db_printf("TCPS_SYN_RECEIVED");
161533965Sjdp		return;
161638889Sjdp
161733965Sjdp	case TCPS_ESTABLISHED:
161860484Sobrien		db_printf("TCPS_ESTABLISHED");
1619104834Sobrien		return;
1620104834Sobrien
162133965Sjdp	case TCPS_CLOSE_WAIT:
162233965Sjdp		db_printf("TCPS_CLOSE_WAIT");
162333965Sjdp		return;
162433965Sjdp
162538889Sjdp	case TCPS_FIN_WAIT_1:
162638889Sjdp		db_printf("TCPS_FIN_WAIT_1");
162738889Sjdp		return;
162833965Sjdp
162933965Sjdp	case TCPS_CLOSING:
163038889Sjdp		db_printf("TCPS_CLOSING");
163133965Sjdp		return;
163233965Sjdp
163389857Sobrien	case TCPS_LAST_ACK:
163489857Sobrien		db_printf("TCPS_LAST_ACK");
163560484Sobrien		return;
163660484Sobrien
163760484Sobrien	case TCPS_FIN_WAIT_2:
163833965Sjdp		db_printf("TCPS_FIN_WAIT_2");
163960484Sobrien		return;
164060484Sobrien
164160484Sobrien	case TCPS_TIME_WAIT:
1642130561Sobrien		db_printf("TCPS_TIME_WAIT");
164360484Sobrien		return;
1644218822Sdim
164560484Sobrien	default:
164660484Sobrien		db_printf("unknown");
164760484Sobrien		return;
1648218822Sdim	}
164978828Sobrien}
165060484Sobrien
1651130561Sobrienstatic void
165260484Sobriendb_print_tflags(u_int t_flags)
165360484Sobrien{
165460484Sobrien	int comma;
165560484Sobrien
165660484Sobrien	comma = 0;
165760484Sobrien	if (t_flags & TF_ACKNOW) {
165860484Sobrien		db_printf("%sTF_ACKNOW", comma ? ", " : "");
165960484Sobrien		comma = 1;
166060484Sobrien	}
166160484Sobrien	if (t_flags & TF_DELACK) {
166233965Sjdp		db_printf("%sTF_DELACK", comma ? ", " : "");
166360484Sobrien		comma = 1;
166460484Sobrien	}
166560484Sobrien	if (t_flags & TF_NODELAY) {
166660484Sobrien		db_printf("%sTF_NODELAY", comma ? ", " : "");
166760484Sobrien		comma = 1;
166860484Sobrien	}
166960484Sobrien	if (t_flags & TF_NOOPT) {
167060484Sobrien		db_printf("%sTF_NOOPT", comma ? ", " : "");
1671130561Sobrien		comma = 1;
1672130561Sobrien	}
167360484Sobrien	if (t_flags & TF_SENTFIN) {
167460484Sobrien		db_printf("%sTF_SENTFIN", comma ? ", " : "");
167533965Sjdp		comma = 1;
167660484Sobrien	}
167760484Sobrien	if (t_flags & TF_REQ_SCALE) {
167860484Sobrien		db_printf("%sTF_REQ_SCALE", comma ? ", " : "");
167933965Sjdp		comma = 1;
168060484Sobrien	}
1681130561Sobrien	if (t_flags & TF_RCVD_SCALE) {
168233965Sjdp		db_printf("%sTF_RECVD_SCALE", comma ? ", " : "");
168333965Sjdp		comma = 1;
168433965Sjdp	}
168533965Sjdp	if (t_flags & TF_REQ_TSTMP) {
168633965Sjdp		db_printf("%sTF_REQ_TSTMP", comma ? ", " : "");
168733965Sjdp		comma = 1;
1688130561Sobrien	}
168933965Sjdp	if (t_flags & TF_RCVD_TSTMP) {
169033965Sjdp		db_printf("%sTF_RCVD_TSTMP", comma ? ", " : "");
169133965Sjdp		comma = 1;
169233965Sjdp	}
169333965Sjdp	if (t_flags & TF_SACK_PERMIT) {
169433965Sjdp		db_printf("%sTF_SACK_PERMIT", comma ? ", " : "");
169533965Sjdp		comma = 1;
1696130561Sobrien	}
1697130561Sobrien	if (t_flags & TF_NEEDSYN) {
1698130561Sobrien		db_printf("%sTF_NEEDSYN", comma ? ", " : "");
1699130561Sobrien		comma = 1;
1700130561Sobrien	}
1701130561Sobrien	if (t_flags & TF_NEEDFIN) {
170233965Sjdp		db_printf("%sTF_NEEDFIN", comma ? ", " : "");
170333965Sjdp		comma = 1;
170433965Sjdp	}
1705130561Sobrien	if (t_flags & TF_NOPUSH) {
1706130561Sobrien		db_printf("%sTF_NOPUSH", comma ? ", " : "");
1707130561Sobrien		comma = 1;
1708130561Sobrien	}
1709130561Sobrien	if (t_flags & TF_NOPUSH) {
1710130561Sobrien		db_printf("%sTF_NOPUSH", comma ? ", " : "");
1711130561Sobrien		comma = 1;
1712130561Sobrien	}
1713130561Sobrien	if (t_flags & TF_MORETOCOME) {
1714130561Sobrien		db_printf("%sTF_MORETOCOME", comma ? ", " : "");
171533965Sjdp		comma = 1;
171633965Sjdp	}
171733965Sjdp	if (t_flags & TF_LQ_OVERFLOW) {
171833965Sjdp		db_printf("%sTF_LQ_OVERFLOW", comma ? ", " : "");
171933965Sjdp		comma = 1;
172033965Sjdp	}
172133965Sjdp	if (t_flags & TF_LASTIDLE) {
172233965Sjdp		db_printf("%sTF_LASTIDLE", comma ? ", " : "");
1723130561Sobrien		comma = 1;
1724130561Sobrien	}
172533965Sjdp	if (t_flags & TF_RXWIN0SENT) {
172633965Sjdp		db_printf("%sTF_RXWIN0SENT", comma ? ", " : "");
172733965Sjdp		comma = 1;
172833965Sjdp	}
172933965Sjdp	if (t_flags & TF_FASTRECOVERY) {
173033965Sjdp		db_printf("%sTF_FASTRECOVERY", comma ? ", " : "");
173133965Sjdp		comma = 1;
173233965Sjdp	}
173333965Sjdp	if (t_flags & TF_WASFRECOVERY) {
173433965Sjdp		db_printf("%sTF_WASFRECOVERY", comma ? ", " : "");
173533965Sjdp		comma = 1;
173689857Sobrien	}
173733965Sjdp	if (t_flags & TF_SIGNATURE) {
173833965Sjdp		db_printf("%sTF_SIGNATURE", comma ? ", " : "");
173933965Sjdp		comma = 1;
174033965Sjdp	}
174133965Sjdp	if (t_flags & TF_FORCEDATA) {
174233965Sjdp		db_printf("%sTF_FORCEDATA", comma ? ", " : "");
174333965Sjdp		comma = 1;
174433965Sjdp	}
174560484Sobrien	if (t_flags & TF_TSO) {
174633965Sjdp		db_printf("%sTF_TSO", comma ? ", " : "");
174733965Sjdp		comma = 1;
1748130561Sobrien	}
1749130561Sobrien	if (t_flags & TF_ECN_PERMIT) {
1750130561Sobrien		db_printf("%sTF_ECN_PERMIT", comma ? ", " : "");
1751130561Sobrien		comma = 1;
175260484Sobrien	}
175333965Sjdp}
175433965Sjdp
175533965Sjdpstatic void
175633965Sjdpdb_print_toobflags(char t_oobflags)
175733965Sjdp{
175833965Sjdp	int comma;
175933965Sjdp
1760218822Sdim	comma = 0;
1761218822Sdim	if (t_oobflags & TCPOOB_HAVEDATA) {
1762218822Sdim		db_printf("%sTCPOOB_HAVEDATA", comma ? ", " : "");
1763218822Sdim		comma = 1;
1764218822Sdim	}
176533965Sjdp	if (t_oobflags & TCPOOB_HADDATA) {
176633965Sjdp		db_printf("%sTCPOOB_HADDATA", comma ? ", " : "");
176733965Sjdp		comma = 1;
176833965Sjdp	}
1769218822Sdim}
177033965Sjdp
177160484Sobrienstatic void
177260484Sobriendb_print_tcpcb(struct tcpcb *tp, const char *name, int indent)
177360484Sobrien{
1774130561Sobrien
177533965Sjdp	db_print_indent(indent);
177689857Sobrien	db_printf("%s at %p\n", name, tp);
177789857Sobrien
177889857Sobrien	indent += 2;
177989857Sobrien
1780218822Sdim	db_print_indent(indent);
1781218822Sdim	db_printf("t_segq first: %p   t_segqlen: %d   t_dupacks: %d\n",
1782218822Sdim	   LIST_FIRST(&tp->t_segq), tp->t_segqlen, tp->t_dupacks);
1783218822Sdim
1784218822Sdim	db_print_indent(indent);
1785218822Sdim	db_printf("tt_rexmt: %p   tt_persist: %p   tt_keep: %p\n",
1786218822Sdim	    &tp->t_timers->tt_rexmt, &tp->t_timers->tt_persist, &tp->t_timers->tt_keep);
1787218822Sdim
1788218822Sdim	db_print_indent(indent);
1789218822Sdim	db_printf("tt_2msl: %p   tt_delack: %p   t_inpcb: %p\n", &tp->t_timers->tt_2msl,
1790218822Sdim	    &tp->t_timers->tt_delack, tp->t_inpcb);
1791218822Sdim
1792218822Sdim	db_print_indent(indent);
1793218822Sdim	db_printf("t_state: %d (", tp->t_state);
1794218822Sdim	db_print_tstate(tp->t_state);
1795130561Sobrien	db_printf(")\n");
1796130561Sobrien
179733965Sjdp	db_print_indent(indent);
179833965Sjdp	db_printf("t_flags: 0x%x (", tp->t_flags);
179933965Sjdp	db_print_tflags(tp->t_flags);
1800218822Sdim	db_printf(")\n");
1801218822Sdim
1802218822Sdim	db_print_indent(indent);
1803218822Sdim	db_printf("snd_una: 0x%08x   snd_max: 0x%08x   snd_nxt: x0%08x\n",
180433965Sjdp	    tp->snd_una, tp->snd_max, tp->snd_nxt);
180533965Sjdp
1806218822Sdim	db_print_indent(indent);
1807218822Sdim	db_printf("snd_up: 0x%08x   snd_wl1: 0x%08x   snd_wl2: 0x%08x\n",
180833965Sjdp	   tp->snd_up, tp->snd_wl1, tp->snd_wl2);
180933965Sjdp
181033965Sjdp	db_print_indent(indent);
181133965Sjdp	db_printf("iss: 0x%08x   irs: 0x%08x   rcv_nxt: 0x%08x\n",
181291041Sobrien	    tp->iss, tp->irs, tp->rcv_nxt);
181333965Sjdp
181433965Sjdp	db_print_indent(indent);
181533965Sjdp	db_printf("rcv_adv: 0x%08x   rcv_wnd: %lu   rcv_up: 0x%08x\n",
181633965Sjdp	    tp->rcv_adv, tp->rcv_wnd, tp->rcv_up);
1817218822Sdim
181833965Sjdp	db_print_indent(indent);
181933965Sjdp	db_printf("snd_wnd: %lu   snd_cwnd: %lu   snd_bwnd: %lu\n",
1820218822Sdim	   tp->snd_wnd, tp->snd_cwnd, tp->snd_bwnd);
1821218822Sdim
1822218822Sdim	db_print_indent(indent);
1823218822Sdim	db_printf("snd_ssthresh: %lu   snd_bandwidth: %lu   snd_recover: "
1824130561Sobrien	    "0x%08x\n", tp->snd_ssthresh, tp->snd_bandwidth,
182533965Sjdp	    tp->snd_recover);
182633965Sjdp
182733965Sjdp	db_print_indent(indent);
182833965Sjdp	db_printf("t_maxopd: %u   t_rcvtime: %lu   t_startime: %lu\n",
182933965Sjdp	    tp->t_maxopd, tp->t_rcvtime, tp->t_starttime);
183089857Sobrien
183189857Sobrien	db_print_indent(indent);
183289857Sobrien	db_printf("t_rttime: %d   t_rtsq: 0x%08x   t_bw_rtttime: %d\n",
183389857Sobrien	    tp->t_rtttime, tp->t_rtseq, tp->t_bw_rtttime);
1834130561Sobrien
183533965Sjdp	db_print_indent(indent);
183691041Sobrien	db_printf("t_bw_rtseq: 0x%08x   t_rxtcur: %d   t_maxseg: %u   "
183791041Sobrien	    "t_srtt: %d\n", tp->t_bw_rtseq, tp->t_rxtcur, tp->t_maxseg,
183833965Sjdp	    tp->t_srtt);
183960484Sobrien
184060484Sobrien	db_print_indent(indent);
1841130561Sobrien	db_printf("t_rttvar: %d   t_rxtshift: %d   t_rttmin: %u   "
184233965Sjdp	    "t_rttbest: %u\n", tp->t_rttvar, tp->t_rxtshift, tp->t_rttmin,
184391041Sobrien	    tp->t_rttbest);
184491041Sobrien
184591041Sobrien	db_print_indent(indent);
184691041Sobrien	db_printf("t_rttupdated: %lu   max_sndwnd: %lu   t_softerror: %d\n",
184791041Sobrien	    tp->t_rttupdated, tp->max_sndwnd, tp->t_softerror);
184891041Sobrien
184991041Sobrien	db_print_indent(indent);
1850218822Sdim	db_printf("t_oobflags: 0x%x (", tp->t_oobflags);
1851218822Sdim	db_print_toobflags(tp->t_oobflags);
1852218822Sdim	db_printf(")   t_iobc: 0x%02x\n", tp->t_iobc);
1853218822Sdim
1854130561Sobrien	db_print_indent(indent);
1855130561Sobrien	db_printf("snd_scale: %u   rcv_scale: %u   request_r_scale: %u\n",
185691041Sobrien	    tp->snd_scale, tp->rcv_scale, tp->request_r_scale);
185791041Sobrien
185891041Sobrien	db_print_indent(indent);
185991041Sobrien	db_printf("ts_recent: %u   ts_recent_age: %lu\n",
186091041Sobrien	    tp->ts_recent, tp->ts_recent_age);
186191041Sobrien
186291041Sobrien	db_print_indent(indent);
186391041Sobrien	db_printf("ts_offset: %u   last_ack_sent: 0x%08x   snd_cwnd_prev: "
186460484Sobrien	    "%lu\n", tp->ts_offset, tp->last_ack_sent, tp->snd_cwnd_prev);
186560484Sobrien
186660484Sobrien	db_print_indent(indent);
186789857Sobrien	db_printf("snd_ssthresh_prev: %lu   snd_recover_prev: 0x%08x   "
186860484Sobrien	    "t_badrxtwin: %lu\n", tp->snd_ssthresh_prev,
186960484Sobrien	    tp->snd_recover_prev, tp->t_badrxtwin);
187060484Sobrien
187160484Sobrien	db_print_indent(indent);
187260484Sobrien	db_printf("snd_numholes: %d  snd_holes first: %p\n",
1873130561Sobrien	    tp->snd_numholes, TAILQ_FIRST(&tp->snd_holes));
187433965Sjdp
187533965Sjdp	db_print_indent(indent);
1876218822Sdim	db_printf("snd_fack: 0x%08x   rcv_numsacks: %d   sack_newdata: "
187733965Sjdp	    "0x%08x\n", tp->snd_fack, tp->rcv_numsacks, tp->sack_newdata);
187833965Sjdp
1879130561Sobrien	/* Skip sackblks, sackhint. */
1880218822Sdim
1881218822Sdim	db_print_indent(indent);
1882218822Sdim	db_printf("t_rttlow: %d   rfbuf_ts: %u   rfbuf_cnt: %d\n",
1883218822Sdim	    tp->t_rttlow, tp->rfbuf_ts, tp->rfbuf_cnt);
1884218822Sdim}
1885218822Sdim
1886218822SdimDB_SHOW_COMMAND(tcpcb, db_show_tcpcb)
188760484Sobrien{
1888218822Sdim	struct tcpcb *tp;
1889218822Sdim
1890218822Sdim	if (!have_addr) {
1891218822Sdim		db_printf("usage: show tcpcb <addr>\n");
1892218822Sdim		return;
1893218822Sdim	}
1894218822Sdim	tp = (struct tcpcb *)addr;
1895218822Sdim
1896218822Sdim	db_print_tcpcb(tp, "tcpcb", 0);
1897218822Sdim}
1898218822Sdim#endif
1899218822Sdim