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