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

Cache object: 1b6662af9605f092e559cea3b437d884


[ 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.