xref: /original-bsd/sys/netns/spp_usrreq.c (revision 57124d5e)
1 /*
2  * Copyright (c) 1984, 1985, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)spp_usrreq.c	7.2 (Berkeley) 10/28/86
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "dir.h"
12 #include "user.h"
13 #include "mbuf.h"
14 #include "protosw.h"
15 #include "socket.h"
16 #include "socketvar.h"
17 #include "errno.h"
18 
19 #include "../net/if.h"
20 #include "../net/route.h"
21 #include "../netinet/tcp_fsm.h"
22 #include "../netinet/tcp_timer.h"
23 
24 #include "ns.h"
25 #include "ns_pcb.h"
26 #include "idp.h"
27 #include "idp_var.h"
28 #include "ns_error.h"
29 #include "sp.h"
30 #include "spidp.h"
31 #include "spp_var.h"
32 #include "spp_debug.h"
33 
34 /*
35  * SP protocol implementation.
36  */
37 spp_init()
38 {
39 
40 	spp_iss = 1; /* WRONG !! should fish it out of TODR */
41 }
42 struct spidp spp_savesi;
43 int traceallspps = 0;
44 extern int sppconsdebug;
45 int spp_hardnosed;
46 int spp_use_delack = 0;
47 
48 /*ARGSUSED*/
49 spp_input(m, nsp, ifp)
50 	register struct mbuf *m;
51 	register struct nspcb *nsp;
52 	struct ifnet *ifp;
53 {
54 	register struct sppcb *cb;
55 	register struct spidp *si = mtod(m, struct spidp *);
56 	register struct socket *so;
57 	short ostate;
58 	int dropsocket = 0;
59 
60 
61 	if (nsp == 0) {
62 		panic("No nspcb in spp_input\n");
63 		return;
64 	}
65 
66 	cb = nstosppcb(nsp);
67 	if (cb == 0) goto bad;
68 
69 	if (m->m_len < sizeof(*si)) {
70 		if ((m = m_pullup(m, sizeof(*si))) == 0) {
71 			spp_istat.hdrops++;
72 			return;
73 		}
74 		si = mtod(m, struct spidp *);
75 	}
76 	si->si_seq = ntohs(si->si_seq);
77 	si->si_ack = ntohs(si->si_ack);
78 	si->si_alo = ntohs(si->si_alo);
79 
80 	so = nsp->nsp_socket;
81 	if (so->so_options & SO_DEBUG || traceallspps) {
82 		ostate = cb->s_state;
83 		spp_savesi = *si;
84 	}
85 	if (so->so_options & SO_ACCEPTCONN) {
86 		so = sonewconn(so);
87 		if (so == 0) {
88 			spp_istat.nonucn++;
89 			goto drop;
90 		}
91 		/*
92 		 * This is ugly, but ....
93 		 *
94 		 * Mark socket as temporary until we're
95 		 * committed to keeping it.  The code at
96 		 * ``drop'' and ``dropwithreset'' check the
97 		 * flag dropsocket to see if the temporary
98 		 * socket created here should be discarded.
99 		 * We mark the socket as discardable until
100 		 * we're committed to it below in TCPS_LISTEN.
101 		 */
102 		dropsocket++;
103 		nsp = (struct nspcb *)so->so_pcb;
104 		nsp->nsp_laddr = si->si_dna;
105 		cb = nstosppcb(nsp);
106 		cb->s_state = TCPS_LISTEN;
107 	}
108 
109 	/*
110 	 * Packet received on connection.
111 	 * reset idle time and keep-alive timer;
112 	 */
113 	cb->s_idle = 0;
114 	cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
115 
116 	switch (cb->s_state) {
117 
118 	case TCPS_LISTEN:{
119 		struct mbuf *am;
120 		register struct sockaddr_ns *sns;
121 		struct ns_addr laddr;
122 
123 		/*
124 		 * If somebody here was carying on a conversation
125 		 * and went away, and his pen pal thinks he can
126 		 * still talk, we get the misdirected packet.
127 		 */
128 		if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
129 			spp_istat.gonawy++;
130 			goto dropwithreset;
131 		}
132 		am = m_get(M_DONTWAIT, MT_SONAME);
133 		if (am == NULL)
134 			goto drop;
135 		am->m_len = sizeof (struct sockaddr_ns);
136 		sns = mtod(am, struct sockaddr_ns *);
137 		sns->sns_family = AF_NS;
138 		sns->sns_addr = si->si_sna;
139 		laddr = nsp->nsp_laddr;
140 		if (ns_nullhost(laddr))
141 			nsp->nsp_laddr = si->si_dna;
142 		if (ns_pcbconnect(nsp, am)) {
143 			nsp->nsp_laddr = laddr;
144 			(void) m_free(am);
145 			spp_istat.noconn++;
146 			goto drop;
147 		}
148 		(void) m_free(am);
149 		spp_template(cb);
150 		dropsocket = 0;		/* committed to socket */
151 		cb->s_did = si->si_sid;
152 		cb->s_rack = si->si_ack;
153 		cb->s_ralo = si->si_alo;
154 #define THREEWAYSHAKE
155 #ifdef THREEWAYSHAKE
156 		cb->s_state = TCPS_SYN_RECEIVED;
157 		cb->s_force = 1 + TCPT_REXMT;
158 		cb->s_timer[TCPT_REXMT] = 2 * TCPTV_MIN;
159 		}
160 		break;
161 	/*
162 	 * This state means that we have heard a response
163 	 * to our acceptance of their connection
164 	 * It is probably logically unnecessary in this
165 	 * implementation.
166 	 */
167 	 case TCPS_SYN_RECEIVED:
168 		if (si->si_did!=cb->s_sid) {
169 			spp_istat.wrncon++;
170 			goto drop;
171 		}
172 #endif
173 		nsp->nsp_fport =  si->si_sport;
174 		cb->s_timer[TCPT_REXMT] = 0;
175 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
176 		soisconnected(so);
177 		cb->s_state = TCPS_ESTABLISHED;
178 		break;
179 
180 	/*
181 	 * This state means that we have gotten a response
182 	 * to our attempt to establish a connection.
183 	 * We fill in the data from the other side,
184 	 * telling us which port to respond to, instead of the well-
185 	 * known one we might have sent to in the first place.
186 	 * We also require that this is a response to our
187 	 * connection id.
188 	 */
189 	case TCPS_SYN_SENT:
190 		if (si->si_did!=cb->s_sid) {
191 			spp_istat.notme++;
192 			goto drop;
193 		}
194 		cb->s_did = si->si_sid;
195 		cb->s_rack = si->si_ack;
196 		cb->s_ralo = si->si_alo;
197 		cb->s_dport = nsp->nsp_fport =  si->si_sport;
198 		cb->s_timer[TCPT_REXMT] = 0;
199 		cb->s_flags |= SF_AK;
200 		soisconnected(so);
201 		cb->s_state = TCPS_ESTABLISHED;
202 	}
203 	if (so->so_options & SO_DEBUG || traceallspps)
204 		spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0);
205 
206 	m->m_len -= sizeof (struct idp);
207 	m->m_off += sizeof (struct idp);
208 
209 	if (spp_reass(cb, si)) {
210 		m_freem(m);
211 	}
212 	(void) spp_output(cb, (struct mbuf *)0);
213 	return;
214 
215 dropwithreset:
216 	if (dropsocket)
217 		(void) soabort(so);
218 	si->si_seq = ntohs(si->si_seq);
219 	si->si_ack = ntohs(si->si_ack);
220 	si->si_alo = ntohs(si->si_alo);
221 	ns_error(dtom(si), NS_ERR_NOSOCK, 0);
222 	if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)
223 		spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
224 	return;
225 
226 drop:
227 bad:
228 	if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)
229 		spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
230 	m_freem(m);
231 }
232 
233 /*
234  * This is structurally similar to the tcp reassembly routine
235  * but its function is somewhat different:  It merely queues
236  * packets up, and suppresses duplicates.
237  */
238 spp_reass(cb, si)
239 register struct sppcb *cb;
240 register struct spidp *si;
241 {
242 	register struct spidp_q *q;
243 	register struct mbuf *m;
244 	struct socket *so = cb->s_nspcb->nsp_socket;
245 	struct sockbuf *sb = & (so->so_rcv);
246 	char packetp = cb->s_flags & SF_HI;
247 	char wakeup = 0;
248 
249 
250 	if (si == SI(0))
251 		goto present;
252 	/*
253 	 * Update our news from them.
254 	 */
255 	if (si->si_cc & SP_SA)
256 		cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_AK);
257 	if (SSEQ_GT(si->si_ack, cb->s_rack)) {
258 		cb->s_rack = si->si_ack;
259 		/*
260 		 * If there are other packets outstanding,
261 		 * restart the timer for them.
262 		 */
263 		if (SSEQ_GEQ(cb->s_snt, si->si_ack)) {
264 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
265 				tcp_beta * cb->s_srtt, TCPTV_MIN,
266 				TCPTV_MAX);
267 			cb->s_rxtshift = 0;
268 		} else
269 			cb->s_timer[TCPT_REXMT] = 0;
270 		/*
271 		 * If transmit timer is running and timed sequence
272 		 * number was acked, update smoothed round trip time.
273 		 */
274 		if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
275 			if (cb->s_srtt == 0)
276 				cb->s_srtt = cb->s_rtt;
277 			else
278 				cb->s_srtt =
279 				    tcp_alpha * cb->s_srtt +
280 				    (1 - tcp_alpha) * cb->s_rtt;
281 			cb->s_rtt = 0;
282 		}
283 	}
284 	if (SSEQ_GT(si->si_alo, cb->s_ralo)) {
285 		cb->s_ralo = si->si_alo;
286 		cb->s_timer[TCPT_PERSIST] = 0;
287 	}
288 	/*
289 	 * If this is a system packet, we don't need to
290 	 * queue it up, and won't update acknowledge #
291 	 */
292 	if (si->si_cc & SP_SP) {
293 		m_freem(dtom(si));
294 		return (0);
295 	}
296 
297 	/*
298 	 * If this packet number has a sequence number less
299 	 * than that of the first packet not yet seen coming
300 	 * from them, this must be a duplicate, so drop.
301 	 */
302 	if (SSEQ_LT(si->si_seq, cb->s_ack)) {
303 		spp_istat.bdreas++;
304 		if (si->si_seq == cb->s_ack-1)
305 			spp_istat.lstdup++;
306 		return (1);
307 	}
308 	/*
309 	 * If this packet number is higher than that which
310 	 * we have allocated refuse it, unless urgent
311 	 */
312 	if (SSEQ_GT(si->si_seq, cb->s_alo)) {
313 		if (si->si_cc & SP_OB) {
314 			if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) {
315 				ns_error(dtom(si), NS_ERR_FULLUP, 0);
316 				return (0);
317 			} /* else queue this packet; */
318 		} else {
319 			spp_istat.notyet++;
320 			return (1);
321 		}
322 	}
323 
324 	/*
325 	 * Loop through all packets queued up to insert in
326 	 * appropriate sequence.
327 	 */
328 
329 	for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
330 	    if (si->si_seq == SI(q)->si_seq) return (1); /*duplicate */
331 	    if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) break;
332 	}
333 	insque(si, q->si_prev);
334 	/*
335 	 * If this packet is urgent, inform process
336 	 */
337 	if (si->si_cc & SP_OB) {
338 		cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
339 		sohasoutofband(so);
340 		cb->s_oobflags |= SF_IOOB;
341 	}
342 present:
343 #define SPINC sizeof(struct sphdr)
344 	/*
345 	 * Loop through all packets queued up to update acknowledge
346 	 * number, and present all acknowledged data to user;
347 	 * If in packet interface mode, show packet headers.
348 	 */
349 	for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
350 		  if (SI(q)->si_seq == cb->s_ack) {
351 			cb->s_ack++;
352 			m = dtom(q);
353 			if (SI(q)->si_cc & SP_OB) {
354 				cb->s_oobflags &= ~SF_IOOB;
355 				if (sb->sb_cc)
356 					so->so_oobmark = sb->sb_cc;
357 				else
358 					so->so_state |= SS_RCVATMARK;
359 			}
360 			q = q->si_prev;
361 			remque(q->si_next);
362 			wakeup = 1;
363 			if (packetp) {
364 				sbappendrecord(sb, m);
365 			} else {
366 				cb->s_rhdr = *mtod(m, struct sphdr *);
367 				m->m_off += SPINC;
368 				m->m_len -= SPINC;
369 				sbappend(sb, m);
370 			}
371 		  } else
372 			break;
373 	}
374 	if (wakeup) sorwakeup(so);
375 	return (0);
376 }
377 
378 spp_ctlinput(cmd, arg)
379 	int cmd;
380 	caddr_t arg;
381 {
382 	struct ns_addr *na;
383 	extern u_char nsctlerrmap[];
384 	extern spp_abort();
385 	extern struct nspcb *idp_drop();
386 	struct ns_errp *errp;
387 	struct nspcb *nsp;
388 	struct sockaddr_ns *sns;
389 	int type;
390 
391 	if (cmd < 0 || cmd > PRC_NCMDS)
392 		return;
393 	type = NS_ERR_UNREACH_HOST;
394 
395 	switch (cmd) {
396 
397 	case PRC_ROUTEDEAD:
398 	case PRC_QUENCH:
399 		break;
400 
401 	case PRC_IFDOWN:
402 	case PRC_HOSTDEAD:
403 	case PRC_HOSTUNREACH:
404 		sns = (struct sockaddr_ns *)arg;
405 		if (sns->sns_family != AF_NS)
406 			return;
407 		na = &sns->sns_addr;
408 		break;
409 
410 	default:
411 		errp = (struct ns_errp *)arg;
412 		na = &errp->ns_err_idp.idp_dna;
413 		type = errp->ns_err_num;
414 		type = ntohs((u_short)type);
415 	}
416 	switch (type) {
417 
418 	case NS_ERR_UNREACH_HOST:
419 		ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0);
420 		break;
421 
422 	case NS_ERR_TOO_BIG:
423 	case NS_ERR_NOSOCK:
424 		nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port,
425 			NS_WILDCARD);
426 		if (nsp) {
427 			if(nsp->nsp_pcb)
428 				(void) spp_drop((struct sppcb *)nsp->nsp_pcb,
429 						(int)nsctlerrmap[cmd]);
430 			else
431 				(void) idp_drop(nsp, (int)nsctlerrmap[cmd]);
432 		}
433 	}
434 }
435 
436 #ifdef notdef
437 int
438 spp_fixmtu(nsp)
439 register struct nspcb *nsp;
440 {
441 	register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb);
442 	register struct mbuf *m;
443 	register struct spidp *si;
444 	struct ns_errp *ep;
445 	struct sockbuf *sb;
446 	int badseq, len;
447 	struct mbuf *firstbad, *m0;
448 
449 	if (cb) {
450 		/*
451 		 * The notification that we have sent
452 		 * too much is bad news -- we will
453 		 * have to go through queued up so far
454 		 * splitting ones which are too big and
455 		 * reassigning sequence numbers and checksums.
456 		 * we should then retransmit all packets from
457 		 * one above the offending packet to the last one
458 		 * we had sent (or our allocation)
459 		 * then the offending one so that the any queued
460 		 * data at our destination will be discarded.
461 		 */
462 		 ep = (struct ns_errp *)nsp->nsp_notify_param;
463 		 sb = &nsp->nsp_socket->so_snd;
464 		 cb->s_mtu = ep->ns_err_param;
465 		 badseq = SI(&ep->ns_err_idp)->si_seq;
466 		 for (m = sb->sb_mb; m; m = m->m_act) {
467 			si = mtod(m, struct spidp *);
468 			if (si->si_seq == badseq)
469 				break;
470 		 }
471 		 if (m == 0) return;
472 		 firstbad = m;
473 		 /*for (;;) {*/
474 			/* calculate length */
475 			for (m0 = m, len = 0; m ; m = m->m_next)
476 				len += m->m_len;
477 			if (len > cb->s_mtu) {
478 			}
479 		/* FINISH THIS
480 		} */
481 	}
482 }
483 #endif
484 
485 int spp_output_cnt = 0;
486 
487 spp_output(cb, m0)
488 	register struct sppcb *cb;
489 	struct mbuf *m0;
490 {
491 	struct socket *so = cb->s_nspcb->nsp_socket;
492 	register struct mbuf *m;
493 	register struct spidp *si = (struct spidp *) 0;
494 	register struct sockbuf *sb = &(so->so_snd);
495 	register int len = 0;
496 	int error = 0;
497 	u_short lookfor = 0;
498 	struct mbuf *mprev;
499 	extern int idpcksum;
500 
501 	if (m0) {
502 		int mtu = cb->s_mtu;
503 		int datalen;
504 		/*
505 		 * Make sure that packet isn't too big.
506 		 */
507 		for (m = m0; m ; m = m->m_next) {
508 			mprev = m;
509 			len += m->m_len;
510 		}
511 		datalen = (cb->s_flags & SF_HO) ?
512 				len - sizeof (struct sphdr) : len;
513 		if (datalen > mtu) {
514 			if (cb->s_flags & SF_PI) {
515 				m_freem(m0);
516 				return (EMSGSIZE);
517 			} else {
518 				int off = 0;
519 				int oldEM = cb->s_cc & SP_EM;
520 
521 				cb->s_cc &= ~SP_EM;
522 				while (len > mtu) {
523 					m = m_copy(m0, off, mtu);
524 					if (m == NULL) {
525 						error = ENOBUFS;
526 						goto bad_copy;
527 					}
528 					error = spp_output(cb, m);
529 					if (error) {
530 					bad_copy:
531 						cb->s_cc |= oldEM;
532 						m_freem(m0);
533 						return(error);
534 					}
535 					m_adj(m0, mtu);
536 					len -= mtu;
537 				}
538 				cb->s_cc |= oldEM;
539 			}
540 		}
541 		/*
542 		 * Force length even, by adding a "garbage byte" if
543 		 * necessary.
544 		 */
545 		if (len & 1) {
546 			m = mprev;
547 			if (m->m_len + m->m_off < MMAXOFF)
548 				m->m_len++;
549 			else {
550 				struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
551 
552 				if (m1 == 0) {
553 					m_freem(m0);
554 					return (ENOBUFS);
555 				}
556 				m1->m_len = 1;
557 				m1->m_off = MMAXOFF - 1;
558 				m->m_next = m1;
559 			}
560 		}
561 		m = m_get(M_DONTWAIT, MT_HEADER);
562 		if (m == 0) {
563 			m_freem(m0);
564 			return (ENOBUFS);
565 		}
566 		/*
567 		 * Fill in mbuf with extended SP header
568 		 * and addresses and length put into network format.
569 		 * Long align so prepended ip headers will work on Gould.
570 		 */
571 		m->m_off = MMAXOFF - sizeof (struct spidp) - 2;
572 		m->m_len = sizeof (struct spidp);
573 		m->m_next = m0;
574 		si = mtod(m, struct spidp *);
575 		*si = cb->s_shdr;
576 		if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
577 			register struct sphdr *sh;
578 			if (m0->m_len < sizeof (*sh)) {
579 				if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
580 					(void) m_free(m);
581 					m_freem(m0);
582 					return (EINVAL);
583 				}
584 				m->m_next = m0;
585 			}
586 			sh = mtod(m0, struct sphdr *);
587 			si->si_dt = sh->sp_dt;
588 			si->si_cc |= sh->sp_cc & SP_EM;
589 			m0->m_len -= sizeof (*sh);
590 			m0->m_off += sizeof (*sh);
591 			len -= sizeof (*sh);
592 		}
593 		len += sizeof(*si);
594 		if (cb->s_oobflags & SF_SOOB) {
595 			/*
596 			 * Per jqj@cornell:
597 			 * make sure OB packets convey exactly 1 byte.
598 			 * If the packet is 1 byte or larger, we
599 			 * have already guaranted there to be at least
600 			 * one garbage byte for the checksum, and
601 			 * extra bytes shouldn't hurt!
602 			 */
603 			if (len > sizeof(*si)) {
604 				si->si_cc |= SP_OB;
605 				len = (1 + sizeof(*si));
606 			}
607 		}
608 		si->si_len = htons((u_short)len);
609 		/*
610 		 * queue stuff up for output
611 		 */
612 		sbappendrecord(sb, m);
613 		cb->s_seq++;
614 	}
615 	/*
616 	 * update window
617 	 */
618 	{
619 		register struct sockbuf *sb2 = &so->so_rcv;
620 		int credit = ((((int)sb2->sb_mbmax) - (int)sb2->sb_mbcnt) /
621 						((short)cb->s_mtu));
622 		int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1;
623 
624 		if (cb->s_alo < alo) {
625 			/* If the amount we are raising the window
626 			   is more than his remaining headroom, tell
627 			   him about it.  In particular, if he is at
628 			   his limit, any amount at all will do! */
629 			u_short raise = alo - cb->s_alo;
630 			u_short headroom = 1 + cb->s_alo - cb->s_ack;
631 
632 			if(SSEQ_LT(headroom, raise))
633 				cb->s_flags |= SF_AK;
634 			cb->s_alo = alo;
635 		}
636 	}
637 
638 	if (cb->s_oobflags & SF_SOOB) {
639 		/*
640 		 * must transmit this out of band packet
641 		 */
642 		cb->s_oobflags &= ~ SF_SOOB;
643 	} else {
644 		/*
645 		 * Decide what to transmit:
646 		 * If it is time to retransmit a packet,
647 		 * send that.
648 		 * If we have a new packet, send that
649 		 * (So long as it is in our allocation)
650 		 * Otherwise, see if it time to bang on them
651 		 * to ask for our current allocation.
652 		 */
653 		if (cb->s_force == (1+TCPT_REXMT)) {
654 			lookfor = cb->s_rack;
655 		} else if (SSEQ_LT(cb->s_snt, cb->s_ralo)) {
656 			lookfor = cb->s_snt + 1;
657 		} else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) {
658 			lookfor = 0;
659 			if (cb->s_timer[TCPT_PERSIST] == 0) {
660 				spp_setpersist(cb);
661 				/* tcp has cb->s_rxtshift = 0; here */
662 			}
663 		}
664 		m = sb->sb_mb;
665 		while (m) {
666 			si = mtod(m, struct spidp *);
667 			m = m->m_act;
668 			if (SSEQ_LT(si->si_seq, cb->s_rack)) {
669 				if ((sb->sb_flags & SB_WAIT)
670 				     || so->so_snd.sb_sel)
671 					 sowwakeup(so);
672 				sbdroprecord(sb);
673 				si = 0;
674 				continue;
675 			}
676 			if (SSEQ_LT(si->si_seq, lookfor))
677 				continue;
678 			break;
679 		}
680 		if (si && (si->si_seq != lookfor))
681 			si = 0;
682 	}
683 	cb->s_want = lookfor;
684 
685 	if (si) {
686 		/*
687 		 * must make a copy of this packet for
688 		 * idp_output to monkey with
689 		 */
690 		 m = m_copy(dtom(si), 0, (int)M_COPYALL);
691 		 if (m == NULL)
692 			return (ENOBUFS);
693 		 m0 = m;
694 		 si = mtod(m, struct spidp *);
695 	} else if (cb->s_force || cb->s_flags & SF_AK) {
696 		/*
697 		 * Must send an acknowledgement or a probe
698 		 */
699 		m = m_get(M_DONTWAIT, MT_HEADER);
700 		if (m == 0)
701 			return (ENOBUFS);
702 		/*
703 		 * Fill in mbuf with extended SP header
704 		 * and addresses and length put into network format.
705 		 */
706 		m->m_off = MMAXOFF - sizeof (struct spidp);
707 		m->m_len = sizeof (*si);
708 		m->m_next = 0;
709 		si = mtod(m, struct spidp *);
710 		*si = cb->s_shdr;
711 		si->si_seq = cb->s_snt + 1;
712 		si->si_len = htons(sizeof (*si));
713 		si->si_cc |= SP_SP;
714 	}
715 	/*
716 	 * Stuff checksum and output datagram.
717 	 */
718 	if (si) {
719 		if (cb->s_flags & (SF_AK|SF_DELACK))
720 			cb->s_flags &= ~(SF_AK|SF_DELACK);
721 		/*
722 		 * If we are almost out of allocation
723 		 * or one of the timers has gone off
724 		 * request an ack.
725 		 */
726 		if (SSEQ_GEQ(cb->s_seq, cb->s_ralo))
727 			si->si_cc |= SP_SA;
728 		if (cb->s_force) {
729 			si->si_cc |= SP_SA;
730 			cb->s_force = 0;
731 		}
732 		/*
733 		 * If this is a new packet (and not a system packet),
734 		 * and we are not currently timing anything,
735 		 * time this one and ask for an ack.
736 		 */
737 		if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) {
738 			cb->s_snt = si->si_seq;
739 			if (cb->s_rtt == 0) {
740 				cb->s_rtseq = si->si_seq;
741 				cb->s_rtt = 1;
742 				si->si_cc |= SP_SA;
743 			}
744 			/*
745 			 * If the retransmit timer has not been set
746 			 * and this is a real packet
747 			 * then start the retransmit timer
748 			 */
749 			if (cb->s_timer[TCPT_REXMT] == 0) {
750 				TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
751 					tcp_beta * cb->s_srtt, TCPTV_MIN,
752 					TCPTV_MAX);
753 				cb->s_rxtshift = 0;
754 			}
755 		}
756 		si->si_seq = htons(si->si_seq);
757 		si->si_alo = htons(cb->s_alo);
758 		si->si_ack = htons(cb->s_ack);
759 
760 		if (idpcksum) {
761 			si->si_sum = 0;
762 			len = ntohs(si->si_len);
763 			if (len & 1)
764 				len++;
765 			si->si_sum = ns_cksum(dtom(si), len);
766 		} else
767 			si->si_sum = 0xffff;
768 
769 		if (so->so_options & SO_DEBUG || traceallspps)
770 			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
771 		spp_output_cnt++;
772 		if (so->so_options & SO_DONTROUTE)
773 			error = ns_output(m, (struct route *)0, NS_ROUTETOIF);
774 		else
775 			error = ns_output(m, &cb->s_nspcb->nsp_route, 0);
776 		if (traceallspps && sppconsdebug) {
777 			printf("spp_out: %x\n", error);
778 		}
779 		if (so->so_options & SO_DEBUG || traceallspps)
780 			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
781 	}
782 	return (error);
783 }
784 
785 /*ARGSUSED*/
786 spp_ctloutput(req, so, level, name, value)
787 	int req;
788 	struct socket *so;
789 	int name;
790 	struct mbuf **value;
791 {
792 	register struct mbuf *m;
793 	struct nspcb *nsp = sotonspcb(so);
794 	register struct sppcb *cb;
795 	int mask, error = 0;
796 
797 	if (level != NSPROTO_SPP) {
798 		/* This will have to be changed when we do more general
799 		   stacking of protocols */
800 		return (idp_ctloutput(req, so, level, name, value));
801 	}
802 	if (nsp == NULL) {
803 		error = EINVAL;
804 		goto release;
805 	} else
806 		cb = nstosppcb(nsp);
807 
808 	switch (req) {
809 
810 	case PRCO_GETOPT:
811 		if (value == NULL)
812 			return (EINVAL);
813 		m = m_get(M_DONTWAIT, MT_DATA);
814 		if (m == NULL)
815 			return (ENOBUFS);
816 		switch (name) {
817 
818 		case SO_HEADERS_ON_INPUT:
819 			mask = SF_HI;
820 			goto get_flags;
821 
822 		case SO_HEADERS_ON_OUTPUT:
823 			mask = SF_HO;
824 		get_flags:
825 			m->m_len = sizeof(short);
826 			m->m_off = MMAXOFF - sizeof(short);
827 			*mtod(m, short *) = cb->s_flags & mask;
828 			break;
829 
830 		case SO_MTU:
831 			m->m_len = sizeof(u_short);
832 			m->m_off = MMAXOFF - sizeof(short);
833 			*mtod(m, short *) = cb->s_mtu;
834 			break;
835 
836 		case SO_LAST_HEADER:
837 			m->m_len = sizeof(struct sphdr);
838 			m->m_off = MMAXOFF - sizeof(struct sphdr);
839 			*mtod(m, struct sphdr *) = cb->s_rhdr;
840 			break;
841 
842 		case SO_DEFAULT_HEADERS:
843 			m->m_len = sizeof(struct spidp);
844 			m->m_off = MMAXOFF - sizeof(struct sphdr);
845 			*mtod(m, struct sphdr *) = cb->s_shdr.si_s;
846 			break;
847 
848 		default:
849 			error = EINVAL;
850 		}
851 		*value = m;
852 		break;
853 
854 	case PRCO_SETOPT:
855 		if (value == 0 || *value == 0) {
856 			error = EINVAL;
857 			break;
858 		}
859 		switch (name) {
860 			int *ok;
861 
862 		case SO_HEADERS_ON_INPUT:
863 			mask = SF_HI;
864 			goto set_head;
865 
866 		case SO_HEADERS_ON_OUTPUT:
867 			mask = SF_HO;
868 		set_head:
869 			if (cb->s_flags & SF_PI) {
870 				ok = mtod(*value, int *);
871 				if (*ok)
872 					cb->s_flags |= mask;
873 				else
874 					cb->s_flags &= ~mask;
875 			} else error = EINVAL;
876 			break;
877 
878 		case SO_MTU:
879 			cb->s_mtu = *(mtod(*value, u_short *));
880 			break;
881 
882 		case SO_DEFAULT_HEADERS:
883 			{
884 				register struct sphdr *sp
885 						= mtod(*value, struct sphdr *);
886 				cb->s_dt = sp->sp_dt;
887 				cb->s_cc = sp->sp_cc & SP_EM;
888 			}
889 			break;
890 
891 		default:
892 			error = EINVAL;
893 		}
894 		m_freem(*value);
895 		break;
896 	}
897 	release:
898 		return (error);
899 }
900 
901 /*ARGSUSED*/
902 spp_usrreq(so, req, m, nam, rights)
903 	struct socket *so;
904 	int req;
905 	struct mbuf *m, *nam, *rights;
906 {
907 	struct nspcb *nsp = sotonspcb(so);
908 	register struct sppcb *cb;
909 	int s = splnet();
910 	int error = 0, ostate;
911 
912 	if (req == PRU_CONTROL)
913                 return (ns_control(so, (int)m, (caddr_t)nam,
914 			(struct ifnet *)rights));
915 	if (rights && rights->m_len) {
916 		error = EINVAL;
917 		goto release;
918 	}
919 	if (nsp == NULL) {
920 		if (req != PRU_ATTACH) {
921 			error = EINVAL;
922 			goto release;
923 		}
924 	} else
925 		cb = nstosppcb(nsp);
926 
927 	ostate = cb ? cb->s_state : 0;
928 
929 	switch (req) {
930 
931 	case PRU_ATTACH:
932 		if (nsp != NULL) {
933 			error = EISCONN;
934 			break;
935 		}
936 		error = ns_pcballoc(so, &nspcb);
937 		if (error)
938 			break;
939 		error = soreserve(so, 2048, 2048);
940 		if (error)
941 			break;
942 		nsp = sotonspcb(so);
943 		{
944 			struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB);
945 
946 			if (mm == NULL) {
947 				error = ENOBUFS;
948 				break;
949 			}
950 			cb = mtod(mm, struct sppcb *);
951 			cb->s_state = TCPS_LISTEN;
952 			cb->s_snt = -1;
953 			cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
954 			cb->s_nspcb = nsp;
955 			nsp->nsp_pcb = (caddr_t) cb;
956 		}
957 		break;
958 
959 	case PRU_DETACH:
960 		if (nsp == NULL) {
961 			error = ENOTCONN;
962 			break;
963 		}
964 		if (cb->s_state > TCPS_LISTEN)
965 			cb = spp_disconnect(cb);
966 		else
967 			cb = spp_close(cb);
968 		break;
969 
970 	case PRU_BIND:
971 		error = ns_pcbbind(nsp, nam);
972 		break;
973 
974 	case PRU_LISTEN:
975 		if (nsp->nsp_lport == 0)
976 			error = ns_pcbbind(nsp, (struct mbuf *)0);
977 		if (error == 0)
978 			cb->s_state = TCPS_LISTEN;
979 		break;
980 
981 	/*
982 	 * Initiate connection to peer.
983 	 * Enter SYN_SENT state, and mark socket as connecting.
984 	 * Start keep-alive timer, setup prototype header,
985 	 * Send initial system packet requesting connection.
986 	 */
987 	case PRU_CONNECT:
988 		if (nsp->nsp_lport == 0) {
989 			error = ns_pcbbind(nsp, (struct mbuf *)0);
990 			if (error)
991 				break;
992 		}
993 		error = ns_pcbconnect(nsp, nam);
994 		if (error)
995 			break;
996 		soisconnecting(so);
997 		cb->s_state = TCPS_SYN_SENT;
998 		cb->s_did = 0;
999 		spp_template(cb);
1000 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
1001 		cb->s_force = 1 + TCPTV_KEEP;
1002 		/*
1003 		 * Other party is required to respond to
1004 		 * the port I send from, but he is not
1005 		 * required to answer from where I am sending to,
1006 		 * so allow wildcarding.
1007 		 * original port I am sending to is still saved in
1008 		 * cb->s_dport.
1009 		 */
1010 		nsp->nsp_fport = 0;
1011 		error = spp_output(cb, (struct mbuf *) 0);
1012 		break;
1013 
1014 	case PRU_CONNECT2:
1015 		error = EOPNOTSUPP;
1016 		break;
1017 
1018 	/*
1019 	 * We may decide later to implement connection closing
1020 	 * handshaking at the spp level optionally.
1021 	 * here is the hook to do it:
1022 	 */
1023 	case PRU_DISCONNECT:
1024 		cb = spp_disconnect(cb);
1025 		break;
1026 
1027 	/*
1028 	 * Accept a connection.  Essentially all the work is
1029 	 * done at higher levels; just return the address
1030 	 * of the peer, storing through addr.
1031 	 */
1032 	case PRU_ACCEPT: {
1033 		struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
1034 
1035 		nam->m_len = sizeof (struct sockaddr_ns);
1036 		sns->sns_family = AF_NS;
1037 		sns->sns_addr = nsp->nsp_faddr;
1038 		break;
1039 		}
1040 
1041 	case PRU_SHUTDOWN:
1042 		socantsendmore(so);
1043 		cb = spp_usrclosed(cb);
1044 		if (cb)
1045 			error = spp_output(cb, (struct mbuf *) 0);
1046 		break;
1047 
1048 	/*
1049 	 * After a receive, possibly send acknowledgment
1050 	 * updating allocation.
1051 	 */
1052 	case PRU_RCVD:
1053 		(void) spp_output(cb, (struct mbuf *) 0);
1054 		break;
1055 
1056 	case PRU_ABORT:
1057 		(void) spp_drop(cb, ECONNABORTED);
1058 		break;
1059 
1060 	case PRU_SENSE:
1061 	case PRU_CONTROL:
1062 		m = NULL;
1063 		error = EOPNOTSUPP;
1064 		break;
1065 
1066 	case PRU_RCVOOB:
1067 		if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
1068 		    (so->so_state & SS_RCVATMARK)) {
1069 			m->m_len = 1;
1070 			*mtod(m, caddr_t) = cb->s_iobc;
1071 			break;
1072 		}
1073 		error = EINVAL;
1074 		break;
1075 
1076 	case PRU_SENDOOB:
1077 		if (sbspace(&so->so_snd) < -512) {
1078 			error = ENOBUFS;
1079 			break;
1080 		}
1081 		cb->s_oobflags |= SF_SOOB;
1082 		/* fall into */
1083 	case PRU_SEND:
1084 		error = spp_output(cb, m);
1085 		m = NULL;
1086 		break;
1087 
1088 	case PRU_SOCKADDR:
1089 		ns_setsockaddr(nsp, nam);
1090 		break;
1091 
1092 	case PRU_PEERADDR:
1093 		ns_setpeeraddr(nsp, nam);
1094 		break;
1095 
1096 	case PRU_SLOWTIMO:
1097 		cb = spp_timers(cb, (int)nam);
1098 		break;
1099 
1100 	case PRU_FASTTIMO:
1101 	case PRU_PROTORCV:
1102 	case PRU_PROTOSEND:
1103 		error =  EOPNOTSUPP;
1104 		break;
1105 
1106 	default:
1107 		panic("sp_usrreq");
1108 	}
1109 	if (cb && (so->so_options & SO_DEBUG || traceallspps))
1110 		spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
1111 release:
1112 	if (m != NULL)
1113 		m_freem(m);
1114 	splx(s);
1115 	return (error);
1116 }
1117 
1118 spp_usrreq_sp(so, req, m, nam, rights)
1119 	struct socket *so;
1120 	int req;
1121 	struct mbuf *m, *nam, *rights;
1122 {
1123 	int error = spp_usrreq(so, req, m, nam, rights);
1124 
1125 	if (req == PRU_ATTACH && error == 0) {
1126 		struct nspcb *nsp = sotonspcb(so);
1127 		((struct sppcb *)nsp->nsp_pcb)->s_flags |=
1128 					(SF_HI | SF_HO | SF_PI);
1129 	}
1130 	return (error);
1131 }
1132 
1133 /*
1134  * Create template to be used to send spp packets on a connection.
1135  * Called after host entry created, fills
1136  * in a skeletal spp header (choosing connection id),
1137  * minimizing the amount of work necessary when the connection is used.
1138  */
1139 spp_template(cb)
1140 	struct sppcb *cb;
1141 {
1142 	register struct nspcb *nsp = cb->s_nspcb;
1143 	register struct spidp *n = &(cb->s_shdr);
1144 
1145 	cb->s_mtu = 576 - sizeof (struct spidp);
1146 	n->si_pt = NSPROTO_SPP;
1147 	n->si_sna = nsp->nsp_laddr;
1148 	n->si_dna = nsp->nsp_faddr;
1149 	n->si_sid = htons(spp_iss);
1150 	spp_iss += SPP_ISSINCR/2;
1151 	n->si_alo = 1;
1152 }
1153 
1154 /*
1155  * Close a SPIP control block:
1156  *	discard spp control block itself
1157  *	discard ns protocol control block
1158  *	wake up any sleepers
1159  */
1160 struct sppcb *
1161 spp_close(cb)
1162 	register struct sppcb *cb;
1163 {
1164 	register struct spidp_q *s;
1165 	struct nspcb *nsp = cb->s_nspcb;
1166 	struct socket *so = nsp->nsp_socket;
1167 	register struct mbuf *m;
1168 
1169 	s = cb->s_q.si_next;
1170 	while (s != &(cb->s_q)) {
1171 		s = s->si_next;
1172 		m = dtom(s->si_prev);
1173 		remque(s->si_prev);
1174 		m_freem(m);
1175 	}
1176 	(void) m_free(dtom(cb));
1177 	nsp->nsp_pcb = 0;
1178 	soisdisconnected(so);
1179 	ns_pcbdetach(nsp);
1180 	return ((struct sppcb *)0);
1181 }
1182 /*
1183  *	Someday we may do level 3 handshaking
1184  *	to close a connection or send a xerox style error.
1185  *	For now, just close.
1186  */
1187 struct sppcb *
1188 spp_usrclosed(cb)
1189 	register struct sppcb *cb;
1190 {
1191 	return (spp_close(cb));
1192 }
1193 struct sppcb *
1194 spp_disconnect(cb)
1195 	register struct sppcb *cb;
1196 {
1197 	return (spp_close(cb));
1198 }
1199 /*
1200  * Drop connection, reporting
1201  * the specified error.
1202  */
1203 struct sppcb *
1204 spp_drop(cb, errno)
1205 	register struct sppcb *cb;
1206 	int errno;
1207 {
1208 	struct socket *so = cb->s_nspcb->nsp_socket;
1209 
1210 	/*
1211 	 * someday, in the xerox world
1212 	 * we will generate error protocol packets
1213 	 * announcing that the socket has gone away.
1214 	 */
1215 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
1216 		tp->t_state = TCPS_CLOSED;
1217 		(void) tcp_output(tp);
1218 	}*/
1219 	so->so_error = errno;
1220 	return (spp_close(cb));
1221 }
1222 
1223 spp_abort(nsp)
1224 	struct nspcb *nsp;
1225 {
1226 
1227 	(void) spp_close((struct sppcb *)nsp->nsp_pcb);
1228 }
1229 
1230 spp_setpersist(cb)
1231 	register struct sppcb *cb;
1232 {
1233 
1234 	/*if (cb->s_timer[TCPT_REXMT])
1235 		panic("spp_output REXMT");*/
1236 	/*
1237 	 * Start/restart persistance timer.
1238 	 */
1239 	TCPT_RANGESET(cb->s_timer[TCPT_PERSIST],
1240 	    ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift,
1241 	    TCPTV_PERSMIN, TCPTV_MAX);
1242 	cb->s_rxtshift++;
1243 	if (cb->s_rxtshift >= TCP_MAXRXTSHIFT)
1244 		cb->s_rxtshift = 0;
1245 }
1246 /*
1247  * Fast timeout routine for processing delayed acks
1248  */
1249 int spp_ftcnt;
1250 spp_fasttimo()
1251 {
1252 	register struct nspcb *nsp;
1253 	register struct sppcb *cb;
1254 	int s = splnet();
1255 
1256 	nsp = nspcb.nsp_next;
1257 	spp_ftcnt++;
1258 	if (nsp)
1259 	for (; nsp != &nspcb; nsp = nsp->nsp_next)
1260 		if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
1261 		    (cb->s_flags & SF_DELACK)) {
1262 			cb->s_flags &= ~SF_DELACK;
1263 			cb->s_flags |= SF_AK;
1264 			(void) spp_output(cb, (struct mbuf *) 0);
1265 		}
1266 	splx(s);
1267 }
1268 
1269 /*
1270  * spp protocol timeout routine called every 500 ms.
1271  * Updates the timers in all active pcb's and
1272  * causes finite state machine actions if timers expire.
1273  */
1274 spp_slowtimo()
1275 {
1276 	register struct nspcb *ip, *ipnxt;
1277 	register struct sppcb *cb;
1278 	int s = splnet();
1279 	register int i;
1280 
1281 	/*
1282 	 * Search through tcb's and update active timers.
1283 	 */
1284 	ip = nspcb.nsp_next;
1285 	if (ip == 0) {
1286 		splx(s);
1287 		return;
1288 	}
1289 	while (ip != &nspcb) {
1290 		cb = nstosppcb(ip);
1291 		ipnxt = ip->nsp_next;
1292 		if (cb == 0)
1293 			goto tpgone;
1294 		for (i = 0; i < TCPT_NTIMERS; i++) {
1295 			if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
1296 				(void) spp_usrreq(cb->s_nspcb->nsp_socket,
1297 				    PRU_SLOWTIMO, (struct mbuf *)0,
1298 				    (struct mbuf *)i, (struct mbuf *)0);
1299 				if (ipnxt->nsp_prev != ip)
1300 					goto tpgone;
1301 			}
1302 		}
1303 		cb->s_idle++;
1304 		if (cb->s_rtt)
1305 			cb->s_rtt++;
1306 tpgone:
1307 		ip = ipnxt;
1308 	}
1309 	spp_iss += SPP_ISSINCR/PR_SLOWHZ;		/* increment iss */
1310 	splx(s);
1311 }
1312 
1313 float	spp_backoff[TCP_MAXRXTSHIFT] =
1314     { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 };
1315 int sppexprexmtbackoff = 0;
1316 /*
1317  * SPP timer processing.
1318  */
1319 struct sppcb *
1320 spp_timers(cb, timer)
1321 	register struct sppcb *cb;
1322 	int timer;
1323 {
1324 
1325 	cb->s_force = 1 + timer;
1326 	switch (timer) {
1327 
1328 	/*
1329 	 * 2 MSL timeout in shutdown went off.  Delete connection
1330 	 * control block.
1331 	 */
1332 	case TCPT_2MSL:
1333 		cb = spp_close(cb);
1334 		break;
1335 
1336 	/*
1337 	 * Retransmission timer went off.  Message has not
1338 	 * been acked within retransmit interval.  Back off
1339 	 * to a longer retransmit interval and retransmit all
1340 	 * unacknowledged messages in the window.
1341 	 */
1342 	case TCPT_REXMT:
1343 		cb->s_rxtshift++;
1344 		if (cb->s_rxtshift > TCP_MAXRXTSHIFT) {
1345 			cb = spp_drop(cb, ETIMEDOUT);
1346 			break;
1347 		}
1348 		(void) spp_output(cb, (struct mbuf *) 0);
1349 		TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1350 		    (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX);
1351 		if (sppexprexmtbackoff) {
1352 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1353 			    cb->s_timer[TCPT_REXMT] << cb->s_rxtshift,
1354 			    TCPTV_MIN, TCPTV_MAX);
1355 		} else {
1356 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1357 			    cb->s_timer[TCPT_REXMT] *
1358 			        spp_backoff[cb->s_rxtshift - 1],
1359 			    TCPTV_MIN, TCPTV_MAX);
1360 		}
1361 		break;
1362 
1363 	/*
1364 	 * Persistance timer into zero window.
1365 	 * Force a probe to be sent.
1366 	 */
1367 	case TCPT_PERSIST:
1368 		(void) spp_output(cb, (struct mbuf *) 0);
1369 		spp_setpersist(cb);
1370 		break;
1371 
1372 	/*
1373 	 * Keep-alive timer went off; send something
1374 	 * or drop connection if idle for too long.
1375 	 */
1376 	case TCPT_KEEP:
1377 		if (cb->s_state < TCPS_ESTABLISHED)
1378 			goto dropit;
1379 		if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
1380 		    	if (cb->s_idle >= TCPTV_MAXIDLE)
1381 				goto dropit;
1382 			(void) spp_output(cb, (struct mbuf *) 0);
1383 		} else
1384 			cb->s_idle = 0;
1385 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
1386 		break;
1387 	dropit:
1388 		cb = spp_drop(cb, ETIMEDOUT);
1389 		break;
1390 	}
1391 	return (cb);
1392 }
1393