many more comments; cleaner
authorBill Joy <root@ucbvax.Berkeley.EDU>
Tue, 22 Dec 1981 03:00:08 +0000 (19:00 -0800)
committerBill Joy <root@ucbvax.Berkeley.EDU>
Tue, 22 Dec 1981 03:00:08 +0000 (19:00 -0800)
SCCS-vsn: sys/netinet/tcp_usrreq.c 1.45

usr/src/sys/netinet/tcp_usrreq.c

index a618b6f..9d9a07f 100644 (file)
@@ -1,4 +1,4 @@
-/* tcp_usrreq.c 1.44 81/12/20 */
+/* tcp_usrreq.c 1.45 81/12/21 */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../net/tcp_debug.h"
 #include "../errno.h"
 
 #include "../net/tcp_debug.h"
 #include "../errno.h"
 
-extern char *tcpstates[];
+/*
+ * TCP protocol interface to socket abstraction.
+ */
+extern char *tcpstates[];
 struct tcpcb *tcp_newtcpcb();
 struct tcpcb *tcp_newtcpcb();
+
 /*
 /*
- * Process a TCP user request for tcp tb.  If this is a send request
+ * Process a TCP user request for TCP tb.  If this is a send request
  * then m is the mbuf chain of send data.  If this is a timer expiration
  * (called from the software clock routine), then timertype tells which timer.
  */
  * then m is the mbuf chain of send data.  If this is a timer expiration
  * (called from the software clock routine), then timertype tells which timer.
  */
