xref: /csrg-svn/sys/netns/spp_usrreq.c (revision 25623)
123215Smckusick /*
225334Ssklower  * Copyright (c) 1984, 1985 Regents of the University of California.
323215Smckusick  * All rights reserved.  The Berkeley software License Agreement
423215Smckusick  * specifies the terms and conditions for redistribution.
523215Smckusick  *
6*25623Ssklower  *	@(#)spp_usrreq.c	6.16 (Berkeley) 12/18/85
723215Smckusick  */
821496Ssklower 
921496Ssklower #include "param.h"
1021496Ssklower #include "dir.h"
1121496Ssklower #include "user.h"
1221496Ssklower #include "mbuf.h"
1321496Ssklower #include "protosw.h"
1421496Ssklower #include "socket.h"
1521496Ssklower #include "socketvar.h"
1621496Ssklower #include "errno.h"
1721496Ssklower 
1821496Ssklower #include "../net/if.h"
1921496Ssklower #include "../net/route.h"
2021496Ssklower #include "../netinet/tcp_fsm.h"
2121496Ssklower #include "../netinet/tcp_timer.h"
2221496Ssklower 
2321496Ssklower #include "ns.h"
2421496Ssklower #include "ns_pcb.h"
2521496Ssklower #include "idp.h"
2621496Ssklower #include "idp_var.h"
2721496Ssklower #include "ns_error.h"
2821496Ssklower #include "sp.h"
2921496Ssklower #include "spidp.h"
3021496Ssklower #include "spp_var.h"
3121496Ssklower #include "spp_debug.h"
3221496Ssklower 
3321496Ssklower /*
3421496Ssklower  * SP protocol implementation.
3521496Ssklower  */
3621496Ssklower spp_init()
3721496Ssklower {
3821496Ssklower 
3921496Ssklower 	spp_iss = 1; /* WRONG !! should fish it out of TODR */
4021496Ssklower }
4121496Ssklower struct spidp spp_savesi;
4221496Ssklower int traceallspps = 0;
4321496Ssklower extern int sppconsdebug;
4424615Ssklower int spp_hardnosed;
4525037Ssklower int spp_use_delack = 0;
4621496Ssklower 
4724615Ssklower /*ARGSUSED*/
4824615Ssklower spp_input(m, nsp, ifp)
4921496Ssklower 	register struct mbuf *m;
5024047Ssklower 	register struct nspcb *nsp;
5124615Ssklower 	struct ifnet *ifp;
5221496Ssklower {
5321496Ssklower 	register struct sppcb *cb;
5421496Ssklower 	register struct spidp *si = mtod(m, struct spidp *);
5521496Ssklower 	register struct socket *so;
5624225Ssklower 	short ostate;
5721496Ssklower 	int dropsocket = 0;
5821496Ssklower 
5921496Ssklower 
6024330Ssklower 	if (nsp == 0) {
6124047Ssklower 		panic("No nspcb in spp_input\n");
6223979Ssklower 		return;
6323979Ssklower 	}
6421496Ssklower 
6521496Ssklower 	cb = nstosppcb(nsp);
6621496Ssklower 	if (cb == 0) goto bad;
6721496Ssklower 
6824047Ssklower 	if (m->m_len < sizeof(*si)) {
6924330Ssklower 		if ((m = m_pullup(m, sizeof(*si))) == 0) {
7024047Ssklower 			spp_istat.hdrops++;
7124047Ssklower 			return;
7224047Ssklower 		}
7324047Ssklower 		si = mtod(m, struct spidp *);
7424047Ssklower 	}
7521496Ssklower 	si->si_seq = ntohs(si->si_seq);
7621496Ssklower 	si->si_ack = ntohs(si->si_ack);
7721496Ssklower 	si->si_alo = ntohs(si->si_alo);
7821496Ssklower 
7921496Ssklower 	so = nsp->nsp_socket;
8021496Ssklower 	if (so->so_options & SO_DEBUG || traceallspps) {
8121496Ssklower 		ostate = cb->s_state;
8221496Ssklower 		spp_savesi = *si;
8321496Ssklower 	}
8421496Ssklower 	if (so->so_options & SO_ACCEPTCONN) {
8521496Ssklower 		so = sonewconn(so);
8621496Ssklower 		if (so == 0) {
8721496Ssklower 			spp_istat.nonucn++;
8821496Ssklower 			goto drop;
8921496Ssklower 		}
9021496Ssklower 		/*
9121496Ssklower 		 * This is ugly, but ....
9221496Ssklower 		 *
9321496Ssklower 		 * Mark socket as temporary until we're
9421496Ssklower 		 * committed to keeping it.  The code at
9521496Ssklower 		 * ``drop'' and ``dropwithreset'' check the
9621496Ssklower 		 * flag dropsocket to see if the temporary
9721496Ssklower 		 * socket created here should be discarded.
9821496Ssklower 		 * We mark the socket as discardable until
9921496Ssklower 		 * we're committed to it below in TCPS_LISTEN.
10021496Ssklower 		 */
10121496Ssklower 		dropsocket++;
10221496Ssklower 		nsp = (struct nspcb *)so->so_pcb;
10321496Ssklower 		nsp->nsp_laddr = si->si_dna;
10421496Ssklower 		cb = nstosppcb(nsp);
10521496Ssklower 		cb->s_state = TCPS_LISTEN;
10621496Ssklower 	}
10721496Ssklower 
10821496Ssklower 	/*
10921496Ssklower 	 * Packet received on connection.
11021496Ssklower 	 * reset idle time and keep-alive timer;
11121496Ssklower 	 */
11221496Ssklower 	cb->s_idle = 0;
11321496Ssklower 	cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
11421496Ssklower 
11521496Ssklower 	switch (cb->s_state) {
11623515Ssklower 
11721496Ssklower 	case TCPS_LISTEN:{
11821496Ssklower 		struct mbuf *am;
11921496Ssklower 		register struct sockaddr_ns *sns;
12021496Ssklower 		struct ns_addr laddr;
12121496Ssklower 
12221496Ssklower 		/*
12321496Ssklower 		 * If somebody here was carying on a conversation
12421496Ssklower 		 * and went away, and his pen pal thinks he can
12521496Ssklower 		 * still talk, we get the misdirected packet.
12621496Ssklower 		 */
12721496Ssklower 		if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
12821496Ssklower 			spp_istat.gonawy++;
12921496Ssklower 			goto dropwithreset;
13021496Ssklower 		}
13121496Ssklower 		am = m_get(M_DONTWAIT, MT_SONAME);
13221496Ssklower 		if (am == NULL)
13321496Ssklower 			goto drop;
13421496Ssklower 		am->m_len = sizeof (struct sockaddr_ns);
13521496Ssklower 		sns = mtod(am, struct sockaddr_ns *);
13621496Ssklower 		sns->sns_family = AF_NS;
13721496Ssklower 		sns->sns_addr = si->si_sna;
13821496Ssklower 		laddr = nsp->nsp_laddr;
13921496Ssklower 		if (ns_nullhost(laddr))
14021496Ssklower 			nsp->nsp_laddr = si->si_dna;
14121496Ssklower 		if (ns_pcbconnect(nsp, am)) {
14221496Ssklower 			nsp->nsp_laddr = laddr;
14321496Ssklower 			(void) m_free(am);
14421496Ssklower 			spp_istat.noconn++;
14521496Ssklower 			goto drop;
14621496Ssklower 		}
14721496Ssklower 		(void) m_free(am);
14821496Ssklower 		spp_template(cb);
14924732Ssklower 		dropsocket = 0;		/* committed to socket */
15021496Ssklower 		cb->s_did = si->si_sid;
15121496Ssklower 		cb->s_rack = si->si_ack;
15221496Ssklower 		cb->s_ralo = si->si_alo;
15324732Ssklower #define THREEWAYSHAKE
15424732Ssklower #ifdef THREEWAYSHAKE
15524732Ssklower 		cb->s_state = TCPS_SYN_RECEIVED;
15624732Ssklower 		cb->s_force = 1 + TCPT_REXMT;
15724732Ssklower 		cb->s_timer[TCPT_REXMT] = 2 * TCPTV_MIN;
15821496Ssklower 		}
15921496Ssklower 		break;
16024732Ssklower 	/*
16124732Ssklower 	 * This state means that we have heard a response
16224732Ssklower 	 * to our acceptance of their connection
16324732Ssklower 	 * It is probably logically unnecessary in this
16424732Ssklower 	 * implementation.
16524732Ssklower 	 */
16624732Ssklower 	 case TCPS_SYN_RECEIVED:
16724732Ssklower 		if (si->si_did!=cb->s_sid) {
16824732Ssklower 			spp_istat.wrncon++;
16924732Ssklower 			goto drop;
17024732Ssklower 		}
17124732Ssklower #endif
17224732Ssklower 		nsp->nsp_fport =  si->si_sport;
17324732Ssklower 		cb->s_timer[TCPT_REXMT] = 0;
17424732Ssklower 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
17524732Ssklower 		soisconnected(so);
17624732Ssklower 		cb->s_state = TCPS_ESTABLISHED;
17724732Ssklower 		break;
17821496Ssklower 
17921496Ssklower 	/*
18021496Ssklower 	 * This state means that we have gotten a response
18121496Ssklower 	 * to our attempt to establish a connection.
18223979Ssklower 	 * We fill in the data from the other side,
18323979Ssklower 	 * telling us which port to respond to, instead of the well-
18423979Ssklower 	 * known one we might have sent to in the first place.
18521496Ssklower 	 * We also require that this is a response to our
18623979Ssklower 	 * connection id.
18721496Ssklower 	 */
18821496Ssklower 	case TCPS_SYN_SENT:
18921496Ssklower 		if (si->si_did!=cb->s_sid) {
19021496Ssklower 			spp_istat.notme++;
19121496Ssklower 			goto drop;
19221496Ssklower 		}
19321496Ssklower 		cb->s_did = si->si_sid;
19421496Ssklower 		cb->s_rack = si->si_ack;
19521496Ssklower 		cb->s_ralo = si->si_alo;
19621496Ssklower 		cb->s_dport = nsp->nsp_fport =  si->si_sport;
19721496Ssklower 		cb->s_timer[TCPT_REXMT] = 0;
19821496Ssklower 		cb->s_flags |= SF_AK;
19921496Ssklower 		soisconnected(so);
20021496Ssklower 		cb->s_state = TCPS_ESTABLISHED;
20121496Ssklower 	}
20221496Ssklower 	if (so->so_options & SO_DEBUG || traceallspps)
20324225Ssklower 		spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0);
20421496Ssklower 
20521496Ssklower 	m->m_len -= sizeof (struct idp);
20621496Ssklower 	m->m_off += sizeof (struct idp);
20721496Ssklower 
20825037Ssklower 	if (spp_reass(cb, si)) {
20925334Ssklower 		m_freem(m);
21021496Ssklower 	}
21125037Ssklower 	(void) spp_output(cb, (struct mbuf *)0);
21221496Ssklower 	return;
21321496Ssklower 
21421496Ssklower dropwithreset:
21521496Ssklower 	if (dropsocket)
21621496Ssklower 		(void) soabort(so);
21721496Ssklower 	si->si_seq = ntohs(si->si_seq);
21821496Ssklower 	si->si_ack = ntohs(si->si_ack);
21921496Ssklower 	si->si_alo = ntohs(si->si_alo);
22021496Ssklower 	ns_error(dtom(si), NS_ERR_NOSOCK, 0);
22121496Ssklower 	if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)
22224225Ssklower 		spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
22321496Ssklower 	return;
22421496Ssklower 
22521496Ssklower drop:
22621496Ssklower bad:
22724330Ssklower 	if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)
22824225Ssklower 		spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
22921496Ssklower 	m_freem(m);
23021496Ssklower }
23121496Ssklower 
23221496Ssklower /*
23321496Ssklower  * This is structurally similar to the tcp reassembly routine
23421496Ssklower  * but its function is somewhat different:  It merely queues
23521496Ssklower  * packets up, and suppresses duplicates.
23621496Ssklower  */
23725037Ssklower spp_reass(cb, si)
23821496Ssklower register struct sppcb *cb;
23921496Ssklower register struct spidp *si;
24021496Ssklower {
24121496Ssklower 	register struct spidp_q *q;
24221496Ssklower 	register struct mbuf *m;
24321496Ssklower 	struct socket *so = cb->s_nspcb->nsp_socket;
24421496Ssklower 	struct sockbuf *sb = & (so->so_rcv);
24521496Ssklower 	char packetp = cb->s_flags & SF_HI;
24621496Ssklower 	char wakeup = 0;
24721496Ssklower 
24821496Ssklower 
24924330Ssklower 	if (si == SI(0))
25021496Ssklower 		goto present;
25121496Ssklower 	/*
25221496Ssklower 	 * Update our news from them.
25321496Ssklower 	 */
25421496Ssklower 	if (si->si_cc & SP_SA)
25525037Ssklower 		cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_AK);
25625037Ssklower 	if (SSEQ_GT(si->si_ack, cb->s_rack)) {
25721496Ssklower 		cb->s_rack = si->si_ack;
25821496Ssklower 		/*
25925037Ssklower 		 * If there are other packets outstanding,
26025037Ssklower 		 * restart the timer for them.
26125037Ssklower 		 */
26225037Ssklower 		if (SSEQ_GEQ(cb->s_snt, si->si_ack)) {
26325037Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
26425037Ssklower 				tcp_beta * cb->s_srtt, TCPTV_MIN,
26525037Ssklower 				TCPTV_MAX);
26625037Ssklower 			cb->s_rxtshift = 0;
26725037Ssklower 		} else
26825037Ssklower 			cb->s_timer[TCPT_REXMT] = 0;
26925037Ssklower 		/*
27021496Ssklower 		 * If transmit timer is running and timed sequence
27121496Ssklower 		 * number was acked, update smoothed round trip time.
27221496Ssklower 		 */
27321496Ssklower 		if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
27421496Ssklower 			if (cb->s_srtt == 0)
27521496Ssklower 				cb->s_srtt = cb->s_rtt;
27621496Ssklower 			else
27721496Ssklower 				cb->s_srtt =
27821496Ssklower 				    tcp_alpha * cb->s_srtt +
27921496Ssklower 				    (1 - tcp_alpha) * cb->s_rtt;
28021496Ssklower 			cb->s_rtt = 0;
28121496Ssklower 		}
28221496Ssklower 	}
28325037Ssklower 	if (SSEQ_GT(si->si_alo, cb->s_ralo)) {
28421496Ssklower 		cb->s_ralo = si->si_alo;
28521496Ssklower 		cb->s_timer[TCPT_PERSIST] = 0;
28621496Ssklower 	}
28721496Ssklower 	/*
28821496Ssklower 	 * If this is a system packet, we don't need to
28921496Ssklower 	 * queue it up, and won't update acknowledge #
29021496Ssklower 	 */
29123561Ssklower 	if (si->si_cc & SP_SP) {
29223561Ssklower 		m_freem(dtom(si));
29323515Ssklower 		return (0);
29423561Ssklower 	}
29521496Ssklower 
29621496Ssklower 	/*
29721496Ssklower 	 * If this packet number has a sequence number less
29821496Ssklower 	 * than that of the first packet not yet seen coming
29921496Ssklower 	 * from them, this must be a duplicate, so drop.
30021496Ssklower 	 */
30125037Ssklower 	if (SSEQ_LT(si->si_seq, cb->s_ack)) {
30223979Ssklower 		spp_istat.bdreas++;
30324330Ssklower 		if (si->si_seq == cb->s_ack-1)
30423979Ssklower 			spp_istat.lstdup++;
30523515Ssklower 		return (1);
30623979Ssklower 	}
30721496Ssklower 	/*
30821496Ssklower 	 * If this packet number is higher than that which
30921496Ssklower 	 * we have allocated refuse it, unless urgent
31021496Ssklower 	 */
31125037Ssklower 	if (SSEQ_GT(si->si_seq, cb->s_alo)) {
31225037Ssklower 		if (si->si_cc & SP_OB) {
31325037Ssklower 			if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) {
31425037Ssklower 				ns_error(dtom(si), NS_ERR_FULLUP, 0);
31525037Ssklower 				return (0);
31625037Ssklower 			} /* else queue this packet; */
31725037Ssklower 		} else {
31825037Ssklower 			spp_istat.notyet++;
31925037Ssklower 			return (1);
32025037Ssklower 		}
32121496Ssklower 	}
32221496Ssklower 
32321496Ssklower 	/*
32421496Ssklower 	 * Loop through all packets queued up to insert in
32521496Ssklower 	 * appropriate sequence.
32621496Ssklower 	 */
32721496Ssklower 
32821496Ssklower 	for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
32924330Ssklower 	    if (si->si_seq == SI(q)->si_seq) return (1); /*duplicate */
33025037Ssklower 	    if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) break;
33121496Ssklower 	}
33225037Ssklower 	insque(si, q->si_prev);
33325037Ssklower 	/*
33425037Ssklower 	 * If this packet is urgent, inform process
33525037Ssklower 	 */
33625037Ssklower 	if (si->si_cc & SP_OB) {
33725037Ssklower 		cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
33825037Ssklower 		sohasoutofband(so);
33925037Ssklower 		cb->s_oobflags |= SF_IOOB;
34025037Ssklower 	}
34121496Ssklower present:
34221496Ssklower #define SPINC sizeof(struct sphdr)
34321496Ssklower 	/*
34421496Ssklower 	 * Loop through all packets queued up to update acknowledge
34521496Ssklower 	 * number, and present all acknowledged data to user;
34621496Ssklower 	 * If in packet interface mode, show packet headers.
34721496Ssklower 	 */
34821496Ssklower 	for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
34924330Ssklower 		  if (SI(q)->si_seq == cb->s_ack) {
35021496Ssklower 			cb->s_ack++;
35121496Ssklower 			m = dtom(q);
35221496Ssklower 			if (SI(q)->si_cc & SP_OB) {
35325037Ssklower 				cb->s_oobflags &= ~SF_IOOB;
35421496Ssklower 				if (sb->sb_cc)
35521496Ssklower 					so->so_oobmark = sb->sb_cc;
35621496Ssklower 				else
35721496Ssklower 					so->so_state |= SS_RCVATMARK;
35821496Ssklower 			}
35921496Ssklower 			q = q->si_prev;
36021496Ssklower 			remque(q->si_next);
36121496Ssklower 			wakeup = 1;
36221496Ssklower 			if (packetp) {
36325037Ssklower 				sbappendrecord(sb, m);
36421496Ssklower 			} else {
36521496Ssklower 				cb->s_rhdr = *mtod(m, struct sphdr *);
36621496Ssklower 				m->m_off += SPINC;
36721496Ssklower 				m->m_len -= SPINC;
36825037Ssklower 				sbappend(sb, m);
36921496Ssklower 			}
37021496Ssklower 		  } else
37121496Ssklower 			break;
37221496Ssklower 	}
37321496Ssklower 	if (wakeup) sorwakeup(so);
37423515Ssklower 	return (0);
37521496Ssklower }
37621496Ssklower 
37721496Ssklower spp_ctlinput(cmd, arg)
37821496Ssklower 	int cmd;
37921496Ssklower 	caddr_t arg;
38021496Ssklower {
38121496Ssklower 	struct ns_addr *na;
38221496Ssklower 	extern u_char nsctlerrmap[];
38321496Ssklower 	extern spp_abort();
38424225Ssklower 	extern struct nspcb *idp_drop();
38523979Ssklower 	struct ns_errp *errp;
38623979Ssklower 	struct nspcb *nsp;
38724615Ssklower 	struct sockaddr_ns *sns;
38821496Ssklower 	int type;
38921496Ssklower 
39021496Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
39121496Ssklower 		return;
39221496Ssklower 	type = NS_ERR_UNREACH_HOST;
39321496Ssklower 
39421496Ssklower 	switch (cmd) {
39523515Ssklower 
39621496Ssklower 	case PRC_ROUTEDEAD:
39721496Ssklower 	case PRC_QUENCH:
39821496Ssklower 		break;
39921496Ssklower 
40021496Ssklower 	case PRC_IFDOWN:
40121496Ssklower 	case PRC_HOSTDEAD:
40221496Ssklower 	case PRC_HOSTUNREACH:
40324615Ssklower 		sns = (struct sockaddr_ns *)arg;
40424615Ssklower 		if (sns->sns_family != AF_NS)
40524615Ssklower 			return;
40624615Ssklower 		na = &sns->sns_addr;
40721496Ssklower 		break;
40821496Ssklower 
40921496Ssklower 	default:
41023979Ssklower 		errp = (struct ns_errp *)arg;
41123979Ssklower 		na = &errp->ns_err_idp.idp_dna;
41223979Ssklower 		type = errp->ns_err_num;
41324225Ssklower 		type = ntohs((u_short)type);
41421496Ssklower 	}
41521496Ssklower 	switch (type) {
41623515Ssklower 
41721496Ssklower 	case NS_ERR_UNREACH_HOST:
41823979Ssklower 		ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0);
41921496Ssklower 		break;
42023515Ssklower 
42121496Ssklower 	case NS_ERR_TOO_BIG:
42223979Ssklower 	case NS_ERR_NOSOCK:
42323979Ssklower 		nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port,
42423979Ssklower 			NS_WILDCARD);
42523979Ssklower 		if (nsp) {
42623979Ssklower 			if(nsp->nsp_pcb)
42724225Ssklower 				(void) spp_drop((struct sppcb *)nsp->nsp_pcb,
42824225Ssklower 						(int)nsctlerrmap[cmd]);
42923979Ssklower 			else
43024225Ssklower 				(void) idp_drop(nsp, (int)nsctlerrmap[cmd]);
43123979Ssklower 		}
43221496Ssklower 	}
43321496Ssklower }
43421496Ssklower 
43524225Ssklower #ifdef notdef
43621496Ssklower int
43721496Ssklower spp_fixmtu(nsp)
43821496Ssklower register struct nspcb *nsp;
43921496Ssklower {
44021496Ssklower 	register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb);
44121496Ssklower 	register struct mbuf *m;
44221496Ssklower 	register struct spidp *si;
44321496Ssklower 	struct ns_errp *ep;
44421496Ssklower 	struct sockbuf *sb;
44521496Ssklower 	int badseq, len;
44621496Ssklower 	struct mbuf *firstbad, *m0;
44721496Ssklower 
44821496Ssklower 	if (cb) {
44921496Ssklower 		/*
45021496Ssklower 		 * The notification that we have sent
45121496Ssklower 		 * too much is bad news -- we will
45221496Ssklower 		 * have to go through queued up so far
45321496Ssklower 		 * splitting ones which are too big and
45421496Ssklower 		 * reassigning sequence numbers and checksums.
45521496Ssklower 		 * we should then retransmit all packets from
45621496Ssklower 		 * one above the offending packet to the last one
45721496Ssklower 		 * we had sent (or our allocation)
45821496Ssklower 		 * then the offending one so that the any queued
45921496Ssklower 		 * data at our destination will be discarded.
46021496Ssklower 		 */
46121496Ssklower 		 ep = (struct ns_errp *)nsp->nsp_notify_param;
46221496Ssklower 		 sb = &nsp->nsp_socket->so_snd;
46321496Ssklower 		 cb->s_mtu = ep->ns_err_param;
46421496Ssklower 		 badseq = SI(&ep->ns_err_idp)->si_seq;
46521496Ssklower 		 for (m = sb->sb_mb; m; m = m->m_act) {
46621496Ssklower 			si = mtod(m, struct spidp *);
46721496Ssklower 			if (si->si_seq == badseq)
46821496Ssklower 				break;
46921496Ssklower 		 }
47024330Ssklower 		 if (m == 0) return;
47121496Ssklower 		 firstbad = m;
47221496Ssklower 		 /*for (;;) {*/
47321496Ssklower 			/* calculate length */
47421496Ssklower 			for (m0 = m, len = 0; m ; m = m->m_next)
47521496Ssklower 				len += m->m_len;
47621496Ssklower 			if (len > cb->s_mtu) {
47721496Ssklower 			}
47821496Ssklower 		/* FINISH THIS
47921496Ssklower 		} */
48021496Ssklower 	}
48121496Ssklower }
48224225Ssklower #endif
48321496Ssklower 
48421496Ssklower int spp_output_cnt = 0;
48523979Ssklower 
48621496Ssklower spp_output(cb, m0)
48721496Ssklower 	register struct sppcb *cb;
48821496Ssklower 	struct mbuf *m0;
48921496Ssklower {
49021496Ssklower 	struct socket *so = cb->s_nspcb->nsp_socket;
49121496Ssklower 	register struct mbuf *m;
49221496Ssklower 	register struct spidp *si = (struct spidp *) 0;
49321496Ssklower 	register struct sockbuf *sb = &(so->so_snd);
49421496Ssklower 	register int len = 0;
49524330Ssklower 	int error = 0;
49624330Ssklower 	u_short lookfor = 0;
49721496Ssklower 	struct mbuf *mprev;
49821496Ssklower 	extern int idpcksum;
49921496Ssklower 
50024330Ssklower 	if (m0) {
50124615Ssklower 		int mtu = cb->s_mtu;
50224615Ssklower 		int datalen;
50324615Ssklower 		/*
50424615Ssklower 		 * Make sure that packet isn't too big.
50524615Ssklower 		 */
50621496Ssklower 		for (m = m0; m ; m = m->m_next) {
50721496Ssklower 			mprev = m;
50821496Ssklower 			len += m->m_len;
50921496Ssklower 		}
51024615Ssklower 		datalen = (cb->s_flags & SF_HO) ?
51124615Ssklower 				len - sizeof (struct sphdr) : len;
51224615Ssklower 		if (datalen > mtu) {
51321496Ssklower 			if (cb->s_flags & SF_PI) {
51421496Ssklower 				m_freem(m0);
51523515Ssklower 				return (EMSGSIZE);
51621496Ssklower 			} else {
51721496Ssklower 				int off = 0;
51824615Ssklower 				int oldEM = cb->s_cc & SP_EM;
51924615Ssklower 
52024615Ssklower 				cb->s_cc &= ~SP_EM;
52121496Ssklower 				while (len > mtu) {
52221496Ssklower 					m = m_copy(m0, off, mtu);
52324330Ssklower 					if (m == NULL) {
52424615Ssklower 						error = ENOBUFS;
52524615Ssklower 						goto bad_copy;
52623515Ssklower 					}
52721496Ssklower 					error = spp_output(cb, m);
52821496Ssklower 					if (error) {
52924615Ssklower 					bad_copy:
53024615Ssklower 						cb->s_cc |= oldEM;
53121496Ssklower 						m_freem(m0);
53224615Ssklower 						return(error);
53321496Ssklower 					}
53421496Ssklower 					m_adj(m0, mtu);
53521496Ssklower 					len -= mtu;
53621496Ssklower 				}
53724615Ssklower 				cb->s_cc |= oldEM;
53821496Ssklower 			}
53921496Ssklower 		}
54024330Ssklower 		/*
54124330Ssklower 		 * Force length even, by adding a "garbage byte" if
54224330Ssklower 		 * necessary.
54324330Ssklower 		 */
54421496Ssklower 		if (len & 1) {
54523979Ssklower 			m = mprev;
54624330Ssklower 			if (m->m_len + m->m_off < MMAXOFF)
54721496Ssklower 				m->m_len++;
54824330Ssklower 			else {
54921496Ssklower 				struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
55021496Ssklower 
55121496Ssklower 				if (m1 == 0) {
55221496Ssklower 					m_freem(m0);
55321496Ssklower 					return (ENOBUFS);
55421496Ssklower 				}
55521496Ssklower 				m1->m_len = 1;
55621496Ssklower 				m1->m_off = MMAXOFF - 1;
55724330Ssklower 				m->m_next = m1;
55821496Ssklower 			}
55921496Ssklower 		}
56021496Ssklower 		m = m_get(M_DONTWAIT, MT_HEADER);
56121496Ssklower 		if (m == 0) {
56221496Ssklower 			m_freem(m0);
56323515Ssklower 			return (ENOBUFS);
56421496Ssklower 		}
56521496Ssklower 		/*
56621496Ssklower 		 * Fill in mbuf with extended SP header
56721496Ssklower 		 * and addresses and length put into network format.
568*25623Ssklower 		 * Long align so prepended ip headers will work on Gould.
56921496Ssklower 		 */
570*25623Ssklower 		m->m_off = MMAXOFF - sizeof (struct spidp) - 2;
57121496Ssklower 		m->m_len = sizeof (struct spidp);
57221496Ssklower 		m->m_next = m0;
57321496Ssklower 		si = mtod(m, struct spidp *);
57421496Ssklower 		*si = cb->s_shdr;
57521496Ssklower 		if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
57624330Ssklower 			register struct sphdr *sh;
57724330Ssklower 			if (m0->m_len < sizeof (*sh)) {
57824330Ssklower 				if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
57924330Ssklower 					(void) m_free(m);
58024330Ssklower 					m_freem(m0);
58124330Ssklower 					return (EINVAL);
58224330Ssklower 				}
58324330Ssklower 				m->m_next = m0;
58424330Ssklower 			}
58524330Ssklower 			sh = mtod(m0, struct sphdr *);
58621496Ssklower 			si->si_dt = sh->sp_dt;
58721496Ssklower 			si->si_cc |= sh->sp_cc & SP_EM;
58821496Ssklower 			m0->m_len -= sizeof (*sh);
58921496Ssklower 			m0->m_off += sizeof (*sh);
59021496Ssklower 			len -= sizeof (*sh);
59121496Ssklower 		}
59221496Ssklower 		len += sizeof(*si);
59323979Ssklower 		if (cb->s_oobflags & SF_SOOB) {
59423979Ssklower 			/*
59523979Ssklower 			 * Per jqj@cornell:
59623979Ssklower 			 * make sure OB packets convey exactly 1 byte.
59723979Ssklower 			 * If the packet is 1 byte or larger, we
59823979Ssklower 			 * have already guaranted there to be at least
59923979Ssklower 			 * one garbage byte for the checksum, and
60023979Ssklower 			 * extra bytes shouldn't hurt!
60123979Ssklower 			 */
60223979Ssklower 			if (len > sizeof(*si)) {
60323979Ssklower 				si->si_cc |= SP_OB;
60423979Ssklower 				len = (1 + sizeof(*si));
60523979Ssklower 			}
60623979Ssklower 		}
60724225Ssklower 		si->si_len = htons((u_short)len);
60821496Ssklower 		/*
60921496Ssklower 		 * queue stuff up for output
61021496Ssklower 		 */
61125037Ssklower 		sbappendrecord(sb, m);
61221496Ssklower 		cb->s_seq++;
61321496Ssklower 	}
61421496Ssklower 	/*
61521496Ssklower 	 * update window
61621496Ssklower 	 */
61721496Ssklower 	{
61824225Ssklower 		register struct sockbuf *sb2 = &so->so_rcv;
619*25623Ssklower 		int credit = ((((int)sb2->sb_mbmax) - (int)sb2->sb_mbcnt) /
62024732Ssklower 						((short)cb->s_mtu));
62124732Ssklower 		int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1;
62221496Ssklower 
62324732Ssklower 		if (cb->s_alo < alo) {
62424732Ssklower 			/* If the amount we are raising the window
62524732Ssklower 			   is more than his remaining headroom, tell
62624732Ssklower 			   him about it.  In particular, if he is at
62724732Ssklower 			   his limit, any amount at all will do! */
62824732Ssklower 			u_short raise = alo - cb->s_alo;
62924732Ssklower 			u_short headroom = 1 + cb->s_alo - cb->s_ack;
63024732Ssklower 
63124732Ssklower 			if(SSEQ_LT(headroom, raise))
63224732Ssklower 				cb->s_flags |= SF_AK;
63324330Ssklower 			cb->s_alo = alo;
63424732Ssklower 		}
63521496Ssklower 	}
63621496Ssklower 
63721496Ssklower 	if (cb->s_oobflags & SF_SOOB) {
63821496Ssklower 		/*
63921496Ssklower 		 * must transmit this out of band packet
64021496Ssklower 		 */
64121496Ssklower 		cb->s_oobflags &= ~ SF_SOOB;
64221496Ssklower 	} else {
64321496Ssklower 		/*
64421496Ssklower 		 * Decide what to transmit:
64525168Ssklower 		 * If it is time to retransmit a packet,
64625168Ssklower 		 * send that.
64721496Ssklower 		 * If we have a new packet, send that
64821496Ssklower 		 * (So long as it is in our allocation)
64921496Ssklower 		 * Otherwise, see if it time to bang on them
65021496Ssklower 		 * to ask for our current allocation.
65121496Ssklower 		 */
65225168Ssklower 		if (cb->s_force == (1+TCPT_REXMT)) {
65325168Ssklower 			lookfor = cb->s_rack;
65425168Ssklower 		} else if (SSEQ_LT(cb->s_snt, cb->s_ralo)) {
65521496Ssklower 			lookfor = cb->s_snt + 1;
65621496Ssklower 		} else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) {
65721496Ssklower 			lookfor = 0;
65824330Ssklower 			if (cb->s_timer[TCPT_PERSIST] == 0) {
65921496Ssklower 				spp_setpersist(cb);
66024330Ssklower 				/* tcp has cb->s_rxtshift = 0; here */
66121496Ssklower 			}
66221496Ssklower 		}
66321496Ssklower 		m = sb->sb_mb;
66424330Ssklower 		while (m) {
66521496Ssklower 			si = mtod(m, struct spidp *);
66621496Ssklower 			m = m->m_act;
66721496Ssklower 			if (SSEQ_LT(si->si_seq, cb->s_rack)) {
66821496Ssklower 				if ((sb->sb_flags & SB_WAIT)
66921496Ssklower 				     || so->so_snd.sb_sel)
67021496Ssklower 					 sowwakeup(so);
67121496Ssklower 				sbdroprecord(sb);
67221496Ssklower 				si = 0;
67321496Ssklower 				continue;
67421496Ssklower 			}
67521496Ssklower 			if (SSEQ_LT(si->si_seq, lookfor))
67621496Ssklower 				continue;
67721496Ssklower 			break;
67821496Ssklower 		}
67924330Ssklower 		if (si && (si->si_seq != lookfor))
68024330Ssklower 			si = 0;
68121496Ssklower 	}
68221496Ssklower 	cb->s_want = lookfor;
68321496Ssklower 
68421496Ssklower 	if (si) {
68521496Ssklower 		/*
68621496Ssklower 		 * must make a copy of this packet for
68721496Ssklower 		 * idp_output to monkey with
68821496Ssklower 		 */
68924330Ssklower 		 m = m_copy(dtom(si), 0, (int)M_COPYALL);
69024330Ssklower 		 if (m == NULL)
69123515Ssklower 			return (ENOBUFS);
69223515Ssklower 		 m0 = m;
69321496Ssklower 		 si = mtod(m, struct spidp *);
69421496Ssklower 	} else if (cb->s_force || cb->s_flags & SF_AK) {
69521496Ssklower 		/*
69621496Ssklower 		 * Must send an acknowledgement or a probe
69721496Ssklower 		 */
69821496Ssklower 		m = m_get(M_DONTWAIT, MT_HEADER);
69921496Ssklower 		if (m == 0)
70023515Ssklower 			return (ENOBUFS);
70121496Ssklower 		/*
70221496Ssklower 		 * Fill in mbuf with extended SP header
70321496Ssklower 		 * and addresses and length put into network format.
70421496Ssklower 		 */
70521496Ssklower 		m->m_off = MMAXOFF - sizeof (struct spidp);
70621496Ssklower 		m->m_len = sizeof (*si);
70721496Ssklower 		m->m_next = 0;
70821496Ssklower 		si = mtod(m, struct spidp *);
70921496Ssklower 		*si = cb->s_shdr;
71021496Ssklower 		si->si_seq = cb->s_snt + 1;
71123979Ssklower 		si->si_len = htons(sizeof (*si));
71221496Ssklower 		si->si_cc |= SP_SP;
71321496Ssklower 	}
71421496Ssklower 	/*
71521496Ssklower 	 * Stuff checksum and output datagram.
71621496Ssklower 	 */
71721496Ssklower 	if (si) {
71825037Ssklower 		if (cb->s_flags & (SF_AK|SF_DELACK))
71925037Ssklower 			cb->s_flags &= ~(SF_AK|SF_DELACK);
72021496Ssklower 		/*
72121496Ssklower 		 * If we are almost out of allocation
72221496Ssklower 		 * or one of the timers has gone off
72321496Ssklower 		 * request an ack.
72421496Ssklower 		 */
72524330Ssklower 		if (SSEQ_GEQ(cb->s_seq, cb->s_ralo))
72621496Ssklower 			si->si_cc |= SP_SA;
72721496Ssklower 		if (cb->s_force) {
72821496Ssklower 			si->si_cc |= SP_SA;
72921496Ssklower 			cb->s_force = 0;
73021496Ssklower 		}
73124330Ssklower 		/*
73224330Ssklower 		 * If this is a new packet (and not a system packet),
73323979Ssklower 		 * and we are not currently timing anything,
73423979Ssklower 		 * time this one and ask for an ack.
73521496Ssklower 		 */
73624330Ssklower 		if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) {
73721496Ssklower 			cb->s_snt = si->si_seq;
73824330Ssklower 			if (cb->s_rtt == 0) {
73921496Ssklower 				cb->s_rtseq = si->si_seq;
74021496Ssklower 				cb->s_rtt = 1;
74121496Ssklower 				si->si_cc |= SP_SA;
74221496Ssklower 			}
74321496Ssklower 			/*
74421496Ssklower 			 * If the retransmit timer has not been set
74521496Ssklower 			 * and this is a real packet
74621496Ssklower 			 * then start the retransmit timer
74721496Ssklower 			 */
74824330Ssklower 			if (cb->s_timer[TCPT_REXMT] == 0) {
74921496Ssklower 				TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
75021496Ssklower 					tcp_beta * cb->s_srtt, TCPTV_MIN,
75121496Ssklower 					TCPTV_MAX);
75221496Ssklower 				cb->s_rxtshift = 0;
75321496Ssklower 			}
75421496Ssklower 		}
75521496Ssklower 		si->si_seq = htons(si->si_seq);
75621496Ssklower 		si->si_alo = htons(cb->s_alo);
75721496Ssklower 		si->si_ack = htons(cb->s_ack);
75821496Ssklower 
75921496Ssklower 		if (idpcksum) {
76021496Ssklower 			si->si_sum = 0;
76123979Ssklower 			len = ntohs(si->si_len);
76224330Ssklower 			if (len & 1)
76324330Ssklower 				len++;
76421496Ssklower 			si->si_sum = ns_cksum(dtom(si), len);
76521496Ssklower 		} else
76621496Ssklower 			si->si_sum = 0xffff;
76721496Ssklower 
76821496Ssklower 		if (so->so_options & SO_DEBUG || traceallspps)
76921496Ssklower 			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
77021496Ssklower 		spp_output_cnt++;
77121496Ssklower 		if (so->so_options & SO_DONTROUTE)
77221496Ssklower 			error = ns_output(m, (struct route *)0, NS_ROUTETOIF);
77321496Ssklower 		else
77421496Ssklower 			error = ns_output(m, &cb->s_nspcb->nsp_route, 0);
77521496Ssklower 		if (traceallspps && sppconsdebug) {
77621496Ssklower 			printf("spp_out: %x\n", error);
77721496Ssklower 		}
77825168Ssklower 		if (so->so_options & SO_DEBUG || traceallspps)
77925168Ssklower 			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
78021496Ssklower 	}
78123515Ssklower 	return (error);
78221496Ssklower }
78321496Ssklower 
78421496Ssklower /*ARGSUSED*/
78521496Ssklower spp_ctloutput(req, so, level, name, value)
78621496Ssklower 	int req;
78721496Ssklower 	struct socket *so;
78821496Ssklower 	int name;
78921496Ssklower 	struct mbuf **value;
79021496Ssklower {
79121496Ssklower 	register struct mbuf *m;
79221496Ssklower 	struct nspcb *nsp = sotonspcb(so);
79321496Ssklower 	register struct sppcb *cb;
79421496Ssklower 	int mask, error = 0;
79521496Ssklower 
79621496Ssklower 	if (level != NSPROTO_SPP) {
79721496Ssklower 		/* This will have to be changed when we do more general
79821496Ssklower 		   stacking of protocols */
79923515Ssklower 		return (idp_ctloutput(req, so, level, name, value));
80021496Ssklower 	}
80121496Ssklower 	if (nsp == NULL) {
80221496Ssklower 		error = EINVAL;
80321496Ssklower 		goto release;
80421496Ssklower 	} else
80521496Ssklower 		cb = nstosppcb(nsp);
80621496Ssklower 
80721496Ssklower 	switch (req) {
80823515Ssklower 
80921496Ssklower 	case PRCO_GETOPT:
81024330Ssklower 		if (value == NULL)
81123515Ssklower 			return (EINVAL);
81221496Ssklower 		m = m_get(M_DONTWAIT, MT_DATA);
81324330Ssklower 		if (m == NULL)
81423515Ssklower 			return (ENOBUFS);
81521496Ssklower 		switch (name) {
81623515Ssklower 
81721496Ssklower 		case SO_HEADERS_ON_INPUT:
81821496Ssklower 			mask = SF_HI;
81921496Ssklower 			goto get_flags;
82023515Ssklower 
82121496Ssklower 		case SO_HEADERS_ON_OUTPUT:
82221496Ssklower 			mask = SF_HO;
82321496Ssklower 		get_flags:
82421496Ssklower 			m->m_len = sizeof(short);
82521496Ssklower 			m->m_off = MMAXOFF - sizeof(short);
82621496Ssklower 			*mtod(m, short *) = cb->s_flags & mask;
82721496Ssklower 			break;
82823515Ssklower 
82924615Ssklower 		case SO_MTU:
83024615Ssklower 			m->m_len = sizeof(u_short);
83124615Ssklower 			m->m_off = MMAXOFF - sizeof(short);
83224615Ssklower 			*mtod(m, short *) = cb->s_mtu;
83324615Ssklower 			break;
83424615Ssklower 
83521496Ssklower 		case SO_LAST_HEADER:
83621496Ssklower 			m->m_len = sizeof(struct sphdr);
83721496Ssklower 			m->m_off = MMAXOFF - sizeof(struct sphdr);
83821496Ssklower 			*mtod(m, struct sphdr *) = cb->s_rhdr;
83921496Ssklower 			break;
84023515Ssklower 
84121496Ssklower 		case SO_DEFAULT_HEADERS:
84221496Ssklower 			m->m_len = sizeof(struct spidp);
84321496Ssklower 			m->m_off = MMAXOFF - sizeof(struct sphdr);
84421496Ssklower 			*mtod(m, struct sphdr *) = cb->s_shdr.si_s;
84525334Ssklower 			break;
84625334Ssklower 
84725334Ssklower 		default:
84825334Ssklower 			error = EINVAL;
84921496Ssklower 		}
85021496Ssklower 		*value = m;
85121496Ssklower 		break;
85223515Ssklower 
85321496Ssklower 	case PRCO_SETOPT:
85424615Ssklower 		if (value == 0 || *value == 0) {
85524615Ssklower 			error = EINVAL;
85624615Ssklower 			break;
85724615Ssklower 		}
85821496Ssklower 		switch (name) {
85924225Ssklower 			int *ok;
86021496Ssklower 
86121496Ssklower 		case SO_HEADERS_ON_INPUT:
86221496Ssklower 			mask = SF_HI;
86321496Ssklower 			goto set_head;
86423515Ssklower 
86521496Ssklower 		case SO_HEADERS_ON_OUTPUT:
86621496Ssklower 			mask = SF_HO;
86721496Ssklower 		set_head:
86824615Ssklower 			if (cb->s_flags & SF_PI) {
86921496Ssklower 				ok = mtod(*value, int *);
87021496Ssklower 				if (*ok)
87121496Ssklower 					cb->s_flags |= mask;
87221496Ssklower 				else
87321496Ssklower 					cb->s_flags &= ~mask;
87421496Ssklower 			} else error = EINVAL;
87521496Ssklower 			break;
87623515Ssklower 
87724615Ssklower 		case SO_MTU:
87824615Ssklower 			cb->s_mtu = *(mtod(*value, u_short *));
87924615Ssklower 			break;
88024615Ssklower 
88121496Ssklower 		case SO_DEFAULT_HEADERS:
88221496Ssklower 			{
88321496Ssklower 				register struct sphdr *sp
88421496Ssklower 						= mtod(*value, struct sphdr *);
88521496Ssklower 				cb->s_dt = sp->sp_dt;
88621496Ssklower 				cb->s_cc = sp->sp_cc & SP_EM;
88721496Ssklower 			}
88825334Ssklower 			break;
88925334Ssklower 
89025334Ssklower 		default:
89125334Ssklower 			error = EINVAL;
89221496Ssklower 		}
89324615Ssklower 		m_freem(*value);
89421496Ssklower 		break;
89521496Ssklower 	}
89621496Ssklower 	release:
89723515Ssklower 		return (error);
89821496Ssklower }
89921496Ssklower 
90021496Ssklower /*ARGSUSED*/
90121496Ssklower spp_usrreq(so, req, m, nam, rights)
90221496Ssklower 	struct socket *so;
90321496Ssklower 	int req;
90421496Ssklower 	struct mbuf *m, *nam, *rights;
90521496Ssklower {
90621496Ssklower 	struct nspcb *nsp = sotonspcb(so);
90721496Ssklower 	register struct sppcb *cb;
90821496Ssklower 	int s = splnet();
90921496Ssklower 	int error = 0, ostate;
91021496Ssklower 
91121496Ssklower 	if (req == PRU_CONTROL)
91221496Ssklower                 return (ns_control(so, (int)m, (caddr_t)nam,
91321496Ssklower 			(struct ifnet *)rights));
91421496Ssklower 	if (rights && rights->m_len) {
91521496Ssklower 		error = EINVAL;
91621496Ssklower 		goto release;
91721496Ssklower 	}
91821496Ssklower 	if (nsp == NULL) {
91921496Ssklower 		if (req != PRU_ATTACH) {
92021496Ssklower 			error = EINVAL;
92121496Ssklower 			goto release;
92221496Ssklower 		}
92321496Ssklower 	} else
92421496Ssklower 		cb = nstosppcb(nsp);
92521496Ssklower 
92621496Ssklower 	ostate = cb ? cb->s_state : 0;
92721496Ssklower 
92821496Ssklower 	switch (req) {
92923515Ssklower 
93021496Ssklower 	case PRU_ATTACH:
93121496Ssklower 		if (nsp != NULL) {
93221496Ssklower 			error = EISCONN;
93321496Ssklower 			break;
93421496Ssklower 		}
93521496Ssklower 		error = ns_pcballoc(so, &nspcb);
93621496Ssklower 		if (error)
93721496Ssklower 			break;
93821496Ssklower 		error = soreserve(so, 2048, 2048);
93921496Ssklower 		if (error)
94021496Ssklower 			break;
94121496Ssklower 		nsp = sotonspcb(so);
94221496Ssklower 		{
94325037Ssklower 			struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB);
94421496Ssklower 
94524330Ssklower 			if (mm == NULL) {
94621496Ssklower 				error = ENOBUFS;
94721496Ssklower 				break;
94821496Ssklower 			}
94921496Ssklower 			cb = mtod(mm, struct sppcb *);
95021496Ssklower 			cb->s_state = TCPS_LISTEN;
95121496Ssklower 			cb->s_snt = -1;
95221496Ssklower 			cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
95321496Ssklower 			cb->s_nspcb = nsp;
95421496Ssklower 			nsp->nsp_pcb = (caddr_t) cb;
95521496Ssklower 		}
95621496Ssklower 		break;
95721496Ssklower 
95821496Ssklower 	case PRU_DETACH:
95921496Ssklower 		if (nsp == NULL) {
96021496Ssklower 			error = ENOTCONN;
96121496Ssklower 			break;
96221496Ssklower 		}
96321496Ssklower 		if (cb->s_state > TCPS_LISTEN)
96421496Ssklower 			cb = spp_disconnect(cb);
96521496Ssklower 		else
96621496Ssklower 			cb = spp_close(cb);
96721496Ssklower 		break;
96821496Ssklower 
96921496Ssklower 	case PRU_BIND:
97021496Ssklower 		error = ns_pcbbind(nsp, nam);
97121496Ssklower 		break;
97221496Ssklower 
97321496Ssklower 	case PRU_LISTEN:
97421496Ssklower 		if (nsp->nsp_lport == 0)
97521496Ssklower 			error = ns_pcbbind(nsp, (struct mbuf *)0);
97621496Ssklower 		if (error == 0)
97721496Ssklower 			cb->s_state = TCPS_LISTEN;
97821496Ssklower 		break;
97921496Ssklower 
98021496Ssklower 	/*
98121496Ssklower 	 * Initiate connection to peer.
98221496Ssklower 	 * Enter SYN_SENT state, and mark socket as connecting.
98321496Ssklower 	 * Start keep-alive timer, setup prototype header,
98421496Ssklower 	 * Send initial system packet requesting connection.
98521496Ssklower 	 */
98621496Ssklower 	case PRU_CONNECT:
98721496Ssklower 		if (nsp->nsp_lport == 0) {
98821496Ssklower 			error = ns_pcbbind(nsp, (struct mbuf *)0);
98921496Ssklower 			if (error)
99021496Ssklower 				break;
99121496Ssklower 		}
99221496Ssklower 		error = ns_pcbconnect(nsp, nam);
99321496Ssklower 		if (error)
99421496Ssklower 			break;
99521496Ssklower 		soisconnecting(so);
99621496Ssklower 		cb->s_state = TCPS_SYN_SENT;
99721496Ssklower 		cb->s_did = 0;
99821496Ssklower 		spp_template(cb);
99921496Ssklower 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
100021496Ssklower 		cb->s_force = 1 + TCPTV_KEEP;
100121496Ssklower 		/*
100221496Ssklower 		 * Other party is required to respond to
100321496Ssklower 		 * the port I send from, but he is not
100421496Ssklower 		 * required to answer from where I am sending to,
100521496Ssklower 		 * so allow wildcarding.
100621496Ssklower 		 * original port I am sending to is still saved in
100721496Ssklower 		 * cb->s_dport.
100821496Ssklower 		 */
100921496Ssklower 		nsp->nsp_fport = 0;
101021496Ssklower 		error = spp_output(cb, (struct mbuf *) 0);
101121496Ssklower 		break;
101221496Ssklower 
101321496Ssklower 	case PRU_CONNECT2:
101421496Ssklower 		error = EOPNOTSUPP;
101521496Ssklower 		break;
101621496Ssklower 
101721496Ssklower 	/*
101821496Ssklower 	 * We may decide later to implement connection closing
101921496Ssklower 	 * handshaking at the spp level optionally.
102021496Ssklower 	 * here is the hook to do it:
102121496Ssklower 	 */
102221496Ssklower 	case PRU_DISCONNECT:
102321496Ssklower 		cb = spp_disconnect(cb);
102421496Ssklower 		break;
102521496Ssklower 
102621496Ssklower 	/*
102721496Ssklower 	 * Accept a connection.  Essentially all the work is
102821496Ssklower 	 * done at higher levels; just return the address
102921496Ssklower 	 * of the peer, storing through addr.
103021496Ssklower 	 */
103121496Ssklower 	case PRU_ACCEPT: {
103221496Ssklower 		struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
103321496Ssklower 
103421496Ssklower 		nam->m_len = sizeof (struct sockaddr_ns);
103521496Ssklower 		sns->sns_family = AF_NS;
103621496Ssklower 		sns->sns_addr = nsp->nsp_faddr;
103721496Ssklower 		break;
103821496Ssklower 		}
103921496Ssklower 
104021496Ssklower 	case PRU_SHUTDOWN:
104121496Ssklower 		socantsendmore(so);
104221496Ssklower 		cb = spp_usrclosed(cb);
104321496Ssklower 		if (cb)
104421496Ssklower 			error = spp_output(cb, (struct mbuf *) 0);
104521496Ssklower 		break;
104621496Ssklower 
104721496Ssklower 	/*
104821496Ssklower 	 * After a receive, possibly send acknowledgment
104921496Ssklower 	 * updating allocation.
105021496Ssklower 	 */
105121496Ssklower 	case PRU_RCVD:
105221496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
105321496Ssklower 		break;
105421496Ssklower 
105521496Ssklower 	case PRU_ABORT:
105624225Ssklower 		(void) spp_drop(cb, ECONNABORTED);
105721496Ssklower 		break;
105821496Ssklower 
105921496Ssklower 	case PRU_SENSE:
106021496Ssklower 	case PRU_CONTROL:
106121496Ssklower 		m = NULL;
106221496Ssklower 		error = EOPNOTSUPP;
106321496Ssklower 		break;
106421496Ssklower 
106521496Ssklower 	case PRU_RCVOOB:
106625037Ssklower 		if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
106725037Ssklower 		    (so->so_state & SS_RCVATMARK)) {
106825037Ssklower 			m->m_len = 1;
106925037Ssklower 			*mtod(m, caddr_t) = cb->s_iobc;
107024732Ssklower 			break;
107124732Ssklower 		}
107225037Ssklower 		error = EINVAL;
107321496Ssklower 		break;
107421496Ssklower 
107521496Ssklower 	case PRU_SENDOOB:
107621496Ssklower 		if (sbspace(&so->so_snd) < -512) {
107721496Ssklower 			error = ENOBUFS;
107821496Ssklower 			break;
107921496Ssklower 		}
108021496Ssklower 		cb->s_oobflags |= SF_SOOB;
1081*25623Ssklower 		/* fall into */
1082*25623Ssklower 	case PRU_SEND:
108321496Ssklower 		error = spp_output(cb, m);
108421496Ssklower 		m = NULL;
108521496Ssklower 		break;
108621496Ssklower 
108721496Ssklower 	case PRU_SOCKADDR:
108821496Ssklower 		ns_setsockaddr(nsp, nam);
108921496Ssklower 		break;
109021496Ssklower 
109121496Ssklower 	case PRU_PEERADDR:
109221496Ssklower 		ns_setpeeraddr(nsp, nam);
109321496Ssklower 		break;
109421496Ssklower 
109521496Ssklower 	case PRU_SLOWTIMO:
109621496Ssklower 		cb = spp_timers(cb, (int)nam);
109721496Ssklower 		break;
109821496Ssklower 
109921496Ssklower 	case PRU_FASTTIMO:
110021496Ssklower 	case PRU_PROTORCV:
110121496Ssklower 	case PRU_PROTOSEND:
110221496Ssklower 		error =  EOPNOTSUPP;
110321496Ssklower 		break;
110421496Ssklower 
110521496Ssklower 	default:
110621496Ssklower 		panic("sp_usrreq");
110721496Ssklower 	}
110821496Ssklower 	if (cb && (so->so_options & SO_DEBUG || traceallspps))
110924225Ssklower 		spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
111021496Ssklower release:
111121496Ssklower 	if (m != NULL)
111221496Ssklower 		m_freem(m);
111321496Ssklower 	splx(s);
111421496Ssklower 	return (error);
111521496Ssklower }
111621496Ssklower 
111721496Ssklower spp_usrreq_sp(so, req, m, nam, rights)
111821496Ssklower 	struct socket *so;
111921496Ssklower 	int req;
112021496Ssklower 	struct mbuf *m, *nam, *rights;
112121496Ssklower {
112221496Ssklower 	int error = spp_usrreq(so, req, m, nam, rights);
112321496Ssklower 
112424330Ssklower 	if (req == PRU_ATTACH && error == 0) {
112521496Ssklower 		struct nspcb *nsp = sotonspcb(so);
112621496Ssklower 		((struct sppcb *)nsp->nsp_pcb)->s_flags |=
112721496Ssklower 					(SF_HI | SF_HO | SF_PI);
112821496Ssklower 	}
112923515Ssklower 	return (error);
113021496Ssklower }
113121496Ssklower 
113221496Ssklower /*
113321496Ssklower  * Create template to be used to send spp packets on a connection.
113421496Ssklower  * Called after host entry created, fills
113521496Ssklower  * in a skeletal spp header (choosing connection id),
113621496Ssklower  * minimizing the amount of work necessary when the connection is used.
113721496Ssklower  */
113821496Ssklower spp_template(cb)
113921496Ssklower 	struct sppcb *cb;
114021496Ssklower {
114121496Ssklower 	register struct nspcb *nsp = cb->s_nspcb;
114221496Ssklower 	register struct spidp *n = &(cb->s_shdr);
114321496Ssklower 
114424615Ssklower 	cb->s_mtu = 576 - sizeof (struct spidp);
114521496Ssklower 	n->si_pt = NSPROTO_SPP;
114621496Ssklower 	n->si_sna = nsp->nsp_laddr;
114721496Ssklower 	n->si_dna = nsp->nsp_faddr;
114821496Ssklower 	n->si_sid = htons(spp_iss);
114921496Ssklower 	spp_iss += SPP_ISSINCR/2;
115021496Ssklower 	n->si_alo = 1;
115121496Ssklower }
115221496Ssklower 
115321496Ssklower /*
115421496Ssklower  * Close a SPIP control block:
115521496Ssklower  *	discard spp control block itself
115621496Ssklower  *	discard ns protocol control block
115721496Ssklower  *	wake up any sleepers
115821496Ssklower  */
115921496Ssklower struct sppcb *
116021496Ssklower spp_close(cb)
116121496Ssklower 	register struct sppcb *cb;
116221496Ssklower {
116321496Ssklower 	register struct spidp_q *s;
116421496Ssklower 	struct nspcb *nsp = cb->s_nspcb;
116521496Ssklower 	struct socket *so = nsp->nsp_socket;
116621496Ssklower 	register struct mbuf *m;
116721496Ssklower 
116821496Ssklower 	s = cb->s_q.si_next;
116921496Ssklower 	while (s != &(cb->s_q)) {
117021496Ssklower 		s = s->si_next;
117121496Ssklower 		m = dtom(s->si_prev);
117221496Ssklower 		remque(s->si_prev);
117321496Ssklower 		m_freem(m);
117421496Ssklower 	}
117521496Ssklower 	(void) m_free(dtom(cb));
117621496Ssklower 	nsp->nsp_pcb = 0;
117721496Ssklower 	soisdisconnected(so);
117821496Ssklower 	ns_pcbdetach(nsp);
117923515Ssklower 	return ((struct sppcb *)0);
118021496Ssklower }
118121496Ssklower /*
118221496Ssklower  *	Someday we may do level 3 handshaking
118321496Ssklower  *	to close a connection or send a xerox style error.
118421496Ssklower  *	For now, just close.
118521496Ssklower  */
118621496Ssklower struct sppcb *
118721496Ssklower spp_usrclosed(cb)
118821496Ssklower 	register struct sppcb *cb;
118921496Ssklower {
119023515Ssklower 	return (spp_close(cb));
119121496Ssklower }
119221496Ssklower struct sppcb *
119321496Ssklower spp_disconnect(cb)
119421496Ssklower 	register struct sppcb *cb;
119521496Ssklower {
119623515Ssklower 	return (spp_close(cb));
119721496Ssklower }
119821496Ssklower /*
119921496Ssklower  * Drop connection, reporting
120021496Ssklower  * the specified error.
120121496Ssklower  */
120221496Ssklower struct sppcb *
120321496Ssklower spp_drop(cb, errno)
120421496Ssklower 	register struct sppcb *cb;
120521496Ssklower 	int errno;
120621496Ssklower {
120721496Ssklower 	struct socket *so = cb->s_nspcb->nsp_socket;
120821496Ssklower 
120921496Ssklower 	/*
121021496Ssklower 	 * someday, in the xerox world
121121496Ssklower 	 * we will generate error protocol packets
121221496Ssklower 	 * announcing that the socket has gone away.
121321496Ssklower 	 */
121421496Ssklower 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
121521496Ssklower 		tp->t_state = TCPS_CLOSED;
121621496Ssklower 		(void) tcp_output(tp);
121721496Ssklower 	}*/
121821496Ssklower 	so->so_error = errno;
121921496Ssklower 	return (spp_close(cb));
122021496Ssklower }
122121496Ssklower 
122221496Ssklower spp_abort(nsp)
122321496Ssklower 	struct nspcb *nsp;
122421496Ssklower {
122521496Ssklower 
122624225Ssklower 	(void) spp_close((struct sppcb *)nsp->nsp_pcb);
122721496Ssklower }
122821496Ssklower 
122921496Ssklower spp_setpersist(cb)
123021496Ssklower 	register struct sppcb *cb;
123121496Ssklower {
123221496Ssklower 
123321496Ssklower 	/*if (cb->s_timer[TCPT_REXMT])
123421496Ssklower 		panic("spp_output REXMT");*/
123521496Ssklower 	/*
123621496Ssklower 	 * Start/restart persistance timer.
123721496Ssklower 	 */
123821496Ssklower 	TCPT_RANGESET(cb->s_timer[TCPT_PERSIST],
123921496Ssklower 	    ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift,
124021496Ssklower 	    TCPTV_PERSMIN, TCPTV_MAX);
124121496Ssklower 	cb->s_rxtshift++;
124221496Ssklower 	if (cb->s_rxtshift >= TCP_MAXRXTSHIFT)
124321496Ssklower 		cb->s_rxtshift = 0;
124421496Ssklower }
124521496Ssklower /*
124621496Ssklower  * Fast timeout routine for processing delayed acks
124721496Ssklower  */
124821496Ssklower int spp_ftcnt;
124921496Ssklower spp_fasttimo()
125021496Ssklower {
125121496Ssklower 	register struct nspcb *nsp;
125221496Ssklower 	register struct sppcb *cb;
125321496Ssklower 	int s = splnet();
125421496Ssklower 
125521496Ssklower 	nsp = nspcb.nsp_next;
125621496Ssklower 	spp_ftcnt++;
125721496Ssklower 	if (nsp)
125821496Ssklower 	for (; nsp != &nspcb; nsp = nsp->nsp_next)
125921496Ssklower 		if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
126021496Ssklower 		    (cb->s_flags & SF_DELACK)) {
126121496Ssklower 			cb->s_flags &= ~SF_DELACK;
126221496Ssklower 			cb->s_flags |= SF_AK;
126321496Ssklower 			(void) spp_output(cb, (struct mbuf *) 0);
126421496Ssklower 		}
126521496Ssklower 	splx(s);
126621496Ssklower }
126721496Ssklower 
126821496Ssklower /*
126921496Ssklower  * spp protocol timeout routine called every 500 ms.
127021496Ssklower  * Updates the timers in all active pcb's and
127121496Ssklower  * causes finite state machine actions if timers expire.
127221496Ssklower  */
127321496Ssklower spp_slowtimo()
127421496Ssklower {
127521496Ssklower 	register struct nspcb *ip, *ipnxt;
127621496Ssklower 	register struct sppcb *cb;
127721496Ssklower 	int s = splnet();
127821496Ssklower 	register int i;
127921496Ssklower 
128021496Ssklower 	/*
128121496Ssklower 	 * Search through tcb's and update active timers.
128221496Ssklower 	 */
128321496Ssklower 	ip = nspcb.nsp_next;
128421496Ssklower 	if (ip == 0) {
128521496Ssklower 		splx(s);
128621496Ssklower 		return;
128721496Ssklower 	}
128821496Ssklower 	while (ip != &nspcb) {
128921496Ssklower 		cb = nstosppcb(ip);
129021496Ssklower 		ipnxt = ip->nsp_next;
129121496Ssklower 		if (cb == 0)
129221496Ssklower 			goto tpgone;
129321496Ssklower 		for (i = 0; i < TCPT_NTIMERS; i++) {
129421496Ssklower 			if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
129521496Ssklower 				(void) spp_usrreq(cb->s_nspcb->nsp_socket,
129621496Ssklower 				    PRU_SLOWTIMO, (struct mbuf *)0,
129721496Ssklower 				    (struct mbuf *)i, (struct mbuf *)0);
129821496Ssklower 				if (ipnxt->nsp_prev != ip)
129921496Ssklower 					goto tpgone;
130021496Ssklower 			}
130121496Ssklower 		}
130221496Ssklower 		cb->s_idle++;
130321496Ssklower 		if (cb->s_rtt)
130421496Ssklower 			cb->s_rtt++;
130521496Ssklower tpgone:
130621496Ssklower 		ip = ipnxt;
130721496Ssklower 	}
130821496Ssklower 	spp_iss += SPP_ISSINCR/PR_SLOWHZ;		/* increment iss */
130921496Ssklower 	splx(s);
131021496Ssklower }
131121496Ssklower 
131221496Ssklower float	spp_backoff[TCP_MAXRXTSHIFT] =
131321496Ssklower     { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 };
131424412Swalsh int sppexprexmtbackoff = 0;
131521496Ssklower /*
131624615Ssklower  * SPP timer processing.
131721496Ssklower  */
131821496Ssklower struct sppcb *
131921496Ssklower spp_timers(cb, timer)
132021496Ssklower 	register struct sppcb *cb;
132121496Ssklower 	int timer;
132221496Ssklower {
132321496Ssklower 
132421496Ssklower 	cb->s_force = 1 + timer;
132521496Ssklower 	switch (timer) {
132621496Ssklower 
132721496Ssklower 	/*
132821496Ssklower 	 * 2 MSL timeout in shutdown went off.  Delete connection
132921496Ssklower 	 * control block.
133021496Ssklower 	 */
133121496Ssklower 	case TCPT_2MSL:
133221496Ssklower 		cb = spp_close(cb);
133321496Ssklower 		break;
133421496Ssklower 
133521496Ssklower 	/*
133621496Ssklower 	 * Retransmission timer went off.  Message has not
133721496Ssklower 	 * been acked within retransmit interval.  Back off
133821496Ssklower 	 * to a longer retransmit interval and retransmit all
133921496Ssklower 	 * unacknowledged messages in the window.
134021496Ssklower 	 */
134121496Ssklower 	case TCPT_REXMT:
134221496Ssklower 		cb->s_rxtshift++;
134321496Ssklower 		if (cb->s_rxtshift > TCP_MAXRXTSHIFT) {
134421496Ssklower 			cb = spp_drop(cb, ETIMEDOUT);
134521496Ssklower 			break;
134621496Ssklower 		}
134721496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
134821496Ssklower 		TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
134921496Ssklower 		    (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX);
135024412Swalsh 		if (sppexprexmtbackoff) {
135121496Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
135221496Ssklower 			    cb->s_timer[TCPT_REXMT] << cb->s_rxtshift,
135321496Ssklower 			    TCPTV_MIN, TCPTV_MAX);
135421496Ssklower 		} else {
135521496Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
135621496Ssklower 			    cb->s_timer[TCPT_REXMT] *
135721496Ssklower 			        spp_backoff[cb->s_rxtshift - 1],
135821496Ssklower 			    TCPTV_MIN, TCPTV_MAX);
135921496Ssklower 		}
136021496Ssklower 		break;
136121496Ssklower 
136221496Ssklower 	/*
136321496Ssklower 	 * Persistance timer into zero window.
136421496Ssklower 	 * Force a probe to be sent.
136521496Ssklower 	 */
136621496Ssklower 	case TCPT_PERSIST:
136721496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
136821496Ssklower 		spp_setpersist(cb);
136921496Ssklower 		break;
137021496Ssklower 
137121496Ssklower 	/*
137221496Ssklower 	 * Keep-alive timer went off; send something
137321496Ssklower 	 * or drop connection if idle for too long.
137421496Ssklower 	 */
137521496Ssklower 	case TCPT_KEEP:
137621496Ssklower 		if (cb->s_state < TCPS_ESTABLISHED)
137721496Ssklower 			goto dropit;
137821496Ssklower 		if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
137921496Ssklower 		    	if (cb->s_idle >= TCPTV_MAXIDLE)
138021496Ssklower 				goto dropit;
138121496Ssklower 			(void) spp_output(cb, (struct mbuf *) 0);
138221496Ssklower 		} else
138321496Ssklower 			cb->s_idle = 0;
138421496Ssklower 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
138521496Ssklower 		break;
138621496Ssklower 	dropit:
138721496Ssklower 		cb = spp_drop(cb, ETIMEDOUT);
138821496Ssklower 		break;
138921496Ssklower 	}
139021496Ssklower 	return (cb);
139121496Ssklower }
1392