# #include "util.h" #include "pkts.h" #include "buf.h" #include "telnet.h" /* This module handles sequence checking and sequencing of incoming data. It also manages the tcp/user receive data interface. */ /* Ch_seq chk sequence nos. in pkt just received from net. Fill pkt management fields: begin seqno, data length, and data ptr. If some seqnos are outside expected range, adjust these management fields to only include expected seqnos. */ ch_seq(ptcb, ppkt, tcp, tcplen) register struct tcb *ptcb; register struct rcvpkt *ppkt; register struct tcp_hdr *tcp; int tcplen; { int slen; long seqlast; long diff1, diff2; ppkt->rp_seqno = tcp->tc_seqno; ppkt->rp_dlen = tcplen - ((tcp->tc_off & 0360) >> 2); slen = ppkt->rp_dlen; if (tcp->tc_flags & SYN) slen++; if (tcp->tc_flags & FIN) slen++; /* If rcv window is 0, seg.seqno must equal expected seqno */ if (ptcb->t_rwnd == 0) { if (tcp->tc_seqno != ptcb->t_rnxt) { if ((ptcb->t_acktime == 0) && (!(tcp->tc_flags & RST))) ptcb->t_acktime = curtime; return(FALSE); } ppkt->rp_dlen = 0; if (slen > 1) tcp->tc_flags &= (~FIN); return(TRUE); } /* If segment length is 0, reject pkt if seg.seqno < expected first seqno or seg.seqno > last expected seqno */ if (slen == 0) { if ( ((ptcb->t_rnxt - tcp->tc_seqno) > 0) || ((tcp->tc_seqno - ptcb->t_rlast) > 0) ) { if ((ptcb->t_acktime == 0) && (!(tcp->tc_flags & RST))) ptcb->t_acktime = curtime; return(FALSE); } return(TRUE); } /* Reject segment if seg.seq > last expected seqno or seq.seq + seg.len - 1 < first expected seqno */ seqlast = tcp->tc_seqno + slen - 1; if ( ((tcp->tc_seqno - ptcb->t_rlast) > 0) || ((ptcb->t_rnxt - seqlast) > 0) ) { if ((ptcb->t_acktime == 0) && (!(tcp->tc_flags & RST))) ptcb->t_acktime = curtime; if ((ptcb->t_rnxt - seqlast) > 0) stats.s_rercv++; return(FALSE); } /* Remove seqno's before expected rcv window */ diff1 = ptcb->t_rnxt - tcp->tc_seqno; diff2 = seqlast - ptcb->t_rlast; ppkt->rp_datp = (char *) tcp + ((tcp->tc_off & 0360) >> 2); if (diff1 > 0) { ppkt->rp_seqno = ptcb->t_rnxt; if (tcp->tc_flags & SYN) { tcp->tc_flags &= (~SYN); diff1--; } ppkt->rp_datp += diff1; ppkt->rp_dlen -= diff1; stats.s_rercv++; } /* Remove seqno's after expected window */ if (diff2 > 0) { if (tcp->tc_flags & FIN) { tcp->tc_flags &= (~FIN); diff2--; } ppkt->rp_dlen -= diff2; } if (ppkt->rp_dlen < 0) { logerr("ch_seq weird dlen %o\n", ppkt->rp_dlen); return(FALSE); } return(TRUE); } ch_later(ptcb) register struct tcb *ptcb; { register struct rcvpkt *ppkt; long diff; struct inet_hdr *inp; register struct tcp_hdr *tcp; int finflag; for (ppkt = nxtque(&rwaitq, NULL); (ppkt != NULL) && ((diff = (ptcb->t_rnxt - ppkt->rp_seqno)) >= 0); ppkt = nxtque(&rwaitq, NULL) ) { deque(&rwaitq, ppkt); if ((ptcb->t_rnxt - (ppkt->rp_seqno + ppkt->rp_dlen)) >= 0) { /* Might lose FIN here */ enque(&frq, ppkt); stats.s_rercv++; continue; } if (diff > 0) { ppkt->rp_seqno = ptcb->t_rnxt; ppkt->rp_dlen -= diff; ppkt->rp_datp += diff; stats.s_rercv++; } inp = &ppkt->rp_inet; tcp = (char *) inp + ((inp->ip_ihlver & 017) << 2); finflag = (tcp->tc_flags & FIN); if (!seq_data(ptcb, ppkt, tcp)) { logerr("ch_later pgm err unseqed data\n"); break; } if (finflag) { tcp_fin(ptcb); break; } } } /* seq_data put data just received from net into proper location on sequenced queue(rseqq). If preceding data is missing, put packet on rwaitq. If packet contains duplicate data or no data, put on frq. If new data that is put on rseqq has urgent flag set and urgent ptr points to or beyond first valid seqno in this packet, call mng_urg to set/update tcp urgent handling fields and put user into urgent mode. */ seq_data(ptcb, ppkt, tcp) register struct tcb *ptcb; register struct rcvpkt *ppkt; register struct tcp_hdr *tcp; { long diff; diff = ppkt->rp_seqno - ptcb->t_rnxt; /* Next in sequence */ if (diff == 0) { if (ppkt->rp_dlen == 0) { enque(&frq, ppkt); return(TRUE); } ptcb->t_rnxt += ppkt->rp_dlen; ppkt->rp_date = ppkt->rp_datp + ppkt->rp_dlen; if (ptcb->t_acktime == 0) ptcb->t_acktime = curtime; if ( (tcp->tc_flags & URG) && ( ((tcp->tc_seqno + tcp->tc_urgp) - ppkt->rp_seqno) >= 0) ) mng_urg(ptcb, tcp); enque(&rseqq, ppkt); return(TRUE); } /* Later sequence no */ if (diff > 0) { if (ppkt->rp_dlen == 0) { enque(&frq, ppkt); return(FALSE); } seq_later(ptcb, ppkt); stats.s_badord++; return(FALSE); } /* Earlier seqno - pgm error */ if (diff < 0) { logerr("seq_data earlier seqno %O %O expect seqno %O\n", tcp->tc_seqno, ppkt->rp_seqno, ptcb->t_rnxt); enque(&frq, ppkt); return(FALSE); } } seq_later(ptcb, ppkt) struct tcb *ptcb; register struct rcvpkt *ppkt; { long seqlast2; register struct rcvpkt *ppkt2; for (ppkt2 = nxtque(&rwaitq, NULL); ppkt2 != NULL; ppkt2 = nxtque(&rwaitq, ppkt)) { seqlast2 = ppkt2->rp_seqno + ppkt2->rp_dlen; if ((ppkt->rp_seqno - seqlast2) >= 0) continue; if ((ppkt2->rp_seqno - ppkt->rp_seqno) > 0) { /* New pkt precedes this pkt */ /* Note that could (but don't) continue thru rwaitq to see if later pkts contain dupe data */ preque(&rwaitq, ppkt2, ppkt); if (((ppkt->rp_seqno + ppkt->rp_dlen) - seqlast2) >= 0) { deque(&rwaitq, ppkt2); enque(&frq, ppkt2); } } else { /* New pkt starts w/in this pkt */ if ((seqlast2 - (ppkt->rp_seqno + ppkt->rp_dlen)) >= 0) /* New pkt duplicate - drop it */ enque(&frq, ppkt); else postque(&rwaitq, ppkt2, ppkt); } return; } /* New pkt follows any data on rwaitq */ enque(&rwaitq, ppkt); return; } #ifndef TCPTEST /* tc_get return next char from buffers on rseqq (i.e. buffers of chars received from net). When no chars on rseqq, chk whether to tell user that have received FIN, return EOF. Chk whether to take user out of urgent mode. */ tc_get() { register struct tcb *ptcb; register struct rcvpkt *ppkt; int value; ptcb = &tcb; if ((ppkt = nxtque(&rseqq, NULL)) == NULL) { if (ptcb->t_state & FIN_RCVD) usr_fin(); return(EOF); } if ((ptcb->t_flags & URGF) && ((ppkt->rp_seqno - ptcb->t_urgseq) >= 0) ) { ptcb->t_flags &= (~URGF); scb.s_rstate = NORMAL; } value = (*ppkt->rp_datp++) & 0377; if (ppkt->rp_datp >= ppkt->rp_date) { deque(&rseqq, ppkt); enque(&frq, ppkt); } else ppkt->rp_seqno++; return(value); } #endif /* mng_urg put user into urgent mode */ mng_urg(ptcb, tcp) register struct tcb *ptcb; register struct tcp_hdr *tcp; { long urgseq; urgseq = tcp->tc_seqno + tcp->tc_urgp; if ( (ptcb->t_flags & URGF) && ((ptcb->t_urgseq - urgseq) > 0) ) urgseq = ptcb->t_urgseq; ptcb->t_flags |= URGF; ptcb->t_urgseq = urgseq; scb.s_rstate = URGENTM; }