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