xref: /csrg-svn/sys/netns/spp_usrreq.c (revision 25168)
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.14 (Berkeley) 10/11/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 it is time to retransmit a packet,
645 		 * send that.
646 		 * If we have a new packet, send that
647 		 * (So long as it is in our allocation)
648 		 * Otherwise, see if it time to bang on them
649 		 * to ask for our current allocation.
650 		 */
651 		if (cb->s_force == (1+TCPT_REXMT)) {
652 			lookfor = cb->s_rack;
653 		} else if (SSEQ_LT(cb->s_snt, cb->s_ralo)) {
654 			lookfor = cb->s_snt + 1;
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 		if (so->so_options & SO_DEBUG || traceallspps)
778 			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
779 	}
780 	return (error);
781 }
782 
783 /*ARGSUSED*/
784 spp_ctloutput(req, so, level, name, value)
785 	int req;
786 	struct socket *so;
787 	int name;
788 	struct mbuf **value;
789 {
790 	register struct mbuf *m;
791 	struct nspcb *nsp = sotonspcb(so);
792 	register struct sppcb *cb;
793 	int mask, error = 0;
794 
795 	if (level != NSPROTO_SPP) {
796 		/* This will have to be changed when we do more general
797 		   stacking of protocols */
798 		return (idp_ctloutput(req, so, level, name, value));
799 	}
800 	if (nsp == NULL) {
801 		error = EINVAL;
802 		goto release;
803 	} else
804 		cb = nstosppcb(nsp);
805 
806 	switch (req) {
807 
808 	case PRCO_GETOPT:
809 		if (value == NULL)
810 			return (EINVAL);
811 		m = m_get(M_DONTWAIT, MT_DATA);
812 		if (m == NULL)
813 			return (ENOBUFS);
814 		switch (name) {
815 
816 		case SO_HEADERS_ON_INPUT:
817 			mask = SF_HI;
818 			goto get_flags;
819 
820 		case SO_HEADERS_ON_OUTPUT:
821 			mask = SF_HO;
822 		get_flags:
823 			m->m_len = sizeof(short);
824 			m->m_off = MMAXOFF - sizeof(short);
825 			*mtod(m, short *) = cb->s_flags & mask;
826 			break;
827 
828 		case SO_MTU:
829 			m->m_len = sizeof(u_short);
830 			m->m_off = MMAXOFF - sizeof(short);
831 			*mtod(m, short *) = cb->s_mtu;
832 			break;
833 
834 		case SO_LAST_HEADER:
835 			m->m_len = sizeof(struct sphdr);
836 			m->m_off = MMAXOFF - sizeof(struct sphdr);
837 			*mtod(m, struct sphdr *) = cb->s_rhdr;
838 			break;
839 
840 		case SO_DEFAULT_HEADERS:
841 			m->m_len = sizeof(struct spidp);
842 			m->m_off = MMAXOFF - sizeof(struct sphdr);
843 			*mtod(m, struct sphdr *) = cb->s_shdr.si_s;
844 		}
845 		*value = m;
846 		break;
847 
848 	case PRCO_SETOPT:
849 		if (value == 0 || *value == 0) {
850 			error = EINVAL;
851 			break;
852 		}
853 		switch (name) {
854 			int *ok;
855 
856 		case SO_HEADERS_ON_INPUT:
857 			mask = SF_HI;
858 			goto set_head;
859 
860 		case SO_HEADERS_ON_OUTPUT:
861 			mask = SF_HO;
862 		set_head:
863 			if (cb->s_flags & SF_PI) {
864 				ok = mtod(*value, int *);
865 				if (*ok)
866 					cb->s_flags |= mask;
867 				else
868 					cb->s_flags &= ~mask;
869 			} else error = EINVAL;
870 			break;
871 
872 		case SO_MTU:
873 			cb->s_mtu = *(mtod(*value, u_short *));
874 			break;
875 
876 		case SO_DEFAULT_HEADERS:
877 			{
878 				register struct sphdr *sp
879 						= mtod(*value, struct sphdr *);
880 				cb->s_dt = sp->sp_dt;
881 				cb->s_cc = sp->sp_cc & SP_EM;
882 			}
883 		}
884 		m_freem(*value);
885 		break;
886 	}
887 	release:
888 		return (error);
889 }
890 
891 /*ARGSUSED*/
892 spp_usrreq(so, req, m, nam, rights)
893 	struct socket *so;
894 	int req;
895 	struct mbuf *m, *nam, *rights;
896 {
897 	struct nspcb *nsp = sotonspcb(so);
898 	register struct sppcb *cb;
899 	int s = splnet();
900 	int error = 0, ostate;
901 
902 	if (req == PRU_CONTROL)
903                 return (ns_control(so, (int)m, (caddr_t)nam,
904 			(struct ifnet *)rights));
905 	if (rights && rights->m_len) {
906 		error = EINVAL;
907 		goto release;
908 	}
909 	if (nsp == NULL) {
910 		if (req != PRU_ATTACH) {
911 			error = EINVAL;
912 			goto release;
913 		}
914 	} else
915 		cb = nstosppcb(nsp);
916 
917 	ostate = cb ? cb->s_state : 0;
918 
919 	switch (req) {
920 
921 	case PRU_ATTACH:
922 		if (nsp != NULL) {
923 			error = EISCONN;
924 			break;
925 		}
926 		error = ns_pcballoc(so, &nspcb);
927 		if (error)
928 			break;
929 		error = soreserve(so, 2048, 2048);
930 		if (error)
931 			break;
932 		nsp = sotonspcb(so);
933 		{
934 			struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB);
935 
936 			if (mm == NULL) {
937 				error = ENOBUFS;
938 				break;
939 			}
940 			cb = mtod(mm, struct sppcb *);
941 			cb->s_state = TCPS_LISTEN;
942 			cb->s_snt = -1;
943 			cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
944 			cb->s_nspcb = nsp;
945 			nsp->nsp_pcb = (caddr_t) cb;
946 		}
947 		break;
948 
949 	case PRU_DETACH:
950 		if (nsp == NULL) {
951 			error = ENOTCONN;
952 			break;
953 		}
954 		if (cb->s_state > TCPS_LISTEN)
955 			cb = spp_disconnect(cb);
956 		else
957 			cb = spp_close(cb);
958 		break;
959 
960 	case PRU_BIND:
961 		error = ns_pcbbind(nsp, nam);
962 		break;
963 
964 	case PRU_LISTEN:
965 		if (nsp->nsp_lport == 0)
966 			error = ns_pcbbind(nsp, (struct mbuf *)0);
967 		if (error == 0)
968 			cb->s_state = TCPS_LISTEN;
969 		break;
970 
971 	/*
972 	 * Initiate connection to peer.
973 	 * Enter SYN_SENT state, and mark socket as connecting.
974 	 * Start keep-alive timer, setup prototype header,
975 	 * Send initial system packet requesting connection.
976 	 */
977 	case PRU_CONNECT:
978 		if (nsp->nsp_lport == 0) {
979 			error = ns_pcbbind(nsp, (struct mbuf *)0);
980 			if (error)
981 				break;
982 		}
983 		error = ns_pcbconnect(nsp, nam);
984 		if (error)
985 			break;
986 		soisconnecting(so);
987 		cb->s_state = TCPS_SYN_SENT;
988 		cb->s_did = 0;
989 		spp_template(cb);
990 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
991 		cb->s_force = 1 + TCPTV_KEEP;
992 		/*
993 		 * Other party is required to respond to
994 		 * the port I send from, but he is not
995 		 * required to answer from where I am sending to,
996 		 * so allow wildcarding.
997 		 * original port I am sending to is still saved in
998 		 * cb->s_dport.
999 		 */
1000 		nsp->nsp_fport = 0;
1001 		error = spp_output(cb, (struct mbuf *) 0);
1002 		break;
1003 
1004 	case PRU_CONNECT2:
1005 		error = EOPNOTSUPP;
1006 		break;
1007 
1008 	/*
1009 	 * We may decide later to implement connection closing
1010 	 * handshaking at the spp level optionally.
1011 	 * here is the hook to do it:
1012 	 */
1013 	case PRU_DISCONNECT:
1014 		cb = spp_disconnect(cb);
1015 		break;
1016 
1017 	/*
1018 	 * Accept a connection.  Essentially all the work is
1019 	 * done at higher levels; just return the address
1020 	 * of the peer, storing through addr.
1021 	 */
1022 	case PRU_ACCEPT: {
1023 		struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
1024 
1025 		nam->m_len = sizeof (struct sockaddr_ns);
1026 		sns->sns_family = AF_NS;
1027 		sns->sns_addr = nsp->nsp_faddr;
1028 		break;
1029 		}
1030 
1031 	case PRU_SHUTDOWN:
1032 		socantsendmore(so);
1033 		cb = spp_usrclosed(cb);
1034 		if (cb)
1035 			error = spp_output(cb, (struct mbuf *) 0);
1036 		break;
1037 
1038 	/*
1039 	 * After a receive, possibly send acknowledgment
1040 	 * updating allocation.
1041 	 */
1042 	case PRU_RCVD:
1043 		(void) spp_output(cb, (struct mbuf *) 0);
1044 		break;
1045 
1046 	case PRU_SEND:
1047 		error = spp_output(cb, m);
1048 		m = NULL;
1049 		break;
1050 
1051 	case PRU_ABORT:
1052 		(void) spp_drop(cb, ECONNABORTED);
1053 		break;
1054 
1055 	case PRU_SENSE:
1056 	case PRU_CONTROL:
1057 		m = NULL;
1058 		error = EOPNOTSUPP;
1059 		break;
1060 
1061 	case PRU_RCVOOB:
1062 		if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
1063 		    (so->so_state & SS_RCVATMARK)) {
1064 			m->m_len = 1;
1065 			*mtod(m, caddr_t) = cb->s_iobc;
1066 			break;
1067 		}
1068 		error = EINVAL;
1069 		break;
1070 
1071 	case PRU_SENDOOB:
1072 		if (sbspace(&so->so_snd) < -512) {
1073 			m_freem(m);
1074 			error = ENOBUFS;
1075 			break;
1076 		}
1077 		cb->s_oobflags |= SF_SOOB;
1078 		error = spp_output(cb, m);
1079 		m = NULL;
1080 		break;
1081 
1082 	case PRU_SOCKADDR:
1083 		ns_setsockaddr(nsp, nam);
1084 		break;
1085 
1086 	case PRU_PEERADDR:
1087 		ns_setpeeraddr(nsp, nam);
1088 		break;
1089 
1090 	case PRU_SLOWTIMO:
1091 		cb = spp_timers(cb, (int)nam);
1092 		break;
1093 
1094 	case PRU_FASTTIMO:
1095 	case PRU_PROTORCV:
1096 	case PRU_PROTOSEND:
1097 		error =  EOPNOTSUPP;
1098 		break;
1099 
1100 	default:
1101 		panic("sp_usrreq");
1102 	}
1103 	if (cb && (so->so_options & SO_DEBUG || traceallspps))
1104 		spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
1105 release:
1106 	if (m != NULL)
1107 		m_freem(m);
1108 	splx(s);
1109 	return (error);
1110 }
1111 
1112 spp_usrreq_sp(so, req, m, nam, rights)
1113 	struct socket *so;
1114 	int req;
1115 	struct mbuf *m, *nam, *rights;
1116 {
1117 	int error = spp_usrreq(so, req, m, nam, rights);
1118 
1119 	if (req == PRU_ATTACH && error == 0) {
1120 		struct nspcb *nsp = sotonspcb(so);
1121 		((struct sppcb *)nsp->nsp_pcb)->s_flags |=
1122 					(SF_HI | SF_HO | SF_PI);
1123 	}
1124 	return (error);
1125 }
1126 
1127 /*
1128  * Create template to be used to send spp packets on a connection.
1129  * Called after host entry created, fills
1130  * in a skeletal spp header (choosing connection id),
1131  * minimizing the amount of work necessary when the connection is used.
1132  */
1133 spp_template(cb)
1134 	struct sppcb *cb;
1135 {
1136 	register struct nspcb *nsp = cb->s_nspcb;
1137 	register struct spidp *n = &(cb->s_shdr);
1138 
1139 	cb->s_mtu = 576 - sizeof (struct spidp);
1140 	n->si_pt = NSPROTO_SPP;
1141 	n->si_sna = nsp->nsp_laddr;
1142 	n->si_dna = nsp->nsp_faddr;
1143 	n->si_sid = htons(spp_iss);
1144 	spp_iss += SPP_ISSINCR/2;
1145 	n->si_alo = 1;
1146 }
1147 
1148 /*
1149  * Close a SPIP control block:
1150  *	discard spp control block itself
1151  *	discard ns protocol control block
1152  *	wake up any sleepers
1153  */
1154 struct sppcb *
1155 spp_close(cb)
1156 	register struct sppcb *cb;
1157 {
1158 	register struct spidp_q *s;
1159 	struct nspcb *nsp = cb->s_nspcb;
1160 	struct socket *so = nsp->nsp_socket;
1161 	register struct mbuf *m;
1162 
1163 	s = cb->s_q.si_next;
1164 	while (s != &(cb->s_q)) {
1165 		s = s->si_next;
1166 		m = dtom(s->si_prev);
1167 		remque(s->si_prev);
1168 		m_freem(m);
1169 	}
1170 	(void) m_free(dtom(cb));
1171 	nsp->nsp_pcb = 0;
1172 	soisdisconnected(so);
1173 	ns_pcbdetach(nsp);
1174 	return ((struct sppcb *)0);
1175 }
1176 /*
1177  *	Someday we may do level 3 handshaking
1178  *	to close a connection or send a xerox style error.
1179  *	For now, just close.
1180  */
1181 struct sppcb *
1182 spp_usrclosed(cb)
1183 	register struct sppcb *cb;
1184 {
1185 	return (spp_close(cb));
1186 }
1187 struct sppcb *
1188 spp_disconnect(cb)
1189 	register struct sppcb *cb;
1190 {
1191 	return (spp_close(cb));
1192 }
1193 /*
1194  * Drop connection, reporting
1195  * the specified error.
1196  */
1197 struct sppcb *
1198 spp_drop(cb, errno)
1199 	register struct sppcb *cb;
1200 	int errno;
1201 {
1202 	struct socket *so = cb->s_nspcb->nsp_socket;
1203 
1204 	/*
1205 	 * someday, in the xerox world
1206 	 * we will generate error protocol packets
1207 	 * announcing that the socket has gone away.
1208 	 */
1209 	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
1210 		tp->t_state = TCPS_CLOSED;
1211 		(void) tcp_output(tp);
1212 	}*/
1213 	so->so_error = errno;
1214 	return (spp_close(cb));
1215 }
1216 
1217 spp_abort(nsp)
1218 	struct nspcb *nsp;
1219 {
1220 
1221 	(void) spp_close((struct sppcb *)nsp->nsp_pcb);
1222 }
1223 
1224 spp_setpersist(cb)
1225 	register struct sppcb *cb;
1226 {
1227 
1228 	/*if (cb->s_timer[TCPT_REXMT])
1229 		panic("spp_output REXMT");*/
1230 	/*
1231 	 * Start/restart persistance timer.
1232 	 */
1233 	TCPT_RANGESET(cb->s_timer[TCPT_PERSIST],
1234 	    ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift,
1235 	    TCPTV_PERSMIN, TCPTV_MAX);
1236 	cb->s_rxtshift++;
1237 	if (cb->s_rxtshift >= TCP_MAXRXTSHIFT)
1238 		cb->s_rxtshift = 0;
1239 }
1240 /*
1241  * Fast timeout routine for processing delayed acks
1242  */
1243 int spp_ftcnt;
1244 spp_fasttimo()
1245 {
1246 	register struct nspcb *nsp;
1247 	register struct sppcb *cb;
1248 	int s = splnet();
1249 
1250 	nsp = nspcb.nsp_next;
1251 	spp_ftcnt++;
1252 	if (nsp)
1253 	for (; nsp != &nspcb; nsp = nsp->nsp_next)
1254 		if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
1255 		    (cb->s_flags & SF_DELACK)) {
1256 			cb->s_flags &= ~SF_DELACK;
1257 			cb->s_flags |= SF_AK;
1258 			(void) spp_output(cb, (struct mbuf *) 0);
1259 		}
1260 	splx(s);
1261 }
1262 
1263 /*
1264  * spp protocol timeout routine called every 500 ms.
1265  * Updates the timers in all active pcb's and
1266  * causes finite state machine actions if timers expire.
1267  */
1268 spp_slowtimo()
1269 {
1270 	register struct nspcb *ip, *ipnxt;
1271 	register struct sppcb *cb;
1272 	int s = splnet();
1273 	register int i;
1274 
1275 	/*
1276 	 * Search through tcb's and update active timers.
1277 	 */
1278 	ip = nspcb.nsp_next;
1279 	if (ip == 0) {
1280 		splx(s);
1281 		return;
1282 	}
1283 	while (ip != &nspcb) {
1284 		cb = nstosppcb(ip);
1285 		ipnxt = ip->nsp_next;
1286 		if (cb == 0)
1287 			goto tpgone;
1288 		for (i = 0; i < TCPT_NTIMERS; i++) {
1289 			if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
1290 				(void) spp_usrreq(cb->s_nspcb->nsp_socket,
1291 				    PRU_SLOWTIMO, (struct mbuf *)0,
1292 				    (struct mbuf *)i, (struct mbuf *)0);
1293 				if (ipnxt->nsp_prev != ip)
1294 					goto tpgone;
1295 			}
1296 		}
1297 		cb->s_idle++;
1298 		if (cb->s_rtt)
1299 			cb->s_rtt++;
1300 tpgone:
1301 		ip = ipnxt;
1302 	}
1303 	spp_iss += SPP_ISSINCR/PR_SLOWHZ;		/* increment iss */
1304 	splx(s);
1305 }
1306 
1307 float	spp_backoff[TCP_MAXRXTSHIFT] =
1308     { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 };
1309 int sppexprexmtbackoff = 0;
1310 /*
1311  * SPP timer processing.
1312  */
1313 struct sppcb *
1314 spp_timers(cb, timer)
1315 	register struct sppcb *cb;
1316 	int timer;
1317 {
1318 
1319 	cb->s_force = 1 + timer;
1320 	switch (timer) {
1321 
1322 	/*
1323 	 * 2 MSL timeout in shutdown went off.  Delete connection
1324 	 * control block.
1325 	 */
1326 	case TCPT_2MSL:
1327 		cb = spp_close(cb);
1328 		break;
1329 
1330 	/*
1331 	 * Retransmission timer went off.  Message has not
1332 	 * been acked within retransmit interval.  Back off
1333 	 * to a longer retransmit interval and retransmit all
1334 	 * unacknowledged messages in the window.
1335 	 */
1336 	case TCPT_REXMT:
1337 		cb->s_rxtshift++;
1338 		if (cb->s_rxtshift > TCP_MAXRXTSHIFT) {
1339 			cb = spp_drop(cb, ETIMEDOUT);
1340 			break;
1341 		}
1342 		(void) spp_output(cb, (struct mbuf *) 0);
1343 		TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1344 		    (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX);
1345 		if (sppexprexmtbackoff) {
1346 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1347 			    cb->s_timer[TCPT_REXMT] << cb->s_rxtshift,
1348 			    TCPTV_MIN, TCPTV_MAX);
1349 		} else {
1350 			TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1351 			    cb->s_timer[TCPT_REXMT] *
1352 			        spp_backoff[cb->s_rxtshift - 1],
1353 			    TCPTV_MIN, TCPTV_MAX);
1354 		}
1355 		break;
1356 
1357 	/*
1358 	 * Persistance timer into zero window.
1359 	 * Force a probe to be sent.
1360 	 */
1361 	case TCPT_PERSIST:
1362 		(void) spp_output(cb, (struct mbuf *) 0);
1363 		spp_setpersist(cb);
1364 		break;
1365 
1366 	/*
1367 	 * Keep-alive timer went off; send something
1368 	 * or drop connection if idle for too long.
1369 	 */
1370 	case TCPT_KEEP:
1371 		if (cb->s_state < TCPS_ESTABLISHED)
1372 			goto dropit;
1373 		if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
1374 		    	if (cb->s_idle >= TCPTV_MAXIDLE)
1375 				goto dropit;
1376 			(void) spp_output(cb, (struct mbuf *) 0);
1377 		} else
1378 			cb->s_idle = 0;
1379 		cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
1380 		break;
1381 	dropit:
1382 		cb = spp_drop(cb, ETIMEDOUT);
1383 		break;
1384 	}
1385 	return (cb);
1386 }
1387