From a6503abfeb4de375c7b7576032e090beb31a23ce Mon Sep 17 00:00:00 2001 From: Bill Joy Date: Thu, 26 Nov 1981 00:10:39 -0800 Subject: [PATCH] listing SCCS-vsn: sys/netinet/tcp_fsm.h 4.8 SCCS-vsn: sys/netinet/tcp_input.c 1.31 SCCS-vsn: sys/netinet/tcp_output.c 4.18 SCCS-vsn: sys/netinet/tcp_subr.c 4.2 SCCS-vsn: sys/netinet/tcp_timer.c 4.2 SCCS-vsn: sys/netinet/tcp_usrreq.c 1.35 SCCS-vsn: sys/netinet/tcp_var.h 4.8 --- usr/src/sys/netinet/tcp_fsm.h | 6 +- usr/src/sys/netinet/tcp_input.c | 17 +- usr/src/sys/netinet/tcp_output.c | 302 ++++++++++++++----------------- usr/src/sys/netinet/tcp_subr.c | 96 +++++++++- usr/src/sys/netinet/tcp_timer.c | 81 +++------ usr/src/sys/netinet/tcp_usrreq.c | 273 +++++----------------------- usr/src/sys/netinet/tcp_var.h | 63 +++---- 7 files changed, 340 insertions(+), 498 deletions(-) diff --git a/usr/src/sys/netinet/tcp_fsm.h b/usr/src/sys/netinet/tcp_fsm.h index d87c693996..dbf5f9046c 100644 --- a/usr/src/sys/netinet/tcp_fsm.h +++ b/usr/src/sys/netinet/tcp_fsm.h @@ -1,4 +1,4 @@ -/* tcp_fsm.h 4.7 81/11/24 */ +/* tcp_fsm.h 4.8 81/11/25 */ /* * TCP FSM state definitions. @@ -11,11 +11,13 @@ #define TCPS_LISTEN 1 /* listening for connection */ #define TCPS_SYN_SENT 2 /* active, have sent syn */ #define TCPS_SYN_RCVD 3 /* have send and received syn */ +/* states < TCPS_ESTABLISHED are those where connections not established */ #define TCPS_ESTABLISHED 4 /* established */ +#define TCPS_CLOSE_WAIT 8 /* rcvd fin, waiting for close */ +/* states > TCPS_CLOSE_WAIT are those where user has closed */ #define TCPS_FIN_WAIT_1 5 /* have closed, sent fin */ #define TCPS_FIN_WAIT_2 6 /* have closed, fin is acked */ #define TCPS_TIME_WAIT 7 /* in 2*msl quiet wait after close */ -#define TCPS_CLOSE_WAIT 8 /* rcvd fin, waiting for close */ #define TCPS_CLOSING 9 /* closed xchd FIN; await FIN ACK */ #define TCPS_LAST_ACK 10 /* had fin and close; await FIN ACK */ diff --git a/usr/src/sys/netinet/tcp_input.c b/usr/src/sys/netinet/tcp_input.c index 9fe2f2058f..91acf5e386 100644 --- a/usr/src/sys/netinet/tcp_input.c +++ b/usr/src/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* tcp_input.c 1.30 81/11/24 */ +/* tcp_input.c 1.31 81/11/25 */ #include "../h/param.h" #include "../h/systm.h" @@ -412,8 +412,10 @@ step6: * therefore can't validate drop the segment. Otherwise ACK * the FIN and let the user know that the connection is closing. */ - if ((tiflags & TH_FIN) && TCPS_HAVERCVDSYN(tp->t_state)) { - tcp_usrclosing(tp); + if (tiflags & TH_FIN) { + if (TCPS_HAVERCVDSYN(tp->t_state) == 0) + goto drop; + socantrcvmore(so); tp->t_flags |= TF_ACKNOW; tp->rcv_nxt++; switch (tp->t_state) { @@ -450,7 +452,7 @@ step6: */ case TCPS_FIN_WAIT_2: tp->t_state = TCPS_FIN_WAIT_2; - tcp_canceltimers(tp, 0); + tcp_canceltimers(tp); tp->t_timer[TCPT_FINACK] = TCPSC_2MSL; break; @@ -562,7 +564,7 @@ tcp_reass(tp, ti, endp) if (q->ti_len) break; if (q == ti) - panic("tcp_text dropall"); + panic("tcp_reass dropall"); q = (struct tcpiphdr *)q->ti_prev; remque(q->ti_next); } @@ -594,7 +596,10 @@ present: panic("tcp_reass"); ti = (struct tcpiphdr *)ti->ti_next; } - sorwakeup(so); + if (so->so_state & SS_CANTRCVMORE) + sbflush(&so->so_rcv); + else + sorwakeup(so); return (flags); drop: m_freem(dtom(ti)); diff --git a/usr/src/sys/netinet/tcp_output.c b/usr/src/sys/netinet/tcp_output.c index 3199ee8110..a3cc817432 100644 --- a/usr/src/sys/netinet/tcp_output.c +++ b/usr/src/sys/netinet/tcp_output.c @@ -1,4 +1,4 @@ -/* tcp_output.c 4.17 81/11/24 */ +/* tcp_output.c 4.18 81/11/25 */ #include "../h/param.h" #include "../h/systm.h" @@ -17,184 +17,158 @@ #include "/usr/include/errno.h" /* - * Special routines to send control messages. + * Tcp output routine: figure out what should be sent + * and, if nothing, send a null segment anyways if force is nonzero + * (e.g. to be sure to send an ACK). + * + * This routine can be called only after SYNs have been exchanged. */ -tcp_sndctl(tp) - struct tcpcb *tp; -{ -COUNT(TCP_SNDCTL); - - if (tcp_send(tp)) - return (1); - tcp_sndnull(tp); - return (0); -} - -tcp_sndwin(tp) - struct tcpcb *tp; -{ - int ihave, hehas; -COUNT(TCP_SNDWIN); - - if (tp->rcv_adv) { - register struct socket *so = tp->t_inpcb->inp_socket; - - ihave = so->so_rcv.sb_hiwat - - (so->so_rcv.sb_cc + tp->seqcnt); - hehas = tp->rcv_adv - tp->rcv_nxt; - if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35) - return; - } - if (tcp_send(tp)) - return; - tcp_sndnull(tp); -} - -tcp_sndnull(tp) +tcp_output(tp) register struct tcpcb *tp; { -COUNT(TCP_SNDNULL); - - (void) tcp_output(tp, 0, 0, (struct mbuf *)0); - tp->tc_flags &= ~TC_ACK_DUE; -} - -/* - * Tcp segment output routine. - */ -tcp_send(tp) - register struct tcpcb *tp; -{ - register unsigned long last, wind; register struct socket *so = tp->t_inpcb->inp_socket; - struct mbuf *m; - int flags = 0, forced, sent, len; + register int len; + struct mbuf *m0; + int off, flags; + register struct mbuf *m; + register struct tcpiphdr *ti; + int win; -COUNT(TCP_SEND); - tp->snd_lst = tp->snd_nxt; - forced = 0; - m = NULL; - if (tp->snd_nxt == tp->iss) { - flags |= TH_SYN; - tp->snd_lst++; - } - last = tp->snd_off; - for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next) - last += m->m_len; - if (tp->snd_nxt > last) { - if ((tp->tc_flags&TC_SND_FIN) && - (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { +COUNT(TCP_OUTPUT); - flags |= TH_FIN; - tp->seq_fin = tp->snd_lst++; - } - } else { - if (tp->tc_flags&TC_SYN_ACKED) { - wind = tp->snd_una + tp->snd_wnd; - tp->snd_lst = MIN(last, wind); - if ((len = tp->snd_lst - tp->snd_nxt) > 1024) - tp->snd_lst -= len - 1024; - if (tp->snd_lst >= wind) - tp->t_persist = T_PERS; - } - if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { - tp->snd_lst = tp->snd_nxt + 1; - forced = 1; - } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0) - return (0); - m = m_copy(so->so_snd.sb_mb, - (int)(MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off), - (int)(tp->snd_lst - tp->snd_off)); - if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) - flags |= TH_EOL; - if ((tp->tc_flags&TC_SND_FIN) && !forced && - tp->snd_lst == last && - (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { - flags |= TH_FIN; - tp->seq_fin = tp->snd_lst++; - } - } - if (tp->snd_nxt >= tp->snd_lst) - return (0); - if (tp->tc_flags & TC_SND_URG) - flags |= TH_URG; - sent = tcp_output(tp, flags, (int)(tp->snd_lst - tp->snd_nxt), m); - if (!forced) { - tp->t_rexmt = tp->t_xmtime; - tp->t_rexmt_val = tp->snd_lst; - if ((tp->tc_flags&TC_REXMT) == 0) { - tp->t_rexmttl = T_REXMTTL; - tp->t_rtl_val = tp->snd_lst; - } + /* + * Determine length of data that can be transmitted. + * If will transmit to end of data and no more data + * is coming, then send FIN also. + * Make a copy of the data (if any). If no data + * and not forced to transmit, just return. + */ + off = tp->snd_nxt - tp->snd_una; + len = MIN(so->so_snd.sb_cc, tp->snd_wnd) - off; + if (len > tp->mtu) + len = tp->mtu; + if (len == so->so_snd.sb_cc && (so->so_state & SS_CANTSNDMORE)) + flags = TH_FIN; + else + flags = 0; + if (len) + goto send; + + /* + * No data to send: see if something else makes us want to send. + * First check if we owe peer and ack or have a unacked FIN to send. + */ + if (tp->t_flags & TF_OWEACK) + goto send; + if ((so->so_state & SS_CANTSNDMORE) && + TCPS_OURFINISACKED(tp->t_state) == 0) + goto send; + if (tp->t_state == TCPS_SYN_SENT) { + flags = TH_SYN; + goto send; } - if (sent) - tp->snd_nxt = tp->snd_lst; - if ((tp->tc_flags&TC_SYN_ACKED) && - tp->snd_una > tp->t_xmt_val) { - tp->t_xmt = 0; - tp->t_xmt_val = tp->snd_lst; + if (tp->t_state == TCPS_CLOSED) { + flags = TH_RST; + goto send; } - tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); - tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi); - return (1); -} -tcp_output(tp, flags, len, dat) - register struct tcpcb *tp; - register int flags; - int len; - struct mbuf *dat; -{ - register struct tcpiphdr *t; /* known to be r9 */ - register struct mbuf *m; - struct socket *so = tp->t_inpcb->inp_socket; - register struct ip *ip; -COUNT(TCP_OUTPUT); - if ((t = tp->t_template) == 0) - return (0); + /* + * Calculate available window in i, and also amount + * of window known to peer (as advertised window less + * next expected input.) If this is 35% or more of the + * maximum possible window, then want to send a segment to peer. + */ + i = sbspace(&so->so_rcv) - tp->seqcnt; + if (i > 0 && + ((100*(i-(tp->rcv_adv-tp->rcv_nxt))/so->so_rcv.sb_hiwat) >= 35)) + goto send; + + /* + * No reason to send a segment, just return. + */ + return; + +send: + /* + * Grab a header mbuf, attaching a copy of data to + * be transmitted, and initialize the header from + * the template for sends on this connection. + */ MGET(m, 0); if (m == 0) return (0); m->m_off = MMAXOFF - sizeof(struct tcpiphdr); m->m_len = sizeof (struct tcpiphdr); - m->m_next = dat; + if (len) { + m->m_next = m_copy(so->so_snd.sb_mb, off, len); + if (m->m_next == 0) + len = 0; + } + ti = mtod(m, struct tcpiphdr *); + if (tp->t_template == 0) + panic("tcp_output"); + bcopy((caddr_t)tp->t_template, ti, sizeof (struct tcpiphdr)); + + /* + * Fill in fields, remembering maximum advertised + * window for use in delaying messages about window sizes. + */ + ti->ti_seq = htonl(tp->snd_nxt); + ti->ti_ackno = htonl(tp->rcv_nxt); + /* OPTIONS */ if (flags & TH_SYN) - len--; + ti->ti_flags = flags; + else + ti->ti_flags = flags | TH_ACK; + win = sbspace(&so->so_rcv); + if (win > 0) + ti->ti_win = htons(win); + if (SEQ_GT(tp->snd_urp, tp->snd_nxt)) + ti->ti_urp = htons((u_short)(tp->snd_urp - tp->snd_nxt)); + ti->ti_flags |= TH_URG; + } else + /* + * If no urgent pointer to send, then we pull + * the urgent pointer to the left edge of the send window + * so that it doesn't drift into the send window on sequence + * number wraparound. + */ + tp->snd_urp = tp->snd_una; /* drag it along */ + + /* + * Put TCP length in extended header, and then + * checksum extended header and data. + */ + if (len) + ti->ti_len = htons((u_short)(len + sizeof (struct tcphdr))); + ti->ti_sum = inet_cksum(m, sizeof (struct tcpiphdr) + len); + + /* + * Fill in IP length and desired time to live and + * send to IP level. + */ + ((struct ip *)ti)->ip_len = len + sizeof (struct tcpiphdr); + ((struct ip *)ti)->ip_ttl = TCP_TTL; + if (ip_output(m) == 0) + return; + + /* + * Data sent (as far as we can tell). + * If this advertises a larger window than any other segment, + * then record its sequence to be used in suppressing messages. + * Advance snd_nxt to reflect transmitted sequence space, + * drop send for purpose of ACK requirements, + * and time transmission if not a retransmit. + */ + if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) + tp->rcv_adv = tp->rcv_nxt + win; + tp->snd_nxt += len; + tp->t_flags &= ~(TF_OWEACK|TF_DELACK); if (flags & TH_FIN) - len--; - if (len < 0) - panic("tcp_output"); - bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr)); - t = mtod(m, struct tcpiphdr *); - if (tp->tc_flags&TC_SND_RST) { - flags &= ~TH_SYN; - flags |= TH_RST; + tp->snd_nxt++; + if (SEQ_GT(tp->snd_nxt, tp->snd_hi)) { + tp->snd_hi = tp->snd_nxt; + /* TIME TRANSMIT */ } - if (tp->tc_flags&TC_SYN_RCVD) - flags |= TH_ACK; - t->ti_flags = flags; - if (flags & TH_URG) - t->ti_urp = htons((u_short)tp->snd_urp); /*XXX */ - t->ti_win = - so->so_rcv.sb_hiwat - - (so->so_rcv.sb_cc + tp->seqcnt); - if (tp->rcv_nxt + t->ti_win > tp->rcv_adv) - tp->rcv_adv = tp->rcv_nxt + t->ti_win; - if (len) - t->ti_len = htons((u_short)(len + sizeof (struct tcphdr))); - t->ti_win = htons(t->ti_win); - t->ti_seq = htonl(tp->snd_nxt); - t->ti_ackno = htonl(tp->rcv_nxt); - t->ti_sum = 0; /* gratuitous? */ - t->ti_sum = inet_cksum(m, sizeof (struct tcpiphdr) + len); - ip = (struct ip *)t; - ip->ip_v = IPVERSION; - ip->ip_hl = 5; - ip->ip_tos = 0; - ip->ip_len = len + sizeof(struct tcpiphdr); - ip->ip_id = ip_id++; - ip->ip_off = 0; - ip->ip_ttl = MAXTTL; - ip_send(ip); - return (1); + return; } diff --git a/usr/src/sys/netinet/tcp_subr.c b/usr/src/sys/netinet/tcp_subr.c index dbe2491c67..3938b7ea62 100644 --- a/usr/src/sys/netinet/tcp_subr.c +++ b/usr/src/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* tcp_subr.c 4.1 81/11/24 */ +/* tcp_subr.c 4.2 81/11/25 */ #include "../h/param.h" #include "../h/systm.h" @@ -97,3 +97,97 @@ tcp_reflect(ti, ack, seq, flags) ((struct ip *)ti)->ip_ttl = MAXTTL; ip_output(m); } + +struct tcpcb * +tcp_newtcpcb(inp) + struct inpcb *inp; +{ + struct mbuf *m = m_getclr(0); + register struct tcpcb *tp; +COUNT(TCP_NEWTCPCB); + + if (m == 0) + return (0); + tp = mtod(m, struct tcpcb *); + + /* + * Make empty reassembly queue. + */ + tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; + + /* + * Initialize sequence numbers and round trip retransmit timer. + */ + tp->t_xmtime = T_REXMT; + tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = + tp->iss = tcp_iss; + tp->snd_off = tp->iss + 1; + tcp_iss += (ISSINCR >> 1) + 1; + + /* + * Hook to inpcb. + */ + tp->t_inpcb = inp; + inp->inp_ppcb = (caddr_t)tp; + return (tp); +} + +tcp_drop(tp, errno) + struct tcpcb *tp; + int errno; +{ + struct socket *so = tp->t_inpcb->inp_socket; + +COUNT(TCP_DROP); + if (TCPS_HAVERCVDSYN(tp->t_state) && + TCPS_OURFINISACKED(tp->t_state) == 0) { + tp->t_state = TCPS_CLOSED; + tcp_output(tp); + } + so->so_error = errno; + socantrcvmore(so); + socantsndmore(so); + tcp_close(tp); +} + +tcp_close(tp) + register struct tcpcb *tp; +{ + register struct tcpiphdr *t; + +COUNT(TCP_CLOSE); + tcp_canceltimers(tp); + t = tp->seg_next; + for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next) + m_freem(dtom(t)); + if (tp->t_template) { + (void) m_free(dtom(tp->t_template)); + tp->t_template = 0; + } + in_pcbfree(tp->t_inpcb); + (void) m_free(dtom(tp)); +} + +/*ARGSUSED*/ +tcp_sense(m) + struct mbuf *m; +{ + +COUNT(TCP_SENSE); + return (EOPNOTSUPP); +} + +tcp_drain() +{ + register struct inpcb *ip; + +COUNT(TCP_DRAIN); +} + +tcp_ctlinput(m) + struct mbuf *m; +{ + +COUNT(TCP_CTLINPUT); + m_freem(m); +} diff --git a/usr/src/sys/netinet/tcp_timer.c b/usr/src/sys/netinet/tcp_timer.c index 34b8e5da0e..85175e521c 100644 --- a/usr/src/sys/netinet/tcp_timer.c +++ b/usr/src/sys/netinet/tcp_timer.c @@ -1,4 +1,4 @@ -/* tcp_timer.c 4.1 81/11/24 */ +/* tcp_timer.c 4.2 81/11/25 */ #include "../h/param.h" #include "../h/systm.h" @@ -46,7 +46,7 @@ COUNT(TCP_TIMEO); for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) { tp = intotcpcb(ip); tmp = &tp->t_init; - for (i = 0; i < TNTIMERS; i++) { + for (i = 0; i < TCPT_NTIMERS; i++) { if (*tmp && --*tmp == 0) (void) tcp_usrreq(tp->t_inpcb->inp_socket, PRU_SLOWTIMO, (struct mbuf *)0, @@ -55,86 +55,51 @@ COUNT(TCP_TIMEO); } tp->t_xmt++; } - tcp_iss += ISSINCR/2; /* increment iss */ + tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ splx(s); } /* - * Cancel all timers for tcp tp. + * Cancel all timers for TCP tp. */ tcp_tcancel(tp) struct tcpcb *tp; { - register short *tmp = &tp->t_init; register int i; - for (i = 0; i < TNTIMERS; i++) - *tmp++ = 0; + for (i = 0; i < TCPT_NTIMERS; i++) + tp->t_timer[i] = 0; } /* * TCP timer went off processing. */ -tcp_timers(tp, timertype) +tcp_timers(tp, timer) register struct tcpcb *tp; - int timertype; + int timer; { COUNT(TCP_TIMERS); switch (timertype) { - case TFINACK: /* fin-ack timer */ - switch (tp->t_state) { + case TCPT_2MSL: + tcp_close(tp); + return; - case TIME_WAIT: - /* - * We can be sure our ACK of foreign FIN was rcvd, - * and can close if no data left for user. - */ - if (rcv_empty(tp)) { - tcp_disconnect(tp); - return (CLOSED); - } - return (RCV_WAIT); /* 17 */ - - case CLOSING: - tp->tc_flags |= TC_WAITED_2_ML; - return (SAME); - - default: - return (SAME); + case TCPT_REXMT: + tp->t_xmtime <<= 1; + if (tp->t_xmtime > TCPT_TOOLONG) { + tcp_drop(tp, ETIMEDOUT); + return; } + tcp_output(tp); + return; - case TREXMT: /* retransmission timer */ - if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ - /* - * Set so for a retransmission, increase rexmt time - * in case of multiple retransmissions. - */ - tp->snd_nxt = tp->snd_una; - tp->tc_flags |= TC_REXMT; - tp->t_xmtime = tp->t_xmtime << 1; - if (tp->t_xmtime > T_REMAX) - tp->t_xmtime = T_REMAX; - (void) tcp_send(tp); - } - return (SAME); - - case TREXMTTL: /* retransmit too long */ - if (tp->t_rtl_val > tp->snd_una) { /* 36 */ - tcp_error(tp, ETIMEDOUT); - return (CLOSED); - } - return (SAME); + case TCPT_PERSIST: + if (tcp_output(tp) == 0) + tp->snd_wnd++, (void) tcp_output(tp), tp->snd_wnd--; - case TPERSIST: /* persist timer */ - /* - * Force a byte send through closed window. - */ - tp->tc_flags |= TC_FORCE_ONE; - (void) tcp_send(tp); - return (SAME); + case TCPT_KEEP: + return; } - panic("tcp_timers"); - /*NOTREACHED*/ } diff --git a/usr/src/sys/netinet/tcp_usrreq.c b/usr/src/sys/netinet/tcp_usrreq.c index d6871f7da1..abad774e17 100644 --- a/usr/src/sys/netinet/tcp_usrreq.c +++ b/usr/src/sys/netinet/tcp_usrreq.c @@ -1,4 +1,4 @@ -/* tcp_usrreq.c 1.34 81/11/24 */ +/* tcp_usrreq.c 1.35 81/11/25 */ #include "../h/param.h" #include "../h/systm.h" @@ -33,27 +33,24 @@ tcp_usrreq(so, req, m, addr) register struct inpcb *inp = sotoinpcb(so); register struct tcpcb *tp; int s = splnet(); - register int nstate; int error = 0; + struct tcpiphdr ti; COUNT(TCP_USRREQ); /* * Make sure attached. If not, * only PRU_ATTACH is valid. */ - if (inp == 0) { - if (req != PRU_ATTACH) { - splx(s); - return (EINVAL); - } - } else { + if (inp == 0 && req != PRU_ATTACH) + splx(s); + return (EINVAL); + } + if (inp) { tp = intotcpcb(inp); - nstate = tp->t_state; #ifdef KPROF - tcp_acounts[nstate][req]++; + tcp_acounts[tp->t_state][req]++; #endif } - switch (req) { case PRU_ATTACH: @@ -62,20 +59,19 @@ COUNT(TCP_USRREQ); break; } error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr); - if (error) { - (void) m_free(dtom(tp)); + if (error) break; - } inp = (struct inpcb *)so->so_pcb; if (so->so_options & SO_ACCEPTCONN) { tp = tcp_newtcpcb(inp); if (tp == 0) { + in_pcbfree(inp); error = ENOBUFS; break; } - nstate = LISTEN; + tp->t_state = TCPS_LISTEN; } else - nstate = CLOSED; + tp->t_state = TCPS_CLOSED; break; case PRU_DETACH: @@ -93,9 +89,9 @@ COUNT(TCP_USRREQ); } tp->t_inpcb = inp; inp->inp_ppcb = (caddr_t)tp; - (void) tcp_sndctl(tp); - nstate = SYN_SENT; soisconnecting(so); + tp->t_state = TCPS_SYN_SENT; + tcp_output(tp); break; case PRU_ACCEPT: @@ -103,72 +99,64 @@ COUNT(TCP_USRREQ); break; case PRU_DISCONNECT: - if (nstate < ESTAB) - tcp_disconnect(tp); + if (tp->t_state < TCPS_ESTABLISHED) + tcp_close(tp); else { - tp->tc_flags |= TC_SND_FIN; - (void) tcp_sndctl(tp); soisdisconnecting(so); + tcp_output(tp); } break; case PRU_SHUTDOWN: - switch (nstate) { + socantsndmore(so); + switch (tp->t_state) { case TCPS_LISTEN: case TCPS_SYN_SENT: - nstate = TCPS_CLOSED; + tp->t_state = TCPS_CLOSED; break; case TCPS_SYN_RCVD: - case TCPS_ESTABLISHED: - case TCPS_CLOSE_WAIT: - tp->tc_flags |= TC_SND_FIN; - (void) tcp_sndctl(tp); - nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; - break; - - case TCPS_FIN_W1: - case TCPS_FIN_W2: - case TCPS_TIME_WAIT: - case TCPS_CLOSING: - case TCPS_LAST_ACK: - case TCPS_RCV_WAIT: + case TCPS_ESTAB: + tp->t_state = TCPS_FIN_WAIT_1; + tcp_output(tp); break; - default: - goto bad; + case TCPS_CLOSE_WAIT: + tp->t_state = TCPS_LAST_ACK; + tcp_output(tp); + break; } break; case PRU_RCVD: - if (nstate < TCPS_ESTAB) - goto bad; - tcp_sndwin(tp); - if (nstate == TCPS_RCV_WAIT && rcv_empty(tp)) - nstate = TCPS_CLOSED; + if (tp->t_state < TCPS_ESTABLISHED) { + error = ENOTCONN; + break; + } + tcp_output(tp); break; case PRU_SEND: - switch (nstate) { - - case ESTAB: - case CLOSE_WAIT: - tcp_usrsend(tp, m); + if (tp->t_state < TCPS_ESTABLISHED) { + error = ENOTCONN; break; - - default: - if (nstate < ESTAB) - goto bad; + } + if (tp->t_state > TCPS_CLOSE_WAIT) { + error = EISDISCONN; m_freem(m); - error = ENOTCONN; break; } + sbappend(&so->so_snd, m); + if (tp->t_options & TO_EOL) + tp->snd_end = tp->snd_una + so->so_snd.sb_cc; + if (tp->t_options & TO_URG) + tp->snd_urp = tp->snd_una + so->so_snd.sb_cc + 1; + tcp_output(tp); break; case PRU_ABORT: - tcp_abort(tp); - nstate = CLOSED; + tcp_drop(tp, ECONNABORTED); break; case PRU_CONTROL: @@ -176,183 +164,12 @@ COUNT(TCP_USRREQ); break; case PRU_SLOWTIMO: - switch (nstate) { - - case 0: - case CLOSED: - case LISTEN: - goto bad; - - default: - nstate = tcp_timers(tp, (int)addr); - } + tcp_timers(tp, (int)addr); break; default: panic("tcp_usrreq"); - bad: - printf("tcp: bad state: tcb=%x state=%d input=%d\n", - tp, tp->t_state, req); - nstate = EFAILEC; - break; - } - switch (nstate) { - - case CLOSED: - case SAME: - break; - - case EFAILEC: - if (m) - m_freem(dtom(m)); - break; - - default: - tp->t_state = nstate; - break; } splx(s); return (error); } - -struct tcpcb * -tcp_newtcpcb(inp) - struct inpcb *inp; -{ - struct mbuf *m = m_getclr(0); - register struct tcpcb *tp; -COUNT(TCP_NEWTCPCB); - - if (m == 0) - return (0); - tp = mtod(m, struct tcpcb *); - - /* - * Make empty reassembly queue. - */ - tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; - - /* - * Initialize sequence numbers and round trip retransmit timer. - */ - tp->t_xmtime = T_REXMT; - tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = - tp->iss = tcp_iss; - tp->snd_off = tp->iss + 1; - tcp_iss += (ISSINCR >> 1) + 1; - - /* - * Hook to inpcb. - */ - tp->t_inpcb = inp; - inp->inp_ppcb = (caddr_t)tp; - return (tp); -} - -tcp_disconnect(tp) - register struct tcpcb *tp; -{ - register struct tcpiphdr *t; - -COUNT(TCP_DISCONNECT); - tcp_tcancel(tp); - t = tp->seg_next; - for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next) - m_freem(dtom(t)); - tcp_drainunack(tp); - if (tp->t_template) { - (void) m_free(dtom(tp->t_template)); - tp->t_template = 0; - } - in_pcbfree(tp->t_inpcb); - (void) m_free(dtom(tp)); -} - -tcp_abort(tp) - register struct tcpcb *tp; -{ - -COUNT(TCP_ABORT); - switch (tp->t_state) { - - case SYN_RCVD: - case ESTAB: - case FIN_W1: - case FIN_W2: - case CLOSE_WAIT: - tp->tc_flags |= TC_SND_RST; - tcp_sndnull(tp); - } - soisdisconnected(tp->t_inpcb->inp_socket); - tcp_disconnect(tp); -} - -/* - * Send data queue headed by m0 into the protocol. - */ -tcp_usrsend(tp, m0) - register struct tcpcb *tp; - struct mbuf *m0; -{ - register struct socket *so = tp->t_inpcb->inp_socket; -COUNT(TCP_USRSEND); - - sbappend(&so->so_snd, m0); - if (tp->t_options & TO_EOL) - tp->snd_end = tp->snd_off + so->so_snd.sb_cc; - if (tp->t_options & TO_URG) { - tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1; - tp->tc_flags |= TC_SND_URG; - } - (void) tcp_send(tp); -} - -/*ARGSUSED*/ -tcp_sense(m) - struct mbuf *m; -{ - -COUNT(TCP_SENSE); - return (EOPNOTSUPP); -} - -tcp_drop(tp, errno) - struct tcpcb *tp; - int errno; -{ - struct socket *so = tp->t_inpcb->inp_socket; - -COUNT(TCP_ERROR); - so->so_error = errno; - sorwakeup(so); - sowwakeup(so); - tcp_disconnect(tp); -} - -tcp_drain() -{ - register struct inpcb *ip; - -COUNT(TCP_DRAIN); - for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) - tcp_drainunack(intotcpcb(ip)); -} - -tcp_drainunack(tp) - register struct tcpcb *tp; -{ - register struct mbuf *m; - -COUNT(TCP_DRAINUNACK); - for (m = tp->seg_unack; m; m = m->m_act) - m_freem(m); - tp->seg_unack = 0; -} - -tcp_ctlinput(m) - struct mbuf *m; -{ - -COUNT(TCP_CTLINPUT); - m_freem(m); -} diff --git a/usr/src/sys/netinet/tcp_var.h b/usr/src/sys/netinet/tcp_var.h index 16ccc00d86..c2aa183585 100644 --- a/usr/src/sys/netinet/tcp_var.h +++ b/usr/src/sys/netinet/tcp_var.h @@ -1,4 +1,4 @@ -/* tcp_var.h 4.7 81/11/24 */ +/* tcp_var.h 4.8 81/11/25 */ /* * Kernel variables for tcp. @@ -43,31 +43,29 @@ struct tcpiphdr { * Definitions of the TCP timers. These timers are counted * down PR_SLOWHZ times a second. */ -#define TCPT_NTIMERS 7 +#define TCPT_NTIMERS 4 -#define TCPT_INIT 0 /* initialization */ -#define TCPT_REXMT 1 /* retransmit */ -#define TCPT_REXMTTL 2 /* retransmit too long */ +#define TCPT_REXMT 0 /* retransmit */ +#define TCPT_2MSL 1 /* 2*msl quiet time timer */ +#define TCPT_PERSIST 2 /* retransmit persistance */ #define TCPT_KEEP 3 /* keep alive */ -#define TCPT_KEEPTTL 4 /* keep alive too long */ -#define TCPT_PERSIST 5 /* retransmit persistance */ -#define TCPT_2MSL 6 /* 2*msl quiet time timer */ /* * Tcp control block. */ struct tcpcb { - struct tcpiphdr *seg_next,*seg_prev; /* seq queue */ - short seqcnt; /* count of chars in seq queue */ - u_char t_state; /* state of this connection */ + struct tcpiphdr *seg_next; /* sequencing queue */ + struct tcpiphdr *seg_prev; + int t_state; /* state of this connection */ + int seqcnt; /* count of chars in seq queue */ short t_timers[TCPT_NTIMERS]; /* tcp timers */ - u_char t_options; /* connection options: */ + short t_options; /* connection options: */ #define TO_PUSH 0x01 /* push mode */ #define TO_URG 0x02 /* urgent mode */ #define TO_KEEP 0x04 /* use keep-alives */ u_char t_flags; #define TF_OWEACK 0x01 /* owe ack to peer */ - struct mbuf *seg_unack; /* unacked message queue */ +#define TF_DELACK 0x02 /* delaying ack to peer */ struct tcpiphdr *t_template; /* skeletal packet for transmit */ struct inpcb *t_inpcb; /* back pointer to internet pcb */ /* @@ -90,44 +88,31 @@ struct tcpcb { /* * Additional variables for this implementation. */ -/* send variables */ - tcp_seq snd_off; /*??*/ /* seq # of first datum in send buf */ - tcp_seq seq_fin; /*??*/ /* seq # of FIN sent */ - tcp_seq snd_hi; /*??*/ /* highest seq # sent */ - tcp_seq snd_end; /*??*/ /* send eol pointer */ - tcp_seq snd_lst; /*??*/ /* seq # of last sent datum */ - tcp_seq snd_wl; /*??*/ /* seq # of last sent window */ - tcp_seq snd_wnd; /*??*/ /* send window max */ -/* retransmit variables */ - tcp_seq t_rexmt_val; /*??*/ /* val saved in rexmt timer */ - tcp_seq t_rtl_val; /*??*/ /* val saved in rexmt too long timer */ - tcp_seq t_xmt_val; /*??*/ /* seq # sent when xmt timer started */ - u_char t_xmtime; /*??*/ /* current rexmt time */ - short t_xmt; /*??*/ /* round trip transmission time */ /* receive variables */ - tcp_seq rcv_end; /*??*/ /* rcv eol pointer */ - tcp_seq rcv_adv; /*??*/ /* advertised window */ + tcp_seq rcv_adv; /* advertised window */ +/* retransmit variables */ + tcp_seq snd_max; /* highest sequence number sent */ + used to recognize retransmits */ }; #define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb) #define sototcpcb(so) (intotcpcb(sotoinpcb(so))) #define ISSINCR 128 /* increment for iss each second */ -#define TCPSIZE 20 /* size of TCP leader (bytes) */ -#define TCP_TTL 30 /* time to live for TCP segs: 30s */ +#define TCP_TTL 60 /* time to live for TCP segs */ /* * TCPSC constants give various timeouts in ``slow-clock'' ticks. */ -#define TCPSC_MSL (TCP_TTL*PR_SLOWHZ) /* max seg lifetime */ -#define TCPSC_REXMT (1*PR_SLOWHZ) /* base retransmit time */ -#define TCPSC_REXMTTL (TCP_TTL*2*PR_SLOWHZ) /* retransmit too long */ -#define TCPSC_KEEP (TCP_TTL*4*PR_SLOWHZ) /* keep alive */ -#define TCPSC_KEEPTTL (4*TCPSC_KEEP) /* keep alive too long */ -#define TCPSC_PERSIST (5*PR_SLOWHZ) /* retransmit persistance */ -#define TCPSC_2MSL (TCP_TTL*2*PR_SLOWHZ) /* 2*msl quiet time timer */ +#define TCPSC_MSL (120*PR_SLOWHZ) /* max seg lifetime */ +#define TCPSC_REXMT ( 1*PR_SLOWHZ) /* base retransmit time */ +#define TCPSC_KEEP (240*PR_SLOWHZ) /* keep alive */ +#define TCPSC_PERSIST ( 5*PR_SLOWHZ) /* retransmit persistance */ + +#define TCPSC_KEEPTTL ( 4*TCPSC_KEEP) /* keep alive too long */ +#define TCPSC_2MSL ( 2*TCPSC_MSL) /* 2*msl quiet time timer */ -#define TCPSC_REMAX (TCP_TTL*PR_SLOWHZ) /* maximum rexmt time */ +#define TCPSC_TOOLONG (480*PR_SLOWHZ) struct tcpstat { int tcps_badsum; -- 2.20.1