cleanup
[unix-history] / usr / src / sys / netinet / tcp_input.c
index d6e6c9f..3cebf0b 100644 (file)
@@ -1,30 +1,29 @@
-/* tcp_input.c 1.1 81/10/24 */
+/* tcp_input.c 1.12 81/10/30 */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
-#include "../bbnnet/net.h"
-#include "../bbnnet/mbuf.h"
-#include "../bbnnet/host.h"
-#include "../bbnnet/imp.h"
-#include "../bbnnet/ucb.h"
-#include "../bbnnet/tcp.h"
-#include "../bbnnet/ip.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/inode.h"
-#include "../bbnnet/fsm.h"
-
-extern int nosum;
+#include "../h/mbuf.h"
+#include "../h/socket.h"
+#include "../inet/inet.h"
+#include "../inet/inet_systm.h"
+#include "../inet/imp.h"
+#include "../inet/inet_host.h"
+#include "../inet/ip.h"
+#include "../inet/tcp.h"
+#include "../inet/tcp_fsm.h"
+
+int    tcpcksum = 1;
 
 tcp_input(mp)
        register struct mbuf *mp;
 {
 
 tcp_input(mp)
        register struct mbuf *mp;
 {
+       register struct th *n;          /* known to be r10 */
+       register int j;                 /* known to be r9 */
        register struct tcb *tp;
        register struct tcb *tp;
-       register struct th *n;
        int nstate;
        struct mbuf *m;
        struct ucb *up;
        int nstate;
        struct mbuf *m;
        struct ucb *up;
-       int hlen, tlen, j;
+       int hlen, tlen;
        u_short lport, fport;
 #ifdef TCPDEBUG
        struct tcp_debug tdb;
        u_short lport, fport;
 #ifdef TCPDEBUG
        struct tcp_debug tdb;
@@ -47,13 +46,24 @@ COUNT(TCP_INPUT);
        if ((hlen = n->t_off << 2) > mp->m_len)
                { printf("tcp header overflow\n"); m_freem(mp); return; }
 
        if ((hlen = n->t_off << 2) > mp->m_len)
                { printf("tcp header overflow\n"); m_freem(mp); return; }
 
-       /*
-        * Checksum extended header and data
-        */
-       j = n->t_sum; n->t_sum = 0;
-       if (j != cksum(mp, sizeof (struct ip) + tlen)) {
-               netstat.t_badsum++;
-               if (nosum == 0) {
+       if (tcpcksum) {
+               /*
+                * Checksum extended header and data
+                */
+               j = n->t_sum; n->t_sum = 0;
+#ifdef vax
+               if (tlen == 20) {
+                       asm("addl3 $8,r10,r0; movl (r0)+,r1; addl2 (r0)+,r1");
+                       asm("adwc (r0)+,r1; adwc (r0)+,r1; adwc (r0)+,r1");
+                       asm("adwc (r0)+,r1; adwc (r0)+,r1; adwc (r0)+,r1");
+                       asm("adwc $0,r1; ashl $-16,r1,r0; addw2 r0,r1");
+                       asm("adwc $0,r1");              /* ### */
+                       asm("mcoml r1,r1; movzwl r1,r1; subl2 r1,r9");
+               } else
+#endif
+                       j -= cksum(mp, sizeof (struct ip) + tlen);
+               if (j != 0) {
+                       netstat.t_badsum++;
                        m_freem(mp);
                        return;
                }
                        m_freem(mp);
                        return;
                }
@@ -62,11 +72,11 @@ COUNT(TCP_INPUT);
        /*
         * Find tcb for message (SHOULDN'T USE LINEAR SEARCH!)
         */
        /*
         * Find tcb for message (SHOULDN'T USE LINEAR SEARCH!)
         */
-       for (tp = netcb.n_tcb_head; tp != 0; tp = tp->t_tcb_next)
+       for (tp = tcb_head; tp != 0; tp = tp->t_tcb_next)
                if (tp->t_lport == lport && tp->t_fport == fport &&
                    tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr)
                        goto found;
                if (tp->t_lport == lport && tp->t_fport == fport &&
                    tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr)
                        goto found;
-       for (tp = netcb.n_tcb_head; tp != 0; tp = tp->t_tcb_next)
+       for (tp = tcb_head; tp != 0; tp = tp->t_tcb_next)
                if (tp->t_lport == lport &&
                    (tp->t_fport==fport || tp->t_fport==0) &&
                    (tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr ||
                if (tp->t_lport == lport &&
                    (tp->t_fport==fport || tp->t_fport==0) &&
                    (tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr ||
@@ -93,7 +103,7 @@ found:
 
        case LISTEN:
                if ((n->th_flags&TH_ACK) || !syn_ok(tp, n)) {
 
        case LISTEN:
                if ((n->th_flags&TH_ACK) || !syn_ok(tp, n)) {
-                       send_rst(tp, n);
+                       tcp_sndrst(tp, n);
                        goto badseg;
                }
                if (n->th_flags&TH_RST)
                        goto badseg;
                }
                if (n->th_flags&TH_RST)
@@ -102,11 +112,11 @@ found:
 
        case SYN_SENT:
                if (!ack_ok(tp, n) || !syn_ok(tp, n)) {
 
        case SYN_SENT:
                if (!ack_ok(tp, n) || !syn_ok(tp, n)) {
-                       send_rst(tp, n);                        /* 71,72,75 */
+                       tcp_sndrst(tp, n);                      /* 71,72,75 */
                        goto badseg;
                }
                if (n->th_flags&TH_RST) {
                        goto badseg;
                }
                if (n->th_flags&TH_RST) {
-                       t_close(tp, URESET);                    /* 70 */
+                       tcp_close(tp, URESET);                  /* 70 */
                        tp->t_state = CLOSED;
                        goto badseg;
                }
                        tp->t_state = CLOSED;
                        goto badseg;
                }
@@ -130,7 +140,7 @@ found:
                        goto badseg;
 
                default:
                        goto badseg;
 
                default:
-                       t_close(tp, URESET);                    /* 66 */
+                       tcp_close(tp, URESET);                  /* 66 */
                        tp->t_state = CLOSED;
                        goto badseg;
                }
                        tp->t_state = CLOSED;
                        goto badseg;
                }
@@ -139,11 +149,11 @@ found:
        case SYN_RCVD:
 common:
                if (ack_ok(tp, n) == 0) {
        case SYN_RCVD:
 common:
                if (ack_ok(tp, n) == 0) {
-                       send_rst(tp, n);                        /* 74 */
+                       tcp_sndrst(tp, n);                      /* 74 */
                        goto badseg;
                }
                if (syn_ok(tp, n) && n->t_seq != tp->irs) {
                        goto badseg;
                }
                if (syn_ok(tp, n) && n->t_seq != tp->irs) {
-                       send_null(tp);                          /* 74 */
+                       tcp_sndnull(tp);                        /* 74 */
                        goto badseg;
                }
                goto goodseg;
                        goto badseg;
                }
                goto goodseg;
@@ -154,12 +164,13 @@ badseg:
 
 goodseg:
 #ifdef notdef
 
 goodseg:
 #ifdef notdef
+       /* DO SOMETHING ABOUT UNACK!!! */
        /*
         * Defer processing if no buffer space for this connection.
         */
        up = tp->t_ucb;
        /*
         * Defer processing if no buffer space for this connection.
         */
        up = tp->t_ucb;
-       if ((int)up->uc_rcv - (int)up->uc_rsize <= 0
-            && n->t_len != 0 && netcb.n_bufs < netcb.n_lowat) {
+       if (up->uc_rcc > up->uc_rhiwat && 
+            && n->t_len != 0 && mbstat.m_bufs < mbstat.m_lowat) {
                mp->m_act = (struct mbuf *)0;
                if ((m = tp->t_rcv_unack) != NULL) {
                        while (m->m_act != NULL)
                mp->m_act = (struct mbuf *)0;
                if ((m = tp->t_rcv_unack) != NULL) {
                        while (m->m_act != NULL)
@@ -167,7 +178,6 @@ goodseg:
                        m->m_act = mp;
                } else
                        tp->t_rcv_unack = mp;
                        m->m_act = mp;
                } else
                        tp->t_rcv_unack = mp;
-
                return;
        }
 #endif
                return;
        }
 #endif
@@ -183,16 +193,7 @@ goodseg:
        acounts[tp->t_state][INRECV]++;
 #ifdef TCPDEBUG
        if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
        acounts[tp->t_state][INRECV]++;
 #ifdef TCPDEBUG
        if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
-               tdb.td_tod = time;
-               tdb.td_tcb = tp;
-               tdb.td_old = nstate;
-               tdb.td_inp = INRECV;
-               tdb.td_tim = 0;
-               tdb.td_sno = n->t_seq;
-               tdb.td_ano = n->t_ackno;
-               tdb.td_wno = n->t_win;
-               tdb.td_lno = n->t_len;
-               tdb.td_flg = n->th_flags;
+               tdb_setup(tp, n, INRECV, &tdb);
        } else
                tdb.td_tod = 0;
 #endif
        } else
                tdb.td_tod = 0;
 #endif
@@ -205,7 +206,8 @@ goodseg:
                        goto done;
                }
                tp->t_fport = n->t_src;
                        goto done;
                }
                tp->t_fport = n->t_src;
-               rcv_ctldat(tp, n, 1);
+               tp->t_ucb->uc_template = tcp_template(tp);
+               tcp_ctldat(tp, n, 1);
                if (tp->tc_flags&TC_FIN_RCVD) {
                        tp->t_finack = T_2ML;                   /* 3 */
                        tp->tc_flags &= ~TC_WAITED_2_ML;
                if (tp->tc_flags&TC_FIN_RCVD) {
                        tp->t_finack = T_2ML;                   /* 3 */
                        tp->tc_flags &= ~TC_WAITED_2_ML;
@@ -221,7 +223,7 @@ goodseg:
                        nstate = EFAILEC;
                        goto done;
                }
                        nstate = EFAILEC;
                        goto done;
                }
-               rcv_ctldat(tp, n, 1);
+               tcp_ctldat(tp, n, 1);
                if (tp->tc_flags&TC_FIN_RCVD) {
                        if (n->th_flags&TH_ACK) {
                                if (n->t_ackno > tp->iss)
                if (tp->tc_flags&TC_FIN_RCVD) {
                        if (n->th_flags&TH_ACK) {
                                if (n->t_ackno > tp->iss)
@@ -254,7 +256,7 @@ goodseg:
        case FIN_W2:
        case TIME_WAIT:
 input:
        case FIN_W2:
        case TIME_WAIT:
 input:
-               rcv_ctldat(tp, n, 1);                           /* 39 */
+               tcp_ctldat(tp, n, 1);                           /* 39 */
                present_data(tp);
                switch (tp->t_state) {
 
                present_data(tp);
                switch (tp->t_state) {
 
@@ -296,11 +298,11 @@ input:
                if (n->th_flags&TH_FIN) {
                        if ((n->th_flags&TH_ACK) &&
                            n->t_ackno <= tp->seq_fin) {
                if (n->th_flags&TH_FIN) {
                        if ((n->th_flags&TH_ACK) &&
                            n->t_ackno <= tp->seq_fin) {
-                               rcv_ctldat(tp, n, 0);           /* 30 */
+                               tcp_ctldat(tp, n, 0);           /* 30 */
                                tp->t_finack = T_2ML;
                                tp->tc_flags &= ~TC_WAITED_2_ML;
                        } else
                                tp->t_finack = T_2ML;
                                tp->tc_flags &= ~TC_WAITED_2_ML;
                        } else
-                               send_ctl(tp);                   /* 31 */
+                               tcp_sndctl(tp);                 /* 31 */
                        goto done;
                }
                goto input;
                        goto done;
                }
                goto input;
@@ -308,7 +310,7 @@ input:
        case CLOSING1:
                j = ack_fin(tp, n);
                if (n->th_flags&TH_FIN) {
        case CLOSING1:
                j = ack_fin(tp, n);
                if (n->th_flags&TH_FIN) {
-                       rcv_ctldat(tp, n, 0);
+                       tcp_ctldat(tp, n, 0);
                        tp->t_finack = T_2ML;
                        tp->tc_flags &= ~TC_WAITED_2_ML;
                        if (j)
                        tp->t_finack = T_2ML;
                        tp->tc_flags &= ~TC_WAITED_2_ML;
                        if (j)
@@ -318,7 +320,7 @@ input:
                if (j) {
                        if (tp->tc_flags&TC_WAITED_2_ML)
                                if (rcv_empty(tp)) {
                if (j) {
                        if (tp->tc_flags&TC_WAITED_2_ML)
                                if (rcv_empty(tp)) {
-                                       t_close(tp, UCLOSED);   /* 15 */
+                                       tcp_close(tp, UCLOSED); /* 15 */
                                        nstate = CLOSED;
                                } else
                                        nstate = RCV_WAIT;      /* 18 */
                                        nstate = CLOSED;
                                } else
                                        nstate = RCV_WAIT;      /* 18 */
@@ -331,14 +333,14 @@ input:
        case CLOSING2:
                if (ack_fin(tp, n)) {
                        if (rcv_empty(tp)) {                    /* 16 */
        case CLOSING2:
                if (ack_fin(tp, n)) {
                        if (rcv_empty(tp)) {                    /* 16 */
-                               t_close(tp, UCLOSED);
+                               tcp_close(tp, UCLOSED);
                                nstate = CLOSED;
                        } else
                                nstate = RCV_WAIT;              /* 19 */
                        goto done;
                }
                if (n->th_flags&TH_FIN) {
                                nstate = CLOSED;
                        } else
                                nstate = RCV_WAIT;              /* 19 */
                        goto done;
                }
                if (n->th_flags&TH_FIN) {
-                       send_ctl(tp);                           /* 31 */
+                       tcp_sndctl(tp);                         /* 31 */
                        goto done;
                }
                goto input;
                        goto done;
                }
                goto input;
@@ -346,7 +348,7 @@ input:
        case RCV_WAIT:
                if ((n->th_flags&TH_FIN) && (n->th_flags&TH_ACK) &&
                    n->t_ackno <= tp->seq_fin) {
        case RCV_WAIT:
                if ((n->th_flags&TH_FIN) && (n->th_flags&TH_ACK) &&
                    n->t_ackno <= tp->seq_fin) {
-                       rcv_ctldat(tp, n, 0);
+                       tcp_ctldat(tp, n, 0);
                        tp->t_finack = T_2ML;
                        tp->tc_flags &= ~TC_WAITED_2_ML;        /* 30 */
                }
                        tp->t_finack = T_2ML;
                        tp->tc_flags &= ~TC_WAITED_2_ML;        /* 30 */
                }
@@ -361,12 +363,8 @@ done:
         * and enter new state.
         */
 #ifdef TCPDEBUG
         * and enter new state.
         */
 #ifdef TCPDEBUG
-       if (tdb.td_tod) {
-               tdb.td_new = nstate;
-               tcp_debug[tdbx++ % TDBSIZE] = tdb;
-               if (tcpconsdebug)
-                       tcp_prt(&tdb);
-       }
+       if (tdb.td_tod)
+               tdb_stuff(&tdb, nstate);
 #endif
        switch (nstate) {
 
 #endif
        switch (nstate) {
 
@@ -413,15 +411,13 @@ notwanted:
        netstat.t_badsegs++;
 }
 
        netstat.t_badsegs++;
 }
 
-rcv_ctldat(tp, n, dataok)
+tcp_ctldat(tp, n, dataok)
        register struct tcb *tp;
        register struct th *n;
 {
        register struct tcb *tp;
        register struct th *n;
 {
-       register sent;
-       register struct ucb *up;
-       register struct mbuf *m, *mn;
-       register len;
-COUNT(RCV_CTLDAT);
+       register struct mbuf *m;
+       int sent;
+COUNT(TCP_CTLDAT);
 
        tp->tc_flags &= ~(TC_DROPPED_TXT|TC_ACK_DUE|TC_NEW_WINDOW);
 /* syn */
 
        tp->tc_flags &= ~(TC_DROPPED_TXT|TC_ACK_DUE|TC_NEW_WINDOW);
 /* syn */
@@ -434,6 +430,10 @@ COUNT(RCV_CTLDAT);
 /* ack */
        if ((n->th_flags&TH_ACK) && (tp->tc_flags&TC_SYN_RCVD) &&
            n->t_ackno > tp->snd_una) {
 /* ack */
        if ((n->th_flags&TH_ACK) && (tp->tc_flags&TC_SYN_RCVD) &&
            n->t_ackno > tp->snd_una) {
+               register struct mbuf *mn;
+               register struct ucb *up;
+               register int len;
+
                up = tp->t_ucb;
 
                /* update snd_una and snd_nxt */
                up = tp->t_ucb;
 
                /* update snd_una and snd_nxt */
@@ -486,38 +486,142 @@ COUNT(RCV_CTLDAT);
                tp->tc_flags |= TC_NEW_WINDOW;
                tp->t_persist = 0;
        }
                tp->tc_flags |= TC_NEW_WINDOW;
                tp->t_persist = 0;
        }
-       if (dataok) {
+       if (dataok == 0)
+               goto ctlonly;
 /* text */
 /* text */
-               if (n->t_len != 0)
-                       rcv_text(tp, n);
+       if (n->t_len == 0)
+               goto notext;
+       { register int i;
+         register struct th *p, *q;
+         register struct mbuf *m;
+         int overage;
+
+       /*
+        * Discard duplicate data already passed to user.
+        */
+       if (SEQ_LT(n->t_seq, tp->rcv_nxt)) {
+               i = tp->rcv_nxt - n->t_seq;
+               if (i >= n->t_len)
+                       goto notext;
+               n->t_seq += i;
+               n->t_len -= i;
+               m_adj(dtom(n), i);
+       }
+
+       /*
+        * Find a segment which begins after this one does.
+        */
+       for (q = tp->t_rcv_next; q != (struct th *)tp; q = q->t_next)
+               if (SEQ_GT(q->t_seq, n->t_seq))
+                       break;
+
+       /*
+        * If there is a preceding segment, it may provide some of
+        * our data already.  If so, drop the data from the incoming
+        * segment.  If it provides all of our data, drop us.
+        */
+       if (q->t_prev != (struct th *)tp) {
+               /* conversion to int (in i) handles seq wraparound */
+               i = q->t_prev->t_seq + q->t_prev->t_len - n->t_seq;
+               if (i > 0) {
+                       if (i >= n->t_len)
+                               goto notext;    /* w/o setting TC_NET_KEEP */
+                       m_adj(dtom(tp), i);
+                       n->t_len -= i;
+                       n->t_seq += i;
+               }
+       }
+
+       /*
+        * While we overlap succeeding segments trim them or,
+        * if they are completely covered, dequeue them.
+        */
+       while (q != (struct th *)tp && SEQ_GT(n->t_seq + n->t_len, q->t_seq)) {
+               i = (n->t_seq + n->t_len) - q->t_seq;
+               if (i < q->t_len) {
+                       q->t_len -= i;
+                       m_adj(dtom(q), i);
+                       break;
+               }
+               q = q->t_next;
+               m_freem(dtom(q->t_prev));
+               remque(q->t_prev);
+       }
+
+       /*
+        * Stick new segment in its place.
+        */
+       insque(n, q->t_prev);
+       tp->seqcnt += n->t_len;
+
+#ifdef notdef
+       /*
+        * Calculate available space and discard segments for
+        * which there is too much.
+        */
+       q = tp->t_rcv_prev;
+       overage = 
+           (tp->t_ucb->uc_rcc + tp->rcv_seqcnt) - tp->t_ucb->uc_rhiwat;
+       if (overage > 0)
+               for (;;) {
+                       i = MIN(q->t_len, overage);
+                       overage -= i;
+                       q->t_len -= i;
+                       m_adj(q, -i);
+                       if (q == n)
+                               tp->tc_flags |= TC_DROPPED_TXT;
+                       if (q->t_len)
+                               break;
+                       if (q == n)
+                               panic("tcp_text dropall");
+                       q = q->t_prev;
+                       remque(q->t_next);
+               }
+#endif
+
+       /*
+        * Advance rcv_next through
+        * newly completed sequence space
+        * and return forcing an ack.
+        */
+       while (n->t_seq == tp->rcv_nxt) {
+               /* present data belongs here */
+               tp->rcv_nxt += n->t_len;
+               n = n->t_next;
+               if (n == (struct th *)tp)
+                       break;
+       }
+       tp->tc_flags |= (TC_ACK_DUE|TC_NET_KEEP);
+       }
+notext:
 /* urg */
 /* urg */
-               if (n->th_flags&TH_URG) {
-                       unsigned urgent;
-
-                       urgent = n->t_urp + n->t_seq;
-                       if (tp->rcv_nxt < urgent) {
-                               if (tp->rcv_urp <= tp->rcv_nxt)
-                                       to_user(tp->t_ucb, UURGENT);
-                               tp->rcv_urp = urgent;
-                       }
+       if (n->th_flags&TH_URG) {
+               unsigned urgent;
+
+               urgent = n->t_urp + n->t_seq;
+               if (tp->rcv_nxt < urgent) {
+                       if (tp->rcv_urp <= tp->rcv_nxt)
+                               to_user(tp->t_ucb, UURGENT);
+                       tp->rcv_urp = urgent;
                }
                }
+       }
 /* eol */
 /* eol */
-               if ((n->th_flags&TH_EOL) &&
-                   (tp->tc_flags&TC_DROPPED_TXT) == 0 &&
-                   tp->t_rcv_prev != (struct th *)tp) {
-                       /* mark last mbuf */
-                       m = dtom(tp->t_rcv_prev);
-                       if (m != NULL) {
-                               while (m->m_next != NULL)
-                                       m = m->m_next;
-                               m->m_act =
-                                   (struct mbuf *)(m->m_off + m->m_len - 1);
-                       }
+       if ((n->th_flags&TH_EOL) &&
+           (tp->tc_flags&TC_DROPPED_TXT) == 0 &&
+           tp->t_rcv_prev != (struct th *)tp) {
+               /* mark last mbuf */
+               m = dtom(tp->t_rcv_prev);
+               if (m != NULL) {
+                       while (m->m_next != NULL)
+                               m = m->m_next;
+                       m->m_act =
+                           (struct mbuf *)(m->m_off + m->m_len - 1);
                }
        }
                }
        }
+ctlonly:
 /* fin */
        if ((n->th_flags&TH_FIN) && (tp->tc_flags&TC_DROPPED_TXT) == 0) {
 /* fin */
        if ((n->th_flags&TH_FIN) && (tp->tc_flags&TC_DROPPED_TXT) == 0) {
-               int last;
+               seq_t last;
 
                if ((tp->tc_flags&TC_FIN_RCVD) == 0) {
                        /* do we really have fin ? */
 
                if ((tp->tc_flags&TC_FIN_RCVD) == 0) {
                        /* do we really have fin ? */
@@ -537,12 +641,16 @@ COUNT(RCV_CTLDAT);
        }
 
 /* respond */
        }
 
 /* respond */
+       sent = 0;
        if (tp->tc_flags&TC_ACK_DUE)
        if (tp->tc_flags&TC_ACK_DUE)
-               sent = send_ctl(tp);
-       else if (tp->tc_flags&TC_NEW_WINDOW)
-               sent = send(tp);
-       else
-               sent = 0;
+               sent = tcp_sndctl(tp);
+       else if (tp->tc_flags&TC_NEW_WINDOW) {
+               seq_t last = tp->snd_off;
+               for (m = tp->t_ucb->uc_sbuf; m != NULL; m = m->m_next)  /*###*/
+                       last += m->m_len;                               /*###*/
+               if (tp->snd_nxt <= last || (tp->tc_flags&TC_SND_FIN))
+                       sent = tcp_send(tp);
+       }
 
 /* set for retrans */
        if (!sent && tp->snd_una < tp->snd_nxt &&
 
 /* set for retrans */
        if (!sent && tp->snd_una < tp->snd_nxt &&
@@ -554,194 +662,6 @@ COUNT(RCV_CTLDAT);
        }
 }
 
        }
 }
 
-rcv_text(tp, t)
-       register struct tcb *tp;
-       register struct th *t;
-{
-       register i;
-       register struct th *p, *q;
-       register struct mbuf *m, *n;
-       struct th *savq;
-       int last, j, k;
-COUNT(RCV_TEXT);
-
-       /* throw away any data we have already received */
-       if ((i = tp->rcv_nxt - t->t_seq) > 0)  {
-               if (i >= t->t_len)
-                       return;
-               t->t_seq += i;
-               t->t_len -= i;
-               m_adj(dtom(t), i);
-       }
-
-       last = t_end(t);                /* last seq # in incoming seg */
-       i = rcv_resource(tp);           /* # buffers available to con */
-
-       /* count buffers in segment */
-
-       for (m = dtom(t), j = 0; m != NULL; m = m->m_next)
-               if (m->m_len != 0) {
-                       j++;
-                       if (m->m_off > MMAXOFF)
-                               j += NMBPG;
-               }
-
-       /* not enough resources to process segment */
-
-       if (j > i && netcb.n_bufs < netcb.n_lowat) {
-
-               /* if segment preceeds top of seqeuncing queue, try to take
-                  buffers from bottom of queue */
-
-                q = tp->t_rcv_next;
-               if (q != (struct th *)tp && tp->rcv_nxt < q->t_seq &&
-                   t->t_seq < q->t_seq)
-
-                       for (k=j-i, p = tp->t_rcv_prev; k > 0 &&
-                            p != (struct th *)tp; k--) {
-                               savq = p->t_prev;
-                               tcp_deq(p);
-                               i += m_freem(dtom(p));
-                               p = savq;
-                       }
-
-               /* if still not enough room, drop text from end of segment */
-
-               if (j > i) {
-
-                       for (m = dtom(t); i > 0 && m != NULL; i--)
-                               m = m->m_next;
-
-                       while (m != NULL) {
-                               t->t_len -= m->m_len;
-                               last -= m->m_len;
-                               m->m_len = 0;
-                               m = m->m_next;
-                       }
-                       tp->tc_flags |= TC_DROPPED_TXT;
-                       if (last < t->t_seq)
-                               return;
-               }
-       }
-
-       /* merge incoming data into the sequence queue */
-
-        q = tp->t_rcv_next;             /* -> top of sequencing queue */
-
-        /* skip frags which new doesn't overlap at end */
-
-        while ((q != (struct th *)tp) && (t->t_seq > t_end(q)))
-               q = q->t_next;
-
-        if (q == (struct th *)tp) {     /* frag at end of chain */
-
-               if (last >= tp->rcv_nxt) {
-                       tp->tc_flags |= TC_NET_KEEP;
-                       tcp_enq(t, tp->t_rcv_prev);
-               }
-
-        } else {
-
-               /* frag doesn't overlap any on chain */
-
-               if (last < q->t_seq) {
-                       tp->tc_flags |= TC_NET_KEEP;
-                       tcp_enq(t, q->t_prev);
-
-               /* new overlaps beginning of next frag only */
-
-               } else if (last < t_end(q)) {
-                       if ((i = last - q->t_seq + 1) < t->t_len) {
-                               t->t_len -= i;
-                               m_adj(dtom(t), -i);
-                               tp->tc_flags |= TC_NET_KEEP;
-                               tcp_enq(t, q->t_prev);
-                       }
-
-               /* new overlaps end of previous frag */
-
-               } else {
-                       savq = q;
-                       if (t->t_seq <= q->t_seq) {     /* complete cover */
-                               savq = q->t_prev;
-                               tcp_deq(q);
-                               m_freem(dtom(q));
-
-                       } else {                        /* overlap */
-                               if ((i = t_end(q) - t->t_seq + 1) < t->t_len) {
-                                       t->t_seq += i;
-                                       t->t_len -= i;
-                                       m_adj(dtom(t), i);
-                               } else
-                                       t->t_len = 0;
-                       }
-
-               /* new overlaps at beginning of successor frags */
-
-                       q = savq->t_next;
-                       while ((q != (struct th *)tp) && (t->t_len != 0) &&
-                               (q->t_seq < last))
-
-                               /* complete cover */
-
-                               if (t_end(q) <= last) {
-                                       p = q->t_next;
-                                       tcp_deq(q);
-                                       m_freem(dtom(q));
-                                       q = p;
-
-                               } else {        /* overlap */
-
-                                       if ((i = last - q->t_seq + 1) < t->t_len) {
-                                               t->t_len -= i;
-                                               m_adj(dtom(t), -i);
-                                       } else
-                                               t->t_len = 0;
-                                       break;
-                               }
-
-               /* enqueue whatever is left of new before successors */
-
-                       if (t->t_len != 0) {
-                               tp->tc_flags |= TC_NET_KEEP;
-                               tcp_enq(t, savq);
-                       }
-               }
-        }
-
-       /* set to ack completed data (no gaps) */
-
-       tp->rcv_nxt = firstempty(tp);
-       tp->tc_flags |= TC_ACK_DUE;
-
-#ifdef notdef
-       /* THIS CODE CANT POSSIBLY WORK */
-       /* if any room remaining in rcv buf, take any unprocessed
-          messages and schedule for later processing */
-
-       i = rcv_resource(tp);
-
-       while ((m = tp->t_rcv_unack) != NULL && i > 0) {
-
-               /* schedule work request */
-
-               t = (struct th *)((int)m + m->m_off);
-               j = (t->t_off << 2) + sizeof(struct ip);
-               m->m_off += j;
-               m->m_len -= j;
-               tp->t_rcv_unack = m->m_act;
-               m->m_act = (struct mbuf *)0;
-               netstat.t_unack++;
-               tcp_work(INRECV, 0, tp, t);
-
-               /* remaining buffer space */
-
-               for (n = m; n != NULL; n = n->m_next)
-                       i--;
-       }
-#endif
-}
-
 present_data(tp)
        register struct tcb *tp;
 {
 present_data(tp)
        register struct tcb *tp;
 {
@@ -752,39 +672,35 @@ present_data(tp)
 COUNT(PRESENT_DATA);
 
        /* connection must be synced and data available for user */
 COUNT(PRESENT_DATA);
 
        /* connection must be synced and data available for user */
-       if (((tp->tc_flags&TC_SYN_ACKED) == 0) ||
-           (t = tp->t_rcv_next) == (struct th *)tp)
+       if ((tp->tc_flags&TC_SYN_ACKED) == 0)
                return;
        up = tp->t_ucb;
                return;
        up = tp->t_ucb;
-       ready = firstempty(tp);     /* seq # of last complete datum */
        mp = &up->uc_rbuf;
        while (*mp)
                mp = &(*mp)->m_next;
        mp = &up->uc_rbuf;
        while (*mp)
                mp = &(*mp)->m_next;
-       while (up->uc_rsize < up->uc_rcv && t != (struct th *) tp &&
-           t_end(t) < ready) {
-               tcp_deq(t);
+       t = tp->t_rcv_next;
+       /* SHOULD PACK DATA IN HERE */
+       while (t != (struct th *)tp && t->t_seq < tp->rcv_nxt) {
+               remque(t);
                m = dtom(t);
                m = dtom(t);
+               up->uc_rcc += t->t_len;
+               tp->seqcnt -= t->t_len;
+               if (tp->seqcnt < 0) panic("present_data");
                t = t->t_next;
                while (m) {
                        if (m->m_len == 0) {
                                m = m_free(m);
                                continue;
                        }
                t = t->t_next;
                while (m) {
                        if (m->m_len == 0) {
                                m = m_free(m);
                                continue;
                        }
-                       up->uc_rsize++;
-                       if (m->m_off > MMAXOFF)
-                               up->uc_rsize += NMBPG;
-                       if (*mp == 0)
-                               *mp = m;
+                       *mp = m;
                        mp = &m->m_next;
                        m = *mp;
                }
        }
                        mp = &m->m_next;
                        m = *mp;
                }
        }
-       if (up->uc_rsize != 0)
+       if (up->uc_rcc != 0)
                netwakeup(up);
                netwakeup(up);
-       /*
-        * Let user know about foreign tcp close if no more data.
-        */
-       if ((tp->tc_flags&TC_FIN_RCVD) && (tp->tc_flags&TC_USR_CLOSED) == 0 &&
-           rcv_empty(tp))
-               to_user(up, UCLOSED);
+       if ((tp->tc_flags&TC_FIN_RCVD) &&                       /* ### */
+           (tp->tc_flags&TC_USR_CLOSED) == 0 &&                /* ### */
+           rcv_empty(tp))                                      /* ### */
+               to_user(up, UCLOSED);                           /* ### */
 }
 }