xref: /csrg-svn/sys/netns/spp_usrreq.c (revision 25334)
123215Smckusick /*
2*25334Ssklower  * 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*25334Ssklower  *	@(#)spp_usrreq.c	6.15 (Berkeley) 10/30/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)) {
209*25334Ssklower 		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.
56821496Ssklower 		 */
56921496Ssklower 		m->m_off = MMAXOFF - sizeof (struct spidp);
57021496Ssklower 		m->m_len = sizeof (struct spidp);
57121496Ssklower 		m->m_next = m0;
57221496Ssklower 		si = mtod(m, struct spidp *);
57321496Ssklower 		*si = cb->s_shdr;
57421496Ssklower 		if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
57524330Ssklower 			register struct sphdr *sh;
57624330Ssklower 			if (m0->m_len < sizeof (*sh)) {
57724330Ssklower 				if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
57824330Ssklower 					(void) m_free(m);
57924330Ssklower 					m_freem(m0);
58024330Ssklower 					return (EINVAL);
58124330Ssklower 				}
58224330Ssklower 				m->m_next = m0;
58324330Ssklower 			}
58424330Ssklower 			sh = mtod(m0, struct sphdr *);
58521496Ssklower 			si->si_dt = sh->sp_dt;
58621496Ssklower 			si->si_cc |= sh->sp_cc & SP_EM;
58721496Ssklower 			m0->m_len -= sizeof (*sh);
58821496Ssklower 			m0->m_off += sizeof (*sh);
58921496Ssklower 			len -= sizeof (*sh);
59021496Ssklower 		}
59121496Ssklower 		len += sizeof(*si);
59223979Ssklower 		if (cb->s_oobflags & SF_SOOB) {
59323979Ssklower 			/*
59423979Ssklower 			 * Per jqj@cornell:
59523979Ssklower 			 * make sure OB packets convey exactly 1 byte.
59623979Ssklower 			 * If the packet is 1 byte or larger, we
59723979Ssklower 			 * have already guaranted there to be at least
59823979Ssklower 			 * one garbage byte for the checksum, and
59923979Ssklower 			 * extra bytes shouldn't hurt!
60023979Ssklower 			 */
60123979Ssklower 			if (len > sizeof(*si)) {
60223979Ssklower 				si->si_cc |= SP_OB;
60323979Ssklower 				len = (1 + sizeof(*si));
60423979Ssklower 			}
60523979Ssklower 		}
60624225Ssklower 		si->si_len = htons((u_short)len);
60721496Ssklower 		/*
60821496Ssklower 		 * queue stuff up for output
60921496Ssklower 		 */
61025037Ssklower 		sbappendrecord(sb, m);
61121496Ssklower 		cb->s_seq++;
61221496Ssklower 	}
61321496Ssklower 	/*
61421496Ssklower 	 * update window
61521496Ssklower 	 */
61621496Ssklower 	{
61724225Ssklower 		register struct sockbuf *sb2 = &so->so_rcv;
61824732Ssklower 		int credit = ((sb2->sb_mbmax - sb2->sb_mbcnt) /
61924732Ssklower 						((short)cb->s_mtu));
62024732Ssklower 		int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1;
62121496Ssklower 
62224732Ssklower 		if (cb->s_alo < alo) {
62324732Ssklower 			/* If the amount we are raising the window
62424732Ssklower 			   is more than his remaining headroom, tell
62524732Ssklower 			   him about it.  In particular, if he is at
62624732Ssklower 			   his limit, any amount at all will do! */
62724732Ssklower 			u_short raise = alo - cb->s_alo;
62824732Ssklower 			u_short headroom = 1 + cb->s_alo - cb->s_ack;
62924732Ssklower 
63024732Ssklower 			if(SSEQ_LT(headroom, raise))
63124732Ssklower 				cb->s_flags |= SF_AK;
63224330Ssklower 			cb->s_alo = alo;
63324732Ssklower 		}
63421496Ssklower 	}
63521496Ssklower 
63621496Ssklower 	if (cb->s_oobflags & SF_SOOB) {
63721496Ssklower 		/*
63821496Ssklower 		 * must transmit this out of band packet
63921496Ssklower 		 */
64021496Ssklower 		cb->s_oobflags &= ~ SF_SOOB;
64121496Ssklower 	} else {
64221496Ssklower 		/*
64321496Ssklower 		 * Decide what to transmit:
64425168Ssklower 		 * If it is time to retransmit a packet,
64525168Ssklower 		 * send that.
64621496Ssklower 		 * If we have a new packet, send that
64721496Ssklower 		 * (So long as it is in our allocation)
64821496Ssklower 		 * Otherwise, see if it time to bang on them
64921496Ssklower 		 * to ask for our current allocation.
65021496Ssklower 		 */
65125168Ssklower 		if (cb->s_force == (1+TCPT_REXMT)) {
65225168Ssklower 			lookfor = cb->s_rack;
65325168Ssklower 		} else if (SSEQ_LT(cb->s_snt, cb->s_ralo)) {
65421496Ssklower 			lookfor = cb->s_snt + 1;
65521496Ssklower 		} else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) {
65621496Ssklower 			lookfor = 0;
65724330Ssklower 			if (cb->s_timer[TCPT_PERSIST] == 0) {
65821496Ssklower 				spp_setpersist(cb);
65924330Ssklower 				/* tcp has cb->s_rxtshift = 0; here */
66021496Ssklower 			}
66121496Ssklower 		}
66221496Ssklower 		m = sb->sb_mb;
66324330Ssklower 		while (m) {
66421496Ssklower 			si = mtod(m, struct spidp *);
66521496Ssklower 			m = m->m_act;
66621496Ssklower 			if (SSEQ_LT(si->si_seq, cb->s_rack)) {
66721496Ssklower 				if ((sb->sb_flags & SB_WAIT)
66821496Ssklower 				     || so->so_snd.sb_sel)
66921496Ssklower 					 sowwakeup(so);
67021496Ssklower 				sbdroprecord(sb);
67121496Ssklower 				si = 0;
67221496Ssklower 				continue;
67321496Ssklower 			}
67421496Ssklower 			if (SSEQ_LT(si->si_seq, lookfor))
67521496Ssklower 				continue;
67621496Ssklower 			break;
67721496Ssklower 		}
67824330Ssklower 		if (si && (si->si_seq != lookfor))
67924330Ssklower 			si = 0;
68021496Ssklower 	}
68121496Ssklower 	cb->s_want = lookfor;
68221496Ssklower 
68321496Ssklower 	if (si) {
68421496Ssklower 		/*
68521496Ssklower 		 * must make a copy of this packet for
68621496Ssklower 		 * idp_output to monkey with
68721496Ssklower 		 */
68824330Ssklower 		 m = m_copy(dtom(si), 0, (int)M_COPYALL);
68924330Ssklower 		 if (m == NULL)
69023515Ssklower 			return (ENOBUFS);
69123515Ssklower 		 m0 = m;
69221496Ssklower 		 si = mtod(m, struct spidp *);
69321496Ssklower 	} else if (cb->s_force || cb->s_flags & SF_AK) {
69421496Ssklower 		/*
69521496Ssklower 		 * Must send an acknowledgement or a probe
69621496Ssklower 		 */
69721496Ssklower 		m = m_get(M_DONTWAIT, MT_HEADER);
69821496Ssklower 		if (m == 0)
69923515Ssklower 			return (ENOBUFS);
70021496Ssklower 		/*
70121496Ssklower 		 * Fill in mbuf with extended SP header
70221496Ssklower 		 * and addresses and length put into network format.
70321496Ssklower 		 */
70421496Ssklower 		m->m_off = MMAXOFF - sizeof (struct spidp);
70521496Ssklower 		m->m_len = sizeof (*si);
70621496Ssklower 		m->m_next = 0;
70721496Ssklower 		si = mtod(m, struct spidp *);
70821496Ssklower 		*si = cb->s_shdr;
70921496Ssklower 		si->si_seq = cb->s_snt + 1;
71023979Ssklower 		si->si_len = htons(sizeof (*si));
71121496Ssklower 		si->si_cc |= SP_SP;
71221496Ssklower 	}
71321496Ssklower 	/*
71421496Ssklower 	 * Stuff checksum and output datagram.
71521496Ssklower 	 */
71621496Ssklower 	if (si) {
71725037Ssklower 		if (cb->s_flags & (SF_AK|SF_DELACK))
71825037Ssklower 			cb->s_flags &= ~(SF_AK|SF_DELACK);
71921496Ssklower 		/*
72021496Ssklower 		 * If we are almost out of allocation
72121496Ssklower 		 * or one of the timers has gone off
72221496Ssklower 		 * request an ack.
72321496Ssklower 		 */
72424330Ssklower 		if (SSEQ_GEQ(cb->s_seq, cb->s_ralo))
72521496Ssklower 			si->si_cc |= SP_SA;
72621496Ssklower 		if (cb->s_force) {
72721496Ssklower 			si->si_cc |= SP_SA;
72821496Ssklower 			cb->s_force = 0;
72921496Ssklower 		}
73024330Ssklower 		/*
73124330Ssklower 		 * If this is a new packet (and not a system packet),
73223979Ssklower 		 * and we are not currently timing anything,
73323979Ssklower 		 * time this one and ask for an ack.
73421496Ssklower 		 */
73524330Ssklower 		if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) {
73621496Ssklower 			cb->s_snt = si->si_seq;
73724330Ssklower 			if (cb->s_rtt == 0) {
73821496Ssklower 				cb->s_rtseq = si->si_seq;
73921496Ssklower 				cb->s_rtt = 1;
74021496Ssklower 				si->si_cc |= SP_SA;
74121496Ssklower 			}
74221496Ssklower 			/*
74321496Ssklower 			 * If the retransmit timer has not been set
74421496Ssklower 			 * and this is a real packet
74521496Ssklower 			 * then start the retransmit timer
74621496Ssklower 			 */
74724330Ssklower 			if (cb->s_timer[TCPT_REXMT] == 0) {
74821496Ssklower 				TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
74921496Ssklower 					tcp_beta * cb->s_srtt, TCPTV_MIN,
75021496Ssklower 					TCPTV_MAX);
75121496Ssklower 				cb->s_rxtshift = 0;
75221496Ssklower 			}
75321496Ssklower 		}
75421496Ssklower 		si->si_seq = htons(si->si_seq);
75521496Ssklower 		si->si_alo = htons(cb->s_alo);
75621496Ssklower 		si->si_ack = htons(cb->s_ack);
75721496Ssklower 
75821496Ssklower 		if (idpcksum) {
75921496Ssklower 			si->si_sum = 0;
76023979Ssklower 			len = ntohs(si->si_len);
76124330Ssklower 			if (len & 1)
76224330Ssklower 				len++;
76321496Ssklower 			si->si_sum = ns_cksum(dtom(si), len);
76421496Ssklower 		} else
76521496Ssklower 			si->si_sum = 0xffff;
76621496Ssklower 
76721496Ssklower 		if (so->so_options & SO_DEBUG || traceallspps)
76821496Ssklower 			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
76921496Ssklower 		spp_output_cnt++;
77021496Ssklower 		if (so->so_options & SO_DONTROUTE)
77121496Ssklower 			error = ns_output(m, (struct route *)0, NS_ROUTETOIF);
77221496Ssklower 		else
77321496Ssklower 			error = ns_output(m, &cb->s_nspcb->nsp_route, 0);
77421496Ssklower 		if (traceallspps && sppconsdebug) {
77521496Ssklower 			printf("spp_out: %x\n", error);
77621496Ssklower 		}
77725168Ssklower 		if (so->so_options & SO_DEBUG || traceallspps)
77825168Ssklower 			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
77921496Ssklower 	}
78023515Ssklower 	return (error);
78121496Ssklower }
78221496Ssklower 
78321496Ssklower /*ARGSUSED*/
78421496Ssklower spp_ctloutput(req, so, level, name, value)
78521496Ssklower 	int req;
78621496Ssklower 	struct socket *so;
78721496Ssklower 	int name;
78821496Ssklower 	struct mbuf **value;
78921496Ssklower {
79021496Ssklower 	register struct mbuf *m;
79121496Ssklower 	struct nspcb *nsp = sotonspcb(so);
79221496Ssklower 	register struct sppcb *cb;
79321496Ssklower 	int mask, error = 0;
79421496Ssklower 
79521496Ssklower 	if (level != NSPROTO_SPP) {
79621496Ssklower 		/* This will have to be changed when we do more general
79721496Ssklower 		   stacking of protocols */
79823515Ssklower 		return (idp_ctloutput(req, so, level, name, value));
79921496Ssklower 	}
80021496Ssklower 	if (nsp == NULL) {
80121496Ssklower 		error = EINVAL;
80221496Ssklower 		goto release;
80321496Ssklower 	} else
80421496Ssklower 		cb = nstosppcb(nsp);
80521496Ssklower 
80621496Ssklower 	switch (req) {
80723515Ssklower 
80821496Ssklower 	case PRCO_GETOPT:
80924330Ssklower 		if (value == NULL)
81023515Ssklower 			return (EINVAL);
81121496Ssklower 		m = m_get(M_DONTWAIT, MT_DATA);
81224330Ssklower 		if (m == NULL)
81323515Ssklower 			return (ENOBUFS);
81421496Ssklower 		switch (name) {
81523515Ssklower 
81621496Ssklower 		case SO_HEADERS_ON_INPUT:
81721496Ssklower 			mask = SF_HI;
81821496Ssklower 			goto get_flags;
81923515Ssklower 
82021496Ssklower 		case SO_HEADERS_ON_OUTPUT:
82121496Ssklower 			mask = SF_HO;
82221496Ssklower 		get_flags:
82321496Ssklower 			m->m_len = sizeof(short);
82421496Ssklower 			m->m_off = MMAXOFF - sizeof(short);
82521496Ssklower 			*mtod(m, short *) = cb->s_flags & mask;
82621496Ssklower 			break;
82723515Ssklower 
82824615Ssklower 		case SO_MTU:
82924615Ssklower 			m->m_len = sizeof(u_short);
83024615Ssklower 			m->m_off = MMAXOFF - sizeof(short);
83124615Ssklower 			*mtod(m, short *) = cb->s_mtu;
83224615Ssklower 			break;
83324615Ssklower 
83421496Ssklower 		case SO_LAST_HEADER:
83521496Ssklower 			m->m_len = sizeof(struct sphdr);
83621496Ssklower 			m->m_off = MMAXOFF - sizeof(struct sphdr);
83721496Ssklower 			*mtod(m, struct sphdr *) = cb->s_rhdr;
83821496Ssklower 			break;
83923515Ssklower 
84021496Ssklower 		case SO_DEFAULT_HEADERS:
84121496Ssklower 			m->m_len = sizeof(struct spidp);
84221496Ssklower 			m->m_off = MMAXOFF - sizeof(struct sphdr);
84321496Ssklower 			*mtod(m, struct sphdr *) = cb->s_shdr.si_s;
844*25334Ssklower 			break;
845*25334Ssklower 
846*25334Ssklower 		default:
847*25334Ssklower 			error = EINVAL;
84821496Ssklower 		}
84921496Ssklower 		*value = m;
85021496Ssklower 		break;
85123515Ssklower 
85221496Ssklower 	case PRCO_SETOPT:
85324615Ssklower 		if (value == 0 || *value == 0) {
85424615Ssklower 			error = EINVAL;
85524615Ssklower 			break;
85624615Ssklower 		}
85721496Ssklower 		switch (name) {
85824225Ssklower 			int *ok;
85921496Ssklower 
86021496Ssklower 		case SO_HEADERS_ON_INPUT:
86121496Ssklower 			mask = SF_HI;
86221496Ssklower 			goto set_head;
86323515Ssklower 
86421496Ssklower 		case SO_HEADERS_ON_OUTPUT:
86521496Ssklower 			mask = SF_HO;
86621496Ssklower 		set_head:
86724615Ssklower 			if (cb->s_flags & SF_PI) {
86821496Ssklower 				ok = mtod(*value, int *);
86921496Ssklower 				if (*ok)
87021496Ssklower 					cb->s_flags |= mask;
87121496Ssklower 				else
87221496Ssklower 					cb->s_flags &= ~mask;
87321496Ssklower 			} else error = EINVAL;
87421496Ssklower 			break;
87523515Ssklower 
87624615Ssklower 		case SO_MTU:
87724615Ssklower 			cb->s_mtu = *(mtod(*value, u_short *));
87824615Ssklower 			break;
87924615Ssklower 
88021496Ssklower 		case SO_DEFAULT_HEADERS:
88121496Ssklower 			{
88221496Ssklower 				register struct sphdr *sp
88321496Ssklower 						= mtod(*value, struct sphdr *);
88421496Ssklower 				cb->s_dt = sp->sp_dt;
88521496Ssklower 				cb->s_cc = sp->sp_cc & SP_EM;
88621496Ssklower 			}
887*25334Ssklower 			break;
888*25334Ssklower 
889*25334Ssklower 		default:
890*25334Ssklower 			error = EINVAL;
89121496Ssklower 		}
89224615Ssklower 		m_freem(*value);
89321496Ssklower 		break;
89421496Ssklower 	}
89521496Ssklower 	release:
89623515Ssklower 		return (error);
89721496Ssklower }
89821496Ssklower 
89921496Ssklower /*ARGSUSED*/
90021496Ssklower spp_usrreq(so, req, m, nam, rights)
90121496Ssklower 	struct socket *so;
90221496Ssklower 	int req;
90321496Ssklower 	struct mbuf *m, *nam, *rights;
90421496Ssklower {
90521496Ssklower 	struct nspcb *nsp = sotonspcb(so);
90621496Ssklower 	register struct sppcb *cb;
90721496Ssklower 	int s = splnet();
90821496Ssklower 	int error = 0, ostate;
90921496Ssklower 
91021496Ssklower 	if (req == PRU_CONTROL)
91121496Ssklower                 return (ns_control(so, (int)m, (caddr_t)nam,
91221496Ssklower 			(struct ifnet *)rights));
91321496Ssklower 	if (rights && rights->m_len) {
91421496Ssklower 		error = EINVAL;
91521496Ssklower 		goto release;
91621496Ssklower 	}
91721496Ssklower 	if (nsp == NULL) {
91821496Ssklower 		if (req != PRU_ATTACH) {
91921496Ssklower 			error = EINVAL;
92021496Ssklower 			goto release;
92121496Ssklower 		}
92221496Ssklower 	} else
92321496Ssklower 		cb = nstosppcb(nsp);
92421496Ssklower 
92521496Ssklower 	ostate = cb ? cb->s_state : 0;
92621496Ssklower 
92721496Ssklower 	switch (req) {
92823515Ssklower 
92921496Ssklower 	case PRU_ATTACH:
93021496Ssklower 		if (nsp != NULL) {
93121496Ssklower 			error = EISCONN;
93221496Ssklower 			break;
93321496Ssklower 		}
93421496Ssklower 		error = ns_pcballoc(so, &nspcb);
93521496Ssklower 		if (error)
93621496Ssklower 			break;
93721496Ssklower 		error = soreserve(so, 2048, 2048);
93821496Ssklower 		if (error)
93921496Ssklower 			break;
94021496Ssklower 		nsp = sotonspcb(so);
94121496Ssklower 		{
94225037Ssklower 			struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB);
94321496Ssklower 
94424330Ssklower 			if (mm == NULL) {
94521496Ssklower 				error = ENOBUFS;
94621496Ssklower 				break;
94721496Ssklower 			}
94821496Ssklower 			cb = mtod(mm, struct sppcb *);
94921496Ssklower 			cb->s_state = TCPS_LISTEN;
95021496Ssklower 			cb->s_snt = -1;
95121496Ssklower 			cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
95221496Ssklower 			cb->s_nspcb = nsp;
95321496Ssklower 			nsp->nsp_pcb = (caddr_t) cb;
95421496Ssklower 		}
95521496Ssklower 		break;
95621496Ssklower 
95721496Ssklower 	case PRU_DETACH:
95821496Ssklower 		if (nsp == NULL) {
95921496Ssklower 			error = ENOTCONN;
96021496Ssklower 			break;
96121496Ssklower 		}
96221496Ssklower 		if (cb->s_state > TCPS_LISTEN)
96321496Ssklower 			cb = spp_disconnect(cb);
96421496Ssklower 		else
96521496Ssklower 			cb = spp_close(cb);
96621496Ssklower 		break;
96721496Ssklower 
96821496Ssklower 	case PRU_BIND:
96921496Ssklower 		error = ns_pcbbind(nsp, nam);
97021496Ssklower 		break;
97121496Ssklower 
97221496Ssklower 	case PRU_LISTEN:
97321496Ssklower 		if (nsp->nsp_lport == 0)
97421496Ssklower 			error = ns_pcbbind(nsp, (struct mbuf *)0);
97521496Ssklower 		if (error == 0)
97621496Ssklower 			cb->s_state = TCPS_LISTEN;
97721496Ssklower 		break;
97821496Ssklower 
97921496Ssklower 	/*
98021496Ssklower 	 * Initiate connection to peer.
98121496Ssklower 	 * Enter SYN_SENT state, and mark socket as connecting.
98221496Ssklower 	 * Start keep-alive timer, setup prototype header,
98321496Ssklower 	 * Send initial system packet requesting connection.
98421496Ssklower 	 */
98521496Ssklower 	case PRU_CONNECT:
98621496Ssklower 		if (nsp->nsp_lport == 0) {
98721496Ssklower 			error = ns_pcbbind(nsp, (struct mbuf *)0);
98821496Ssklower 			if (error)
98921496Ssklower 				break;
99021496Ssklower 		}
99121496Ssklower 		error = ns_pcbconnect(nsp, nam);
99221496Ssklower 		if (error)
99321496Ssklower 			break;
99421496Ssklower 		soisconnecting(so);
99521496Ssklower 		cb->s_state = TCPS_SYN_SENT;
99621496Ssklower 		cb->s_did = 0;
99721496Ssklower 		spp_template(cb);
99821496Ssklower 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
99921496Ssklower 		cb->s_force = 1 + TCPTV_KEEP;
100021496Ssklower 		/*
100121496Ssklower 		 * Other party is required to respond to
100221496Ssklower 		 * the port I send from, but he is not
100321496Ssklower 		 * required to answer from where I am sending to,
100421496Ssklower 		 * so allow wildcarding.
100521496Ssklower 		 * original port I am sending to is still saved in
100621496Ssklower 		 * cb->s_dport.
100721496Ssklower 		 */
100821496Ssklower 		nsp->nsp_fport = 0;
100921496Ssklower 		error = spp_output(cb, (struct mbuf *) 0);
101021496Ssklower 		break;
101121496Ssklower 
101221496Ssklower 	case PRU_CONNECT2:
101321496Ssklower 		error = EOPNOTSUPP;
101421496Ssklower 		break;
101521496Ssklower 
101621496Ssklower 	/*
101721496Ssklower 	 * We may decide later to implement connection closing
101821496Ssklower 	 * handshaking at the spp level optionally.
101921496Ssklower 	 * here is the hook to do it:
102021496Ssklower 	 */
102121496Ssklower 	case PRU_DISCONNECT:
102221496Ssklower 		cb = spp_disconnect(cb);
102321496Ssklower 		break;
102421496Ssklower 
102521496Ssklower 	/*
102621496Ssklower 	 * Accept a connection.  Essentially all the work is
102721496Ssklower 	 * done at higher levels; just return the address
102821496Ssklower 	 * of the peer, storing through addr.
102921496Ssklower 	 */
103021496Ssklower 	case PRU_ACCEPT: {
103121496Ssklower 		struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
103221496Ssklower 
103321496Ssklower 		nam->m_len = sizeof (struct sockaddr_ns);
103421496Ssklower 		sns->sns_family = AF_NS;
103521496Ssklower 		sns->sns_addr = nsp->nsp_faddr;
103621496Ssklower 		break;
103721496Ssklower 		}
103821496Ssklower 
103921496Ssklower 	case PRU_SHUTDOWN:
104021496Ssklower 		socantsendmore(so);
104121496Ssklower 		cb = spp_usrclosed(cb);
104221496Ssklower 		if (cb)
104321496Ssklower 			error = spp_output(cb, (struct mbuf *) 0);
104421496Ssklower 		break;
104521496Ssklower 
104621496Ssklower 	/*
104721496Ssklower 	 * After a receive, possibly send acknowledgment
104821496Ssklower 	 * updating allocation.
104921496Ssklower 	 */
105021496Ssklower 	case PRU_RCVD:
105121496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
105221496Ssklower 		break;
105321496Ssklower 
105421496Ssklower 	case PRU_SEND:
105521496Ssklower 		error = spp_output(cb, m);
105621496Ssklower 		m = NULL;
105721496Ssklower 		break;
105821496Ssklower 
105921496Ssklower 	case PRU_ABORT:
106024225Ssklower 		(void) spp_drop(cb, ECONNABORTED);
106121496Ssklower 		break;
106221496Ssklower 
106321496Ssklower 	case PRU_SENSE:
106421496Ssklower 	case PRU_CONTROL:
106521496Ssklower 		m = NULL;
106621496Ssklower 		error = EOPNOTSUPP;
106721496Ssklower 		break;
106821496Ssklower 
106921496Ssklower 	case PRU_RCVOOB:
107025037Ssklower 		if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
107125037Ssklower 		    (so->so_state & SS_RCVATMARK)) {
107225037Ssklower 			m->m_len = 1;
107325037Ssklower 			*mtod(m, caddr_t) = cb->s_iobc;
107424732Ssklower 			break;
107524732Ssklower 		}
107625037Ssklower 		error = EINVAL;
107721496Ssklower 		break;
107821496Ssklower 
107921496Ssklower 	case PRU_SENDOOB:
108021496Ssklower 		if (sbspace(&so->so_snd) < -512) {
108121496Ssklower 			m_freem(m);
108221496Ssklower 			error = ENOBUFS;
108321496Ssklower 			break;
108421496Ssklower 		}
108521496Ssklower 		cb->s_oobflags |= SF_SOOB;
108621496Ssklower 		error = spp_output(cb, m);
108721496Ssklower 		m = NULL;
108821496Ssklower 		break;
108921496Ssklower 
109021496Ssklower 	case PRU_SOCKADDR:
109121496Ssklower 		ns_setsockaddr(nsp, nam);
109221496Ssklower 		break;
109321496Ssklower 
109421496Ssklower 	case PRU_PEERADDR:
109521496Ssklower 		ns_setpeeraddr(nsp, nam);
109621496Ssklower 		break;
109721496Ssklower 
109821496Ssklower 	case PRU_SLOWTIMO:
109921496Ssklower 		cb = spp_timers(cb, (int)nam);
110021496Ssklower 		break;
110121496Ssklower 
110221496Ssklower 	case PRU_FASTTIMO:
110321496Ssklower 	case PRU_PROTORCV:
110421496Ssklower 	case PRU_PROTOSEND:
110521496Ssklower 		error =  EOPNOTSUPP;
110621496Ssklower 		break;
110721496Ssklower 
110821496Ssklower 	default:
110921496Ssklower 		panic("sp_usrreq");
111021496Ssklower 	}
111121496Ssklower 	if (cb && (so->so_options & SO_DEBUG || traceallspps))
111224225Ssklower 		spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
111321496Ssklower release:
111421496Ssklower 	if (m != NULL)
111521496Ssklower 		m_freem(m);
111621496Ssklower 	splx(s);
111721496Ssklower 	return (error);
111821496Ssklower }
111921496Ssklower 
112021496Ssklower spp_usrreq_sp(so, req, m, nam, rights)
112121496Ssklower 	struct socket *so;
112221496Ssklower 	int req;
112321496Ssklower 	struct mbuf *m, *nam, *rights;
112421496Ssklower {
112521496Ssklower 	int error = spp_usrreq(so, req, m, nam, rights);
112621496Ssklower 
112724330Ssklower 	if (req == PRU_ATTACH && error == 0) {
112821496Ssklower 		struct nspcb *nsp = sotonspcb(so);
112921496Ssklower 		((struct sppcb *)nsp->nsp_pcb)->s_flags |=
113021496Ssklower 					(SF_HI | SF_HO | SF_PI);
113121496Ssklower 	}
113223515Ssklower 	return (error);
113321496Ssklower }
113421496Ssklower 
113521496Ssklower /*
113621496Ssklower  * Create template to be used to send spp packets on a connection.
113721496Ssklower  * Called after host entry created, fills
113821496Ssklower  * in a skeletal spp header (choosing connection id),
113921496Ssklower  * minimizing the amount of work necessary when the connection is used.
114021496Ssklower  */
114121496Ssklower spp_template(cb)
114221496Ssklower 	struct sppcb *cb;
114321496Ssklower {
114421496Ssklower 	register struct nspcb *nsp = cb->s_nspcb;
114521496Ssklower 	register struct spidp *n = &(cb->s_shdr);
114621496Ssklower 
114724615Ssklower 	cb->s_mtu = 576 - sizeof (struct spidp);
114821496Ssklower 	n->si_pt = NSPROTO_SPP;
114921496Ssklower 	n->si_sna = nsp->nsp_laddr;
115021496Ssklower 	n->si_dna = nsp->nsp_faddr;
115121496Ssklower 	n->si_sid = htons(spp_iss);
115221496Ssklower 	spp_iss += SPP_ISSINCR/2;
115321496Ssklower 	n->si_alo = 1;
115421496Ssklower }
115521496Ssklower 
115621496Ssklower /*
115721496Ssklower  * Close a SPIP control block:
115821496Ssklower  *	discard spp control block itself
115921496Ssklower  *	discard ns protocol control block
116021496Ssklower  *	wake up any sleepers
116121496Ssklower  */
116221496Ssklower struct sppcb *
116321496Ssklower spp_close(cb)
116421496Ssklower 	register struct sppcb *cb;
116521496Ssklower {
116621496Ssklower 	register struct spidp_q *s;
116721496Ssklower 	struct nspcb *nsp = cb->s_nspcb;
116821496Ssklower 	struct socket *so = nsp->nsp_socket;
116921496Ssklower 	register struct mbuf *m;
117021496Ssklower 
117121496Ssklower 	s = cb->s_q.si_next;
117221496Ssklower 	while (s != &(cb->s_q)) {
117321496Ssklower 		s = s->si_next;
117421496Ssklower 		m = dtom(s->si_prev);
117521496Ssklower 		remque(s->si_prev);
117621496Ssklower 		m_freem(m);
117721496Ssklower 	}
117821496Ssklower 	(void) m_free(dtom(cb));
117921496Ssklower 	nsp->nsp_pcb = 0;
118021496Ssklower 	soisdisconnected(so);
118121496Ssklower 	ns_pcbdetach(nsp);
118223515Ssklower 	return ((struct sppcb *)0);
118321496Ssklower }
118421496Ssklower /*
118521496Ssklower  *	Someday we may do level 3 handshaking
118621496Ssklower  *	to close a connection or send a xerox style error.
118721496Ssklower  *	For now, just close.
118821496Ssklower  */
118921496Ssklower struct sppcb *
119021496Ssklower spp_usrclosed(cb)
119121496Ssklower 	register struct sppcb *cb;
119221496Ssklower {
119323515Ssklower 	return (spp_close(cb));
119421496Ssklower }
119521496Ssklower struct sppcb *
119621496Ssklower spp_disconnect(cb)
119721496Ssklower 	register struct sppcb *cb;
119821496Ssklower {
119923515Ssklower 	return (spp_close(cb));
120021496Ssklower }
120121496Ssklower /*
120221496Ssklower  * Drop connection, reporting
120321496Ssklower  * the specified error.
120421496Ssklower  */
120521496Ssklower struct sppcb *
120621496Ssklower spp_drop(cb, errno)
120721496Ssklower 	register struct sppcb *cb;
120821496Ssklower 	int errno;
120921496Ssklower {
121021496Ssklower 	struct socket *so = cb->s_nspcb->nsp_socket;
121121496Ssklower 
121221496Ssklower 	/*
121321496Ssklower 	 * someday, in the xerox world
121421496Ssklower 	 * we will generate error protocol packets
121521496Ssklower 	 * announcing that the socket has gone away.
121621496Ssklower 	 */
121721496Ssklower 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
121821496Ssklower 		tp->t_state = TCPS_CLOSED;
121921496Ssklower 		(void) tcp_output(tp);
122021496Ssklower 	}*/
122121496Ssklower 	so->so_error = errno;
122221496Ssklower 	return (spp_close(cb));
122321496Ssklower }
122421496Ssklower 
122521496Ssklower spp_abort(nsp)
122621496Ssklower 	struct nspcb *nsp;
122721496Ssklower {
122821496Ssklower 
122924225Ssklower 	(void) spp_close((struct sppcb *)nsp->nsp_pcb);
123021496Ssklower }
123121496Ssklower 
123221496Ssklower spp_setpersist(cb)
123321496Ssklower 	register struct sppcb *cb;
123421496Ssklower {
123521496Ssklower 
123621496Ssklower 	/*if (cb->s_timer[TCPT_REXMT])
123721496Ssklower 		panic("spp_output REXMT");*/
123821496Ssklower 	/*
123921496Ssklower 	 * Start/restart persistance timer.
124021496Ssklower 	 */
124121496Ssklower 	TCPT_RANGESET(cb->s_timer[TCPT_PERSIST],
124221496Ssklower 	    ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift,
124321496Ssklower 	    TCPTV_PERSMIN, TCPTV_MAX);
124421496Ssklower 	cb->s_rxtshift++;
124521496Ssklower 	if (cb->s_rxtshift >= TCP_MAXRXTSHIFT)
124621496Ssklower 		cb->s_rxtshift = 0;
124721496Ssklower }
124821496Ssklower /*
124921496Ssklower  * Fast timeout routine for processing delayed acks
125021496Ssklower  */
125121496Ssklower int spp_ftcnt;
125221496Ssklower spp_fasttimo()
125321496Ssklower {
125421496Ssklower 	register struct nspcb *nsp;
125521496Ssklower 	register struct sppcb *cb;
125621496Ssklower 	int s = splnet();
125721496Ssklower 
125821496Ssklower 	nsp = nspcb.nsp_next;
125921496Ssklower 	spp_ftcnt++;
126021496Ssklower 	if (nsp)
126121496Ssklower 	for (; nsp != &nspcb; nsp = nsp->nsp_next)
126221496Ssklower 		if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
126321496Ssklower 		    (cb->s_flags & SF_DELACK)) {
126421496Ssklower 			cb->s_flags &= ~SF_DELACK;
126521496Ssklower 			cb->s_flags |= SF_AK;
126621496Ssklower 			(void) spp_output(cb, (struct mbuf *) 0);
126721496Ssklower 		}
126821496Ssklower 	splx(s);
126921496Ssklower }
127021496Ssklower 
127121496Ssklower /*
127221496Ssklower  * spp protocol timeout routine called every 500 ms.
127321496Ssklower  * Updates the timers in all active pcb's and
127421496Ssklower  * causes finite state machine actions if timers expire.
127521496Ssklower  */
127621496Ssklower spp_slowtimo()
127721496Ssklower {
127821496Ssklower 	register struct nspcb *ip, *ipnxt;
127921496Ssklower 	register struct sppcb *cb;
128021496Ssklower 	int s = splnet();
128121496Ssklower 	register int i;
128221496Ssklower 
128321496Ssklower 	/*
128421496Ssklower 	 * Search through tcb's and update active timers.
128521496Ssklower 	 */
128621496Ssklower 	ip = nspcb.nsp_next;
128721496Ssklower 	if (ip == 0) {
128821496Ssklower 		splx(s);
128921496Ssklower 		return;
129021496Ssklower 	}
129121496Ssklower 	while (ip != &nspcb) {
129221496Ssklower 		cb = nstosppcb(ip);
129321496Ssklower 		ipnxt = ip->nsp_next;
129421496Ssklower 		if (cb == 0)
129521496Ssklower 			goto tpgone;
129621496Ssklower 		for (i = 0; i < TCPT_NTIMERS; i++) {
129721496Ssklower 			if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
129821496Ssklower 				(void) spp_usrreq(cb->s_nspcb->nsp_socket,
129921496Ssklower 				    PRU_SLOWTIMO, (struct mbuf *)0,
130021496Ssklower 				    (struct mbuf *)i, (struct mbuf *)0);
130121496Ssklower 				if (ipnxt->nsp_prev != ip)
130221496Ssklower 					goto tpgone;
130321496Ssklower 			}
130421496Ssklower 		}
130521496Ssklower 		cb->s_idle++;
130621496Ssklower 		if (cb->s_rtt)
130721496Ssklower 			cb->s_rtt++;
130821496Ssklower tpgone:
130921496Ssklower 		ip = ipnxt;
131021496Ssklower 	}
131121496Ssklower 	spp_iss += SPP_ISSINCR/PR_SLOWHZ;		/* increment iss */
131221496Ssklower 	splx(s);
131321496Ssklower }
131421496Ssklower 
131521496Ssklower float	spp_backoff[TCP_MAXRXTSHIFT] =
131621496Ssklower     { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 };
131724412Swalsh int sppexprexmtbackoff = 0;
131821496Ssklower /*
131924615Ssklower  * SPP timer processing.
132021496Ssklower  */
132121496Ssklower struct sppcb *
132221496Ssklower spp_timers(cb, timer)
132321496Ssklower 	register struct sppcb *cb;
132421496Ssklower 	int timer;
132521496Ssklower {
132621496Ssklower 
132721496Ssklower 	cb->s_force = 1 + timer;
132821496Ssklower 	switch (timer) {
132921496Ssklower 
133021496Ssklower 	/*
133121496Ssklower 	 * 2 MSL timeout in shutdown went off.  Delete connection
133221496Ssklower 	 * control block.
133321496Ssklower 	 */
133421496Ssklower 	case TCPT_2MSL:
133521496Ssklower 		cb = spp_close(cb);
133621496Ssklower 		break;
133721496Ssklower 
133821496Ssklower 	/*
133921496Ssklower 	 * Retransmission timer went off.  Message has not
134021496Ssklower 	 * been acked within retransmit interval.  Back off
134121496Ssklower 	 * to a longer retransmit interval and retransmit all
134221496Ssklower 	 * unacknowledged messages in the window.
134321496Ssklower 	 */
134421496Ssklower 	case TCPT_REXMT:
134521496Ssklower 		cb->s_rxtshift++;
134621496Ssklower 		if (cb->s_rxtshift > TCP_MAXRXTSHIFT) {
134721496Ssklower 			cb = spp_drop(cb, ETIMEDOUT);
134821496Ssklower 			break;
134921496Ssklower 		}
135021496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
135121496Ssklower 		TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
135221496Ssklower 		    (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX);
135324412Swalsh 		if (sppexprexmtbackoff) {
135421496Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
135521496Ssklower 			    cb->s_timer[TCPT_REXMT] << cb->s_rxtshift,
135621496Ssklower 			    TCPTV_MIN, TCPTV_MAX);
135721496Ssklower 		} else {
135821496Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
135921496Ssklower 			    cb->s_timer[TCPT_REXMT] *
136021496Ssklower 			        spp_backoff[cb->s_rxtshift - 1],
136121496Ssklower 			    TCPTV_MIN, TCPTV_MAX);
136221496Ssklower 		}
136321496Ssklower 		break;
136421496Ssklower 
136521496Ssklower 	/*
136621496Ssklower 	 * Persistance timer into zero window.
136721496Ssklower 	 * Force a probe to be sent.
136821496Ssklower 	 */
136921496Ssklower 	case TCPT_PERSIST:
137021496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
137121496Ssklower 		spp_setpersist(cb);
137221496Ssklower 		break;
137321496Ssklower 
137421496Ssklower 	/*
137521496Ssklower 	 * Keep-alive timer went off; send something
137621496Ssklower 	 * or drop connection if idle for too long.
137721496Ssklower 	 */
137821496Ssklower 	case TCPT_KEEP:
137921496Ssklower 		if (cb->s_state < TCPS_ESTABLISHED)
138021496Ssklower 			goto dropit;
138121496Ssklower 		if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
138221496Ssklower 		    	if (cb->s_idle >= TCPTV_MAXIDLE)
138321496Ssklower 				goto dropit;
138421496Ssklower 			(void) spp_output(cb, (struct mbuf *) 0);
138521496Ssklower 		} else
138621496Ssklower 			cb->s_idle = 0;
138721496Ssklower 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
138821496Ssklower 		break;
138921496Ssklower 	dropit:
139021496Ssklower 		cb = spp_drop(cb, ETIMEDOUT);
139121496Ssklower 		break;
139221496Ssklower 	}
139321496Ssklower 	return (cb);
139421496Ssklower }
1395