1139823Simp/*- 21541Srgrimes * Copyright (c) 1982, 1986, 1988, 1993 3157376Srwatson * The Regents of the University of California. 4166807Srwatson * Copyright (c) 2006-2007 Robert N. M. Watson 5222488Srwatson * Copyright (c) 2010-2011 Juniper Networks, Inc. 6157376Srwatson * All rights reserved. 71541Srgrimes * 8222488Srwatson * Portions of this software were developed by Robert N. M. Watson under 9222488Srwatson * contract to Juniper Networks, Inc. 10222488Srwatson * 111541Srgrimes * Redistribution and use in source and binary forms, with or without 121541Srgrimes * modification, are permitted provided that the following conditions 131541Srgrimes * are met: 141541Srgrimes * 1. Redistributions of source code must retain the above copyright 151541Srgrimes * notice, this list of conditions and the following disclaimer. 161541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171541Srgrimes * notice, this list of conditions and the following disclaimer in the 181541Srgrimes * documentation and/or other materials provided with the distribution. 191541Srgrimes * 4. Neither the name of the University nor the names of its contributors 201541Srgrimes * may be used to endorse or promote products derived from this software 211541Srgrimes * without specific prior written permission. 221541Srgrimes * 231541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 241541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 251541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 261541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 271541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 281541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 291541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 301541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 311541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 321541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 331541Srgrimes * SUCH DAMAGE. 341541Srgrimes * 356481Swollman * From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94 361541Srgrimes */ 371541Srgrimes 38172467Ssilby#include <sys/cdefs.h> 39172467Ssilby__FBSDID("$FreeBSD: stable/10/sys/netinet/tcp_usrreq.c 338985 2018-09-27 18:48:50Z gordon $"); 40172467Ssilby 41166807Srwatson#include "opt_ddb.h" 42125680Sbms#include "opt_inet.h" 4355679Sshin#include "opt_inet6.h" 4429514Sjoerg#include "opt_tcpdebug.h" 4529514Sjoerg 461541Srgrimes#include <sys/param.h> 471541Srgrimes#include <sys/systm.h> 48231025Sglebius#include <sys/limits.h> 4998102Shsu#include <sys/malloc.h> 506510Swollman#include <sys/kernel.h> 5112172Sphk#include <sys/sysctl.h> 521541Srgrimes#include <sys/mbuf.h> 5355679Sshin#ifdef INET6 5455679Sshin#include <sys/domain.h> 5555679Sshin#endif /* INET6 */ 561541Srgrimes#include <sys/socket.h> 571541Srgrimes#include <sys/socketvar.h> 581541Srgrimes#include <sys/protosw.h> 5972786Srwatson#include <sys/proc.h> 6072786Srwatson#include <sys/jail.h> 61307906Sjch#include <sys/syslog.h> 621541Srgrimes 63166807Srwatson#ifdef DDB 64166807Srwatson#include <ddb/ddb.h> 65166807Srwatson#endif 66166807Srwatson 671541Srgrimes#include <net/if.h> 681541Srgrimes#include <net/route.h> 69196019Srwatson#include <net/vnet.h> 701541Srgrimes 71215166Slstewart#include <netinet/cc.h> 721541Srgrimes#include <netinet/in.h> 73221250Sbz#include <netinet/in_pcb.h> 741541Srgrimes#include <netinet/in_systm.h> 75221250Sbz#include <netinet/in_var.h> 76221250Sbz#include <netinet/ip_var.h> 7755679Sshin#ifdef INET6 7855679Sshin#include <netinet/ip6.h> 7955679Sshin#include <netinet6/in6_pcb.h> 8055679Sshin#include <netinet6/ip6_var.h> 81148385Sume#include <netinet6/scope6_var.h> 8255679Sshin#endif 83292823Spkelsey#ifdef TCP_RFC7413 84292823Spkelsey#include <netinet/tcp_fastopen.h> 85292823Spkelsey#endif 861541Srgrimes#include <netinet/tcp_fsm.h> 871541Srgrimes#include <netinet/tcp_seq.h> 881541Srgrimes#include <netinet/tcp_timer.h> 891541Srgrimes#include <netinet/tcp_var.h> 901541Srgrimes#include <netinet/tcpip.h> 912788Sdg#ifdef TCPDEBUG 921541Srgrimes#include <netinet/tcp_debug.h> 932788Sdg#endif 94237263Snp#ifdef TCP_OFFLOAD 95174757Skmacy#include <netinet/tcp_offload.h> 96237263Snp#endif 971541Srgrimes 981541Srgrimes/* 991541Srgrimes * TCP protocol interface to socket abstraction. 1001541Srgrimes */ 101127526Spjdstatic int tcp_attach(struct socket *); 102221250Sbz#ifdef INET 10393085Sbdestatic int tcp_connect(struct tcpcb *, struct sockaddr *, 10493085Sbde struct thread *td); 105221250Sbz#endif /* INET */ 10655679Sshin#ifdef INET6 10792723Salfredstatic int tcp6_connect(struct tcpcb *, struct sockaddr *, 10893085Sbde struct thread *td); 10955679Sshin#endif /* INET6 */ 110157376Srwatsonstatic void tcp_disconnect(struct tcpcb *); 111157376Srwatsonstatic void tcp_usrclosed(struct tcpcb *); 112138118Srwatsonstatic void tcp_fill_info(struct tcpcb *, struct tcp_info *); 11317096Swollman 1146283Swollman#ifdef TCPDEBUG 11574134Sjlemon#define TCPDEBUG0 int ostate = 0 11617096Swollman#define TCPDEBUG1() ostate = tp ? tp->t_state : 0 11797658Stanimura#define TCPDEBUG2(req) if (tp && (so->so_options & SO_DEBUG)) \ 11897658Stanimura tcp_trace(TA_USER, ostate, tp, 0, 0, req) 11917096Swollman#else 12017096Swollman#define TCPDEBUG0 12117096Swollman#define TCPDEBUG1() 12217096Swollman#define TCPDEBUG2(req) 12317096Swollman#endif 12417096Swollman 1256283Swollman/* 12617096Swollman * TCP attaches to socket via pru_attach(), reserving space, 12717096Swollman * and an internet control block. 12817096Swollman */ 12917096Swollmanstatic int 13083366Sjuliantcp_usr_attach(struct socket *so, int proto, struct thread *td) 13117096Swollman{ 132157376Srwatson struct inpcb *inp; 133157376Srwatson struct tcpcb *tp = NULL; 13417096Swollman int error; 13517096Swollman TCPDEBUG0; 13617096Swollman 137157376Srwatson inp = sotoinpcb(so); 138157376Srwatson KASSERT(inp == NULL, ("tcp_usr_attach: inp != NULL")); 13917096Swollman TCPDEBUG1(); 14017096Swollman 141127526Spjd error = tcp_attach(so); 14217096Swollman if (error) 14317096Swollman goto out; 14417096Swollman 14517096Swollman if ((so->so_options & SO_LINGER) && so->so_linger == 0) 14646016Sache so->so_linger = TCP_LINGERTIME; 14798102Shsu 14898102Shsu inp = sotoinpcb(so); 14998102Shsu tp = intotcpcb(inp); 15017096Swollmanout: 15117096Swollman TCPDEBUG2(PRU_ATTACH); 15217096Swollman return error; 15317096Swollman} 15417096Swollman 15517096Swollman/* 156160549Srwatson * tcp_detach is called when the socket layer loses its final reference 157160549Srwatson * to the socket, be it a file descriptor reference, a reference from TCP, 158160549Srwatson * etc. At this point, there is only one case in which we will keep around 159160549Srwatson * inpcb state: time wait. 160157993Srwatson * 161160549Srwatson * This function can probably be re-absorbed back into tcp_usr_detach() now 162160549Srwatson * that there is a single detach path. 16317096Swollman */ 164157370Srwatsonstatic void 165157993Srwatsontcp_detach(struct socket *so, struct inpcb *inp) 16617096Swollman{ 16717096Swollman struct tcpcb *tp; 16817096Swollman 169309108Sjch INP_INFO_LOCK_ASSERT(&V_tcbinfo); 170178285Srwatson INP_WLOCK_ASSERT(inp); 17117096Swollman 172157993Srwatson KASSERT(so->so_pcb == inp, ("tcp_detach: so_pcb != inp")); 173157993Srwatson KASSERT(inp->inp_socket == so, ("tcp_detach: inp_socket != so")); 174157410Srwatson 175160549Srwatson tp = intotcpcb(inp); 176160549Srwatson 177189848Srwatson if (inp->inp_flags & INP_TIMEWAIT) { 178160549Srwatson /* 179160549Srwatson * There are two cases to handle: one in which the time wait 180160549Srwatson * state is being discarded (INP_DROPPED), and one in which 181160549Srwatson * this connection will remain in timewait. In the former, 182160549Srwatson * it is time to discard all state (except tcptw, which has 183160549Srwatson * already been discarded by the timewait close code, which 184160549Srwatson * should be further up the call stack somewhere). In the 185160549Srwatson * latter case, we detach from the socket, but leave the pcb 186160549Srwatson * present until timewait ends. 187160549Srwatson * 188160549Srwatson * XXXRW: Would it be cleaner to free the tcptw here? 189275402Sjch * 190275402Sjch * Astute question indeed, from twtcp perspective there are 191275402Sjch * three cases to consider: 192275402Sjch * 193275402Sjch * #1 tcp_detach is called at tcptw creation time by 194275402Sjch * tcp_twstart, then do not discard the newly created tcptw 195275402Sjch * and leave inpcb present until timewait ends 196275402Sjch * #2 tcp_detach is called at timewait end (or reuse) by 197275402Sjch * tcp_twclose, then the tcptw has already been discarded 198309108Sjch * (or reused) and inpcb is freed here 199275402Sjch * #3 tcp_detach is called() after timewait ends (or reuse) 200275402Sjch * (e.g. by soclose), then tcptw has already been discarded 201309108Sjch * (or reused) and inpcb is freed here 202275402Sjch * 203275402Sjch * In all three cases the tcptw should not be freed here. 204160549Srwatson */ 205189848Srwatson if (inp->inp_flags & INP_DROPPED) { 206185344Sbz in_pcbdetach(inp); 207307906Sjch if (__predict_true(tp == NULL)) { 208307906Sjch in_pcbfree(inp); 209307906Sjch } else { 210307906Sjch /* 211307906Sjch * This case should not happen as in TIMEWAIT 212307906Sjch * state the inp should not be destroyed before 213307906Sjch * its tcptw. If INVARIANTS is defined, panic. 214307906Sjch */ 215307906Sjch#ifdef INVARIANTS 216307906Sjch panic("%s: Panic before an inp double-free: " 217307906Sjch "INP_TIMEWAIT && INP_DROPPED && tp != NULL" 218307906Sjch , __func__); 219307906Sjch#else 220307906Sjch log(LOG_ERR, "%s: Avoid an inp double-free: " 221307906Sjch "INP_TIMEWAIT && INP_DROPPED && tp != NULL" 222307906Sjch , __func__); 223307906Sjch#endif 224307906Sjch INP_WUNLOCK(inp); 225307906Sjch } 226157376Srwatson } else { 227185344Sbz in_pcbdetach(inp); 228178285Srwatson INP_WUNLOCK(inp); 229157376Srwatson } 230157376Srwatson } else { 231157429Srwatson /* 232160549Srwatson * If the connection is not in timewait, we consider two 233160549Srwatson * two conditions: one in which no further processing is 234160549Srwatson * necessary (dropped || embryonic), and one in which TCP is 235160549Srwatson * not yet done, but no longer requires the socket, so the 236160549Srwatson * pcb will persist for the time being. 237160549Srwatson * 238160549Srwatson * XXXRW: Does the second case still occur? 239157429Srwatson */ 240189848Srwatson if (inp->inp_flags & INP_DROPPED || 241157376Srwatson tp->t_state < TCPS_SYN_SENT) { 242157376Srwatson tcp_discardcb(tp); 243185344Sbz in_pcbdetach(inp); 244185370Sbz in_pcbfree(inp); 245229714Snp } else { 246185370Sbz in_pcbdetach(inp); 247229714Snp INP_WUNLOCK(inp); 248229714Snp } 249157376Srwatson } 250157993Srwatson} 251157993Srwatson 252157993Srwatson/* 253157993Srwatson * pru_detach() detaches the TCP protocol from the socket. 254157993Srwatson * If the protocol state is non-embryonic, then can't 255157993Srwatson * do this directly: have to initiate a pru_disconnect(), 256157993Srwatson * which may finish later; embryonic TCB's can just 257157993Srwatson * be discarded here. 258157993Srwatson */ 259157993Srwatsonstatic void 260157993Srwatsontcp_usr_detach(struct socket *so) 261157993Srwatson{ 262157993Srwatson struct inpcb *inp; 263309108Sjch int rlock = 0; 264157993Srwatson 265157993Srwatson inp = sotoinpcb(so); 266157993Srwatson KASSERT(inp != NULL, ("tcp_usr_detach: inp == NULL")); 267309108Sjch if (!INP_INFO_WLOCKED(&V_tcbinfo)) { 268309108Sjch INP_INFO_RLOCK(&V_tcbinfo); 269309108Sjch rlock = 1; 270309108Sjch } 271178285Srwatson INP_WLOCK(inp); 272157993Srwatson KASSERT(inp->inp_socket != NULL, 273157993Srwatson ("tcp_usr_detach: inp_socket == NULL")); 274157993Srwatson tcp_detach(so, inp); 275309108Sjch if (rlock) 276309108Sjch INP_INFO_RUNLOCK(&V_tcbinfo); 27717096Swollman} 27817096Swollman 279221250Sbz#ifdef INET 28017096Swollman/* 28117096Swollman * Give the socket an address. 28217096Swollman */ 28317096Swollmanstatic int 28483366Sjuliantcp_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 28517096Swollman{ 28617096Swollman int error = 0; 28798102Shsu struct inpcb *inp; 288157376Srwatson struct tcpcb *tp = NULL; 28917096Swollman struct sockaddr_in *sinp; 29017096Swollman 291127862Spjd sinp = (struct sockaddr_in *)nam; 292127862Spjd if (nam->sa_len != sizeof (*sinp)) 293127862Spjd return (EINVAL); 29417096Swollman /* 29517096Swollman * Must check for multicast addresses and disallow binding 29617096Swollman * to them. 29717096Swollman */ 29817096Swollman if (sinp->sin_family == AF_INET && 299127862Spjd IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) 300127862Spjd return (EAFNOSUPPORT); 301127862Spjd 302157376Srwatson TCPDEBUG0; 303157376Srwatson inp = sotoinpcb(so); 304157376Srwatson KASSERT(inp != NULL, ("tcp_usr_bind: inp == NULL")); 305178285Srwatson INP_WLOCK(inp); 306189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 307157376Srwatson error = EINVAL; 308157376Srwatson goto out; 309157376Srwatson } 310157376Srwatson tp = intotcpcb(inp); 311157376Srwatson TCPDEBUG1(); 312222488Srwatson INP_HASH_WLOCK(&V_tcbinfo); 313127505Spjd error = in_pcbbind(inp, nam, td->td_ucred); 314222488Srwatson INP_HASH_WUNLOCK(&V_tcbinfo); 315157376Srwatsonout: 316157376Srwatson TCPDEBUG2(PRU_BIND); 317178285Srwatson INP_WUNLOCK(inp); 318157376Srwatson 319157376Srwatson return (error); 32017096Swollman} 321221250Sbz#endif /* INET */ 32217096Swollman 32355679Sshin#ifdef INET6 32455679Sshinstatic int 32583366Sjuliantcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 32655679Sshin{ 32755679Sshin int error = 0; 32898102Shsu struct inpcb *inp; 329157376Srwatson struct tcpcb *tp = NULL; 33055679Sshin struct sockaddr_in6 *sin6p; 331338985Sgordon u_char vflagsav; 33255679Sshin 333127862Spjd sin6p = (struct sockaddr_in6 *)nam; 334127862Spjd if (nam->sa_len != sizeof (*sin6p)) 335127862Spjd return (EINVAL); 33655679Sshin /* 33755679Sshin * Must check for multicast addresses and disallow binding 33855679Sshin * to them. 33955679Sshin */ 34055679Sshin if (sin6p->sin6_family == AF_INET6 && 341127862Spjd IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) 342127862Spjd return (EAFNOSUPPORT); 343127862Spjd 344157376Srwatson TCPDEBUG0; 345157376Srwatson inp = sotoinpcb(so); 346157376Srwatson KASSERT(inp != NULL, ("tcp6_usr_bind: inp == NULL")); 347178285Srwatson INP_WLOCK(inp); 348338985Sgordon vflagsav = inp->inp_vflag; 349189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 350157376Srwatson error = EINVAL; 351157376Srwatson goto out; 352157376Srwatson } 353157376Srwatson tp = intotcpcb(inp); 354157376Srwatson TCPDEBUG1(); 355222488Srwatson INP_HASH_WLOCK(&V_tcbinfo); 35655679Sshin inp->inp_vflag &= ~INP_IPV4; 35755679Sshin inp->inp_vflag |= INP_IPV6; 358221250Sbz#ifdef INET 359100685Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 36055679Sshin if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr)) 36155679Sshin inp->inp_vflag |= INP_IPV4; 36255679Sshin else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { 36355679Sshin struct sockaddr_in sin; 36455679Sshin 36555679Sshin in6_sin6_2_sin(&sin, sin6p); 36655679Sshin inp->inp_vflag |= INP_IPV4; 36755679Sshin inp->inp_vflag &= ~INP_IPV6; 368127505Spjd error = in_pcbbind(inp, (struct sockaddr *)&sin, 369127505Spjd td->td_ucred); 370222488Srwatson INP_HASH_WUNLOCK(&V_tcbinfo); 37155679Sshin goto out; 37255679Sshin } 37355679Sshin } 374221250Sbz#endif 375127505Spjd error = in6_pcbbind(inp, nam, td->td_ucred); 376222488Srwatson INP_HASH_WUNLOCK(&V_tcbinfo); 377157376Srwatsonout: 378338985Sgordon if (error != 0) 379338985Sgordon inp->inp_vflag = vflagsav; 380157376Srwatson TCPDEBUG2(PRU_BIND); 381178285Srwatson INP_WUNLOCK(inp); 382157376Srwatson return (error); 38355679Sshin} 38455679Sshin#endif /* INET6 */ 38555679Sshin 386221250Sbz#ifdef INET 38717096Swollman/* 38817096Swollman * Prepare to accept connections. 38917096Swollman */ 39017096Swollmanstatic int 391151888Srwatsontcp_usr_listen(struct socket *so, int backlog, struct thread *td) 39217096Swollman{ 39317096Swollman int error = 0; 39498102Shsu struct inpcb *inp; 395157376Srwatson struct tcpcb *tp = NULL; 39617096Swollman 397157376Srwatson TCPDEBUG0; 398157376Srwatson inp = sotoinpcb(so); 399157376Srwatson KASSERT(inp != NULL, ("tcp_usr_listen: inp == NULL")); 400178285Srwatson INP_WLOCK(inp); 401189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 402157376Srwatson error = EINVAL; 403157376Srwatson goto out; 404157376Srwatson } 405157376Srwatson tp = intotcpcb(inp); 406157376Srwatson TCPDEBUG1(); 407142190Srwatson SOCK_LOCK(so); 408142190Srwatson error = solisten_proto_check(so); 409222488Srwatson INP_HASH_WLOCK(&V_tcbinfo); 410142190Srwatson if (error == 0 && inp->inp_lport == 0) 411127505Spjd error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); 412222488Srwatson INP_HASH_WUNLOCK(&V_tcbinfo); 413142190Srwatson if (error == 0) { 414254889Smarkj tcp_state_change(tp, TCPS_LISTEN); 415151888Srwatson solisten_proto(so, backlog); 416237263Snp#ifdef TCP_OFFLOAD 417245915Snp if ((so->so_options & SO_NO_OFFLOAD) == 0) 418245915Snp tcp_offload_listen_start(tp); 419237263Snp#endif 420142190Srwatson } 421142190Srwatson SOCK_UNLOCK(so); 422157376Srwatson 423292823Spkelsey#ifdef TCP_RFC7413 424292823Spkelsey if (tp->t_flags & TF_FASTOPEN) 425292823Spkelsey tp->t_tfo_pending = tcp_fastopen_alloc_counter(); 426292823Spkelsey#endif 427157376Srwatsonout: 428157376Srwatson TCPDEBUG2(PRU_LISTEN); 429178285Srwatson INP_WUNLOCK(inp); 430157376Srwatson return (error); 43117096Swollman} 432221250Sbz#endif /* INET */ 43317096Swollman 43455679Sshin#ifdef INET6 43555679Sshinstatic int 436151888Srwatsontcp6_usr_listen(struct socket *so, int backlog, struct thread *td) 43755679Sshin{ 43855679Sshin int error = 0; 43998102Shsu struct inpcb *inp; 440157376Srwatson struct tcpcb *tp = NULL; 441338985Sgordon u_char vflagsav; 44255679Sshin 443157376Srwatson TCPDEBUG0; 444157376Srwatson inp = sotoinpcb(so); 445157376Srwatson KASSERT(inp != NULL, ("tcp6_usr_listen: inp == NULL")); 446178285Srwatson INP_WLOCK(inp); 447189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 448157376Srwatson error = EINVAL; 449157376Srwatson goto out; 450157376Srwatson } 451338985Sgordon vflagsav = inp->inp_vflag; 452157376Srwatson tp = intotcpcb(inp); 453157376Srwatson TCPDEBUG1(); 454142190Srwatson SOCK_LOCK(so); 455142190Srwatson error = solisten_proto_check(so); 456222488Srwatson INP_HASH_WLOCK(&V_tcbinfo); 457142190Srwatson if (error == 0 && inp->inp_lport == 0) { 45855679Sshin inp->inp_vflag &= ~INP_IPV4; 459100685Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) 46055679Sshin inp->inp_vflag |= INP_IPV4; 461127505Spjd error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); 46255679Sshin } 463222488Srwatson INP_HASH_WUNLOCK(&V_tcbinfo); 464142190Srwatson if (error == 0) { 465254889Smarkj tcp_state_change(tp, TCPS_LISTEN); 466151888Srwatson solisten_proto(so, backlog); 467237263Snp#ifdef TCP_OFFLOAD 468245915Snp if ((so->so_options & SO_NO_OFFLOAD) == 0) 469245915Snp tcp_offload_listen_start(tp); 470237263Snp#endif 471142190Srwatson } 472142190Srwatson SOCK_UNLOCK(so); 473157376Srwatson 474292823Spkelsey#ifdef TCP_RFC7413 475292823Spkelsey if (tp->t_flags & TF_FASTOPEN) 476292823Spkelsey tp->t_tfo_pending = tcp_fastopen_alloc_counter(); 477292823Spkelsey#endif 478338985Sgordon if (error != 0) 479338985Sgordon inp->inp_vflag = vflagsav; 480338985Sgordon 481157376Srwatsonout: 482157376Srwatson TCPDEBUG2(PRU_LISTEN); 483178285Srwatson INP_WUNLOCK(inp); 484157376Srwatson return (error); 48555679Sshin} 48655679Sshin#endif /* INET6 */ 48755679Sshin 488221250Sbz#ifdef INET 48917096Swollman/* 49017096Swollman * Initiate connection to peer. 49117096Swollman * Create a template for use in transmissions on this connection. 49217096Swollman * Enter SYN_SENT state, and mark socket as connecting. 49317096Swollman * Start keep-alive timer, and seed output sequence space. 49417096Swollman * Send initial segment on connection. 49517096Swollman */ 49617096Swollmanstatic int 49783366Sjuliantcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 49817096Swollman{ 49917096Swollman int error = 0; 50098102Shsu struct inpcb *inp; 501157376Srwatson struct tcpcb *tp = NULL; 50217096Swollman struct sockaddr_in *sinp; 50317096Swollman 504127862Spjd sinp = (struct sockaddr_in *)nam; 505127862Spjd if (nam->sa_len != sizeof (*sinp)) 506127862Spjd return (EINVAL); 50717096Swollman /* 50817096Swollman * Must disallow TCP ``connections'' to multicast addresses. 50917096Swollman */ 51017096Swollman if (sinp->sin_family == AF_INET 511127862Spjd && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) 512127862Spjd return (EAFNOSUPPORT); 513188144Sjamie if ((error = prison_remote_ip4(td->td_ucred, &sinp->sin_addr)) != 0) 514188144Sjamie return (error); 51546155Sphk 516157376Srwatson TCPDEBUG0; 517157376Srwatson inp = sotoinpcb(so); 518157376Srwatson KASSERT(inp != NULL, ("tcp_usr_connect: inp == NULL")); 519178285Srwatson INP_WLOCK(inp); 520282968Sjch if (inp->inp_flags & INP_TIMEWAIT) { 521282968Sjch error = EADDRINUSE; 522157376Srwatson goto out; 523157376Srwatson } 524282968Sjch if (inp->inp_flags & INP_DROPPED) { 525282968Sjch error = ECONNREFUSED; 526282968Sjch goto out; 527282968Sjch } 528157376Srwatson tp = intotcpcb(inp); 529157376Srwatson TCPDEBUG1(); 53083366Sjulian if ((error = tcp_connect(tp, nam, td)) != 0) 53117096Swollman goto out; 532237263Snp#ifdef TCP_OFFLOAD 533237263Snp if (registered_toedevs > 0 && 534245915Snp (so->so_options & SO_NO_OFFLOAD) == 0 && 535237263Snp (error = tcp_offload_connect(so, nam)) == 0) 536237263Snp goto out; 537237263Snp#endif 538237263Snp tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); 539237263Snp error = tcp_output(tp); 540157376Srwatsonout: 541157376Srwatson TCPDEBUG2(PRU_CONNECT); 542178285Srwatson INP_WUNLOCK(inp); 543157376Srwatson return (error); 54417096Swollman} 545221250Sbz#endif /* INET */ 54617096Swollman 54755679Sshin#ifdef INET6 54855679Sshinstatic int 54983366Sjuliantcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 55055679Sshin{ 55155679Sshin int error = 0; 55298102Shsu struct inpcb *inp; 553157376Srwatson struct tcpcb *tp = NULL; 55455679Sshin struct sockaddr_in6 *sin6p; 555338985Sgordon u_int8_t incflagsav; 556338985Sgordon u_char vflagsav; 55755679Sshin 558157376Srwatson TCPDEBUG0; 559157376Srwatson 560127862Spjd sin6p = (struct sockaddr_in6 *)nam; 561127862Spjd if (nam->sa_len != sizeof (*sin6p)) 562127862Spjd return (EINVAL); 56355679Sshin /* 56455679Sshin * Must disallow TCP ``connections'' to multicast addresses. 56555679Sshin */ 56655679Sshin if (sin6p->sin6_family == AF_INET6 567127862Spjd && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) 568127862Spjd return (EAFNOSUPPORT); 56955679Sshin 570157376Srwatson inp = sotoinpcb(so); 571157376Srwatson KASSERT(inp != NULL, ("tcp6_usr_connect: inp == NULL")); 572178285Srwatson INP_WLOCK(inp); 573338985Sgordon vflagsav = inp->inp_vflag; 574338985Sgordon incflagsav = inp->inp_inc.inc_flags; 575282968Sjch if (inp->inp_flags & INP_TIMEWAIT) { 576282968Sjch error = EADDRINUSE; 577157376Srwatson goto out; 578157376Srwatson } 579282968Sjch if (inp->inp_flags & INP_DROPPED) { 580282968Sjch error = ECONNREFUSED; 581282968Sjch goto out; 582282968Sjch } 583157376Srwatson tp = intotcpcb(inp); 584157376Srwatson TCPDEBUG1(); 585221250Sbz#ifdef INET 586222488Srwatson /* 587222488Srwatson * XXXRW: Some confusion: V4/V6 flags relate to binding, and 588222488Srwatson * therefore probably require the hash lock, which isn't held here. 589222488Srwatson * Is this a significant problem? 590222488Srwatson */ 59178064Sume if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { 59255679Sshin struct sockaddr_in sin; 59355679Sshin 594100871Smaxim if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) { 595100871Smaxim error = EINVAL; 596100871Smaxim goto out; 597100871Smaxim } 59878064Sume 59955679Sshin in6_sin6_2_sin(&sin, sin6p); 600188144Sjamie if ((error = prison_remote_ip4(td->td_ucred, 601188144Sjamie &sin.sin_addr)) != 0) 602185435Sbz goto out; 603338985Sgordon inp->inp_vflag |= INP_IPV4; 604338985Sgordon inp->inp_vflag &= ~INP_IPV6; 60583366Sjulian if ((error = tcp_connect(tp, (struct sockaddr *)&sin, td)) != 0) 60655679Sshin goto out; 607237263Snp#ifdef TCP_OFFLOAD 608237263Snp if (registered_toedevs > 0 && 609245934Snp (so->so_options & SO_NO_OFFLOAD) == 0 && 610237263Snp (error = tcp_offload_connect(so, nam)) == 0) 611237263Snp goto out; 612237263Snp#endif 613237263Snp error = tcp_output(tp); 61455679Sshin goto out; 61555679Sshin } 616221250Sbz#endif 617338985Sgordon if ((error = prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr)) != 0) 618338985Sgordon goto out; 61955679Sshin inp->inp_vflag &= ~INP_IPV4; 62055679Sshin inp->inp_vflag |= INP_IPV6; 621186222Sbz inp->inp_inc.inc_flags |= INC_ISIPV6; 62283366Sjulian if ((error = tcp6_connect(tp, nam, td)) != 0) 62355679Sshin goto out; 624237263Snp#ifdef TCP_OFFLOAD 625237263Snp if (registered_toedevs > 0 && 626245934Snp (so->so_options & SO_NO_OFFLOAD) == 0 && 627237263Snp (error = tcp_offload_connect(so, nam)) == 0) 628237263Snp goto out; 629237263Snp#endif 630237263Snp tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); 631237263Snp error = tcp_output(tp); 632157376Srwatson 633157376Srwatsonout: 634338985Sgordon /* 635338985Sgordon * If the implicit bind in the connect call fails, restore 636338985Sgordon * the flags we modified. 637338985Sgordon */ 638338985Sgordon if (error != 0 && inp->inp_lport == 0) { 639338985Sgordon inp->inp_vflag = vflagsav; 640338985Sgordon inp->inp_inc.inc_flags = incflagsav; 641338985Sgordon } 642338985Sgordon 643157376Srwatson TCPDEBUG2(PRU_CONNECT); 644178285Srwatson INP_WUNLOCK(inp); 645157376Srwatson return (error); 64655679Sshin} 64755679Sshin#endif /* INET6 */ 64855679Sshin 64917096Swollman/* 65017096Swollman * Initiate disconnect from peer. 65117096Swollman * If connection never passed embryonic stage, just drop; 65217096Swollman * else if don't need to let data drain, then can just drop anyways, 65317096Swollman * else have to begin TCP shutdown process: mark socket disconnecting, 65417096Swollman * drain unread data, state switch to reflect user close, and 65517096Swollman * send segment (e.g. FIN) to peer. Socket will be really disconnected 65617096Swollman * when peer sends FIN and acks ours. 65717096Swollman * 65817096Swollman * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. 65917096Swollman */ 66017096Swollmanstatic int 66117096Swollmantcp_usr_disconnect(struct socket *so) 66217096Swollman{ 663157376Srwatson struct inpcb *inp; 664157376Srwatson struct tcpcb *tp = NULL; 66517096Swollman int error = 0; 66617096Swollman 667157376Srwatson TCPDEBUG0; 668309108Sjch INP_INFO_RLOCK(&V_tcbinfo); 669157376Srwatson inp = sotoinpcb(so); 670157376Srwatson KASSERT(inp != NULL, ("tcp_usr_disconnect: inp == NULL")); 671178285Srwatson INP_WLOCK(inp); 672303365Sjch if (inp->inp_flags & INP_TIMEWAIT) 673303365Sjch goto out; 674303365Sjch if (inp->inp_flags & INP_DROPPED) { 675164516Ssam error = ECONNRESET; 676157376Srwatson goto out; 677157376Srwatson } 678157376Srwatson tp = intotcpcb(inp); 679157376Srwatson TCPDEBUG1(); 680157376Srwatson tcp_disconnect(tp); 681157376Srwatsonout: 682157376Srwatson TCPDEBUG2(PRU_DISCONNECT); 683178285Srwatson INP_WUNLOCK(inp); 684309108Sjch INP_INFO_RUNLOCK(&V_tcbinfo); 685157376Srwatson return (error); 68617096Swollman} 68717096Swollman 688221250Sbz#ifdef INET 68917096Swollman/* 690204809Srwatson * Accept a connection. Essentially all the work is done at higher levels; 691204809Srwatson * just return the address of the peer, storing through addr. 69217096Swollman */ 69317096Swollmanstatic int 69428270Swollmantcp_usr_accept(struct socket *so, struct sockaddr **nam) 69517096Swollman{ 69617096Swollman int error = 0; 69798102Shsu struct inpcb *inp = NULL; 69874134Sjlemon struct tcpcb *tp = NULL; 699102218Struckman struct in_addr addr; 700102218Struckman in_port_t port = 0; 70174134Sjlemon TCPDEBUG0; 70217096Swollman 703157424Srwatson if (so->so_state & SS_ISDISCONNECTED) 704157424Srwatson return (ECONNABORTED); 70598102Shsu 70698102Shsu inp = sotoinpcb(so); 707157376Srwatson KASSERT(inp != NULL, ("tcp_usr_accept: inp == NULL")); 708178285Srwatson INP_WLOCK(inp); 709189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 710157424Srwatson error = ECONNABORTED; 711157376Srwatson goto out; 71274134Sjlemon } 71374134Sjlemon tp = intotcpcb(inp); 71474134Sjlemon TCPDEBUG1(); 71598102Shsu 716133874Srwatson /* 717169462Srwatson * We inline in_getpeeraddr and COMMON_END here, so that we can 718102218Struckman * copy the data of interest and defer the malloc until after we 719102218Struckman * release the lock. 72098102Shsu */ 721102218Struckman port = inp->inp_fport; 722102218Struckman addr = inp->inp_faddr; 72398102Shsu 724157376Srwatsonout: 725157376Srwatson TCPDEBUG2(PRU_ACCEPT); 726178285Srwatson INP_WUNLOCK(inp); 727102218Struckman if (error == 0) 728102218Struckman *nam = in_sockaddr(port, &addr); 729102218Struckman return error; 73017096Swollman} 731221250Sbz#endif /* INET */ 73217096Swollman 73355679Sshin#ifdef INET6 73455679Sshinstatic int 73555679Sshintcp6_usr_accept(struct socket *so, struct sockaddr **nam) 73655679Sshin{ 73798102Shsu struct inpcb *inp = NULL; 73855679Sshin int error = 0; 73974134Sjlemon struct tcpcb *tp = NULL; 740102218Struckman struct in_addr addr; 741102218Struckman struct in6_addr addr6; 742102218Struckman in_port_t port = 0; 743102218Struckman int v4 = 0; 74474134Sjlemon TCPDEBUG0; 74555679Sshin 746159944Srwatson if (so->so_state & SS_ISDISCONNECTED) 747159944Srwatson return (ECONNABORTED); 74898102Shsu 74998102Shsu inp = sotoinpcb(so); 750157376Srwatson KASSERT(inp != NULL, ("tcp6_usr_accept: inp == NULL")); 751222488Srwatson INP_INFO_RLOCK(&V_tcbinfo); 752178285Srwatson INP_WLOCK(inp); 753189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 754164516Ssam error = ECONNABORTED; 755157376Srwatson goto out; 75674134Sjlemon } 75774134Sjlemon tp = intotcpcb(inp); 75874134Sjlemon TCPDEBUG1(); 759157376Srwatson 760133874Srwatson /* 761102218Struckman * We inline in6_mapped_peeraddr and COMMON_END here, so that we can 762102218Struckman * copy the data of interest and defer the malloc until after we 763102218Struckman * release the lock. 764102218Struckman */ 765102218Struckman if (inp->inp_vflag & INP_IPV4) { 766102218Struckman v4 = 1; 767102218Struckman port = inp->inp_fport; 768102218Struckman addr = inp->inp_faddr; 769102218Struckman } else { 770102218Struckman port = inp->inp_fport; 771102218Struckman addr6 = inp->in6p_faddr; 772102218Struckman } 773102218Struckman 774157376Srwatsonout: 775157376Srwatson TCPDEBUG2(PRU_ACCEPT); 776178285Srwatson INP_WUNLOCK(inp); 777222488Srwatson INP_INFO_RUNLOCK(&V_tcbinfo); 778102218Struckman if (error == 0) { 779102218Struckman if (v4) 780102218Struckman *nam = in6_v4mapsin6_sockaddr(port, &addr); 781102218Struckman else 782102218Struckman *nam = in6_sockaddr(port, &addr6); 783102218Struckman } 784102218Struckman return error; 78555679Sshin} 78655679Sshin#endif /* INET6 */ 78798102Shsu 78817096Swollman/* 78917096Swollman * Mark the connection as being incapable of further output. 79017096Swollman */ 79117096Swollmanstatic int 79217096Swollmantcp_usr_shutdown(struct socket *so) 79317096Swollman{ 79417096Swollman int error = 0; 79598102Shsu struct inpcb *inp; 796157376Srwatson struct tcpcb *tp = NULL; 79717096Swollman 798157376Srwatson TCPDEBUG0; 799309108Sjch INP_INFO_RLOCK(&V_tcbinfo); 800157376Srwatson inp = sotoinpcb(so); 801157376Srwatson KASSERT(inp != NULL, ("inp == NULL")); 802178285Srwatson INP_WLOCK(inp); 803189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 804164516Ssam error = ECONNRESET; 805157376Srwatson goto out; 806157376Srwatson } 807157376Srwatson tp = intotcpcb(inp); 808157376Srwatson TCPDEBUG1(); 80917096Swollman socantsendmore(so); 810157376Srwatson tcp_usrclosed(tp); 811189848Srwatson if (!(inp->inp_flags & INP_DROPPED)) 812237263Snp error = tcp_output(tp); 813157376Srwatson 814157376Srwatsonout: 815157376Srwatson TCPDEBUG2(PRU_SHUTDOWN); 816178285Srwatson INP_WUNLOCK(inp); 817309108Sjch INP_INFO_RUNLOCK(&V_tcbinfo); 818157376Srwatson 819157376Srwatson return (error); 82017096Swollman} 82117096Swollman 82217096Swollman/* 82317096Swollman * After a receive, possibly send window update to peer. 82417096Swollman */ 82517096Swollmanstatic int 82617096Swollmantcp_usr_rcvd(struct socket *so, int flags) 82717096Swollman{ 828157376Srwatson struct inpcb *inp; 829157376Srwatson struct tcpcb *tp = NULL; 83017096Swollman int error = 0; 83117096Swollman 832157376Srwatson TCPDEBUG0; 833157376Srwatson inp = sotoinpcb(so); 834157376Srwatson KASSERT(inp != NULL, ("tcp_usr_rcvd: inp == NULL")); 835178285Srwatson INP_WLOCK(inp); 836189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 837164516Ssam error = ECONNRESET; 838157376Srwatson goto out; 839157376Srwatson } 840157376Srwatson tp = intotcpcb(inp); 841157376Srwatson TCPDEBUG1(); 842292823Spkelsey#ifdef TCP_RFC7413 843292823Spkelsey /* 844292823Spkelsey * For passively-created TFO connections, don't attempt a window 845292823Spkelsey * update while still in SYN_RECEIVED as this may trigger an early 846292823Spkelsey * SYN|ACK. It is preferable to have the SYN|ACK be sent along with 847292823Spkelsey * application response data, or failing that, when the DELACK timer 848292823Spkelsey * expires. 849292823Spkelsey */ 850292823Spkelsey if ((tp->t_flags & TF_FASTOPEN) && 851292823Spkelsey (tp->t_state == TCPS_SYN_RECEIVED)) 852292823Spkelsey goto out; 853292823Spkelsey#endif 854237263Snp#ifdef TCP_OFFLOAD 855237263Snp if (tp->t_flags & TF_TOE) 856237263Snp tcp_offload_rcvd(tp); 857245921Snp else 858237263Snp#endif 859237263Snp tcp_output(tp); 860157376Srwatson 861157376Srwatsonout: 862157376Srwatson TCPDEBUG2(PRU_RCVD); 863178285Srwatson INP_WUNLOCK(inp); 864157376Srwatson return (error); 86517096Swollman} 86617096Swollman 86717096Swollman/* 86817096Swollman * Do a send by putting data in output queue and updating urgent 86947720Speter * marker if URG set. Possibly send more data. Unlike the other 87047720Speter * pru_*() routines, the mbuf chains are our responsibility. We 87147720Speter * must either enqueue them or free them. The other pru_* routines 87247720Speter * generally are caller-frees. 87317096Swollman */ 87417096Swollmanstatic int 875133874Srwatsontcp_usr_send(struct socket *so, int flags, struct mbuf *m, 876167785Sandre struct sockaddr *nam, struct mbuf *control, struct thread *td) 87717096Swollman{ 87817096Swollman int error = 0; 87998102Shsu struct inpcb *inp; 880157376Srwatson struct tcpcb *tp = NULL; 88155679Sshin#ifdef INET6 88255679Sshin int isipv6; 88355679Sshin#endif 88447720Speter TCPDEBUG0; 88517096Swollman 88698102Shsu /* 887222488Srwatson * We require the pcbinfo lock if we will close the socket as part of 888222488Srwatson * this call. 88998102Shsu */ 890222488Srwatson if (flags & PRUS_EOF) 891309108Sjch INP_INFO_RLOCK(&V_tcbinfo); 89298102Shsu inp = sotoinpcb(so); 893157376Srwatson KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL")); 894178285Srwatson INP_WLOCK(inp); 895189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 896162376Sandre if (control) 897162376Sandre m_freem(control); 898162376Sandre if (m) 899162376Sandre m_freem(m); 900164516Ssam error = ECONNRESET; 90131840Sdg goto out; 90217096Swollman } 90355679Sshin#ifdef INET6 90455679Sshin isipv6 = nam && nam->sa_family == AF_INET6; 90555679Sshin#endif /* INET6 */ 90647720Speter tp = intotcpcb(inp); 90747720Speter TCPDEBUG1(); 90847720Speter if (control) { 90947720Speter /* TCP doesn't do control messages (rights, creds, etc) */ 91047720Speter if (control->m_len) { 91147720Speter m_freem(control); 91247720Speter if (m) 91347720Speter m_freem(m); 91447720Speter error = EINVAL; 91547720Speter goto out; 91647720Speter } 91747720Speter m_freem(control); /* empty control, just free it */ 91847720Speter } 91998102Shsu if (!(flags & PRUS_OOB)) { 920121628Ssam sbappendstream(&so->so_snd, m); 92117096Swollman if (nam && tp->t_state < TCPS_SYN_SENT) { 92217096Swollman /* 92317096Swollman * Do implied connect if not yet connected, 92417096Swollman * initialize window to default value, and 92517096Swollman * initialize maxseg/maxopd using peer's cached 92617096Swollman * MSS. 92717096Swollman */ 92855679Sshin#ifdef INET6 92955679Sshin if (isipv6) 93083366Sjulian error = tcp6_connect(tp, nam, td); 931221250Sbz#endif /* INET6 */ 932221250Sbz#if defined(INET6) && defined(INET) 93355679Sshin else 934221250Sbz#endif 935221250Sbz#ifdef INET 936221250Sbz error = tcp_connect(tp, nam, td); 937221250Sbz#endif 93817096Swollman if (error) 93917096Swollman goto out; 94017096Swollman tp->snd_wnd = TTCP_CLIENT_SND_WND; 94117096Swollman tcp_mss(tp, -1); 94217096Swollman } 94317096Swollman if (flags & PRUS_EOF) { 94417096Swollman /* 94517096Swollman * Close the send side of the connection after 94617096Swollman * the data is sent. 94717096Swollman */ 948309108Sjch INP_INFO_RLOCK_ASSERT(&V_tcbinfo); 94917096Swollman socantsendmore(so); 950157376Srwatson tcp_usrclosed(tp); 95117096Swollman } 952189848Srwatson if (!(inp->inp_flags & INP_DROPPED)) { 95342902Sfenner if (flags & PRUS_MORETOCOME) 95442902Sfenner tp->t_flags |= TF_MORETOCOME; 955237263Snp error = tcp_output(tp); 95642902Sfenner if (flags & PRUS_MORETOCOME) 95742902Sfenner tp->t_flags &= ~TF_MORETOCOME; 95842902Sfenner } 95917096Swollman } else { 960157376Srwatson /* 961157376Srwatson * XXXRW: PRUS_EOF not implemented with PRUS_OOB? 962157376Srwatson */ 963143610Srwatson SOCKBUF_LOCK(&so->so_snd); 96417096Swollman if (sbspace(&so->so_snd) < -512) { 965143610Srwatson SOCKBUF_UNLOCK(&so->so_snd); 96617096Swollman m_freem(m); 96717096Swollman error = ENOBUFS; 96817096Swollman goto out; 96917096Swollman } 97017096Swollman /* 97117096Swollman * According to RFC961 (Assigned Protocols), 97217096Swollman * the urgent pointer points to the last octet 97317096Swollman * of urgent data. We continue, however, 97417096Swollman * to consider it to indicate the first octet 97517096Swollman * of data past the urgent section. 97617096Swollman * Otherwise, snd_up should be one lower. 97717096Swollman */ 978143610Srwatson sbappendstream_locked(&so->so_snd, m); 979143610Srwatson SOCKBUF_UNLOCK(&so->so_snd); 98022962Swollman if (nam && tp->t_state < TCPS_SYN_SENT) { 98122962Swollman /* 98222962Swollman * Do implied connect if not yet connected, 98322962Swollman * initialize window to default value, and 98422962Swollman * initialize maxseg/maxopd using peer's cached 98522962Swollman * MSS. 98622962Swollman */ 98755679Sshin#ifdef INET6 98855679Sshin if (isipv6) 98983366Sjulian error = tcp6_connect(tp, nam, td); 990221250Sbz#endif /* INET6 */ 991221250Sbz#if defined(INET6) && defined(INET) 99255679Sshin else 993221250Sbz#endif 994221250Sbz#ifdef INET 995221250Sbz error = tcp_connect(tp, nam, td); 996221250Sbz#endif 99722962Swollman if (error) 99822962Swollman goto out; 99922962Swollman tp->snd_wnd = TTCP_CLIENT_SND_WND; 100022962Swollman tcp_mss(tp, -1); 100122962Swollman } 100217096Swollman tp->snd_up = tp->snd_una + so->so_snd.sb_cc; 1003146463Sps tp->t_flags |= TF_FORCEDATA; 1004237263Snp error = tcp_output(tp); 1005146463Sps tp->t_flags &= ~TF_FORCEDATA; 100617096Swollman } 1007145766Srwatsonout: 1008145766Srwatson TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB : 1009145766Srwatson ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND)); 1010178285Srwatson INP_WUNLOCK(inp); 1011222488Srwatson if (flags & PRUS_EOF) 1012309108Sjch INP_INFO_RUNLOCK(&V_tcbinfo); 1013145771Sgrehan return (error); 101417096Swollman} 101517096Swollman 101617096Swollman/* 1017160549Srwatson * Abort the TCP. Drop the connection abruptly. 101817096Swollman */ 1019157366Srwatsonstatic void 102017096Swollmantcp_usr_abort(struct socket *so) 102117096Swollman{ 102298102Shsu struct inpcb *inp; 1023160549Srwatson struct tcpcb *tp = NULL; 1024157993Srwatson TCPDEBUG0; 1025157376Srwatson 1026157993Srwatson inp = sotoinpcb(so); 1027157993Srwatson KASSERT(inp != NULL, ("tcp_usr_abort: inp == NULL")); 1028157376Srwatson 1029309108Sjch INP_INFO_RLOCK(&V_tcbinfo); 1030178285Srwatson INP_WLOCK(inp); 1031157993Srwatson KASSERT(inp->inp_socket != NULL, 1032157993Srwatson ("tcp_usr_abort: inp_socket == NULL")); 1033157993Srwatson 1034157376Srwatson /* 1035160549Srwatson * If we still have full TCP state, and we're not dropped, drop. 1036157376Srwatson */ 1037189848Srwatson if (!(inp->inp_flags & INP_TIMEWAIT) && 1038189848Srwatson !(inp->inp_flags & INP_DROPPED)) { 1039157993Srwatson tp = intotcpcb(inp); 1040160549Srwatson TCPDEBUG1(); 1041157993Srwatson tcp_drop(tp, ECONNABORTED); 1042160549Srwatson TCPDEBUG2(PRU_ABORT); 1043157993Srwatson } 1044189848Srwatson if (!(inp->inp_flags & INP_DROPPED)) { 1045160549Srwatson SOCK_LOCK(so); 1046160549Srwatson so->so_state |= SS_PROTOREF; 1047160549Srwatson SOCK_UNLOCK(so); 1048189848Srwatson inp->inp_flags |= INP_SOCKREF; 1049160549Srwatson } 1050178285Srwatson INP_WUNLOCK(inp); 1051309108Sjch INP_INFO_RUNLOCK(&V_tcbinfo); 105217096Swollman} 105317096Swollman 105417096Swollman/* 1055160549Srwatson * TCP socket is closed. Start friendly disconnect. 1056160549Srwatson */ 1057160549Srwatsonstatic void 1058160549Srwatsontcp_usr_close(struct socket *so) 1059160549Srwatson{ 1060160549Srwatson struct inpcb *inp; 1061160549Srwatson struct tcpcb *tp = NULL; 1062160549Srwatson TCPDEBUG0; 1063160549Srwatson 1064160549Srwatson inp = sotoinpcb(so); 1065160549Srwatson KASSERT(inp != NULL, ("tcp_usr_close: inp == NULL")); 1066160549Srwatson 1067309108Sjch INP_INFO_RLOCK(&V_tcbinfo); 1068178285Srwatson INP_WLOCK(inp); 1069160549Srwatson KASSERT(inp->inp_socket != NULL, 1070160549Srwatson ("tcp_usr_close: inp_socket == NULL")); 1071160549Srwatson 1072160549Srwatson /* 1073160549Srwatson * If we still have full TCP state, and we're not dropped, initiate 1074160549Srwatson * a disconnect. 1075160549Srwatson */ 1076189848Srwatson if (!(inp->inp_flags & INP_TIMEWAIT) && 1077189848Srwatson !(inp->inp_flags & INP_DROPPED)) { 1078160549Srwatson tp = intotcpcb(inp); 1079160549Srwatson TCPDEBUG1(); 1080160549Srwatson tcp_disconnect(tp); 1081160549Srwatson TCPDEBUG2(PRU_CLOSE); 1082160549Srwatson } 1083189848Srwatson if (!(inp->inp_flags & INP_DROPPED)) { 1084160549Srwatson SOCK_LOCK(so); 1085160549Srwatson so->so_state |= SS_PROTOREF; 1086160549Srwatson SOCK_UNLOCK(so); 1087189848Srwatson inp->inp_flags |= INP_SOCKREF; 1088160549Srwatson } 1089178285Srwatson INP_WUNLOCK(inp); 1090309108Sjch INP_INFO_RUNLOCK(&V_tcbinfo); 1091160549Srwatson} 1092160549Srwatson 1093160549Srwatson/* 109417096Swollman * Receive out-of-band data. 109517096Swollman */ 109617096Swollmanstatic int 109717096Swollmantcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags) 109817096Swollman{ 109917096Swollman int error = 0; 110098102Shsu struct inpcb *inp; 1101157376Srwatson struct tcpcb *tp = NULL; 110217096Swollman 1103157376Srwatson TCPDEBUG0; 1104157376Srwatson inp = sotoinpcb(so); 1105157376Srwatson KASSERT(inp != NULL, ("tcp_usr_rcvoob: inp == NULL")); 1106178285Srwatson INP_WLOCK(inp); 1107189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 1108164516Ssam error = ECONNRESET; 1109157376Srwatson goto out; 1110157376Srwatson } 1111157376Srwatson tp = intotcpcb(inp); 1112157376Srwatson TCPDEBUG1(); 111317096Swollman if ((so->so_oobmark == 0 && 1114130480Srwatson (so->so_rcv.sb_state & SBS_RCVATMARK) == 0) || 111597658Stanimura so->so_options & SO_OOBINLINE || 111697658Stanimura tp->t_oobflags & TCPOOB_HADDATA) { 111717096Swollman error = EINVAL; 111817096Swollman goto out; 111917096Swollman } 112017096Swollman if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { 112117096Swollman error = EWOULDBLOCK; 112217096Swollman goto out; 112317096Swollman } 112417096Swollman m->m_len = 1; 112517096Swollman *mtod(m, caddr_t) = tp->t_iobc; 112617096Swollman if ((flags & MSG_PEEK) == 0) 112717096Swollman tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA); 1128157376Srwatson 1129157376Srwatsonout: 1130157376Srwatson TCPDEBUG2(PRU_RCVOOB); 1131178285Srwatson INP_WUNLOCK(inp); 1132157376Srwatson return (error); 113317096Swollman} 113417096Swollman 1135221250Sbz#ifdef INET 113617096Swollmanstruct pr_usrreqs tcp_usrreqs = { 1137137386Sphk .pru_abort = tcp_usr_abort, 1138137386Sphk .pru_accept = tcp_usr_accept, 1139137386Sphk .pru_attach = tcp_usr_attach, 1140137386Sphk .pru_bind = tcp_usr_bind, 1141137386Sphk .pru_connect = tcp_usr_connect, 1142137386Sphk .pru_control = in_control, 1143137386Sphk .pru_detach = tcp_usr_detach, 1144137386Sphk .pru_disconnect = tcp_usr_disconnect, 1145137386Sphk .pru_listen = tcp_usr_listen, 1146169462Srwatson .pru_peeraddr = in_getpeeraddr, 1147137386Sphk .pru_rcvd = tcp_usr_rcvd, 1148137386Sphk .pru_rcvoob = tcp_usr_rcvoob, 1149137386Sphk .pru_send = tcp_usr_send, 1150137386Sphk .pru_shutdown = tcp_usr_shutdown, 1151169462Srwatson .pru_sockaddr = in_getsockaddr, 1152160549Srwatson .pru_sosetlabel = in_pcbsosetlabel, 1153160549Srwatson .pru_close = tcp_usr_close, 115417096Swollman}; 1155221250Sbz#endif /* INET */ 115617096Swollman 115755679Sshin#ifdef INET6 115855679Sshinstruct pr_usrreqs tcp6_usrreqs = { 1159137386Sphk .pru_abort = tcp_usr_abort, 1160137386Sphk .pru_accept = tcp6_usr_accept, 1161137386Sphk .pru_attach = tcp_usr_attach, 1162137386Sphk .pru_bind = tcp6_usr_bind, 1163137386Sphk .pru_connect = tcp6_usr_connect, 1164137386Sphk .pru_control = in6_control, 1165137386Sphk .pru_detach = tcp_usr_detach, 1166137386Sphk .pru_disconnect = tcp_usr_disconnect, 1167137386Sphk .pru_listen = tcp6_usr_listen, 1168137386Sphk .pru_peeraddr = in6_mapped_peeraddr, 1169137386Sphk .pru_rcvd = tcp_usr_rcvd, 1170137386Sphk .pru_rcvoob = tcp_usr_rcvoob, 1171137386Sphk .pru_send = tcp_usr_send, 1172137386Sphk .pru_shutdown = tcp_usr_shutdown, 1173137386Sphk .pru_sockaddr = in6_mapped_sockaddr, 1174217126Sjhb .pru_sosetlabel = in_pcbsosetlabel, 1175160549Srwatson .pru_close = tcp_usr_close, 117655679Sshin}; 117755679Sshin#endif /* INET6 */ 117855679Sshin 1179221250Sbz#ifdef INET 118017096Swollman/* 11816283Swollman * Common subroutine to open a TCP connection to remote host specified 11826283Swollman * by struct sockaddr_in in mbuf *nam. Call in_pcbbind to assign a local 1183105629Siedowse * port number if needed. Call in_pcbconnect_setup to do the routing and 1184105629Siedowse * to choose a local host address (interface). If there is an existing 1185105629Siedowse * incarnation of the same connection in TIME-WAIT state and if the remote 1186105629Siedowse * host was sending CC options and if the connection duration was < MSL, then 11876283Swollman * truncate the previous TIME-WAIT state and proceed. 11886283Swollman * Initialize connection parameters and enter SYN-SENT state. 11896283Swollman */ 119012296Sphkstatic int 1191167785Sandretcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) 11926283Swollman{ 11936283Swollman struct inpcb *inp = tp->t_inpcb, *oinp; 11946283Swollman struct socket *so = inp->inp_socket; 1195105629Siedowse struct in_addr laddr; 1196105629Siedowse u_short lport; 119732821Sdg int error; 11986283Swollman 1199178285Srwatson INP_WLOCK_ASSERT(inp); 1200222488Srwatson INP_HASH_WLOCK(&V_tcbinfo); 1201157376Srwatson 12026283Swollman if (inp->inp_lport == 0) { 1203127505Spjd error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); 12046283Swollman if (error) 1205222488Srwatson goto out; 12066283Swollman } 12076283Swollman 12088876Srgrimes /* 12096283Swollman * Cannot simply call in_pcbconnect, because there might be an 12106283Swollman * earlier incarnation of this same connection still in 12116283Swollman * TIME_WAIT state, creating an ADDRINUSE error. 12126283Swollman */ 1213105629Siedowse laddr = inp->inp_laddr; 1214105629Siedowse lport = inp->inp_lport; 1215105629Siedowse error = in_pcbconnect_setup(inp, nam, &laddr.s_addr, &lport, 1216127505Spjd &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, td->td_ucred); 1217105629Siedowse if (error && oinp == NULL) 1218222488Srwatson goto out; 1219222488Srwatson if (oinp) { 1220222488Srwatson error = EADDRINUSE; 1221222488Srwatson goto out; 1222222488Srwatson } 1223105629Siedowse inp->inp_laddr = laddr; 12247684Sdg in_pcbrehash(inp); 1225222488Srwatson INP_HASH_WUNLOCK(&V_tcbinfo); 12266283Swollman 1227166403Sandre /* 1228166403Sandre * Compute window scaling to request: 1229166403Sandre * Scale to fit into sweet spot. See tcp_syncache.c. 1230166403Sandre * XXX: This should move to tcp_output(). 1231166403Sandre */ 12326283Swollman while (tp->request_r_scale < TCP_MAX_WINSHIFT && 1233172795Ssilby (TCP_MAXWIN << tp->request_r_scale) < sb_max) 12346283Swollman tp->request_r_scale++; 12356283Swollman 12366283Swollman soisconnecting(so); 1237190948Srwatson TCPSTAT_INC(tcps_connattempt); 1238254889Smarkj tcp_state_change(tp, TCPS_SYN_SENT); 123982122Ssilby tp->iss = tcp_new_isn(tp); 12406283Swollman tcp_sendseqinit(tp); 124112045Solah 12426283Swollman return 0; 1243222488Srwatson 1244222488Srwatsonout: 1245222488Srwatson INP_HASH_WUNLOCK(&V_tcbinfo); 1246222488Srwatson return (error); 12476283Swollman} 1248221250Sbz#endif /* INET */ 12496283Swollman 125055679Sshin#ifdef INET6 125155679Sshinstatic int 1252167785Sandretcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) 125355679Sshin{ 125455679Sshin struct inpcb *inp = tp->t_inpcb, *oinp; 125555679Sshin struct socket *so = inp->inp_socket; 125655679Sshin struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; 1257194777Sbz struct in6_addr addr6; 125855679Sshin int error; 125955679Sshin 1260178285Srwatson INP_WLOCK_ASSERT(inp); 1261222488Srwatson INP_HASH_WLOCK(&V_tcbinfo); 1262157376Srwatson 126355679Sshin if (inp->inp_lport == 0) { 1264127505Spjd error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); 126555679Sshin if (error) 1266222488Srwatson goto out; 126755679Sshin } 126855679Sshin 126955679Sshin /* 127055679Sshin * Cannot simply call in_pcbconnect, because there might be an 127155679Sshin * earlier incarnation of this same connection still in 127255679Sshin * TIME_WAIT state, creating an ADDRINUSE error. 1273148385Sume * in6_pcbladdr() also handles scope zone IDs. 1274222488Srwatson * 1275222488Srwatson * XXXRW: We wouldn't need to expose in6_pcblookup_hash_locked() 1276222488Srwatson * outside of in6_pcb.c if there were an in6_pcbconnect_setup(). 127755679Sshin */ 127855679Sshin error = in6_pcbladdr(inp, nam, &addr6); 127955679Sshin if (error) 1280222602Srwatson goto out; 1281222488Srwatson oinp = in6_pcblookup_hash_locked(inp->inp_pcbinfo, 128255679Sshin &sin6->sin6_addr, sin6->sin6_port, 128355679Sshin IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) 1284194777Sbz ? &addr6 128555679Sshin : &inp->in6p_laddr, 128655679Sshin inp->inp_lport, 0, NULL); 1287222488Srwatson if (oinp) { 1288222488Srwatson error = EADDRINUSE; 1289222488Srwatson goto out; 1290222488Srwatson } 129155679Sshin if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) 1292194777Sbz inp->in6p_laddr = addr6; 129355679Sshin inp->in6p_faddr = sin6->sin6_addr; 129455679Sshin inp->inp_fport = sin6->sin6_port; 1295132259Sume /* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ 1296186141Sbz inp->inp_flow &= ~IPV6_FLOWLABEL_MASK; 1297186141Sbz if (inp->inp_flags & IN6P_AUTOFLOWLABEL) 1298186141Sbz inp->inp_flow |= 1299132259Sume (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK); 130055679Sshin in_pcbrehash(inp); 1301222488Srwatson INP_HASH_WUNLOCK(&V_tcbinfo); 130255679Sshin 130355679Sshin /* Compute window scaling to request. */ 130455679Sshin while (tp->request_r_scale < TCP_MAX_WINSHIFT && 1305190800Sbz (TCP_MAXWIN << tp->request_r_scale) < sb_max) 130655679Sshin tp->request_r_scale++; 130755679Sshin 130855679Sshin soisconnecting(so); 1309190948Srwatson TCPSTAT_INC(tcps_connattempt); 1310254889Smarkj tcp_state_change(tp, TCPS_SYN_SENT); 131182122Ssilby tp->iss = tcp_new_isn(tp); 131255679Sshin tcp_sendseqinit(tp); 131355679Sshin 131455679Sshin return 0; 1315222488Srwatson 1316222488Srwatsonout: 1317222488Srwatson INP_HASH_WUNLOCK(&V_tcbinfo); 1318222488Srwatson return error; 131955679Sshin} 132055679Sshin#endif /* INET6 */ 132155679Sshin 132238482Swollman/* 1323138118Srwatson * Export TCP internal state information via a struct tcp_info, based on the 1324138118Srwatson * Linux 2.6 API. Not ABI compatible as our constants are mapped differently 1325138118Srwatson * (TCP state machine, etc). We export all information using FreeBSD-native 1326138118Srwatson * constants -- for example, the numeric values for tcpi_state will differ 1327138118Srwatson * from Linux. 1328138118Srwatson */ 1329138118Srwatsonstatic void 1330167785Sandretcp_fill_info(struct tcpcb *tp, struct tcp_info *ti) 1331138118Srwatson{ 1332138118Srwatson 1333178285Srwatson INP_WLOCK_ASSERT(tp->t_inpcb); 1334138118Srwatson bzero(ti, sizeof(*ti)); 1335138118Srwatson 1336138118Srwatson ti->tcpi_state = tp->t_state; 1337138118Srwatson if ((tp->t_flags & TF_REQ_TSTMP) && (tp->t_flags & TF_RCVD_TSTMP)) 1338138118Srwatson ti->tcpi_options |= TCPI_OPT_TIMESTAMPS; 1339169317Sandre if (tp->t_flags & TF_SACK_PERMIT) 1340138118Srwatson ti->tcpi_options |= TCPI_OPT_SACK; 1341138118Srwatson if ((tp->t_flags & TF_REQ_SCALE) && (tp->t_flags & TF_RCVD_SCALE)) { 1342138118Srwatson ti->tcpi_options |= TCPI_OPT_WSCALE; 1343138118Srwatson ti->tcpi_snd_wscale = tp->snd_scale; 1344138118Srwatson ti->tcpi_rcv_wscale = tp->rcv_scale; 1345138118Srwatson } 1346166433Sbms 1347200847Sjhb ti->tcpi_rto = tp->t_rxtcur * tick; 1348200847Sjhb ti->tcpi_last_data_recv = (long)(ticks - (int)tp->t_rcvtime) * tick; 1349166433Sbms ti->tcpi_rtt = ((u_int64_t)tp->t_srtt * tick) >> TCP_RTT_SHIFT; 1350166433Sbms ti->tcpi_rttvar = ((u_int64_t)tp->t_rttvar * tick) >> TCP_RTTVAR_SHIFT; 1351166433Sbms 1352138118Srwatson ti->tcpi_snd_ssthresh = tp->snd_ssthresh; 1353138118Srwatson ti->tcpi_snd_cwnd = tp->snd_cwnd; 1354138118Srwatson 1355138118Srwatson /* 1356138118Srwatson * FreeBSD-specific extension fields for tcp_info. 1357138118Srwatson */ 1358138136Srwatson ti->tcpi_rcv_space = tp->rcv_wnd; 1359178793Skmacy ti->tcpi_rcv_nxt = tp->rcv_nxt; 1360138118Srwatson ti->tcpi_snd_wnd = tp->snd_wnd; 1361212765Sandre ti->tcpi_snd_bwnd = 0; /* Unused, kept for compat. */ 1362178801Skmacy ti->tcpi_snd_nxt = tp->snd_nxt; 1363200847Sjhb ti->tcpi_snd_mss = tp->t_maxseg; 1364200847Sjhb ti->tcpi_rcv_mss = tp->t_maxseg; 1365178801Skmacy if (tp->t_flags & TF_TOE) 1366178801Skmacy ti->tcpi_options |= TCPI_OPT_TOE; 1367215434Sgnn ti->tcpi_snd_rexmitpack = tp->t_sndrexmitpack; 1368215434Sgnn ti->tcpi_rcv_ooopack = tp->t_rcvoopack; 1369215434Sgnn ti->tcpi_snd_zerowin = tp->t_sndzerowin; 1370138118Srwatson} 1371138118Srwatson 1372138118Srwatson/* 1373175438Srwatson * tcp_ctloutput() must drop the inpcb lock before performing copyin on 1374175438Srwatson * socket option arguments. When it re-acquires the lock after the copy, it 1375175438Srwatson * has to revalidate that the connection is still valid for the socket 1376175438Srwatson * option. 137738482Swollman */ 1378178285Srwatson#define INP_WLOCK_RECHECK(inp) do { \ 1379178285Srwatson INP_WLOCK(inp); \ 1380189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { \ 1381178285Srwatson INP_WUNLOCK(inp); \ 1382175438Srwatson return (ECONNRESET); \ 1383175438Srwatson } \ 1384175438Srwatson tp = intotcpcb(inp); \ 1385175438Srwatson} while(0) 1386175438Srwatson 13876283Swollmanint 1388167785Sandretcp_ctloutput(struct socket *so, struct sockopt *sopt) 13891541Srgrimes{ 1390131147Srwatson int error, opt, optval; 1391231025Sglebius u_int ui; 139238482Swollman struct inpcb *inp; 139338482Swollman struct tcpcb *tp; 1394138118Srwatson struct tcp_info ti; 1395215166Slstewart char buf[TCP_CA_NAME_MAX]; 1396215166Slstewart struct cc_algo *algo; 13971541Srgrimes 139838482Swollman error = 0; 13991541Srgrimes inp = sotoinpcb(so); 1400157376Srwatson KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL")); 1401178285Srwatson INP_WLOCK(inp); 140238482Swollman if (sopt->sopt_level != IPPROTO_TCP) { 140355679Sshin#ifdef INET6 1404185371Sbz if (inp->inp_vflag & INP_IPV6PROTO) { 1405178285Srwatson INP_WUNLOCK(inp); 140655679Sshin error = ip6_ctloutput(so, sopt); 1407221250Sbz } 140855679Sshin#endif /* INET6 */ 1409221250Sbz#if defined(INET6) && defined(INET) 1410221250Sbz else 1411221250Sbz#endif 1412221250Sbz#ifdef INET 1413221250Sbz { 1414178285Srwatson INP_WUNLOCK(inp); 1415175438Srwatson error = ip_ctloutput(so, sopt); 1416175438Srwatson } 1417175438Srwatson#endif 14181541Srgrimes return (error); 14191541Srgrimes } 1420189848Srwatson if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 1421178285Srwatson INP_WUNLOCK(inp); 1422175438Srwatson return (ECONNRESET); 1423157376Srwatson } 14241541Srgrimes 142538482Swollman switch (sopt->sopt_dir) { 142638482Swollman case SOPT_SET: 142738482Swollman switch (sopt->sopt_name) { 1428125680Sbms#ifdef TCP_SIGNATURE 1429125890Sbms case TCP_MD5SIG: 1430178285Srwatson INP_WUNLOCK(inp); 1431125680Sbms error = sooptcopyin(sopt, &optval, sizeof optval, 1432175438Srwatson sizeof optval); 1433125680Sbms if (error) 1434175438Srwatson return (error); 1435125680Sbms 1436178285Srwatson INP_WLOCK_RECHECK(inp); 1437125680Sbms if (optval > 0) 1438125680Sbms tp->t_flags |= TF_SIGNATURE; 1439125680Sbms else 1440125680Sbms tp->t_flags &= ~TF_SIGNATURE; 1441237263Snp goto unlock_and_done; 1442125680Sbms#endif /* TCP_SIGNATURE */ 1443237263Snp 144438482Swollman case TCP_NODELAY: 144538482Swollman case TCP_NOOPT: 1446178285Srwatson INP_WUNLOCK(inp); 144738482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 1448175438Srwatson sizeof optval); 144938482Swollman if (error) 1450175438Srwatson return (error); 14511541Srgrimes 1452178285Srwatson INP_WLOCK_RECHECK(inp); 145338482Swollman switch (sopt->sopt_name) { 145438482Swollman case TCP_NODELAY: 145538482Swollman opt = TF_NODELAY; 145638482Swollman break; 145738482Swollman case TCP_NOOPT: 145838482Swollman opt = TF_NOOPT; 145938482Swollman break; 146038482Swollman default: 146138482Swollman opt = 0; /* dead code to fool gcc */ 146238482Swollman break; 146338482Swollman } 14641541Srgrimes 146538482Swollman if (optval) 146638482Swollman tp->t_flags |= opt; 14671541Srgrimes else 146838482Swollman tp->t_flags &= ~opt; 1469237263Snpunlock_and_done: 1470237263Snp#ifdef TCP_OFFLOAD 1471237263Snp if (tp->t_flags & TF_TOE) { 1472237263Snp tcp_offload_ctloutput(tp, sopt->sopt_dir, 1473237263Snp sopt->sopt_name); 1474237263Snp } 1475237263Snp#endif 1476178285Srwatson INP_WUNLOCK(inp); 14771541Srgrimes break; 14781541Srgrimes 147971937Sjlemon case TCP_NOPUSH: 1480178285Srwatson INP_WUNLOCK(inp); 148171937Sjlemon error = sooptcopyin(sopt, &optval, sizeof optval, 1482175438Srwatson sizeof optval); 148371937Sjlemon if (error) 1484175438Srwatson return (error); 148571937Sjlemon 1486178285Srwatson INP_WLOCK_RECHECK(inp); 148771937Sjlemon if (optval) 148871937Sjlemon tp->t_flags |= TF_NOPUSH; 1489218271Sjhb else if (tp->t_flags & TF_NOPUSH) { 149071937Sjlemon tp->t_flags &= ~TF_NOPUSH; 1491218271Sjhb if (TCPS_HAVEESTABLISHED(tp->t_state)) 1492218271Sjhb error = tcp_output(tp); 149371937Sjlemon } 1494237263Snp goto unlock_and_done; 149571937Sjlemon 14961541Srgrimes case TCP_MAXSEG: 1497178285Srwatson INP_WUNLOCK(inp); 149838482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 1499175438Srwatson sizeof optval); 150038482Swollman if (error) 1501175438Srwatson return (error); 15021541Srgrimes 1503178285Srwatson INP_WLOCK_RECHECK(inp); 1504124258Sandre if (optval > 0 && optval <= tp->t_maxseg && 1505181803Sbz optval + 40 >= V_tcp_minmss) 150638482Swollman tp->t_maxseg = optval; 15076283Swollman else 15086283Swollman error = EINVAL; 1509237263Snp goto unlock_and_done; 15106283Swollman 1511138118Srwatson case TCP_INFO: 1512178285Srwatson INP_WUNLOCK(inp); 1513138118Srwatson error = EINVAL; 1514138118Srwatson break; 1515138118Srwatson 1516215166Slstewart case TCP_CONGESTION: 1517215166Slstewart INP_WUNLOCK(inp); 1518215166Slstewart bzero(buf, sizeof(buf)); 1519215166Slstewart error = sooptcopyin(sopt, &buf, sizeof(buf), 1); 1520215166Slstewart if (error) 1521215166Slstewart break; 1522215166Slstewart INP_WLOCK_RECHECK(inp); 1523215166Slstewart /* 1524215166Slstewart * Return EINVAL if we can't find the requested cc algo. 1525215166Slstewart */ 1526215166Slstewart error = EINVAL; 1527215166Slstewart CC_LIST_RLOCK(); 1528215166Slstewart STAILQ_FOREACH(algo, &cc_list, entries) { 1529215166Slstewart if (strncmp(buf, algo->name, TCP_CA_NAME_MAX) 1530215166Slstewart == 0) { 1531215166Slstewart /* We've found the requested algo. */ 1532215166Slstewart error = 0; 1533215166Slstewart /* 1534215166Slstewart * We hold a write lock over the tcb 1535215166Slstewart * so it's safe to do these things 1536215166Slstewart * without ordering concerns. 1537215166Slstewart */ 1538215166Slstewart if (CC_ALGO(tp)->cb_destroy != NULL) 1539215166Slstewart CC_ALGO(tp)->cb_destroy(tp->ccv); 1540215166Slstewart CC_ALGO(tp) = algo; 1541215166Slstewart /* 1542215166Slstewart * If something goes pear shaped 1543215166Slstewart * initialising the new algo, 1544215166Slstewart * fall back to newreno (which 1545215166Slstewart * does not require initialisation). 1546215166Slstewart */ 1547215166Slstewart if (algo->cb_init != NULL) 1548215166Slstewart if (algo->cb_init(tp->ccv) > 0) { 1549215166Slstewart CC_ALGO(tp) = &newreno_cc_algo; 1550215166Slstewart /* 1551215166Slstewart * The only reason init 1552215166Slstewart * should fail is 1553215166Slstewart * because of malloc. 1554215166Slstewart */ 1555215166Slstewart error = ENOMEM; 1556215166Slstewart } 1557215166Slstewart break; /* Break the STAILQ_FOREACH. */ 1558215166Slstewart } 1559215166Slstewart } 1560215166Slstewart CC_LIST_RUNLOCK(); 1561237263Snp goto unlock_and_done; 1562215166Slstewart 1563231025Sglebius case TCP_KEEPIDLE: 1564231025Sglebius case TCP_KEEPINTVL: 1565231025Sglebius case TCP_KEEPINIT: 1566231025Sglebius INP_WUNLOCK(inp); 1567231025Sglebius error = sooptcopyin(sopt, &ui, sizeof(ui), sizeof(ui)); 1568231025Sglebius if (error) 1569231025Sglebius return (error); 1570231025Sglebius 1571231025Sglebius if (ui > (UINT_MAX / hz)) { 1572231025Sglebius error = EINVAL; 1573231025Sglebius break; 1574231025Sglebius } 1575231025Sglebius ui *= hz; 1576231025Sglebius 1577231025Sglebius INP_WLOCK_RECHECK(inp); 1578231025Sglebius switch (sopt->sopt_name) { 1579231025Sglebius case TCP_KEEPIDLE: 1580231025Sglebius tp->t_keepidle = ui; 1581231025Sglebius /* 1582231025Sglebius * XXX: better check current remaining 1583231025Sglebius * timeout and "merge" it with new value. 1584231025Sglebius */ 1585231025Sglebius if ((tp->t_state > TCPS_LISTEN) && 1586231025Sglebius (tp->t_state <= TCPS_CLOSING)) 1587231025Sglebius tcp_timer_activate(tp, TT_KEEP, 1588231025Sglebius TP_KEEPIDLE(tp)); 1589231025Sglebius break; 1590231025Sglebius case TCP_KEEPINTVL: 1591231025Sglebius tp->t_keepintvl = ui; 1592231025Sglebius if ((tp->t_state == TCPS_FIN_WAIT_2) && 1593231025Sglebius (TP_MAXIDLE(tp) > 0)) 1594231025Sglebius tcp_timer_activate(tp, TT_2MSL, 1595231025Sglebius TP_MAXIDLE(tp)); 1596231025Sglebius break; 1597231025Sglebius case TCP_KEEPINIT: 1598231025Sglebius tp->t_keepinit = ui; 1599231025Sglebius if (tp->t_state == TCPS_SYN_RECEIVED || 1600231025Sglebius tp->t_state == TCPS_SYN_SENT) 1601231025Sglebius tcp_timer_activate(tp, TT_KEEP, 1602231025Sglebius TP_KEEPINIT(tp)); 1603231025Sglebius break; 1604231025Sglebius } 1605237263Snp goto unlock_and_done; 1606231025Sglebius 1607240985Sglebius case TCP_KEEPCNT: 1608240985Sglebius INP_WUNLOCK(inp); 1609240985Sglebius error = sooptcopyin(sopt, &ui, sizeof(ui), sizeof(ui)); 1610240985Sglebius if (error) 1611240985Sglebius return (error); 1612240985Sglebius 1613240985Sglebius INP_WLOCK_RECHECK(inp); 1614240985Sglebius tp->t_keepcnt = ui; 1615240985Sglebius if ((tp->t_state == TCPS_FIN_WAIT_2) && 1616240985Sglebius (TP_MAXIDLE(tp) > 0)) 1617240985Sglebius tcp_timer_activate(tp, TT_2MSL, 1618240985Sglebius TP_MAXIDLE(tp)); 1619240985Sglebius goto unlock_and_done; 1620240985Sglebius 1621292823Spkelsey#ifdef TCP_RFC7413 1622292823Spkelsey case TCP_FASTOPEN: 1623292823Spkelsey INP_WUNLOCK(inp); 1624292823Spkelsey if (!V_tcp_fastopen_enabled) 1625292823Spkelsey return (EPERM); 1626292823Spkelsey 1627292823Spkelsey error = sooptcopyin(sopt, &optval, sizeof optval, 1628292823Spkelsey sizeof optval); 1629292823Spkelsey if (error) 1630292823Spkelsey return (error); 1631292823Spkelsey 1632292823Spkelsey INP_WLOCK_RECHECK(inp); 1633292823Spkelsey if (optval) { 1634292823Spkelsey tp->t_flags |= TF_FASTOPEN; 1635292823Spkelsey if ((tp->t_state == TCPS_LISTEN) && 1636292823Spkelsey (tp->t_tfo_pending == NULL)) 1637292823Spkelsey tp->t_tfo_pending = 1638292823Spkelsey tcp_fastopen_alloc_counter(); 1639292823Spkelsey } else 1640292823Spkelsey tp->t_flags &= ~TF_FASTOPEN; 1641292823Spkelsey goto unlock_and_done; 1642292823Spkelsey#endif 1643292823Spkelsey 16441541Srgrimes default: 1645178285Srwatson INP_WUNLOCK(inp); 16461541Srgrimes error = ENOPROTOOPT; 16471541Srgrimes break; 16481541Srgrimes } 16491541Srgrimes break; 16501541Srgrimes 165138482Swollman case SOPT_GET: 1652175438Srwatson tp = intotcpcb(inp); 165338482Swollman switch (sopt->sopt_name) { 1654125680Sbms#ifdef TCP_SIGNATURE 1655125890Sbms case TCP_MD5SIG: 1656125680Sbms optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0; 1657178285Srwatson INP_WUNLOCK(inp); 1658138118Srwatson error = sooptcopyout(sopt, &optval, sizeof optval); 1659125680Sbms break; 1660125783Sbms#endif 1661175438Srwatson 16621541Srgrimes case TCP_NODELAY: 166338482Swollman optval = tp->t_flags & TF_NODELAY; 1664178285Srwatson INP_WUNLOCK(inp); 1665138118Srwatson error = sooptcopyout(sopt, &optval, sizeof optval); 16661541Srgrimes break; 16671541Srgrimes case TCP_MAXSEG: 166838482Swollman optval = tp->t_maxseg; 1669178285Srwatson INP_WUNLOCK(inp); 1670138118Srwatson error = sooptcopyout(sopt, &optval, sizeof optval); 16711541Srgrimes break; 16726283Swollman case TCP_NOOPT: 167338482Swollman optval = tp->t_flags & TF_NOOPT; 1674178285Srwatson INP_WUNLOCK(inp); 1675138118Srwatson error = sooptcopyout(sopt, &optval, sizeof optval); 16766283Swollman break; 16776283Swollman case TCP_NOPUSH: 167838482Swollman optval = tp->t_flags & TF_NOPUSH; 1679178285Srwatson INP_WUNLOCK(inp); 1680138118Srwatson error = sooptcopyout(sopt, &optval, sizeof optval); 16816283Swollman break; 1682138118Srwatson case TCP_INFO: 1683138118Srwatson tcp_fill_info(tp, &ti); 1684178285Srwatson INP_WUNLOCK(inp); 1685138118Srwatson error = sooptcopyout(sopt, &ti, sizeof ti); 1686138118Srwatson break; 1687215166Slstewart case TCP_CONGESTION: 1688215166Slstewart bzero(buf, sizeof(buf)); 1689215166Slstewart strlcpy(buf, CC_ALGO(tp)->name, TCP_CA_NAME_MAX); 1690215166Slstewart INP_WUNLOCK(inp); 1691215166Slstewart error = sooptcopyout(sopt, buf, TCP_CA_NAME_MAX); 1692215166Slstewart break; 1693261017Sglebius case TCP_KEEPIDLE: 1694261017Sglebius case TCP_KEEPINTVL: 1695261017Sglebius case TCP_KEEPINIT: 1696261017Sglebius case TCP_KEEPCNT: 1697261017Sglebius switch (sopt->sopt_name) { 1698261017Sglebius case TCP_KEEPIDLE: 1699261017Sglebius ui = tp->t_keepidle / hz; 1700261017Sglebius break; 1701261017Sglebius case TCP_KEEPINTVL: 1702261017Sglebius ui = tp->t_keepintvl / hz; 1703261017Sglebius break; 1704261017Sglebius case TCP_KEEPINIT: 1705261017Sglebius ui = tp->t_keepinit / hz; 1706261017Sglebius break; 1707261017Sglebius case TCP_KEEPCNT: 1708261017Sglebius ui = tp->t_keepcnt; 1709261017Sglebius break; 1710261017Sglebius } 1711261017Sglebius INP_WUNLOCK(inp); 1712261017Sglebius error = sooptcopyout(sopt, &ui, sizeof(ui)); 1713261017Sglebius break; 1714292823Spkelsey#ifdef TCP_RFC7413 1715292823Spkelsey case TCP_FASTOPEN: 1716292823Spkelsey optval = tp->t_flags & TF_FASTOPEN; 1717292823Spkelsey INP_WUNLOCK(inp); 1718292823Spkelsey error = sooptcopyout(sopt, &optval, sizeof optval); 1719292823Spkelsey break; 1720292823Spkelsey#endif 17211541Srgrimes default: 1722178285Srwatson INP_WUNLOCK(inp); 17231541Srgrimes error = ENOPROTOOPT; 17241541Srgrimes break; 17251541Srgrimes } 17261541Srgrimes break; 17271541Srgrimes } 17281541Srgrimes return (error); 17291541Srgrimes} 1730178285Srwatson#undef INP_WLOCK_RECHECK 17311541Srgrimes 17321621Sdg/* 17331541Srgrimes * Attach TCP protocol to socket, allocating 17341541Srgrimes * internet protocol control block, tcp control block, 17351541Srgrimes * bufer space, and entering LISTEN state if to accept connections. 17361541Srgrimes */ 173712296Sphkstatic int 1738167785Sandretcp_attach(struct socket *so) 17391541Srgrimes{ 1740167785Sandre struct tcpcb *tp; 17411541Srgrimes struct inpcb *inp; 17421541Srgrimes int error; 17431541Srgrimes 17441541Srgrimes if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 1745226437Sandre error = soreserve(so, V_tcp_sendspace, V_tcp_recvspace); 17461541Srgrimes if (error) 17471541Srgrimes return (error); 17481541Srgrimes } 1749166405Sandre so->so_rcv.sb_flags |= SB_AUTOSIZE; 1750166405Sandre so->so_snd.sb_flags |= SB_AUTOSIZE; 1751309108Sjch INP_INFO_RLOCK(&V_tcbinfo); 1752181803Sbz error = in_pcballoc(so, &V_tcbinfo); 1753159218Srwatson if (error) { 1754309108Sjch INP_INFO_RUNLOCK(&V_tcbinfo); 17551541Srgrimes return (error); 1756159218Srwatson } 17571541Srgrimes inp = sotoinpcb(so); 175855679Sshin#ifdef INET6 1759185371Sbz if (inp->inp_vflag & INP_IPV6PROTO) { 176055679Sshin inp->inp_vflag |= INP_IPV6; 176155679Sshin inp->in6p_hops = -1; /* use kernel default */ 176255679Sshin } 176355679Sshin else 176455679Sshin#endif 176554263Sshin inp->inp_vflag |= INP_IPV4; 17661541Srgrimes tp = tcp_newtcpcb(inp); 1767157376Srwatson if (tp == NULL) { 1768185344Sbz in_pcbdetach(inp); 1769185370Sbz in_pcbfree(inp); 1770309108Sjch INP_INFO_RUNLOCK(&V_tcbinfo); 17711541Srgrimes return (ENOBUFS); 17721541Srgrimes } 17731541Srgrimes tp->t_state = TCPS_CLOSED; 1774178285Srwatson INP_WUNLOCK(inp); 1775309108Sjch INP_INFO_RUNLOCK(&V_tcbinfo); 17761541Srgrimes return (0); 17771541Srgrimes} 17781541Srgrimes 17791541Srgrimes/* 17801541Srgrimes * Initiate (or continue) disconnect. 17811541Srgrimes * If embryonic state, just send reset (once). 17821541Srgrimes * If in ``let data drain'' option and linger null, just drop. 17831541Srgrimes * Otherwise (hard), mark socket disconnecting and drop 17841541Srgrimes * current input data; switch states based on user close, and 17851541Srgrimes * send segment to peer (with FIN). 17861541Srgrimes */ 1787157376Srwatsonstatic void 1788167785Sandretcp_disconnect(struct tcpcb *tp) 17891541Srgrimes{ 1790146865Srwatson struct inpcb *inp = tp->t_inpcb; 1791146865Srwatson struct socket *so = inp->inp_socket; 17921541Srgrimes 1793309108Sjch INP_INFO_RLOCK_ASSERT(&V_tcbinfo); 1794178285Srwatson INP_WLOCK_ASSERT(inp); 1795146865Srwatson 1796157376Srwatson /* 1797157376Srwatson * Neither tcp_close() nor tcp_drop() should return NULL, as the 1798157376Srwatson * socket is still open. 1799157376Srwatson */ 1800157376Srwatson if (tp->t_state < TCPS_ESTABLISHED) { 18011541Srgrimes tp = tcp_close(tp); 1802157376Srwatson KASSERT(tp != NULL, 1803157376Srwatson ("tcp_disconnect: tcp_close() returned NULL")); 1804157376Srwatson } else if ((so->so_options & SO_LINGER) && so->so_linger == 0) { 180597658Stanimura tp = tcp_drop(tp, 0); 1806157376Srwatson KASSERT(tp != NULL, 1807157376Srwatson ("tcp_disconnect: tcp_drop() returned NULL")); 1808157376Srwatson } else { 180997658Stanimura soisdisconnecting(so); 181097658Stanimura sbflush(&so->so_rcv); 1811157376Srwatson tcp_usrclosed(tp); 1812189848Srwatson if (!(inp->inp_flags & INP_DROPPED)) 1813237263Snp tcp_output(tp); 18141541Srgrimes } 18151541Srgrimes} 18161541Srgrimes 18171541Srgrimes/* 18181541Srgrimes * User issued close, and wish to trail through shutdown states: 18191541Srgrimes * if never received SYN, just forget it. If got a SYN from peer, 18201541Srgrimes * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. 18211541Srgrimes * If already got a FIN from peer, then almost done; go to LAST_ACK 18221541Srgrimes * state. In all other cases, have already sent FIN to peer (e.g. 18231541Srgrimes * after PRU_SHUTDOWN), and just have to play tedious game waiting 18241541Srgrimes * for peer to send FIN or not respond to keep-alives, etc. 18251541Srgrimes * We can let the user exit from the close as soon as the FIN is acked. 18261541Srgrimes */ 1827157376Srwatsonstatic void 1828167785Sandretcp_usrclosed(struct tcpcb *tp) 18291541Srgrimes{ 18301541Srgrimes 1831309108Sjch INP_INFO_RLOCK_ASSERT(&V_tcbinfo); 1832178285Srwatson INP_WLOCK_ASSERT(tp->t_inpcb); 1833146865Srwatson 18341541Srgrimes switch (tp->t_state) { 1835174757Skmacy case TCPS_LISTEN: 1836237263Snp#ifdef TCP_OFFLOAD 1837237263Snp tcp_offload_listen_stop(tp); 1838237263Snp#endif 1839288509Shiren tcp_state_change(tp, TCPS_CLOSED); 1840174757Skmacy /* FALLTHROUGH */ 18411541Srgrimes case TCPS_CLOSED: 18421541Srgrimes tp = tcp_close(tp); 1843157376Srwatson /* 1844157376Srwatson * tcp_close() should never return NULL here as the socket is 1845157376Srwatson * still open. 1846157376Srwatson */ 1847157376Srwatson KASSERT(tp != NULL, 1848157376Srwatson ("tcp_usrclosed: tcp_close() returned NULL")); 18491541Srgrimes break; 18501541Srgrimes 18516283Swollman case TCPS_SYN_SENT: 18521541Srgrimes case TCPS_SYN_RECEIVED: 18536283Swollman tp->t_flags |= TF_NEEDFIN; 18546283Swollman break; 18556283Swollman 18561541Srgrimes case TCPS_ESTABLISHED: 1857254889Smarkj tcp_state_change(tp, TCPS_FIN_WAIT_1); 18581541Srgrimes break; 18591541Srgrimes 18601541Srgrimes case TCPS_CLOSE_WAIT: 1861254889Smarkj tcp_state_change(tp, TCPS_LAST_ACK); 18621541Srgrimes break; 18631541Srgrimes } 1864170153Srwatson if (tp->t_state >= TCPS_FIN_WAIT_2) { 18651541Srgrimes soisdisconnected(tp->t_inpcb->inp_socket); 1866170153Srwatson /* Prevent the connection hanging in FIN_WAIT_2 forever. */ 1867167036Smohans if (tp->t_state == TCPS_FIN_WAIT_2) { 1868167036Smohans int timeout; 1869167036Smohans 1870167036Smohans timeout = (tcp_fast_finwait2_recycle) ? 1871231025Sglebius tcp_finwait2_timeout : TP_MAXIDLE(tp); 1872168615Sandre tcp_timer_activate(tp, TT_2MSL, timeout); 1873167036Smohans } 187411928Solah } 18751541Srgrimes} 1876166807Srwatson 1877166807Srwatson#ifdef DDB 1878166807Srwatsonstatic void 1879166807Srwatsondb_print_indent(int indent) 1880166807Srwatson{ 1881166807Srwatson int i; 1882166807Srwatson 1883166807Srwatson for (i = 0; i < indent; i++) 1884166807Srwatson db_printf(" "); 1885166807Srwatson} 1886166807Srwatson 1887166807Srwatsonstatic void 1888166807Srwatsondb_print_tstate(int t_state) 1889166807Srwatson{ 1890166807Srwatson 1891166807Srwatson switch (t_state) { 1892166807Srwatson case TCPS_CLOSED: 1893166807Srwatson db_printf("TCPS_CLOSED"); 1894166807Srwatson return; 1895166807Srwatson 1896166807Srwatson case TCPS_LISTEN: 1897166807Srwatson db_printf("TCPS_LISTEN"); 1898166807Srwatson return; 1899166807Srwatson 1900166807Srwatson case TCPS_SYN_SENT: 1901166807Srwatson db_printf("TCPS_SYN_SENT"); 1902166807Srwatson return; 1903166807Srwatson 1904166807Srwatson case TCPS_SYN_RECEIVED: 1905166807Srwatson db_printf("TCPS_SYN_RECEIVED"); 1906166807Srwatson return; 1907166807Srwatson 1908166807Srwatson case TCPS_ESTABLISHED: 1909166807Srwatson db_printf("TCPS_ESTABLISHED"); 1910166807Srwatson return; 1911166807Srwatson 1912166807Srwatson case TCPS_CLOSE_WAIT: 1913166807Srwatson db_printf("TCPS_CLOSE_WAIT"); 1914166807Srwatson return; 1915166807Srwatson 1916166807Srwatson case TCPS_FIN_WAIT_1: 1917166807Srwatson db_printf("TCPS_FIN_WAIT_1"); 1918166807Srwatson return; 1919166807Srwatson 1920166807Srwatson case TCPS_CLOSING: 1921166807Srwatson db_printf("TCPS_CLOSING"); 1922166807Srwatson return; 1923166807Srwatson 1924166807Srwatson case TCPS_LAST_ACK: 1925166807Srwatson db_printf("TCPS_LAST_ACK"); 1926166807Srwatson return; 1927166807Srwatson 1928166807Srwatson case TCPS_FIN_WAIT_2: 1929166807Srwatson db_printf("TCPS_FIN_WAIT_2"); 1930166807Srwatson return; 1931166807Srwatson 1932166807Srwatson case TCPS_TIME_WAIT: 1933166807Srwatson db_printf("TCPS_TIME_WAIT"); 1934166807Srwatson return; 1935166807Srwatson 1936166807Srwatson default: 1937166807Srwatson db_printf("unknown"); 1938166807Srwatson return; 1939166807Srwatson } 1940166807Srwatson} 1941166807Srwatson 1942166807Srwatsonstatic void 1943166807Srwatsondb_print_tflags(u_int t_flags) 1944166807Srwatson{ 1945166807Srwatson int comma; 1946166807Srwatson 1947166807Srwatson comma = 0; 1948166807Srwatson if (t_flags & TF_ACKNOW) { 1949166807Srwatson db_printf("%sTF_ACKNOW", comma ? ", " : ""); 1950166807Srwatson comma = 1; 1951166807Srwatson } 1952166807Srwatson if (t_flags & TF_DELACK) { 1953166807Srwatson db_printf("%sTF_DELACK", comma ? ", " : ""); 1954166807Srwatson comma = 1; 1955166807Srwatson } 1956166807Srwatson if (t_flags & TF_NODELAY) { 1957166807Srwatson db_printf("%sTF_NODELAY", comma ? ", " : ""); 1958166807Srwatson comma = 1; 1959166807Srwatson } 1960166807Srwatson if (t_flags & TF_NOOPT) { 1961166807Srwatson db_printf("%sTF_NOOPT", comma ? ", " : ""); 1962166807Srwatson comma = 1; 1963166807Srwatson } 1964166807Srwatson if (t_flags & TF_SENTFIN) { 1965166807Srwatson db_printf("%sTF_SENTFIN", comma ? ", " : ""); 1966166807Srwatson comma = 1; 1967166807Srwatson } 1968166807Srwatson if (t_flags & TF_REQ_SCALE) { 1969166807Srwatson db_printf("%sTF_REQ_SCALE", comma ? ", " : ""); 1970166807Srwatson comma = 1; 1971166807Srwatson } 1972166807Srwatson if (t_flags & TF_RCVD_SCALE) { 1973166807Srwatson db_printf("%sTF_RECVD_SCALE", comma ? ", " : ""); 1974166807Srwatson comma = 1; 1975166807Srwatson } 1976166807Srwatson if (t_flags & TF_REQ_TSTMP) { 1977166807Srwatson db_printf("%sTF_REQ_TSTMP", comma ? ", " : ""); 1978166807Srwatson comma = 1; 1979166807Srwatson } 1980166807Srwatson if (t_flags & TF_RCVD_TSTMP) { 1981166807Srwatson db_printf("%sTF_RCVD_TSTMP", comma ? ", " : ""); 1982166807Srwatson comma = 1; 1983166807Srwatson } 1984166807Srwatson if (t_flags & TF_SACK_PERMIT) { 1985166807Srwatson db_printf("%sTF_SACK_PERMIT", comma ? ", " : ""); 1986166807Srwatson comma = 1; 1987166807Srwatson } 1988166807Srwatson if (t_flags & TF_NEEDSYN) { 1989166807Srwatson db_printf("%sTF_NEEDSYN", comma ? ", " : ""); 1990166807Srwatson comma = 1; 1991166807Srwatson } 1992166807Srwatson if (t_flags & TF_NEEDFIN) { 1993166807Srwatson db_printf("%sTF_NEEDFIN", comma ? ", " : ""); 1994166807Srwatson comma = 1; 1995166807Srwatson } 1996166807Srwatson if (t_flags & TF_NOPUSH) { 1997166807Srwatson db_printf("%sTF_NOPUSH", comma ? ", " : ""); 1998166807Srwatson comma = 1; 1999166807Srwatson } 2000166807Srwatson if (t_flags & TF_MORETOCOME) { 2001166807Srwatson db_printf("%sTF_MORETOCOME", comma ? ", " : ""); 2002166807Srwatson comma = 1; 2003166807Srwatson } 2004166807Srwatson if (t_flags & TF_LQ_OVERFLOW) { 2005166807Srwatson db_printf("%sTF_LQ_OVERFLOW", comma ? ", " : ""); 2006166807Srwatson comma = 1; 2007166807Srwatson } 2008166807Srwatson if (t_flags & TF_LASTIDLE) { 2009166807Srwatson db_printf("%sTF_LASTIDLE", comma ? ", " : ""); 2010166807Srwatson comma = 1; 2011166807Srwatson } 2012166807Srwatson if (t_flags & TF_RXWIN0SENT) { 2013166807Srwatson db_printf("%sTF_RXWIN0SENT", comma ? ", " : ""); 2014166807Srwatson comma = 1; 2015166807Srwatson } 2016166807Srwatson if (t_flags & TF_FASTRECOVERY) { 2017166807Srwatson db_printf("%sTF_FASTRECOVERY", comma ? ", " : ""); 2018166807Srwatson comma = 1; 2019166807Srwatson } 2020215166Slstewart if (t_flags & TF_CONGRECOVERY) { 2021215166Slstewart db_printf("%sTF_CONGRECOVERY", comma ? ", " : ""); 2022215166Slstewart comma = 1; 2023215166Slstewart } 2024166807Srwatson if (t_flags & TF_WASFRECOVERY) { 2025166807Srwatson db_printf("%sTF_WASFRECOVERY", comma ? ", " : ""); 2026166807Srwatson comma = 1; 2027166807Srwatson } 2028166807Srwatson if (t_flags & TF_SIGNATURE) { 2029166807Srwatson db_printf("%sTF_SIGNATURE", comma ? ", " : ""); 2030166807Srwatson comma = 1; 2031166807Srwatson } 2032166807Srwatson if (t_flags & TF_FORCEDATA) { 2033166807Srwatson db_printf("%sTF_FORCEDATA", comma ? ", " : ""); 2034166807Srwatson comma = 1; 2035166807Srwatson } 2036166807Srwatson if (t_flags & TF_TSO) { 2037166807Srwatson db_printf("%sTF_TSO", comma ? ", " : ""); 2038166807Srwatson comma = 1; 2039166807Srwatson } 2040181056Srpaulo if (t_flags & TF_ECN_PERMIT) { 2041181056Srpaulo db_printf("%sTF_ECN_PERMIT", comma ? ", " : ""); 2042181056Srpaulo comma = 1; 2043181056Srpaulo } 2044292823Spkelsey if (t_flags & TF_FASTOPEN) { 2045292823Spkelsey db_printf("%sTF_FASTOPEN", comma ? ", " : ""); 2046292823Spkelsey comma = 1; 2047292823Spkelsey } 2048166807Srwatson} 2049166807Srwatson 2050166807Srwatsonstatic void 2051166807Srwatsondb_print_toobflags(char t_oobflags) 2052166807Srwatson{ 2053166807Srwatson int comma; 2054166807Srwatson 2055166807Srwatson comma = 0; 2056166807Srwatson if (t_oobflags & TCPOOB_HAVEDATA) { 2057166807Srwatson db_printf("%sTCPOOB_HAVEDATA", comma ? ", " : ""); 2058166807Srwatson comma = 1; 2059166807Srwatson } 2060166807Srwatson if (t_oobflags & TCPOOB_HADDATA) { 2061166807Srwatson db_printf("%sTCPOOB_HADDATA", comma ? ", " : ""); 2062166807Srwatson comma = 1; 2063166807Srwatson } 2064166807Srwatson} 2065166807Srwatson 2066166807Srwatsonstatic void 2067166807Srwatsondb_print_tcpcb(struct tcpcb *tp, const char *name, int indent) 2068166807Srwatson{ 2069166807Srwatson 2070166807Srwatson db_print_indent(indent); 2071166807Srwatson db_printf("%s at %p\n", name, tp); 2072166807Srwatson 2073166807Srwatson indent += 2; 2074166807Srwatson 2075166807Srwatson db_print_indent(indent); 2076166807Srwatson db_printf("t_segq first: %p t_segqlen: %d t_dupacks: %d\n", 2077166807Srwatson LIST_FIRST(&tp->t_segq), tp->t_segqlen, tp->t_dupacks); 2078166807Srwatson 2079166807Srwatson db_print_indent(indent); 2080172074Srwatson db_printf("tt_rexmt: %p tt_persist: %p tt_keep: %p\n", 2081172309Ssilby &tp->t_timers->tt_rexmt, &tp->t_timers->tt_persist, &tp->t_timers->tt_keep); 2082166807Srwatson 2083166807Srwatson db_print_indent(indent); 2084172309Ssilby db_printf("tt_2msl: %p tt_delack: %p t_inpcb: %p\n", &tp->t_timers->tt_2msl, 2085172309Ssilby &tp->t_timers->tt_delack, tp->t_inpcb); 2086166807Srwatson 2087166807Srwatson db_print_indent(indent); 2088166807Srwatson db_printf("t_state: %d (", tp->t_state); 2089166807Srwatson db_print_tstate(tp->t_state); 2090166807Srwatson db_printf(")\n"); 2091166807Srwatson 2092166807Srwatson db_print_indent(indent); 2093166807Srwatson db_printf("t_flags: 0x%x (", tp->t_flags); 2094166807Srwatson db_print_tflags(tp->t_flags); 2095166807Srwatson db_printf(")\n"); 2096166807Srwatson 2097166807Srwatson db_print_indent(indent); 2098166807Srwatson db_printf("snd_una: 0x%08x snd_max: 0x%08x snd_nxt: x0%08x\n", 2099166807Srwatson tp->snd_una, tp->snd_max, tp->snd_nxt); 2100166807Srwatson 2101166807Srwatson db_print_indent(indent); 2102166807Srwatson db_printf("snd_up: 0x%08x snd_wl1: 0x%08x snd_wl2: 0x%08x\n", 2103166807Srwatson tp->snd_up, tp->snd_wl1, tp->snd_wl2); 2104166807Srwatson 2105166807Srwatson db_print_indent(indent); 2106166807Srwatson db_printf("iss: 0x%08x irs: 0x%08x rcv_nxt: 0x%08x\n", 2107166807Srwatson tp->iss, tp->irs, tp->rcv_nxt); 2108166807Srwatson 2109166807Srwatson db_print_indent(indent); 2110166807Srwatson db_printf("rcv_adv: 0x%08x rcv_wnd: %lu rcv_up: 0x%08x\n", 2111166807Srwatson tp->rcv_adv, tp->rcv_wnd, tp->rcv_up); 2112166807Srwatson 2113166807Srwatson db_print_indent(indent); 2114212765Sandre db_printf("snd_wnd: %lu snd_cwnd: %lu\n", 2115212765Sandre tp->snd_wnd, tp->snd_cwnd); 2116166807Srwatson 2117166807Srwatson db_print_indent(indent); 2118212765Sandre db_printf("snd_ssthresh: %lu snd_recover: " 2119212765Sandre "0x%08x\n", tp->snd_ssthresh, tp->snd_recover); 2120166807Srwatson 2121166807Srwatson db_print_indent(indent); 2122194303Sjhb db_printf("t_maxopd: %u t_rcvtime: %u t_startime: %u\n", 2123166807Srwatson tp->t_maxopd, tp->t_rcvtime, tp->t_starttime); 2124166807Srwatson 2125166807Srwatson db_print_indent(indent); 2126212765Sandre db_printf("t_rttime: %u t_rtsq: 0x%08x\n", 2127212765Sandre tp->t_rtttime, tp->t_rtseq); 2128166807Srwatson 2129166807Srwatson db_print_indent(indent); 2130212765Sandre db_printf("t_rxtcur: %d t_maxseg: %u t_srtt: %d\n", 2131212765Sandre tp->t_rxtcur, tp->t_maxseg, tp->t_srtt); 2132166807Srwatson 2133166807Srwatson db_print_indent(indent); 2134166807Srwatson db_printf("t_rttvar: %d t_rxtshift: %d t_rttmin: %u " 2135166807Srwatson "t_rttbest: %u\n", tp->t_rttvar, tp->t_rxtshift, tp->t_rttmin, 2136166807Srwatson tp->t_rttbest); 2137166807Srwatson 2138166807Srwatson db_print_indent(indent); 2139166807Srwatson db_printf("t_rttupdated: %lu max_sndwnd: %lu t_softerror: %d\n", 2140166807Srwatson tp->t_rttupdated, tp->max_sndwnd, tp->t_softerror); 2141166807Srwatson 2142166807Srwatson db_print_indent(indent); 2143166807Srwatson db_printf("t_oobflags: 0x%x (", tp->t_oobflags); 2144166807Srwatson db_print_toobflags(tp->t_oobflags); 2145166807Srwatson db_printf(") t_iobc: 0x%02x\n", tp->t_iobc); 2146166807Srwatson 2147166807Srwatson db_print_indent(indent); 2148166807Srwatson db_printf("snd_scale: %u rcv_scale: %u request_r_scale: %u\n", 2149166807Srwatson tp->snd_scale, tp->rcv_scale, tp->request_r_scale); 2150166807Srwatson 2151166807Srwatson db_print_indent(indent); 2152194303Sjhb db_printf("ts_recent: %u ts_recent_age: %u\n", 2153169318Sandre tp->ts_recent, tp->ts_recent_age); 2154166807Srwatson 2155166807Srwatson db_print_indent(indent); 2156166807Srwatson db_printf("ts_offset: %u last_ack_sent: 0x%08x snd_cwnd_prev: " 2157166807Srwatson "%lu\n", tp->ts_offset, tp->last_ack_sent, tp->snd_cwnd_prev); 2158166807Srwatson 2159166807Srwatson db_print_indent(indent); 2160166807Srwatson db_printf("snd_ssthresh_prev: %lu snd_recover_prev: 0x%08x " 2161194303Sjhb "t_badrxtwin: %u\n", tp->snd_ssthresh_prev, 2162166807Srwatson tp->snd_recover_prev, tp->t_badrxtwin); 2163166807Srwatson 2164166807Srwatson db_print_indent(indent); 2165169317Sandre db_printf("snd_numholes: %d snd_holes first: %p\n", 2166169317Sandre tp->snd_numholes, TAILQ_FIRST(&tp->snd_holes)); 2167166807Srwatson 2168166807Srwatson db_print_indent(indent); 2169166807Srwatson db_printf("snd_fack: 0x%08x rcv_numsacks: %d sack_newdata: " 2170166807Srwatson "0x%08x\n", tp->snd_fack, tp->rcv_numsacks, tp->sack_newdata); 2171166807Srwatson 2172166807Srwatson /* Skip sackblks, sackhint. */ 2173166807Srwatson 2174166807Srwatson db_print_indent(indent); 2175166807Srwatson db_printf("t_rttlow: %d rfbuf_ts: %u rfbuf_cnt: %d\n", 2176166807Srwatson tp->t_rttlow, tp->rfbuf_ts, tp->rfbuf_cnt); 2177166807Srwatson} 2178166807Srwatson 2179166807SrwatsonDB_SHOW_COMMAND(tcpcb, db_show_tcpcb) 2180166807Srwatson{ 2181166807Srwatson struct tcpcb *tp; 2182166807Srwatson 2183166807Srwatson if (!have_addr) { 2184166807Srwatson db_printf("usage: show tcpcb <addr>\n"); 2185166807Srwatson return; 2186166807Srwatson } 2187166807Srwatson tp = (struct tcpcb *)addr; 2188166807Srwatson 2189166807Srwatson db_print_tcpcb(tp, "tcpcb", 0); 2190166807Srwatson} 2191166807Srwatson#endif 2192