home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netinet / tcp_usrreq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-08  |  11.9 KB  |  499 lines

  1. /*
  2.  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
  3.  * 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.  *    @(#)tcp_usrreq.c    7.15 (Berkeley) 6/28/90
  34.  */
  35.  
  36. #include "param.h"
  37. #include "systm.h"
  38. #include "malloc.h"
  39. #include "mbuf.h"
  40. #include "socket.h"
  41. #include "socketvar.h"
  42. #include "protosw.h"
  43. #include "errno.h"
  44. #include "stat.h"
  45.  
  46. #include "../net/if.h"
  47. #include "../net/route.h"
  48.  
  49. #include "in.h"
  50. #include "in_systm.h"
  51. #include "ip.h"
  52. #include "in_pcb.h"
  53. #include "ip_var.h"
  54. #include "tcp.h"
  55. #include "tcp_fsm.h"
  56. #include "tcp_seq.h"
  57. #include "tcp_timer.h"
  58. #include "tcp_var.h"
  59. #include "tcpip.h"
  60. #include "tcp_debug.h"
  61.  
  62. /*
  63.  * TCP protocol interface to socket abstraction.
  64.  */
  65. extern    char *tcpstates[];
  66. struct    tcpcb *tcp_newtcpcb();
  67.  
  68. /*
  69.  * Process a TCP user request for TCP tb.  If this is a send request
  70.  * then m is the mbuf chain of send data.  If this is a timer expiration
  71.  * (called from the software clock routine), then timertype tells which timer.
  72.  */
  73. /*ARGSUSED*/
  74. tcp_usrreq(so, req, m, nam, control)
  75.     struct socket *so;
  76.     int req;
  77.     struct mbuf *m, *nam, *control;
  78. {
  79.     register struct inpcb *inp;
  80.     register struct tcpcb *tp;
  81.     int s;
  82.     int error = 0;
  83.     int ostate;
  84.  
  85.     if (req == PRU_CONTROL)
  86.         return (in_control(so, (int)m, (caddr_t)nam,
  87.             (struct ifnet *)control));
  88.     if (control && control->m_len) {
  89.         m_freem(control);
  90.         if (m)
  91.             m_freem(m);
  92.         return (EINVAL);
  93.     }
  94.  
  95.     s = splnet();
  96.     inp = sotoinpcb(so);
  97.     /*
  98.      * When a TCP is attached to a socket, then there will be
  99.      * a (struct inpcb) pointed at by the socket, and this
  100.      * structure will point at a subsidary (struct tcpcb).
  101.      */
  102.     if (inp == 0 && req != PRU_ATTACH) {
  103.         splx(s);
  104.         return (EINVAL);        /* XXX */
  105.     }
  106.     if (inp) {
  107.         tp = intotcpcb(inp);
  108.         /* WHAT IF TP IS 0? */
  109. #ifdef KPROF
  110.         tcp_acounts[tp->t_state][req]++;
  111. #endif
  112.         ostate = tp->t_state;
  113.     } else
  114.         ostate = 0;
  115.     switch (req) {
  116.  
  117.     /*
  118.      * TCP attaches to socket via PRU_ATTACH, reserving space,
  119.      * and an internet control block.
  120.      */
  121.     case PRU_ATTACH:
  122.         if (inp) {
  123.             error = EISCONN;
  124.             break;
  125.         }
  126.         error = tcp_attach(so);
  127.         if (error)
  128.             break;
  129.         if ((so->so_options & SO_LINGER) && so->so_linger == 0)
  130.             so->so_linger = TCP_LINGERTIME;
  131.         tp = sototcpcb(so);
  132.         break;
  133.  
  134.     /*
  135.      * PRU_DETACH detaches the TCP protocol from the socket.
  136.      * If the protocol state is non-embryonic, then can't
  137.      * do this directly: have to initiate a PRU_DISCONNECT,
  138.      * which may finish later; embryonic TCB's can just
  139.      * be discarded here.
  140.      */
  141.     case PRU_DETACH:
  142.         if (tp->t_state > TCPS_LISTEN)
  143.             tp = tcp_disconnect(tp);
  144.         else
  145.             tp = tcp_close(tp);
  146.         break;
  147.  
  148.     /*
  149.      * Give the socket an address.
  150.      */
  151.     case PRU_BIND:
  152.         error = in_pcbbind(inp, nam);
  153.         if (error)
  154.             break;
  155.         break;
  156.  
  157.     /*
  158.      * Prepare to accept connections.
  159.      */
  160.     case PRU_LISTEN:
  161.         if (inp->inp_lport == 0)
  162.             error = in_pcbbind(inp, (struct mbuf *)0);
  163.         if (error == 0)
  164.             tp->t_state = TCPS_LISTEN;
  165.         break;
  166.  
  167.     /*
  168.      * Initiate connection to peer.
  169.      * Create a template for use in transmissions on this connection.
  170.      * Enter SYN_SENT state, and mark socket as connecting.
  171.      * Start keep-alive timer, and seed output sequence space.
  172.      * Send initial segment on connection.
  173.      */
  174.     case PRU_CONNECT:
  175.         if (inp->inp_lport == 0) {
  176.             error = in_pcbbind(inp, (struct mbuf *)0);
  177.             if (error)
  178.                 break;
  179.         }
  180.         error = in_pcbconnect(inp, nam);
  181.         if (error)
  182.             break;
  183.         tp->t_template = tcp_template(tp);
  184.         if (tp->t_template == 0) {
  185.             in_pcbdisconnect(inp);
  186.             error = ENOBUFS;
  187.             break;
  188.         }
  189.         soisconnecting(so);
  190.         tcpstat.tcps_connattempt++;
  191.         tp->t_state = TCPS_SYN_SENT;
  192.         tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
  193.         tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
  194.         tcp_sendseqinit(tp);
  195.         error = tcp_output(tp);
  196.         break;
  197.  
  198.     /*
  199.      * Create a TCP connection between two sockets.
  200.      */
  201.     case PRU_CONNECT2:
  202.         error = EOPNOTSUPP;
  203.         break;
  204.  
  205.     /*
  206.      * Initiate disconnect from peer.
  207.      * If connection never passed embryonic stage, just drop;
  208.      * else if don't need to let data drain, then can just drop anyways,
  209.      * else have to begin TCP shutdown process: mark socket disconnecting,
  210.      * drain unread data, state switch to reflect user close, and
  211.      * send segment (e.g. FIN) to peer.  Socket will be really disconnected
  212.      * when peer sends FIN and acks ours.
  213.      *
  214.      * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
  215.      */
  216.     case PRU_DISCONNECT:
  217.         tp = tcp_disconnect(tp);
  218.         break;
  219.  
  220.     /*
  221.      * Accept a connection.  Essentially all the work is
  222.      * done at higher levels; just return the address
  223.      * of the peer, storing through addr.
  224.      */
  225.     case PRU_ACCEPT: {
  226.         struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
  227.  
  228.         nam->m_len = sizeof (struct sockaddr_in);
  229.         sin->sin_family = AF_INET;
  230.         sin->sin_len = sizeof(*sin);
  231.         sin->sin_port = inp->inp_fport;
  232.         sin->sin_addr = inp->inp_faddr;
  233.         break;
  234.         }
  235.  
  236.     /*
  237.      * Mark the connection as being incapable of further output.
  238.      */
  239.     case PRU_SHUTDOWN:
  240.         socantsendmore(so);
  241.         tp = tcp_usrclosed(tp);
  242.         if (tp)
  243.             error = tcp_output(tp);
  244.         break;
  245.  
  246.     /*
  247.      * After a receive, possibly send window update to peer.
  248.      */
  249.     case PRU_RCVD:
  250.         (void) tcp_output(tp);
  251.         break;
  252.  
  253.     /*
  254.      * Do a send by putting data in output queue and updating urgent
  255.      * marker if URG set.  Possibly send more data.
  256.      */
  257.     case PRU_SEND:
  258.         sbappend(&so->so_snd, m);
  259.         error = tcp_output(tp);
  260.         break;
  261.  
  262.     /*
  263.      * Abort the TCP.
  264.      */
  265.     case PRU_ABORT:
  266.         tp = tcp_drop(tp, ECONNABORTED);
  267.         break;
  268.  
  269.     case PRU_SENSE:
  270.         ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
  271.         (void) splx(s);
  272.         return (0);
  273.  
  274.     case PRU_RCVOOB:
  275.         if ((so->so_oobmark == 0 &&
  276.             (so->so_state & SS_RCVATMARK) == 0) ||
  277.             so->so_options & SO_OOBINLINE ||
  278.             tp->t_oobflags & TCPOOB_HADDATA) {
  279.             error = EINVAL;
  280.             break;
  281.         }
  282.         if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
  283.             error = EWOULDBLOCK;
  284.             break;
  285.         }
  286.         m->m_len = 1;
  287.         *mtod(m, caddr_t) = tp->t_iobc;
  288.         if (((int)nam & MSG_PEEK) == 0)
  289.             tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
  290.         break;
  291.  
  292.     case PRU_SENDOOB:
  293.         if (sbspace(&so->so_snd) < -512) {
  294.             m_freem(m);
  295.             error = ENOBUFS;
  296.             break;
  297.         }
  298.         /*
  299.          * According to RFC961 (Assigned Protocols),
  300.          * the urgent pointer points to the last octet
  301.          * of urgent data.  We continue, however,
  302.          * to consider it to indicate the first octet
  303.          * of data past the urgent section.
  304.          * Otherwise, snd_up should be one lower.
  305.          */
  306.         sbappend(&so->so_snd, m);
  307.         tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
  308.         tp->t_force = 1;
  309.         error = tcp_output(tp);
  310.         tp->t_force = 0;
  311.         break;
  312.  
  313.     case PRU_SOCKADDR:
  314.         in_setsockaddr(inp, nam);
  315.         break;
  316.  
  317.     case PRU_PEERADDR:
  318.         in_setpeeraddr(inp, nam);
  319.         break;
  320.  
  321.     /*
  322.      * TCP slow timer went off; going through this
  323.      * routine for tracing's sake.
  324.      */
  325.     case PRU_SLOWTIMO:
  326.         tp = tcp_timers(tp, (int)nam);
  327.         req |= (int)nam << 8;        /* for debug's sake */
  328.         break;
  329.  
  330.     default:
  331.         panic("tcp_usrreq");
  332.     }
  333.     if (tp && (so->so_options & SO_DEBUG))
  334.         tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
  335.     splx(s);
  336.     return (error);
  337. }
  338.  
  339. tcp_ctloutput(op, so, level, optname, mp)
  340.     int op;
  341.     struct socket *so;
  342.     int level, optname;
  343.     struct mbuf **mp;
  344. {
  345.     int error = 0;
  346.     struct inpcb *inp = sotoinpcb(so);
  347.     register struct tcpcb *tp = intotcpcb(inp);
  348.     register struct mbuf *m;
  349.  
  350.     if (level != IPPROTO_TCP)
  351.         return (ip_ctloutput(op, so, level, optname, mp));
  352.  
  353.     switch (op) {
  354.  
  355.     case PRCO_SETOPT:
  356.         m = *mp;
  357.         switch (optname) {
  358.  
  359.         case TCP_NODELAY:
  360.             if (m == NULL || m->m_len < sizeof (int))
  361.                 error = EINVAL;
  362.             else if (*mtod(m, int *))
  363.                 tp->t_flags |= TF_NODELAY;
  364.             else
  365.                 tp->t_flags &= ~TF_NODELAY;
  366.             break;
  367.  
  368.         case TCP_MAXSEG:    /* not yet */
  369.         default:
  370.             error = EINVAL;
  371.             break;
  372.         }
  373.         if (m)
  374.             (void) m_free(m);
  375.         break;
  376.  
  377.     case PRCO_GETOPT:
  378.         *mp = m = m_get(M_WAIT, MT_SOOPTS);
  379.         m->m_len = sizeof(int);
  380.  
  381.         switch (optname) {
  382.         case TCP_NODELAY:
  383.             *mtod(m, int *) = tp->t_flags & TF_NODELAY;
  384.             break;
  385.         case TCP_MAXSEG:
  386.             *mtod(m, int *) = tp->t_maxseg;
  387.             break;
  388.         default:
  389.             error = EINVAL;
  390.             break;
  391.         }
  392.         break;
  393.     }
  394.     return (error);
  395. }
  396.  
  397. u_long    tcp_sendspace = 1024*4;
  398. u_long    tcp_recvspace = 1024*4;
  399.  
  400. /*
  401.  * Attach TCP protocol to socket, allocating
  402.  * internet protocol control block, tcp control block,
  403.  * bufer space, and entering LISTEN state if to accept connections.
  404.  */
  405. tcp_attach(so)
  406.     struct socket *so;
  407. {
  408.     register struct tcpcb *tp;
  409.     struct inpcb *inp;
  410.     int error;
  411.  
  412.     if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  413.         error = soreserve(so, tcp_sendspace, tcp_recvspace);
  414.         if (error)
  415.             return (error);
  416.     }
  417.     error = in_pcballoc(so, &tcb);
  418.     if (error)
  419.         return (error);
  420.     inp = sotoinpcb(so);
  421.     tp = tcp_newtcpcb(inp);
  422.     if (tp == 0) {
  423.         int nofd = so->so_state & SS_NOFDREF;    /* XXX */
  424.  
  425.         so->so_state &= ~SS_NOFDREF;    /* don't free the socket yet */
  426.         in_pcbdetach(inp);
  427.         so->so_state |= nofd;
  428.         return (ENOBUFS);
  429.     }
  430.     tp->t_state = TCPS_CLOSED;
  431.     return (0);
  432. }
  433.  
  434. /*
  435.  * Initiate (or continue) disconnect.
  436.  * If embryonic state, just send reset (once).
  437.  * If in ``let data drain'' option and linger null, just drop.
  438.  * Otherwise (hard), mark socket disconnecting and drop
  439.  * current input data; switch states based on user close, and
  440.  * send segment to peer (with FIN).
  441.  */
  442. struct tcpcb *
  443. tcp_disconnect(tp)
  444.     register struct tcpcb *tp;
  445. {
  446.     struct socket *so = tp->t_inpcb->inp_socket;
  447.  
  448.     if (tp->t_state < TCPS_ESTABLISHED)
  449.         tp = tcp_close(tp);
  450.     else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
  451.         tp = tcp_drop(tp, 0);
  452.     else {
  453.         soisdisconnecting(so);
  454.         sbflush(&so->so_rcv);
  455.         tp = tcp_usrclosed(tp);
  456.         if (tp)
  457.             (void) tcp_output(tp);
  458.     }
  459.     return (tp);
  460. }
  461.  
  462. /*
  463.  * User issued close, and wish to trail through shutdown states:
  464.  * if never received SYN, just forget it.  If got a SYN from peer,
  465.  * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
  466.  * If already got a FIN from peer, then almost done; go to LAST_ACK
  467.  * state.  In all other cases, have already sent FIN to peer (e.g.
  468.  * after PRU_SHUTDOWN), and just have to play tedious game waiting
  469.  * for peer to send FIN or not respond to keep-alives, etc.
  470.  * We can let the user exit from the close as soon as the FIN is acked.
  471.  */
  472. struct tcpcb *
  473. tcp_usrclosed(tp)
  474.     register struct tcpcb *tp;
  475. {
  476.  
  477.     switch (tp->t_state) {
  478.  
  479.     case TCPS_CLOSED:
  480.     case TCPS_LISTEN:
  481.     case TCPS_SYN_SENT:
  482.         tp->t_state = TCPS_CLOSED;
  483.         tp = tcp_close(tp);
  484.         break;
  485.  
  486.     case TCPS_SYN_RECEIVED:
  487.     case TCPS_ESTABLISHED:
  488.         tp->t_state = TCPS_FIN_WAIT_1;
  489.         break;
  490.  
  491.     case TCPS_CLOSE_WAIT:
  492.         tp->t_state = TCPS_LAST_ACK;
  493.         break;
  494.     }
  495.     if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
  496.         soisdisconnected(tp->t_inpcb->inp_socket);
  497.     return (tp);
  498. }
  499.