1 /* $NetBSD: spp_usrreq.c,v 1.35 2003/09/30 00:01:18 christos Exp $ */
2
3 /*
4 * Copyright (c) 1984, 1985, 1986, 1987, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * @(#)spp_usrreq.c 8.2 (Berkeley) 1/9/95
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: spp_usrreq.c,v 1.35 2003/09/30 00:01:18 christos Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
40 #include <sys/mbuf.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/errno.h>
45
46 #include <net/if.h>
47 #include <net/route.h>
48 #include <netinet/tcp_fsm.h>
49
50 #include <netns/ns.h>
51 #include <netns/ns_pcb.h>
52 #include <netns/ns_var.h>
53 #include <netns/idp.h>
54 #include <netns/idp_var.h>
55 #include <netns/ns_error.h>
56 #include <netns/sp.h>
57 #include <netns/spidp.h>
58 #include <netns/spp_timer.h>
59 #include <netns/spp_var.h>
60 #include <netns/spp_debug.h>
61
62 #include <machine/stdarg.h>
63
64 MALLOC_DEFINE(M_SPIDPQ, "SP queue ent", "SP packet queue entry");
65
66 /*
67 * SP protocol implementation.
68 */
69 void
70 spp_init()
71 {
72
73 spp_iss = 1; /* WRONG !! should fish it out of TODR */
74 }
75
76 int spp_use_delack = 0;
77 int traceallspps = 0;
78 int spp_hardnosed;
79 u_short spp_iss;
80 struct spidp spp_savesi;
81 struct spp_istat spp_istat;
82
83
84 /*ARGSUSED*/
85 void
86 #if __STDC__
87 spp_input(struct mbuf *m, ...)
88 #else
89 spp_input(m, va_alist)
90 struct mbuf *m;
91 va_dcl
92 #endif
93 {
94 struct nspcb *nsp;
95 struct sppcb *cb;
96 struct spidp *si = mtod(m, struct spidp *);
97 struct socket *so;
98 short ostate = 0;
99 int dropsocket = 0;
100 va_list ap;
101
102 va_start(ap, m);
103 nsp = va_arg(ap, struct nspcb *);
104 va_end(ap);
105
106
107 sppstat.spps_rcvtotal++;
108 if (nsp == 0) {
109 panic("No nspcb in spp_input");
110 return;
111 }
112
113 cb = nstosppcb(nsp);
114 if (cb == 0) goto bad;
115
116 if (m->m_len < sizeof(*si)) {
117 if ((m = m_pullup(m, sizeof(*si))) == 0) {
118 sppstat.spps_rcvshort++;
119 return;
120 }
121 si = mtod(m, struct spidp *);
122 }
123
124 /* Convert some header fields to host format. */
125 NTOHS(si->si_seq);
126 NTOHS(si->si_ack);
127 NTOHS(si->si_alo);
128
129 so = nsp->nsp_socket;
130 if (so->so_options & SO_DEBUG || traceallspps) {
131 ostate = cb->s_state;
132 spp_savesi = *si;
133 }
134 if (so->so_options & SO_ACCEPTCONN) {
135 struct sppcb *ocb = cb;
136
137 so = sonewconn(so, 0);
138 if (so == 0) {
139 goto drop;
140 }
141 /*
142 * This is ugly, but ....
143 *
144 * Mark socket as temporary until we're
145 * committed to keeping it. The code at
146 * ``drop'' and ``dropwithreset'' check the
147 * flag dropsocket to see if the temporary
148 * socket created here should be discarded.
149 * We mark the socket as discardable until
150 * we're committed to it below in TCPS_LISTEN.
151 */
152 dropsocket++;
153 nsp = (struct nspcb *)so->so_pcb;
154 nsp->nsp_laddr = si->si_dna;
155 cb = nstosppcb(nsp);
156 cb->s_mtu = ocb->s_mtu; /* preserve sockopts */
157 cb->s_flags = ocb->s_flags; /* preserve sockopts */
158 cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */
159 cb->s_state = TCPS_LISTEN;
160 }
161
162 /*
163 * Packet received on connection.
164 * reset idle time and keep-alive timer;
165 */
166 cb->s_idle = 0;
167 cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
168
169 switch (cb->s_state) {
170
171 case TCPS_LISTEN:{
172 struct mbuf *am;
173 struct sockaddr_ns *sns;
174 struct ns_addr laddr;
175
176 /*
177 * If somebody here was carying on a conversation
178 * and went away, and his pen pal thinks he can
179 * still talk, we get the misdirected packet.
180 */
181 if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
182 spp_istat.gonawy++;
183 goto dropwithreset;
184 }
185 am = m_get(M_DONTWAIT, MT_SONAME);
186 if (am == NULL)
187 goto drop;
188 am->m_len = sizeof (struct sockaddr_ns);
189 sns = mtod(am, struct sockaddr_ns *);
190 sns->sns_len = sizeof(*sns);
191 sns->sns_family = AF_NS;
192 sns->sns_addr = si->si_sna;
193 laddr = nsp->nsp_laddr;
194 if (ns_nullhost(laddr))
195 nsp->nsp_laddr = si->si_dna;
196 if (ns_pcbconnect(nsp, am)) {
197 nsp->nsp_laddr = laddr;
198 (void) m_free(am);
199 spp_istat.noconn++;
200 goto drop;
201 }
202 (void) m_free(am);
203 spp_template(cb);
204 dropsocket = 0; /* committed to socket */
205 cb->s_did = si->si_sid;
206 cb->s_rack = si->si_ack;
207 cb->s_ralo = si->si_alo;
208 #define THREEWAYSHAKE
209 #ifdef THREEWAYSHAKE
210 cb->s_state = TCPS_SYN_RECEIVED;
211 cb->s_force = 1 + SPPT_KEEP;
212 sppstat.spps_accepts++;
213 cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
214 }
215 break;
216 /*
217 * This state means that we have heard a response
218 * to our acceptance of their connection
219 * It is probably logically unnecessary in this
220 * implementation.
221 */
222 case TCPS_SYN_RECEIVED: {
223 if (si->si_did!=cb->s_sid) {
224 spp_istat.wrncon++;
225 goto drop;
226 }
227 #endif
228 nsp->nsp_fport = si->si_sport;
229 cb->s_timer[SPPT_REXMT] = 0;
230 cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
231 soisconnected(so);
232 cb->s_state = TCPS_ESTABLISHED;
233 sppstat.spps_accepts++;
234 }
235 break;
236
237 /*
238 * This state means that we have gotten a response
239 * to our attempt to establish a connection.
240 * We fill in the data from the other side,
241 * telling us which port to respond to, instead of the well-
242 * known one we might have sent to in the first place.
243 * We also require that this is a response to our
244 * connection id.
245 */
246 case TCPS_SYN_SENT:
247 if (si->si_did!=cb->s_sid) {
248 spp_istat.notme++;
249 goto drop;
250 }
251 sppstat.spps_connects++;
252 cb->s_did = si->si_sid;
253 cb->s_rack = si->si_ack;
254 cb->s_ralo = si->si_alo;
255 cb->s_dport = nsp->nsp_fport = si->si_sport;
256 cb->s_timer[SPPT_REXMT] = 0;
257 cb->s_flags |= SF_ACKNOW;
258 soisconnected(so);
259 cb->s_state = TCPS_ESTABLISHED;
260 /* Use roundtrip time of connection request for initial rtt */
261 if (cb->s_rtt) {
262 cb->s_srtt = cb->s_rtt << 3;
263 cb->s_rttvar = cb->s_rtt << 1;
264 SPPT_RANGESET(cb->s_rxtcur,
265 ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
266 SPPTV_MIN, SPPTV_REXMTMAX);
267 cb->s_rtt = 0;
268 }
269 }
270 if (so->so_options & SO_DEBUG || traceallspps)
271 spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0);
272
273 m->m_len -= sizeof (struct idp);
274 m->m_pkthdr.len -= sizeof (struct idp);
275 m->m_data += sizeof (struct idp);
276
277 if (spp_reass(cb, si, m)) {
278 (void) m_freem(m);
279 }
280 if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT)))
281 (void) spp_output(NULL, cb);
282 cb->s_flags &= ~(SF_WIN|SF_RXT);
283 return;
284
285 dropwithreset:
286 if (dropsocket)
287 (void) soabort(so);
288 /* Convert back to network format. */
289 HTONS(si->si_seq);
290 HTONS(si->si_ack);
291 HTONS(si->si_alo);
292 ns_error(m, NS_ERR_NOSOCK, 0);
293 if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)
294 spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
295 return;
296
297 drop:
298 bad:
299 if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG ||
300 traceallspps)
301 spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
302 m_freem(m);
303 }
304
305 int spprexmtthresh = 3;
306
307 /*
308 * This is structurally similar to the tcp reassembly routine
309 * but its function is somewhat different: It merely queues
310 * packets up, and suppresses duplicates.
311 */
312 int
313 spp_reass(cb, si, m0)
314 struct sppcb *cb;
315 struct spidp *si;
316 struct mbuf *m0;
317 {
318 struct spidp_q *p, *q, *si_q;
319 struct mbuf *m;
320 struct socket *so = cb->s_nspcb->nsp_socket;
321 char packetp = cb->s_flags & SF_HI;
322 int incr;
323 char wakeup = 0;
324
325 if (si == SI(0))
326 goto present;
327 /*
328 * Update our news from them.
329 */
330 if (si->si_cc & SP_SA)
331 cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_ACKNOW);
332 if (SSEQ_GT(si->si_alo, cb->s_ralo))
333 cb->s_flags |= SF_WIN;
334 if (SSEQ_LEQ(si->si_ack, cb->s_rack)) {
335 if ((si->si_cc & SP_SP) && cb->s_rack != (cb->s_smax + 1)) {
336 sppstat.spps_rcvdupack++;
337 /*
338 * If this is a completely duplicate ack
339 * and other conditions hold, we assume
340 * a packet has been dropped and retransmit
341 * it exactly as in tcp_input().
342 */
343 if (si->si_ack != cb->s_rack ||
344 si->si_alo != cb->s_ralo)
345 cb->s_dupacks = 0;
346 else if (++cb->s_dupacks == spprexmtthresh) {
347 u_short onxt = cb->s_snxt;
348 int cwnd = cb->s_cwnd;
349
350 cb->s_snxt = si->si_ack;
351 cb->s_cwnd = CUNIT;
352 cb->s_force = 1 + SPPT_REXMT;
353 (void) spp_output(NULL, cb);
354 cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
355 cb->s_rtt = 0;
356 if (cwnd >= 4 * CUNIT)
357 cb->s_cwnd = cwnd / 2;
358 if (SSEQ_GT(onxt, cb->s_snxt))
359 cb->s_snxt = onxt;
360 return (1);
361 }
362 } else
363 cb->s_dupacks = 0;
364 goto update_window;
365 }
366 cb->s_dupacks = 0;
367 /*
368 * If our correspondent acknowledges data we haven't sent
369 * TCP would drop the packet after acking. We'll be a little
370 * more permissive
371 */
372 if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) {
373 sppstat.spps_rcvacktoomuch++;
374 si->si_ack = cb->s_smax + 1;
375 }
376 sppstat.spps_rcvackpack++;
377 /*
378 * If transmit timer is running and timed sequence
379 * number was acked, update smoothed round trip time.
380 * See discussion of algorithm in tcp_input.c
381 */
382 if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
383 sppstat.spps_rttupdated++;
384 if (cb->s_srtt != 0) {
385 short delta;
386 delta = cb->s_rtt - (cb->s_srtt >> 3);
387 if ((cb->s_srtt += delta) <= 0)
388 cb->s_srtt = 1;
389 if (delta < 0)
390 delta = -delta;
391 delta -= (cb->s_rttvar >> 2);
392 if ((cb->s_rttvar += delta) <= 0)
393 cb->s_rttvar = 1;
394 } else {
395 /*
396 * No rtt measurement yet
397 */
398 cb->s_srtt = cb->s_rtt << 3;
399 cb->s_rttvar = cb->s_rtt << 1;
400 }
401 cb->s_rtt = 0;
402 cb->s_rxtshift = 0;
403 SPPT_RANGESET(cb->s_rxtcur,
404 ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
405 SPPTV_MIN, SPPTV_REXMTMAX);
406 }
407 /*
408 * If all outstanding data is acked, stop retransmit
409 * timer and remember to restart (more output or persist).
410 * If there is more data to be acked, restart retransmit
411 * timer, using current (possibly backed-off) value;
412 */
413 if (si->si_ack == cb->s_smax + 1) {
414 cb->s_timer[SPPT_REXMT] = 0;
415 cb->s_flags |= SF_RXT;
416 } else if (cb->s_timer[SPPT_PERSIST] == 0)
417 cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
418 /*
419 * When new data is acked, open the congestion window.
420 * If the window gives us less than ssthresh packets
421 * in flight, open exponentially (maxseg at a time).
422 * Otherwise open linearly (maxseg^2 / cwnd at a time).
423 */
424 incr = CUNIT;
425 if (cb->s_cwnd > cb->s_ssthresh)
426 incr = max(incr * incr / cb->s_cwnd, 1);
427 cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx);
428 /*
429 * Trim Acked data from output queue.
430 */
431 while ((m = so->so_snd.sb_mb) != NULL) {
432 if (SSEQ_LT((mtod(m, struct spidp *))->si_seq, si->si_ack))
433 sbdroprecord(&so->so_snd);
434 else
435 break;
436 }
437 sowwakeup(so);
438 cb->s_rack = si->si_ack;
439 update_window:
440 if (SSEQ_LT(cb->s_snxt, cb->s_rack))
441 cb->s_snxt = cb->s_rack;
442 if (SSEQ_LT(cb->s_swl1, si->si_seq) || (cb->s_swl1 == si->si_seq &&
443 (SSEQ_LT(cb->s_swl2, si->si_ack) ||
444 (cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))))) {
445 /* keep track of pure window updates */
446 if ((si->si_cc & SP_SP) && cb->s_swl2 == si->si_ack
447 && SSEQ_LT(cb->s_ralo, si->si_alo)) {
448 sppstat.spps_rcvwinupd++;
449 sppstat.spps_rcvdupack--;
450 }
451 cb->s_ralo = si->si_alo;
452 cb->s_swl1 = si->si_seq;
453 cb->s_swl2 = si->si_ack;
454 cb->s_swnd = (1 + si->si_alo - si->si_ack);
455 if (cb->s_swnd > cb->s_smxw)
456 cb->s_smxw = cb->s_swnd;
457 cb->s_flags |= SF_WIN;
458 }
459 /*
460 * If this packet number is higher than that which
461 * we have allocated refuse it, unless urgent
462 */
463 if (SSEQ_GT(si->si_seq, cb->s_alo)) {
464 if (si->si_cc & SP_SP) {
465 sppstat.spps_rcvwinprobe++;
466 return (1);
467 } else
468 sppstat.spps_rcvpackafterwin++;
469 if (si->si_cc & SP_OB) {
470 if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) {
471 ns_error(m0, NS_ERR_FULLUP, 0);
472 return (0);
473 } /* else queue this packet; */
474 } else {
475 /*struct socket *so = cb->s_nspcb->nsp_socket;
476 if (so->so_state & SS_NOFDREF) {
477 ns_error(m0, NS_ERR_NOSOCK, 0);
478 (void)spp_close(cb);
479 } else
480 would crash system*/
481 spp_istat.notyet++;
482 ns_error(m0, NS_ERR_FULLUP, 0);
483 return (0);
484 }
485 }
486 /*
487 * If this is a system packet, we don't need to
488 * queue it up, and won't update acknowledge #
489 */
490 if (si->si_cc & SP_SP) {
491 return (1);
492 }
493 /*
494 * We have already seen this packet, so drop.
495 */
496 if (SSEQ_LT(si->si_seq, cb->s_ack)) {
497 spp_istat.bdreas++;
498 sppstat.spps_rcvduppack++;
499 if (si->si_seq == cb->s_ack - 1)
500 spp_istat.lstdup++;
501 return (1);
502 }
503 /*
504 * Loop through all packets queued up to insert in
505 * appropriate sequence.
506 */
507 for (p = NULL, q = cb->s_q.lh_first; q != NULL;
508 p = q, q = q->si_q.le_next) {
509 if (si->si_seq == q->si_spidp->si_seq) {
510 sppstat.spps_rcvduppack++;
511 return (1);
512 }
513 if (SSEQ_LT(si->si_seq, q->si_spidp->si_seq)) {
514 sppstat.spps_rcvoopack++;
515 break;
516 }
517 }
518
519 MALLOC(si_q, struct spidp_q *, sizeof (struct spidp_q),
520 M_SPIDPQ, M_NOWAIT);
521 if (si_q == NULL) {
522 sppstat.spps_rcvshort ++; /* XXX rcvmemdrop... */
523 return (1);
524 }
525 si_q->si_spidp = si;
526 si_q->si_m = m0;
527 if (p == NULL) {
528 LIST_INSERT_HEAD(&cb->s_q, si_q, si_q);
529 } else {
530 LIST_INSERT_AFTER(p, si_q, si_q);
531 }
532 /*
533 * If this packet is urgent, inform process
534 */
535 if (si->si_cc & SP_OB) {
536 cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
537 sohasoutofband(so);
538 cb->s_oobflags |= SF_IOOB;
539 }
540 present:
541 #define SPINC sizeof(struct sphdr)
542 /*
543 * Loop through all packets queued up to update acknowledge
544 * number, and present all acknowledged data to user;
545 * If in packet interface mode, show packet headers.
546 */
547 for (q = cb->s_q.lh_first; q != NULL; q = p) {
548 if (q->si_spidp->si_seq == cb->s_ack) {
549 cb->s_ack++;
550 m = q->si_m;
551 if (q->si_spidp->si_cc & SP_OB) {
552 cb->s_oobflags &= ~SF_IOOB;
553 if (so->so_rcv.sb_cc)
554 so->so_oobmark = so->so_rcv.sb_cc;
555 else
556 so->so_state |= SS_RCVATMARK;
557 }
558 p = q->si_q.le_next;
559 LIST_REMOVE(q, si_q);
560 FREE(q, M_SPIDPQ);
561 wakeup = 1;
562 sppstat.spps_rcvpack++;
563 #ifdef SF_NEWCALL
564 if (cb->s_flags2 & SF_NEWCALL) {
565 struct sphdr *sp = mtod(m, struct sphdr *);
566 u_char dt = sp->sp_dt;
567 if (dt != cb->s_rhdr.sp_dt) {
568 struct mbuf *mm =
569 m_getclr(M_DONTWAIT, MT_CONTROL);
570 if (mm != NULL) {
571 u_short *s =
572 mtod(mm, u_short *);
573 cb->s_rhdr.sp_dt = dt;
574 mm->m_len = 5; /*XXX*/
575 s[0] = 5;
576 s[1] = 1;
577 *(u_char *)(&s[2]) = dt;
578 sbappend(&so->so_rcv, mm);
579 }
580 }
581 if (sp->sp_cc & SP_OB) {
582 MCHTYPE(m, MT_OOBDATA);
583 so->so_oobmark = 0;
584 so->so_state &= ~SS_RCVATMARK;
585 }
586 if (packetp == 0) {
587 m->m_data += SPINC;
588 m->m_len -= SPINC;
589 m->m_pkthdr.len -= SPINC;
590 }
591 if ((sp->sp_cc & SP_EM) || packetp) {
592 sbappendrecord(&so->so_rcv, m);
593 } else
594 sbappend(&so->so_rcv, m);
595 } else
596 #endif
597 if (packetp) {
598 sbappendrecord(&so->so_rcv, m);
599 } else {
600 cb->s_rhdr = *mtod(m, struct sphdr *);
601 m->m_data += SPINC;
602 m->m_len -= SPINC;
603 m->m_pkthdr.len -= SPINC;
604 sbappend(&so->so_rcv, m);
605 }
606 } else
607 break;
608 }
609 if (wakeup) sorwakeup(so);
610 return (0);
611 }
612
613 void *
614 spp_ctlinput(cmd, sa, arg)
615 int cmd;
616 struct sockaddr *sa;
617 void *arg;
618 {
619 struct ns_addr *na;
620 struct ns_errp *errp = NULL;
621 struct nspcb *nsp;
622 struct sockaddr_ns *sns;
623 int type;
624
625 if ((unsigned)cmd >= PRC_NCMDS)
626 return NULL;
627 type = NS_ERR_UNREACH_HOST;
628
629
630 switch (cmd) {
631
632 case PRC_ROUTEDEAD:
633 return NULL;
634
635 case PRC_IFDOWN:
636 case PRC_HOSTDEAD:
637 case PRC_HOSTUNREACH:
638 sns = (struct sockaddr_ns *) sa;
639 if (sns->sns_family != AF_NS)
640 return NULL;
641 na = &sns->sns_addr;
642 break;
643
644 case PRC_REDIRECT_NET:
645 case PRC_REDIRECT_HOST:
646 case PRC_REDIRECT_TOSNET:
647 case PRC_REDIRECT_TOSHOST:
648 /*
649 * PRC_IS_REDIRECT: Call ns_rtchange to flush the route, so
650 * that the next time we attempt output we try a new one
651 * XXX: Is this the right way? ns_rtchange has a comment
652 * that needs to be fixed.
653 */
654 sns = (struct sockaddr_ns *) sa;
655 if (sns->sns_family != AF_NS)
656 return NULL;
657 na = &sns->sns_addr;
658 ns_pcbnotify(na, (int)nsctlerrmap[cmd], ns_rtchange, (long) 0);
659 return NULL;
660
661 default:
662 errp = arg;
663 na = &errp->ns_err_idp.idp_dna;
664 type = errp->ns_err_num;
665 type = ntohs((u_int16_t)type);
666 break;
667 }
668
669 switch (type) {
670
671 case NS_ERR_UNREACH_HOST:
672 ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0);
673 break;
674
675 case NS_ERR_TOO_BIG:
676 case NS_ERR_NOSOCK:
677 nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port,
678 NS_WILDCARD);
679 if (nsp) {
680 if(nsp->nsp_pcb)
681 (void) spp_drop((struct sppcb *)nsp->nsp_pcb,
682 (int)nsctlerrmap[cmd]);
683 else
684 (void) idp_drop(nsp, (int)nsctlerrmap[cmd]);
685 }
686 break;
687
688 case NS_ERR_FULLUP:
689 ns_pcbnotify(na, 0, spp_quench, (long) 0);
690 }
691 return NULL;
692 }
693
694 /*
695 * When a source quench is received, close congestion window
696 * to one packet. We will gradually open it again as we proceed.
697 */
698 void
699 spp_quench(nsp)
700 struct nspcb *nsp;
701 {
702 struct sppcb *cb = nstosppcb(nsp);
703
704 if (cb)
705 cb->s_cwnd = CUNIT;
706 }
707
708 #ifdef notdef
709 int
710 spp_fixmtu(nsp)
711 struct nspcb *nsp;
712 {
713 struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb);
714 struct mbuf *m;
715 struct spidp *si;
716 struct ns_errp *ep;
717 struct sockbuf *sb;
718 int badseq, len;
719 struct mbuf *firstbad, *m0;
720
721 if (cb) {
722 /*
723 * The notification that we have sent
724 * too much is bad news -- we will
725 * have to go through queued up so far
726 * splitting ones which are too big and
727 * reassigning sequence numbers and checksums.
728 * we should then retransmit all packets from
729 * one above the offending packet to the last one
730 * we had sent (or our allocation)
731 * then the offending one so that the any queued
732 * data at our destination will be discarded.
733 */
734 ep = (struct ns_errp *)nsp->nsp_notify_param;
735 sb = &nsp->nsp_socket->so_snd;
736 cb->s_mtu = ep->ns_err_param;
737 badseq = SI(&ep->ns_err_idp)->si_seq;
738 for (m = sb->sb_mb; m; m = m->m_nextpkt) {
739 si = mtod(m, struct spidp *);
740 if (si->si_seq == badseq)
741 break;
742 }
743 if (m == 0) return;
744 firstbad = m;
745 /*for (;;) {*/
746 /* calculate length */
747 for (m0 = m, len = 0; m ; m = m->m_next)
748 len += m->m_len;
749 if (len > cb->s_mtu) {
750 }
751 /* FINISH THIS
752 } */
753 }
754 }
755 #endif
756
757 int
758 #if __STDC__
759 spp_output(struct mbuf *m0, ...)
760 #else
761 spp_output(m0, va_alist)
762 struct mbuf *m0;
763 va_dcl
764 #endif
765 {
766 struct sppcb *cb = NULL;
767 struct socket *so;
768 struct mbuf *m = NULL;
769 struct spidp *si = (struct spidp *) 0;
770 struct sockbuf *sb;
771 int len = 0, win, rcv_win;
772 short span, off, recordp = 0;
773 u_short alo;
774 int error = 0, sendalot;
775 #ifdef notdef
776 int idle;
777 #endif
778 struct mbuf *mprev = NULL;
779 extern int idpcksum;
780 va_list ap;
781
782 va_start(ap, m0);
783 cb = va_arg(ap, struct sppcb *);
784 va_end(ap);
785
786 so = cb->s_nspcb->nsp_socket;
787 sb = &so->so_snd;
788
789 if (m0) {
790 int mtu = cb->s_mtu;
791 int datalen;
792 /*
793 * Make sure that packet isn't too big.
794 */
795 for (m = m0; m ; m = m->m_next) {
796 mprev = m;
797 len += m->m_len;
798 if (m->m_flags & M_EOR)
799 recordp = 1;
800 }
801 datalen = (cb->s_flags & SF_HO) ?
802 len - sizeof (struct sphdr) : len;
803 if (datalen > mtu) {
804 if (cb->s_flags & SF_PI) {
805 m_freem(m0);
806 return (EMSGSIZE);
807 } else {
808 int oldEM = cb->s_cc & SP_EM;
809
810 cb->s_cc &= ~SP_EM;
811 while (len > mtu) {
812 /*
813 * Here we are only being called
814 * from usrreq(), so it is OK to
815 * block.
816 */
817 m = m_copym(m0, 0, mtu, M_WAIT);
818 if (cb->s_flags & SF_NEWCALL) {
819 struct mbuf *mm = m;
820 while (mm) {
821 mm->m_flags &= ~M_EOR;
822 mm = mm->m_next;
823 }
824 }
825 error = spp_output(m, cb);
826 if (error) {
827 cb->s_cc |= oldEM;
828 m_freem(m0);
829 return(error);
830 }
831 m_adj(m0, mtu);
832 len -= mtu;
833 }
834 cb->s_cc |= oldEM;
835 }
836 }
837 /*
838 * Force length even, by adding a "garbage byte" if
839 * necessary.
840 */
841 if (len & 1) {
842 m = mprev;
843 if (M_TRAILINGSPACE(m) >= 1)
844 m->m_len++;
845 else {
846 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
847
848 if (m1 == 0) {
849 m_freem(m0);
850 return (ENOBUFS);
851 }
852 m1->m_len = 1;
853 *(mtod(m1, u_char *)) = 0;
854 m->m_next = m1;
855 }
856 }
857 m = m_gethdr(M_DONTWAIT, MT_HEADER);
858 if (m == 0) {
859 m_freem(m0);
860 return (ENOBUFS);
861 }
862 /*
863 * Fill in mbuf with extended SP header
864 * and addresses and length put into network format.
865 */
866 MH_ALIGN(m, sizeof (struct spidp));
867 m->m_len = sizeof (struct spidp);
868 m->m_next = m0;
869 si = mtod(m, struct spidp *);
870 si->si_i = *cb->s_idp;
871 si->si_s = cb->s_shdr;
872 if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
873 struct sphdr *sh;
874 if (m0->m_len < sizeof (*sh)) {
875 if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
876 (void) m_free(m);
877 m_freem(m0);
878 return (EINVAL);
879 }
880 m->m_next = m0;
881 }
882 sh = mtod(m0, struct sphdr *);
883 si->si_dt = sh->sp_dt;
884 si->si_cc |= sh->sp_cc & SP_EM;
885 m0->m_len -= sizeof (*sh);
886 m0->m_data += sizeof (*sh);
887 len -= sizeof (*sh);
888 }
889 len += sizeof(*si);
890 if ((cb->s_flags2 & SF_NEWCALL) && recordp)
891 si->si_cc |= SP_EM;
892 if (cb->s_oobflags & SF_SOOB) {
893 /*
894 * Per jqj@cornell:
895 * make sure OB packets convey exactly 1 byte.
896 * If the packet is 1 byte or larger, we
897 * have already guaranted there to be at least
898 * one garbage byte for the checksum, and
899 * extra bytes shouldn't hurt!
900 */
901 if (len > sizeof(*si)) {
902 si->si_cc |= SP_OB;
903 len = (1 + sizeof(*si));
904 }
905 }
906 si->si_len = htons((u_int16_t)len);
907 m->m_pkthdr.len = ((len - 1) | 1) + 1;
908 /*
909 * queue stuff up for output
910 */
911 sbappendrecord(sb, m);
912 cb->s_seq++;
913 }
914 #ifdef notdef
915 idle = (cb->s_smax == (cb->s_rack - 1));
916 #endif
917 again:
918 sendalot = 0;
919 off = cb->s_snxt - cb->s_rack;
920 win = min(cb->s_swnd, (cb->s_cwnd/CUNIT));
921
922 /*
923 * If in persist timeout with window of 0, send a probe.
924 * Otherwise, if window is small but nonzero
925 * and timer expired, send what we can and go into
926 * transmit state.
927 */
928 if (cb->s_force == 1 + SPPT_PERSIST) {
929 if (win != 0) {
930 cb->s_timer[SPPT_PERSIST] = 0;
931 cb->s_rxtshift = 0;
932 }
933 }
934 span = cb->s_seq - cb->s_rack;
935 len = min(span, win) - off;
936
937 if (len < 0) {
938 /*
939 * Window shrank after we went into it.
940 * If window shrank to 0, cancel pending
941 * restransmission and pull s_snxt back
942 * to (closed) window. We will enter persist
943 * state below. If the widndow didn't close completely,
944 * just wait for an ACK.
945 */
946 len = 0;
947 if (win == 0) {
948 cb->s_timer[SPPT_REXMT] = 0;
949 cb->s_snxt = cb->s_rack;
950 }
951 }
952 if (len > 1)
953 sendalot = 1;
954 rcv_win = sbspace(&so->so_rcv);
955
956 /*
957 * Send if we owe peer an ACK.
958 */
959 if (cb->s_oobflags & SF_SOOB) {
960 /*
961 * must transmit this out of band packet
962 */
963 cb->s_oobflags &= ~ SF_SOOB;
964 sendalot = 1;
965 sppstat.spps_sndurg++;
966 goto found;
967 }
968 if (cb->s_flags & SF_ACKNOW)
969 goto send;
970 if (cb->s_state < TCPS_ESTABLISHED)
971 goto send;
972 /*
973 * Silly window can't happen in spp.
974 * Code from tcp deleted.
975 */
976 if (len)
977 goto send;
978 /*
979 * Compare available window to amount of window
980 * known to peer (as advertised window less
981 * next expected input.) If the difference is at least two
982 * packets or at least 35% of the mximum possible window,
983 * then want to send a window update to peer.
984 */
985 if (rcv_win > 0) {
986 u_int16_t delta = 1 + cb->s_alo - cb->s_ack;
987 int adv = rcv_win - (delta * cb->s_mtu);
988
989 if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) ||
990 (100 * adv / so->so_rcv.sb_hiwat >= 35)) {
991 sppstat.spps_sndwinup++;
992 cb->s_flags |= SF_ACKNOW;
993 goto send;
994 }
995
996 }
997 /*
998 * Many comments from tcp_output.c are appropriate here
999 * including . . .
1000 * If send window is too small, there is data to transmit, and no
1001 * retransmit or persist is pending, then go to persist state.
1002 * If nothing happens soon, send when timer expires:
1003 * if window is nonzero, transmit what we can,
1004 * otherwise send a probe.
1005 */
1006 if (so->so_snd.sb_cc && cb->s_timer[SPPT_REXMT] == 0 &&
1007 cb->s_timer[SPPT_PERSIST] == 0) {
1008 cb->s_rxtshift = 0;
1009 spp_setpersist(cb);
1010 }
1011 /*
1012 * No reason to send a packet, just return.
1013 */
1014 cb->s_outx = 1;
1015 return (0);
1016
1017 send:
1018 /*
1019 * Find requested packet.
1020 */
1021 si = 0;
1022 if (len > 0) {
1023 cb->s_want = cb->s_snxt;
1024 for (m = sb->sb_mb; m; m = m->m_nextpkt) {
1025 si = mtod(m, struct spidp *);
1026 if (SSEQ_LEQ(cb->s_snxt, si->si_seq))
1027 break;
1028 }
1029 found:
1030 if (si) {
1031 if (si->si_seq == cb->s_snxt)
1032 cb->s_snxt++;
1033 else
1034 sppstat.spps_sndvoid++, si = 0;
1035 }
1036 }
1037 /*
1038 * update window
1039 */
1040 if (rcv_win < 0)
1041 rcv_win = 0;
1042 alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu));
1043 if (SSEQ_LT(alo, cb->s_alo))
1044 alo = cb->s_alo;
1045
1046 if (si) {
1047 /*
1048 * must make a copy of this packet for
1049 * idp_output to monkey with
1050 */
1051 m = m_copy(m, 0, (int)M_COPYALL);
1052 if (m == NULL) {
1053 return (ENOBUFS);
1054 }
1055 si = mtod(m, struct spidp *);
1056 if (SSEQ_LT(si->si_seq, cb->s_smax))
1057 sppstat.spps_sndrexmitpack++;
1058 else
1059 sppstat.spps_sndpack++;
1060 } else if (cb->s_force || cb->s_flags & SF_ACKNOW) {
1061 /*
1062 * Must send an acknowledgement or a probe
1063 */
1064 if (cb->s_force)
1065 sppstat.spps_sndprobe++;
1066 if (cb->s_flags & SF_ACKNOW)
1067 sppstat.spps_sndacks++;
1068 m = m_gethdr(M_DONTWAIT, MT_HEADER);
1069 if (m == 0)
1070 return (ENOBUFS);
1071 /*
1072 * Fill in mbuf with extended SP header
1073 * and addresses and length put into network format.
1074 */
1075 MH_ALIGN(m, sizeof (struct spidp));
1076 m->m_len = sizeof (*si);
1077 m->m_pkthdr.len = sizeof (*si);
1078 si = mtod(m, struct spidp *);
1079 si->si_i = *cb->s_idp;
1080 si->si_s = cb->s_shdr;
1081 si->si_seq = cb->s_smax + 1;
1082 si->si_len = htons(sizeof (*si));
1083 si->si_cc |= SP_SP;
1084 } else {
1085 cb->s_outx = 3;
1086 if (so->so_options & SO_DEBUG || traceallspps)
1087 spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
1088 return (0);
1089 }
1090 /*
1091 * Stuff checksum and output datagram.
1092 */
1093 if ((si->si_cc & SP_SP) == 0) {
1094 if (cb->s_force != (1 + SPPT_PERSIST) ||
1095 cb->s_timer[SPPT_PERSIST] == 0) {
1096 /*
1097 * If this is a new packet and we are not currently
1098 * timing anything, time this one.
1099 */
1100 if (SSEQ_LT(cb->s_smax, si->si_seq)) {
1101 cb->s_smax = si->si_seq;
1102 if (cb->s_rtt == 0) {
1103 sppstat.spps_segstimed++;
1104 cb->s_rtseq = si->si_seq;
1105 cb->s_rtt = 1;
1106 }
1107 }
1108 /*
1109 * Set rexmt timer if not currently set,
1110 * Initial value for retransmit timer is smoothed
1111 * round-trip time + 2 * round-trip time variance.
1112 * Initialize shift counter which is used for backoff
1113 * of retransmit time.
1114 */
1115 if (cb->s_timer[SPPT_REXMT] == 0 &&
1116 cb->s_snxt != cb->s_rack) {
1117 cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
1118 if (cb->s_timer[SPPT_PERSIST]) {
1119 cb->s_timer[SPPT_PERSIST] = 0;
1120 cb->s_rxtshift = 0;
1121 }
1122 }
1123 } else if (SSEQ_LT(cb->s_smax, si->si_seq)) {
1124 cb->s_smax = si->si_seq;
1125 }
1126 } else if (cb->s_state < TCPS_ESTABLISHED) {
1127 if (cb->s_rtt == 0)
1128 cb->s_rtt = 1; /* Time initial handshake */
1129 if (cb->s_timer[SPPT_REXMT] == 0)
1130 cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
1131 }
1132 {
1133 /*
1134 * Do not request acks when we ack their data packets or
1135 * when we do a gratuitous window update.
1136 */
1137 if (((si->si_cc & SP_SP) == 0) || cb->s_force)
1138 si->si_cc |= SP_SA;
1139 si->si_seq = htons(si->si_seq);
1140 si->si_alo = htons(alo);
1141 si->si_ack = htons(cb->s_ack);
1142
1143 if (idpcksum) {
1144 si->si_sum = 0;
1145 len = ntohs(si->si_len);
1146 if (len & 1)
1147 len++;
1148 si->si_sum = ns_cksum(m, len);
1149 } else
1150 si->si_sum = 0xffff;
1151
1152 cb->s_outx = 4;
1153 if (so->so_options & SO_DEBUG || traceallspps)
1154 spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
1155
1156 if (so->so_options & SO_DONTROUTE)
1157 error = ns_output(m, (struct route *)0, NS_ROUTETOIF);
1158 else
1159 error = ns_output(m, &cb->s_nspcb->nsp_route, 0);
1160 }
1161 if (error) {
1162 return (error);
1163 }
1164 sppstat.spps_sndtotal++;
1165 /*
1166 * Data sent (as far as we can tell).
1167 * If this advertises a larger window than any other segment,
1168 * then remember the size of the advertized window.
1169 * Any pending ACK has now been sent.
1170 */
1171 cb->s_force = 0;
1172 cb->s_flags &= ~(SF_ACKNOW|SF_DELACK);
1173 if (SSEQ_GT(alo, cb->s_alo))
1174 cb->s_alo = alo;
1175 if (sendalot)
1176 goto again;
1177 cb->s_outx = 5;
1178 return (0);
1179 }
1180
1181 int spp_do_persist_panics = 0;
1182
1183 void
1184 spp_setpersist(cb)
1185 struct sppcb *cb;
1186 {
1187 int t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
1188 extern int spp_backoff[];
1189
1190 if (cb->s_timer[SPPT_REXMT] && spp_do_persist_panics)
1191 panic("spp_output REXMT");
1192 /*
1193 * Start/restart persistance timer.
1194 */
1195 SPPT_RANGESET(cb->s_timer[SPPT_PERSIST],
1196 t*spp_backoff[cb->s_rxtshift],
1197 SPPTV_PERSMIN, SPPTV_PERSMAX);
1198 if (cb->s_rxtshift < SPP_MAXRXTSHIFT)
1199 cb->s_rxtshift++;
1200 }
1201
1202 /*ARGSUSED*/
1203 int
1204 spp_ctloutput(req, so, level, name, value)
1205 int req;
1206 struct socket *so;
1207 int name, level;
1208 struct mbuf **value;
1209 {
1210 struct mbuf *m;
1211 struct nspcb *nsp = sotonspcb(so);
1212 struct sppcb *cb;
1213 int mask, error = 0;
1214
1215 if (level != NSPROTO_SPP) {
1216 /* This will have to be changed when we do more general
1217 stacking of protocols */
1218 return (idp_ctloutput(req, so, level, name, value));
1219 }
1220 if (nsp == NULL) {
1221 error = EINVAL;
1222 goto release;
1223 } else
1224 cb = nstosppcb(nsp);
1225
1226 switch (req) {
1227
1228 case PRCO_GETOPT:
1229 if (value == NULL)
1230 return (EINVAL);
1231 m = m_get(M_DONTWAIT, MT_DATA);
1232 if (m == NULL)
1233 return (ENOBUFS);
1234 switch (name) {
1235
1236 case SO_HEADERS_ON_INPUT:
1237 mask = SF_HI;
1238 goto get_flags;
1239
1240 case SO_HEADERS_ON_OUTPUT:
1241 mask = SF_HO;
1242 get_flags:
1243 m->m_len = sizeof(short);
1244 *mtod(m, short *) = cb->s_flags & mask;
1245 break;
1246
1247 case SO_MTU:
1248 m->m_len = sizeof(u_short);
1249 *mtod(m, short *) = cb->s_mtu;
1250 break;
1251
1252 case SO_LAST_HEADER:
1253 m->m_len = sizeof(struct sphdr);
1254 *mtod(m, struct sphdr *) = cb->s_rhdr;
1255 break;
1256
1257 case SO_DEFAULT_HEADERS:
1258 m->m_len = sizeof(struct spidp);
1259 *mtod(m, struct sphdr *) = cb->s_shdr;
1260 break;
1261
1262 default:
1263 error = EINVAL;
1264 }
1265 *value = m;
1266 break;
1267
1268 case PRCO_SETOPT:
1269 if (value == 0 || *value == 0) {
1270 error = EINVAL;
1271 break;
1272 }
1273 switch (name) {
1274 int *ok;
1275
1276 case SO_HEADERS_ON_INPUT:
1277 mask = SF_HI;
1278 goto set_head;
1279
1280 case SO_HEADERS_ON_OUTPUT:
1281 mask = SF_HO;
1282 set_head:
1283 if (cb->s_flags & SF_PI) {
1284 ok = mtod(*value, int *);
1285 if (*ok)
1286 cb->s_flags |= mask;
1287 else
1288 cb->s_flags &= ~mask;
1289 } else error = EINVAL;
1290 break;
1291
1292 case SO_MTU:
1293 cb->s_mtu = *(mtod(*value, u_short *));
1294 break;
1295
1296 #ifdef SF_NEWCALL
1297 case SO_NEWCALL:
1298 ok = mtod(*value, int *);
1299 if (*ok)
1300 cb->s_flags2 |= SF_NEWCALL;
1301 else
1302 cb->s_flags2 &= ~SF_NEWCALL;
1303 break;
1304 #endif
1305
1306 case SO_DEFAULT_HEADERS:
1307 {
1308 struct sphdr *sp
1309 = mtod(*value, struct sphdr *);
1310 cb->s_dt = sp->sp_dt;
1311 cb->s_cc = sp->sp_cc & SP_EM;
1312 }
1313 break;
1314
1315 default:
1316 error = EINVAL;
1317 }
1318 m_freem(*value);
1319 break;
1320 }
1321 release:
1322 return (error);
1323 }
1324
1325 u_long spp_sendspace = 3072;
1326 u_long spp_recvspace = 3072;
1327
1328 /*ARGSUSED*/
1329 int
1330 spp_usrreq(so, req, m, nam, control, p)
1331 struct socket *so;
1332 int req;
1333 struct mbuf *m, *nam, *control;
1334 struct proc *p;
1335 {
1336 struct nspcb *nsp;
1337 struct sppcb *cb = NULL;
1338 int s;
1339 int error = 0;
1340 int ostate;
1341
1342 if (req == PRU_CONTROL)
1343 return (ns_control(so, (u_long)m, (caddr_t)nam,
1344 (struct ifnet *)control, p));
1345
1346 if (req == PRU_PURGEIF) {
1347 ns_purgeif((struct ifnet *)control);
1348 return (0);
1349 }
1350
1351 s = splsoftnet();
1352 nsp = sotonspcb(so);
1353 if (nsp == 0 && req != PRU_ATTACH) {
1354 error = EINVAL;
1355 goto release;
1356 }
1357 if (nsp) {
1358 cb = nstosppcb(nsp);
1359 ostate = cb->s_state;
1360 } else
1361 ostate = 0;
1362
1363 switch (req) {
1364
1365 case PRU_ATTACH:
1366 if (nsp != 0) {
1367 error = EISCONN;
1368 break;
1369 }
1370 if ((error = soreserve(so, spp_sendspace, spp_recvspace)) ||
1371 (error = ns_pcballoc(so, &nspcb)))
1372 break;
1373 nsp = sotonspcb(so);
1374 cb = malloc(sizeof(*cb), M_PCB, M_NOWAIT);
1375 if (cb == 0) {
1376 error = ENOBUFS;
1377 break;
1378 }
1379 bzero((caddr_t)cb, sizeof(*cb));
1380 cb->s_idp = malloc(sizeof(*cb->s_idp), M_PCB, M_NOWAIT);
1381 if (cb->s_idp == 0) {
1382 free(cb, M_PCB);
1383 error = ENOBUFS;
1384 break;
1385 }
1386 bzero((caddr_t)cb->s_idp, sizeof(*cb->s_idp));
1387 cb->s_state = TCPS_LISTEN;
1388 cb->s_smax = -1;
1389 cb->s_swl1 = -1;
1390 LIST_INIT(&cb->s_q);
1391 cb->s_nspcb = nsp;
1392 cb->s_mtu = 576 - sizeof (struct spidp);
1393 cb->s_cwnd = sbspace(&so->so_snd) * CUNIT / cb->s_mtu;
1394 cb->s_ssthresh = cb->s_cwnd;
1395 cb->s_cwmx = sbspace(&so->so_snd) * CUNIT /
1396 (2 * sizeof (struct spidp));
1397 /* Above is recomputed when connecting to account
1398 for changed buffering or mtu's */
1399 cb->s_rtt = SPPTV_SRTTBASE;
1400 cb->s_rttvar = SPPTV_SRTTDFLT << 2;
1401 SPPT_RANGESET(cb->s_rxtcur,
1402 ((SPPTV_SRTTBASE >> 2) + (SPPTV_SRTTDFLT << 2)) >> 1,
1403 SPPTV_MIN, SPPTV_REXMTMAX);
1404 nsp->nsp_pcb = (caddr_t) cb;
1405 break;
1406
1407 case PRU_DETACH:
1408 if (cb->s_state > TCPS_LISTEN)
1409 cb = spp_disconnect(cb);
1410 else
1411 cb = spp_close(cb);
1412 break;
1413
1414 case PRU_BIND:
1415 error = ns_pcbbind(nsp, nam, p);
1416 break;
1417
1418 case PRU_LISTEN:
1419 if (nsp->nsp_lport == 0)
1420 error = ns_pcbbind(nsp, (struct mbuf *)0,
1421 (struct proc *)0);
1422 if (error == 0)
1423 cb->s_state = TCPS_LISTEN;
1424 break;
1425
1426 /*
1427 * Initiate connection to peer.
1428 * Enter SYN_SENT state, and mark socket as connecting.
1429 * Start keep-alive timer, setup prototype header,
1430 * Send initial system packet requesting connection.
1431 */
1432 case PRU_CONNECT:
1433 if (nsp->nsp_lport == 0) {
1434 error = ns_pcbbind(nsp, (struct mbuf *)0,
1435 (struct proc *)0);
1436 if (error)
1437 break;
1438 }
1439 error = ns_pcbconnect(nsp, nam);
1440 if (error)
1441 break;
1442 soisconnecting(so);
1443 sppstat.spps_connattempt++;
1444 cb->s_state = TCPS_SYN_SENT;
1445 cb->s_did = 0;
1446 spp_template(cb);
1447 cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
1448 cb->s_force = 1 + SPPTV_KEEP;
1449 /*
1450 * Other party is required to respond to
1451 * the port I send from, but he is not
1452 * required to answer from where I am sending to,
1453 * so allow wildcarding.
1454 * original port I am sending to is still saved in
1455 * cb->s_dport.
1456 */
1457 nsp->nsp_fport = 0;
1458 error = spp_output(NULL, cb);
1459 break;
1460
1461 case PRU_CONNECT2:
1462 error = EOPNOTSUPP;
1463 break;
1464
1465 /*
1466 * We may decide later to implement connection closing
1467 * handshaking at the spp level optionally.
1468 * here is the hook to do it:
1469 */
1470 case PRU_DISCONNECT:
1471 cb = spp_disconnect(cb);
1472 break;
1473
1474 /*
1475 * Accept a connection. Essentially all the work is
1476 * done at higher levels; just return the address
1477 * of the peer, storing through addr.
1478 */
1479 case PRU_ACCEPT:
1480 ns_setpeeraddr(nsp, nam);
1481 break;
1482
1483 case PRU_SHUTDOWN:
1484 socantsendmore(so);
1485 cb = spp_usrclosed(cb);
1486 if (cb)
1487 error = spp_output(NULL, cb);
1488 break;
1489
1490 /*
1491 * After a receive, possibly send acknowledgement
1492 * updating allocation.
1493 */
1494 case PRU_RCVD:
1495 cb->s_flags |= SF_RVD;
1496 (void) spp_output(NULL, cb);
1497 cb->s_flags &= ~SF_RVD;
1498 break;
1499
1500 case PRU_SEND:
1501 error = spp_output(m, cb);
1502 break;
1503
1504 case PRU_ABORT:
1505 cb = spp_drop(cb, ECONNABORTED);
1506 break;
1507
1508 case PRU_SENSE:
1509 /*
1510 * stat: don't bother with a blocksize.
1511 */
1512 splx(s);
1513 return (0);
1514
1515 case PRU_RCVOOB:
1516 if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
1517 (so->so_state & SS_RCVATMARK)) {
1518 m->m_len = 1;
1519 *mtod(m, caddr_t) = cb->s_iobc;
1520 break;
1521 }
1522 error = EINVAL;
1523 break;
1524
1525 case PRU_SENDOOB:
1526 if (sbspace(&so->so_snd) < -512) {
1527 m_freem(m);
1528 error = ENOBUFS;
1529 break;
1530 }
1531 cb->s_oobflags |= SF_SOOB;
1532 error = spp_output(m, cb);
1533 break;
1534
1535 case PRU_SOCKADDR:
1536 ns_setsockaddr(nsp, nam);
1537 break;
1538
1539 case PRU_PEERADDR:
1540 ns_setpeeraddr(nsp, nam);
1541 break;
1542
1543 case PRU_SLOWTIMO:
1544 cb = spp_timers(cb, (long)nam);
1545 req |= ((long)nam) << 8;
1546 break;
1547
1548 default:
1549 panic("sp_usrreq");
1550 }
1551 if (cb && (so->so_options & SO_DEBUG || traceallspps))
1552 spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
1553 release:
1554 splx(s);
1555 return (error);
1556 }
1557
1558 int
1559 spp_usrreq_sp(so, req, m, nam, control, p)
1560 struct socket *so;
1561 int req;
1562 struct mbuf *m, *nam, *control;
1563 struct proc *p;
1564 {
1565 int error = spp_usrreq(so, req, m, nam, control, p);
1566
1567 if (req == PRU_ATTACH && error == 0) {
1568 struct nspcb *nsp = sotonspcb(so);
1569 ((struct sppcb *)nsp->nsp_pcb)->s_flags |=
1570 (SF_HI | SF_HO | SF_PI);
1571 }
1572 return (error);
1573 }
1574
1575 /*
1576 * Create template to be used to send spp packets on a connection.
1577 * Called after host entry created, fills
1578 * in a skeletal spp header (choosing connection id),
1579 * minimizing the amount of work necessary when the connection is used.
1580 */
1581 void
1582 spp_template(cb)
1583 struct sppcb *cb;
1584 {
1585 struct nspcb *nsp = cb->s_nspcb;
1586 struct idp *idp = cb->s_idp;
1587 struct sockbuf *sb = &(nsp->nsp_socket->so_snd);
1588
1589 idp->idp_pt = NSPROTO_SPP;
1590 idp->idp_sna = nsp->nsp_laddr;
1591 idp->idp_dna = nsp->nsp_faddr;
1592 cb->s_sid = htons(spp_iss);
1593 spp_iss += SPP_ISSINCR/2;
1594 cb->s_alo = 1;
1595 cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu;
1596 cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement
1597 of large packets */
1598 cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spidp));
1599 cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd);
1600 /* But allow for lots of little packets as well */
1601 }
1602
1603 /*
1604 * Close a SPIP control block:
1605 * discard spp control block itself
1606 * discard ns protocol control block
1607 * wake up any sleepers
1608 */
1609 struct sppcb *
1610 spp_close(cb)
1611 struct sppcb *cb;
1612 {
1613 struct spidp_q *s, *n;
1614 struct nspcb *nsp = cb->s_nspcb;
1615 struct socket *so = nsp->nsp_socket;
1616 struct mbuf *m;
1617
1618 for (s = cb->s_q.lh_first; s != NULL; s = n) {
1619 n = s->si_q.le_next;
1620 m = s->si_m;
1621 LIST_REMOVE(s, si_q);
1622 FREE(s, M_SPIDPQ);
1623 m_freem(m);
1624 }
1625 free(cb->s_idp, M_PCB);
1626 free(cb, M_PCB);
1627 nsp->nsp_pcb = 0;
1628 soisdisconnected(so);
1629 ns_pcbdetach(nsp);
1630 sppstat.spps_closed++;
1631 return ((struct sppcb *)0);
1632 }
1633 /*
1634 * Someday we may do level 3 handshaking
1635 * to close a connection or send a xerox style error.
1636 * For now, just close.
1637 */
1638 struct sppcb *
1639 spp_usrclosed(cb)
1640 struct sppcb *cb;
1641 {
1642 return (spp_close(cb));
1643 }
1644 struct sppcb *
1645 spp_disconnect(cb)
1646 struct sppcb *cb;
1647 {
1648 return (spp_close(cb));
1649 }
1650 /*
1651 * Drop connection, reporting
1652 * the specified error.
1653 */
1654 struct sppcb *
1655 spp_drop(cb, errno)
1656 struct sppcb *cb;
1657 int errno;
1658 {
1659 struct socket *so = cb->s_nspcb->nsp_socket;
1660
1661 /*
1662 * someday, in the xerox world
1663 * we will generate error protocol packets
1664 * announcing that the socket has gone away.
1665 */
1666 if (TCPS_HAVERCVDSYN(cb->s_state)) {
1667 sppstat.spps_drops++;
1668 cb->s_state = TCPS_CLOSED;
1669 /*(void) tcp_output(cb);*/
1670 } else
1671 sppstat.spps_conndrops++;
1672 so->so_error = errno;
1673 return (spp_close(cb));
1674 }
1675
1676 void
1677 spp_abort(nsp)
1678 struct nspcb *nsp;
1679 {
1680
1681 (void) spp_close((struct sppcb *)nsp->nsp_pcb);
1682 }
1683
1684 int spp_backoff[SPP_MAXRXTSHIFT+1] =
1685 { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
1686 /*
1687 * Fast timeout routine for processing delayed acks
1688 */
1689 void
1690 spp_fasttimo()
1691 {
1692 struct nspcb *nsp;
1693 struct sppcb *cb;
1694 int s = splsoftnet();
1695
1696 nsp = nspcb.nsp_next;
1697 if (nsp)
1698 for (; nsp != &nspcb; nsp = nsp->nsp_next)
1699 if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
1700 (cb->s_flags & SF_DELACK)) {
1701 cb->s_flags &= ~SF_DELACK;
1702 cb->s_flags |= SF_ACKNOW;
1703 sppstat.spps_delack++;
1704 (void) spp_output(NULL, cb);
1705 }
1706 splx(s);
1707 }
1708
1709 /*
1710 * spp protocol timeout routine called every 500 ms.
1711 * Updates the timers in all active pcb's and
1712 * causes finite state machine actions if timers expire.
1713 */
1714 void
1715 spp_slowtimo()
1716 {
1717 struct nspcb *ip, *ipnxt;
1718 struct sppcb *cb;
1719 int s = splsoftnet();
1720 long i;
1721
1722 /*
1723 * Search through tcb's and update active timers.
1724 */
1725 ip = nspcb.nsp_next;
1726 if (ip == 0) {
1727 splx(s);
1728 return;
1729 }
1730 while (ip != &nspcb) {
1731 cb = nstosppcb(ip);
1732 ipnxt = ip->nsp_next;
1733 if (cb == 0)
1734 goto tpgone;
1735 for (i = 0; i < SPPT_NTIMERS; i++) {
1736 if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
1737 (void) spp_usrreq(cb->s_nspcb->nsp_socket,
1738 PRU_SLOWTIMO, (struct mbuf *)0,
1739 (struct mbuf *)i, (struct mbuf *)0,
1740 (struct proc *)0);
1741 if (ipnxt->nsp_prev != ip)
1742 goto tpgone;
1743 }
1744 }
1745 cb->s_idle++;
1746 if (cb->s_rtt)
1747 cb->s_rtt++;
1748 tpgone:
1749 ip = ipnxt;
1750 }
1751 spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */
1752 splx(s);
1753 }
1754 /*
1755 * SPP timer processing.
1756 */
1757 struct sppcb *
1758 spp_timers(cb, timer)
1759 struct sppcb *cb;
1760 long timer;
1761 {
1762 long rexmt;
1763 int win;
1764
1765 cb->s_force = 1 + timer;
1766 switch (timer) {
1767
1768 /*
1769 * 2 MSL timeout in shutdown went off. TCP deletes connection
1770 * control block.
1771 */
1772 case SPPT_2MSL:
1773 printf("spp: SPPT_2MSL went off for no reason\n");
1774 cb->s_timer[timer] = 0;
1775 break;
1776
1777 /*
1778 * Retransmission timer went off. Message has not
1779 * been acked within retransmit interval. Back off
1780 * to a longer retransmit interval and retransmit one packet.
1781 */
1782 case SPPT_REXMT:
1783 if (++cb->s_rxtshift > SPP_MAXRXTSHIFT) {
1784 cb->s_rxtshift = SPP_MAXRXTSHIFT;
1785 sppstat.spps_timeoutdrop++;
1786 cb = spp_drop(cb, ETIMEDOUT);
1787 break;
1788 }
1789 sppstat.spps_rexmttimeo++;
1790 rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
1791 rexmt *= spp_backoff[cb->s_rxtshift];
1792 SPPT_RANGESET(cb->s_rxtcur, rexmt, SPPTV_MIN, SPPTV_REXMTMAX);
1793 cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
1794 /*
1795 * If we have backed off fairly far, our srtt
1796 * estimate is probably bogus. Clobber it
1797 * so we'll take the next rtt measurement as our srtt;
1798 * move the current srtt into rttvar to keep the current
1799 * retransmit times until then.
1800 */
1801 if (cb->s_rxtshift > SPP_MAXRXTSHIFT / 4 ) {
1802 cb->s_rttvar += (cb->s_srtt >> 2);
1803 cb->s_srtt = 0;
1804 }
1805 cb->s_snxt = cb->s_rack;
1806 /*
1807 * If timing a packet, stop the timer.
1808 */
1809 cb->s_rtt = 0;
1810 /*
1811 * See very long discussion in tcp_timer.c about congestion
1812 * window and sstrhesh
1813 */
1814 win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2;
1815 if (win < 2)
1816 win = 2;
1817 cb->s_cwnd = CUNIT;
1818 cb->s_ssthresh = win * CUNIT;
1819 (void) spp_output(NULL, cb);
1820 break;
1821
1822 /*
1823 * Persistance timer into zero window.
1824 * Force a probe to be sent.
1825 */
1826 case SPPT_PERSIST:
1827 sppstat.spps_persisttimeo++;
1828 spp_setpersist(cb);
1829 (void) spp_output(NULL, cb);
1830 break;
1831
1832 /*
1833 * Keep-alive timer went off; send something
1834 * or drop connection if idle for too long.
1835 */
1836 case SPPT_KEEP:
1837 sppstat.spps_keeptimeo++;
1838 if (cb->s_state < TCPS_ESTABLISHED)
1839 goto dropit;
1840 if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
1841 if (cb->s_idle >= SPPTV_MAXIDLE)
1842 goto dropit;
1843 sppstat.spps_keepprobe++;
1844 (void) spp_output(NULL, cb);
1845 } else
1846 cb->s_idle = 0;
1847 cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
1848 break;
1849 dropit:
1850 sppstat.spps_keepdrops++;
1851 cb = spp_drop(cb, ETIMEDOUT);
1852 break;
1853 }
1854 return (cb);
1855 }
1856 #ifndef lint
1857 int SppcbSize = sizeof (struct sppcb);
1858 int NspcbSize = sizeof (struct nspcb);
1859 #endif /* lint */
Cache object: 504970b6ec9dd56b65f01330c0ced2fa
|