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