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