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