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