The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/tcp_usrreq.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 7ce21ae46d3a32b51743377c0b2a7fdd


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.