🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.bugs.4bsd.ucb-fixes
1 messages
1 total messages Started by Keith Bostic Tue, 05 Apr 1988 03:18
V1.52 ((netns 2 of 2) updated IP/TCP and XNS sources for 4.3BSD)
#55
Author: Keith Bostic
Date: Tue, 05 Apr 1988 03:18
2204 lines
60715 bytes
Subject: (netns 2 of 2) updated IP/TCP and XNS sources for 4.3BSD
Index: sys 4.3BSD

Description:
	This is number 7 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 netns 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:
#
#	netns
#	netns/sp.h
#	netns/spidp.h
#	netns/spp_debug.c
#	netns/spp_debug.h
#	netns/spp_usrreq.c
#	netns/spp_var.h
#
echo c - netns
mkdir netns > /dev/null 2>&1
echo x - netns/sp.h
sed 's/^X//' >netns/sp.h << 'END-of-netns/sp.h'
X/*
X * Copyright (c) 1984, 1985, 1986, 1987 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 *      @(#)sp.h	7.2 (Berkeley) 1/20/88
X */
X
X/*
X * Definitions for Xerox NS style sequenced packet protocol
X */
X
Xstruct sphdr {
X	u_char	sp_cc;		/* connection control */
X	u_char	sp_dt;		/* datastream type */
X#define	SP_SP	0x80		/* system packet */
X#define	SP_SA	0x40		/* send acknowledgement */
X#define	SP_OB	0x20		/* attention (out of band data) */
X#define	SP_EM	0x10		/* end of message */
X	u_short	sp_sid;		/* source connection identifier */
X	u_short	sp_did;		/* destination connection identifier */
X	u_short	sp_seq;		/* sequence number */
X	u_short	sp_ack;		/* acknowledge number */
X	u_short	sp_alo;		/* allocation number */
X};
END-of-netns/sp.h
echo x - netns/spidp.h
sed 's/^X//' >netns/spidp.h << 'END-of-netns/spidp.h'
X/*
X * Copyright (c) 1984, 1985, 1986, 1987 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 *      @(#)spidp.h	7.2 (Berkeley) 1/20/88
X */
X
X/*
X * Definitions for NS(tm) Internet Datagram Protocol
X * containing a Sequenced Packet Protocol packet.
X */
Xstruct spidp {
X	struct idp	si_i;
X	struct sphdr 	si_s;
X};
Xstruct spidp_q {
X	struct spidp_q	*si_next;
X	struct spidp_q	*si_prev;
X};
X#define SI(x)	((struct spidp *)x)
X#define si_sum	si_i.idp_sum
X#define si_len	si_i.idp_len
X#define si_tc	si_i.idp_tc
X#define si_pt	si_i.idp_pt
X#define si_dna	si_i.idp_dna
X#define si_sna	si_i.idp_sna
X#define si_sport	si_i.idp_sna.x_port
X#define si_cc	si_s.sp_cc
X#define si_dt	si_s.sp_dt
X#define si_sid	si_s.sp_sid
X#define si_did	si_s.sp_did
X#define si_seq	si_s.sp_seq
X#define si_ack	si_s.sp_ack
X#define si_alo	si_s.sp_alo
END-of-netns/spidp.h
echo x - netns/spp_debug.c
sed 's/^X//' >netns/spp_debug.c << 'END-of-netns/spp_debug.c'
X/*
X * Copyright (c) 1984, 1985, 1986, 1987 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 *      @(#)spp_debug.c	7.4 (Berkeley) 3/12/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#include "../netinet/tcp_fsm.h"
X
X#include "ns.h"
X#include "ns_pcb.h"
X#include "idp.h"
X#include "idp_var.h"
X#include "sp.h"
X#include "spidp.h"
X#define SPPTIMERS
X#include "spp_timer.h"
X#include "spp_var.h"
X#define	SANAMES
X#include "spp_debug.h"
X
Xint	sppconsdebug = 0;
X/*
X * spp debug routines
X */
Xspp_trace(act, ostate, sp, si, req)
X	short act;
X	u_char ostate;
X	struct sppcb *sp;
X	struct spidp *si;
X	int req;
X{
X#ifdef INET
X	u_short seq, ack, len, alo;
X	unsigned long iptime();
X	int flags;
X	struct spp_debug *sd = &spp_debug[spp_debx++];
X	extern char *prurequests[];
X	extern char *sanames[];
X	extern char *tcpstates[];
X	extern char *spptimers[];
X
X	if (spp_debx == SPP_NDEBUG)
X		spp_debx = 0;
X	sd->sd_time = iptime();
X	sd->sd_act = act;
X	sd->sd_ostate = ostate;
X	sd->sd_cb = (caddr_t)sp;
X	if (sp)
X		sd->sd_sp = *sp;
X	else
X		bzero((caddr_t)&sd->sd_sp, sizeof (*sp));
X	if (si)
X		sd->sd_si = *si;
X	else
X		bzero((caddr_t)&sd->sd_si, sizeof (*si));
X	sd->sd_req = req;
X	if (sppconsdebug == 0)
X		return;
X	if (ostate >= TCP_NSTATES) ostate = 0;
X	if (act >= SA_DROP) act = SA_DROP;
X	if (sp)
X		printf("%x %s:", sp, tcpstates[ostate]);
X	else
X		printf("???????? ");
X	printf("%s ", sanames[act]);
X	switch (act) {
X
X	case SA_RESPOND:
X	case SA_INPUT:
X	case SA_OUTPUT:
X	case SA_DROP:
X		if (si == 0)
X			break;
X		seq = si->si_seq;
X		ack = si->si_ack;
X		alo = si->si_alo;
X		len = si->si_len;
X		if (act == SA_OUTPUT) {
X			seq = ntohs(seq);
X			ack = ntohs(ack);
X			alo = ntohs(alo);
X			len = ntohs(len);
X		}
X#ifndef lint
X#define p1(f)  { printf("%s = %x, ", "f", f); }
X		p1(seq); p1(ack); p1(alo); p1(len);
X#endif
X		flags = si->si_cc;
X		if (flags) {
X			char *cp = "<";
X#ifndef lint
X#define pf(f) { if (flags&SP_/**/f) { printf("%s%s", cp, "f"); cp = ","; } }
X			pf(SP); pf(SA); pf(OB); pf(EM);
X#else
X			cp = cp;
X#endif
X			printf(">");
X		}
X#ifndef lint
X#define p2(f)  { printf("%s = %x, ", "f", si->si_/**/f); }
X		p2(sid);p2(did);p2(dt);p2(pt);
X#endif
X		ns_printhost(&si->si_sna);
X		ns_printhost(&si->si_dna);
X
X		if (act==SA_RESPOND) {
X			printf("idp_len = %x, ",
X				((struct idp *)si)->idp_len);
X		}
X		break;
X
X	case SA_USER:
X		printf("%s", prurequests[req&0xff]);
X		if ((req & 0xff) == PRU_SLOWTIMO)
X			printf("<%s>", spptimers[req>>8]);
X		break;
X	}
X	if (sp)
X		printf(" -> %s", tcpstates[sp->s_state]);
X	/* print out internal state of sp !?! */
X	printf("\n");
X	if (sp == 0)
X		return;
X#ifndef lint
X#define p3(f)  { printf("%s = %x, ", "f", sp->s_/**/f); }
X	printf("\t"); p3(rack);p3(ralo);p3(smax);p3(flags); printf("\n");
X#endif
X#endif
X}
END-of-netns/spp_debug.c
echo x - netns/spp_debug.h
sed 's/^X//' >netns/spp_debug.h << 'END-of-netns/spp_debug.h'
X/*
X * Copyright (c) 1984, 1985, 1986, 1987 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 *      @(#)spp_debug.h	7.2 (Berkeley) 1/20/88
X */
X
Xstruct	spp_debug {
X	u_long	sd_time;
X	short	sd_act;
X	short	sd_ostate;
X	caddr_t	sd_cb;
X	short	sd_req;
X	struct	spidp sd_si;
X	struct	sppcb sd_sp;
X};
X
X#define	SA_INPUT 	0
X#define	SA_OUTPUT	1
X#define	SA_USER		2
X#define	SA_RESPOND	3
X#define	SA_DROP		4
X
X#ifdef SANAMES
Xchar	*sanames[] =
X    { "input", "output", "user", "respond", "drop" };
X#endif
X
X#define	SPP_NDEBUG 100
Xstruct	spp_debug spp_debug[SPP_NDEBUG];
Xint	spp_debx;
END-of-netns/spp_debug.h
echo x - netns/spp_usrreq.c
sed 's/^X//' >netns/spp_usrreq.c << 'END-of-netns/spp_usrreq.c'
X/*
X * Copyright (c) 1984, 1985, 1986, 1987 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 *      @(#)spp_usrreq.c	7.6 (Berkeley) 3/12/88
X */
X
X#include "param.h"
X#include "systm.h"
X#include "dir.h"
X#include "user.h"
X#include "mbuf.h"
X#include "protosw.h"
X#include "socket.h"
X#include "socketvar.h"
X#include "errno.h"
X
X#include "../net/if.h"
X#include "../net/route.h"
X#include "../netinet/tcp_fsm.h"
X
X#include "ns.h"
X#include "ns_pcb.h"
X#include "idp.h"
X#include "idp_var.h"
X#include "ns_error.h"
X#include "sp.h"
X#include "spidp.h"
X#include "spp_timer.h"
X#include "spp_var.h"
X#include "spp_debug.h"
X
X/*
X * SP protocol implementation.
X */
Xspp_init()
X{
X
X	spp_iss = 1; /* WRONG !! should fish it out of TODR */
X}
Xstruct spidp spp_savesi;
Xint traceallspps = 0;
Xextern int sppconsdebug;
Xint spp_hardnosed;
Xint spp_use_delack = 0;
X
X/*ARGSUSED*/
Xspp_input(m, nsp, ifp)
X	register struct mbuf *m;
X	register struct nspcb *nsp;
X	struct ifnet *ifp;
X{
X	register struct sppcb *cb;
X	register struct spidp *si = mtod(m, struct spidp *);
X	register struct socket *so;
X	short ostate;
X	int dropsocket = 0;
X
X
X	sppstat.spps_rcvtotal++;
X	if (nsp == 0) {
X		panic("No nspcb in spp_input\n");
X		return;
X	}
X
X	cb = nstosppcb(nsp);
X	if (cb == 0) goto bad;
X
X	if (m->m_len < sizeof(*si)) {
X		if ((m = m_pullup(m, sizeof(*si))) == 0) {
X			sppstat.spps_rcvshort++;
X			return;
X		}
X		si = mtod(m, struct spidp *);
X	}
X	si->si_seq = ntohs(si->si_seq);
X	si->si_ack = ntohs(si->si_ack);
X	si->si_alo = ntohs(si->si_alo);
X
X	so = nsp->nsp_socket;
X	if (so->so_options & SO_DEBUG || traceallspps) {
X		ostate = cb->s_state;
X		spp_savesi = *si;
X	}
X	if (so->so_options & SO_ACCEPTCONN) {
X		struct sppcb *ocb = cb;
X		struct socket *oso = so;
X		so = sonewconn(so);
X		if (so == 0) {
X			goto drop;
X		}
X		/*
X		 * This is ugly, but ....
X		 *
X		 * Mark socket as temporary until we're
X		 * committed to keeping it.  The code at
X		 * ``drop'' and ``dropwithreset'' check the
X		 * flag dropsocket to see if the temporary
X		 * socket created here should be discarded.
X		 * We mark the socket as discardable until
X		 * we're committed to it below in TCPS_LISTEN.
X		 */
X		dropsocket++;
X		nsp = (struct nspcb *)so->so_pcb;
X		nsp->nsp_laddr = si->si_dna;
X		cb = nstosppcb(nsp);
X		cb->s_mtu = ocb->s_mtu;		/* preserve sockopts */
X		cb->s_flags = ocb->s_flags;	/* preserve sockopts */
X		if (so->so_snd.sb_hiwat != oso->so_snd.sb_hiwat) /*XXX*/
X			sbreserve(&so->so_snd, oso->so_snd.sb_hiwat);
X		if (so->so_rcv.sb_hiwat != oso->so_rcv.sb_hiwat) /*XXX*/
X			sbreserve(&so->so_rcv, oso->so_rcv.sb_hiwat);
X		cb->s_state = TCPS_LISTEN;
X	}
X
X	/*
X	 * Packet received on connection.
X	 * reset idle time and keep-alive timer;
X	 */
X	cb->s_idle = 0;
X	cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
X
X	switch (cb->s_state) {
X
X	case TCPS_LISTEN:{
X		struct mbuf *am;
X		register struct sockaddr_ns *sns;
X		struct ns_addr laddr;
X
X		/*
X		 * If somebody here was carying on a conversation
X		 * and went away, and his pen pal thinks he can
X		 * still talk, we get the misdirected packet.
X		 */
X		if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
X			spp_istat.gonawy++;
X			goto dropwithreset;
X		}
X		am = m_get(M_DONTWAIT, MT_SONAME);
X		if (am == NULL)
X			goto drop;
X		am->m_len = sizeof (struct sockaddr_ns);
X		sns = mtod(am, struct sockaddr_ns *);
X		sns->sns_family = AF_NS;
X		sns->sns_addr = si->si_sna;
X		laddr = nsp->nsp_laddr;
X		if (ns_nullhost(laddr))
X			nsp->nsp_laddr = si->si_dna;
X		if (ns_pcbconnect(nsp, am)) {
X			nsp->nsp_laddr = laddr;
X			(void) m_free(am);
X			spp_istat.noconn++;
X			goto drop;
X		}
X		(void) m_free(am);
X		spp_template(cb);
X		dropsocket = 0;		/* committed to socket */
X		cb->s_did = si->si_sid;
X		cb->s_rack = si->si_ack;
X		cb->s_ralo = si->si_alo;
X#define THREEWAYSHAKE
X#ifdef THREEWAYSHAKE
X		cb->s_state = TCPS_SYN_RECEIVED;
X		cb->s_force = 1 + SPPT_KEEP;
X		sppstat.spps_accepts++;
X		cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
X		}
X		break;
X	/*
X	 * This state means that we have heard a response
X	 * to our acceptance of their connection
X	 * It is probably logically unnecessary in this
X	 * implementation.
X	 */
X	 case TCPS_SYN_RECEIVED: {
X		if (si->si_did!=cb->s_sid) {
X			spp_istat.wrncon++;
X			goto drop;
X		}
X#endif
X		nsp->nsp_fport =  si->si_sport;
X		cb->s_timer[SPPT_REXMT] = 0;
X		cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
X		soisconnected(so);
X		cb->s_state = TCPS_ESTABLISHED;
X		sppstat.spps_accepts++;
X		}
X		break;
X
X	/*
X	 * This state means that we have gotten a response
X	 * to our attempt to establish a connection.
X	 * We fill in the data from the other side,
X	 * telling us which port to respond to, instead of the well-
X	 * known one we might have sent to in the first place.
X	 * We also require that this is a response to our
X	 * connection id.
X	 */
X	case TCPS_SYN_SENT:
X		if (si->si_did!=cb->s_sid) {
X			spp_istat.notme++;
X			goto drop;
X		}
X		sppstat.spps_connects++;
X		cb->s_did = si->si_sid;
X		cb->s_rack = si->si_ack;
X		cb->s_ralo = si->si_alo;
X		cb->s_dport = nsp->nsp_fport =  si->si_sport;
X		cb->s_timer[SPPT_REXMT] = 0;
X		cb->s_flags |= SF_ACKNOW;
X		soisconnected(so);
X		cb->s_state = TCPS_ESTABLISHED;
X		/* Use roundtrip time of connection request for initial rtt */
X		if (cb->s_rtt) {
X			cb->s_srtt = cb->s_rtt << 3;
X			cb->s_rttvar = cb->s_rtt << 1;
X			SPPT_RANGESET(cb->s_rxtcur,
X			    ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
X			    SPPTV_MIN, SPPTV_REXMTMAX);
X			    cb->s_rtt = 0;
X		}
X	}
X	if (so->so_options & SO_DEBUG || traceallspps)
X		spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0);
X
X	m->m_len -= sizeof (struct idp);
X	m->m_off += sizeof (struct idp);
X
X	if (spp_reass(cb, si)) {
X		(void) m_freem(m);
X	}
X	if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT)))
X		(void) spp_output(cb, (struct mbuf *)0);
X	cb->s_flags &= ~(SF_WIN|SF_RXT);
X	return;
X
Xdropwithreset:
X	if (dropsocket)
X		(void) soabort(so);
X	si->si_seq = ntohs(si->si_seq);
X	si->si_ack = ntohs(si->si_ack);
X	si->si_alo = ntohs(si->si_alo);
X	ns_error(dtom(si), NS_ERR_NOSOCK, 0);
X	if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)
X		spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
X	return;
X
Xdrop:
Xbad:
X	if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG ||
X            traceallspps)
X		spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
X	m_freem(m);
X}
X
Xint spprexmtthresh = 3;
X
X/*
X * This is structurally similar to the tcp reassembly routine
X * but its function is somewhat different:  It merely queues
X * packets up, and suppresses duplicates.
X */
Xspp_reass(cb, si)
Xregister struct sppcb *cb;
Xregister struct spidp *si;
X{
X	register struct spidp_q *q;
X	register struct mbuf *m;
X	register struct socket *so = cb->s_nspcb->nsp_socket;
X	char packetp = cb->s_flags & SF_HI;
X	int incr;
X	char wakeup = 0;
X
X	if (si == SI(0))
X		goto present;
X	/*
X	 * Update our news from them.
X	 */
X	if (si->si_cc & SP_SA)
X		cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_ACKNOW);
X	if (SSEQ_GT(si->si_alo, cb->s_ralo))
X		cb->s_flags |= SF_WIN;
X	if (SSEQ_LEQ(si->si_ack, cb->s_rack)) {
X		if ((si->si_cc & SP_SP) && cb->s_rack != (cb->s_smax + 1)) {
X			sppstat.spps_rcvdupack++;
X			/*
X			 * If this is a completely duplicate ack
X			 * and other conditions hold, we assume
X			 * a packet has been dropped and retransmit
X			 * it exactly as in tcp_input().
X			 */
X			if (si->si_ack != cb->s_rack ||
X			    si->si_alo != cb->s_ralo)
X				cb->s_dupacks = 0;
X			else if (++cb->s_dupacks == spprexmtthresh) {
X				u_short onxt = cb->s_snxt;
X				int cwnd = cb->s_cwnd;
X
X				cb->s_snxt = si->si_ack;
X				cb->s_cwnd = CUNIT;
X				cb->s_force = 1 + SPPT_REXMT;
X				(void) spp_output(cb, (struct mbuf *)0);
X				cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
X				cb->s_rtt = 0;
X				if (cwnd >= 4 * CUNIT)
X					cb->s_cwnd = cwnd / 2;
X				if (SSEQ_GT(onxt, cb->s_snxt))
X					cb->s_snxt = onxt;
X				return (1);
X			}
X		} else
X			cb->s_dupacks = 0;
X		goto update_window;
X	}
X	cb->s_dupacks = 0;
X	/*
X	 * If our correspondent acknowledges data we haven't sent
X	 * TCP would drop the packet after acking.  We'll be a little
X	 * more permissive
X	 */
X	if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) {
X		sppstat.spps_rcvacktoomuch++;
X		si->si_ack = cb->s_smax + 1;
X	}
X	sppstat.spps_rcvackpack++;
X	/*
X	 * If transmit timer is running and timed sequence
X	 * number was acked, update smoothed round trip time.
X	 * See discussion of algorithm in tcp_input.c
X	 */
X	if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
X		sppstat.spps_rttupdated++;
X		if (cb->s_srtt != 0) {
X			register short delta;
X			delta = cb->s_rtt - (cb->s_srtt >> 3);
X			if ((cb->s_srtt += delta) <= 0)
X				cb->s_srtt = 1;
X			if (delta < 0)
X				delta = -delta;
X			delta -= (cb->s_rttvar >> 2);
X			if ((cb->s_rttvar += delta) <= 0)
X				cb->s_rttvar = 1;
X		} else {
X			/*
X			 * No rtt measurement yet
X			 */
X			cb->s_srtt = cb->s_rtt << 3;
X			cb->s_rttvar = cb->s_rtt << 1;
X		}
X		cb->s_rtt = 0;
X		cb->s_rxtshift = 0;
X		SPPT_RANGESET(cb->s_rxtcur,
X			((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
X			SPPTV_MIN, SPPTV_REXMTMAX);
X	}
X	/*
X	 * If all outstanding data is acked, stop retransmit
X	 * timer and remember to restart (more output or persist).
X	 * If there is more data to be acked, restart retransmit
X	 * timer, using current (possibly backed-off) value;
X	 */
X	if (si->si_ack == cb->s_smax + 1) {
X		cb->s_timer[SPPT_REXMT] = 0;
X		cb->s_flags |= SF_RXT;
X	} else if (cb->s_timer[SPPT_PERSIST] == 0)
X		cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
X	/*
X	 * When new data is acked, open the congestion window.
X	 * If the window gives us less than ssthresh packets
X	 * in flight, open exponentially (maxseg at a time).
X	 * Otherwise open linearly (maxseg^2 / cwnd at a time).
X	 */
X	incr = CUNIT;
X	if (cb->s_cwnd > cb->s_ssthresh)
X		incr = MAX(incr * incr / cb->s_cwnd, 1);
X	cb->s_cwnd = MIN(cb->s_cwnd + incr, cb->s_cwmx);
X	/*
X	 * Trim Acked data from output queue.
X	 */
X	while ((m = so->so_snd.sb_mb) != NULL) {
X		if (SSEQ_LT((mtod(m, struct spidp *))->si_seq, si->si_ack))
X			sbdroprecord(&so->so_snd);
X		else
X			break;
X	}
X	if ((so->so_snd.sb_flags & SB_WAIT) || so->so_snd.sb_sel)
X		 sowwakeup(so);
X	cb->s_rack = si->si_ack;
Xupdate_window:
X	if (SSEQ_LT(cb->s_snxt, cb->s_rack))
X		cb->s_snxt = cb->s_rack;
X	if (SSEQ_LT(cb->s_swl1, si->si_seq) || cb->s_swl1 == si->si_seq &&
X	    (SSEQ_LT(cb->s_swl2, si->si_ack) ||
X	     cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))) {
X		/* keep track of pure window updates */
X		if ((si->si_cc & SP_SP) && cb->s_swl2 == si->si_ack
X		    && SSEQ_LT(cb->s_ralo, si->si_alo)) {
X			sppstat.spps_rcvwinupd++;
X			sppstat.spps_rcvdupack--;
X		}
X		cb->s_ralo = si->si_alo;
X		cb->s_swl1 = si->si_seq;
X		cb->s_swl2 = si->si_ack;
X		cb->s_swnd = (1 + si->si_alo - si->si_ack);
X		if (cb->s_swnd > cb->s_smxw)
X			cb->s_smxw = cb->s_swnd;
X		cb->s_flags |= SF_WIN;
X	}
X	/*
X	 * If this packet number is higher than that which
X	 * we have allocated refuse it, unless urgent
X	 */
X	if (SSEQ_GT(si->si_seq, cb->s_alo)) {
X		if (si->si_cc & SP_SP) {
X			sppstat.spps_rcvwinprobe++;
X			return (1);
X		} else
X			sppstat.spps_rcvpackafterwin++;
X		if (si->si_cc & SP_OB) {
X			if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) {
X				ns_error(dtom(si), NS_ERR_FULLUP, 0);
X				return (0);
X			} /* else queue this packet; */
X		} else {
X			/*register struct socket *so = cb->s_nspcb->nsp_socket;
X			if (so->so_state && SS_NOFDREF) {
X				ns_error(dtom(si), NS_ERR_NOSOCK, 0);
X				(void)spp_close(cb);
X			} else
X				       would crash system*/
X			spp_istat.notyet++;
X			ns_error(dtom(si), NS_ERR_FULLUP, 0);
X			return (0);
X		}
X	}
X	/*
X	 * If this is a system packet, we don't need to
X	 * queue it up, and won't update acknowledge #
X	 */
X	if (si->si_cc & SP_SP) {
X		return (1);
X	}
X	/*
X	 * We have already seen this packet, so drop.
X	 */
X	if (SSEQ_LT(si->si_seq, cb->s_ack)) {
X		spp_istat.bdreas++;
X		sppstat.spps_rcvduppack++;
X		if (si->si_seq == cb->s_ack - 1)
X			spp_istat.lstdup++;
X		return (1);
X	}
X	/*
X	 * Loop through all packets queued up to insert in
X	 * appropriate sequence.
X	 */
X	for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
X		if (si->si_seq == SI(q)->si_seq) {
X			sppstat.spps_rcvduppack++;
X			return (1);
X		}
X		if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) {
X			sppstat.spps_rcvoopack++;
X			break;
X		}
X	}
X	insque(si, q->si_prev);
X	/*
X	 * If this packet is urgent, inform process
X	 */
X	if (si->si_cc & SP_OB) {
X		cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
X		sohasoutofband(so);
X		cb->s_oobflags |= SF_IOOB;
X	}
Xpresent:
X#define SPINC sizeof(struct sphdr)
X	/*
X	 * Loop through all packets queued up to update acknowledge
X	 * number, and present all acknowledged data to user;
X	 * If in packet interface mode, show packet headers.
X	 */
X	for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
X		  if (SI(q)->si_seq == cb->s_ack) {
X			cb->s_ack++;
X			m = dtom(q);
X			if (SI(q)->si_cc & SP_OB) {
X				cb->s_oobflags &= ~SF_IOOB;
X				if (so->so_rcv.sb_cc)
X					so->so_oobmark = so->so_rcv.sb_cc;
X				else
X					so->so_state |= SS_RCVATMARK;
X			}
X			q = q->si_prev;
X			remque(q->si_next);
X			wakeup = 1;
X			sppstat.spps_rcvpack++;
X			if (packetp) {
X				sbappendrecord(&so->so_rcv, m);
X			} else {
X				cb->s_rhdr = *mtod(m, struct sphdr *);
X				m->m_off += SPINC;
X				m->m_len -= SPINC;
X				sbappend(&so->so_rcv, m);
X			}
X		  } else
X			break;
X	}
X	if (wakeup) sorwakeup(so);
X	return (0);
X}
X
Xspp_ctlinput(cmd, arg)
X	int cmd;
X	caddr_t arg;
X{
X	struct ns_addr *na;
X	extern u_char nsctlerrmap[];
X	extern spp_abort(), spp_quench();
X	extern struct nspcb *idp_drop();
X	struct ns_errp *errp;
X	struct nspcb *nsp;
X	struct sockaddr_ns *sns;
X	int type;
X
X	if (cmd < 0 || cmd > PRC_NCMDS)
X		return;
X	type = NS_ERR_UNREACH_HOST;
X
X	switch (cmd) {
X
X	case PRC_ROUTEDEAD:
X		return;
X
X	case PRC_IFDOWN:
X	case PRC_HOSTDEAD:
X	case PRC_HOSTUNREACH:
X		sns = (struct sockaddr_ns *)arg;
X		if (sns->sns_family != AF_NS)
X			return;
X		na = &sns->sns_addr;
X		break;
X
X	default:
X		errp = (struct ns_errp *)arg;
X		na = &errp->ns_err_idp.idp_dna;
X		type = errp->ns_err_num;
X		type = ntohs((u_short)type);
X	}
X	switch (type) {
X
X	case NS_ERR_UNREACH_HOST:
X		ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0);
X		break;
X
X	case NS_ERR_TOO_BIG:
X	case NS_ERR_NOSOCK:
X		nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port,
X			NS_WILDCARD);
X		if (nsp) {
X			if(nsp->nsp_pcb)
X				(void) spp_drop((struct sppcb *)nsp->nsp_pcb,
X						(int)nsctlerrmap[cmd]);
X			else
X				(void) idp_drop(nsp, (int)nsctlerrmap[cmd]);
X		}
X		break;
X
X	case NS_ERR_FULLUP:
X		ns_pcbnotify(na, 0, spp_quench, (long) 0);
X	}
X}
X/*
X * When a source quench is received, close congestion window
X * to one packet.  We will gradually open it again as we proceed.
X */
Xspp_quench(nsp)
X	struct nspcb *nsp;
X{
X	struct sppcb *cb = nstosppcb(nsp);
X
X	if (cb)
X		cb->s_cwnd = CUNIT;
X}
X
X#ifdef notdef
Xint
Xspp_fixmtu(nsp)
Xregister struct nspcb *nsp;
X{
X	register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb);
X	register struct mbuf *m;
X	register struct spidp *si;
X	struct ns_errp *ep;
X	struct sockbuf *sb;
X	int badseq, len;
X	struct mbuf *firstbad, *m0;
X
X	if (cb) {
X		/* 
X		 * The notification that we have sent
X		 * too much is bad news -- we will
X		 * have to go through queued up so far
X		 * splitting ones which are too big and
X		 * reassigning sequence numbers and checksums.
X		 * we should then retransmit all packets from
X		 * one above the offending packet to the last one
X		 * we had sent (or our allocation)
X		 * then the offending one so that the any queued
X		 * data at our destination will be discarded.
X		 */
X		 ep = (struct ns_errp *)nsp->nsp_notify_param;
X		 sb = &nsp->nsp_socket->so_snd;
X		 cb->s_mtu = ep->ns_err_param;
X		 badseq = SI(&ep->ns_err_idp)->si_seq;
X		 for (m = sb->sb_mb; m; m = m->m_act) {
X			si = mtod(m, struct spidp *);
X			if (si->si_seq == badseq)
X				break;
X		 }
X		 if (m == 0) return;
X		 firstbad = m;
X		 /*for (;;) {*/
X			/* calculate length */
X			for (m0 = m, len = 0; m ; m = m->m_next)
X				len += m->m_len;
X			if (len > cb->s_mtu) {
X			}
X		/* FINISH THIS
X		} */
X	}
X}
X#endif
X
Xspp_output(cb, m0)
X	register struct sppcb *cb;
X	struct mbuf *m0;
X{
X	struct socket *so = cb->s_nspcb->nsp_socket;
X	register struct mbuf *m;
X	register struct spidp *si = (struct spidp *) 0;
X	register struct sockbuf *sb = &so->so_snd;
X	int len = 0, win, rcv_win;
X	short span, off;
X	u_short alo;
X	int error = 0, idle, sendalot;
X	struct mbuf *mprev;
X	extern int idpcksum;
X
X	if (m0) {
X		int mtu = cb->s_mtu;
X		int datalen;
X		/*
X		 * Make sure that packet isn't too big.
X		 */
X		for (m = m0; m ; m = m->m_next) {
X			mprev = m;
X			len += m->m_len;
X		}
X		datalen = (cb->s_flags & SF_HO) ?
X				len - sizeof (struct sphdr) : len;
X		if (datalen > mtu) {
X			if (cb->s_flags & SF_PI) {
X				m_freem(m0);
X				return (EMSGSIZE);
X			} else {
X				int oldEM = cb->s_cc & SP_EM;
X
X				cb->s_cc &= ~SP_EM;
X				while (len > mtu) {
X					m = m_copy(m0, 0, mtu);
X					if (m == NULL) {
X						error = ENOBUFS;
X						goto bad_copy;
X					}
X					error = spp_output(cb, m);
X					if (error) {
X					bad_copy:
X						cb->s_cc |= oldEM;
X						m_freem(m0);
X						return(error);
X					}
X					m_adj(m0, mtu);
X					len -= mtu;
X				}
X				cb->s_cc |= oldEM;
X			}
X		}
X		/*
X		 * Force length even, by adding a "garbage byte" if
X		 * necessary.
X		 */
X		if (len & 1) {
X			m = mprev;
X			if (m->m_len + m->m_off < MMAXOFF)
X				m->m_len++;
X			else {
X				struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
X
X				if (m1 == 0) {
X					m_freem(m0);
X					return (ENOBUFS);
X				}
X				m1->m_len = 1;
X				m1->m_off = MMAXOFF - 1;
X				m->m_next = m1;
X			}
X		}
X		m = m_get(M_DONTWAIT, MT_HEADER);
X		if (m == 0) {
X			m_freem(m0);
X			return (ENOBUFS);
X		}
X		/*
X		 * Fill in mbuf with extended SP header
X		 * and addresses and length put into network format.
X		 * Long align so prepended ip headers will work on Gould.
X		 */
X		m->m_off = MMAXOFF - sizeof (struct spidp) - 2;
X		m->m_len = sizeof (struct spidp);
X		m->m_next = m0;
X		si = mtod(m, struct spidp *);
X		si->si_i = *cb->s_idp;
X		si->si_s = cb->s_shdr;
X		if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
X			register struct sphdr *sh;
X			if (m0->m_len < sizeof (*sh)) {
X				if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
X					(void) m_free(m);
X					m_freem(m0);
X					return (EINVAL);
X				}
X				m->m_next = m0;
X			}
X			sh = mtod(m0, struct sphdr *);
X			si->si_dt = sh->sp_dt;
X			si->si_cc |= sh->sp_cc & SP_EM;
X			m0->m_len -= sizeof (*sh);
X			m0->m_off += sizeof (*sh);
X			len -= sizeof (*sh);
X		}
X		len += sizeof(*si);
X		if (cb->s_oobflags & SF_SOOB) {
X			/*
X			 * Per jqj@cornell:
X			 * make sure OB packets convey exactly 1 byte.
X			 * If the packet is 1 byte or larger, we
X			 * have already guaranted there to be at least
X			 * one garbage byte for the checksum, and
X			 * extra bytes shouldn't hurt!
X			 */
X			if (len > sizeof(*si)) {
X				si->si_cc |= SP_OB;
X				len = (1 + sizeof(*si));
X			}
X		}
X		si->si_len = htons((u_short)len);
X		/*
X		 * queue stuff up for output
X		 */
X		sbappendrecord(sb, m);
X		cb->s_seq++;
X	}
X	idle = (cb->s_smax == (cb->s_rack - 1));
Xagain:
X	sendalot = 0;
X	off = cb->s_snxt - cb->s_rack;
X	win = MIN(cb->s_swnd, (cb->s_cwnd/CUNIT));
X
X	/*
X	 * If in persist timeout with window of 0, send a probe.
X	 * Otherwise, if window is small but nonzero
X	 * and timer expired, send what we can and go into
X	 * transmit state.
X	 */
X	if (cb->s_force == 1 + SPPT_PERSIST) {
X		if (win != 0) {
X			cb->s_timer[SPPT_PERSIST] = 0;
X			cb->s_rxtshift = 0;
X		}
X	}
X	span = cb->s_seq - cb->s_rack;
X	len = MIN(span, win) - off;
X
X	if (len < 0) {
X		/*
X		 * Window shrank after we went into it.
X		 * If window shrank to 0, cancel pending
X		 * restransmission and pull s_snxt back
X		 * to (closed) window.  We will enter persist
X		 * state below.  If the widndow didn't close completely,
X		 * just wait for an ACK.
X		 */
X		len = 0;
X		if (win == 0) {
X			cb->s_timer[SPPT_REXMT] = 0;
X			cb->s_snxt = cb->s_rack;
X		}
X	}
X	if (len > 1)
X		sendalot = 1;
X	rcv_win = sbspace(&so->so_rcv);
X
X	/*
X	 * Send if we owe peer an ACK.
X	 */
X	if (cb->s_oobflags & SF_SOOB) {
X		/*
X		 * must transmit this out of band packet
X		 */
X		cb->s_oobflags &= ~ SF_SOOB;
X		sendalot = 1;
X		sppstat.spps_sndurg++;
X		goto found;
X	}
X	if (cb->s_flags & SF_ACKNOW)
X		goto send;
X	if (cb->s_state < TCPS_ESTABLISHED)
X		goto send;
X	/*
X	 * Silly window can't happen in spp.
X	 * Code from tcp deleted.
X	 */
X	if (len)
X		goto send;
X	/*
X	 * Compare available window to amount of window
X	 * known to peer (as advertised window less
X	 * next expected input.)  If the difference is at least two
X	 * packets or at least 35% of the mximum possible window,
X	 * then want to send a window update to peer.
X	 */
X	if (rcv_win > 0) {
X		u_short delta =  1 + cb->s_alo - cb->s_ack;
X		int adv = rcv_win - (delta * cb->s_mtu);
X		
X		if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) ||
X		    (100 * adv / so->so_rcv.sb_hiwat >= 35)) {
X			sppstat.spps_sndwinup++;
X			cb->s_flags |= SF_ACKNOW;
X			goto send;
X		}
X
X	}
X	/*
X	 * Many comments from tcp_output.c are appropriate here
X	 * including . . .
X	 * If send window is too small, there is data to transmit, and no
X	 * retransmit or persist is pending, then go to persist state.
X	 * If nothing happens soon, send when timer expires:
X	 * if window is nonzero, transmit what we can,
X	 * otherwise send a probe.
X	 */
X	if (so->so_snd.sb_cc && cb->s_timer[SPPT_REXMT] == 0 &&
X		cb->s_timer[SPPT_PERSIST] == 0) {
X			cb->s_rxtshift = 0;
X			spp_setpersist(cb);
X	}
X	/*
X	 * No reason to send a packet, just return.
X	 */
X	cb->s_outx = 1;
X	return (0);
X
Xsend:
X	/*
X	 * Find requested packet.
X	 */
X	si = 0;
X	if (len > 0) {
X		cb->s_want = cb->s_snxt;
X		for (m = sb->sb_mb; m; m = m->m_act) {
X			si = mtod(m, struct spidp *);
X			if (SSEQ_LEQ(cb->s_snxt, si->si_seq))
X				break;
X		}
X	found:
X		if (si) {
X			if (si->si_seq == cb->s_snxt)
X					cb->s_snxt++;
X				else
X					sppstat.spps_sndvoid++, si = 0;
X		}
X	}
X	/*
X	 * update window
X	 */
X	if (rcv_win < 0)
X		rcv_win = 0;
X	alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu));
X	if (SSEQ_LT(alo, cb->s_alo)) 
X		alo = cb->s_alo;
X
X	if (si) {
X		/*
X		 * must make a copy of this packet for
X		 * idp_output to monkey with
X		 */
X		m = m_copy(dtom(si), 0, (int)M_COPYALL);
X		if (m == NULL) {
X			return (ENOBUFS);
X		}
X		m0 = m;
X		si = mtod(m, struct spidp *);
X		if (SSEQ_LT(si->si_seq, cb->s_smax))
X			sppstat.spps_sndrexmitpack++;
X		else
X			sppstat.spps_sndpack++;
X	} else if (cb->s_force || cb->s_flags & SF_ACKNOW) {
X		/*
X		 * Must send an acknowledgement or a probe
X		 */
X		if (cb->s_force)
X			sppstat.spps_sndprobe++;
X		if (cb->s_flags & SF_ACKNOW)
X			sppstat.spps_sndacks++;
X		m = m_get(M_DONTWAIT, MT_HEADER);
X		if (m == 0) {
X			return (ENOBUFS);
X		}
X		/*
X		 * Fill in mbuf with extended SP header
X		 * and addresses and length put into network format.
X		 * Allign beginning of packet to long to prepend
X		 * ifp's on loopback, or NSIP encaspulation for fussy cpu's.
X		 */
X		m->m_off = MMAXOFF - sizeof (struct spidp) - 2;
X		m->m_len = sizeof (*si);
X		m->m_next = 0;
X		si = mtod(m, struct spidp *);
X		si->si_i = *cb->s_idp;
X		si->si_s = cb->s_shdr;
X		si->si_seq = cb->s_smax + 1;
X		si->si_len = htons(sizeof (*si));
X		si->si_cc |= SP_SP;
X	} else {
X		cb->s_outx = 3;
X		if (so->so_options & SO_DEBUG || traceallspps)
X			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
X		return (0);
X	}
X	/*
X	 * Stuff checksum and output datagram.
X	 */
X	if ((si->si_cc & SP_SP) == 0) {
X		if (cb->s_force != (1 + SPPT_PERSIST) ||
X		    cb->s_timer[SPPT_PERSIST] == 0) {
X			/*
X			 * If this is a new packet and we are not currently 
X			 * timing anything, time this one.
X			 */
X			if (SSEQ_LT(cb->s_smax, si->si_seq)) {
X				cb->s_smax = si->si_seq;
X				if (cb->s_rtt == 0) {
X					sppstat.spps_segstimed++;
X					cb->s_rtseq = si->si_seq;
X					cb->s_rtt = 1;
X				}
X			}
X			/*
X			 * Set rexmt timer if not currently set,
X			 * Initial value for retransmit timer is smoothed
X			 * round-trip time + 2 * round-trip time variance.
X			 * Initialize shift counter which is used for backoff
X			 * of retransmit time.
X			 */
X			if (cb->s_timer[SPPT_REXMT] == 0 &&
X			    cb->s_snxt != cb->s_rack) {
X				cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
X				if (cb->s_timer[SPPT_PERSIST]) {
X					cb->s_timer[SPPT_PERSIST] = 0;
X					cb->s_rxtshift = 0;
X				}
X			}
X		} else if (SSEQ_LT(cb->s_smax, si->si_seq)) {
X			cb->s_smax = si->si_seq;
X		}
X	} else if (cb->s_state < TCPS_ESTABLISHED) {
X		if (cb->s_rtt == 0)
X			cb->s_rtt = 1; /* Time initial handshake */
X		if (cb->s_timer[SPPT_REXMT] == 0)
X			cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
X	}
X	{
X		/*
X		 * Do not request acks when we ack their data packets or
X		 * when we do a gratuitous window update.
X		 */
X		if (((si->si_cc & SP_SP) == 0) || cb->s_force)
X				si->si_cc |= SP_SA;
X		si->si_seq = htons(si->si_seq);
X		si->si_alo = htons(alo);
X		si->si_ack = htons(cb->s_ack);
X
X		if (idpcksum) {
X			si->si_sum = 0;
X			len = ntohs(si->si_len);
X			if (len & 1)
X				len++;
X			si->si_sum = ns_cksum(dtom(si), len);
X		} else
X			si->si_sum = 0xffff;
X
X		cb->s_outx = 4;
X		if (so->so_options & SO_DEBUG || traceallspps)
X			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
X
X		if (so->so_options & SO_DONTROUTE)
X			error = ns_output(m, (struct route *)0, NS_ROUTETOIF);
X		else
X			error = ns_output(m, &cb->s_nspcb->nsp_route, 0);
X	}
X	if (error) {
X		return (error);
X	}
X	sppstat.spps_sndtotal++;
X	/*
X	 * Data sent (as far as we can tell).
X	 * If this advertises a larger window than any other segment,
X	 * then remember the size of the advertized window.
X	 * Any pending ACK has now been sent.
X	 */
X	cb->s_force = 0;
X	cb->s_flags &= ~(SF_ACKNOW|SF_DELACK);
X	if (SSEQ_GT(alo, cb->s_alo))
X		cb->s_alo = alo;
X	if (sendalot)
X		goto again;
X	cb->s_outx = 5;
X	return (0);
X}
X
Xint spp_do_persist_panics = 0;
X
Xspp_setpersist(cb)
X	register struct sppcb *cb;
X{
X	register t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
X	extern int spp_backoff[];
X
X	if (cb->s_timer[SPPT_REXMT] && spp_do_persist_panics)
X		panic("spp_output REXMT");
X	/*
X	 * Start/restart persistance timer.
X	 */
X	SPPT_RANGESET(cb->s_timer[SPPT_PERSIST],
X	    t*spp_backoff[cb->s_rxtshift],
X	    SPPTV_PERSMIN, SPPTV_PERSMAX);
X	if (cb->s_rxtshift < SPP_MAXRXTSHIFT)
X		cb->s_rxtshift++;
X}
X/*ARGSUSED*/
Xspp_ctloutput(req, so, level, name, value)
X	int req;
X	struct socket *so;
X	int name;
X	struct mbuf **value;
X{
X	register struct mbuf *m;
X	struct nspcb *nsp = sotonspcb(so);
X	register struct sppcb *cb;
X	int mask, error = 0;
X
X	if (level != NSPROTO_SPP) {
X		/* This will have to be changed when we do more general
X		   stacking of protocols */
X		return (idp_ctloutput(req, so, level, name, value));
X	}
X	if (nsp == NULL) {
X		error = EINVAL;
X		goto release;
X	} else
X		cb = nstosppcb(nsp);
X
X	switch (req) {
X
X	case PRCO_GETOPT:
X		if (value == NULL)
X			return (EINVAL);
X		m = m_get(M_DONTWAIT, MT_DATA);
X		if (m == NULL)
X			return (ENOBUFS);
X		switch (name) {
X
X		case SO_HEADERS_ON_INPUT:
X			mask = SF_HI;
X			goto get_flags;
X
X		case SO_HEADERS_ON_OUTPUT:
X			mask = SF_HO;
X		get_flags:
X			m->m_len = sizeof(short);
X			m->m_off = MMAXOFF - sizeof(short);
X			*mtod(m, short *) = cb->s_flags & mask;
X			break;
X
X		case SO_MTU:
X			m->m_len = sizeof(u_short);
X			m->m_off = MMAXOFF - sizeof(short);
X			*mtod(m, short *) = cb->s_mtu;
X			break;
X
X		case SO_LAST_HEADER:
X			m->m_len = sizeof(struct sphdr);
X			m->m_off = MMAXOFF - sizeof(struct sphdr);
X			*mtod(m, struct sphdr *) = cb->s_rhdr;
X			break;
X
X		case SO_DEFAULT_HEADERS:
X			m->m_len = sizeof(struct spidp);
X			m->m_off = MMAXOFF - sizeof(struct sphdr);
X			*mtod(m, struct sphdr *) = cb->s_shdr;
X			break;
X
X		default:
X			error = EINVAL;
X		}
X		*value = m;
X		break;
X
X	case PRCO_SETOPT:
X		if (value == 0 || *value == 0) {
X			error = EINVAL;
X			break;
X		}
X		switch (name) {
X			int *ok;
X
X		case SO_HEADERS_ON_INPUT:
X			mask = SF_HI;
X			goto set_head;
X
X		case SO_HEADERS_ON_OUTPUT:
X			mask = SF_HO;
X		set_head:
X			if (cb->s_flags & SF_PI) {
X				ok = mtod(*value, int *);
X				if (*ok)
X					cb->s_flags |= mask;
X				else
X					cb->s_flags &= ~mask;
X			} else error = EINVAL;
X			break;
X
X		case SO_MTU:
X			cb->s_mtu = *(mtod(*value, u_short *));
X			break;
X
X		case SO_DEFAULT_HEADERS:
X			{
X				register struct sphdr *sp
X						= mtod(*value, struct sphdr *);
X				cb->s_dt = sp->sp_dt;
X				cb->s_cc = sp->sp_cc & SP_EM;
X			}
X			break;
X
X		default:
X			error = EINVAL;
X		}
X		m_freem(*value);
X		break;
X	}
X	release:
X		return (error);
X}
X
X/*ARGSUSED*/
Xspp_usrreq(so, req, m, nam, rights)
X	struct socket *so;
X	int req;
X	struct mbuf *m, *nam, *rights;
X{
X	struct nspcb *nsp = sotonspcb(so);
X	register struct sppcb *cb;
X	int s = splnet();
X	int error = 0, ostate;
X	struct mbuf *mm;
X	register struct sockbuf *sb;
X
X	if (req == PRU_CONTROL)
X                return (ns_control(so, (int)m, (caddr_t)nam,
X			(struct ifnet *)rights));
X	if (rights && rights->m_len) {
X		error = EINVAL;
X		goto release;
X	}
X	if (nsp == NULL) {
X		if (req != PRU_ATTACH) {
X			error = EINVAL;
X			goto release;
X		}
X	} else
X		cb = nstosppcb(nsp);
X
X	ostate = cb ? cb->s_state : 0;
X
X	switch (req) {
X
X	case PRU_ATTACH:
X		if (nsp != NULL) {
X			error = EISCONN;
X			break;
X		}
X		error = ns_pcballoc(so, &nspcb);
X		if (error)
X			break;
X		error = soreserve(so, 3072, 3072);
X		if (error)
X			break;
X		nsp = sotonspcb(so);
X
X		mm = m_getclr(M_DONTWAIT, MT_PCB);
X		sb = &so->so_snd;
X
X		if (mm == NULL) {
X			error = ENOBUFS;
X			break;
X		}
X		cb = mtod(mm, struct sppcb *);
X		mm = m_getclr(M_DONTWAIT, MT_HEADER);
X		if (mm == NULL) {
X			m_free(dtom(m));
X			error = ENOBUFS;
X			break;
X		}
X		cb->s_idp = mtod(mm, struct idp *);
X		cb->s_state = TCPS_LISTEN;
X		cb->s_smax = -1;
X		cb->s_swl1 = -1;
X		cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
X		cb->s_nspcb = nsp;
X		cb->s_mtu = 576 - sizeof (struct spidp);
X		cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu;
X		cb->s_ssthresh = cb->s_cwnd;
X		cb->s_cwmx = sb->sb_mbmax * CUNIT /
X				(2 * sizeof (struct spidp));
X		/* Above is recomputed when connecting to account
X		   for changed buffering or mtu's */
X		cb->s_rtt = SPPTV_SRTTBASE;
X		cb->s_rttvar = SPPTV_SRTTDFLT << 2;
X		SPPT_RANGESET(cb->s_rxtcur,
X		    ((SPPTV_SRTTBASE >> 2) + (SPPTV_SRTTDFLT << 2)) >> 1,
X		    SPPTV_MIN, SPPTV_REXMTMAX);
X		nsp->nsp_pcb = (caddr_t) cb; 
X		break;
X
X	case PRU_DETACH:
X		if (nsp == NULL) {
X			error = ENOTCONN;
X			break;
X		}
X		if (cb->s_state > TCPS_LISTEN)
X			cb = spp_disconnect(cb);
X		else
X			cb = spp_close(cb);
X		break;
X
X	case PRU_BIND:
X		error = ns_pcbbind(nsp, nam);
X		break;
X
X	case PRU_LISTEN:
X		if (nsp->nsp_lport == 0)
X			error = ns_pcbbind(nsp, (struct mbuf *)0);
X		if (error == 0)
X			cb->s_state = TCPS_LISTEN;
X		break;
X
X	/*
X	 * Initiate connection to peer.
X	 * Enter SYN_SENT state, and mark socket as connecting.
X	 * Start keep-alive timer, setup prototype header,
X	 * Send initial system packet requesting connection.
X	 */
X	case PRU_CONNECT:
X		if (nsp->nsp_lport == 0) {
X			error = ns_pcbbind(nsp, (struct mbuf *)0);
X			if (error)
X				break;
X		}
X		error = ns_pcbconnect(nsp, nam);
X		if (error)
X			break;
X		soisconnecting(so);
X		sppstat.spps_connattempt++;
X		cb->s_state = TCPS_SYN_SENT;
X		cb->s_did = 0;
X		spp_template(cb);
X		cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
X		cb->s_force = 1 + SPPTV_KEEP;
X		/*
X		 * Other party is required to respond to
X		 * the port I send from, but he is not
X		 * required to answer from where I am sending to,
X		 * so allow wildcarding.
X		 * original port I am sending to is still saved in
X		 * cb->s_dport.
X		 */
X		nsp->nsp_fport = 0;
X		error = spp_output(cb, (struct mbuf *) 0);
X		break;
X
X	case PRU_CONNECT2:
X		error = EOPNOTSUPP;
X		break;
X
X	/*
X	 * We may decide later to implement connection closing
X	 * handshaking at the spp level optionally.
X	 * here is the hook to do it:
X	 */
X	case PRU_DISCONNECT:
X		cb = spp_disconnect(cb);
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_ns *sns = mtod(nam, struct sockaddr_ns *);
X
X		nam->m_len = sizeof (struct sockaddr_ns);
X		sns->sns_family = AF_NS;
X		sns->sns_addr = nsp->nsp_faddr;
X		break;
X		}
X
X	case PRU_SHUTDOWN:
X		socantsendmore(so);
X		cb = spp_usrclosed(cb);
X		if (cb)
X			error = spp_output(cb, (struct mbuf *) 0);
X		break;
X
X	/*
X	 * After a receive, possibly send acknowledgment
X	 * updating allocation.
X	 */
X	case PRU_RCVD:
X		cb->s_flags |= SF_RVD;
X		(void) spp_output(cb, (struct mbuf *) 0);
X		cb->s_flags &= ~SF_RVD;
X		break;
X
X	case PRU_ABORT:
X		(void) spp_drop(cb, ECONNABORTED);
X		break;
X
X	case PRU_SENSE:
X	case PRU_CONTROL:
X		m = NULL;
X		error = EOPNOTSUPP;
X		break;
X
X	case PRU_RCVOOB:
X		if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
X		    (so->so_state & SS_RCVATMARK)) {
X			m->m_len = 1;
X			*mtod(m, caddr_t) = cb->s_iobc;
X			break;
X		}
X		error = EINVAL;
X		break;
X
X	case PRU_SENDOOB:
X		if (sbspace(&so->so_snd) < -512) {
X			error = ENOBUFS;
X			break;
X		}
X		cb->s_oobflags |= SF_SOOB;
X		/* fall into */
X	case PRU_SEND:
X		error = spp_output(cb, m);
X		m = NULL;
X		break;
X
X	case PRU_SOCKADDR:
X		ns_setsockaddr(nsp, nam);
X		break;
X
X	case PRU_PEERADDR:
X		ns_setpeeraddr(nsp, nam);
X		break;
X
X	case PRU_SLOWTIMO:
X		cb = spp_timers(cb, (int)nam);
X		req |= ((int)nam) << 8;
X		break;
X
X	case PRU_FASTTIMO:
X	case PRU_PROTORCV:
X	case PRU_PROTOSEND:
X		error =  EOPNOTSUPP;
X		break;
X
X	default:
X		panic("sp_usrreq");
X	}
X	if (cb && (so->so_options & SO_DEBUG || traceallspps))
X		spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
Xrelease:
X	if (m != NULL)
X		m_freem(m);
X	splx(s);
X	return (error);
X}
X
Xspp_usrreq_sp(so, req, m, nam, rights)
X	struct socket *so;
X	int req;
X	struct mbuf *m, *nam, *rights;
X{
X	int error = spp_usrreq(so, req, m, nam, rights);
X
X	if (req == PRU_ATTACH && error == 0) {
X		struct nspcb *nsp = sotonspcb(so);
X		((struct sppcb *)nsp->nsp_pcb)->s_flags |=
X					(SF_HI | SF_HO | SF_PI);
X	}
X	return (error);
X}
X
X/*
X * Create template to be used to send spp packets on a connection.
X * Called after host entry created, fills
X * in a skeletal spp header (choosing connection id),
X * minimizing the amount of work necessary when the connection is used.
X */
Xspp_template(cb)
X	register struct sppcb *cb;
X{
X	register struct nspcb *nsp = cb->s_nspcb;
X	register struct idp *idp = cb->s_idp;
X	register struct sockbuf *sb = &(nsp->nsp_socket->so_snd);
X
X	idp->idp_pt = NSPROTO_SPP;
X	idp->idp_sna = nsp->nsp_laddr;
X	idp->idp_dna = nsp->nsp_faddr;
X	cb->s_sid = htons(spp_iss);
X	spp_iss += SPP_ISSINCR/2;
X	cb->s_alo = 1;
X	cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu;
X	cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement
X					of large packets */
X	cb->s_cwmx = (sb->sb_mbmax * CUNIT) / (2 * sizeof(struct spidp));
X	cb->s_cwmx = MAX(cb->s_cwmx, cb->s_cwnd);
X		/* But allow for lots of little packets as well */
X}
X
X/*
X * Close a SPIP control block:
X *	discard spp control block itself
X *	discard ns protocol control block
X *	wake up any sleepers
X */
Xstruct sppcb *
Xspp_close(cb)
X	register struct sppcb *cb;
X{
X	register struct spidp_q *s;
X	struct nspcb *nsp = cb->s_nspcb;
X	struct socket *so = nsp->nsp_socket;
X	register struct mbuf *m;
X
X	s = cb->s_q.si_next;
X	while (s != &(cb->s_q)) {
X		s = s->si_next;
X		m = dtom(s->si_prev);
X		remque(s->si_prev);
X		m_freem(m);
X	}
X	(void) m_free(dtom(cb->s_idp));
X	(void) m_free(dtom(cb));
X	nsp->nsp_pcb = 0;
X	soisdisconnected(so);
X	ns_pcbdetach(nsp);
X	sppstat.spps_closed++;
X	return ((struct sppcb *)0);
X}
X/*
X *	Someday we may do level 3 handshaking
X *	to close a connection or send a xerox style error.
X *	For now, just close.
X */
Xstruct sppcb *
Xspp_usrclosed(cb)
X	register struct sppcb *cb;
X{
X	return (spp_close(cb));
X}
Xstruct sppcb *
Xspp_disconnect(cb)
X	register struct sppcb *cb;
X{
X	return (spp_close(cb));
X}
X/*
X * Drop connection, reporting
X * the specified error.
X */
Xstruct sppcb *
Xspp_drop(cb, errno)
X	register struct sppcb *cb;
X	int errno;
X{
X	struct socket *so = cb->s_nspcb->nsp_socket;
X
X	/*
X	 * someday, in the xerox world
X	 * we will generate error protocol packets
X	 * announcing that the socket has gone away.
X	 */
X	if (TCPS_HAVERCVDSYN(cb->s_state)) {
X		sppstat.spps_drops++;
X		cb->s_state = TCPS_CLOSED;
X		/*(void) tcp_output(cb);*/
X	} else
X		sppstat.spps_conndrops++;
X	so->so_error = errno;
X	return (spp_close(cb));
X}
X
Xspp_abort(nsp)
X	struct nspcb *nsp;
X{
X
X	(void) spp_close((struct sppcb *)nsp->nsp_pcb);
X}
X
Xint	spp_backoff[SPP_MAXRXTSHIFT+1] =
X    { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
X/*
X * Fast timeout routine for processing delayed acks
X */
Xspp_fasttimo()
X{
X	register struct nspcb *nsp;
X	register struct sppcb *cb;
X	int s = splnet();
X
X	nsp = nspcb.nsp_next;
X	if (nsp)
X	for (; nsp != &nspcb; nsp = nsp->nsp_next)
X		if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
X		    (cb->s_flags & SF_DELACK)) {
X			cb->s_flags &= ~SF_DELACK;
X			cb->s_flags |= SF_ACKNOW;
X			sppstat.spps_delack++;
X			(void) spp_output(cb, (struct mbuf *) 0);
X		}
X	splx(s);
X}
X
X/*
X * spp protocol timeout routine called every 500 ms.
X * Updates the timers in all active pcb's and
X * causes finite state machine actions if timers expire.
X */
Xspp_slowtimo()
X{
X	register struct nspcb *ip, *ipnxt;
X	register struct sppcb *cb;
X	int s = splnet();
X	register int i;
X
X	/*
X	 * Search through tcb's and update active timers.
X	 */
X	ip = nspcb.nsp_next;
X	if (ip == 0) {
X		splx(s);
X		return;
X	}
X	while (ip != &nspcb) {
X		cb = nstosppcb(ip);
X		ipnxt = ip->nsp_next;
X		if (cb == 0)
X			goto tpgone;
X		for (i = 0; i < SPPT_NTIMERS; i++) {
X			if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
X				(void) spp_usrreq(cb->s_nspcb->nsp_socket,
X				    PRU_SLOWTIMO, (struct mbuf *)0,
X				    (struct mbuf *)i, (struct mbuf *)0);
X				if (ipnxt->nsp_prev != ip)
X					goto tpgone;
X			}
X		}
X		cb->s_idle++;
X		if (cb->s_rtt)
X			cb->s_rtt++;
Xtpgone:
X		ip = ipnxt;
X	}
X	spp_iss += SPP_ISSINCR/PR_SLOWHZ;		/* increment iss */
X	splx(s);
X}
X/*
X * SPP timer processing.
X */
Xstruct sppcb *
Xspp_timers(cb, timer)
X	register struct sppcb *cb;
X	int timer;
X{
X	long rexmt;
X	int win;
X
X	cb->s_force = 1 + timer;
X	switch (timer) {
X
X	/*
X	 * 2 MSL timeout in shutdown went off.  TCP deletes connection
X	 * control block.
X	 */
X	case SPPT_2MSL:
X		printf("spp: SPPT_2MSL went off for no reason\n");
X		cb->s_timer[timer] = 0;
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 packet.
X	 */
X	case SPPT_REXMT:
X		if (++cb->s_rxtshift > SPP_MAXRXTSHIFT) {
X			cb->s_rxtshift = SPP_MAXRXTSHIFT;
X			sppstat.spps_timeoutdrop++;
X			cb = spp_drop(cb, ETIMEDOUT);
X			break;
X		}
X		sppstat.spps_rexmttimeo++;
X		rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
X		rexmt *= spp_backoff[cb->s_rxtshift];
X		SPPT_RANGESET(cb->s_rxtcur, rexmt, SPPTV_MIN, SPPTV_REXMTMAX);
X		cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
X		/*
X		 * If we have backed off fairly far, our srtt
X		 * 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 (cb->s_rxtshift > SPP_MAXRXTSHIFT / 4 ) {
X			cb->s_rttvar += (cb->s_srtt >> 2);
X			cb->s_srtt = 0;
X		}
X		cb->s_snxt = cb->s_rack;
X		/*
X		 * If timing a packet, stop the timer.
X		 */
X		cb->s_rtt = 0;
X		/*
X		 * See very long discussion in tcp_timer.c about congestion
X		 * window and sstrhesh
X		 */
X		win = MIN(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2;
X		if (win < 2)
X			win = 2;
X		cb->s_cwnd = CUNIT;
X		cb->s_ssthresh = win * CUNIT;
X		(void) spp_output(cb, (struct mbuf *) 0);
X		break;
X
X	/*
X	 * Persistance timer into zero window.
X	 * Force a probe to be sent.
X	 */
X	case SPPT_PERSIST:
X		sppstat.spps_persisttimeo++;
X		spp_setpersist(cb);
X		(void) spp_output(cb, (struct mbuf *) 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 SPPT_KEEP:
X		sppstat.spps_keeptimeo++;
X		if (cb->s_state < TCPS_ESTABLISHED)
X			goto dropit;
X		if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
X		    	if (cb->s_idle >= SPPTV_MAXIDLE)
X				goto dropit;
X			sppstat.spps_keepprobe++;
X			(void) spp_output(cb, (struct mbuf *) 0);
X		} else
X			cb->s_idle = 0;
X		cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
X		break;
X	dropit:
X		sppstat.spps_keepdrops++;
X		cb = spp_drop(cb, ETIMEDOUT);
X		break;
X	}
X	return (cb);
X}
X#ifndef lint
Xint SppcbSize = sizeof (struct sppcb);
Xint NspcbSize = sizeof (struct nspcb);
X#endif lint
END-of-netns/spp_usrreq.c
echo x - netns/spp_var.h
sed 's/^X//' >netns/spp_var.h << 'END-of-netns/spp_var.h'
X/*
X * Copyright (c) 1984, 1985, 1986, 1987 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 *      @(#)spp_var.h	7.4 (Berkeley) 3/12/88
X */
X
X/*
X * Sp control block, one per connection
X */
Xstruct sppcb {
X	struct	spidp_q	s_q;		/* queue for out-of-order receipt */
X	struct	nspcb	*s_nspcb;	/* backpointer to internet pcb */
X	u_char	s_state;
X	u_char	s_flags;
X#define	SF_ACKNOW	0x01		/* Ack peer immediately */
X#define	SF_DELACK	0x02		/* Ack, but try to delay it */
X#define	SF_HI	0x04			/* Show headers on input */
X#define	SF_HO	0x08			/* Show headers on output */
X#define	SF_PI	0x10			/* Packet (datagram) interface */
X#define SF_WIN	0x20			/* Window info changed */
X#define SF_RXT	0x40			/* Rxt info changed */
X#define SF_RVD	0x80			/* Calling from read usrreq routine */
X	u_short s_mtu;			/* Max packet size for this stream */
X/* use sequence fields in headers to store sequence numbers for this
X   connection */
X	struct	idp	*s_idp;
X	struct	sphdr	s_shdr;		/* prototype header to transmit */
X#define s_cc s_shdr.sp_cc		/* connection control (for EM bit) */
X#define s_dt s_shdr.sp_dt		/* datastream type */
X#define s_sid s_shdr.sp_sid		/* source connection identifier */
X#define s_did s_shdr.sp_did		/* destination connection identifier */
X#define s_seq s_shdr.sp_seq		/* sequence number */
X#define s_ack s_shdr.sp_ack		/* acknowledge number */
X#define s_alo s_shdr.sp_alo		/* allocation number */
X#define s_dport s_idp->idp_dna.x_port	/* where we are sending */
X	struct sphdr s_rhdr;		/* last received header (in effect!)*/
X	u_short s_rack;			/* their acknowledge number */
X	u_short s_ralo;			/* their allocation number */
X	u_short s_smax;			/* highest packet # we have sent */
X	u_short	s_snxt;			/* which packet to send next */
X
X/* congestion control */
X#define	CUNIT	1024			/* scaling for ... */
X	int	s_cwnd;			/* Congestion-controlled window */
X					/* in packets * CUNIT */
X	short	s_swnd;			/* == tcp snd_wnd, in packets */
X	short	s_smxw;			/* == tcp max_sndwnd */
X					/* difference of two spp_seq's can be
X					   no bigger than a short */
X	u_short	s_swl1;			/* == tcp snd_wl1 */
X	u_short	s_swl2;			/* == tcp snd_wl2 */
X	int	s_cwmx;			/* max allowable cwnd */
X	int	s_ssthresh;		/* s_cwnd size threshhold for
X					 * slow start exponential-to-
X					 * linear switch */
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 */
X	short	s_idle;			/* time idle */
X	short	s_timer[SPPT_NTIMERS];	/* timers */
X	short	s_rxtshift;		/* log(2) of rexmt exp. backoff */
X	short	s_rxtcur;		/* current retransmit value */
X	u_short	s_rtseq;		/* packet being timed */
X	short	s_rtt;			/* timer for round trips */
X	short	s_srtt;			/* averaged timer */
X	short	s_rttvar;		/* variance in round trip time */
X	char	s_force;		/* which timer expired */
X	char	s_dupacks;		/* counter to intuit xmt loss */
X
X/* out of band data */
X	char	s_oobflags;
X#define SF_SOOB	0x08			/* sending out of band data */
X#define SF_IOOB 0x10			/* receiving out of band data */
X	char	s_iobc;			/* input characters */
X/* debug stuff */
X	u_short	s_want;			/* Last candidate for sending */
X	char	s_outx;			/* exit taken from spp_output */
X	char	s_inx;			/* exit taken from spp_input */
X};
X
X#define	nstosppcb(np)	((struct sppcb *)(np)->nsp_pcb)
X#define	sotosppcb(so)	(nstosppcb(sotonspcb(so)))
X
Xstruct	sppstat {
X	long	spps_connattempt;	/* connections initiated */
X	long	spps_accepts;		/* connections accepted */
X	long	spps_connects;		/* connections established */
X	long	spps_drops;		/* connections dropped */
X	long	spps_conndrops;		/* embryonic connections dropped */
X	long	spps_closed;		/* conn. closed (includes drops) */
X	long	spps_segstimed;		/* segs where we tried to get rtt */
X	long	spps_rttupdated;	/* times we succeeded */
X	long	spps_delack;		/* delayed acks sent */
X	long	spps_timeoutdrop;	/* conn. dropped in rxmt timeout */
X	long	spps_rexmttimeo;	/* retransmit timeouts */
X	long	spps_persisttimeo;	/* persist timeouts */
X	long	spps_keeptimeo;		/* keepalive timeouts */
X	long	spps_keepprobe;		/* keepalive probes sent */
X	long	spps_keepdrops;		/* connections dropped in keepalive */
X
X	long	spps_sndtotal;		/* total packets sent */
X	long	spps_sndpack;		/* data packets sent */
X	long	spps_sndbyte;		/* data bytes sent */
X	long	spps_sndrexmitpack;	/* data packets retransmitted */
X	long	spps_sndrexmitbyte;	/* data bytes retransmitted */
X	long	spps_sndacks;		/* ack-only packets sent */
X	long	spps_sndprobe;		/* window probes sent */
X	long	spps_sndurg;		/* packets sent with URG only */
X	long	spps_sndwinup;		/* window update-only packets sent */
X	long	spps_sndctrl;		/* control (SYN|FIN|RST) packets sent */
X	long	spps_sndvoid;		/* couldn't find requested packet*/
X
X	long	spps_rcvtotal;		/* total packets received */
X	long	spps_rcvpack;		/* packets received in sequence */
X	long	spps_rcvbyte;		/* bytes received in sequence */
X	long	spps_rcvbadsum;		/* packets received with ccksum errs */
X	long	spps_rcvbadoff;		/* packets received with bad offset */
X	long	spps_rcvshort;		/* packets received too short */
X	long	spps_rcvduppack;	/* duplicate-only packets received */
X	long	spps_rcvdupbyte;	/* duplicate-only bytes received */
X	long	spps_rcvpartduppack;	/* packets with some duplicate data */
X	long	spps_rcvpartdupbyte;	/* dup. bytes in part-dup. packets */
X	long	spps_rcvoopack;		/* out-of-order packets received */
X	long	spps_rcvoobyte;		/* out-of-order bytes received */
X	long	spps_rcvpackafterwin;	/* packets with data after window */
X	long	spps_rcvbyteafterwin;	/* bytes rcvd after window */
X	long	spps_rcvafterclose;	/* packets rcvd after "close" */
X	long	spps_rcvwinprobe;	/* rcvd window probe packets */
X	long	spps_rcvdupack;		/* rcvd duplicate acks */
X	long	spps_rcvacktoomuch;	/* rcvd acks for unsent data */
X	long	spps_rcvackpack;	/* rcvd ack packets */
X	long	spps_rcvackbyte;	/* bytes acked by rcvd acks */
X	long	spps_rcvwinupd;		/* rcvd window update packets */
X};
Xstruct	spp_istat {
X	short	hdrops;
X	short	badsum;
X	short	badlen;
X	short	slotim;
X	short	fastim;
X	short	nonucn;
X	short	noconn;
X	short	notme;
X	short	wrncon;
X	short	bdreas;
X	short	gonawy;
X	short	notyet;
X	short	lstdup;
X	struct sppstat newstats;
X};
X
X#ifdef KERNEL
Xstruct spp_istat spp_istat;
X
X/* Following was struct sppstat sppstat; */
X#ifndef sppstat
X#define sppstat spp_istat.newstats
X#endif
X
Xu_short spp_iss;
Xextern struct sppcb *spp_close(), *spp_disconnect(),
X	*spp_usrclosed(), *spp_timers(), *spp_drop();
X#endif
X
X#define	SPP_ISSINCR	128
X/*
X * SPP sequence numbers are 16 bit integers operated
X * on with modular arithmetic.  These macros can be
X * used to compare such integers.
X */
X#ifdef sun
Xshort xnsCbug;
X#define	SSEQ_LT(a,b)	((xnsCbug = (short)((a)-(b))) < 0)
X#define	SSEQ_LEQ(a,b)	((xnsCbug = (short)((a)-(b))) <= 0)
X#define	SSEQ_GT(a,b)	((xnsCbug = (short)((a)-(b))) > 0)
X#define	SSEQ_GEQ(a,b)	((xnsCbug = (short)((a)-(b))) >= 0)
X#else
X#define	SSEQ_LT(a,b)	(((short)((a)-(b))) < 0)
X#define	SSEQ_LEQ(a,b)	(((short)((a)-(b))) <= 0)
X#define	SSEQ_GT(a,b)	(((short)((a)-(b))) > 0)
X#define	SSEQ_GEQ(a,b)	(((short)((a)-(b))) >= 0)
X#endif
END-of-netns/spp_var.h
exit
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads