X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/87e78f19945465f2956ce53e73276da266cea593..60b16fa99999b351e7d648443d9e29e2ab878ab9:/usr/src/sys/netinet/tcp_input.c diff --git a/usr/src/sys/netinet/tcp_input.c b/usr/src/sys/netinet/tcp_input.c index d6e6c9fe2f..3cebf0bf31 100644 --- a/usr/src/sys/netinet/tcp_input.c +++ b/usr/src/sys/netinet/tcp_input.c @@ -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 "../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; { + register struct th *n; /* known to be r10 */ + register int j; /* known to be r9 */ register struct tcb *tp; - register struct th *n; 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; @@ -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; } - /* - * 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; } @@ -62,11 +72,11 @@ COUNT(TCP_INPUT); /* * 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; - 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 || @@ -93,7 +103,7 @@ found: 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) @@ -102,11 +112,11 @@ found: 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) { - t_close(tp, URESET); /* 70 */ + tcp_close(tp, URESET); /* 70 */ tp->t_state = CLOSED; goto badseg; } @@ -130,7 +140,7 @@ found: goto badseg; default: - t_close(tp, URESET); /* 66 */ + tcp_close(tp, URESET); /* 66 */ tp->t_state = CLOSED; goto badseg; } @@ -139,11 +149,11 @@ found: 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) { - send_null(tp); /* 74 */ + tcp_sndnull(tp); /* 74 */ goto badseg; } goto goodseg; @@ -154,12 +164,13 @@ badseg: goodseg: #ifdef notdef + /* DO SOMETHING ABOUT UNACK!!! */ /* * 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) @@ -167,7 +178,6 @@ goodseg: m->m_act = mp; } else tp->t_rcv_unack = mp; - return; } #endif @@ -183,16 +193,7 @@ goodseg: 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 @@ -205,7 +206,8 @@ goodseg: 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; @@ -221,7 +223,7 @@ goodseg: 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) @@ -254,7 +256,7 @@ goodseg: 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) { @@ -296,11 +298,11 @@ input: 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 - send_ctl(tp); /* 31 */ + tcp_sndctl(tp); /* 31 */ goto done; } goto input; @@ -308,7 +310,7 @@ input: 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) @@ -318,7 +320,7 @@ input: 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 */ @@ -331,14 +333,14 @@ input: 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) { - send_ctl(tp); /* 31 */ + tcp_sndctl(tp); /* 31 */ 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) { - rcv_ctldat(tp, n, 0); + tcp_ctldat(tp, n, 0); tp->t_finack = T_2ML; tp->tc_flags &= ~TC_WAITED_2_ML; /* 30 */ } @@ -361,12 +363,8 @@ done: * 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) { @@ -413,15 +411,13 @@ notwanted: netstat.t_badsegs++; } -rcv_ctldat(tp, n, dataok) +tcp_ctldat(tp, n, dataok) 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 */ @@ -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) { + register struct mbuf *mn; + register struct ucb *up; + register int len; + 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; } - if (dataok) { + if (dataok == 0) + goto ctlonly; /* 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 */ - 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 */ - 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) { - int last; + seq_t last; if ((tp->tc_flags&TC_FIN_RCVD) == 0) { /* do we really have fin ? */ @@ -537,12 +641,16 @@ COUNT(RCV_CTLDAT); } /* respond */ + sent = 0; 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 && @@ -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; { @@ -752,39 +672,35 @@ present_data(tp) 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; - ready = firstempty(tp); /* seq # of last complete datum */ 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); + 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; } - 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; } } - if (up->uc_rsize != 0) + if (up->uc_rcc != 0) 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); /* ### */ }