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