V1.56 ((tcp 2 of 2) updated IP/TCP and XNS sources for 4.3BSD)
Keith Bostic
bostic at OKEEFFE.BERKELEY.EDU
Tue Apr 5 13:18:48 AEST 1988
Subject: (tcp 2 of 2) updated IP/TCP and XNS sources for 4.3BSD
Index: sys 4.3BSD
Description:
This is number 11 of 11 total articles posted to the newsgroup
comp.bugs.4bsd.ucb-fixes. This archive is number 2 of the 2
articles that make up the tcp posting.
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# netinet
# netinet/tcp_seq.h
# netinet/tcp_subr.c
# netinet/tcp_timer.c
# netinet/tcp_timer.h
# netinet/tcp_usrreq.c
# netinet/tcp_var.h
# netinet/tcpip.h
#
echo c - netinet
mkdir netinet > /dev/null 2>&1
echo x - netinet/tcp_seq.h
sed 's/^X//' >netinet/tcp_seq.h << 'END-of-netinet/tcp_seq.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)tcp_seq.h 7.2 (Berkeley) 12/7/87
X */
X
X/*
X * TCP sequence numbers are 32 bit integers operated
X * on with modular arithmetic. These macros can be
X * used to compare such integers.
X */
X#define SEQ_LT(a,b) ((int)((a)-(b)) < 0)
X#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
X#define SEQ_GT(a,b) ((int)((a)-(b)) > 0)
X#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0)
X
X/*
X * Macros to initialize tcp sequence numbers for
X * send and receive from initial send and receive
X * sequence numbers.
X */
X#define tcp_rcvseqinit(tp) \
X (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1
X
X#define tcp_sendseqinit(tp) \
X (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \
X (tp)->iss
X
X#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */
X
X#ifdef KERNEL
Xtcp_seq tcp_iss; /* tcp initial send seq # */
X#endif
END-of-netinet/tcp_seq.h
echo x - netinet/tcp_subr.c
sed 's/^X//' >netinet/tcp_subr.c << 'END-of-netinet/tcp_subr.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)tcp_subr.c 7.13.1.1 (Berkeley) 2/7/88
X */
X
X#include "param.h"
X#include "systm.h"
X#include "mbuf.h"
X#include "socket.h"
X#include "socketvar.h"
X#include "protosw.h"
X#include "errno.h"
X
X#include "../net/route.h"
X#include "../net/if.h"
X
X#include "in.h"
X#include "in_pcb.h"
X#include "in_systm.h"
X#include "ip.h"
X#include "ip_var.h"
X#include "ip_icmp.h"
X#include "tcp.h"
X#include "tcp_fsm.h"
X#include "tcp_seq.h"
X#include "tcp_timer.h"
X#include "tcp_var.h"
X#include "tcpip.h"
X
Xint tcp_ttl = TCP_TTL;
X
X/*
X * Tcp initialization
X */
Xtcp_init()
X{
X
X tcp_iss = 1; /* wrong */
X tcb.inp_next = tcb.inp_prev = &tcb;
X}
X
X/*
X * Create template to be used to send tcp packets on a connection.
X * Call after host entry created, allocates an mbuf and fills
X * in a skeletal tcp/ip header, minimizing the amount of work
X * necessary when the connection is used.
X */
Xstruct tcpiphdr *
Xtcp_template(tp)
X struct tcpcb *tp;
X{
X register struct inpcb *inp = tp->t_inpcb;
X register struct mbuf *m;
X register struct tcpiphdr *n;
X
X if ((n = tp->t_template) == 0) {
X m = m_get(M_DONTWAIT, MT_HEADER);
X if (m == NULL)
X return (0);
X m->m_off = MMAXOFF - sizeof (struct tcpiphdr);
X m->m_len = sizeof (struct tcpiphdr);
X n = mtod(m, struct tcpiphdr *);
X }
X n->ti_next = n->ti_prev = 0;
X n->ti_x1 = 0;
X n->ti_pr = IPPROTO_TCP;
X n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
X n->ti_src = inp->inp_laddr;
X n->ti_dst = inp->inp_faddr;
X n->ti_sport = inp->inp_lport;
X n->ti_dport = inp->inp_fport;
X n->ti_seq = 0;
X n->ti_ack = 0;
X n->ti_x2 = 0;
X n->ti_off = 5;
X n->ti_flags = 0;
X n->ti_win = 0;
X n->ti_sum = 0;
X n->ti_urp = 0;
X return (n);
X}
X
X/*
X * Send a single message to the TCP at address specified by
X * the given TCP/IP header. If flags==0, then we make a copy
X * of the tcpiphdr at ti and send directly to the addressed host.
X * This is used to force keep alive messages out using the TCP
X * template for a connection tp->t_template. If flags are given
X * then we send a message back to the TCP which originated the
X * segment ti, and discard the mbuf containing it and any other
X * attached mbufs.
X *
X * In any case the ack and sequence number of the transmitted
X * segment are as specified by the parameters.
X */
Xtcp_respond(tp, ti, ack, seq, flags)
X struct tcpcb *tp;
X register struct tcpiphdr *ti;
X tcp_seq ack, seq;
X int flags;
X{
X register struct mbuf *m;
X int win = 0, tlen;
X struct route *ro = 0;
X
X if (tp) {
X win = sbspace(&tp->t_inpcb->inp_socket->so_rcv);
X ro = &tp->t_inpcb->inp_route;
X }
X if (flags == 0) {
X m = m_get(M_DONTWAIT, MT_HEADER);
X if (m == NULL)
X return;
X#ifdef TCP_COMPAT_42
X tlen = 1;
X#else
X tlen = 0;
X#endif
X m->m_len = sizeof (struct tcpiphdr) + tlen;
X *mtod(m, struct tcpiphdr *) = *ti;
X ti = mtod(m, struct tcpiphdr *);
X flags = TH_ACK;
X } else {
X m = dtom(ti);
X m_freem(m->m_next);
X m->m_next = 0;
X m->m_off = (int)ti - (int)m;
X tlen = 0;
X m->m_len = sizeof (struct tcpiphdr);
X#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
X xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long);
X xchg(ti->ti_dport, ti->ti_sport, u_short);
X#undef xchg
X }
X ti->ti_next = ti->ti_prev = 0;
X ti->ti_x1 = 0;
X ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
X ti->ti_seq = htonl(seq);
X ti->ti_ack = htonl(ack);
X ti->ti_x2 = 0;
X ti->ti_off = sizeof (struct tcphdr) >> 2;
X ti->ti_flags = flags;
X ti->ti_win = htons((u_short)win);
X ti->ti_urp = 0;
X ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + tlen);
X ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + tlen;
X ((struct ip *)ti)->ip_ttl = tcp_ttl;
X (void) ip_output(m, (struct mbuf *)0, ro, 0);
X}
X
X/*
X * Create a new TCP control block, making an
X * empty reassembly queue and hooking it to the argument
X * protocol control block.
X */
Xstruct tcpcb *
Xtcp_newtcpcb(inp)
X struct inpcb *inp;
X{
X struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
X register struct tcpcb *tp;
X
X if (m == NULL)
X return ((struct tcpcb *)0);
X tp = mtod(m, struct tcpcb *);
X tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
X tp->t_maxseg = TCP_MSS;
X tp->t_flags = 0; /* sends options! */
X tp->t_inpcb = inp;
X /*
X * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
X * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
X * reasonable initial retransmit time.
X */
X tp->t_srtt = TCPTV_SRTTBASE;
X tp->t_rttvar = TCPTV_SRTTDFLT << 2;
X TCPT_RANGESET(tp->t_rxtcur,
X ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
X TCPTV_MIN, TCPTV_REXMTMAX);
X tp->snd_cwnd = sbspace(&inp->inp_socket->so_snd);
X tp->snd_ssthresh = 65535; /* XXX */
X inp->inp_ppcb = (caddr_t)tp;
X return (tp);
X}
X
X/*
X * Drop a TCP connection, reporting
X * the specified error. If connection is synchronized,
X * then send a RST to peer.
X */
Xstruct tcpcb *
Xtcp_drop(tp, errno)
X register struct tcpcb *tp;
X int errno;
X{
X struct socket *so = tp->t_inpcb->inp_socket;
X
X if (TCPS_HAVERCVDSYN(tp->t_state)) {
X tp->t_state = TCPS_CLOSED;
X (void) tcp_output(tp);
X tcpstat.tcps_drops++;
X } else
X tcpstat.tcps_conndrops++;
X so->so_error = errno;
X return (tcp_close(tp));
X}
X
X/*
X * Close a TCP control block:
X * discard all space held by the tcp
X * discard internet protocol block
X * wake up any sleepers
X */
Xstruct tcpcb *
Xtcp_close(tp)
X register struct tcpcb *tp;
X{
X register struct tcpiphdr *t;
X struct inpcb *inp = tp->t_inpcb;
X struct socket *so = inp->inp_socket;
X register struct mbuf *m;
X
X t = tp->seg_next;
X while (t != (struct tcpiphdr *)tp) {
X t = (struct tcpiphdr *)t->ti_next;
X m = dtom(t->ti_prev);
X remque(t->ti_prev);
X m_freem(m);
X }
X if (tp->t_template)
X (void) m_free(dtom(tp->t_template));
X (void) m_free(dtom(tp));
X inp->inp_ppcb = 0;
X soisdisconnected(so);
X in_pcbdetach(inp);
X tcpstat.tcps_closed++;
X return ((struct tcpcb *)0);
X}
X
Xtcp_drain()
X{
X
X}
X
X/*
X * Notify a tcp user of an asynchronous error;
X * just wake up so that he can collect error status.
X */
Xtcp_notify(inp)
X register struct inpcb *inp;
X{
X
X wakeup((caddr_t) &inp->inp_socket->so_timeo);
X sorwakeup(inp->inp_socket);
X sowwakeup(inp->inp_socket);
X}
Xtcp_ctlinput(cmd, sa)
X int cmd;
X struct sockaddr *sa;
X{
X extern u_char inetctlerrmap[];
X struct sockaddr_in *sin;
X int tcp_quench(), in_rtchange();
X
X if ((unsigned)cmd > PRC_NCMDS)
X return;
X if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
X return;
X sin = (struct sockaddr_in *)sa;
X if (sin->sin_addr.s_addr == INADDR_ANY)
X return;
X
X switch (cmd) {
X
X case PRC_QUENCH:
X in_pcbnotify(&tcb, &sin->sin_addr, 0, tcp_quench);
X break;
X
X case PRC_ROUTEDEAD:
X case PRC_REDIRECT_NET:
X case PRC_REDIRECT_HOST:
X case PRC_REDIRECT_TOSNET:
X case PRC_REDIRECT_TOSHOST:
X#if BSD>=43
X in_pcbnotify(&tcb, &sin->sin_addr, 0, in_rtchange);
X#endif
X break;
X
X default:
X if (inetctlerrmap[cmd] == 0)
X return; /* XXX */
X in_pcbnotify(&tcb, &sin->sin_addr, (int)inetctlerrmap[cmd],
X tcp_notify);
X }
X}
X
X#if BSD<43
X/* XXX fake routine */
Xtcp_abort(inp)
X struct inpcb *inp;
X{
X return;
X}
X#endif
X
X/*
X * When a source quench is received, close congestion window
X * to one segment. We will gradually open it again as we proceed.
X */
Xtcp_quench(inp)
X struct inpcb *inp;
X{
X struct tcpcb *tp = intotcpcb(inp);
X
X if (tp)
X tp->snd_cwnd = tp->t_maxseg;
X}
END-of-netinet/tcp_subr.c
echo x - netinet/tcp_timer.c
sed 's/^X//' >netinet/tcp_timer.c << 'END-of-netinet/tcp_timer.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)tcp_timer.c 7.11.1.2 (Berkeley) 3/16/88
X */
X
X#include "param.h"
X#include "systm.h"
X#include "mbuf.h"
X#include "socket.h"
X#include "socketvar.h"
X#include "protosw.h"
X#include "errno.h"
X
X#include "../net/if.h"
X#include "../net/route.h"
X
X#include "in.h"
X#include "in_pcb.h"
X#include "in_systm.h"
X#include "ip.h"
X#include "ip_var.h"
X#include "tcp.h"
X#include "tcp_fsm.h"
X#include "tcp_seq.h"
X#include "tcp_timer.h"
X#include "tcp_var.h"
X#include "tcpip.h"
X
Xint tcpnodelack = 0;
Xint tcp_keepidle = TCPTV_KEEP_IDLE;
Xint tcp_keepintvl = TCPTV_KEEPINTVL;
Xint tcp_maxidle;
X/*
X * Fast timeout routine for processing delayed acks
X */
Xtcp_fasttimo()
X{
X register struct inpcb *inp;
X register struct tcpcb *tp;
X int s = splnet();
X
X inp = tcb.inp_next;
X if (inp)
X for (; inp != &tcb; inp = inp->inp_next)
X if ((tp = (struct tcpcb *)inp->inp_ppcb) &&
X (tp->t_flags & TF_DELACK)) {
X tp->t_flags &= ~TF_DELACK;
X tp->t_flags |= TF_ACKNOW;
X tcpstat.tcps_delack++;
X (void) tcp_output(tp);
X }
X splx(s);
X}
X
X/*
X * Tcp protocol timeout routine called every 500 ms.
X * Updates the timers in all active tcb's and
X * causes finite state machine actions if timers expire.
X */
Xtcp_slowtimo()
X{
X register struct inpcb *ip, *ipnxt;
X register struct tcpcb *tp;
X int s = splnet();
X register int i;
X
X tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl;
X /*
X * Search through tcb's and update active timers.
X */
X ip = tcb.inp_next;
X if (ip == 0) {
X splx(s);
X return;
X }
X for (; ip != &tcb; ip = ipnxt) {
X ipnxt = ip->inp_next;
X tp = intotcpcb(ip);
X if (tp == 0)
X continue;
X for (i = 0; i < TCPT_NTIMERS; i++) {
X if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
X (void) tcp_usrreq(tp->t_inpcb->inp_socket,
X PRU_SLOWTIMO, (struct mbuf *)0,
X (struct mbuf *)i, (struct mbuf *)0);
X if (ipnxt->inp_prev != ip)
X goto tpgone;
X }
X }
X tp->t_idle++;
X if (tp->t_rtt)
X tp->t_rtt++;
Xtpgone:
X ;
X }
X tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */
X#ifdef TCP_COMPAT_42
X if ((int)tcp_iss < 0)
X tcp_iss = 0; /* XXX */
X#endif
X splx(s);
X}
X
X/*
X * Cancel all timers for TCP tp.
X */
Xtcp_canceltimers(tp)
X struct tcpcb *tp;
X{
X register int i;
X
X for (i = 0; i < TCPT_NTIMERS; i++)
X tp->t_timer[i] = 0;
X}
X
Xint tcp_backoff[TCP_MAXRXTSHIFT + 1] =
X { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
X
X/*
X * TCP timer processing.
X */
Xstruct tcpcb *
Xtcp_timers(tp, timer)
X register struct tcpcb *tp;
X int timer;
X{
X register int rexmt;
X
X switch (timer) {
X
X /*
X * 2 MSL timeout in shutdown went off. If we're closed but
X * still waiting for peer to close and connection has been idle
X * too long, or if 2MSL time is up from TIME_WAIT, delete connection
X * control block. Otherwise, check again in a bit.
X */
X case TCPT_2MSL:
X if (tp->t_state != TCPS_TIME_WAIT &&
X tp->t_idle <= tcp_maxidle)
X tp->t_timer[TCPT_2MSL] = tcp_keepintvl;
X else
X tp = tcp_close(tp);
X break;
X
X /*
X * Retransmission timer went off. Message has not
X * been acked within retransmit interval. Back off
X * to a longer retransmit interval and retransmit one segment.
X */
X case TCPT_REXMT:
X if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
X tp->t_rxtshift = TCP_MAXRXTSHIFT;
X tcpstat.tcps_timeoutdrop++;
X tp = tcp_drop(tp, ETIMEDOUT);
X break;
X }
X tcpstat.tcps_rexmttimeo++;
X rexmt = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;
X rexmt *= tcp_backoff[tp->t_rxtshift];
X TCPT_RANGESET(tp->t_rxtcur, rexmt, TCPTV_MIN, TCPTV_REXMTMAX);
X tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
X /*
X * If losing, let the lower level know and try for
X * a better route. Also, if we backed off this far,
X * our srtt estimate is probably bogus. Clobber it
X * so we'll take the next rtt measurement as our srtt;
X * move the current srtt into rttvar to keep the current
X * retransmit times until then.
X */
X if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
X#if BSD>=43
X in_losing(tp->t_inpcb);
X#endif
X tp->t_rttvar += (tp->t_srtt >> 2);
X tp->t_srtt = 0;
X }
X tp->snd_nxt = tp->snd_una;
X /*
X * If timing a segment in this window, stop the timer.
X */
X tp->t_rtt = 0;
X /*
X * Close the congestion window down to one segment
X * (we'll open it by one segment for each ack we get).
X * Since we probably have a window's worth of unacked
X * data accumulated, this "slow start" keeps us from
X * dumping all that data as back-to-back packets (which
X * might overwhelm an intermediate gateway).
X *
X * There are two phases to the opening: Initially we
X * open by one mss on each ack. This makes the window
X * size increase exponentially with time. If the
X * window is larger than the path can handle, this
X * exponential growth results in dropped packet(s)
X * almost immediately. To get more time between
X * drops but still "push" the network to take advantage
X * of improving conditions, we switch from exponential
X * to linear window opening at some threshhold size.
X * For a threshhold, we use half the current window
X * size, truncated to a multiple of the mss.
X *
X * (the minimum cwnd that will give us exponential
X * growth is 2 mss. We don't allow the threshhold
X * to go below this.)
X */
X {
X u_int win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
X if (win < 2)
X win = 2;
X tp->snd_cwnd = tp->t_maxseg;
X tp->snd_ssthresh = win * tp->t_maxseg;
X }
X (void) tcp_output(tp);
X break;
X
X /*
X * Persistance timer into zero window.
X * Force a byte to be output, if possible.
X */
X case TCPT_PERSIST:
X tcpstat.tcps_persisttimeo++;
X tcp_setpersist(tp);
X tp->t_force = 1;
X (void) tcp_output(tp);
X tp->t_force = 0;
X break;
X
X /*
X * Keep-alive timer went off; send something
X * or drop connection if idle for too long.
X */
X case TCPT_KEEP:
X tcpstat.tcps_keeptimeo++;
X if (tp->t_state < TCPS_ESTABLISHED)
X goto dropit;
X if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE &&
X tp->t_state <= TCPS_CLOSE_WAIT) {
X if (tp->t_idle >= tcp_keepidle + tcp_maxidle)
X goto dropit;
X /*
X * Send a packet designed to force a response
X * if the peer is up and reachable:
X * either an ACK if the connection is still alive,
X * or an RST if the peer has closed the connection
X * due to timeout or reboot.
X * Using sequence number tp->snd_una-1
X * causes the transmitted zero-length segment
X * to lie outside the receive window;
X * by the protocol spec, this requires the
X * correspondent TCP to respond.
X */
X tcpstat.tcps_keepprobe++;
X#ifdef TCP_COMPAT_42
X /*
X * The keepalive packet must have nonzero length
X * to get a 4.2 host to respond.
X */
X tcp_respond(tp, tp->t_template,
X tp->rcv_nxt - 1, tp->snd_una - 1, 0);
X#else
X tcp_respond(tp, tp->t_template,
X tp->rcv_nxt, tp->snd_una - 1, 0);
X#endif
X tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
X } else
X tp->t_timer[TCPT_KEEP] = tcp_keepidle;
X break;
X dropit:
X tcpstat.tcps_keepdrops++;
X tp = tcp_drop(tp, ETIMEDOUT);
X break;
X }
X return (tp);
X}
END-of-netinet/tcp_timer.c
echo x - netinet/tcp_timer.h
sed 's/^X//' >netinet/tcp_timer.h << 'END-of-netinet/tcp_timer.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)tcp_timer.h 7.5 (Berkeley) 3/16/88
X */
X
X/*
X * Definitions of the TCP timers. These timers are counted
X * down PR_SLOWHZ times a second.
X */
X#define TCPT_NTIMERS 4
X
X#define TCPT_REXMT 0 /* retransmit */
X#define TCPT_PERSIST 1 /* retransmit persistance */
X#define TCPT_KEEP 2 /* keep alive */
X#define TCPT_2MSL 3 /* 2*msl quiet time timer */
X
X/*
X * The TCPT_REXMT timer is used to force retransmissions.
X * The TCP has the TCPT_REXMT timer set whenever segments
X * have been sent for which ACKs are expected but not yet
X * received. If an ACK is received which advances tp->snd_una,
X * then the retransmit timer is cleared (if there are no more
X * outstanding segments) or reset to the base value (if there
X * are more ACKs expected). Whenever the retransmit timer goes off,
X * we retransmit one unacknowledged segment, and do a backoff
X * on the retransmit timer.
X *
X * The TCPT_PERSIST timer is used to keep window size information
X * flowing even if the window goes shut. If all previous transmissions
X * have been acknowledged (so that there are no retransmissions in progress),
X * and the window is too small to bother sending anything, then we start
X * the TCPT_PERSIST timer. When it expires, if the window is nonzero,
X * we go to transmit state. Otherwise, at intervals send a single byte
X * into the peer's window to force him to update our window information.
X * We do this at most as often as TCPT_PERSMIN time intervals,
X * but no more frequently than the current estimate of round-trip
X * packet time. The TCPT_PERSIST timer is cleared whenever we receive
X * a window update from the peer.
X *
X * The TCPT_KEEP timer is used to keep connections alive. If an
X * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time,
X * but not yet established, then we drop the connection. Once the connection
X * is established, if the connection is idle for TCPTV_KEEP_IDLE time
X * (and keepalives have been enabled on the socket), we begin to probe
X * the connection. We force the peer to send us a segment by sending:
X * <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
X * This segment is (deliberately) outside the window, and should elicit
X * an ack segment in response from the peer. If, despite the TCPT_KEEP
X * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE
X * amount of time probing, then we drop the connection.
X */
X
X#define TCP_TTL 30 /* default time to live for TCP segs */
X/*
X * Time constants.
X */
X#define TCPTV_MSL ( 30*PR_SLOWHZ) /* max seg lifetime (hah!) */
X#define TCPTV_SRTTBASE 0 /* base roundtrip time;
X if 0, no idea yet */
X#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */
X
X#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistance */
X#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */
X
X#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */
X#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */
X#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */
X#define TCPTV_KEEPCNT 8 /* max probes before drop */
X
X#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */
X#define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) /* max allowable REXMT value */
X
X#define TCP_LINGERTIME 120 /* linger at most 2 minutes */
X
X#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */
X
X#ifdef TCPTIMERS
Xchar *tcptimers[] =
X { "REXMT", "PERSIST", "KEEP", "2MSL" };
X#endif
X
X/*
X * Force a time value to be in a certain range.
X */
X#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \
X (tv) = (value); \
X if ((tv) < (tvmin)) \
X (tv) = (tvmin); \
X else if ((tv) > (tvmax)) \
X (tv) = (tvmax); \
X}
X
X#ifdef KERNEL
Xextern int tcp_keepidle; /* time before keepalive probes begin */
Xextern int tcp_keepintvl; /* time between keepalive probes */
Xextern int tcp_maxidle; /* time to drop after starting probes */
Xextern int tcp_ttl; /* time to live for TCP segs */
Xextern int tcp_backoff[];
X#endif
END-of-netinet/tcp_timer.h
echo x - netinet/tcp_usrreq.c
sed 's/^X//' >netinet/tcp_usrreq.c << 'END-of-netinet/tcp_usrreq.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)tcp_usrreq.c 7.7.1.2 (Berkeley) 3/16/88
X */
X
X#include "param.h"
X#include "systm.h"
X#include "mbuf.h"
X#include "socket.h"
X#include "socketvar.h"
X#include "protosw.h"
X#include "errno.h"
X#include "stat.h"
X
X#include "../net/if.h"
X#include "../net/route.h"
X
X#include "in.h"
X#include "in_pcb.h"
X#include "in_systm.h"
X#include "ip.h"
X#include "ip_var.h"
X#include "tcp.h"
X#include "tcp_fsm.h"
X#include "tcp_seq.h"
X#include "tcp_timer.h"
X#include "tcp_var.h"
X#include "tcpip.h"
X#include "tcp_debug.h"
X
X/*
X * TCP protocol interface to socket abstraction.
X */
Xextern char *tcpstates[];
Xstruct tcpcb *tcp_newtcpcb();
X
X/*
X * Process a TCP user request for TCP tb. If this is a send request
X * then m is the mbuf chain of send data. If this is a timer expiration
X * (called from the software clock routine), then timertype tells which timer.
X */
X/*ARGSUSED*/
Xtcp_usrreq(so, req, m, nam, rights)
X struct socket *so;
X int req;
X struct mbuf *m, *nam, *rights;
X{
X register struct inpcb *inp;
X register struct tcpcb *tp;
X int s;
X int error = 0;
X int ostate;
X
X#if BSD>=43
X if (req == PRU_CONTROL)
X return (in_control(so, (int)m, (caddr_t)nam,
X (struct ifnet *)rights));
X#else
X if (req == PRU_CONTROL)
X return(EOPNOTSUPP);
X#endif
X if (rights && rights->m_len)
X return (EINVAL);
X
X s = splnet();
X inp = sotoinpcb(so);
X /*
X * When a TCP is attached to a socket, then there will be
X * a (struct inpcb) pointed at by the socket, and this
X * structure will point at a subsidary (struct tcpcb).
X */
X if (inp == 0 && req != PRU_ATTACH) {
X splx(s);
X return (EINVAL); /* XXX */
X }
X if (inp) {
X tp = intotcpcb(inp);
X /* WHAT IF TP IS 0? */
X#ifdef KPROF
X tcp_acounts[tp->t_state][req]++;
X#endif
X ostate = tp->t_state;
X } else
X ostate = 0;
X switch (req) {
X
X /*
X * TCP attaches to socket via PRU_ATTACH, reserving space,
X * and an internet control block.
X */
X case PRU_ATTACH:
X if (inp) {
X error = EISCONN;
X break;
X }
X error = tcp_attach(so);
X if (error)
X break;
X if ((so->so_options & SO_LINGER) && so->so_linger == 0)
X so->so_linger = TCP_LINGERTIME;
X tp = sototcpcb(so);
X break;
X
X /*
X * PRU_DETACH detaches the TCP protocol from the socket.
X * If the protocol state is non-embryonic, then can't
X * do this directly: have to initiate a PRU_DISCONNECT,
X * which may finish later; embryonic TCB's can just
X * be discarded here.
X */
X case PRU_DETACH:
X if (tp->t_state > TCPS_LISTEN)
X tp = tcp_disconnect(tp);
X else
X tp = tcp_close(tp);
X break;
X
X /*
X * Give the socket an address.
X */
X case PRU_BIND:
X error = in_pcbbind(inp, nam);
X if (error)
X break;
X break;
X
X /*
X * Prepare to accept connections.
X */
X case PRU_LISTEN:
X if (inp->inp_lport == 0)
X error = in_pcbbind(inp, (struct mbuf *)0);
X if (error == 0)
X tp->t_state = TCPS_LISTEN;
X break;
X
X /*
X * Initiate connection to peer.
X * Create a template for use in transmissions on this connection.
X * Enter SYN_SENT state, and mark socket as connecting.
X * Start keep-alive timer, and seed output sequence space.
X * Send initial segment on connection.
X */
X case PRU_CONNECT:
X if (inp->inp_lport == 0) {
X error = in_pcbbind(inp, (struct mbuf *)0);
X if (error)
X break;
X }
X error = in_pcbconnect(inp, nam);
X if (error)
X break;
X tp->t_template = tcp_template(tp);
X if (tp->t_template == 0) {
X in_pcbdisconnect(inp);
X error = ENOBUFS;
X break;
X }
X soisconnecting(so);
X tcpstat.tcps_connattempt++;
X tp->t_state = TCPS_SYN_SENT;
X tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
X tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
X tcp_sendseqinit(tp);
X error = tcp_output(tp);
X break;
X
X /*
X * Create a TCP connection between two sockets.
X */
X case PRU_CONNECT2:
X error = EOPNOTSUPP;
X break;
X
X /*
X * Initiate disconnect from peer.
X * If connection never passed embryonic stage, just drop;
X * else if don't need to let data drain, then can just drop anyways,
X * else have to begin TCP shutdown process: mark socket disconnecting,
X * drain unread data, state switch to reflect user close, and
X * send segment (e.g. FIN) to peer. Socket will be really disconnected
X * when peer sends FIN and acks ours.
X *
X * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
X */
X case PRU_DISCONNECT:
X tp = tcp_disconnect(tp);
X break;
X
X /*
X * Accept a connection. Essentially all the work is
X * done at higher levels; just return the address
X * of the peer, storing through addr.
X */
X case PRU_ACCEPT: {
X struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
X
X nam->m_len = sizeof (struct sockaddr_in);
X sin->sin_family = AF_INET;
X sin->sin_port = inp->inp_fport;
X sin->sin_addr = inp->inp_faddr;
X break;
X }
X
X /*
X * Mark the connection as being incapable of further output.
X */
X case PRU_SHUTDOWN:
X socantsendmore(so);
X tp = tcp_usrclosed(tp);
X if (tp)
X error = tcp_output(tp);
X break;
X
X /*
X * After a receive, possibly send window update to peer.
X */
X case PRU_RCVD:
X (void) tcp_output(tp);
X break;
X
X /*
X * Do a send by putting data in output queue and updating urgent
X * marker if URG set. Possibly send more data.
X */
X case PRU_SEND:
X sbappend(&so->so_snd, m);
X error = tcp_output(tp);
X break;
X
X /*
X * Abort the TCP.
X */
X case PRU_ABORT:
X tp = tcp_drop(tp, ECONNABORTED);
X break;
X
X case PRU_SENSE:
X ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
X (void) splx(s);
X return (0);
X
X case PRU_RCVOOB:
X if ((so->so_oobmark == 0 &&
X (so->so_state & SS_RCVATMARK) == 0) ||
X#ifdef SO_OOBINLINE
X so->so_options & SO_OOBINLINE ||
X#endif
X tp->t_oobflags & TCPOOB_HADDATA) {
X error = EINVAL;
X break;
X }
X if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
X error = EWOULDBLOCK;
X break;
X }
X m->m_len = 1;
X *mtod(m, caddr_t) = tp->t_iobc;
X if (((int)nam & MSG_PEEK) == 0)
X tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
X break;
X
X case PRU_SENDOOB:
X if (sbspace(&so->so_snd) < -512) {
X m_freem(m);
X error = ENOBUFS;
X break;
X }
X /*
X * According to RFC961 (Assigned Protocols),
X * the urgent pointer points to the last octet
X * of urgent data. We continue, however,
X * to consider it to indicate the first octet
X * of data past the urgent section.
X * Otherwise, snd_up should be one lower.
X */
X sbappend(&so->so_snd, m);
X tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
X tp->t_force = 1;
X error = tcp_output(tp);
X tp->t_force = 0;
X break;
X
X case PRU_SOCKADDR:
X in_setsockaddr(inp, nam);
X break;
X
X case PRU_PEERADDR:
X in_setpeeraddr(inp, nam);
X break;
X
X /*
X * TCP slow timer went off; going through this
X * routine for tracing's sake.
X */
X case PRU_SLOWTIMO:
X tp = tcp_timers(tp, (int)nam);
X req |= (int)nam << 8; /* for debug's sake */
X break;
X
X default:
X panic("tcp_usrreq");
X }
X if (tp && (so->so_options & SO_DEBUG))
X tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
X splx(s);
X return (error);
X}
X
X#if BSD>=43
Xtcp_ctloutput(op, so, level, optname, mp)
X int op;
X struct socket *so;
X int level, optname;
X struct mbuf **mp;
X{
X int error = 0;
X struct inpcb *inp = sotoinpcb(so);
X register struct tcpcb *tp = intotcpcb(inp);
X register struct mbuf *m;
X
X if (level != IPPROTO_TCP)
X return (ip_ctloutput(op, so, level, optname, mp));
X
X switch (op) {
X
X case PRCO_SETOPT:
X m = *mp;
X switch (optname) {
X
X case TCP_NODELAY:
X if (m == NULL || m->m_len < sizeof (int))
X error = EINVAL;
X else if (*mtod(m, int *))
X tp->t_flags |= TF_NODELAY;
X else
X tp->t_flags &= ~TF_NODELAY;
X break;
X
X case TCP_MAXSEG: /* not yet */
X default:
X error = EINVAL;
X break;
X }
X if (m)
X (void) m_free(m);
X break;
X
X case PRCO_GETOPT:
X *mp = m = m_get(M_WAIT, MT_SOOPTS);
X m->m_len = sizeof(int);
X
X switch (optname) {
X case TCP_NODELAY:
X *mtod(m, int *) = tp->t_flags & TF_NODELAY;
X break;
X case TCP_MAXSEG:
X *mtod(m, int *) = tp->t_maxseg;
X break;
X default:
X error = EINVAL;
X break;
X }
X break;
X }
X return (error);
X}
X#endif
X
Xint tcp_sendspace = 1024*4;
Xint tcp_recvspace = 1024*4;
X/*
X * Attach TCP protocol to socket, allocating
X * internet protocol control block, tcp control block,
X * bufer space, and entering LISTEN state if to accept connections.
X */
Xtcp_attach(so)
X struct socket *so;
X{
X register struct tcpcb *tp;
X struct inpcb *inp;
X int error;
X
X error = soreserve(so, tcp_sendspace, tcp_recvspace);
X if (error)
X return (error);
X error = in_pcballoc(so, &tcb);
X if (error)
X return (error);
X inp = sotoinpcb(so);
X tp = tcp_newtcpcb(inp);
X if (tp == 0) {
X int nofd = so->so_state & SS_NOFDREF; /* XXX */
X
X so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */
X in_pcbdetach(inp);
X so->so_state |= nofd;
X return (ENOBUFS);
X }
X tp->t_state = TCPS_CLOSED;
X return (0);
X}
X
X/*
X * Initiate (or continue) disconnect.
X * If embryonic state, just send reset (once).
X * If in ``let data drain'' option and linger null, just drop.
X * Otherwise (hard), mark socket disconnecting and drop
X * current input data; switch states based on user close, and
X * send segment to peer (with FIN).
X */
Xstruct tcpcb *
Xtcp_disconnect(tp)
X register struct tcpcb *tp;
X{
X struct socket *so = tp->t_inpcb->inp_socket;
X
X if (tp->t_state < TCPS_ESTABLISHED)
X tp = tcp_close(tp);
X else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
X tp = tcp_drop(tp, 0);
X else {
X soisdisconnecting(so);
X sbflush(&so->so_rcv);
X tp = tcp_usrclosed(tp);
X if (tp)
X (void) tcp_output(tp);
X }
X return (tp);
X}
X
X/*
X * User issued close, and wish to trail through shutdown states:
X * if never received SYN, just forget it. If got a SYN from peer,
X * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
X * If already got a FIN from peer, then almost done; go to LAST_ACK
X * state. In all other cases, have already sent FIN to peer (e.g.
X * after PRU_SHUTDOWN), and just have to play tedious game waiting
X * for peer to send FIN or not respond to keep-alives, etc.
X * We can let the user exit from the close as soon as the FIN is acked.
X */
Xstruct tcpcb *
Xtcp_usrclosed(tp)
X register struct tcpcb *tp;
X{
X
X switch (tp->t_state) {
X
X case TCPS_CLOSED:
X case TCPS_LISTEN:
X case TCPS_SYN_SENT:
X tp->t_state = TCPS_CLOSED;
X tp = tcp_close(tp);
X break;
X
X case TCPS_SYN_RECEIVED:
X case TCPS_ESTABLISHED:
X tp->t_state = TCPS_FIN_WAIT_1;
X break;
X
X case TCPS_CLOSE_WAIT:
X tp->t_state = TCPS_LAST_ACK;
X break;
X }
X if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
X soisdisconnected(tp->t_inpcb->inp_socket);
X return (tp);
X}
END-of-netinet/tcp_usrreq.c
echo x - netinet/tcp_var.h
sed 's/^X//' >netinet/tcp_var.h << 'END-of-netinet/tcp_var.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)tcp_var.h 7.7 (Berkeley) 2/27/88
X */
X
X/*
X * TCP configuration: This is a half-assed attempt to make TCP
X * self-configure for a few varieties of 4.2 and 4.3-based unixes.
X * If you don't have a) a 4.3bsd vax or b) a 3.x Sun (x<6), check
X * this carefully (it's probably not right). Please send me mail
X * if you run into configuration problems.
X * - Van Jacobson (van at lbl-csam.arpa)
X */
X
X#ifndef BSD
X#define BSD 42 /* if we're not 4.3, pretend we're 4.2 */
X#define OLDSTAT /* set if we have to use old netstat binaries */
X#endif
X
X/* #define OLDSTAT /* set if we have to use old netstat binaries */
X
X#if sun || BSD < 43
X#define TCP_COMPAT_42 /* set if we have to interop w/4.2 systems */
X#endif
X
X#ifndef SB_MAX
X#ifdef SB_MAXCOUNT
X#define SB_MAX SB_MAXCOUNT /* Sun has to be a little bit different... */
X#else
X#define SB_MAX 32767 /* XXX */
X#endif SB_MAXCOUNT
X#endif SB_MAX
X
X#ifndef IP_MAXPACKET
X#define IP_MAXPACKET 65535 /* maximum packet size */
X#endif
X
X/*
X * Bill Nowicki pointed out that the page size (CLBYTES) has
X * nothing to do with the mbuf cluster size. So, we followed
X * Sun's lead and made the new define MCLBYTES stand for the mbuf
X * cluster size. The following define makes up backwards compatible
X * with 4.3 and 4.2. If CLBYTES is >1024 on your machine, check
X * this against the mbuf cluster definitions in /usr/include/sys/mbuf.h.
X */
X#ifndef MCLBYTES
X#define MCLBYTES CLBYTES /* XXX */
X#endif
X
X/*
X * The routine in_localaddr is broken in Sun's 3.4. We redefine ours
X * (in tcp_input.c) so we use can it but won't have a name conflict.
X */
X#ifdef sun
X#define in_localaddr tcp_in_localaddr
X#endif
X
X/* --------------- end of TCP config ---------------- */
X
X/*
X * Kernel variables for tcp.
X */
X
X/*
X * Tcp control block, one per tcp; fields:
X */
Xstruct tcpcb {
X struct tcpiphdr *seg_next; /* sequencing queue */
X struct tcpiphdr *seg_prev;
X short t_state; /* state of this connection */
X short t_timer[TCPT_NTIMERS]; /* tcp timers */
X short t_rxtshift; /* log(2) of rexmt exp. backoff */
X short t_rxtcur; /* current retransmit value */
X short t_dupacks; /* consecutive dup acks recd */
X u_short t_maxseg; /* maximum segment size */
X char t_force; /* 1 if forcing out a byte */
X u_char t_flags;
X#define TF_ACKNOW 0x01 /* ack peer immediately */
X#define TF_DELACK 0x02 /* ack, but try to delay it */
X#define TF_NODELAY 0x04 /* don't delay packets to coalesce */
X#define TF_NOOPT 0x08 /* don't use tcp options */
X#define TF_SENTFIN 0x10 /* have sent FIN */
X struct tcpiphdr *t_template; /* skeletal packet for transmit */
X struct inpcb *t_inpcb; /* back pointer to internet pcb */
X/*
X * The following fields are used as in the protocol specification.
X * See RFC783, Dec. 1981, page 21.
X */
X/* send sequence variables */
X tcp_seq snd_una; /* send unacknowledged */
X tcp_seq snd_nxt; /* send next */
X tcp_seq snd_up; /* send urgent pointer */
X tcp_seq snd_wl1; /* window update seg seq number */
X tcp_seq snd_wl2; /* window update seg ack number */
X tcp_seq iss; /* initial send sequence number */
X u_short snd_wnd; /* send window */
X/* receive sequence variables */
X u_short rcv_wnd; /* receive window */
X tcp_seq rcv_nxt; /* receive next */
X tcp_seq rcv_up; /* receive urgent pointer */
X tcp_seq irs; /* initial receive sequence number */
X/*
X * Additional variables for this implementation.
X */
X/* receive variables */
X tcp_seq rcv_adv; /* advertised window */
X/* retransmit variables */
X tcp_seq snd_max; /* highest sequence number sent
X * used to recognize retransmits
X */
X/* congestion control (for slow start, source quench, retransmit after loss) */
X u_short snd_cwnd; /* congestion-controlled window */
X u_short snd_ssthresh; /* snd_cwnd size threshhold for
X * for slow start exponential to
X * linear switch */
X/*
X * transmit timing stuff.
X * srtt and rttvar are stored as fixed point; for convenience in smoothing,
X * srtt has 3 bits to the right of the binary point, rttvar has 2.
X * "Variance" is actually smoothed difference.
X */
X short t_idle; /* inactivity time */
X short t_rtt; /* round trip time */
X tcp_seq t_rtseq; /* sequence number being timed */
X short t_srtt; /* smoothed round-trip time */
X short t_rttvar; /* variance in round-trip time */
X u_short max_rcvd; /* most peer has sent into window */
X u_short max_sndwnd; /* largest window peer has offered */
X/* out-of-band data */
X char t_oobflags; /* have some */
X char t_iobc; /* input character */
X#define TCPOOB_HAVEDATA 0x01
X#define TCPOOB_HADDATA 0x02
X};
X
X#define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb)
X#define sototcpcb(so) (intotcpcb(sotoinpcb(so)))
X
X/*
X * TCP statistics.
X * Many of these should be kept per connection,
X * but that's inconvenient at the moment.
X */
Xstruct tcpstat {
X#ifdef OLDSTAT
X /*
X * Declare statistics the same as in 4.3
X * at the start of tcpstat (same size and
X * position) for netstat.
X */
X int tcps_rcvbadsum;
X int tcps_rcvbadoff;
X int tcps_rcvshort;
X int tcps_badsegs;
X int tcps_unack;
X#define tcps_badsum tcps_rcvbadsum
X#define tcps_badoff tcps_rcvbadoff
X#define tcps_hdrops tcps_rcvshort
X
X#endif OLDSTAT
X u_long tcps_connattempt; /* connections initiated */
X u_long tcps_accepts; /* connections accepted */
X u_long tcps_connects; /* connections established */
X u_long tcps_drops; /* connections dropped */
X u_long tcps_conndrops; /* embryonic connections dropped */
X u_long tcps_closed; /* conn. closed (includes drops) */
X u_long tcps_segstimed; /* segs where we tried to get rtt */
X u_long tcps_rttupdated; /* times we succeeded */
X u_long tcps_delack; /* delayed acks sent */
X u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */
X u_long tcps_rexmttimeo; /* retransmit timeouts */
X u_long tcps_persisttimeo; /* persist timeouts */
X u_long tcps_keeptimeo; /* keepalive timeouts */
X u_long tcps_keepprobe; /* keepalive probes sent */
X u_long tcps_keepdrops; /* connections dropped in keepalive */
X
X u_long tcps_sndtotal; /* total packets sent */
X u_long tcps_sndpack; /* data packets sent */
X u_long tcps_sndbyte; /* data bytes sent */
X u_long tcps_sndrexmitpack; /* data packets retransmitted */
X u_long tcps_sndrexmitbyte; /* data bytes retransmitted */
X u_long tcps_sndacks; /* ack-only packets sent */
X u_long tcps_sndprobe; /* window probes sent */
X u_long tcps_sndurg; /* packets sent with URG only */
X u_long tcps_sndwinup; /* window update-only packets sent */
X u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */
X
X u_long tcps_rcvtotal; /* total packets received */
X u_long tcps_rcvpack; /* packets received in sequence */
X u_long tcps_rcvbyte; /* bytes received in sequence */
X#ifndef OLDSTAT
X u_long tcps_rcvbadsum; /* packets received with ccksum errs */
X u_long tcps_rcvbadoff; /* packets received with bad offset */
X u_long tcps_rcvshort; /* packets received too short */
X#endif
X u_long tcps_rcvduppack; /* duplicate-only packets received */
X u_long tcps_rcvdupbyte; /* duplicate-only bytes received */
X u_long tcps_rcvpartduppack; /* packets with some duplicate data */
X u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */
X u_long tcps_rcvoopack; /* out-of-order packets received */
X u_long tcps_rcvoobyte; /* out-of-order bytes received */
X u_long tcps_rcvpackafterwin; /* packets with data after window */
X u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */
X u_long tcps_rcvafterclose; /* packets rcvd after "close" */
X u_long tcps_rcvwinprobe; /* rcvd window probe packets */
X u_long tcps_rcvdupack; /* rcvd duplicate acks */
X u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */
X u_long tcps_rcvackpack; /* rcvd ack packets */
X u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */
X u_long tcps_rcvwinupd; /* rcvd window update packets */
X};
X
X#ifdef KERNEL
Xstruct inpcb tcb; /* head of queue of active tcpcb's */
Xstruct tcpstat tcpstat; /* tcp statistics */
Xstruct tcpiphdr *tcp_template();
Xstruct tcpcb *tcp_close(), *tcp_drop();
Xstruct tcpcb *tcp_timers(), *tcp_disconnect(), *tcp_usrclosed();
X#endif
END-of-netinet/tcp_var.h
echo x - netinet/tcpip.h
sed 's/^X//' >netinet/tcpip.h << 'END-of-netinet/tcpip.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)tcpip.h 7.2 (Berkeley) 12/7/87
X */
X
X/*
X * Tcp+ip header, after ip options removed.
X */
Xstruct tcpiphdr {
X struct ipovly ti_i; /* overlaid ip structure */
X struct tcphdr ti_t; /* tcp header */
X};
X#define ti_next ti_i.ih_next
X#define ti_prev ti_i.ih_prev
X#define ti_x1 ti_i.ih_x1
X#define ti_pr ti_i.ih_pr
X#define ti_len ti_i.ih_len
X#define ti_src ti_i.ih_src
X#define ti_dst ti_i.ih_dst
X#define ti_sport ti_t.th_sport
X#define ti_dport ti_t.th_dport
X#define ti_seq ti_t.th_seq
X#define ti_ack ti_t.th_ack
X#define ti_x2 ti_t.th_x2
X#define ti_off ti_t.th_off
X#define ti_flags ti_t.th_flags
X#define ti_win ti_t.th_win
X#define ti_sum ti_t.th_sum
X#define ti_urp ti_t.th_urp
END-of-netinet/tcpip.h
exit
More information about the Comp.bugs.4bsd.ucb-fixes
mailing list