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