xref: /csrg-svn/sys/netns/spp_usrreq.c (revision 29925)
123215Smckusick /*
229171Smckusick  * Copyright (c) 1984, 1985, 1986 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*29925Skarels  *	@(#)spp_usrreq.c	7.2 (Berkeley) 10/28/86
723215Smckusick  */
821496Ssklower 
921496Ssklower #include "param.h"
10*29925Skarels #include "systm.h"
1121496Ssklower #include "dir.h"
1221496Ssklower #include "user.h"
1321496Ssklower #include "mbuf.h"
1421496Ssklower #include "protosw.h"
1521496Ssklower #include "socket.h"
1621496Ssklower #include "socketvar.h"
1721496Ssklower #include "errno.h"
1821496Ssklower 
1921496Ssklower #include "../net/if.h"
2021496Ssklower #include "../net/route.h"
2121496Ssklower #include "../netinet/tcp_fsm.h"
2221496Ssklower #include "../netinet/tcp_timer.h"
2321496Ssklower 
2421496Ssklower #include "ns.h"
2521496Ssklower #include "ns_pcb.h"
2621496Ssklower #include "idp.h"
2721496Ssklower #include "idp_var.h"
2821496Ssklower #include "ns_error.h"
2921496Ssklower #include "sp.h"
3021496Ssklower #include "spidp.h"
3121496Ssklower #include "spp_var.h"
3221496Ssklower #include "spp_debug.h"
3321496Ssklower 
3421496Ssklower /*
3521496Ssklower  * SP protocol implementation.
3621496Ssklower  */
3721496Ssklower spp_init()
3821496Ssklower {
3921496Ssklower 
4021496Ssklower 	spp_iss = 1; /* WRONG !! should fish it out of TODR */
4121496Ssklower }
4221496Ssklower struct spidp spp_savesi;
4321496Ssklower int traceallspps = 0;
4421496Ssklower extern int sppconsdebug;
4524615Ssklower int spp_hardnosed;
4625037Ssklower int spp_use_delack = 0;
4721496Ssklower 
4824615Ssklower /*ARGSUSED*/
4924615Ssklower spp_input(m, nsp, ifp)
5021496Ssklower 	register struct mbuf *m;
5124047Ssklower 	register struct nspcb *nsp;
5224615Ssklower 	struct ifnet *ifp;
5321496Ssklower {
5421496Ssklower 	register struct sppcb *cb;
5521496Ssklower 	register struct spidp *si = mtod(m, struct spidp *);
5621496Ssklower 	register struct socket *so;
5724225Ssklower 	short ostate;
5821496Ssklower 	int dropsocket = 0;
5921496Ssklower 
6021496Ssklower 
6124330Ssklower 	if (nsp == 0) {
6224047Ssklower 		panic("No nspcb in spp_input\n");
6323979Ssklower 		return;
6423979Ssklower 	}
6521496Ssklower 
6621496Ssklower 	cb = nstosppcb(nsp);
6721496Ssklower 	if (cb == 0) goto bad;
6821496Ssklower 
6924047Ssklower 	if (m->m_len < sizeof(*si)) {
7024330Ssklower 		if ((m = m_pullup(m, sizeof(*si))) == 0) {
7124047Ssklower 			spp_istat.hdrops++;
7224047Ssklower 			return;
7324047Ssklower 		}
7424047Ssklower 		si = mtod(m, struct spidp *);
7524047Ssklower 	}
7621496Ssklower 	si->si_seq = ntohs(si->si_seq);
7721496Ssklower 	si->si_ack = ntohs(si->si_ack);
7821496Ssklower 	si->si_alo = ntohs(si->si_alo);
7921496Ssklower 
8021496Ssklower 	so = nsp->nsp_socket;
8121496Ssklower 	if (so->so_options & SO_DEBUG || traceallspps) {
8221496Ssklower 		ostate = cb->s_state;
8321496Ssklower 		spp_savesi = *si;
8421496Ssklower 	}
8521496Ssklower 	if (so->so_options & SO_ACCEPTCONN) {
8621496Ssklower 		so = sonewconn(so);
8721496Ssklower 		if (so == 0) {
8821496Ssklower 			spp_istat.nonucn++;
8921496Ssklower 			goto drop;
9021496Ssklower 		}
9121496Ssklower 		/*
9221496Ssklower 		 * This is ugly, but ....
9321496Ssklower 		 *
9421496Ssklower 		 * Mark socket as temporary until we're
9521496Ssklower 		 * committed to keeping it.  The code at
9621496Ssklower 		 * ``drop'' and ``dropwithreset'' check the
9721496Ssklower 		 * flag dropsocket to see if the temporary
9821496Ssklower 		 * socket created here should be discarded.
9921496Ssklower 		 * We mark the socket as discardable until
10021496Ssklower 		 * we're committed to it below in TCPS_LISTEN.
10121496Ssklower 		 */
10221496Ssklower 		dropsocket++;
10321496Ssklower 		nsp = (struct nspcb *)so->so_pcb;
10421496Ssklower 		nsp->nsp_laddr = si->si_dna;
10521496Ssklower 		cb = nstosppcb(nsp);
10621496Ssklower 		cb->s_state = TCPS_LISTEN;
10721496Ssklower 	}
10821496Ssklower 
10921496Ssklower 	/*
11021496Ssklower 	 * Packet received on connection.
11121496Ssklower 	 * reset idle time and keep-alive timer;
11221496Ssklower 	 */
11321496Ssklower 	cb->s_idle = 0;
11421496Ssklower 	cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
11521496Ssklower 
11621496Ssklower 	switch (cb->s_state) {
11723515Ssklower 
11821496Ssklower 	case TCPS_LISTEN:{
11921496Ssklower 		struct mbuf *am;
12021496Ssklower 		register struct sockaddr_ns *sns;
12121496Ssklower 		struct ns_addr laddr;
12221496Ssklower 
12321496Ssklower 		/*
12421496Ssklower 		 * If somebody here was carying on a conversation
12521496Ssklower 		 * and went away, and his pen pal thinks he can
12621496Ssklower 		 * still talk, we get the misdirected packet.
12721496Ssklower 		 */
12821496Ssklower 		if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
12921496Ssklower 			spp_istat.gonawy++;
13021496Ssklower 			goto dropwithreset;
13121496Ssklower 		}
13221496Ssklower 		am = m_get(M_DONTWAIT, MT_SONAME);
13321496Ssklower 		if (am == NULL)
13421496Ssklower 			goto drop;
13521496Ssklower 		am->m_len = sizeof (struct sockaddr_ns);
13621496Ssklower 		sns = mtod(am, struct sockaddr_ns *);
13721496Ssklower 		sns->sns_family = AF_NS;
13821496Ssklower 		sns->sns_addr = si->si_sna;
13921496Ssklower 		laddr = nsp->nsp_laddr;
14021496Ssklower 		if (ns_nullhost(laddr))
14121496Ssklower 			nsp->nsp_laddr = si->si_dna;
14221496Ssklower 		if (ns_pcbconnect(nsp, am)) {
14321496Ssklower 			nsp->nsp_laddr = laddr;
14421496Ssklower 			(void) m_free(am);
14521496Ssklower 			spp_istat.noconn++;
14621496Ssklower 			goto drop;
14721496Ssklower 		}
14821496Ssklower 		(void) m_free(am);
14921496Ssklower 		spp_template(cb);
15024732Ssklower 		dropsocket = 0;		/* committed to socket */
15121496Ssklower 		cb->s_did = si->si_sid;
15221496Ssklower 		cb->s_rack = si->si_ack;
15321496Ssklower 		cb->s_ralo = si->si_alo;
15424732Ssklower #define THREEWAYSHAKE
15524732Ssklower #ifdef THREEWAYSHAKE
15624732Ssklower 		cb->s_state = TCPS_SYN_RECEIVED;
15724732Ssklower 		cb->s_force = 1 + TCPT_REXMT;
15824732Ssklower 		cb->s_timer[TCPT_REXMT] = 2 * TCPTV_MIN;
15921496Ssklower 		}
16021496Ssklower 		break;
16124732Ssklower 	/*
16224732Ssklower 	 * This state means that we have heard a response
16324732Ssklower 	 * to our acceptance of their connection
16424732Ssklower 	 * It is probably logically unnecessary in this
16524732Ssklower 	 * implementation.
16624732Ssklower 	 */
16724732Ssklower 	 case TCPS_SYN_RECEIVED:
16824732Ssklower 		if (si->si_did!=cb->s_sid) {
16924732Ssklower 			spp_istat.wrncon++;
17024732Ssklower 			goto drop;
17124732Ssklower 		}
17224732Ssklower #endif
17324732Ssklower 		nsp->nsp_fport =  si->si_sport;
17424732Ssklower 		cb->s_timer[TCPT_REXMT] = 0;
17524732Ssklower 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
17624732Ssklower 		soisconnected(so);
17724732Ssklower 		cb->s_state = TCPS_ESTABLISHED;
17824732Ssklower 		break;
17921496Ssklower 
18021496Ssklower 	/*
18121496Ssklower 	 * This state means that we have gotten a response
18221496Ssklower 	 * to our attempt to establish a connection.
18323979Ssklower 	 * We fill in the data from the other side,
18423979Ssklower 	 * telling us which port to respond to, instead of the well-
18523979Ssklower 	 * known one we might have sent to in the first place.
18621496Ssklower 	 * We also require that this is a response to our
18723979Ssklower 	 * connection id.
18821496Ssklower 	 */
18921496Ssklower 	case TCPS_SYN_SENT:
19021496Ssklower 		if (si->si_did!=cb->s_sid) {
19121496Ssklower 			spp_istat.notme++;
19221496Ssklower 			goto drop;
19321496Ssklower 		}
19421496Ssklower 		cb->s_did = si->si_sid;
19521496Ssklower 		cb->s_rack = si->si_ack;
19621496Ssklower 		cb->s_ralo = si->si_alo;
19721496Ssklower 		cb->s_dport = nsp->nsp_fport =  si->si_sport;
19821496Ssklower 		cb->s_timer[TCPT_REXMT] = 0;
19921496Ssklower 		cb->s_flags |= SF_AK;
20021496Ssklower 		soisconnected(so);
20121496Ssklower 		cb->s_state = TCPS_ESTABLISHED;
20221496Ssklower 	}
20321496Ssklower 	if (so->so_options & SO_DEBUG || traceallspps)
20424225Ssklower 		spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0);
20521496Ssklower 
20621496Ssklower 	m->m_len -= sizeof (struct idp);
20721496Ssklower 	m->m_off += sizeof (struct idp);
20821496Ssklower 
20925037Ssklower 	if (spp_reass(cb, si)) {
21025334Ssklower 		m_freem(m);
21121496Ssklower 	}
21225037Ssklower 	(void) spp_output(cb, (struct mbuf *)0);
21321496Ssklower 	return;
21421496Ssklower 
21521496Ssklower dropwithreset:
21621496Ssklower 	if (dropsocket)
21721496Ssklower 		(void) soabort(so);
21821496Ssklower 	si->si_seq = ntohs(si->si_seq);
21921496Ssklower 	si->si_ack = ntohs(si->si_ack);
22021496Ssklower 	si->si_alo = ntohs(si->si_alo);
22121496Ssklower 	ns_error(dtom(si), NS_ERR_NOSOCK, 0);
22221496Ssklower 	if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)
22324225Ssklower 		spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
22421496Ssklower 	return;
22521496Ssklower 
22621496Ssklower drop:
22721496Ssklower bad:
22824330Ssklower 	if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)
22924225Ssklower 		spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
23021496Ssklower 	m_freem(m);
23121496Ssklower }
23221496Ssklower 
23321496Ssklower /*
23421496Ssklower  * This is structurally similar to the tcp reassembly routine
23521496Ssklower  * but its function is somewhat different:  It merely queues
23621496Ssklower  * packets up, and suppresses duplicates.
23721496Ssklower  */
23825037Ssklower spp_reass(cb, si)
23921496Ssklower register struct sppcb *cb;
24021496Ssklower register struct spidp *si;
24121496Ssklower {
24221496Ssklower 	register struct spidp_q *q;
24321496Ssklower 	register struct mbuf *m;
24421496Ssklower 	struct socket *so = cb->s_nspcb->nsp_socket;
24521496Ssklower 	struct sockbuf *sb = & (so->so_rcv);
24621496Ssklower 	char packetp = cb->s_flags & SF_HI;
24721496Ssklower 	char wakeup = 0;
24821496Ssklower 
24921496Ssklower 
25024330Ssklower 	if (si == SI(0))
25121496Ssklower 		goto present;
25221496Ssklower 	/*
25321496Ssklower 	 * Update our news from them.
25421496Ssklower 	 */
25521496Ssklower 	if (si->si_cc & SP_SA)
25625037Ssklower 		cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_AK);
25725037Ssklower 	if (SSEQ_GT(si->si_ack, cb->s_rack)) {
25821496Ssklower 		cb->s_rack = si->si_ack;
25921496Ssklower 		/*
26025037Ssklower 		 * If there are other packets outstanding,
26125037Ssklower 		 * restart the timer for them.
26225037Ssklower 		 */
26325037Ssklower 		if (SSEQ_GEQ(cb->s_snt, si->si_ack)) {
26425037Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
26525037Ssklower 				tcp_beta * cb->s_srtt, TCPTV_MIN,
26625037Ssklower 				TCPTV_MAX);
26725037Ssklower 			cb->s_rxtshift = 0;
26825037Ssklower 		} else
26925037Ssklower 			cb->s_timer[TCPT_REXMT] = 0;
27025037Ssklower 		/*
27121496Ssklower 		 * If transmit timer is running and timed sequence
27221496Ssklower 		 * number was acked, update smoothed round trip time.
27321496Ssklower 		 */
27421496Ssklower 		if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
27521496Ssklower 			if (cb->s_srtt == 0)
27621496Ssklower 				cb->s_srtt = cb->s_rtt;
27721496Ssklower 			else
27821496Ssklower 				cb->s_srtt =
27921496Ssklower 				    tcp_alpha * cb->s_srtt +
28021496Ssklower 				    (1 - tcp_alpha) * cb->s_rtt;
28121496Ssklower 			cb->s_rtt = 0;
28221496Ssklower 		}
28321496Ssklower 	}
28425037Ssklower 	if (SSEQ_GT(si->si_alo, cb->s_ralo)) {
28521496Ssklower 		cb->s_ralo = si->si_alo;
28621496Ssklower 		cb->s_timer[TCPT_PERSIST] = 0;
28721496Ssklower 	}
28821496Ssklower 	/*
28921496Ssklower 	 * If this is a system packet, we don't need to
29021496Ssklower 	 * queue it up, and won't update acknowledge #
29121496Ssklower 	 */
29223561Ssklower 	if (si->si_cc & SP_SP) {
29323561Ssklower 		m_freem(dtom(si));
29423515Ssklower 		return (0);
29523561Ssklower 	}
29621496Ssklower 
29721496Ssklower 	/*
29821496Ssklower 	 * If this packet number has a sequence number less
29921496Ssklower 	 * than that of the first packet not yet seen coming
30021496Ssklower 	 * from them, this must be a duplicate, so drop.
30121496Ssklower 	 */
30225037Ssklower 	if (SSEQ_LT(si->si_seq, cb->s_ack)) {
30323979Ssklower 		spp_istat.bdreas++;
30424330Ssklower 		if (si->si_seq == cb->s_ack-1)
30523979Ssklower 			spp_istat.lstdup++;
30623515Ssklower 		return (1);
30723979Ssklower 	}
30821496Ssklower 	/*
30921496Ssklower 	 * If this packet number is higher than that which
31021496Ssklower 	 * we have allocated refuse it, unless urgent
31121496Ssklower 	 */
31225037Ssklower 	if (SSEQ_GT(si->si_seq, cb->s_alo)) {
31325037Ssklower 		if (si->si_cc & SP_OB) {
31425037Ssklower 			if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) {
31525037Ssklower 				ns_error(dtom(si), NS_ERR_FULLUP, 0);
31625037Ssklower 				return (0);
31725037Ssklower 			} /* else queue this packet; */
31825037Ssklower 		} else {
31925037Ssklower 			spp_istat.notyet++;
32025037Ssklower 			return (1);
32125037Ssklower 		}
32221496Ssklower 	}
32321496Ssklower 
32421496Ssklower 	/*
32521496Ssklower 	 * Loop through all packets queued up to insert in
32621496Ssklower 	 * appropriate sequence.
32721496Ssklower 	 */
32821496Ssklower 
32921496Ssklower 	for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
33024330Ssklower 	    if (si->si_seq == SI(q)->si_seq) return (1); /*duplicate */
33125037Ssklower 	    if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) break;
33221496Ssklower 	}
33325037Ssklower 	insque(si, q->si_prev);
33425037Ssklower 	/*
33525037Ssklower 	 * If this packet is urgent, inform process
33625037Ssklower 	 */
33725037Ssklower 	if (si->si_cc & SP_OB) {
33825037Ssklower 		cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
33925037Ssklower 		sohasoutofband(so);
34025037Ssklower 		cb->s_oobflags |= SF_IOOB;
34125037Ssklower 	}
34221496Ssklower present:
34321496Ssklower #define SPINC sizeof(struct sphdr)
34421496Ssklower 	/*
34521496Ssklower 	 * Loop through all packets queued up to update acknowledge
34621496Ssklower 	 * number, and present all acknowledged data to user;
34721496Ssklower 	 * If in packet interface mode, show packet headers.
34821496Ssklower 	 */
34921496Ssklower 	for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
35024330Ssklower 		  if (SI(q)->si_seq == cb->s_ack) {
35121496Ssklower 			cb->s_ack++;
35221496Ssklower 			m = dtom(q);
35321496Ssklower 			if (SI(q)->si_cc & SP_OB) {
35425037Ssklower 				cb->s_oobflags &= ~SF_IOOB;
35521496Ssklower 				if (sb->sb_cc)
35621496Ssklower 					so->so_oobmark = sb->sb_cc;
35721496Ssklower 				else
35821496Ssklower 					so->so_state |= SS_RCVATMARK;
35921496Ssklower 			}
36021496Ssklower 			q = q->si_prev;
36121496Ssklower 			remque(q->si_next);
36221496Ssklower 			wakeup = 1;
36321496Ssklower 			if (packetp) {
36425037Ssklower 				sbappendrecord(sb, m);
36521496Ssklower 			} else {
36621496Ssklower 				cb->s_rhdr = *mtod(m, struct sphdr *);
36721496Ssklower 				m->m_off += SPINC;
36821496Ssklower 				m->m_len -= SPINC;
36925037Ssklower 				sbappend(sb, m);
37021496Ssklower 			}
37121496Ssklower 		  } else
37221496Ssklower 			break;
37321496Ssklower 	}
37421496Ssklower 	if (wakeup) sorwakeup(so);
37523515Ssklower 	return (0);
37621496Ssklower }
37721496Ssklower 
37821496Ssklower spp_ctlinput(cmd, arg)
37921496Ssklower 	int cmd;
38021496Ssklower 	caddr_t arg;
38121496Ssklower {
38221496Ssklower 	struct ns_addr *na;
38321496Ssklower 	extern u_char nsctlerrmap[];
38421496Ssklower 	extern spp_abort();
38524225Ssklower 	extern struct nspcb *idp_drop();
38623979Ssklower 	struct ns_errp *errp;
38723979Ssklower 	struct nspcb *nsp;
38824615Ssklower 	struct sockaddr_ns *sns;
38921496Ssklower 	int type;
39021496Ssklower 
39121496Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
39221496Ssklower 		return;
39321496Ssklower 	type = NS_ERR_UNREACH_HOST;
39421496Ssklower 
39521496Ssklower 	switch (cmd) {
39623515Ssklower 
39721496Ssklower 	case PRC_ROUTEDEAD:
39821496Ssklower 	case PRC_QUENCH:
39921496Ssklower 		break;
40021496Ssklower 
40121496Ssklower 	case PRC_IFDOWN:
40221496Ssklower 	case PRC_HOSTDEAD:
40321496Ssklower 	case PRC_HOSTUNREACH:
40424615Ssklower 		sns = (struct sockaddr_ns *)arg;
40524615Ssklower 		if (sns->sns_family != AF_NS)
40624615Ssklower 			return;
40724615Ssklower 		na = &sns->sns_addr;
40821496Ssklower 		break;
40921496Ssklower 
41021496Ssklower 	default:
41123979Ssklower 		errp = (struct ns_errp *)arg;
41223979Ssklower 		na = &errp->ns_err_idp.idp_dna;
41323979Ssklower 		type = errp->ns_err_num;
41424225Ssklower 		type = ntohs((u_short)type);
41521496Ssklower 	}
41621496Ssklower 	switch (type) {
41723515Ssklower 
41821496Ssklower 	case NS_ERR_UNREACH_HOST:
41923979Ssklower 		ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0);
42021496Ssklower 		break;
42123515Ssklower 
42221496Ssklower 	case NS_ERR_TOO_BIG:
42323979Ssklower 	case NS_ERR_NOSOCK:
42423979Ssklower 		nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port,
42523979Ssklower 			NS_WILDCARD);
42623979Ssklower 		if (nsp) {
42723979Ssklower 			if(nsp->nsp_pcb)
42824225Ssklower 				(void) spp_drop((struct sppcb *)nsp->nsp_pcb,
42924225Ssklower 						(int)nsctlerrmap[cmd]);
43023979Ssklower 			else
43124225Ssklower 				(void) idp_drop(nsp, (int)nsctlerrmap[cmd]);
43223979Ssklower 		}
43321496Ssklower 	}
43421496Ssklower }
43521496Ssklower 
43624225Ssklower #ifdef notdef
43721496Ssklower int
43821496Ssklower spp_fixmtu(nsp)
43921496Ssklower register struct nspcb *nsp;
44021496Ssklower {
44121496Ssklower 	register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb);
44221496Ssklower 	register struct mbuf *m;
44321496Ssklower 	register struct spidp *si;
44421496Ssklower 	struct ns_errp *ep;
44521496Ssklower 	struct sockbuf *sb;
44621496Ssklower 	int badseq, len;
44721496Ssklower 	struct mbuf *firstbad, *m0;
44821496Ssklower 
44921496Ssklower 	if (cb) {
45021496Ssklower 		/*
45121496Ssklower 		 * The notification that we have sent
45221496Ssklower 		 * too much is bad news -- we will
45321496Ssklower 		 * have to go through queued up so far
45421496Ssklower 		 * splitting ones which are too big and
45521496Ssklower 		 * reassigning sequence numbers and checksums.
45621496Ssklower 		 * we should then retransmit all packets from
45721496Ssklower 		 * one above the offending packet to the last one
45821496Ssklower 		 * we had sent (or our allocation)
45921496Ssklower 		 * then the offending one so that the any queued
46021496Ssklower 		 * data at our destination will be discarded.
46121496Ssklower 		 */
46221496Ssklower 		 ep = (struct ns_errp *)nsp->nsp_notify_param;
46321496Ssklower 		 sb = &nsp->nsp_socket->so_snd;
46421496Ssklower 		 cb->s_mtu = ep->ns_err_param;
46521496Ssklower 		 badseq = SI(&ep->ns_err_idp)->si_seq;
46621496Ssklower 		 for (m = sb->sb_mb; m; m = m->m_act) {
46721496Ssklower 			si = mtod(m, struct spidp *);
46821496Ssklower 			if (si->si_seq == badseq)
46921496Ssklower 				break;
47021496Ssklower 		 }
47124330Ssklower 		 if (m == 0) return;
47221496Ssklower 		 firstbad = m;
47321496Ssklower 		 /*for (;;) {*/
47421496Ssklower 			/* calculate length */
47521496Ssklower 			for (m0 = m, len = 0; m ; m = m->m_next)
47621496Ssklower 				len += m->m_len;
47721496Ssklower 			if (len > cb->s_mtu) {
47821496Ssklower 			}
47921496Ssklower 		/* FINISH THIS
48021496Ssklower 		} */
48121496Ssklower 	}
48221496Ssklower }
48324225Ssklower #endif
48421496Ssklower 
48521496Ssklower int spp_output_cnt = 0;
48623979Ssklower 
48721496Ssklower spp_output(cb, m0)
48821496Ssklower 	register struct sppcb *cb;
48921496Ssklower 	struct mbuf *m0;
49021496Ssklower {
49121496Ssklower 	struct socket *so = cb->s_nspcb->nsp_socket;
49221496Ssklower 	register struct mbuf *m;
49321496Ssklower 	register struct spidp *si = (struct spidp *) 0;
49421496Ssklower 	register struct sockbuf *sb = &(so->so_snd);
49521496Ssklower 	register int len = 0;
49624330Ssklower 	int error = 0;
49724330Ssklower 	u_short lookfor = 0;
49821496Ssklower 	struct mbuf *mprev;
49921496Ssklower 	extern int idpcksum;
50021496Ssklower 
50124330Ssklower 	if (m0) {
50224615Ssklower 		int mtu = cb->s_mtu;
50324615Ssklower 		int datalen;
50424615Ssklower 		/*
50524615Ssklower 		 * Make sure that packet isn't too big.
50624615Ssklower 		 */
50721496Ssklower 		for (m = m0; m ; m = m->m_next) {
50821496Ssklower 			mprev = m;
50921496Ssklower 			len += m->m_len;
51021496Ssklower 		}
51124615Ssklower 		datalen = (cb->s_flags & SF_HO) ?
51224615Ssklower 				len - sizeof (struct sphdr) : len;
51324615Ssklower 		if (datalen > mtu) {
51421496Ssklower 			if (cb->s_flags & SF_PI) {
51521496Ssklower 				m_freem(m0);
51623515Ssklower 				return (EMSGSIZE);
51721496Ssklower 			} else {
51821496Ssklower 				int off = 0;
51924615Ssklower 				int oldEM = cb->s_cc & SP_EM;
52024615Ssklower 
52124615Ssklower 				cb->s_cc &= ~SP_EM;
52221496Ssklower 				while (len > mtu) {
52321496Ssklower 					m = m_copy(m0, off, mtu);
52424330Ssklower 					if (m == NULL) {
52524615Ssklower 						error = ENOBUFS;
52624615Ssklower 						goto bad_copy;
52723515Ssklower 					}
52821496Ssklower 					error = spp_output(cb, m);
52921496Ssklower 					if (error) {
53024615Ssklower 					bad_copy:
53124615Ssklower 						cb->s_cc |= oldEM;
53221496Ssklower 						m_freem(m0);
53324615Ssklower 						return(error);
53421496Ssklower 					}
53521496Ssklower 					m_adj(m0, mtu);
53621496Ssklower 					len -= mtu;
53721496Ssklower 				}
53824615Ssklower 				cb->s_cc |= oldEM;
53921496Ssklower 			}
54021496Ssklower 		}
54124330Ssklower 		/*
54224330Ssklower 		 * Force length even, by adding a "garbage byte" if
54324330Ssklower 		 * necessary.
54424330Ssklower 		 */
54521496Ssklower 		if (len & 1) {
54623979Ssklower 			m = mprev;
54724330Ssklower 			if (m->m_len + m->m_off < MMAXOFF)
54821496Ssklower 				m->m_len++;
54924330Ssklower 			else {
55021496Ssklower 				struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
55121496Ssklower 
55221496Ssklower 				if (m1 == 0) {
55321496Ssklower 					m_freem(m0);
55421496Ssklower 					return (ENOBUFS);
55521496Ssklower 				}
55621496Ssklower 				m1->m_len = 1;
55721496Ssklower 				m1->m_off = MMAXOFF - 1;
55824330Ssklower 				m->m_next = m1;
55921496Ssklower 			}
56021496Ssklower 		}
56121496Ssklower 		m = m_get(M_DONTWAIT, MT_HEADER);
56221496Ssklower 		if (m == 0) {
56321496Ssklower 			m_freem(m0);
56423515Ssklower 			return (ENOBUFS);
56521496Ssklower 		}
56621496Ssklower 		/*
56721496Ssklower 		 * Fill in mbuf with extended SP header
56821496Ssklower 		 * and addresses and length put into network format.
56925623Ssklower 		 * Long align so prepended ip headers will work on Gould.
57021496Ssklower 		 */
57125623Ssklower 		m->m_off = MMAXOFF - sizeof (struct spidp) - 2;
57221496Ssklower 		m->m_len = sizeof (struct spidp);
57321496Ssklower 		m->m_next = m0;
57421496Ssklower 		si = mtod(m, struct spidp *);
57521496Ssklower 		*si = cb->s_shdr;
57621496Ssklower 		if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
57724330Ssklower 			register struct sphdr *sh;
57824330Ssklower 			if (m0->m_len < sizeof (*sh)) {
57924330Ssklower 				if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
58024330Ssklower 					(void) m_free(m);
58124330Ssklower 					m_freem(m0);
58224330Ssklower 					return (EINVAL);
58324330Ssklower 				}
58424330Ssklower 				m->m_next = m0;
58524330Ssklower 			}
58624330Ssklower 			sh = mtod(m0, struct sphdr *);
58721496Ssklower 			si->si_dt = sh->sp_dt;
58821496Ssklower 			si->si_cc |= sh->sp_cc & SP_EM;
58921496Ssklower 			m0->m_len -= sizeof (*sh);
59021496Ssklower 			m0->m_off += sizeof (*sh);
59121496Ssklower 			len -= sizeof (*sh);
59221496Ssklower 		}
59321496Ssklower 		len += sizeof(*si);
59423979Ssklower 		if (cb->s_oobflags & SF_SOOB) {
59523979Ssklower 			/*
59623979Ssklower 			 * Per jqj@cornell:
59723979Ssklower 			 * make sure OB packets convey exactly 1 byte.
59823979Ssklower 			 * If the packet is 1 byte or larger, we
59923979Ssklower 			 * have already guaranted there to be at least
60023979Ssklower 			 * one garbage byte for the checksum, and
60123979Ssklower 			 * extra bytes shouldn't hurt!
60223979Ssklower 			 */
60323979Ssklower 			if (len > sizeof(*si)) {
60423979Ssklower 				si->si_cc |= SP_OB;
60523979Ssklower 				len = (1 + sizeof(*si));
60623979Ssklower 			}
60723979Ssklower 		}
60824225Ssklower 		si->si_len = htons((u_short)len);
60921496Ssklower 		/*
61021496Ssklower 		 * queue stuff up for output
61121496Ssklower 		 */
61225037Ssklower 		sbappendrecord(sb, m);
61321496Ssklower 		cb->s_seq++;
61421496Ssklower 	}
61521496Ssklower 	/*
61621496Ssklower 	 * update window
61721496Ssklower 	 */
61821496Ssklower 	{
61924225Ssklower 		register struct sockbuf *sb2 = &so->so_rcv;
62025623Ssklower 		int credit = ((((int)sb2->sb_mbmax) - (int)sb2->sb_mbcnt) /
62124732Ssklower 						((short)cb->s_mtu));
62224732Ssklower 		int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1;
62321496Ssklower 
62424732Ssklower 		if (cb->s_alo < alo) {
62524732Ssklower 			/* If the amount we are raising the window
62624732Ssklower 			   is more than his remaining headroom, tell
62724732Ssklower 			   him about it.  In particular, if he is at
62824732Ssklower 			   his limit, any amount at all will do! */
62924732Ssklower 			u_short raise = alo - cb->s_alo;
63024732Ssklower 			u_short headroom = 1 + cb->s_alo - cb->s_ack;
63124732Ssklower 
63224732Ssklower 			if(SSEQ_LT(headroom, raise))
63324732Ssklower 				cb->s_flags |= SF_AK;
63424330Ssklower 			cb->s_alo = alo;
63524732Ssklower 		}
63621496Ssklower 	}
63721496Ssklower 
63821496Ssklower 	if (cb->s_oobflags & SF_SOOB) {
63921496Ssklower 		/*
64021496Ssklower 		 * must transmit this out of band packet
64121496Ssklower 		 */
64221496Ssklower 		cb->s_oobflags &= ~ SF_SOOB;
64321496Ssklower 	} else {
64421496Ssklower 		/*
64521496Ssklower 		 * Decide what to transmit:
64625168Ssklower 		 * If it is time to retransmit a packet,
64725168Ssklower 		 * send that.
64821496Ssklower 		 * If we have a new packet, send that
64921496Ssklower 		 * (So long as it is in our allocation)
65021496Ssklower 		 * Otherwise, see if it time to bang on them
65121496Ssklower 		 * to ask for our current allocation.
65221496Ssklower 		 */
65325168Ssklower 		if (cb->s_force == (1+TCPT_REXMT)) {
65425168Ssklower 			lookfor = cb->s_rack;
65525168Ssklower 		} else if (SSEQ_LT(cb->s_snt, cb->s_ralo)) {
65621496Ssklower 			lookfor = cb->s_snt + 1;
65721496Ssklower 		} else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) {
65821496Ssklower 			lookfor = 0;
65924330Ssklower 			if (cb->s_timer[TCPT_PERSIST] == 0) {
66021496Ssklower 				spp_setpersist(cb);
66124330Ssklower 				/* tcp has cb->s_rxtshift = 0; here */
66221496Ssklower 			}
66321496Ssklower 		}
66421496Ssklower 		m = sb->sb_mb;
66524330Ssklower 		while (m) {
66621496Ssklower 			si = mtod(m, struct spidp *);
66721496Ssklower 			m = m->m_act;
66821496Ssklower 			if (SSEQ_LT(si->si_seq, cb->s_rack)) {
66921496Ssklower 				if ((sb->sb_flags & SB_WAIT)
67021496Ssklower 				     || so->so_snd.sb_sel)
67121496Ssklower 					 sowwakeup(so);
67221496Ssklower 				sbdroprecord(sb);
67321496Ssklower 				si = 0;
67421496Ssklower 				continue;
67521496Ssklower 			}
67621496Ssklower 			if (SSEQ_LT(si->si_seq, lookfor))
67721496Ssklower 				continue;
67821496Ssklower 			break;
67921496Ssklower 		}
68024330Ssklower 		if (si && (si->si_seq != lookfor))
68124330Ssklower 			si = 0;
68221496Ssklower 	}
68321496Ssklower 	cb->s_want = lookfor;
68421496Ssklower 
68521496Ssklower 	if (si) {
68621496Ssklower 		/*
68721496Ssklower 		 * must make a copy of this packet for
68821496Ssklower 		 * idp_output to monkey with
68921496Ssklower 		 */
69024330Ssklower 		 m = m_copy(dtom(si), 0, (int)M_COPYALL);
69124330Ssklower 		 if (m == NULL)
69223515Ssklower 			return (ENOBUFS);
69323515Ssklower 		 m0 = m;
69421496Ssklower 		 si = mtod(m, struct spidp *);
69521496Ssklower 	} else if (cb->s_force || cb->s_flags & SF_AK) {
69621496Ssklower 		/*
69721496Ssklower 		 * Must send an acknowledgement or a probe
69821496Ssklower 		 */
69921496Ssklower 		m = m_get(M_DONTWAIT, MT_HEADER);
70021496Ssklower 		if (m == 0)
70123515Ssklower 			return (ENOBUFS);
70221496Ssklower 		/*
70321496Ssklower 		 * Fill in mbuf with extended SP header
70421496Ssklower 		 * and addresses and length put into network format.
70521496Ssklower 		 */
70621496Ssklower 		m->m_off = MMAXOFF - sizeof (struct spidp);
70721496Ssklower 		m->m_len = sizeof (*si);
70821496Ssklower 		m->m_next = 0;
70921496Ssklower 		si = mtod(m, struct spidp *);
71021496Ssklower 		*si = cb->s_shdr;
71121496Ssklower 		si->si_seq = cb->s_snt + 1;
71223979Ssklower 		si->si_len = htons(sizeof (*si));
71321496Ssklower 		si->si_cc |= SP_SP;
71421496Ssklower 	}
71521496Ssklower 	/*
71621496Ssklower 	 * Stuff checksum and output datagram.
71721496Ssklower 	 */
71821496Ssklower 	if (si) {
71925037Ssklower 		if (cb->s_flags & (SF_AK|SF_DELACK))
72025037Ssklower 			cb->s_flags &= ~(SF_AK|SF_DELACK);
72121496Ssklower 		/*
72221496Ssklower 		 * If we are almost out of allocation
72321496Ssklower 		 * or one of the timers has gone off
72421496Ssklower 		 * request an ack.
72521496Ssklower 		 */
72624330Ssklower 		if (SSEQ_GEQ(cb->s_seq, cb->s_ralo))
72721496Ssklower 			si->si_cc |= SP_SA;
72821496Ssklower 		if (cb->s_force) {
72921496Ssklower 			si->si_cc |= SP_SA;
73021496Ssklower 			cb->s_force = 0;
73121496Ssklower 		}
73224330Ssklower 		/*
73324330Ssklower 		 * If this is a new packet (and not a system packet),
73423979Ssklower 		 * and we are not currently timing anything,
73523979Ssklower 		 * time this one and ask for an ack.
73621496Ssklower 		 */
73724330Ssklower 		if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) {
73821496Ssklower 			cb->s_snt = si->si_seq;
73924330Ssklower 			if (cb->s_rtt == 0) {
74021496Ssklower 				cb->s_rtseq = si->si_seq;
74121496Ssklower 				cb->s_rtt = 1;
74221496Ssklower 				si->si_cc |= SP_SA;
74321496Ssklower 			}
74421496Ssklower 			/*
74521496Ssklower 			 * If the retransmit timer has not been set
74621496Ssklower 			 * and this is a real packet
74721496Ssklower 			 * then start the retransmit timer
74821496Ssklower 			 */
74924330Ssklower 			if (cb->s_timer[TCPT_REXMT] == 0) {
75021496Ssklower 				TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
75121496Ssklower 					tcp_beta * cb->s_srtt, TCPTV_MIN,
75221496Ssklower 					TCPTV_MAX);
75321496Ssklower 				cb->s_rxtshift = 0;
75421496Ssklower 			}
75521496Ssklower 		}
75621496Ssklower 		si->si_seq = htons(si->si_seq);
75721496Ssklower 		si->si_alo = htons(cb->s_alo);
75821496Ssklower 		si->si_ack = htons(cb->s_ack);
75921496Ssklower 
76021496Ssklower 		if (idpcksum) {
76121496Ssklower 			si->si_sum = 0;
76223979Ssklower 			len = ntohs(si->si_len);
76324330Ssklower 			if (len & 1)
76424330Ssklower 				len++;
76521496Ssklower 			si->si_sum = ns_cksum(dtom(si), len);
76621496Ssklower 		} else
76721496Ssklower 			si->si_sum = 0xffff;
76821496Ssklower 
76921496Ssklower 		if (so->so_options & SO_DEBUG || traceallspps)
77021496Ssklower 			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
77121496Ssklower 		spp_output_cnt++;
77221496Ssklower 		if (so->so_options & SO_DONTROUTE)
77321496Ssklower 			error = ns_output(m, (struct route *)0, NS_ROUTETOIF);
77421496Ssklower 		else
77521496Ssklower 			error = ns_output(m, &cb->s_nspcb->nsp_route, 0);
77621496Ssklower 		if (traceallspps && sppconsdebug) {
77721496Ssklower 			printf("spp_out: %x\n", error);
77821496Ssklower 		}
77925168Ssklower 		if (so->so_options & SO_DEBUG || traceallspps)
78025168Ssklower 			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
78121496Ssklower 	}
78223515Ssklower 	return (error);
78321496Ssklower }
78421496Ssklower 
78521496Ssklower /*ARGSUSED*/
78621496Ssklower spp_ctloutput(req, so, level, name, value)
78721496Ssklower 	int req;
78821496Ssklower 	struct socket *so;
78921496Ssklower 	int name;
79021496Ssklower 	struct mbuf **value;
79121496Ssklower {
79221496Ssklower 	register struct mbuf *m;
79321496Ssklower 	struct nspcb *nsp = sotonspcb(so);
79421496Ssklower 	register struct sppcb *cb;
79521496Ssklower 	int mask, error = 0;
79621496Ssklower 
79721496Ssklower 	if (level != NSPROTO_SPP) {
79821496Ssklower 		/* This will have to be changed when we do more general
79921496Ssklower 		   stacking of protocols */
80023515Ssklower 		return (idp_ctloutput(req, so, level, name, value));
80121496Ssklower 	}
80221496Ssklower 	if (nsp == NULL) {
80321496Ssklower 		error = EINVAL;
80421496Ssklower 		goto release;
80521496Ssklower 	} else
80621496Ssklower 		cb = nstosppcb(nsp);
80721496Ssklower 
80821496Ssklower 	switch (req) {
80923515Ssklower 
81021496Ssklower 	case PRCO_GETOPT:
81124330Ssklower 		if (value == NULL)
81223515Ssklower 			return (EINVAL);
81321496Ssklower 		m = m_get(M_DONTWAIT, MT_DATA);
81424330Ssklower 		if (m == NULL)
81523515Ssklower 			return (ENOBUFS);
81621496Ssklower 		switch (name) {
81723515Ssklower 
81821496Ssklower 		case SO_HEADERS_ON_INPUT:
81921496Ssklower 			mask = SF_HI;
82021496Ssklower 			goto get_flags;
82123515Ssklower 
82221496Ssklower 		case SO_HEADERS_ON_OUTPUT:
82321496Ssklower 			mask = SF_HO;
82421496Ssklower 		get_flags:
82521496Ssklower 			m->m_len = sizeof(short);
82621496Ssklower 			m->m_off = MMAXOFF - sizeof(short);
82721496Ssklower 			*mtod(m, short *) = cb->s_flags & mask;
82821496Ssklower 			break;
82923515Ssklower 
83024615Ssklower 		case SO_MTU:
83124615Ssklower 			m->m_len = sizeof(u_short);
83224615Ssklower 			m->m_off = MMAXOFF - sizeof(short);
83324615Ssklower 			*mtod(m, short *) = cb->s_mtu;
83424615Ssklower 			break;
83524615Ssklower 
83621496Ssklower 		case SO_LAST_HEADER:
83721496Ssklower 			m->m_len = sizeof(struct sphdr);
83821496Ssklower 			m->m_off = MMAXOFF - sizeof(struct sphdr);
83921496Ssklower 			*mtod(m, struct sphdr *) = cb->s_rhdr;
84021496Ssklower 			break;
84123515Ssklower 
84221496Ssklower 		case SO_DEFAULT_HEADERS:
84321496Ssklower 			m->m_len = sizeof(struct spidp);
84421496Ssklower 			m->m_off = MMAXOFF - sizeof(struct sphdr);
84521496Ssklower 			*mtod(m, struct sphdr *) = cb->s_shdr.si_s;
84625334Ssklower 			break;
84725334Ssklower 
84825334Ssklower 		default:
84925334Ssklower 			error = EINVAL;
85021496Ssklower 		}
85121496Ssklower 		*value = m;
85221496Ssklower 		break;
85323515Ssklower 
85421496Ssklower 	case PRCO_SETOPT:
85524615Ssklower 		if (value == 0 || *value == 0) {
85624615Ssklower 			error = EINVAL;
85724615Ssklower 			break;
85824615Ssklower 		}
85921496Ssklower 		switch (name) {
86024225Ssklower 			int *ok;
86121496Ssklower 
86221496Ssklower 		case SO_HEADERS_ON_INPUT:
86321496Ssklower 			mask = SF_HI;
86421496Ssklower 			goto set_head;
86523515Ssklower 
86621496Ssklower 		case SO_HEADERS_ON_OUTPUT:
86721496Ssklower 			mask = SF_HO;
86821496Ssklower 		set_head:
86924615Ssklower 			if (cb->s_flags & SF_PI) {
87021496Ssklower 				ok = mtod(*value, int *);
87121496Ssklower 				if (*ok)
87221496Ssklower 					cb->s_flags |= mask;
87321496Ssklower 				else
87421496Ssklower 					cb->s_flags &= ~mask;
87521496Ssklower 			} else error = EINVAL;
87621496Ssklower 			break;
87723515Ssklower 
87824615Ssklower 		case SO_MTU:
87924615Ssklower 			cb->s_mtu = *(mtod(*value, u_short *));
88024615Ssklower 			break;
88124615Ssklower 
88221496Ssklower 		case SO_DEFAULT_HEADERS:
88321496Ssklower 			{
88421496Ssklower 				register struct sphdr *sp
88521496Ssklower 						= mtod(*value, struct sphdr *);
88621496Ssklower 				cb->s_dt = sp->sp_dt;
88721496Ssklower 				cb->s_cc = sp->sp_cc & SP_EM;
88821496Ssklower 			}
88925334Ssklower 			break;
89025334Ssklower 
89125334Ssklower 		default:
89225334Ssklower 			error = EINVAL;
89321496Ssklower 		}
89424615Ssklower 		m_freem(*value);
89521496Ssklower 		break;
89621496Ssklower 	}
89721496Ssklower 	release:
89823515Ssklower 		return (error);
89921496Ssklower }
90021496Ssklower 
90121496Ssklower /*ARGSUSED*/
90221496Ssklower spp_usrreq(so, req, m, nam, rights)
90321496Ssklower 	struct socket *so;
90421496Ssklower 	int req;
90521496Ssklower 	struct mbuf *m, *nam, *rights;
90621496Ssklower {
90721496Ssklower 	struct nspcb *nsp = sotonspcb(so);
90821496Ssklower 	register struct sppcb *cb;
90921496Ssklower 	int s = splnet();
91021496Ssklower 	int error = 0, ostate;
91121496Ssklower 
91221496Ssklower 	if (req == PRU_CONTROL)
91321496Ssklower                 return (ns_control(so, (int)m, (caddr_t)nam,
91421496Ssklower 			(struct ifnet *)rights));
91521496Ssklower 	if (rights && rights->m_len) {
91621496Ssklower 		error = EINVAL;
91721496Ssklower 		goto release;
91821496Ssklower 	}
91921496Ssklower 	if (nsp == NULL) {
92021496Ssklower 		if (req != PRU_ATTACH) {
92121496Ssklower 			error = EINVAL;
92221496Ssklower 			goto release;
92321496Ssklower 		}
92421496Ssklower 	} else
92521496Ssklower 		cb = nstosppcb(nsp);
92621496Ssklower 
92721496Ssklower 	ostate = cb ? cb->s_state : 0;
92821496Ssklower 
92921496Ssklower 	switch (req) {
93023515Ssklower 
93121496Ssklower 	case PRU_ATTACH:
93221496Ssklower 		if (nsp != NULL) {
93321496Ssklower 			error = EISCONN;
93421496Ssklower 			break;
93521496Ssklower 		}
93621496Ssklower 		error = ns_pcballoc(so, &nspcb);
93721496Ssklower 		if (error)
93821496Ssklower 			break;
93921496Ssklower 		error = soreserve(so, 2048, 2048);
94021496Ssklower 		if (error)
94121496Ssklower 			break;
94221496Ssklower 		nsp = sotonspcb(so);
94321496Ssklower 		{
94425037Ssklower 			struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB);
94521496Ssklower 
94624330Ssklower 			if (mm == NULL) {
94721496Ssklower 				error = ENOBUFS;
94821496Ssklower 				break;
94921496Ssklower 			}
95021496Ssklower 			cb = mtod(mm, struct sppcb *);
95121496Ssklower 			cb->s_state = TCPS_LISTEN;
95221496Ssklower 			cb->s_snt = -1;
95321496Ssklower 			cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
95421496Ssklower 			cb->s_nspcb = nsp;
95521496Ssklower 			nsp->nsp_pcb = (caddr_t) cb;
95621496Ssklower 		}
95721496Ssklower 		break;
95821496Ssklower 
95921496Ssklower 	case PRU_DETACH:
96021496Ssklower 		if (nsp == NULL) {
96121496Ssklower 			error = ENOTCONN;
96221496Ssklower 			break;
96321496Ssklower 		}
96421496Ssklower 		if (cb->s_state > TCPS_LISTEN)
96521496Ssklower 			cb = spp_disconnect(cb);
96621496Ssklower 		else
96721496Ssklower 			cb = spp_close(cb);
96821496Ssklower 		break;
96921496Ssklower 
97021496Ssklower 	case PRU_BIND:
97121496Ssklower 		error = ns_pcbbind(nsp, nam);
97221496Ssklower 		break;
97321496Ssklower 
97421496Ssklower 	case PRU_LISTEN:
97521496Ssklower 		if (nsp->nsp_lport == 0)
97621496Ssklower 			error = ns_pcbbind(nsp, (struct mbuf *)0);
97721496Ssklower 		if (error == 0)
97821496Ssklower 			cb->s_state = TCPS_LISTEN;
97921496Ssklower 		break;
98021496Ssklower 
98121496Ssklower 	/*
98221496Ssklower 	 * Initiate connection to peer.
98321496Ssklower 	 * Enter SYN_SENT state, and mark socket as connecting.
98421496Ssklower 	 * Start keep-alive timer, setup prototype header,
98521496Ssklower 	 * Send initial system packet requesting connection.
98621496Ssklower 	 */
98721496Ssklower 	case PRU_CONNECT:
98821496Ssklower 		if (nsp->nsp_lport == 0) {
98921496Ssklower 			error = ns_pcbbind(nsp, (struct mbuf *)0);
99021496Ssklower 			if (error)
99121496Ssklower 				break;
99221496Ssklower 		}
99321496Ssklower 		error = ns_pcbconnect(nsp, nam);
99421496Ssklower 		if (error)
99521496Ssklower 			break;
99621496Ssklower 		soisconnecting(so);
99721496Ssklower 		cb->s_state = TCPS_SYN_SENT;
99821496Ssklower 		cb->s_did = 0;
99921496Ssklower 		spp_template(cb);
100021496Ssklower 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
100121496Ssklower 		cb->s_force = 1 + TCPTV_KEEP;
100221496Ssklower 		/*
100321496Ssklower 		 * Other party is required to respond to
100421496Ssklower 		 * the port I send from, but he is not
100521496Ssklower 		 * required to answer from where I am sending to,
100621496Ssklower 		 * so allow wildcarding.
100721496Ssklower 		 * original port I am sending to is still saved in
100821496Ssklower 		 * cb->s_dport.
100921496Ssklower 		 */
101021496Ssklower 		nsp->nsp_fport = 0;
101121496Ssklower 		error = spp_output(cb, (struct mbuf *) 0);
101221496Ssklower 		break;
101321496Ssklower 
101421496Ssklower 	case PRU_CONNECT2:
101521496Ssklower 		error = EOPNOTSUPP;
101621496Ssklower 		break;
101721496Ssklower 
101821496Ssklower 	/*
101921496Ssklower 	 * We may decide later to implement connection closing
102021496Ssklower 	 * handshaking at the spp level optionally.
102121496Ssklower 	 * here is the hook to do it:
102221496Ssklower 	 */
102321496Ssklower 	case PRU_DISCONNECT:
102421496Ssklower 		cb = spp_disconnect(cb);
102521496Ssklower 		break;
102621496Ssklower 
102721496Ssklower 	/*
102821496Ssklower 	 * Accept a connection.  Essentially all the work is
102921496Ssklower 	 * done at higher levels; just return the address
103021496Ssklower 	 * of the peer, storing through addr.
103121496Ssklower 	 */
103221496Ssklower 	case PRU_ACCEPT: {
103321496Ssklower 		struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
103421496Ssklower 
103521496Ssklower 		nam->m_len = sizeof (struct sockaddr_ns);
103621496Ssklower 		sns->sns_family = AF_NS;
103721496Ssklower 		sns->sns_addr = nsp->nsp_faddr;
103821496Ssklower 		break;
103921496Ssklower 		}
104021496Ssklower 
104121496Ssklower 	case PRU_SHUTDOWN:
104221496Ssklower 		socantsendmore(so);
104321496Ssklower 		cb = spp_usrclosed(cb);
104421496Ssklower 		if (cb)
104521496Ssklower 			error = spp_output(cb, (struct mbuf *) 0);
104621496Ssklower 		break;
104721496Ssklower 
104821496Ssklower 	/*
104921496Ssklower 	 * After a receive, possibly send acknowledgment
105021496Ssklower 	 * updating allocation.
105121496Ssklower 	 */
105221496Ssklower 	case PRU_RCVD:
105321496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
105421496Ssklower 		break;
105521496Ssklower 
105621496Ssklower 	case PRU_ABORT:
105724225Ssklower 		(void) spp_drop(cb, ECONNABORTED);
105821496Ssklower 		break;
105921496Ssklower 
106021496Ssklower 	case PRU_SENSE:
106121496Ssklower 	case PRU_CONTROL:
106221496Ssklower 		m = NULL;
106321496Ssklower 		error = EOPNOTSUPP;
106421496Ssklower 		break;
106521496Ssklower 
106621496Ssklower 	case PRU_RCVOOB:
106725037Ssklower 		if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
106825037Ssklower 		    (so->so_state & SS_RCVATMARK)) {
106925037Ssklower 			m->m_len = 1;
107025037Ssklower 			*mtod(m, caddr_t) = cb->s_iobc;
107124732Ssklower 			break;
107224732Ssklower 		}
107325037Ssklower 		error = EINVAL;
107421496Ssklower 		break;
107521496Ssklower 
107621496Ssklower 	case PRU_SENDOOB:
107721496Ssklower 		if (sbspace(&so->so_snd) < -512) {
107821496Ssklower 			error = ENOBUFS;
107921496Ssklower 			break;
108021496Ssklower 		}
108121496Ssklower 		cb->s_oobflags |= SF_SOOB;
108225623Ssklower 		/* fall into */
108325623Ssklower 	case PRU_SEND:
108421496Ssklower 		error = spp_output(cb, m);
108521496Ssklower 		m = NULL;
108621496Ssklower 		break;
108721496Ssklower 
108821496Ssklower 	case PRU_SOCKADDR:
108921496Ssklower 		ns_setsockaddr(nsp, nam);
109021496Ssklower 		break;
109121496Ssklower 
109221496Ssklower 	case PRU_PEERADDR:
109321496Ssklower 		ns_setpeeraddr(nsp, nam);
109421496Ssklower 		break;
109521496Ssklower 
109621496Ssklower 	case PRU_SLOWTIMO:
109721496Ssklower 		cb = spp_timers(cb, (int)nam);
109821496Ssklower 		break;
109921496Ssklower 
110021496Ssklower 	case PRU_FASTTIMO:
110121496Ssklower 	case PRU_PROTORCV:
110221496Ssklower 	case PRU_PROTOSEND:
110321496Ssklower 		error =  EOPNOTSUPP;
110421496Ssklower 		break;
110521496Ssklower 
110621496Ssklower 	default:
110721496Ssklower 		panic("sp_usrreq");
110821496Ssklower 	}
110921496Ssklower 	if (cb && (so->so_options & SO_DEBUG || traceallspps))
111024225Ssklower 		spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
111121496Ssklower release:
111221496Ssklower 	if (m != NULL)
111321496Ssklower 		m_freem(m);
111421496Ssklower 	splx(s);
111521496Ssklower 	return (error);
111621496Ssklower }
111721496Ssklower 
111821496Ssklower spp_usrreq_sp(so, req, m, nam, rights)
111921496Ssklower 	struct socket *so;
112021496Ssklower 	int req;
112121496Ssklower 	struct mbuf *m, *nam, *rights;
112221496Ssklower {
112321496Ssklower 	int error = spp_usrreq(so, req, m, nam, rights);
112421496Ssklower 
112524330Ssklower 	if (req == PRU_ATTACH && error == 0) {
112621496Ssklower 		struct nspcb *nsp = sotonspcb(so);
112721496Ssklower 		((struct sppcb *)nsp->nsp_pcb)->s_flags |=
112821496Ssklower 					(SF_HI | SF_HO | SF_PI);
112921496Ssklower 	}
113023515Ssklower 	return (error);
113121496Ssklower }
113221496Ssklower 
113321496Ssklower /*
113421496Ssklower  * Create template to be used to send spp packets on a connection.
113521496Ssklower  * Called after host entry created, fills
113621496Ssklower  * in a skeletal spp header (choosing connection id),
113721496Ssklower  * minimizing the amount of work necessary when the connection is used.
113821496Ssklower  */
113921496Ssklower spp_template(cb)
114021496Ssklower 	struct sppcb *cb;
114121496Ssklower {
114221496Ssklower 	register struct nspcb *nsp = cb->s_nspcb;
114321496Ssklower 	register struct spidp *n = &(cb->s_shdr);
114421496Ssklower 
114524615Ssklower 	cb->s_mtu = 576 - sizeof (struct spidp);
114621496Ssklower 	n->si_pt = NSPROTO_SPP;
114721496Ssklower 	n->si_sna = nsp->nsp_laddr;
114821496Ssklower 	n->si_dna = nsp->nsp_faddr;
114921496Ssklower 	n->si_sid = htons(spp_iss);
115021496Ssklower 	spp_iss += SPP_ISSINCR/2;
115121496Ssklower 	n->si_alo = 1;
115221496Ssklower }
115321496Ssklower 
115421496Ssklower /*
115521496Ssklower  * Close a SPIP control block:
115621496Ssklower  *	discard spp control block itself
115721496Ssklower  *	discard ns protocol control block
115821496Ssklower  *	wake up any sleepers
115921496Ssklower  */
116021496Ssklower struct sppcb *
116121496Ssklower spp_close(cb)
116221496Ssklower 	register struct sppcb *cb;
116321496Ssklower {
116421496Ssklower 	register struct spidp_q *s;
116521496Ssklower 	struct nspcb *nsp = cb->s_nspcb;
116621496Ssklower 	struct socket *so = nsp->nsp_socket;
116721496Ssklower 	register struct mbuf *m;
116821496Ssklower 
116921496Ssklower 	s = cb->s_q.si_next;
117021496Ssklower 	while (s != &(cb->s_q)) {
117121496Ssklower 		s = s->si_next;
117221496Ssklower 		m = dtom(s->si_prev);
117321496Ssklower 		remque(s->si_prev);
117421496Ssklower 		m_freem(m);
117521496Ssklower 	}
117621496Ssklower 	(void) m_free(dtom(cb));
117721496Ssklower 	nsp->nsp_pcb = 0;
117821496Ssklower 	soisdisconnected(so);
117921496Ssklower 	ns_pcbdetach(nsp);
118023515Ssklower 	return ((struct sppcb *)0);
118121496Ssklower }
118221496Ssklower /*
118321496Ssklower  *	Someday we may do level 3 handshaking
118421496Ssklower  *	to close a connection or send a xerox style error.
118521496Ssklower  *	For now, just close.
118621496Ssklower  */
118721496Ssklower struct sppcb *
118821496Ssklower spp_usrclosed(cb)
118921496Ssklower 	register struct sppcb *cb;
119021496Ssklower {
119123515Ssklower 	return (spp_close(cb));
119221496Ssklower }
119321496Ssklower struct sppcb *
119421496Ssklower spp_disconnect(cb)
119521496Ssklower 	register struct sppcb *cb;
119621496Ssklower {
119723515Ssklower 	return (spp_close(cb));
119821496Ssklower }
119921496Ssklower /*
120021496Ssklower  * Drop connection, reporting
120121496Ssklower  * the specified error.
120221496Ssklower  */
120321496Ssklower struct sppcb *
120421496Ssklower spp_drop(cb, errno)
120521496Ssklower 	register struct sppcb *cb;
120621496Ssklower 	int errno;
120721496Ssklower {
120821496Ssklower 	struct socket *so = cb->s_nspcb->nsp_socket;
120921496Ssklower 
121021496Ssklower 	/*
121121496Ssklower 	 * someday, in the xerox world
121221496Ssklower 	 * we will generate error protocol packets
121321496Ssklower 	 * announcing that the socket has gone away.
121421496Ssklower 	 */
121521496Ssklower 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
121621496Ssklower 		tp->t_state = TCPS_CLOSED;
121721496Ssklower 		(void) tcp_output(tp);
121821496Ssklower 	}*/
121921496Ssklower 	so->so_error = errno;
122021496Ssklower 	return (spp_close(cb));
122121496Ssklower }
122221496Ssklower 
122321496Ssklower spp_abort(nsp)
122421496Ssklower 	struct nspcb *nsp;
122521496Ssklower {
122621496Ssklower 
122724225Ssklower 	(void) spp_close((struct sppcb *)nsp->nsp_pcb);
122821496Ssklower }
122921496Ssklower 
123021496Ssklower spp_setpersist(cb)
123121496Ssklower 	register struct sppcb *cb;
123221496Ssklower {
123321496Ssklower 
123421496Ssklower 	/*if (cb->s_timer[TCPT_REXMT])
123521496Ssklower 		panic("spp_output REXMT");*/
123621496Ssklower 	/*
123721496Ssklower 	 * Start/restart persistance timer.
123821496Ssklower 	 */
123921496Ssklower 	TCPT_RANGESET(cb->s_timer[TCPT_PERSIST],
124021496Ssklower 	    ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift,
124121496Ssklower 	    TCPTV_PERSMIN, TCPTV_MAX);
124221496Ssklower 	cb->s_rxtshift++;
124321496Ssklower 	if (cb->s_rxtshift >= TCP_MAXRXTSHIFT)
124421496Ssklower 		cb->s_rxtshift = 0;
124521496Ssklower }
124621496Ssklower /*
124721496Ssklower  * Fast timeout routine for processing delayed acks
124821496Ssklower  */
124921496Ssklower int spp_ftcnt;
125021496Ssklower spp_fasttimo()
125121496Ssklower {
125221496Ssklower 	register struct nspcb *nsp;
125321496Ssklower 	register struct sppcb *cb;
125421496Ssklower 	int s = splnet();
125521496Ssklower 
125621496Ssklower 	nsp = nspcb.nsp_next;
125721496Ssklower 	spp_ftcnt++;
125821496Ssklower 	if (nsp)
125921496Ssklower 	for (; nsp != &nspcb; nsp = nsp->nsp_next)
126021496Ssklower 		if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
126121496Ssklower 		    (cb->s_flags & SF_DELACK)) {
126221496Ssklower 			cb->s_flags &= ~SF_DELACK;
126321496Ssklower 			cb->s_flags |= SF_AK;
126421496Ssklower 			(void) spp_output(cb, (struct mbuf *) 0);
126521496Ssklower 		}
126621496Ssklower 	splx(s);
126721496Ssklower }
126821496Ssklower 
126921496Ssklower /*
127021496Ssklower  * spp protocol timeout routine called every 500 ms.
127121496Ssklower  * Updates the timers in all active pcb's and
127221496Ssklower  * causes finite state machine actions if timers expire.
127321496Ssklower  */
127421496Ssklower spp_slowtimo()
127521496Ssklower {
127621496Ssklower 	register struct nspcb *ip, *ipnxt;
127721496Ssklower 	register struct sppcb *cb;
127821496Ssklower 	int s = splnet();
127921496Ssklower 	register int i;
128021496Ssklower 
128121496Ssklower 	/*
128221496Ssklower 	 * Search through tcb's and update active timers.
128321496Ssklower 	 */
128421496Ssklower 	ip = nspcb.nsp_next;
128521496Ssklower 	if (ip == 0) {
128621496Ssklower 		splx(s);
128721496Ssklower 		return;
128821496Ssklower 	}
128921496Ssklower 	while (ip != &nspcb) {
129021496Ssklower 		cb = nstosppcb(ip);
129121496Ssklower 		ipnxt = ip->nsp_next;
129221496Ssklower 		if (cb == 0)
129321496Ssklower 			goto tpgone;
129421496Ssklower 		for (i = 0; i < TCPT_NTIMERS; i++) {
129521496Ssklower 			if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
129621496Ssklower 				(void) spp_usrreq(cb->s_nspcb->nsp_socket,
129721496Ssklower 				    PRU_SLOWTIMO, (struct mbuf *)0,
129821496Ssklower 				    (struct mbuf *)i, (struct mbuf *)0);
129921496Ssklower 				if (ipnxt->nsp_prev != ip)
130021496Ssklower 					goto tpgone;
130121496Ssklower 			}
130221496Ssklower 		}
130321496Ssklower 		cb->s_idle++;
130421496Ssklower 		if (cb->s_rtt)
130521496Ssklower 			cb->s_rtt++;
130621496Ssklower tpgone:
130721496Ssklower 		ip = ipnxt;
130821496Ssklower 	}
130921496Ssklower 	spp_iss += SPP_ISSINCR/PR_SLOWHZ;		/* increment iss */
131021496Ssklower 	splx(s);
131121496Ssklower }
131221496Ssklower 
131321496Ssklower float	spp_backoff[TCP_MAXRXTSHIFT] =
131421496Ssklower     { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 };
131524412Swalsh int sppexprexmtbackoff = 0;
131621496Ssklower /*
131724615Ssklower  * SPP timer processing.
131821496Ssklower  */
131921496Ssklower struct sppcb *
132021496Ssklower spp_timers(cb, timer)
132121496Ssklower 	register struct sppcb *cb;
132221496Ssklower 	int timer;
132321496Ssklower {
132421496Ssklower 
132521496Ssklower 	cb->s_force = 1 + timer;
132621496Ssklower 	switch (timer) {
132721496Ssklower 
132821496Ssklower 	/*
132921496Ssklower 	 * 2 MSL timeout in shutdown went off.  Delete connection
133021496Ssklower 	 * control block.
133121496Ssklower 	 */
133221496Ssklower 	case TCPT_2MSL:
133321496Ssklower 		cb = spp_close(cb);
133421496Ssklower 		break;
133521496Ssklower 
133621496Ssklower 	/*
133721496Ssklower 	 * Retransmission timer went off.  Message has not
133821496Ssklower 	 * been acked within retransmit interval.  Back off
133921496Ssklower 	 * to a longer retransmit interval and retransmit all
134021496Ssklower 	 * unacknowledged messages in the window.
134121496Ssklower 	 */
134221496Ssklower 	case TCPT_REXMT:
134321496Ssklower 		cb->s_rxtshift++;
134421496Ssklower 		if (cb->s_rxtshift > TCP_MAXRXTSHIFT) {
134521496Ssklower 			cb = spp_drop(cb, ETIMEDOUT);
134621496Ssklower 			break;
134721496Ssklower 		}
134821496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
134921496Ssklower 		TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
135021496Ssklower 		    (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX);
135124412Swalsh 		if (sppexprexmtbackoff) {
135221496Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
135321496Ssklower 			    cb->s_timer[TCPT_REXMT] << cb->s_rxtshift,
135421496Ssklower 			    TCPTV_MIN, TCPTV_MAX);
135521496Ssklower 		} else {
135621496Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
135721496Ssklower 			    cb->s_timer[TCPT_REXMT] *
135821496Ssklower 			        spp_backoff[cb->s_rxtshift - 1],
135921496Ssklower 			    TCPTV_MIN, TCPTV_MAX);
136021496Ssklower 		}
136121496Ssklower 		break;
136221496Ssklower 
136321496Ssklower 	/*
136421496Ssklower 	 * Persistance timer into zero window.
136521496Ssklower 	 * Force a probe to be sent.
136621496Ssklower 	 */
136721496Ssklower 	case TCPT_PERSIST:
136821496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
136921496Ssklower 		spp_setpersist(cb);
137021496Ssklower 		break;
137121496Ssklower 
137221496Ssklower 	/*
137321496Ssklower 	 * Keep-alive timer went off; send something
137421496Ssklower 	 * or drop connection if idle for too long.
137521496Ssklower 	 */
137621496Ssklower 	case TCPT_KEEP:
137721496Ssklower 		if (cb->s_state < TCPS_ESTABLISHED)
137821496Ssklower 			goto dropit;
137921496Ssklower 		if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
138021496Ssklower 		    	if (cb->s_idle >= TCPTV_MAXIDLE)
138121496Ssklower 				goto dropit;
138221496Ssklower 			(void) spp_output(cb, (struct mbuf *) 0);
138321496Ssklower 		} else
138421496Ssklower 			cb->s_idle = 0;
138521496Ssklower 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
138621496Ssklower 		break;
138721496Ssklower 	dropit:
138821496Ssklower 		cb = spp_drop(cb, ETIMEDOUT);
138921496Ssklower 		break;
139021496Ssklower 	}
139121496Ssklower 	return (cb);
139221496Ssklower }
1393