# #include "util.h" #include "pkts.h" #include "buf.h" #include "telnet.h" /* This module handles buffering of data going from user level (e.g. telnet) to tcp. It manages the user/tcp send interface. */ /* sb_init init intermediate send to net buffer. This buffer handles outgoing sequence numbers and their corresponding data or flags (SYN or FIN). */ sb_init() { register struct sndcbuf *sbp; sbp = &sndcbuf; sbp->sb_flags = SNDSYN; sbp->sb_len = 0; sbp->sb_seqno = tcb.t_iss; sbp->sb_urg = 0; sbp->sb_datp = &sbp->sb_data[0]; sbp->sb_date = &sbp->sb_data[0]; sbp->sb_bbuff = &sbp->sb_data[0]; sbp->sb_ebuff = &sbp->sb_data[NSBUFF]; } /* tc_put put telnet char into intermediate * send to net buffer */ tc_put(ch) char ch; { register struct sndcbuf *sbp; char *date; sbp = &sndcbuf; *(sbp->sb_date) = ch; date = (sbp->sb_date + 1) < sbp->sb_ebuff ? sbp->sb_date + 1 : sbp->sb_bbuff; if (date == sbp->sb_datp) return(FALSE); sbp->sb_date = date; sbp->sb_len++; if ((NSBUFF - sbp->sb_len) < 10) return(FALSE); return(TRUE); } /* tc_puts put telnet chars into intermediate * send to net buffer */ tc_puts(str) register char *str; { register struct sndcbuf *sbp; register char *chp; char *che, *che2; short len; len = strlen(str); if (len > tc_nput()) return(FALSE); sbp = &sndcbuf; chp = sbp->sb_date; che = chp + len; if (che > sbp->sb_ebuff) { che = sbp->sb_bbuff + (len - (sbp->sb_ebuff - chp)); while (chp < sbp->sb_ebuff) *chp++ = *str++; chp = sbp->sb_bbuff; } while (chp < che) *chp++ = *str++; sbp->sb_date = che; sbp->sb_len += len; return(TRUE); } /* tc_nput return no. of chars for which have space in current intermediate send to net buffer */ tc_nput() { return( (NSBUFF - sndcbuf.sb_len) ); } /* tc_putdone return TRUE if no chars or flags to send, FALSE otherwise */ tc_putdone() { register struct sndcbuf *sbp; sbp = &sndcbuf; if ((sbp->sb_len == 0) && ((sbp->sb_flags & (SNDSYN|SNDFIN)) == 0) ) return(TRUE); return(FALSE); } /* sb_noseq return count of data and/or flags to be sent starting w. seqno. If SYN is queued to be sent, only send it. Compute count of buffered data and flags starting at seqno. Then decide how many seqnos useable send window will allow. If advertised send window is 0 and seqno == suna, send 1 data byte. If useable send window is < 25% of advertised send window and no. of seqs is > useable window, send no data. */ sb_noseq(ptcb, seqno) register struct tcb *ptcb; long seqno; { register struct sndcbuf *sbp; register int nseq; int uwnd, sdata; sbp = &sndcbuf; nseq = 0; sdata = 0; if (sbp->sb_flags & SNDSYN) { if (seqno == ptcb->t_iss) return(1); return(0); } if ((scb.s_state & DSND) || (sbp->sb_flags & SNDFIN)) nseq = (sbp->sb_seqno + sbp->sb_len) - seqno; if (sbp->sb_flags & SNDFIN) nseq++; if (nseq <= 0) return(0); if (ptcb->t_swnd == 0) { if (seqno == ptcb->t_suna) sdata = 1; } else { uwnd = (ptcb->t_suna + ptcb->t_swnd) - seqno; if (nseq <= uwnd) sdata = nseq; else if (uwnd > (ptcb->t_swnd >> 2)) sdata = uwnd; } return(sdata); } /* sb_ack Remove acked chars from intermediate send buffer from sb_seqno to ptcb->t_suna (first unacked seqno). Turn off SNDSYN or SNDFIN in sb_flags, if SYN's or FIN's seqno has been acked. Clear sb_urg, if urgent data has been acked. */ sb_ack(ptcb) struct tcb *ptcb; { register struct sndcbuf *sbp; register short len1; register char *chp; sbp = &sndcbuf; len1 = ptcb->t_suna - sbp->sb_seqno; if (len1 == 0) return; if ((len1 < 0) || ((len1 - sbp->sb_len) > 1)) return( sb_badack(ptcb) ); if (sbp->sb_flags & SNDSYN) { if ((ptcb->t_state & (SYN_SENT|SYN_ACK)) != (SYN_SENT|SYN_ACK)) return( sb_badack(ptcb) ); sbp->sb_flags &= (~SNDSYN); sbp->sb_seqno++; len1--; } if (len1 > sbp->sb_len) { if ((ptcb->t_state & (FIN_SENT|FIN_ACK)) != (FIN_SENT|FIN_ACK)) return( sb_badack(ptcb) ); sbp->sb_flags &= (~SNDFIN); len1--; } chp = sbp->sb_datp + len1; if (chp >= sbp->sb_ebuff) chp = sbp->sb_bbuff + (len1 - (sbp->sb_ebuff - sbp->sb_datp)); sbp->sb_datp = chp; sbp->sb_seqno += len1; sbp->sb_len -= len1; if (sbp->sb_urg) { if (sbp->sb_urg <= len1) sbp->sb_urg = 0; else sbp->sb_urg -= len1; } } sb_badack(ptcb) register struct tcb *ptcb; { register struct sndcbuf *sbp; sbp = &sndcbuf; logerr("sb_badack state %o suna %O buff seqno %O flgs %o len %o iss %O\n", ptcb->t_state, ptcb->t_suna, sbp->sb_seqno, sbp->sb_flags, sbp->sb_len, ptcb->t_iss); } /* sb_pkt make tcp packet. If SYN waiting to be sent, send only it. Otherwise, copy buffered send data into outgoing tcp pkt. Specifically, copy nseq bytes (or available bytes) from sndcbuf, starting at sequence no. seqno, to tcp pkt. If appropriate set FIN flag, and/or URG flag and urg ptr. Clr PSH flag if more data buffered to be sent after this pkt. */ sb_pkt(ptcb, seqno, nseq) struct tcb *ptcb; long seqno; int nseq; { register struct sndcbuf *sbp; struct tcp_hdr *tcp; register char *obuff; register char *chp; char *che; short len1, len2, dlen; sbp = &sndcbuf; len1 = seqno - sbp->sb_seqno; if (len1 < 0) { logerr("sb_pkt trying to get acked seqnos %O %O\n", seqno, sbp->sb_seqno); return(0); } if (sbp->sb_flags & SNDSYN) { if (seqno == ptcb->t_iss) sb_syn(ptcb); return(0); } len2 = (sbp->sb_seqno + sbp->sb_len) - seqno; if (len2 < 0) return(0); tcp = &ptcb->t_tcp; obuff = &ptcb->t_data; if ((sbp->sb_flags & SNDFIN) && (len2 < nseq)) tcp->tc_flags |= (FIN|PSH); if (len2 == 0) return(0); dlen = len2 < nseq ? len2:nseq; chp = sbp->sb_datp + len1; if (chp >= sbp->sb_ebuff) chp = sbp->sb_bbuff + (len1 - (sbp->sb_ebuff - sbp->sb_datp)); che = chp + dlen; if (che > sbp->sb_ebuff) { che = sbp->sb_bbuff + (dlen - (sbp->sb_ebuff - chp)); while (chp < sbp->sb_ebuff) *obuff++ = *chp++; chp = sbp->sb_bbuff; } while (chp < che) *obuff++ = *chp++; if (dlen < len2) tcp->tc_flags &= (~PSH); if (sbp->sb_urg > len1) { tcp->tc_flags |= (URG|PSH); tcp->tc_urgp = sbp->sb_urg - len1; } return(dlen); } /* sb_syn make syn pkt */ sb_syn(ptcb) register struct tcb *ptcb; { register struct tcp_hdr *tcp; register struct tcp_opt *tcpo; tcp = &ptcb->t_tcp; tcp->tc_flags |= (SYN|PSH); tcp->tc_off = (((TCPHSIZ + 4) << 2) & 0360); tcpo = &ptcb->t_data; tcpo->tc_okind = TCPOPT_MAXSEG; tcpo->tc_olen = 4; tcpo->tc_odata = swab(ptcb->t_maxdata); /* Max tcp rcv data */ } /* tcp_urg user level request that currently buffered data be sent as urgent. */ tcp_urg() { register struct sndcbuf *sbp; sbp = &sndcbuf; sbp->sb_urg = sbp->sb_len; } /* tcp_close user level request to close connection. */ tcp_close() { scb.s_state &= ~DSND; if ((tcb.t_state & FIN_SENT) || (tcb.t_state == CLOSED2)) return; sndcbuf.sb_flags |= SNDFIN; } /* tcp_abort user level request to abort connection. */ tcp_abort() { scb.s_state = UCLOSED; tcb.t_state = CLOSED2; net_close(); }