xref: /csrg-svn/sys/netns/spp_usrreq.c (revision 25037)
123215Smckusick /*
223215Smckusick  * Copyright (c) 1982 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*25037Ssklower  *	@(#)spp_usrreq.c	6.13 (Berkeley) 09/26/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;
45*25037Ssklower 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 
208*25037Ssklower 	if (spp_reass(cb, si)) {
20921496Ssklower 		goto drop;
21021496Ssklower 	}
211*25037Ssklower 	(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  */
237*25037Ssklower 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)
255*25037Ssklower 		cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_AK);
256*25037Ssklower 	if (SSEQ_GT(si->si_ack, cb->s_rack)) {
25721496Ssklower 		cb->s_rack = si->si_ack;
25821496Ssklower 		/*
259*25037Ssklower 		 * If there are other packets outstanding,
260*25037Ssklower 		 * restart the timer for them.
261*25037Ssklower 		 */
262*25037Ssklower 		if (SSEQ_GEQ(cb->s_snt, si->si_ack)) {
263*25037Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
264*25037Ssklower 				tcp_beta * cb->s_srtt, TCPTV_MIN,
265*25037Ssklower 				TCPTV_MAX);
266*25037Ssklower 			cb->s_rxtshift = 0;
267*25037Ssklower 		} else
268*25037Ssklower 			cb->s_timer[TCPT_REXMT] = 0;
269*25037Ssklower 		/*
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 	}
283*25037Ssklower 	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 	 */
301*25037Ssklower 	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 	 */
311*25037Ssklower 	if (SSEQ_GT(si->si_seq, cb->s_alo)) {
312*25037Ssklower 		if (si->si_cc & SP_OB) {
313*25037Ssklower 			if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) {
314*25037Ssklower 				ns_error(dtom(si), NS_ERR_FULLUP, 0);
315*25037Ssklower 				return (0);
316*25037Ssklower 			} /* else queue this packet; */
317*25037Ssklower 		} else {
318*25037Ssklower 			spp_istat.notyet++;
319*25037Ssklower 			return (1);
320*25037Ssklower 		}
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 */
330*25037Ssklower 	    if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) break;
33121496Ssklower 	}
332*25037Ssklower 	insque(si, q->si_prev);
333*25037Ssklower 	/*
334*25037Ssklower 	 * If this packet is urgent, inform process
335*25037Ssklower 	 */
336*25037Ssklower 	if (si->si_cc & SP_OB) {
337*25037Ssklower 		cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
338*25037Ssklower 		sohasoutofband(so);
339*25037Ssklower 		cb->s_oobflags |= SF_IOOB;
340*25037Ssklower 	}
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) {
353*25037Ssklower 				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) {
363*25037Ssklower 				sbappendrecord(sb, m);
36421496Ssklower 			} else {
36521496Ssklower 				cb->s_rhdr = *mtod(m, struct sphdr *);
36621496Ssklower 				m->m_off += SPINC;
36721496Ssklower 				m->m_len -= SPINC;
368*25037Ssklower 				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 		 */
610*25037Ssklower 		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:
64421496Ssklower 		 * If we have a new packet, send that
64521496Ssklower 		 * (So long as it is in our allocation)
64621496Ssklower 		 * If it is time to retransmit a packet,
64721496Ssklower 		 * send that.
64821496Ssklower 		 * Otherwise, see if it time to bang on them
64921496Ssklower 		 * to ask for our current allocation.
65021496Ssklower 		 */
65121496Ssklower 		if (SSEQ_LT(cb->s_snt, cb->s_ralo))
65221496Ssklower 			lookfor = cb->s_snt + 1;
65324330Ssklower 		else if (cb->s_force == (1+TCPT_REXMT)) {
65421496Ssklower 			lookfor = cb->s_rack;
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) {
717*25037Ssklower 		if (cb->s_flags & (SF_AK|SF_DELACK))
718*25037Ssklower 			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 		}
77723515Ssklower 		return (error);
77821496Ssklower 	}
77921496Ssklower 	if (so->so_options & SO_DEBUG || traceallspps)
78021496Ssklower 		spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
78123515Ssklower 	return (error);
78221496Ssklower }
78321496Ssklower 
78421496Ssklower /*ARGSUSED*/
78521496Ssklower spp_ctloutput(req, so, level, name, value)
78621496Ssklower 	int req;
78721496Ssklower 	struct socket *so;
78821496Ssklower 	int name;
78921496Ssklower 	struct mbuf **value;
79021496Ssklower {
79121496Ssklower 	register struct mbuf *m;
79221496Ssklower 	struct nspcb *nsp = sotonspcb(so);
79321496Ssklower 	register struct sppcb *cb;
79421496Ssklower 	int mask, error = 0;
79521496Ssklower 
79621496Ssklower 	if (level != NSPROTO_SPP) {
79721496Ssklower 		/* This will have to be changed when we do more general
79821496Ssklower 		   stacking of protocols */
79923515Ssklower 		return (idp_ctloutput(req, so, level, name, value));
80021496Ssklower 	}
80121496Ssklower 	if (nsp == NULL) {
80221496Ssklower 		error = EINVAL;
80321496Ssklower 		goto release;
80421496Ssklower 	} else
80521496Ssklower 		cb = nstosppcb(nsp);
80621496Ssklower 
80721496Ssklower 	switch (req) {
80823515Ssklower 
80921496Ssklower 	case PRCO_GETOPT:
81024330Ssklower 		if (value == NULL)
81123515Ssklower 			return (EINVAL);
81221496Ssklower 		m = m_get(M_DONTWAIT, MT_DATA);
81324330Ssklower 		if (m == NULL)
81423515Ssklower 			return (ENOBUFS);
81521496Ssklower 		switch (name) {
81623515Ssklower 
81721496Ssklower 		case SO_HEADERS_ON_INPUT:
81821496Ssklower 			mask = SF_HI;
81921496Ssklower 			goto get_flags;
82023515Ssklower 
82121496Ssklower 		case SO_HEADERS_ON_OUTPUT:
82221496Ssklower 			mask = SF_HO;
82321496Ssklower 		get_flags:
82421496Ssklower 			m->m_len = sizeof(short);
82521496Ssklower 			m->m_off = MMAXOFF - sizeof(short);
82621496Ssklower 			*mtod(m, short *) = cb->s_flags & mask;
82721496Ssklower 			break;
82823515Ssklower 
82924615Ssklower 		case SO_MTU:
83024615Ssklower 			m->m_len = sizeof(u_short);
83124615Ssklower 			m->m_off = MMAXOFF - sizeof(short);
83224615Ssklower 			*mtod(m, short *) = cb->s_mtu;
83324615Ssklower 			break;
83424615Ssklower 
83521496Ssklower 		case SO_LAST_HEADER:
83621496Ssklower 			m->m_len = sizeof(struct sphdr);
83721496Ssklower 			m->m_off = MMAXOFF - sizeof(struct sphdr);
83821496Ssklower 			*mtod(m, struct sphdr *) = cb->s_rhdr;
83921496Ssklower 			break;
84023515Ssklower 
84121496Ssklower 		case SO_DEFAULT_HEADERS:
84221496Ssklower 			m->m_len = sizeof(struct spidp);
84321496Ssklower 			m->m_off = MMAXOFF - sizeof(struct sphdr);
84421496Ssklower 			*mtod(m, struct sphdr *) = cb->s_shdr.si_s;
84521496Ssklower 		}
84621496Ssklower 		*value = m;
84721496Ssklower 		break;
84823515Ssklower 
84921496Ssklower 	case PRCO_SETOPT:
85024615Ssklower 		if (value == 0 || *value == 0) {
85124615Ssklower 			error = EINVAL;
85224615Ssklower 			break;
85324615Ssklower 		}
85421496Ssklower 		switch (name) {
85524225Ssklower 			int *ok;
85621496Ssklower 
85721496Ssklower 		case SO_HEADERS_ON_INPUT:
85821496Ssklower 			mask = SF_HI;
85921496Ssklower 			goto set_head;
86023515Ssklower 
86121496Ssklower 		case SO_HEADERS_ON_OUTPUT:
86221496Ssklower 			mask = SF_HO;
86321496Ssklower 		set_head:
86424615Ssklower 			if (cb->s_flags & SF_PI) {
86521496Ssklower 				ok = mtod(*value, int *);
86621496Ssklower 				if (*ok)
86721496Ssklower 					cb->s_flags |= mask;
86821496Ssklower 				else
86921496Ssklower 					cb->s_flags &= ~mask;
87021496Ssklower 			} else error = EINVAL;
87121496Ssklower 			break;
87223515Ssklower 
87324615Ssklower 		case SO_MTU:
87424615Ssklower 			cb->s_mtu = *(mtod(*value, u_short *));
87524615Ssklower 			break;
87624615Ssklower 
87721496Ssklower 		case SO_DEFAULT_HEADERS:
87821496Ssklower 			{
87921496Ssklower 				register struct sphdr *sp
88021496Ssklower 						= mtod(*value, struct sphdr *);
88121496Ssklower 				cb->s_dt = sp->sp_dt;
88221496Ssklower 				cb->s_cc = sp->sp_cc & SP_EM;
88321496Ssklower 			}
88421496Ssklower 		}
88524615Ssklower 		m_freem(*value);
88621496Ssklower 		break;
88721496Ssklower 	}
88821496Ssklower 	release:
88923515Ssklower 		return (error);
89021496Ssklower }
89121496Ssklower 
89221496Ssklower /*ARGSUSED*/
89321496Ssklower spp_usrreq(so, req, m, nam, rights)
89421496Ssklower 	struct socket *so;
89521496Ssklower 	int req;
89621496Ssklower 	struct mbuf *m, *nam, *rights;
89721496Ssklower {
89821496Ssklower 	struct nspcb *nsp = sotonspcb(so);
89921496Ssklower 	register struct sppcb *cb;
90021496Ssklower 	int s = splnet();
90121496Ssklower 	int error = 0, ostate;
90221496Ssklower 
90321496Ssklower 	if (req == PRU_CONTROL)
90421496Ssklower                 return (ns_control(so, (int)m, (caddr_t)nam,
90521496Ssklower 			(struct ifnet *)rights));
90621496Ssklower 	if (rights && rights->m_len) {
90721496Ssklower 		error = EINVAL;
90821496Ssklower 		goto release;
90921496Ssklower 	}
91021496Ssklower 	if (nsp == NULL) {
91121496Ssklower 		if (req != PRU_ATTACH) {
91221496Ssklower 			error = EINVAL;
91321496Ssklower 			goto release;
91421496Ssklower 		}
91521496Ssklower 	} else
91621496Ssklower 		cb = nstosppcb(nsp);
91721496Ssklower 
91821496Ssklower 	ostate = cb ? cb->s_state : 0;
91921496Ssklower 
92021496Ssklower 	switch (req) {
92123515Ssklower 
92221496Ssklower 	case PRU_ATTACH:
92321496Ssklower 		if (nsp != NULL) {
92421496Ssklower 			error = EISCONN;
92521496Ssklower 			break;
92621496Ssklower 		}
92721496Ssklower 		error = ns_pcballoc(so, &nspcb);
92821496Ssklower 		if (error)
92921496Ssklower 			break;
93021496Ssklower 		error = soreserve(so, 2048, 2048);
93121496Ssklower 		if (error)
93221496Ssklower 			break;
93321496Ssklower 		nsp = sotonspcb(so);
93421496Ssklower 		{
935*25037Ssklower 			struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB);
93621496Ssklower 
93724330Ssklower 			if (mm == NULL) {
93821496Ssklower 				error = ENOBUFS;
93921496Ssklower 				break;
94021496Ssklower 			}
94121496Ssklower 			cb = mtod(mm, struct sppcb *);
94221496Ssklower 			cb->s_state = TCPS_LISTEN;
94321496Ssklower 			cb->s_snt = -1;
94421496Ssklower 			cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
94521496Ssklower 			cb->s_nspcb = nsp;
94621496Ssklower 			nsp->nsp_pcb = (caddr_t) cb;
94721496Ssklower 		}
94821496Ssklower 		break;
94921496Ssklower 
95021496Ssklower 	case PRU_DETACH:
95121496Ssklower 		if (nsp == NULL) {
95221496Ssklower 			error = ENOTCONN;
95321496Ssklower 			break;
95421496Ssklower 		}
95521496Ssklower 		if (cb->s_state > TCPS_LISTEN)
95621496Ssklower 			cb = spp_disconnect(cb);
95721496Ssklower 		else
95821496Ssklower 			cb = spp_close(cb);
95921496Ssklower 		break;
96021496Ssklower 
96121496Ssklower 	case PRU_BIND:
96221496Ssklower 		error = ns_pcbbind(nsp, nam);
96321496Ssklower 		break;
96421496Ssklower 
96521496Ssklower 	case PRU_LISTEN:
96621496Ssklower 		if (nsp->nsp_lport == 0)
96721496Ssklower 			error = ns_pcbbind(nsp, (struct mbuf *)0);
96821496Ssklower 		if (error == 0)
96921496Ssklower 			cb->s_state = TCPS_LISTEN;
97021496Ssklower 		break;
97121496Ssklower 
97221496Ssklower 	/*
97321496Ssklower 	 * Initiate connection to peer.
97421496Ssklower 	 * Enter SYN_SENT state, and mark socket as connecting.
97521496Ssklower 	 * Start keep-alive timer, setup prototype header,
97621496Ssklower 	 * Send initial system packet requesting connection.
97721496Ssklower 	 */
97821496Ssklower 	case PRU_CONNECT:
97921496Ssklower 		if (nsp->nsp_lport == 0) {
98021496Ssklower 			error = ns_pcbbind(nsp, (struct mbuf *)0);
98121496Ssklower 			if (error)
98221496Ssklower 				break;
98321496Ssklower 		}
98421496Ssklower 		error = ns_pcbconnect(nsp, nam);
98521496Ssklower 		if (error)
98621496Ssklower 			break;
98721496Ssklower 		soisconnecting(so);
98821496Ssklower 		cb->s_state = TCPS_SYN_SENT;
98921496Ssklower 		cb->s_did = 0;
99021496Ssklower 		spp_template(cb);
99121496Ssklower 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
99221496Ssklower 		cb->s_force = 1 + TCPTV_KEEP;
99321496Ssklower 		/*
99421496Ssklower 		 * Other party is required to respond to
99521496Ssklower 		 * the port I send from, but he is not
99621496Ssklower 		 * required to answer from where I am sending to,
99721496Ssklower 		 * so allow wildcarding.
99821496Ssklower 		 * original port I am sending to is still saved in
99921496Ssklower 		 * cb->s_dport.
100021496Ssklower 		 */
100121496Ssklower 		nsp->nsp_fport = 0;
100221496Ssklower 		error = spp_output(cb, (struct mbuf *) 0);
100321496Ssklower 		break;
100421496Ssklower 
100521496Ssklower 	case PRU_CONNECT2:
100621496Ssklower 		error = EOPNOTSUPP;
100721496Ssklower 		break;
100821496Ssklower 
100921496Ssklower 	/*
101021496Ssklower 	 * We may decide later to implement connection closing
101121496Ssklower 	 * handshaking at the spp level optionally.
101221496Ssklower 	 * here is the hook to do it:
101321496Ssklower 	 */
101421496Ssklower 	case PRU_DISCONNECT:
101521496Ssklower 		cb = spp_disconnect(cb);
101621496Ssklower 		break;
101721496Ssklower 
101821496Ssklower 	/*
101921496Ssklower 	 * Accept a connection.  Essentially all the work is
102021496Ssklower 	 * done at higher levels; just return the address
102121496Ssklower 	 * of the peer, storing through addr.
102221496Ssklower 	 */
102321496Ssklower 	case PRU_ACCEPT: {
102421496Ssklower 		struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
102521496Ssklower 
102621496Ssklower 		nam->m_len = sizeof (struct sockaddr_ns);
102721496Ssklower 		sns->sns_family = AF_NS;
102821496Ssklower 		sns->sns_addr = nsp->nsp_faddr;
102921496Ssklower 		break;
103021496Ssklower 		}
103121496Ssklower 
103221496Ssklower 	case PRU_SHUTDOWN:
103321496Ssklower 		socantsendmore(so);
103421496Ssklower 		cb = spp_usrclosed(cb);
103521496Ssklower 		if (cb)
103621496Ssklower 			error = spp_output(cb, (struct mbuf *) 0);
103721496Ssklower 		break;
103821496Ssklower 
103921496Ssklower 	/*
104021496Ssklower 	 * After a receive, possibly send acknowledgment
104121496Ssklower 	 * updating allocation.
104221496Ssklower 	 */
104321496Ssklower 	case PRU_RCVD:
104421496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
104521496Ssklower 		break;
104621496Ssklower 
104721496Ssklower 	case PRU_SEND:
104821496Ssklower 		error = spp_output(cb, m);
104921496Ssklower 		m = NULL;
105021496Ssklower 		break;
105121496Ssklower 
105221496Ssklower 	case PRU_ABORT:
105324225Ssklower 		(void) spp_drop(cb, ECONNABORTED);
105421496Ssklower 		break;
105521496Ssklower 
105621496Ssklower 	case PRU_SENSE:
105721496Ssklower 	case PRU_CONTROL:
105821496Ssklower 		m = NULL;
105921496Ssklower 		error = EOPNOTSUPP;
106021496Ssklower 		break;
106121496Ssklower 
106221496Ssklower 	case PRU_RCVOOB:
1063*25037Ssklower 		if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
1064*25037Ssklower 		    (so->so_state & SS_RCVATMARK)) {
1065*25037Ssklower 			m->m_len = 1;
1066*25037Ssklower 			*mtod(m, caddr_t) = cb->s_iobc;
106724732Ssklower 			break;
106824732Ssklower 		}
1069*25037Ssklower 		error = EINVAL;
107021496Ssklower 		break;
107121496Ssklower 
107221496Ssklower 	case PRU_SENDOOB:
107321496Ssklower 		if (sbspace(&so->so_snd) < -512) {
107421496Ssklower 			m_freem(m);
107521496Ssklower 			error = ENOBUFS;
107621496Ssklower 			break;
107721496Ssklower 		}
107821496Ssklower 		cb->s_oobflags |= SF_SOOB;
107921496Ssklower 		error = spp_output(cb, m);
108021496Ssklower 		m = NULL;
108121496Ssklower 		break;
108221496Ssklower 
108321496Ssklower 	case PRU_SOCKADDR:
108421496Ssklower 		ns_setsockaddr(nsp, nam);
108521496Ssklower 		break;
108621496Ssklower 
108721496Ssklower 	case PRU_PEERADDR:
108821496Ssklower 		ns_setpeeraddr(nsp, nam);
108921496Ssklower 		break;
109021496Ssklower 
109121496Ssklower 	case PRU_SLOWTIMO:
109221496Ssklower 		cb = spp_timers(cb, (int)nam);
109321496Ssklower 		break;
109421496Ssklower 
109521496Ssklower 	case PRU_FASTTIMO:
109621496Ssklower 	case PRU_PROTORCV:
109721496Ssklower 	case PRU_PROTOSEND:
109821496Ssklower 		error =  EOPNOTSUPP;
109921496Ssklower 		break;
110021496Ssklower 
110121496Ssklower 	default:
110221496Ssklower 		panic("sp_usrreq");
110321496Ssklower 	}
110421496Ssklower 	if (cb && (so->so_options & SO_DEBUG || traceallspps))
110524225Ssklower 		spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
110621496Ssklower release:
110721496Ssklower 	if (m != NULL)
110821496Ssklower 		m_freem(m);
110921496Ssklower 	splx(s);
111021496Ssklower 	return (error);
111121496Ssklower }
111221496Ssklower 
111321496Ssklower spp_usrreq_sp(so, req, m, nam, rights)
111421496Ssklower 	struct socket *so;
111521496Ssklower 	int req;
111621496Ssklower 	struct mbuf *m, *nam, *rights;
111721496Ssklower {
111821496Ssklower 	int error = spp_usrreq(so, req, m, nam, rights);
111921496Ssklower 
112024330Ssklower 	if (req == PRU_ATTACH && error == 0) {
112121496Ssklower 		struct nspcb *nsp = sotonspcb(so);
112221496Ssklower 		((struct sppcb *)nsp->nsp_pcb)->s_flags |=
112321496Ssklower 					(SF_HI | SF_HO | SF_PI);
112421496Ssklower 	}
112523515Ssklower 	return (error);
112621496Ssklower }
112721496Ssklower 
112821496Ssklower /*
112921496Ssklower  * Create template to be used to send spp packets on a connection.
113021496Ssklower  * Called after host entry created, fills
113121496Ssklower  * in a skeletal spp header (choosing connection id),
113221496Ssklower  * minimizing the amount of work necessary when the connection is used.
113321496Ssklower  */
113421496Ssklower spp_template(cb)
113521496Ssklower 	struct sppcb *cb;
113621496Ssklower {
113721496Ssklower 	register struct nspcb *nsp = cb->s_nspcb;
113821496Ssklower 	register struct spidp *n = &(cb->s_shdr);
113921496Ssklower 
114024615Ssklower 	cb->s_mtu = 576 - sizeof (struct spidp);
114121496Ssklower 	n->si_pt = NSPROTO_SPP;
114221496Ssklower 	n->si_sna = nsp->nsp_laddr;
114321496Ssklower 	n->si_dna = nsp->nsp_faddr;
114421496Ssklower 	n->si_sid = htons(spp_iss);
114521496Ssklower 	spp_iss += SPP_ISSINCR/2;
114621496Ssklower 	n->si_alo = 1;
114721496Ssklower }
114821496Ssklower 
114921496Ssklower /*
115021496Ssklower  * Close a SPIP control block:
115121496Ssklower  *	discard spp control block itself
115221496Ssklower  *	discard ns protocol control block
115321496Ssklower  *	wake up any sleepers
115421496Ssklower  */
115521496Ssklower struct sppcb *
115621496Ssklower spp_close(cb)
115721496Ssklower 	register struct sppcb *cb;
115821496Ssklower {
115921496Ssklower 	register struct spidp_q *s;
116021496Ssklower 	struct nspcb *nsp = cb->s_nspcb;
116121496Ssklower 	struct socket *so = nsp->nsp_socket;
116221496Ssklower 	register struct mbuf *m;
116321496Ssklower 
116421496Ssklower 	s = cb->s_q.si_next;
116521496Ssklower 	while (s != &(cb->s_q)) {
116621496Ssklower 		s = s->si_next;
116721496Ssklower 		m = dtom(s->si_prev);
116821496Ssklower 		remque(s->si_prev);
116921496Ssklower 		m_freem(m);
117021496Ssklower 	}
117121496Ssklower 	(void) m_free(dtom(cb));
117221496Ssklower 	nsp->nsp_pcb = 0;
117321496Ssklower 	soisdisconnected(so);
117421496Ssklower 	ns_pcbdetach(nsp);
117523515Ssklower 	return ((struct sppcb *)0);
117621496Ssklower }
117721496Ssklower /*
117821496Ssklower  *	Someday we may do level 3 handshaking
117921496Ssklower  *	to close a connection or send a xerox style error.
118021496Ssklower  *	For now, just close.
118121496Ssklower  */
118221496Ssklower struct sppcb *
118321496Ssklower spp_usrclosed(cb)
118421496Ssklower 	register struct sppcb *cb;
118521496Ssklower {
118623515Ssklower 	return (spp_close(cb));
118721496Ssklower }
118821496Ssklower struct sppcb *
118921496Ssklower spp_disconnect(cb)
119021496Ssklower 	register struct sppcb *cb;
119121496Ssklower {
119223515Ssklower 	return (spp_close(cb));
119321496Ssklower }
119421496Ssklower /*
119521496Ssklower  * Drop connection, reporting
119621496Ssklower  * the specified error.
119721496Ssklower  */
119821496Ssklower struct sppcb *
119921496Ssklower spp_drop(cb, errno)
120021496Ssklower 	register struct sppcb *cb;
120121496Ssklower 	int errno;
120221496Ssklower {
120321496Ssklower 	struct socket *so = cb->s_nspcb->nsp_socket;
120421496Ssklower 
120521496Ssklower 	/*
120621496Ssklower 	 * someday, in the xerox world
120721496Ssklower 	 * we will generate error protocol packets
120821496Ssklower 	 * announcing that the socket has gone away.
120921496Ssklower 	 */
121021496Ssklower 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
121121496Ssklower 		tp->t_state = TCPS_CLOSED;
121221496Ssklower 		(void) tcp_output(tp);
121321496Ssklower 	}*/
121421496Ssklower 	so->so_error = errno;
121521496Ssklower 	return (spp_close(cb));
121621496Ssklower }
121721496Ssklower 
121821496Ssklower spp_abort(nsp)
121921496Ssklower 	struct nspcb *nsp;
122021496Ssklower {
122121496Ssklower 
122224225Ssklower 	(void) spp_close((struct sppcb *)nsp->nsp_pcb);
122321496Ssklower }
122421496Ssklower 
122521496Ssklower spp_setpersist(cb)
122621496Ssklower 	register struct sppcb *cb;
122721496Ssklower {
122821496Ssklower 
122921496Ssklower 	/*if (cb->s_timer[TCPT_REXMT])
123021496Ssklower 		panic("spp_output REXMT");*/
123121496Ssklower 	/*
123221496Ssklower 	 * Start/restart persistance timer.
123321496Ssklower 	 */
123421496Ssklower 	TCPT_RANGESET(cb->s_timer[TCPT_PERSIST],
123521496Ssklower 	    ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift,
123621496Ssklower 	    TCPTV_PERSMIN, TCPTV_MAX);
123721496Ssklower 	cb->s_rxtshift++;
123821496Ssklower 	if (cb->s_rxtshift >= TCP_MAXRXTSHIFT)
123921496Ssklower 		cb->s_rxtshift = 0;
124021496Ssklower }
124121496Ssklower /*
124221496Ssklower  * Fast timeout routine for processing delayed acks
124321496Ssklower  */
124421496Ssklower int spp_ftcnt;
124521496Ssklower spp_fasttimo()
124621496Ssklower {
124721496Ssklower 	register struct nspcb *nsp;
124821496Ssklower 	register struct sppcb *cb;
124921496Ssklower 	int s = splnet();
125021496Ssklower 
125121496Ssklower 	nsp = nspcb.nsp_next;
125221496Ssklower 	spp_ftcnt++;
125321496Ssklower 	if (nsp)
125421496Ssklower 	for (; nsp != &nspcb; nsp = nsp->nsp_next)
125521496Ssklower 		if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
125621496Ssklower 		    (cb->s_flags & SF_DELACK)) {
125721496Ssklower 			cb->s_flags &= ~SF_DELACK;
125821496Ssklower 			cb->s_flags |= SF_AK;
125921496Ssklower 			(void) spp_output(cb, (struct mbuf *) 0);
126021496Ssklower 		}
126121496Ssklower 	splx(s);
126221496Ssklower }
126321496Ssklower 
126421496Ssklower /*
126521496Ssklower  * spp protocol timeout routine called every 500 ms.
126621496Ssklower  * Updates the timers in all active pcb's and
126721496Ssklower  * causes finite state machine actions if timers expire.
126821496Ssklower  */
126921496Ssklower spp_slowtimo()
127021496Ssklower {
127121496Ssklower 	register struct nspcb *ip, *ipnxt;
127221496Ssklower 	register struct sppcb *cb;
127321496Ssklower 	int s = splnet();
127421496Ssklower 	register int i;
127521496Ssklower 
127621496Ssklower 	/*
127721496Ssklower 	 * Search through tcb's and update active timers.
127821496Ssklower 	 */
127921496Ssklower 	ip = nspcb.nsp_next;
128021496Ssklower 	if (ip == 0) {
128121496Ssklower 		splx(s);
128221496Ssklower 		return;
128321496Ssklower 	}
128421496Ssklower 	while (ip != &nspcb) {
128521496Ssklower 		cb = nstosppcb(ip);
128621496Ssklower 		ipnxt = ip->nsp_next;
128721496Ssklower 		if (cb == 0)
128821496Ssklower 			goto tpgone;
128921496Ssklower 		for (i = 0; i < TCPT_NTIMERS; i++) {
129021496Ssklower 			if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
129121496Ssklower 				(void) spp_usrreq(cb->s_nspcb->nsp_socket,
129221496Ssklower 				    PRU_SLOWTIMO, (struct mbuf *)0,
129321496Ssklower 				    (struct mbuf *)i, (struct mbuf *)0);
129421496Ssklower 				if (ipnxt->nsp_prev != ip)
129521496Ssklower 					goto tpgone;
129621496Ssklower 			}
129721496Ssklower 		}
129821496Ssklower 		cb->s_idle++;
129921496Ssklower 		if (cb->s_rtt)
130021496Ssklower 			cb->s_rtt++;
130121496Ssklower tpgone:
130221496Ssklower 		ip = ipnxt;
130321496Ssklower 	}
130421496Ssklower 	spp_iss += SPP_ISSINCR/PR_SLOWHZ;		/* increment iss */
130521496Ssklower 	splx(s);
130621496Ssklower }
130721496Ssklower 
130821496Ssklower float	spp_backoff[TCP_MAXRXTSHIFT] =
130921496Ssklower     { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 };
131024412Swalsh int sppexprexmtbackoff = 0;
131121496Ssklower /*
131224615Ssklower  * SPP timer processing.
131321496Ssklower  */
131421496Ssklower struct sppcb *
131521496Ssklower spp_timers(cb, timer)
131621496Ssklower 	register struct sppcb *cb;
131721496Ssklower 	int timer;
131821496Ssklower {
131921496Ssklower 
132021496Ssklower 	cb->s_force = 1 + timer;
132121496Ssklower 	switch (timer) {
132221496Ssklower 
132321496Ssklower 	/*
132421496Ssklower 	 * 2 MSL timeout in shutdown went off.  Delete connection
132521496Ssklower 	 * control block.
132621496Ssklower 	 */
132721496Ssklower 	case TCPT_2MSL:
132821496Ssklower 		cb = spp_close(cb);
132921496Ssklower 		break;
133021496Ssklower 
133121496Ssklower 	/*
133221496Ssklower 	 * Retransmission timer went off.  Message has not
133321496Ssklower 	 * been acked within retransmit interval.  Back off
133421496Ssklower 	 * to a longer retransmit interval and retransmit all
133521496Ssklower 	 * unacknowledged messages in the window.
133621496Ssklower 	 */
133721496Ssklower 	case TCPT_REXMT:
133821496Ssklower 		cb->s_rxtshift++;
133921496Ssklower 		if (cb->s_rxtshift > TCP_MAXRXTSHIFT) {
134021496Ssklower 			cb = spp_drop(cb, ETIMEDOUT);
134121496Ssklower 			break;
134221496Ssklower 		}
134321496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
134421496Ssklower 		TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
134521496Ssklower 		    (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX);
134624412Swalsh 		if (sppexprexmtbackoff) {
134721496Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
134821496Ssklower 			    cb->s_timer[TCPT_REXMT] << cb->s_rxtshift,
134921496Ssklower 			    TCPTV_MIN, TCPTV_MAX);
135021496Ssklower 		} else {
135121496Ssklower 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
135221496Ssklower 			    cb->s_timer[TCPT_REXMT] *
135321496Ssklower 			        spp_backoff[cb->s_rxtshift - 1],
135421496Ssklower 			    TCPTV_MIN, TCPTV_MAX);
135521496Ssklower 		}
135621496Ssklower 		break;
135721496Ssklower 
135821496Ssklower 	/*
135921496Ssklower 	 * Persistance timer into zero window.
136021496Ssklower 	 * Force a probe to be sent.
136121496Ssklower 	 */
136221496Ssklower 	case TCPT_PERSIST:
136321496Ssklower 		(void) spp_output(cb, (struct mbuf *) 0);
136421496Ssklower 		spp_setpersist(cb);
136521496Ssklower 		break;
136621496Ssklower 
136721496Ssklower 	/*
136821496Ssklower 	 * Keep-alive timer went off; send something
136921496Ssklower 	 * or drop connection if idle for too long.
137021496Ssklower 	 */
137121496Ssklower 	case TCPT_KEEP:
137221496Ssklower 		if (cb->s_state < TCPS_ESTABLISHED)
137321496Ssklower 			goto dropit;
137421496Ssklower 		if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
137521496Ssklower 		    	if (cb->s_idle >= TCPTV_MAXIDLE)
137621496Ssklower 				goto dropit;
137721496Ssklower 			(void) spp_output(cb, (struct mbuf *) 0);
137821496Ssklower 		} else
137921496Ssklower 			cb->s_idle = 0;
138021496Ssklower 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
138121496Ssklower 		break;
138221496Ssklower 	dropit:
138321496Ssklower 		cb = spp_drop(cb, ETIMEDOUT);
138421496Ssklower 		break;
138521496Ssklower 	}
138621496Ssklower 	return (cb);
138721496Ssklower }
1388