@@ -42,12 +46,23 @@ tcp_usrreq(so, req, m, addr)
 COUNT(TCP_USRREQ);
 
        /*
 COUNT(TCP_USRREQ);
 
        /*
-        * Make sure attached.  If not,
-        * only PRU_ATTACH is valid.
+        * When a TCP is attached to a socket, then there will be
+        * a (struct inpcb) pointed at by the socket, and this
+        * structure will point at a subsidary (struct tcpcb).
+        * The normal sequence of events is:
+        *      PRU_ATTACH              creating these structures
+        *      PRU_CONNECT             connecting to a remote peer
+        *      (PRU_SEND|PRU_RCVD)*    exchanging data
+        *      PRU_DISCONNECT          disconnecting from remote peer
+        *      PRU_DETACH              deleting the structures
+        * With the operations from PRU_CONNECT through PRU_DISCONNECT
+        * possible repeated several times.
+        *
+        * MULTIPLE CONNECTS ARE NOT YET IMPLEMENTED.
         */
        if (inp == 0 && req != PRU_ATTACH) {
                splx(s);
         */
        if (inp == 0 && req != PRU_ATTACH) {
                splx(s);
-               return (EINVAL);
+               return (EINVAL);                /* XXX */
        }
        if (inp) {
                tp = intotcpcb(inp);
        }
        if (inp) {
                tp = intotcpcb(inp);
@@ -58,42 +73,56 @@ COUNT(TCP_USRREQ);
        }
        switch (req) {
 
        }
        switch (req) {
 
+       /*
+        * TCP attaches to socket via PRU_ATTACH, reserving space,
+        * and internet and TCP control blocks.
+        * If the socket is to receive connections,
+        * then the LISTEN state is entered.
+        */
        case PRU_ATTACH:
                if (inp) {
                        error = EISCONN;
                        break;
                }
        case PRU_ATTACH:
                if (inp) {
                        error = EISCONN;
                        break;
                }
-               error = in_pcbattach(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr);
+               error = tcp_attach(so, (struct sockaddr *)addr);
                if (error)
                        break;
                if (error)
                        break;
-               inp = (struct inpcb *)so->so_pcb;
-               tp = tcp_newtcpcb(inp);
-               if (so->so_options & SO_ACCEPTCONN) {
-                       if (tp == 0) {
-                               in_pcbdetach(inp);
-                               error = ENOBUFS;
-                               break;
-                       }
-                       tp->t_state = TCPS_LISTEN;
-               } else
-                       tp->t_state = TCPS_CLOSED;
+               tp = sototcpcb(so);
                break;
 
                break;
 
+       /*
+        * PRU_DETACH detaches the TCP protocol from the socket.
+        * If the protocol state is non-embryonic, then can't
+        * do this directly: have to initiate a PRU_DISCONNECT,
+        * which may finish later; embryonic TCB's can just
+        * be discarded here.
+        */
        case PRU_DETACH:
        case PRU_DETACH:
-               if (tp)
-                       goto disconn;
-               in_pcbdetach(inp);
+               if (tp->t_state > TCPS_LISTEN)
+                       tcp_disconnect(tp);
+               else {
+                       tcp_close(tp);
+                       tp = 0;
+               }
                break;
 
                break;
 
+       /*
+        * Initiate connection to peer.
+        * Create a template for use in transmissions on this connection.
+        * Enter SYN_SENT state, and mark socket as connecting.
+        * Start keep-alive timer, and seed output sequence space.
+        * Send initial segment on connection.
+        */
        case PRU_CONNECT:
                error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
                if (error)
                        break;
                tp->t_template = tcp_template(tp);
        case PRU_CONNECT:
                error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
                if (error)
                        break;
                tp->t_template = tcp_template(tp);
-               if (tp->t_template == 0)
-                       goto badcon2;
-               tp->t_inpcb = inp;
-               inp->inp_ppcb = (caddr_t)tp;
+               if (tp->t_template == 0) {
+                       in_pcbdisconnect(inp);
+                       error = ENOBUFS;
+                       break;
+               }
                soisconnecting(so);
                tp->t_state = TCPS_SYN_SENT;
                tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
                soisconnecting(so);
                tp->t_state = TCPS_SYN_SENT;
                tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
@@ -102,41 +131,50 @@ COUNT(TCP_USRREQ);
                (void) tcp_output(tp);
                break;
 
                (void) tcp_output(tp);
                break;
 
-badcon2:
-               (void) m_free(dtom(tp));
-badcon:
-               in_pcbdisconnect(inp);
-               error = ENOBUFS;
+       /*
+        * Initiate disconnect from peer.
+        * If connection never passed embryonic stage, just drop;
+        * else if don't need to let data drain, then can just drop anyways,
+        * else have to begin TCP shutdown process: mark socket disconnecting,
+        * drain unread data, state switch to reflect user close, and
+        * send segment (e.g. FIN) to peer.  Socket will be really disconnected
+        * when peer sends FIN and acks ours.
+        *
+        * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
+        */
+       case PRU_DISCONNECT:
+               tcp_disconnect(tp);
                break;
 
                break;
 
+       /*
+        * Accept a connection.  Essentially all the work is
+        * done at higher levels; just return the address
+        * of the peer, storing through addr.
+        */
        case PRU_ACCEPT:
        case PRU_ACCEPT:
-               *(struct sockaddr *)addr = so->so_addr;
-               break;
-
-       case PRU_DISCONNECT:
-disconn:
-               if (tp->t_state < TCPS_ESTABLISHED)
-                       tcp_close(tp);
-               else if ((so->so_state & SO_LETDATADRAIN) == 0)
-                       tcp_drop(tp, 0);
-               else {
-                       soisdisconnecting(so);
-                       sbflush(&so->so_rcv);
-                       tcp_usrclosed(tp);
-                       (void) tcp_output(tp);
-               }
+               in_pcbconnaddr(inp, (struct sockaddr *)addr);
                break;
 
                break;
 
+       /*
+        * Mark the connection as being incapable of further output.
+        */
        case PRU_SHUTDOWN:
                socantsendmore(so);
                tcp_usrclosed(tp);
                (void) tcp_output(tp);
                break;
 
        case PRU_SHUTDOWN:
                socantsendmore(so);
                tcp_usrclosed(tp);
                (void) tcp_output(tp);
                break;
 
+       /*
+        * After a receive, possibly send window update to peer.
+        */
        case PRU_RCVD:
                (void) tcp_output(tp);
                break;
 
        case PRU_RCVD:
                (void) tcp_output(tp);
                break;
 
+       /*
+        * Do a send by putting data in output queue and updating urgent
+        * marker if URG set.  Possibly send more data.
+        */
        case PRU_SEND:
                sbappend(&so->so_snd, m);
 /*
        case PRU_SEND:
                sbappend(&so->so_snd, m);
 /*
@@ -148,10 +186,14 @@ disconn:
                (void) tcp_output(tp);
                break;
 
                (void) tcp_output(tp);
                break;
 
+       /*
+        * Abort the TCP.
+        */
        case PRU_ABORT:
                tcp_drop(tp, ECONNABORTED);
                break;
 
        case PRU_ABORT:
                tcp_drop(tp, ECONNABORTED);
                break;
 
+/* SOME AS YET UNIMPLEMENTED HOOKS */
        case PRU_CONTROL:
                error = EOPNOTSUPP;
                break;
        case PRU_CONTROL:
                error = EOPNOTSUPP;
                break;
@@ -167,7 +209,12 @@ disconn:
        case PRU_SENDOOB:
                error = EOPNOTSUPP;
                break;
        case PRU_SENDOOB:
                error = EOPNOTSUPP;
                break;
+/* END UNIMPLEMENTED HOOKS */
 
 
+       /*
+        * TCP slow timer went off; going through this
+        * routine for tracing's sake.
+        */
        case PRU_SLOWTIMO:
                tcp_timers(tp, (int)addr);
                req |= (int)addr << 8;          /* for debug's sake */
        case PRU_SLOWTIMO:
                tcp_timers(tp, (int)addr);
                req |= (int)addr << 8;          /* for debug's sake */
@@ -182,6 +229,69 @@ disconn:
        return (error);
 }
 
        return (error);
 }
 
