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