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