xref: /csrg-svn/sys/netns/spp_usrreq.c (revision 25037)
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.13 (Berkeley) 09/26/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 		goto drop;
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 		 */
569 		m->m_off = MMAXOFF - sizeof (struct spidp);
570 		m->m_len = sizeof (struct spidp);
571 		m->m_next = m0;
572 		si = mtod(m, struct spidp *);
573 		*si = cb->s_shdr;
574 		if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
575 			register struct sphdr *sh;
576 			if (m0->m_len < sizeof (*sh)) {
577 				if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
578 					(void) m_free(m);
579 					m_freem(m0);
580 					return (EINVAL);
581 				}
582 				m->m_next = m0;
583 			}
584 			sh = mtod(m0, struct sphdr *);
585 			si->si_dt = sh->sp_dt;
586 			si->si_cc |= sh->sp_cc & SP_EM;
587 			m0->m_len -= sizeof (*sh);
588 			m0->m_off += sizeof (*sh);
589 			len -= sizeof (*sh);
590 		}
591 		len += sizeof(*si);
592 		if (cb->s_oobflags & SF_SOOB) {
593 			/*
594 			 * Per jqj@cornell:
595 			 * make sure OB packets convey exactly 1 byte.
596 			 * If the packet is 1 byte or larger, we
597 			 * have already guaranted there to be at least
598 			 * one garbage byte for the checksum, and
599 			 * extra bytes shouldn't hurt!
600 			 */
601 			if (len > sizeof(*si)) {
602 				si->si_cc |= SP_OB;
603 				len = (1 + sizeof(*si));
604 			}
605 		}
606 		si->si_len = htons((u_short)len);
607 		/*
608 		 * queue stuff up for output
609 		 */
610 		sbappendrecord(sb, m);
611 		cb->s_seq++;
612 	}
613 	/*
614 	 * update window
615 	 */
616 	{
617 		register struct sockbuf *sb2 = &so->so_rcv;
618 		int credit = ((sb2->sb_mbmax - sb2->sb_mbcnt) /
619 						((short)cb->s_mtu));
620 		int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1;
621 
622 		if (cb->s_alo < alo) {
623 			/* If the amount we are raising the window
624 			   is more than his remaining headroom, tell
625 			   him about it.  In particular, if he is at
626 			   his limit, any amount at all will do! */
627 			u_short raise = alo - cb->s_alo;
628 			u_short headroom = 1 + cb->s_alo - cb->s_ack;
629 
630 			if(SSEQ_LT(headroom, raise))
631 				cb->s_flags |= SF_AK;
632 			cb->s_alo = alo;
633 		}
634 	}
635 
636 	if (cb->s_oobflags & SF_SOOB) {
637 		/*
638 		 * must transmit this out of band packet
639 		 */
640 		cb->s_oobflags &= ~ SF_SOOB;
641 	} else {
642 		/*
643 		 * Decide what to transmit:
644 		 * If we have a new packet, send that
645 		 * (So long as it is in our allocation)
646 		 * If it is time to retransmit a packet,
647 		 * send that.
648 		 * Otherwise, see if it time to bang on them
649 		 * to ask for our current allocation.
650 		 */
651 		if (SSEQ_LT(cb->s_snt, cb->s_ralo))
652 			lookfor = cb->s_snt + 1;
653 		else if (cb->s_force == (1+TCPT_REXMT)) {
654 			lookfor = cb->s_rack;
655 		} else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) {
656 			lookfor = 0;
657 			if (cb->s_timer[TCPT_PERSIST] == 0) {
658 				spp_setpersist(cb);
659 				/* tcp has cb->s_rxtshift = 0; here */
660 			}
661 		}
662 		m = sb->sb_mb;
663 		while (m) {
664 			si = mtod(m, struct spidp *);
665 			m = m->m_act;
666 			if (SSEQ_LT(si->si_seq, cb->s_rack)) {
667 				if ((sb->sb_flags & SB_WAIT)
668 				     || so->so_snd.sb_sel)
669 					 sowwakeup(so);
670 				sbdroprecord(sb);
671 				si = 0;
672 				continue;
673 			}
674 			if (SSEQ_LT(si->si_seq, lookfor))
675 				continue;
676 			break;
677 		}
678 		if (si && (si->si_seq != lookfor))
679 			si = 0;
680 	}
681 	cb->s_want = lookfor;
682 
683 	if (si) {
684 		/*
685 		 * must make a copy of this packet for
686 		 * idp_output to monkey with
687 		 */
688 		 m = m_copy(dtom(si), 0, (int)M_COPYALL);
689 		 if (m == NULL)
690 			return (ENOBUFS);
691 		 m0 = m;
692 		 si = mtod(m, struct spidp *);
693 	} else if (cb->s_force || cb->s_flags & SF_AK) {
694 		/*
695 		 * Must send an acknowledgement or a probe
696 		 */
697 		m = m_get(M_DONTWAIT, MT_HEADER);
698 		if (m == 0)
699 			return (ENOBUFS);
700 		/*
701 		 * Fill in mbuf with extended SP header
702 		 * and addresses and length put into network format.
703 		 */
704 		m->m_off = MMAXOFF - sizeof (struct spidp);
705 		m->m_len = sizeof (*si);
706 		m->m_next = 0;
707 		si = mtod(m, struct spidp *);
708 		*si = cb->s_shdr;
709 		si->si_seq = cb->s_snt + 1;
710 		si->si_len = htons(sizeof (*si));
711 		si->si_cc |= SP_SP;
712 	}
713 	/*
714 	 * Stuff checksum and output datagram.
715 	 */
716 	if (si) {
717 		if (cb->s_flags & (SF_AK|SF_DELACK))
718 			cb->s_flags &= ~(SF_AK|SF_DELACK);
719 		/*
720 		 * If we are almost out of allocation
721 		 * or one of the timers has gone off
722 		 * request an ack.
723 		 */
724 		if (SSEQ_GEQ(cb->s_seq, cb->s_ralo))
725 			si->si_cc |= SP_SA;
726 		if (cb->s_force) {
727 			si->si_cc |= SP_SA;
728 			cb->s_force = 0;
729 		}
730 		/*
731 		 * If this is a new packet (and not a system packet),
732 		 * and we are not currently timing anything,
733 		 * time this one and ask for an ack.
734 		 */
735 		if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) {
736 			cb->s_snt = si->si_seq;
737 			if (cb->s_rtt == 0) {
738 				cb->s_rtseq = si->si_seq;
739 				cb->s_rtt = 1;
740 				si->si_cc |= SP_SA;
741 			}
742 			/*
743 			 * If the retransmit timer has not been set
744 			 * and this is a real packet
745 			 * then start the retransmit timer
746 			 */
747 			if (cb->s_timer[TCPT_REXMT] == 0) {
748 				TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
749 					tcp_beta * cb->s_srtt, TCPTV_MIN,
750 					TCPTV_MAX);
751 				cb->s_rxtshift = 0;
752 			}
753 		}
754 		si->si_seq = htons(si->si_seq);
755 		si->si_alo = htons(cb->s_alo);
756 		si->si_ack = htons(cb->s_ack);
757 
758 		if (idpcksum) {
759 			si->si_sum = 0;
760 			len = ntohs(si->si_len);
761 			if (len & 1)
762 				len++;
763 			si->si_sum = ns_cksum(dtom(si), len);
764 		} else
765 			si->si_sum = 0xffff;
766 
767 		if (so->so_options & SO_DEBUG || traceallspps)
768 			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
769 		spp_output_cnt++;
770 		if (so->so_options & SO_DONTROUTE)
771 			error = ns_output(m, (struct route *)0, NS_ROUTETOIF);
772 		else
773 			error = ns_output(m, &cb->s_nspcb->nsp_route, 0);
774 		if (traceallspps && sppconsdebug) {
775 			printf("spp_out: %x\n", error);
776 		}
777 		return (error);
778 	}
779 	if (so->so_options & SO_DEBUG || traceallspps)
780 		spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
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 		}
846 		*value = m;
847 		break;
848 
849 	case PRCO_SETOPT:
850 		if (value == 0 || *value == 0) {
851 			error = EINVAL;
852 			break;
853 		}
854 		switch (name) {
855 			int *ok;
856 
857 		case SO_HEADERS_ON_INPUT:
858 			mask = SF_HI;
859 			goto set_head;
860 
861 		case SO_HEADERS_ON_OUTPUT:
862 			mask = SF_HO;
863 		set_head:
864 			if (cb->s_flags & SF_PI) {
865 				ok = mtod(*value, int *);
866 				if (*ok)
867 					cb->s_flags |= mask;
868 				else
869 					cb->s_flags &= ~mask;
870 			} else error = EINVAL;
871 			break;
872 
873 		case SO_MTU:
874 			cb->s_mtu = *(mtod(*value, u_short *));
875 			break;
876 
877 		case SO_DEFAULT_HEADERS:
878 			{
879 				register struct sphdr *sp
880 						= mtod(*value, struct sphdr *);
881 				cb->s_dt = sp->sp_dt;
882 				cb->s_cc = sp->sp_cc & SP_EM;
883 			}
884 		}
885 		m_freem(*value);
886 		break;
887 	}
888 	release:
889 		return (error);
890 }
891 
892 /*ARGSUSED*/
893 spp_usrreq(so, req, m, nam, rights)
894 	struct socket *so;
895 	int req;
896 	struct mbuf *m, *nam, *rights;
897 {
898 	struct nspcb *nsp = sotonspcb(so);
899 	register struct sppcb *cb;
900 	int s = splnet();
901 	int error = 0, ostate;
902 
903 	if (req == PRU_CONTROL)
904                 return (ns_control(so, (int)m, (caddr_t)nam,
905 			(struct ifnet *)rights));
906 	if (rights && rights->m_len) {
907 		error = EINVAL;
908 		goto release;
909 	}
910 	if (nsp == NULL) {
911 		if (req != PRU_ATTACH) {
912 			error = EINVAL;
913 			goto release;
914 		}
915 	} else
916 		cb = nstosppcb(nsp);
917 
918 	ostate = cb ? cb->s_state : 0;
919 
920 	switch (req) {
921 
922 	case PRU_ATTACH:
923 		if (nsp != NULL) {
924 			error = EISCONN;
925 			break;
926 		}
927 		error = ns_pcballoc(so, &nspcb);
928 		if (error)
929 			break;
930 		error = soreserve(so, 2048, 2048);
931 		if (error)
932 			break;
933 		nsp = sotonspcb(so);
934 		{
935 			struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB);
936 
937 			if (mm == NULL) {
938 				error = ENOBUFS;
939 				break;
940 			}
941 			cb = mtod(mm, struct sppcb *);
942 			cb->s_state = TCPS_LISTEN;
943 			cb->s_snt = -1;
944 			cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
945 			cb->s_nspcb = nsp;
946 			nsp->nsp_pcb = (caddr_t) cb;
947 		}
948 		break;
949 
950 	case PRU_DETACH:
951 		if (nsp == NULL) {
952 			error = ENOTCONN;
953 			break;
954 		}
955 		if (cb->s_state > TCPS_LISTEN)
956 			cb = spp_disconnect(cb);
957 		else
958 			cb = spp_close(cb);
959 		break;
960 
961 	case PRU_BIND:
962 		error = ns_pcbbind(nsp, nam);
963 		break;
964 
965 	case PRU_LISTEN:
966 		if (nsp->nsp_lport == 0)
967 			error = ns_pcbbind(nsp, (struct mbuf *)0);
968 		if (error == 0)
969 			cb->s_state = TCPS_LISTEN;
970 		break;
971 
972 	/*
973 	 * Initiate connection to peer.
974 	 * Enter SYN_SENT state, and mark socket as connecting.
975 	 * Start keep-alive timer, setup prototype header,
976 	 * Send initial system packet requesting connection.
977 	 */
978 	case PRU_CONNECT:
979 		if (nsp->nsp_lport == 0) {
980 			error = ns_pcbbind(nsp, (struct mbuf *)0);
981 			if (error)
982 				break;
983 		}
984 		error = ns_pcbconnect(nsp, nam);
985 		if (error)
986 			break;
987 		soisconnecting(so);
988 		cb->s_state = TCPS_SYN_SENT;
989 		cb->s_did = 0;
990 		spp_template(cb);
991 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
992 		cb->s_force = 1 + TCPTV_KEEP;
993 		/*
994 		 * Other party is required to respond to
995 		 * the port I send from, but he is not
996 		 * required to answer from where I am sending to,
997 		 * so allow wildcarding.
998 		 * original port I am sending to is still saved in
999 		 * cb->s_dport.
1000 		 */
1001 		nsp->nsp_fport = 0;
1002 		error = spp_output(cb, (struct mbuf *) 0);
1003 		break;
1004 
1005 	case PRU_CONNECT2:
1006 		error = EOPNOTSUPP;
1007 		break;
1008 
1009 	/*
1010 	 * We may decide later to implement connection closing
1011 	 * handshaking at the spp level optionally.
1012 	 * here is the hook to do it:
1013 	 */
1014 	case PRU_DISCONNECT:
1015 		cb = spp_disconnect(cb);
1016 		break;
1017 
1018 	/*
1019 	 * Accept a connection.  Essentially all the work is
1020 	 * done at higher levels; just return the address
1021 	 * of the peer, storing through addr.
1022 	 */
1023 	case PRU_ACCEPT: {
1024 		struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
1025 
1026 		nam->m_len = sizeof (struct sockaddr_ns);
1027 		sns->sns_family = AF_NS;
1028 		sns->sns_addr = nsp->nsp_faddr;
1029 		break;
1030 		}
1031 
1032 	case PRU_SHUTDOWN:
1033 		socantsendmore(so);
1034 		cb = spp_usrclosed(cb);
1035 		if (cb)
1036 			error = spp_output(cb, (struct mbuf *) 0);
1037 		break;
1038 
1039 	/*
1040 	 * After a receive, possibly send acknowledgment
1041 	 * updating allocation.
1042 	 */
1043 	case PRU_RCVD:
1044 		(void) spp_output(cb, (struct mbuf *) 0);
1045 		break;
1046 
1047 	case PRU_SEND:
1048 		error = spp_output(cb, m);
1049 		m = NULL;
1050 		break;
1051 
1052 	case PRU_ABORT:
1053 		(void) spp_drop(cb, ECONNABORTED);
1054 		break;
1055 
1056 	case PRU_SENSE:
1057 	case PRU_CONTROL:
1058 		m = NULL;
1059 		error = EOPNOTSUPP;
1060 		break;
1061 
1062 	case PRU_RCVOOB:
1063 		if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
1064 		    (so->so_state & SS_RCVATMARK)) {
1065 			m->m_len = 1;
1066 			*mtod(m, caddr_t) = cb->s_iobc;
1067 			break;
1068 		}
1069 		error = EINVAL;
1070 		break;
1071 
1072 	case PRU_SENDOOB:
1073 		if (sbspace(&so->so_snd) < -512) {
1074 			m_freem(m);
1075 			error = ENOBUFS;
1076 			break;
1077 		}
1078 		cb->s_oobflags |= SF_SOOB;
1079 		error = spp_output(cb, m);
1080 		m = NULL;
1081 		break;
1082 
1083 	case PRU_SOCKADDR:
1084 		ns_setsockaddr(nsp, nam);
1085 		break;
1086 
1087 	case PRU_PEERADDR:
1088 		ns_setpeeraddr(nsp, nam);
1089 		break;
1090 
1091 	case PRU_SLOWTIMO:
1092 		cb = spp_timers(cb, (int)nam);
1093 		break;
1094 
1095 	case PRU_FASTTIMO:
1096 	case PRU_PROTORCV:
1097 	case PRU_PROTOSEND:
1098 		error =  EOPNOTSUPP;
1099 		break;
1100 
1101 	default:
1102 		panic("sp_usrreq");
1103 	}
1104 	if (cb && (so->so_options & SO_DEBUG || traceallspps))
1105 		spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
1106 release:
1107 	if (m != NULL)
1108 		m_freem(m);
1109 	splx(s);
1110 	return (error);
1111 }
1112 
1113 spp_usrreq_sp(so, req, m, nam, rights)
1114 	struct socket *so;
1115 	int req;
1116 	struct mbuf *m, *nam, *rights;
1117 {
1118 	int error = spp_usrreq(so, req, m, nam, rights);
1119 
1120 	if (req == PRU_ATTACH && error == 0) {
1121 		struct nspcb *nsp = sotonspcb(so);
1122 		((struct sppcb *)nsp->nsp_pcb)->s_flags |=
1123 					(SF_HI | SF_HO | SF_PI);
1124 	}
1125 	return (error);
1126 }
1127 
1128 /*
1129  * Create template to be used to send spp packets on a connection.
1130  * Called after host entry created, fills
1131  * in a skeletal spp header (choosing connection id),
1132  * minimizing the amount of work necessary when the connection is used.
1133  */
1134 spp_template(cb)
1135 	struct sppcb *cb;
1136 {
1137 	register struct nspcb *nsp = cb->s_nspcb;
1138 	register struct spidp *n = &(cb->s_shdr);
1139 
1140 	cb->s_mtu = 576 - sizeof (struct spidp);
1141 	n->si_pt = NSPROTO_SPP;
1142 	n->si_sna = nsp->nsp_laddr;
1143 	n->si_dna = nsp->nsp_faddr;
1144 	n->si_sid = htons(spp_iss);
1145 	spp_iss += SPP_ISSINCR/2;
1146 	n->si_alo = 1;
1147 }
1148 
1149 /*
1150  * Close a SPIP control block:
1151  *	discard spp control block itself
1152  *	discard ns protocol control block
1153  *	wake up any sleepers
1154  */
1155 struct sppcb *
1156 spp_close(cb)
1157 	register struct sppcb *cb;
1158 {
1159 	register struct spidp_q *s;
1160 	struct nspcb *nsp = cb->s_nspcb;
1161 	struct socket *so = nsp->nsp_socket;
1162 	register struct mbuf *m;
1163 
1164 	s = cb->s_q.si_next;
1165 	while (s != &(cb->s_q)) {
1166 		s = s->si_next;
1167 		m = dtom(s->si_prev);
1168 		remque(s->si_prev);
1169 		m_freem(m);
1170 	}
1171 	(void) m_free(dtom(cb));
1172 	nsp->nsp_pcb = 0;
1173 	soisdisconnected(so);
1174 	ns_pcbdetach(nsp);
1175 	return ((struct sppcb *)0);
1176 }
1177 /*
1178  *	Someday we may do level 3 handshaking
1179  *	to close a connection or send a xerox style error.
1180  *	For now, just close.
1181  */
1182 struct sppcb *
1183 spp_usrclosed(cb)
1184 	register struct sppcb *cb;
1185 {
1186 	return (spp_close(cb));
1187 }
1188 struct sppcb *
1189 spp_disconnect(cb)
1190 	register struct sppcb *cb;
1191 {
1192 	return (spp_close(cb));
1193 }
1194 /*
1195  * Drop connection, reporting
1196  * the specified error.
1197  */
1198 struct sppcb *
1199 spp_drop(cb, errno)
1200 	register struct sppcb *cb;
1201 	int errno;
1202 {
1203 	struct socket *so = cb->s_nspcb->nsp_socket;
1204 
1205 	/*
1206 	 * someday, in the xerox world
1207 	 * we will generate error protocol packets
1208 	 * announcing that the socket has gone away.
1209 	 */
1210 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
1211 		tp->t_state = TCPS_CLOSED;
1212 		(void) tcp_output(tp);
1213 	}*/
1214 	so->so_error = errno;
1215 	return (spp_close(cb));
1216 }
1217 
1218 spp_abort(nsp)
1219 	struct nspcb *nsp;
1220 {
1221 
1222 	(void) spp_close((struct sppcb *)nsp->nsp_pcb);
1223 }
1224 
1225 spp_setpersist(cb)
1226 	register struct sppcb *cb;
1227 {
1228 
1229 	/*if (cb->s_timer[TCPT_REXMT])
1230 		panic("spp_output REXMT");*/
1231 	/*
1232 	 * Start/restart persistance timer.
1233 	 */
1234 	TCPT_RANGESET(cb->s_timer[TCPT_PERSIST],
1235 	    ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift,
1236 	    TCPTV_PERSMIN, TCPTV_MAX);
1237 	cb->s_rxtshift++;
1238 	if (cb->s_rxtshift >= TCP_MAXRXTSHIFT)
1239 		cb->s_rxtshift = 0;
1240 }
1241 /*
1242  * Fast timeout routine for processing delayed acks
1243  */
1244 int spp_ftcnt;
1245 spp_fasttimo()
1246 {
1247 	register struct nspcb *nsp;
1248 	register struct sppcb *cb;
1249 	int s = splnet();
1250 
1251 	nsp = nspcb.nsp_next;
1252 	spp_ftcnt++;
1253 	if (nsp)
1254 	for (; nsp != &nspcb; nsp = nsp->nsp_next)
1255 		if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
1256 		    (cb->s_flags & SF_DELACK)) {
1257 			cb->s_flags &= ~SF_DELACK;
1258 			cb->s_flags |= SF_AK;
1259 			(void) spp_output(cb, (struct mbuf *) 0);
1260 		}
1261 	splx(s);
1262 }
1263 
1264 /*
1265  * spp protocol timeout routine called every 500 ms.
1266  * Updates the timers in all active pcb's and
1267  * causes finite state machine actions if timers expire.
1268  */
1269 spp_slowtimo()
1270 {
1271 	register struct nspcb *ip, *ipnxt;
1272 	register struct sppcb *cb;
1273 	int s = splnet();
1274 	register int i;
1275 
1276 	/*
1277 	 * Search through tcb's and update active timers.
1278 	 */
1279 	ip = nspcb.nsp_next;
1280 	if (ip == 0) {
1281 		splx(s);
1282 		return;
1283 	}
1284 	while (ip != &nspcb) {
1285 		cb = nstosppcb(ip);
1286 		ipnxt = ip->nsp_next;
1287 		if (cb == 0)
1288 			goto tpgone;
1289 		for (i = 0; i < TCPT_NTIMERS; i++) {
1290 			if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
1291 				(void) spp_usrreq(cb->s_nspcb->nsp_socket,
1292 				    PRU_SLOWTIMO, (struct mbuf *)0,
1293 				    (struct mbuf *)i, (struct mbuf *)0);
1294 				if (ipnxt->nsp_prev != ip)
1295 					goto tpgone;
1296 			}
1297 		}
1298 		cb->s_idle++;
1299 		if (cb->s_rtt)
1300 			cb->s_rtt++;
1301 tpgone:
1302 		ip = ipnxt;
1303 	}
1304 	spp_iss += SPP_ISSINCR/PR_SLOWHZ;		/* increment iss */
1305 	splx(s);
1306 }
1307 
1308 float	spp_backoff[TCP_MAXRXTSHIFT] =
1309     { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 };
1310 int sppexprexmtbackoff = 0;
1311 /*
1312  * SPP timer processing.
1313  */
1314 struct sppcb *
1315 spp_timers(cb, timer)
1316 	register struct sppcb *cb;
1317 	int timer;
1318 {
1319 
1320 	cb->s_force = 1 + timer;
1321 	switch (timer) {
1322 
1323 	/*
1324 	 * 2 MSL timeout in shutdown went off.  Delete connection
1325 	 * control block.
1326 	 */
1327 	case TCPT_2MSL:
1328 		cb = spp_close(cb);
1329 		break;
1330 
1331 	/*
1332 	 * Retransmission timer went off.  Message has not
1333 	 * been acked within retransmit interval.  Back off
1334 	 * to a longer retransmit interval and retransmit all
1335 	 * unacknowledged messages in the window.
1336 	 */
1337 	case TCPT_REXMT:
1338 		cb->s_rxtshift++;
1339 		if (cb->s_rxtshift > TCP_MAXRXTSHIFT) {
1340 			cb = spp_drop(cb, ETIMEDOUT);
1341 			break;
1342 		}
1343 		(void) spp_output(cb, (struct mbuf *) 0);
1344 		TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1345 		    (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX);
1346 		if (sppexprexmtbackoff) {
1347 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1348 			    cb->s_timer[TCPT_REXMT] << cb->s_rxtshift,
1349 			    TCPTV_MIN, TCPTV_MAX);
1350 		} else {
1351 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1352 			    cb->s_timer[TCPT_REXMT] *
1353 			        spp_backoff[cb->s_rxtshift - 1],
1354 			    TCPTV_MIN, TCPTV_MAX);
1355 		}
1356 		break;
1357 
1358 	/*
1359 	 * Persistance timer into zero window.
1360 	 * Force a probe to be sent.
1361 	 */
1362 	case TCPT_PERSIST:
1363 		(void) spp_output(cb, (struct mbuf *) 0);
1364 		spp_setpersist(cb);
1365 		break;
1366 
1367 	/*
1368 	 * Keep-alive timer went off; send something
1369 	 * or drop connection if idle for too long.
1370 	 */
1371 	case TCPT_KEEP:
1372 		if (cb->s_state < TCPS_ESTABLISHED)
1373 			goto dropit;
1374 		if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
1375 		    	if (cb->s_idle >= TCPTV_MAXIDLE)
1376 				goto dropit;
1377 			(void) spp_output(cb, (struct mbuf *) 0);
1378 		} else
1379 			cb->s_idle = 0;
1380 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
1381 		break;
1382 	dropit:
1383 		cb = spp_drop(cb, ETIMEDOUT);
1384 		break;
1385 	}
1386 	return (cb);
1387 }
1388