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