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