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

Cache object: 1ba3fd3120bc5a62047df939c0cedd3d


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