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