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