bostic@OKEEFFE.BERKELEY.EDU (Keith Bostic) (04/05/88)
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@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