From 405c9168af72200b21fd65c6312d9b6dc4ab358f Mon Sep 17 00:00:00 2001 From: Bill Joy Date: Thu, 3 Dec 1981 01:00:40 -0800 Subject: [PATCH] yet more lint SCCS-vsn: sys/net/if.c 4.5 SCCS-vsn: sys/net/if.h 4.5 SCCS-vsn: sys/vax/if/if_en.c 4.16 SCCS-vsn: sys/vax/if/if_en.h 4.2 SCCS-vsn: sys/net/if_loop.c 4.2 SCCS-vsn: sys/netinet/in_pcb.c 4.11 SCCS-vsn: sys/netinet/ip_input.c 1.21 SCCS-vsn: sys/netinet/ip_var.h 4.5 SCCS-vsn: sys/net/raw_usrreq.c 4.2 SCCS-vsn: sys/netinet/tcp_input.c 1.34 SCCS-vsn: sys/netinet/tcp_output.c 4.21 SCCS-vsn: sys/netinet/tcp_subr.c 4.5 SCCS-vsn: sys/netinet/tcp_timer.c 4.5 SCCS-vsn: sys/netinet/tcp_timer.h 4.2 SCCS-vsn: sys/netinet/tcp_usrreq.c 1.38 SCCS-vsn: sys/netinet/tcp_var.h 4.11 SCCS-vsn: sys/netinet/udp_usrreq.c 4.13 --- usr/src/sys/net/if.c | 11 +++- usr/src/sys/net/if.h | 5 +- usr/src/sys/net/if_loop.c | 4 +- usr/src/sys/net/raw_usrreq.c | 3 +- usr/src/sys/netinet/in_pcb.c | 82 +++++++++++++++++++++++------ usr/src/sys/netinet/ip_input.c | 29 ++++++----- usr/src/sys/netinet/ip_var.h | 5 +- usr/src/sys/netinet/tcp_input.c | 71 +++++++++++-------------- usr/src/sys/netinet/tcp_output.c | 50 ++++++++++++++---- usr/src/sys/netinet/tcp_subr.c | 44 ++++++++++++---- usr/src/sys/netinet/tcp_timer.c | 56 +++++++++++++++----- usr/src/sys/netinet/tcp_timer.h | 89 +++++++++++++++++++++++++++----- usr/src/sys/netinet/tcp_usrreq.c | 11 ++-- usr/src/sys/netinet/tcp_var.h | 17 +++--- usr/src/sys/netinet/udp_usrreq.c | 16 +++--- usr/src/sys/vax/if/if_en.c | 5 +- usr/src/sys/vax/if/if_en.h | 6 ++- 17 files changed, 354 insertions(+), 150 deletions(-) diff --git a/usr/src/sys/net/if.c b/usr/src/sys/net/if.c index 1cd6adb347..bbda36e3f6 100644 --- a/usr/src/sys/net/if.c +++ b/usr/src/sys/net/if.c @@ -1,4 +1,4 @@ -/* if.c 4.4 81/11/29 */ +/* if.c 4.5 81/12/02 */ #include "../h/param.h" #include "../h/systm.h" @@ -6,6 +6,15 @@ #include "../net/in_systm.h" #include "../net/if.h" +if_attach(ifp) + struct ifnet *ifp; +{ + +COUNT(IF_ATTACH); + ifp->if_next = ifnet; + ifnet = ifp; +} + /*ARGSUSED*/ struct ifnet * if_ifwithaddr(in) diff --git a/usr/src/sys/net/if.h b/usr/src/sys/net/if.h index 428833f223..59139908bb 100644 --- a/usr/src/sys/net/if.h +++ b/usr/src/sys/net/if.h @@ -1,4 +1,4 @@ -/* if.h 4.4 81/11/29 */ +/* if.h 4.5 81/12/02 */ /* * Structures defining a network interface, providing a packet @@ -62,9 +62,10 @@ struct ifnet { #define IF_ENQUEUE(ifq, m) { \ (m)->m_act = 0; \ if ((ifq)->ifq_tail == 0) \ - (ifq)->ifq_head = (ifq)->ifq_tail = m; \ + (ifq)->ifq_head = m; \ else \ (ifq)->ifq_tail->m_act = m; \ + (ifq)->ifq_tail = m; \ } #define IF_DEQUEUE(ifq, m) { \ (m) = (ifq)->ifq_head; \ diff --git a/usr/src/sys/net/if_loop.c b/usr/src/sys/net/if_loop.c index 8dd37fdb51..6e85fdc221 100644 --- a/usr/src/sys/net/if_loop.c +++ b/usr/src/sys/net/if_loop.c @@ -1,4 +1,4 @@ -/* if_loop.c 4.1 81/11/29 */ +/* if_loop.c 4.2 81/12/02 */ /* * Loopback interface driver for protocol testing and timing. @@ -29,7 +29,7 @@ loattach() ifp->if_net = LONET; ifp->if_output = looutput; ifp->if_next = ifnet; - ifnet = ifp; + if_attach(ifp); } looutput(ifp, m0, pf) diff --git a/usr/src/sys/net/raw_usrreq.c b/usr/src/sys/net/raw_usrreq.c index 1b6b625577..c1dac29fe3 100644 --- a/usr/src/sys/net/raw_usrreq.c +++ b/usr/src/sys/net/raw_usrreq.c @@ -1,4 +1,4 @@ -/* raw_usrreq.c 4.1 81/11/29 */ +/* raw_usrreq.c 4.2 81/12/02 */ #include "../h/param.h" #include "../h/mbuf.h" @@ -18,7 +18,6 @@ raw_input(m, pf, af) struct sockaddr af; { struct mbuf *mh; - struct sockproto *pfp; int s; mh = m_get(0); diff --git a/usr/src/sys/netinet/in_pcb.c b/usr/src/sys/netinet/in_pcb.c index f41c8687d9..930704fcf7 100644 --- a/usr/src/sys/netinet/in_pcb.c +++ b/usr/src/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* in_pcb.c 4.10 81/11/29 */ +/* in_pcb.c 4.11 81/12/02 */ #include "../h/param.h" #include "../h/systm.h" @@ -12,12 +12,42 @@ #include "../net/if.h" #include "../net/in_pcb.h" +/* + * Routines to manage internet protocol control blocks. + * + * At PRU_ATTACH time a protocol control block is allocated in + * in_pcballoc() and inserted on a doubly-linked list of such blocks + * for the protocol. A port address is either requested (and verified + * to not be in use) or assigned at this time. We also allocate + * space in the socket sockbuf structures here, although this is + * not a clearly correct place to put this function. + * + * A connectionless protocol will have its protocol control block + * removed at PRU_DETACH time, when the socket will be freed (freeing + * the space reserved) and the block will be removed from the list of + * blocks for its protocol. + * + * A connection-based protocol may be connected to a remote peer at + * PRU_CONNECT time through the routine in_pcbconnect(). In the normal + * case a PRU_DISCONNECT occurs causing a in_pcbdisconnect(). + * It is also possible that higher-level routines will opt out of the + * relationship with the connection before the connection shut down + * is complete. This often occurs in protocols like TCP where we must + * hold on to the protocol control block for a unreasonably long time + * after the connection is used up to avoid races in later connection + * establishment. To handle this we allow higher-level routines to + * disassociate themselves from the socket, marking it SS_USERGONE while + * the disconnect is in progress. We notice that this has happened + * when the disconnect is complete, and perform the PRU_DETACH operation, + * freeing the socket. + */ + /* * Allocate a protocol control block, space * for send and receive data, and local host information. * Return error. If no error make socket point at pcb. */ -in_pcballoc(so, head, sndcc, rcvcc, sin) +in_pcbattach(so, head, sndcc, rcvcc, sin) struct socket *so; struct inpcb *head; int sndcc, rcvcc; @@ -28,6 +58,7 @@ in_pcballoc(so, head, sndcc, rcvcc, sin) struct ifnet *ifp; u_long lport; +COUNT(IN_PCBATTACH); if (sin) { if (sin->sin_family != AF_INET) return (EAFNOSUPPORT); @@ -65,7 +96,7 @@ again: for (xp = head->inp_next; xp != head; xp = xp->inp_next) if (xp->inp_lport == head->inp_lport) goto again; - lport = head->inp_lport; + lport = htons(head->inp_lport); gotport: inp->inp_socket = so; inp->inp_lport = lport; @@ -83,11 +114,12 @@ bad: return (ENOBUFS); } -in_pcbsetpeer(inp, sin) +in_pcbconnect(inp, sin) struct inpcb *inp; struct sockaddr_in *sin; { +COUNT(IN_PCBCONNECT); if (sin->sin_family != AF_INET) return (EAFNOSUPPORT); if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) @@ -98,7 +130,17 @@ in_pcbsetpeer(inp, sin) return (0); } -in_pcbfree(inp) +in_pcbdisconnect(inp) + struct inpcb *inp; +{ + +COUNT(IN_PCBDISCONNECT); + inp->inp_faddr.s_addr = 0; + if (inp->inp_socket->so_state & SS_USERGONE) + in_pcbdetach(inp); +} + +in_pcbdetach(inp) struct inpcb *inp; { struct socket *so = inp->inp_socket; @@ -109,6 +151,12 @@ in_pcbfree(inp) (void) m_free(dtom(inp)); } +/* + * Look for a control block to accept a segment. + * First choice is an exact address match. + * Second choice is a match of local address, with + * unspecified foreign address. + */ struct inpcb * in_pcblookup(head, faddr, fport, laddr, lport) struct inpcb *head; @@ -116,19 +164,19 @@ in_pcblookup(head, faddr, fport, laddr, lport) u_short fport, lport; { register struct inpcb *inp; + struct inpcb *match = 0; - for (inp = head->inp_next; inp != head; inp = inp->inp_next) + for (inp = head->inp_next; inp != head; inp = inp->inp_next) { + if (inp->inp_laddr.s_addr != laddr.s_addr || + inp->inp_lport != lport) + continue; + if (inp->inp_faddr.s_addr == 0) { + match = inp; + continue; + } if (inp->inp_faddr.s_addr == faddr.s_addr && - inp->inp_fport == fport && - inp->inp_laddr.s_addr == laddr.s_addr && - inp->inp_lport == lport) + inp->inp_fport == fport) return (inp); - for (inp = head->inp_next; inp != head; inp = inp->inp_next) - if ((inp->inp_faddr.s_addr == faddr.s_addr || - inp->inp_faddr.s_addr == 0) && - (inp->inp_fport == fport || inp->inp_fport == 0) && - inp->inp_laddr.s_addr == laddr.s_addr && - (inp->inp_lport == lport || inp->inp_lport == 0)) - return (inp); - return (0); + } + return (match); } diff --git a/usr/src/sys/netinet/ip_input.c b/usr/src/sys/netinet/ip_input.c index b4fc9ccc4f..f9aa3aec3b 100644 --- a/usr/src/sys/netinet/ip_input.c +++ b/usr/src/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* ip_input.c 1.20 81/11/29 */ +/* ip_input.c 1.21 81/12/02 */ #include "../h/param.h" #include "../h/systm.h" @@ -17,7 +17,8 @@ u_char ip_protox[IPPROTO_MAX]; /* - * Ip initialization. + * Ip initialization: fill in IP protocol switch table. + * All protocols not implemented in kernel go to raw IP protocol handler. */ ip_init() { @@ -41,10 +42,6 @@ COUNT(IP_INIT); u_char ipcksum = 1; struct ip *ip_reass(); -/* - * Ip input routines. - */ - /* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassamble. If complete and fragment queue exists, discard. @@ -74,12 +71,14 @@ next: m_pullup(m, sizeof (struct ip)) == 0) goto bad; ip = mtod(m, struct ip *); - if ((hlen = ip->ip_hl << 2) > m->m_len && - m_pullup(m, hlen) == 0) - goto bad; + if ((hlen = ip->ip_hl << 2) > m->m_len) { + if (m_pullup(m, hlen) == 0) + goto bad; + ip = mtod(m, struct ip *); + } if (ipcksum) if ((ip->ip_sum = in_cksum(m, hlen)) != 0xffff) { - printf("ip_sum %x\n", ip->ip_sum); + printf("ip_sum %x\n", ip->ip_sum); /* XXX */ ipstat.ips_badsum++; goto bad; } @@ -98,12 +97,15 @@ next: * Drop packet if shorter than we expect. */ i = 0; - for (m0 = m; m != NULL; m = m->m_next) + m0 = m; + for (; m != NULL; m = m->m_next) i += m->m_len; m = m0; if (i != ip->ip_len) { - if (i < ip->ip_len) + if (i < ip->ip_len) { + ipstat.ips_tooshort++; goto bad; + } m_adj(m, ip->ip_len - i); } @@ -212,6 +214,8 @@ COUNT(IP_REASS); fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; fp->ipq_src = ((struct ip *)ip)->ip_src; fp->ipq_dst = ((struct ip *)ip)->ip_dst; + q = (struct ipasfrag *)fp; + goto insert; } /* @@ -253,6 +257,7 @@ COUNT(IP_REASS); ip_deq(q->ipf_prev); } +insert: /* * Stick new segment in its place; * check for complete reassembly. diff --git a/usr/src/sys/netinet/ip_var.h b/usr/src/sys/netinet/ip_var.h index 2d419e1d03..337a18a0ca 100644 --- a/usr/src/sys/netinet/ip_var.h +++ b/usr/src/sys/netinet/ip_var.h @@ -1,4 +1,4 @@ -/* ip_var.h 4.4 81/11/26 */ +/* ip_var.h 4.5 81/12/02 */ /* * Overlay for ip header used by other protocols (tcp, udp). @@ -46,7 +46,8 @@ struct ipasfrag { }; struct ipstat { - int ips_badsum; + int ips_badsum; /* checksum bad */ + int ips_tooshort; /* packet too short */ }; #ifdef KERNEL diff --git a/usr/src/sys/netinet/tcp_input.c b/usr/src/sys/netinet/tcp_input.c index c42be63f18..44f04bf6f8 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.33 81/11/29 */ +/* tcp_input.c 1.34 81/12/02 */ #include "../h/param.h" #include "../h/systm.h" @@ -111,6 +111,13 @@ COUNT(TCP_INPUT); goto dropwithreset; so = inp->inp_socket; + /* + * Segment received on connection. + * Reset idle time and keep-alive timer. + */ + tp->t_idle = 0; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; + /* * Calculate amount of space in receive window, * and then do TCP input processing. @@ -178,9 +185,10 @@ COUNT(TCP_INPUT); tp->irs = ti->ti_seq; tcp_rcvseqinit(tp); tp->t_flags |= TF_ACKNOW; - if (SEQ_GT(tp->snd_una, tp->iss)) + if (SEQ_GT(tp->snd_una, tp->iss)) { tp->t_state = TCPS_ESTABLISHED; - else + (void) tcp_reass(tp, (struct tcpiphdr *)0); + } else tp->t_state = TCPS_SYN_RECEIVED; goto trimthenstep6; @@ -333,6 +341,7 @@ trimthenstep6: goto dropwithreset; soisconnected(so); tp->t_state = TCPS_ESTABLISHED; + (void) tcp_reass(tp, (struct tcpiphdr *)0); /* fall into ... */ /* @@ -358,11 +367,23 @@ trimthenstep6: if (acked > so->so_snd.sb_cc) { sbflush(&so->so_snd); acked -= so->so_snd.sb_cc; + /* if acked our FIN is acked */ } else { sbdrop(&so->so_snd, acked); acked = 0; } - /* if acked our FIN is acked */ + + /* + * If transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + */ + if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) { + tp->t_srtt = + tcp_beta * tp->t_srtt + + (1 - tcp_beta) * tp->t_rtt; + tp->t_rtt = 0; + } + tp->snd_una = ti->ti_ack; /* @@ -415,7 +436,7 @@ trimthenstep6: * it and restart the finack timer. */ case TCPS_TIME_WAIT: - tp->t_timer[TCPT_2MSL] = 2 * TCPSC_MSL; + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; goto dropafterack; } #undef ourfinisacked @@ -495,14 +516,14 @@ step6: case TCPS_FIN_WAIT_2: tp->t_state = TCPS_TIME_WAIT;; tcp_canceltimers(tp); - tp->t_timer[TCPT_2MSL] = TCPSC_2MSL; + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; break; /* * In TIME_WAIT state restart the 2 MSL time_wait timer. */ case TCPS_TIME_WAIT: - tp->t_timer[TCPT_2MSL] = TCPSC_2MSL; + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; break; } } @@ -562,14 +583,11 @@ tcp_reass(tp, ti) COUNT(TCP_REASS); /* - * If no data in this segment may want - * to move data up to socket structure (if - * connection is now established). + * Call with ti==0 after become established to + * force pre-ESTABLISHED data up to user socket. */ - if (ti->ti_len == 0) { - m_freem(dtom(ti)); + if (ti == 0) goto present; - } /* * Find a segment which begins after this one does. @@ -620,30 +638,6 @@ COUNT(TCP_REASS); * Stick new segment in its place. */ insque(ti, q->ti_prev); - tp->t_seqcnt += ti->ti_len; - - /* - * Calculate available space and discard segments for - * which there is too much. - */ - overage = - (so->so_rcv.sb_cc + tp->t_seqcnt) - so->so_rcv.sb_hiwat; - if (overage > 0) { - q = tp->seg_prev; - for (;;) { - register int i = MIN(q->ti_len, overage); - overage -= i; - tp->t_seqcnt -= i; - q->ti_len -= i; - m_adj(dtom(q), -i); - if (q->ti_len) - break; - if (q == ti) - panic("tcp_reass dropall"); - q = (struct tcpiphdr *)q->ti_prev; - remque(q->ti_next); - } - } /* * Advance rcv_next through newly completed sequence space. @@ -666,9 +660,6 @@ present: while (ti != (struct tcpiphdr *)tp && ti->ti_seq < tp->rcv_nxt) { remque(ti); sbappend(&so->so_rcv, dtom(ti)); - tp->t_seqcnt -= ti->ti_len; - if (tp->t_seqcnt < 0) - panic("tcp_reass"); ti = (struct tcpiphdr *)ti->ti_next; } if (so->so_state & SS_CANTRCVMORE) diff --git a/usr/src/sys/netinet/tcp_output.c b/usr/src/sys/netinet/tcp_output.c index a3799fd700..bae98faab0 100644 --- a/usr/src/sys/netinet/tcp_output.c +++ b/usr/src/sys/netinet/tcp_output.c @@ -1,8 +1,9 @@ -/* tcp_output.c 4.20 81/11/29 */ +/* tcp_output.c 4.21 81/12/02 */ #include "../h/param.h" #include "../h/systm.h" #include "../h/mbuf.h" +#include "../h/protosw.h" #include "../h/socket.h" #include "../h/socketvar.h" #include "../net/in.h" @@ -46,10 +47,12 @@ COUNT(TCP_OUTPUT); * to send, then transmit; otherwise, investigate further. */ off = tp->snd_nxt - tp->snd_una; - len = MIN(so->so_snd.sb_cc, tp->snd_wnd) - off; + len = MIN(so->so_snd.sb_cc, tp->snd_wnd+tp->t_force) - off; if (len > tp->t_maxseg) len = tp->t_maxseg; flags = tcp_outflags[tp->t_state]; + if (len < so->so_snd.sb_cc) + flags &= ~TH_FIN; if (len || (flags & (TH_SYN|TH_RST))) goto send; @@ -153,15 +156,42 @@ send: tp->snd_nxt += len; /* - * Arrange for retransmit and time this transmit if - * not already a retransmit and sending either data, - * SYN or FIN. + * If this transmission closes the window, + * start persistance timer at 2 round trip + * times but at least TCPTV_PERSMIN ticks. */ - if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { - tp->rxt_seq = tp->snd_nxt - len; - tp->rxt_time = 0; - tp->rxt_cnt = 0; - tp->t_timer[TCPT_REXMT] = 0; /* XXX */ + if (tp->snd_una + tp->snd_wnd >= tp->snd_nxt && + tp->t_timer[TCPT_PERSIST] == 0) { + tp->t_timer[TCPT_PERSIST] = 2 * tp->t_srtt; + if (tp->t_timer[TCPT_PERSIST] < TCPTV_PERSMIN) + tp->t_timer[TCPT_PERSIST] = TCPTV_PERSMIN; + if (tp->t_timer[TCPT_PERSIST] > TCPTV_MAX) + tp->t_timer[TCPT_PERSIST] = TCPTV_MAX; + } + + /* + * Time this transmission if not a retransmission and + * not currently timing anything. + */ + if (SEQ_GT(tp->snd_nxt, tp->snd_max) && tp->t_rtt == 0) { + tp->t_rtt = 1; + tp->t_rtseq = tp->snd_nxt - len; + } + + /* + * Set retransmit timer if not currently set. + * Initial value for retransmit timer to tcp_beta*tp->t_srtt, + * with a minimum of TCPTV_MIN and a max of TCPTV_MAX. + * Initialize shift counter which is used for exponential + * backoff of retransmit time. + */ + if (tp->t_timer[TCPT_REXMT] == 0) { + tp->t_timer[TCPT_REXMT] = tcp_beta * tp->t_srtt; + if (tp->t_timer[TCPT_REXMT] < TCPTV_MIN) + tp->t_timer[TCPT_REXMT] = TCPTV_MIN; + if (tp->t_timer[TCPT_REXMT] > TCPTV_MAX) + tp->t_timer[TCPT_REXMT] = TCPTV_MAX; + tp->t_rxtshift = 0; } /* diff --git a/usr/src/sys/netinet/tcp_subr.c b/usr/src/sys/netinet/tcp_subr.c index 471e4673f0..9cb31d355a 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.4 81/11/29 */ +/* tcp_subr.c 4.5 81/12/02 */ #include "../h/param.h" #include "../h/systm.h" @@ -13,7 +13,6 @@ #include "../net/ip.h" #include "../net/ip_var.h" #include "../net/tcp.h" -#define TCPFSTAB #include "../net/tcp_fsm.h" #include "../net/tcp_seq.h" #include "../net/tcp_timer.h" @@ -30,6 +29,8 @@ tcp_init() COUNT(TCP_INIT); tcp_iss = 1; /* wrong */ tcb.inp_next = tcb.inp_prev = &tcb; + tcp_alpha = TCP_ALPHA; + tcp_beta = TCP_BETA; } /* @@ -73,24 +74,44 @@ COUNT(TCP_TEMPLATE); } /* - * Send a reset message back to send of TCP segment ti, - * with ack, seq and flags fields as specified by parameters. + * Send a single message to the TCP at address specified by + * the given TCP/IP header. If flags==0, then we make a copy + * of the tcpiphdr at ti and send directly to the addressed host. + * This is used to force keep alive messages out using the TCP + * template for a connection tp->t_template. If flags are given + * then we send a message back to the TCP which originated the + * segment ti, and discard the mbuf containing it and any other + * attached mbufs. + * + * In any case the ack and sequence number of the transmitted + * segment are as specified by the parameters. */ tcp_respond(ti, ack, seq, flags) register struct tcpiphdr *ti; tcp_seq ack, seq; int flags; { - struct mbuf *m = dtom(ti); + struct mbuf *m; COUNT(TCP_RESPOND); - m_freem(m->m_next); - m->m_next = 0; - m->m_len = sizeof(struct tcpiphdr); + if (flags == 0) { + m = m_get(0); + if (m == 0) + return; + m->m_off = MMINOFF; + m->m_len = sizeof (struct tcpiphdr); + *mtod(m, struct tcpiphdr *) = *ti; + ti = mtod(m, struct tcpiphdr *); + flags = TH_ACK; + } else { + m_freem(m->m_next); + m->m_next = 0; + m->m_len = sizeof (struct tcpiphdr); #define xchg(a,b,type) { type t; t=a; a=b; b=t; } - xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); - xchg(ti->ti_dport, ti->ti_sport, u_short); + xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); + xchg(ti->ti_dport, ti->ti_sport, u_short); #undef xchg + } ti->ti_next = ti->ti_prev = 0; ti->ti_x1 = 0; ti->ti_len = htons(sizeof (struct tcphdr)); @@ -148,6 +169,7 @@ COUNT(TCP_DROP); } so->so_error = errno; tcp_close(tp); + in_pcbdetach(tp->t_inpcb); } /* @@ -172,10 +194,10 @@ COUNT(TCP_CLOSE); (void) m_free(dtom(tp->t_tcpopt)); if (tp->t_ipopt) (void) m_free(dtom(tp->t_ipopt)); - in_pcbfree(tp->t_inpcb); (void) m_free(dtom(tp)); socantrcvmore(so); socantsendmore(so); + in_pcbdisconnect(tp->t_inpcb); } tcp_drain() diff --git a/usr/src/sys/netinet/tcp_timer.c b/usr/src/sys/netinet/tcp_timer.c index 31ce879ed3..b6f3f33c0d 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.4 81/11/29 */ +/* tcp_timer.c 4.5 81/12/02 */ #include "../h/param.h" #include "../h/systm.h" @@ -53,6 +53,9 @@ COUNT(TCP_SLOWTIMO); PRU_SLOWTIMO, (struct mbuf *)0, (caddr_t)i); } + tp->t_idle++; + if (tp->t_rtt) + tp->t_rtt++; } tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ splx(s); @@ -72,7 +75,7 @@ COUNT(TCP_CANCELTIMERS); } /* - * TCP timer went off processing. + * TCP timer processing. */ tcp_timers(tp, timer) register struct tcpcb *tp; @@ -82,29 +85,54 @@ tcp_timers(tp, timer) COUNT(TCP_TIMERS); switch (timer) { + /* + * 2 MSL timeout in shutdown went off. Delete connection + * control block. + */ case TCPT_2MSL: tcp_close(tp); return; + /* + * Retransmission timer went off. Message has not + * been acked within retransmit interval. Back off + * to a longer retransmit interval and retransmit all + * unacknowledged messages in the window. + */ case TCPT_REXMT: -#if 0 - tp->t_xmtime <<= 1; - if (tp->t_xmtime > TCPSC_TOOLONG) { - tcp_drop(tp, ETIMEDOUT); - return; - } -#endif - tcp_output(tp); + tp->t_rxtshift++; + TCPT_RANGESET(tp->t_timer[TCPT_REXMT], + ((int)(2 * tp->t_srtt)) << tp->t_rxtshift, + TCPTV_MIN, TCPTV_MAX); + tp->snd_nxt = tp->snd_una; + /* this only transmits one segment! */ + (void) tcp_output(tp); return; + /* + * Persistance timer into zero window. + * Force a byte to be output, if possible. + */ case TCPT_PERSIST: - if (tcp_output(tp) == 0) - tp->snd_wnd++, (void) tcp_output(tp), tp->snd_wnd--; - /* reset? */ + tp->t_force = 1; + (void) tcp_output(tp); + tp->t_force = 0; + TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], + 2 * tp->t_srtt, TCPTV_PERSMIN, TCPTV_MAX); return; + /* + * Keep-alive timer went off; send something + * or drop connection if idle for too long. + */ case TCPT_KEEP: - /* reset? */ + if (tp->t_state < TCPS_ESTABLISHED || + tp->t_idle >= TCPTV_MAXIDLE) { + tcp_drop(tp, ETIMEDOUT); + return; + } + tcp_respond(tp->t_template, tp->rcv_nxt, tp->snd_una-1, 0); + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; return; } } diff --git a/usr/src/sys/netinet/tcp_timer.h b/usr/src/sys/netinet/tcp_timer.h index f22e634849..cc73ea6eb8 100644 --- a/usr/src/sys/netinet/tcp_timer.h +++ b/usr/src/sys/netinet/tcp_timer.h @@ -1,4 +1,4 @@ -/* tcp_timer.h 4.1 81/11/29 */ +/* tcp_timer.h 4.2 81/12/02 */ /* * Definitions of the TCP timers. These timers are counted @@ -7,25 +7,88 @@ #define TCPT_NTIMERS 4 #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_PERSIST 1 /* retransmit persistance */ +#define TCPT_KEEP 2 /* keep alive */ +#define TCPT_2MSL 3 /* 2*msl quiet time timer */ + +/* + * The TCPT_REXMT timer is used to force retransmissions. + * The TCP has the TCPT_REXMT timer set whenever segments + * have been sent for which ACKs are expected but not yet + * received. If an ACK is received which advances tp->snd_una, + * then the retransmit timer is cleared (if there are no more + * outstanding segments) or reset to the base value (if there + * are more ACKs expected). Whenever the retransmit timer goes off, + * we retransmit all unacknowledged segments, and do an exponential + * backoff on the retransmit timer. + * + * The TCPT_PERSIST timer is used to keep window size information + * flowing even if the window goes shut. If an output is attempted when there + * is data ready to transmit, but nothing gets sent because the window + * is shut, then we start the TCPT_PERSIST timer, and at intervals + * send a single byte into the peers window to force him to update + * our window information. We do this at most as often as TCPT_PERSMIN + * time intervals, but no more frequently than the current estimate of + * round-trip packet time. The TCPT_PERSIST timer is cleared whenever + * we receive a window update from the peer. + * + * The TCPT_KEEP timer is used to keep connections alive. If an + * connection is idle (no segments received) for TCPTV_KEEP amount of time, + * but not yet established, then we drop the connection. If the connection + * is established, then we force the peer to send us a segment by sending: + * + * This segment is (deliberately) outside the window, and should elicit + * an ack segment in response from the peer. If, despite the TCPT_KEEP + * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE + * amount of time, then we drop the connection. + */ #define TCP_TTL 60 /* time to live for TCP segs */ /* - * TCPSC constants give various timeouts in ``slow-clock'' ticks. + * Time constants. */ -#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 TCPTV_MSL (120*PR_SLOWHZ) /* max seg lifetime */ +#define TCPTV_SRTTBASE ( 1*PR_SLOWHZ) /* base roundtrip time */ +#define TCPTV_KEEP (240*PR_SLOWHZ) /* keep alive - 4 mins */ +#define TCPTV_PERSMIN ( 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 TCPTV_MAXIDLE ( 4*TCPTV_KEEP) /* maximum allowable idle + time before drop conn */ -#define TCPSC_TOOLONG (480*PR_SLOWHZ) +#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ +#define TCPTV_MAX (480*PR_SLOWHZ) /* maximum allowable value */ #ifdef TCPTIMERS char *tcptimers[] = - { "INIT", "REXMT", "REXMTTL", "KEEP", "KEEPTTL", "PERSIST", "2MSL" }; + { "REXMT", "KEEP", "PERSIST", "2MSL" }; #endif + +/* + * Retransmission smoothing constants. + * Smoothed round trip time is updated by + * tp->t_srtt = (tcp_alpha * tp->t_srtt) + ((1 - tcp_alpha) * tp->t_rtt) + * each time a new value of tp->t_rtt is available. The initial + * retransmit timeout is then based on + * tp->t_timer[TCPT_REXMT] = tcp_beta * tp->t_srtt; + * limited, however to be at least TCPTV_REXMTLO and at most TCPTV_REXMTHI. + */ +float tcp_alpha, tcp_beta; + +/* + * Initial values of tcp_alpha and tcp_beta. + * These are conservative: averaging over a long + * period of time, and allowing for large individual deviations from + * tp->t_srtt. + */ +#define TCP_ALPHA 0.9 +#define TCP_BETA 2.0 + +/* + * Force a time value to be in a certain range. + */ +#define TCPT_RANGESET(tv, value, tvmin, tvmax) \ + (tv) = (value); \ + if ((tv) < (tvmin)) \ + (tv) = (tvmin); \ + if ((tv) > (tvmax)) \ + (tv) = (tvmax); diff --git a/usr/src/sys/netinet/tcp_usrreq.c b/usr/src/sys/netinet/tcp_usrreq.c index 3202c3d60b..90f17cce79 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.37 81/11/29 */ +/* tcp_usrreq.c 1.38 81/12/02 */ #include "../h/param.h" #include "../h/systm.h" @@ -59,14 +59,14 @@ COUNT(TCP_USRREQ); error = EISCONN; break; } - error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr); + error = in_pcbattach(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr); 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); + in_pcbdetach(inp); error = ENOBUFS; break; } @@ -76,15 +76,16 @@ COUNT(TCP_USRREQ); break; case PRU_DETACH: + in_pcbdetach(inp); break; case PRU_CONNECT: - error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); + error = in_pcbconnect(inp, (struct sockaddr_in *)addr); if (error) break; tp = tcp_newtcpcb(inp); if (tp == 0) { - inp->inp_faddr.s_addr = 0; + in_pcbdisconnect(inp); error = ENOBUFS; break; } diff --git a/usr/src/sys/netinet/tcp_var.h b/usr/src/sys/netinet/tcp_var.h index 96a4ca0464..2dbd546001 100644 --- a/usr/src/sys/netinet/tcp_var.h +++ b/usr/src/sys/netinet/tcp_var.h @@ -1,27 +1,28 @@ -/* tcp_var.h 4.10 81/11/29 */ +/* tcp_var.h 4.11 81/12/02 */ /* * Kernel variables for tcp. */ /* - * Tcp control block. + * Tcp control block, one per tcp; fields: */ struct tcpcb { struct tcpiphdr *seg_next; /* sequencing queue */ struct tcpiphdr *seg_prev; int t_state; /* state of this connection */ - int t_seqcnt; /* count of chars in seq queue */ short t_timer[TCPT_NTIMERS]; /* tcp timers */ + short t_rxtshift; /* log(2) of rexmt exp. backoff */ struct mbuf *t_tcpopt; /* tcp options */ struct mbuf *t_ipopt; /* ip options */ short t_maxseg; /* maximum segment size */ + short t_force; /* 1 if forcing out a byte */ u_char t_flags; #define TF_ACKNOW 0x01 /* ack peer immediately */ #define TF_DELACK 0x02 /* ack, but try to delay it */ #define TF_PUSH 0x04 /* push mode */ #define TF_URG 0x08 /* urgent mode */ -#define TF_KEEP 0x10 /* use keep-alives */ +#define TF_DONTKEEP 0x10 /* don't use keep-alives */ struct tcpiphdr *t_template; /* skeletal packet for transmit */ struct inpcb *t_inpcb; /* back pointer to internet pcb */ /* @@ -49,9 +50,11 @@ struct tcpcb { /* retransmit variables */ tcp_seq snd_max; /* highest sequence number sent used to recognize retransmits */ - tcp_seq rxt_seq; - short rxt_time; - short rxt_cnt; +/* transmit timing stuff */ + short t_idle; /* inactivity time */ + short t_rtt; /* round trip time */ + tcp_seq t_rtseq; /* sequence number being timed */ + float t_srtt; /* smoothed round-trip time */ }; #define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb) diff --git a/usr/src/sys/netinet/udp_usrreq.c b/usr/src/sys/netinet/udp_usrreq.c index 062ff7b184..70de8567eb 100644 --- a/usr/src/sys/netinet/udp_usrreq.c +++ b/usr/src/sys/netinet/udp_usrreq.c @@ -1,4 +1,4 @@ -/* udp_usrreq.c 4.12 81/11/29 */ +/* udp_usrreq.c 4.13 81/12/02 */ #include "../h/param.h" #include "../h/dir.h" @@ -184,7 +184,7 @@ COUNT(UDP_USRREQ); case PRU_ATTACH: if (inp != 0) return (EINVAL); - error = in_pcballoc(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); + error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr); if (error) return (error); break; @@ -192,13 +192,13 @@ COUNT(UDP_USRREQ); case PRU_DETACH: if (inp == 0) return (ENOTCONN); - in_pcbfree(inp); + in_pcbdetach(inp); break; case PRU_CONNECT: if (inp->inp_faddr.s_addr) return (EISCONN); - error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); + error = in_pcbconnect(inp, (struct sockaddr_in *)addr); if (error) return (error); soisconnected(so); @@ -210,7 +210,7 @@ COUNT(UDP_USRREQ); case PRU_DISCONNECT: if (inp->inp_faddr.s_addr == 0) return (ENOTCONN); - inp->inp_faddr.s_addr = 0; + in_pcbdisconnect(inp); soisdisconnected(so); break; @@ -222,7 +222,7 @@ COUNT(UDP_USRREQ); if (addr) { if (inp->inp_faddr.s_addr) return (EISCONN); - error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); + error = in_pcbconnect(inp, (struct sockaddr_in *)addr); if (error) return (error); } else { @@ -231,11 +231,11 @@ COUNT(UDP_USRREQ); } udp_output(inp, m); if (addr) - inp->inp_faddr.s_addr = 0; + in_pcbdisconnect(inp); break; case PRU_ABORT: - in_pcbfree(inp); + in_pcbdetach(inp); sofree(so); soisdisconnected(so); break; diff --git a/usr/src/sys/vax/if/if_en.c b/usr/src/sys/vax/if/if_en.c index 9048145123..9b6fa50387 100644 --- a/usr/src/sys/vax/if/if_en.c +++ b/usr/src/sys/vax/if/if_en.c @@ -1,4 +1,4 @@ -/* if_en.c 4.15 81/11/29 */ +/* if_en.c 4.16 81/12/02 */ #include "en.h" @@ -105,6 +105,7 @@ COUNT(ENATTACH); es->es_if.if_output = enoutput; es->es_if.if_init = eninit; es->es_if.if_ubareset = enreset; + if_attach(&es->es_if); } /* @@ -215,7 +216,7 @@ restart: */ UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); addr = (struct endevice *)ui->ui_addr; - addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_addr; + addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; addr->en_odelay = es->es_delay; addr->en_owc = -((es->es_olen + 1) >> 1); addr->en_ostat = EN_IEN|EN_GO; diff --git a/usr/src/sys/vax/if/if_en.h b/usr/src/sys/vax/if/if_en.h index 8fdfd2e821..7cf6a1b34a 100644 --- a/usr/src/sys/vax/if/if_en.h +++ b/usr/src/sys/vax/if/if_en.h @@ -1,4 +1,4 @@ -/* if_en.h 4.1 81/11/30 */ +/* if_en.h 4.2 81/12/02 */ /* * Structure of a Ethernet header. @@ -9,11 +9,13 @@ struct en_header { u_short en_type; }; +#define ENPUP_PUPTYPE 0x0400 /* PUP protocol */ #define ENPUP_IPTYPE 0x0800 /* IP protocol */ /* + * The ENPUP_NTRAILER packet types starting at ENPUP_TRAIL have * (type-ENPUP_TRAIL)*512 bytes of data followed - * by a PUP type (as given above). + * by a PUP type (as given above) and then the (variable-length) header. */ #define ENPUP_TRAIL 0x1000 /* Trailer PUP */ #define ENPUP_NTRAILER 16 -- 2.20.1