+/*
+ * Attach TCP protocol to socket, allocating
+ * internet protocol control block, tcp control block,
+ * bufer space, and entering LISTEN state if to accept connections.
+ */
+tcp_attach(so, sa)
+       struct socket *so;
+       struct sockaddr *sa;
+{
+       register struct tcpcb *tp;
+       struct inpcb *inp;
+       int error;
+
+       error = in_pcbattach(so, &tcb, 2048, 2048, (struct sockaddr_in *)sa);
+       if (error)
+               return (error);
+       inp = (struct inpcb *)so->so_pcb;
+       tp = tcp_newtcpcb(inp);
+       if (so->so_options & SO_ACCEPTCONN) {
+               if (tp == 0) {
+                       in_pcbdetach(inp);
+                       return (ENOBUFS);
+               }
+               tp->t_state = TCPS_LISTEN;
+       } else
+               tp->t_state = TCPS_CLOSED;
+       return (0);
+}
+
+/*
+ * Initiate (or continue) disconnect.
+ * If embryonic state, just send reset (once).
+ * If not in ``let data drain'' option, just drop.
+ * Otherwise (hard), mark socket disconnecting and drop
+ * current input data; switch states based on user close, and
+ * send segment to peer (with FIN).
+ */
+tcp_disconnect(tp)
+       struct tcpcb *tp;
+{
+       struct socket *so = tp->t_inpcb->inp_socket;
+
+       if (tp->t_state < TCPS_ESTABLISHED)
+               tcp_close(tp);
+       else if ((so->so_options & SO_LETDATADRAIN) == 0)
+               tcp_drop(tp, 0);
+       else {
+               soisdisconnecting(so);
+               sbflush(&so->so_rcv);
+               tcp_usrclosed(tp);
+               (void) tcp_output(tp);
+       }
+}
+
+/*
+ * User issued close, and wish to trail through shutdown states:
+ * if never received SYN, just forget it.  If got a SYN from peer,
+ * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
+ * If already got a FIN from peer, then almost done; go to LAST_ACK
+ * state.  In all other cases, have already sent FIN to peer (e.g.
+ * after PRU_SHUTDOWN), and just have to play tedious game waiting
+ * for peer to send FIN or not respond to keep-alives, etc.
+ */
 tcp_usrclosed(tp)
        struct tcpcb *tp;
 {
 tcp_usrclosed(tp)
        struct tcpcb *tp;
 {