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

Cache object: 35cb72925f0fb6607bb90d1f17d27808


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