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