spx_reass.c revision 21673
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 * $FreeBSD: head/sys/netipx/spx_usrreq.c 21673 1997-01-14 07:20:47Z jkh $ 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/queue.h> 45#include <sys/socket.h> 46#include <sys/socketvar.h> 47#include <sys/errno.h> 48 49#include <net/if.h> 50#include <net/route.h> 51#include <netinet/tcp_fsm.h> 52 53#include <netipx/ipx.h> 54#include <netipx/ipx_pcb.h> 55#include <netipx/ipx_var.h> 56#include <netipx/ipx_error.h> 57#include <netipx/spx.h> 58#include <netipx/spx_timer.h> 59#include <netipx/spx_var.h> 60#include <netipx/spx_debug.h> 61 62/* 63 * SPX protocol implementation. 64 */ 65 66struct spx spx_savesi; 67int traceallspxs = 0; 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_as_sa, dummy) 588 int cmd; 589 struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */ 590 void *dummy; 591{ 592 caddr_t arg = (/* XXX */ caddr_t)arg_as_sa; 593 struct ipx_addr *na; 594 struct ipx_errp *errp = (struct ipx_errp *)arg; 595 struct ipxpcb *ipxp; 596 struct sockaddr_ipx *sipx; 597 int type; 598 599 if (cmd < 0 || cmd > PRC_NCMDS) 600 return; 601 type = IPX_ERR_UNREACH_HOST; 602 603 switch (cmd) { 604 605 case PRC_ROUTEDEAD: 606 return; 607 608 case PRC_IFDOWN: 609 case PRC_HOSTDEAD: 610 case PRC_HOSTUNREACH: 611 sipx = (struct sockaddr_ipx *)arg; 612 if (sipx->sipx_family != AF_IPX) 613 return; 614 na = &sipx->sipx_addr; 615 break; 616 617 default: 618 errp = (struct ipx_errp *)arg; 619 na = &errp->ipx_err_ipx.ipx_dna; 620 type = errp->ipx_err_num; 621 type = ntohs((u_short)type); 622 break; 623 } 624 switch (type) { 625 626 case IPX_ERR_UNREACH_HOST: 627 ipx_pcbnotify(na, (int)ipxctlerrmap[cmd], spx_abort, (long)0); 628 break; 629 630 case IPX_ERR_TOO_BIG: 631 case IPX_ERR_NOSOCK: 632 ipxp = ipx_pcblookup(na, errp->ipx_err_ipx.ipx_sna.x_port, 633 IPX_WILDCARD); 634 if (ipxp) { 635 if(ipxp->ipxp_pcb) 636 (void) spx_drop((struct spxpcb *)ipxp->ipxp_pcb, 637 (int)ipxctlerrmap[cmd]); 638 else 639 (void) ipx_drop(ipxp, (int)ipxctlerrmap[cmd]); 640 } 641 break; 642 643 case IPX_ERR_FULLUP: 644 ipx_pcbnotify(na, 0, spx_quench, (long)0); 645 break; 646 } 647} 648/* 649 * When a source quench is received, close congestion window 650 * to one packet. We will gradually open it again as we proceed. 651 */ 652void 653spx_quench(ipxp) 654 struct ipxpcb *ipxp; 655{ 656 struct spxpcb *cb = ipxtospxpcb(ipxp); 657 658 if (cb) 659 cb->s_cwnd = CUNIT; 660} 661 662#ifdef notdef 663int 664spx_fixmtu(ipxp) 665register struct ipxpcb *ipxp; 666{ 667 register struct spxpcb *cb = (struct spxpcb *)(ipxp->ipxp_pcb); 668 register struct mbuf *m; 669 register struct spx *si; 670 struct ipx_errp *ep; 671 struct sockbuf *sb; 672 int badseq, len; 673 struct mbuf *firstbad, *m0; 674 675 if (cb) { 676 /* 677 * The notification that we have sent 678 * too much is bad news -- we will 679 * have to go through queued up so far 680 * splitting ones which are too big and 681 * reassigning sequence numbers and checksums. 682 * we should then retransmit all packets from 683 * one above the offending packet to the last one 684 * we had sent (or our allocation) 685 * then the offending one so that the any queued 686 * data at our destination will be discarded. 687 */ 688 ep = (struct ipx_errp *)ipxp->ipxp_notify_param; 689 sb = &ipxp->ipxp_socket->so_snd; 690 cb->s_mtu = ep->ipx_err_param; 691 badseq = SI(&ep->ipx_err_ipx)->si_seq; 692 for (m = sb->sb_mb; m; m = m->m_act) { 693 si = mtod(m, struct spx *); 694 if (si->si_seq == badseq) 695 break; 696 } 697 if (m == 0) return; 698 firstbad = m; 699 /*for (;;) {*/ 700 /* calculate length */ 701 for (m0 = m, len = 0; m ; m = m->m_next) 702 len += m->m_len; 703 if (len > cb->s_mtu) { 704 } 705 /* FINISH THIS 706 } */ 707 } 708} 709#endif 710 711int 712spx_output(cb, m0) 713 register struct spxpcb *cb; 714 struct mbuf *m0; 715{ 716 struct socket *so = cb->s_ipxpcb->ipxp_socket; 717 register struct mbuf *m; 718 register struct spx *si = (struct spx *) 0; 719 register struct sockbuf *sb = &so->so_snd; 720 int len = 0, win, rcv_win; 721 short span, off, recordp = 0; 722 u_short alo; 723 int error = 0, sendalot; 724#ifdef notdef 725 int idle; 726#endif 727 struct mbuf *mprev; 728 729 if (m0) { 730 int mtu = cb->s_mtu; 731 int datalen; 732 /* 733 * Make sure that packet isn't too big. 734 */ 735 for (m = m0; m ; m = m->m_next) { 736 mprev = m; 737 len += m->m_len; 738 if (m->m_flags & M_EOR) 739 recordp = 1; 740 } 741 datalen = (cb->s_flags & SF_HO) ? 742 len - sizeof (struct spxhdr) : len; 743 if (datalen > mtu) { 744 if (cb->s_flags & SF_PI) { 745 m_freem(m0); 746 return (EMSGSIZE); 747 } else { 748 int oldEM = cb->s_cc & SPX_EM; 749 750 cb->s_cc &= ~SPX_EM; 751 while (len > mtu) { 752 /* 753 * Here we are only being called 754 * from usrreq(), so it is OK to 755 * block. 756 */ 757 m = m_copym(m0, 0, mtu, M_WAIT); 758 if (cb->s_flags & SF_NEWCALL) { 759 struct mbuf *mm = m; 760 spx_newchecks[7]++; 761 while (mm) { 762 mm->m_flags &= ~M_EOR; 763 mm = mm->m_next; 764 } 765 } 766 error = spx_output(cb, m); 767 if (error) { 768 cb->s_cc |= oldEM; 769 m_freem(m0); 770 return(error); 771 } 772 m_adj(m0, mtu); 773 len -= mtu; 774 } 775 cb->s_cc |= oldEM; 776 } 777 } 778 /* 779 * Force length even, by adding a "garbage byte" if 780 * necessary. 781 */ 782 if (len & 1) { 783 m = mprev; 784 if (M_TRAILINGSPACE(m) >= 1) 785 m->m_len++; 786 else { 787 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 788 789 if (m1 == 0) { 790 m_freem(m0); 791 return (ENOBUFS); 792 } 793 m1->m_len = 1; 794 *(mtod(m1, u_char *)) = 0; 795 m->m_next = m1; 796 } 797 } 798 m = m_gethdr(M_DONTWAIT, MT_HEADER); 799 if (m == 0) { 800 m_freem(m0); 801 return (ENOBUFS); 802 } 803 /* 804 * Fill in mbuf with extended SP header 805 * and addresses and length put into network format. 806 */ 807 MH_ALIGN(m, sizeof (struct spx)); 808 m->m_len = sizeof (struct spx); 809 m->m_next = m0; 810 si = mtod(m, struct spx *); 811 si->si_i = *cb->s_ipx; 812 si->si_s = cb->s_shdr; 813 if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 814 register struct spxhdr *sh; 815 if (m0->m_len < sizeof (*sh)) { 816 if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 817 (void) m_free(m); 818 m_freem(m0); 819 return (EINVAL); 820 } 821 m->m_next = m0; 822 } 823 sh = mtod(m0, struct spxhdr *); 824 si->si_dt = sh->spx_dt; 825 si->si_cc |= sh->spx_cc & SPX_EM; 826 m0->m_len -= sizeof (*sh); 827 m0->m_data += sizeof (*sh); 828 len -= sizeof (*sh); 829 } 830 len += sizeof(*si); 831 if ((cb->s_flags2 & SF_NEWCALL) && recordp) { 832 si->si_cc |= SPX_EM; 833 spx_newchecks[8]++; 834 } 835 if (cb->s_oobflags & SF_SOOB) { 836 /* 837 * Per jqj@cornell: 838 * make sure OB packets convey exactly 1 byte. 839 * If the packet is 1 byte or larger, we 840 * have already guaranted there to be at least 841 * one garbage byte for the checksum, and 842 * extra bytes shouldn't hurt! 843 */ 844 if (len > sizeof(*si)) { 845 si->si_cc |= SPX_OB; 846 len = (1 + sizeof(*si)); 847 } 848 } 849 si->si_len = htons((u_short)len); 850 m->m_pkthdr.len = ((len - 1) | 1) + 1; 851 /* 852 * queue stuff up for output 853 */ 854 sbappendrecord(sb, m); 855 cb->s_seq++; 856 } 857#ifdef notdef 858 idle = (cb->s_smax == (cb->s_rack - 1)); 859#endif 860again: 861 sendalot = 0; 862 off = cb->s_snxt - cb->s_rack; 863 win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)); 864 865 /* 866 * If in persist timeout with window of 0, send a probe. 867 * Otherwise, if window is small but nonzero 868 * and timer expired, send what we can and go into 869 * transmit state. 870 */ 871 if (cb->s_force == 1 + SPXT_PERSIST) { 872 if (win != 0) { 873 cb->s_timer[SPXT_PERSIST] = 0; 874 cb->s_rxtshift = 0; 875 } 876 } 877 span = cb->s_seq - cb->s_rack; 878 len = min(span, win) - off; 879 880 if (len < 0) { 881 /* 882 * Window shrank after we went into it. 883 * If window shrank to 0, cancel pending 884 * restransmission and pull s_snxt back 885 * to (closed) window. We will enter persist 886 * state below. If the widndow didn't close completely, 887 * just wait for an ACK. 888 */ 889 len = 0; 890 if (win == 0) { 891 cb->s_timer[SPXT_REXMT] = 0; 892 cb->s_snxt = cb->s_rack; 893 } 894 } 895 if (len > 1) 896 sendalot = 1; 897 rcv_win = sbspace(&so->so_rcv); 898 899 /* 900 * Send if we owe peer an ACK. 901 */ 902 if (cb->s_oobflags & SF_SOOB) { 903 /* 904 * must transmit this out of band packet 905 */ 906 cb->s_oobflags &= ~ SF_SOOB; 907 sendalot = 1; 908 spxstat.spxs_sndurg++; 909 goto found; 910 } 911 if (cb->s_flags & SF_ACKNOW) 912 goto send; 913 if (cb->s_state < TCPS_ESTABLISHED) 914 goto send; 915 /* 916 * Silly window can't happen in spx. 917 * Code from tcp deleted. 918 */ 919 if (len) 920 goto send; 921 /* 922 * Compare available window to amount of window 923 * known to peer (as advertised window less 924 * next expected input.) If the difference is at least two 925 * packets or at least 35% of the mximum possible window, 926 * then want to send a window update to peer. 927 */ 928 if (rcv_win > 0) { 929 u_short delta = 1 + cb->s_alo - cb->s_ack; 930 int adv = rcv_win - (delta * cb->s_mtu); 931 932 if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || 933 (100 * adv / so->so_rcv.sb_hiwat >= 35)) { 934 spxstat.spxs_sndwinup++; 935 cb->s_flags |= SF_ACKNOW; 936 goto send; 937 } 938 939 } 940 /* 941 * Many comments from tcp_output.c are appropriate here 942 * including . . . 943 * If send window is too small, there is data to transmit, and no 944 * retransmit or persist is pending, then go to persist state. 945 * If nothing happens soon, send when timer expires: 946 * if window is nonzero, transmit what we can, 947 * otherwise send a probe. 948 */ 949 if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 && 950 cb->s_timer[SPXT_PERSIST] == 0) { 951 cb->s_rxtshift = 0; 952 spx_setpersist(cb); 953 } 954 /* 955 * No reason to send a packet, just return. 956 */ 957 cb->s_outx = 1; 958 return (0); 959 960send: 961 /* 962 * Find requested packet. 963 */ 964 si = 0; 965 if (len > 0) { 966 cb->s_want = cb->s_snxt; 967 for (m = sb->sb_mb; m; m = m->m_act) { 968 si = mtod(m, struct spx *); 969 if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) 970 break; 971 } 972 found: 973 if (si) { 974 if (si->si_seq == cb->s_snxt) 975 cb->s_snxt++; 976 else 977 spxstat.spxs_sndvoid++, si = 0; 978 } 979 } 980 /* 981 * update window 982 */ 983 if (rcv_win < 0) 984 rcv_win = 0; 985 alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); 986 if (SSEQ_LT(alo, cb->s_alo)) 987 alo = cb->s_alo; 988 989 if (si) { 990 /* 991 * must make a copy of this packet for 992 * ipx_output to monkey with 993 */ 994 m = m_copy(dtom(si), 0, (int)M_COPYALL); 995 if (m == NULL) { 996 return (ENOBUFS); 997 } 998 si = mtod(m, struct spx *); 999 if (SSEQ_LT(si->si_seq, cb->s_smax)) 1000 spxstat.spxs_sndrexmitpack++; 1001 else 1002 spxstat.spxs_sndpack++; 1003 } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { 1004 /* 1005 * Must send an acknowledgement or a probe 1006 */ 1007 if (cb->s_force) 1008 spxstat.spxs_sndprobe++; 1009 if (cb->s_flags & SF_ACKNOW) 1010 spxstat.spxs_sndacks++; 1011 m = m_gethdr(M_DONTWAIT, MT_HEADER); 1012 if (m == 0) 1013 return (ENOBUFS); 1014 /* 1015 * Fill in mbuf with extended SP header 1016 * and addresses and length put into network format. 1017 */ 1018 MH_ALIGN(m, sizeof (struct spx)); 1019 m->m_len = sizeof (*si); 1020 m->m_pkthdr.len = sizeof (*si); 1021 si = mtod(m, struct spx *); 1022 si->si_i = *cb->s_ipx; 1023 si->si_s = cb->s_shdr; 1024 si->si_seq = cb->s_smax + 1; 1025 si->si_len = htons(sizeof (*si)); 1026 si->si_cc |= SPX_SP; 1027 } else { 1028 cb->s_outx = 3; 1029 if (so->so_options & SO_DEBUG || traceallspxs) 1030 spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 1031 return (0); 1032 } 1033 /* 1034 * Stuff checksum and output datagram. 1035 */ 1036 if ((si->si_cc & SPX_SP) == 0) { 1037 if (cb->s_force != (1 + SPXT_PERSIST) || 1038 cb->s_timer[SPXT_PERSIST] == 0) { 1039 /* 1040 * If this is a new packet and we are not currently 1041 * timing anything, time this one. 1042 */ 1043 if (SSEQ_LT(cb->s_smax, si->si_seq)) { 1044 cb->s_smax = si->si_seq; 1045 if (cb->s_rtt == 0) { 1046 spxstat.spxs_segstimed++; 1047 cb->s_rtseq = si->si_seq; 1048 cb->s_rtt = 1; 1049 } 1050 } 1051 /* 1052 * Set rexmt timer if not currently set, 1053 * Initial value for retransmit timer is smoothed 1054 * round-trip time + 2 * round-trip time variance. 1055 * Initialize shift counter which is used for backoff 1056 * of retransmit time. 1057 */ 1058 if (cb->s_timer[SPXT_REXMT] == 0 && 1059 cb->s_snxt != cb->s_rack) { 1060 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 1061 if (cb->s_timer[SPXT_PERSIST]) { 1062 cb->s_timer[SPXT_PERSIST] = 0; 1063 cb->s_rxtshift = 0; 1064 } 1065 } 1066 } else if (SSEQ_LT(cb->s_smax, si->si_seq)) { 1067 cb->s_smax = si->si_seq; 1068 } 1069 } else if (cb->s_state < TCPS_ESTABLISHED) { 1070 if (cb->s_rtt == 0) 1071 cb->s_rtt = 1; /* Time initial handshake */ 1072 if (cb->s_timer[SPXT_REXMT] == 0) 1073 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 1074 } 1075 { 1076 /* 1077 * Do not request acks when we ack their data packets or 1078 * when we do a gratuitous window update. 1079 */ 1080 if (((si->si_cc & SPX_SP) == 0) || cb->s_force) 1081 si->si_cc |= SPX_SA; 1082 si->si_seq = htons(si->si_seq); 1083 si->si_alo = htons(alo); 1084 si->si_ack = htons(cb->s_ack); 1085 1086 if (ipxcksum) { 1087 si->si_sum = 0; 1088 len = ntohs(si->si_len); 1089 if (len & 1) 1090 len++; 1091 si->si_sum = ipx_cksum(m, len); 1092 } else 1093 si->si_sum = 0xffff; 1094 1095 cb->s_outx = 4; 1096 if (so->so_options & SO_DEBUG || traceallspxs) 1097 spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 1098 1099 if (so->so_options & SO_DONTROUTE) 1100 error = ipx_outputfl(m, (struct route *)0, IPX_ROUTETOIF); 1101 else 1102 error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0); 1103 } 1104 if (error) { 1105 return (error); 1106 } 1107 spxstat.spxs_sndtotal++; 1108 /* 1109 * Data sent (as far as we can tell). 1110 * If this advertises a larger window than any other segment, 1111 * then remember the size of the advertized window. 1112 * Any pending ACK has now been sent. 1113 */ 1114 cb->s_force = 0; 1115 cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); 1116 if (SSEQ_GT(alo, cb->s_alo)) 1117 cb->s_alo = alo; 1118 if (sendalot) 1119 goto again; 1120 cb->s_outx = 5; 1121 return (0); 1122} 1123 1124int spx_do_persist_panics = 0; 1125 1126void 1127spx_setpersist(cb) 1128 register struct spxpcb *cb; 1129{ 1130 register t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 1131 1132 if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics) 1133 panic("spx_output REXMT"); 1134 /* 1135 * Start/restart persistance timer. 1136 */ 1137 SPXT_RANGESET(cb->s_timer[SPXT_PERSIST], 1138 t*spx_backoff[cb->s_rxtshift], 1139 SPXTV_PERSMIN, SPXTV_PERSMAX); 1140 if (cb->s_rxtshift < SPX_MAXRXTSHIFT) 1141 cb->s_rxtshift++; 1142} 1143/*ARGSUSED*/ 1144int 1145spx_ctloutput(req, so, level, name, value) 1146 int req; 1147 struct socket *so; 1148 int level, name; 1149 struct mbuf **value; 1150{ 1151 register struct mbuf *m; 1152 struct ipxpcb *ipxp = sotoipxpcb(so); 1153 register struct spxpcb *cb; 1154 int mask, error = 0; 1155 1156 if (level != IPXPROTO_SPX) { 1157 /* This will have to be changed when we do more general 1158 stacking of protocols */ 1159 return (ipx_ctloutput(req, so, level, name, value)); 1160 } 1161 if (ipxp == NULL) { 1162 error = EINVAL; 1163 goto release; 1164 } else 1165 cb = ipxtospxpcb(ipxp); 1166 1167 switch (req) { 1168 1169 case PRCO_GETOPT: 1170 if (value == NULL) 1171 return (EINVAL); 1172 m = m_get(M_DONTWAIT, MT_DATA); 1173 if (m == NULL) 1174 return (ENOBUFS); 1175 switch (name) { 1176 1177 case SO_HEADERS_ON_INPUT: 1178 mask = SF_HI; 1179 goto get_flags; 1180 1181 case SO_HEADERS_ON_OUTPUT: 1182 mask = SF_HO; 1183 get_flags: 1184 m->m_len = sizeof(short); 1185 *mtod(m, short *) = cb->s_flags & mask; 1186 break; 1187 1188 case SO_MTU: 1189 m->m_len = sizeof(u_short); 1190 *mtod(m, short *) = cb->s_mtu; 1191 break; 1192 1193 case SO_LAST_HEADER: 1194 m->m_len = sizeof(struct spxhdr); 1195 *mtod(m, struct spxhdr *) = cb->s_rhdr; 1196 break; 1197 1198 case SO_DEFAULT_HEADERS: 1199 m->m_len = sizeof(struct spx); 1200 *mtod(m, struct spxhdr *) = cb->s_shdr; 1201 break; 1202 1203 default: 1204 error = EINVAL; 1205 } 1206 *value = m; 1207 break; 1208 1209 case PRCO_SETOPT: 1210 if (value == 0 || *value == 0) { 1211 error = EINVAL; 1212 break; 1213 } 1214 switch (name) { 1215 int *ok; 1216 1217 case SO_HEADERS_ON_INPUT: 1218 mask = SF_HI; 1219 goto set_head; 1220 1221 case SO_HEADERS_ON_OUTPUT: 1222 mask = SF_HO; 1223 set_head: 1224 if (cb->s_flags & SF_PI) { 1225 ok = mtod(*value, int *); 1226 if (*ok) 1227 cb->s_flags |= mask; 1228 else 1229 cb->s_flags &= ~mask; 1230 } else error = EINVAL; 1231 break; 1232 1233 case SO_MTU: 1234 cb->s_mtu = *(mtod(*value, u_short *)); 1235 break; 1236 1237#ifdef SF_NEWCALL 1238 case SO_NEWCALL: 1239 ok = mtod(*value, int *); 1240 if (*ok) { 1241 cb->s_flags2 |= SF_NEWCALL; 1242 spx_newchecks[5]++; 1243 } else { 1244 cb->s_flags2 &= ~SF_NEWCALL; 1245 spx_newchecks[6]++; 1246 } 1247 break; 1248#endif 1249 1250 case SO_DEFAULT_HEADERS: 1251 { 1252 register struct spxhdr *sp 1253 = mtod(*value, struct spxhdr *); 1254 cb->s_dt = sp->spx_dt; 1255 cb->s_cc = sp->spx_cc & SPX_EM; 1256 } 1257 break; 1258 1259 default: 1260 error = EINVAL; 1261 } 1262 m_freem(*value); 1263 break; 1264 } 1265 release: 1266 return (error); 1267} 1268 1269/*ARGSUSED*/ 1270int 1271spx_usrreq(so, req, m, nam, controlp) 1272 struct socket *so; 1273 int req; 1274 struct mbuf *m, *nam, *controlp; 1275{ 1276 struct ipxpcb *ipxp = sotoipxpcb(so); 1277 register struct spxpcb *cb = NULL; 1278 int s = splnet(); 1279 int error = 0, ostate; 1280 struct mbuf *mm; 1281 register struct sockbuf *sb; 1282 1283 if (req == PRU_CONTROL) 1284 return (ipx_control(so, (int)m, (caddr_t)nam, 1285 (struct ifnet *)controlp)); 1286 if (ipxp == NULL) { 1287 if (req != PRU_ATTACH) { 1288 error = EINVAL; 1289 goto release; 1290 } 1291 } else 1292 cb = ipxtospxpcb(ipxp); 1293 1294 ostate = cb ? cb->s_state : 0; 1295 1296 switch (req) { 1297 1298 case PRU_ATTACH: 1299 if (ipxp != NULL) { 1300 error = EISCONN; 1301 break; 1302 } 1303 error = ipx_pcballoc(so, &ipxpcb); 1304 if (error) 1305 break; 1306 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 1307 error = soreserve(so, (u_long) 3072, (u_long) 3072); 1308 if (error) 1309 break; 1310 } 1311 ipxp = sotoipxpcb(so); 1312 1313 mm = m_getclr(M_DONTWAIT, MT_PCB); 1314 sb = &so->so_snd; 1315 1316 if (mm == NULL) { 1317 error = ENOBUFS; 1318 break; 1319 } 1320 cb = mtod(mm, struct spxpcb *); 1321 mm = m_getclr(M_DONTWAIT, MT_HEADER); 1322 if (mm == NULL) { 1323 (void) m_free(dtom(m)); 1324 error = ENOBUFS; 1325 break; 1326 } 1327 cb->s_ipx = mtod(mm, struct ipx *); 1328 cb->s_state = TCPS_LISTEN; 1329 cb->s_smax = -1; 1330 cb->s_swl1 = -1; 1331 cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 1332 cb->s_ipxpcb = ipxp; 1333 cb->s_mtu = 576 - sizeof (struct spx); 1334 cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; 1335 cb->s_ssthresh = cb->s_cwnd; 1336 cb->s_cwmx = sbspace(sb) * CUNIT / 1337 (2 * sizeof (struct spx)); 1338 /* Above is recomputed when connecting to account 1339 for changed buffering or mtu's */ 1340 cb->s_rtt = SPXTV_SRTTBASE; 1341 cb->s_rttvar = SPXTV_SRTTDFLT << 2; 1342 SPXT_RANGESET(cb->s_rxtcur, 1343 ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1, 1344 SPXTV_MIN, SPXTV_REXMTMAX); 1345 ipxp->ipxp_pcb = (caddr_t) cb; 1346 break; 1347 1348 case PRU_DETACH: 1349 if (ipxp == NULL) { 1350 error = ENOTCONN; 1351 break; 1352 } 1353 if (cb->s_state > TCPS_LISTEN) 1354 cb = spx_disconnect(cb); 1355 else 1356 cb = spx_close(cb); 1357 break; 1358 1359 case PRU_BIND: 1360 error = ipx_pcbbind(ipxp, nam); 1361 break; 1362 1363 case PRU_LISTEN: 1364 if (ipxp->ipxp_lport == 0) 1365 error = ipx_pcbbind(ipxp, (struct mbuf *)0); 1366 if (error == 0) 1367 cb->s_state = TCPS_LISTEN; 1368 break; 1369 1370 /* 1371 * Initiate connection to peer. 1372 * Enter SYN_SENT state, and mark socket as connecting. 1373 * Start keep-alive timer, setup prototype header, 1374 * Send initial system packet requesting connection. 1375 */ 1376 case PRU_CONNECT: 1377 if (ipxp->ipxp_lport == 0) { 1378 error = ipx_pcbbind(ipxp, (struct mbuf *)0); 1379 if (error) 1380 break; 1381 } 1382 error = ipx_pcbconnect(ipxp, nam); 1383 if (error) 1384 break; 1385 soisconnecting(so); 1386 spxstat.spxs_connattempt++; 1387 cb->s_state = TCPS_SYN_SENT; 1388 cb->s_did = 0; 1389 spx_template(cb); 1390 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 1391 cb->s_force = 1 + SPXTV_KEEP; 1392 /* 1393 * Other party is required to respond to 1394 * the port I send from, but he is not 1395 * required to answer from where I am sending to, 1396 * so allow wildcarding. 1397 * original port I am sending to is still saved in 1398 * cb->s_dport. 1399 */ 1400 ipxp->ipxp_fport = 0; 1401 error = spx_output(cb, (struct mbuf *) 0); 1402 break; 1403 1404 case PRU_CONNECT2: 1405 error = EOPNOTSUPP; 1406 break; 1407 1408 /* 1409 * We may decide later to implement connection closing 1410 * handshaking at the spx level optionally. 1411 * here is the hook to do it: 1412 */ 1413 case PRU_DISCONNECT: 1414 cb = spx_disconnect(cb); 1415 break; 1416 1417 /* 1418 * Accept a connection. Essentially all the work is 1419 * done at higher levels; just return the address 1420 * of the peer, storing through addr. 1421 */ 1422 case PRU_ACCEPT: { 1423 struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 1424 1425 nam->m_len = sizeof (struct sockaddr_ipx); 1426 sipx->sipx_family = AF_IPX; 1427 sipx->sipx_addr = ipxp->ipxp_faddr; 1428 break; 1429 } 1430 1431 case PRU_SHUTDOWN: 1432 socantsendmore(so); 1433 cb = spx_usrclosed(cb); 1434 if (cb) 1435 error = spx_output(cb, (struct mbuf *) 0); 1436 break; 1437 1438 /* 1439 * After a receive, possibly send acknowledgment 1440 * updating allocation. 1441 */ 1442 case PRU_RCVD: 1443 cb->s_flags |= SF_RVD; 1444 (void) spx_output(cb, (struct mbuf *) 0); 1445 cb->s_flags &= ~SF_RVD; 1446 break; 1447 1448 case PRU_ABORT: 1449 (void) spx_drop(cb, ECONNABORTED); 1450 break; 1451 1452 case PRU_SENSE: 1453 case PRU_CONTROL: 1454 m = NULL; 1455 error = EOPNOTSUPP; 1456 break; 1457 1458 case PRU_RCVOOB: 1459 if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 1460 (so->so_state & SS_RCVATMARK)) { 1461 m->m_len = 1; 1462 *mtod(m, caddr_t) = cb->s_iobc; 1463 break; 1464 } 1465 error = EINVAL; 1466 break; 1467 1468 case PRU_SENDOOB: 1469 if (sbspace(&so->so_snd) < -512) { 1470 error = ENOBUFS; 1471 break; 1472 } 1473 cb->s_oobflags |= SF_SOOB; 1474 /* fall into */ 1475 case PRU_SEND: 1476 if (controlp) { 1477 u_short *p = mtod(controlp, u_short *); 1478 spx_newchecks[2]++; 1479 if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */ 1480 cb->s_shdr.spx_dt = *(u_char *)(&p[2]); 1481 spx_newchecks[3]++; 1482 } 1483 m_freem(controlp); 1484 } 1485 controlp = NULL; 1486 error = spx_output(cb, m); 1487 m = NULL; 1488 break; 1489 1490 case PRU_SOCKADDR: 1491 ipx_setsockaddr(ipxp, nam); 1492 break; 1493 1494 case PRU_PEERADDR: 1495 ipx_setpeeraddr(ipxp, nam); 1496 break; 1497 1498 case PRU_SLOWTIMO: 1499 cb = spx_timers(cb, (int)nam); 1500 req |= ((int)nam) << 8; 1501 break; 1502 1503 case PRU_FASTTIMO: 1504 case PRU_PROTORCV: 1505 case PRU_PROTOSEND: 1506 error = EOPNOTSUPP; 1507 break; 1508 1509 default: 1510 panic("spx_usrreq"); 1511 } 1512 if (cb && (so->so_options & SO_DEBUG || traceallspxs)) 1513 spx_trace(SA_USER, (u_char)ostate, cb, (struct spx *)0, req); 1514release: 1515 if (controlp != NULL) 1516 m_freem(controlp); 1517 if (m != NULL) 1518 m_freem(m); 1519 splx(s); 1520 return (error); 1521} 1522 1523int 1524spx_usrreq_sp(so, req, m, nam, controlp) 1525 struct socket *so; 1526 int req; 1527 struct mbuf *m, *nam, *controlp; 1528{ 1529 int error = spx_usrreq(so, req, m, nam, controlp); 1530 1531 if (req == PRU_ATTACH && error == 0) { 1532 struct ipxpcb *ipxp = sotoipxpcb(so); 1533 ((struct spxpcb *)ipxp->ipxp_pcb)->s_flags |= 1534 (SF_HI | SF_HO | SF_PI); 1535 } 1536 return (error); 1537} 1538 1539/* 1540 * Create template to be used to send spx packets on a connection. 1541 * Called after host entry created, fills 1542 * in a skeletal spx header (choosing connection id), 1543 * minimizing the amount of work necessary when the connection is used. 1544 */ 1545void 1546spx_template(cb) 1547 register struct spxpcb *cb; 1548{ 1549 register struct ipxpcb *ipxp = cb->s_ipxpcb; 1550 register struct ipx *ipx = cb->s_ipx; 1551 register struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd); 1552 1553 ipx->ipx_pt = IPXPROTO_SPX; 1554 ipx->ipx_sna = ipxp->ipxp_laddr; 1555 ipx->ipx_dna = ipxp->ipxp_faddr; 1556 cb->s_sid = htons(spx_iss); 1557 spx_iss += SPX_ISSINCR/2; 1558 cb->s_alo = 1; 1559 cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; 1560 cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement 1561 of large packets */ 1562 cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx)); 1563 cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); 1564 /* But allow for lots of little packets as well */ 1565} 1566 1567/* 1568 * Close a SPIP control block: 1569 * discard spx control block itself 1570 * discard ipx protocol control block 1571 * wake up any sleepers 1572 */ 1573struct spxpcb * 1574spx_close(cb) 1575 register struct spxpcb *cb; 1576{ 1577 register struct spx_q *s; 1578 struct ipxpcb *ipxp = cb->s_ipxpcb; 1579 struct socket *so = ipxp->ipxp_socket; 1580 register struct mbuf *m; 1581 1582 s = cb->s_q.si_next; 1583 while (s != &(cb->s_q)) { 1584 s = s->si_next; 1585 m = dtom(s->si_prev); 1586 remque(s->si_prev); 1587 m_freem(m); 1588 } 1589 (void) m_free(dtom(cb->s_ipx)); 1590 (void) m_free(dtom(cb)); 1591 ipxp->ipxp_pcb = 0; 1592 soisdisconnected(so); 1593 ipx_pcbdetach(ipxp); 1594 spxstat.spxs_closed++; 1595 return ((struct spxpcb *)0); 1596} 1597/* 1598 * Someday we may do level 3 handshaking 1599 * to close a connection or send a xerox style error. 1600 * For now, just close. 1601 */ 1602struct spxpcb * 1603spx_usrclosed(cb) 1604 register struct spxpcb *cb; 1605{ 1606 return (spx_close(cb)); 1607} 1608struct spxpcb * 1609spx_disconnect(cb) 1610 register struct spxpcb *cb; 1611{ 1612 return (spx_close(cb)); 1613} 1614/* 1615 * Drop connection, reporting 1616 * the specified error. 1617 */ 1618struct spxpcb * 1619spx_drop(cb, errno) 1620 register struct spxpcb *cb; 1621 int errno; 1622{ 1623 struct socket *so = cb->s_ipxpcb->ipxp_socket; 1624 1625 /* 1626 * someday, in the xerox world 1627 * we will generate error protocol packets 1628 * announcing that the socket has gone away. 1629 */ 1630 if (TCPS_HAVERCVDSYN(cb->s_state)) { 1631 spxstat.spxs_drops++; 1632 cb->s_state = TCPS_CLOSED; 1633 /*(void) tcp_output(cb);*/ 1634 } else 1635 spxstat.spxs_conndrops++; 1636 so->so_error = errno; 1637 return (spx_close(cb)); 1638} 1639 1640void 1641spx_abort(ipxp) 1642 struct ipxpcb *ipxp; 1643{ 1644 1645 (void) spx_close((struct spxpcb *)ipxp->ipxp_pcb); 1646} 1647 1648int spx_backoff[SPX_MAXRXTSHIFT+1] = 1649 { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 1650/* 1651 * Fast timeout routine for processing delayed acks 1652 */ 1653void 1654spx_fasttimo() 1655{ 1656 register struct ipxpcb *ipxp; 1657 register struct spxpcb *cb; 1658 int s = splnet(); 1659 1660 ipxp = ipxpcb.ipxp_next; 1661 if (ipxp) 1662 for (; ipxp != &ipxpcb; ipxp = ipxp->ipxp_next) 1663 if ((cb = (struct spxpcb *)ipxp->ipxp_pcb) && 1664 (cb->s_flags & SF_DELACK)) { 1665 cb->s_flags &= ~SF_DELACK; 1666 cb->s_flags |= SF_ACKNOW; 1667 spxstat.spxs_delack++; 1668 (void) spx_output(cb, (struct mbuf *) 0); 1669 } 1670 splx(s); 1671} 1672 1673/* 1674 * spx protocol timeout routine called every 500 ms. 1675 * Updates the timers in all active pcb's and 1676 * causes finite state machine actions if timers expire. 1677 */ 1678void 1679spx_slowtimo() 1680{ 1681 register struct ipxpcb *ip, *ipnxt; 1682 register struct spxpcb *cb; 1683 int s = splnet(); 1684 register int i; 1685 1686 /* 1687 * Search through tcb's and update active timers. 1688 */ 1689 ip = ipxpcb.ipxp_next; 1690 if (ip == 0) { 1691 splx(s); 1692 return; 1693 } 1694 while (ip != &ipxpcb) { 1695 cb = ipxtospxpcb(ip); 1696 ipnxt = ip->ipxp_next; 1697 if (cb == 0) 1698 goto tpgone; 1699 for (i = 0; i < SPXT_NTIMERS; i++) { 1700 if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 1701 (void) spx_usrreq(cb->s_ipxpcb->ipxp_socket, 1702 PRU_SLOWTIMO, (struct mbuf *)0, 1703 (struct mbuf *)i, (struct mbuf *)0); 1704 if (ipnxt->ipxp_prev != ip) 1705 goto tpgone; 1706 } 1707 } 1708 cb->s_idle++; 1709 if (cb->s_rtt) 1710 cb->s_rtt++; 1711tpgone: 1712 ip = ipnxt; 1713 } 1714 spx_iss += SPX_ISSINCR/PR_SLOWHZ; /* increment iss */ 1715 splx(s); 1716} 1717/* 1718 * SPX timer processing. 1719 */ 1720struct spxpcb * 1721spx_timers(cb, timer) 1722 register struct spxpcb *cb; 1723 int timer; 1724{ 1725 long rexmt; 1726 int win; 1727 1728 cb->s_force = 1 + timer; 1729 switch (timer) { 1730 1731 /* 1732 * 2 MSL timeout in shutdown went off. TCP deletes connection 1733 * control block. 1734 */ 1735 case SPXT_2MSL: 1736 printf("spx: SPXT_2MSL went off for no reason\n"); 1737 cb->s_timer[timer] = 0; 1738 break; 1739 1740 /* 1741 * Retransmission timer went off. Message has not 1742 * been acked within retransmit interval. Back off 1743 * to a longer retransmit interval and retransmit one packet. 1744 */ 1745 case SPXT_REXMT: 1746 if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) { 1747 cb->s_rxtshift = SPX_MAXRXTSHIFT; 1748 spxstat.spxs_timeoutdrop++; 1749 cb = spx_drop(cb, ETIMEDOUT); 1750 break; 1751 } 1752 spxstat.spxs_rexmttimeo++; 1753 rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 1754 rexmt *= spx_backoff[cb->s_rxtshift]; 1755 SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX); 1756 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 1757 /* 1758 * If we have backed off fairly far, our srtt 1759 * estimate is probably bogus. Clobber it 1760 * so we'll take the next rtt measurement as our srtt; 1761 * move the current srtt into rttvar to keep the current 1762 * retransmit times until then. 1763 */ 1764 if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) { 1765 cb->s_rttvar += (cb->s_srtt >> 2); 1766 cb->s_srtt = 0; 1767 } 1768 cb->s_snxt = cb->s_rack; 1769 /* 1770 * If timing a packet, stop the timer. 1771 */ 1772 cb->s_rtt = 0; 1773 /* 1774 * See very long discussion in tcp_timer.c about congestion 1775 * window and sstrhesh 1776 */ 1777 win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; 1778 if (win < 2) 1779 win = 2; 1780 cb->s_cwnd = CUNIT; 1781 cb->s_ssthresh = win * CUNIT; 1782 (void) spx_output(cb, (struct mbuf *) 0); 1783 break; 1784 1785 /* 1786 * Persistance timer into zero window. 1787 * Force a probe to be sent. 1788 */ 1789 case SPXT_PERSIST: 1790 spxstat.spxs_persisttimeo++; 1791 spx_setpersist(cb); 1792 (void) spx_output(cb, (struct mbuf *) 0); 1793 break; 1794 1795 /* 1796 * Keep-alive timer went off; send something 1797 * or drop connection if idle for too long. 1798 */ 1799 case SPXT_KEEP: 1800 spxstat.spxs_keeptimeo++; 1801 if (cb->s_state < TCPS_ESTABLISHED) 1802 goto dropit; 1803 if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) { 1804 if (cb->s_idle >= SPXTV_MAXIDLE) 1805 goto dropit; 1806 spxstat.spxs_keepprobe++; 1807 (void) spx_output(cb, (struct mbuf *) 0); 1808 } else 1809 cb->s_idle = 0; 1810 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 1811 break; 1812 dropit: 1813 spxstat.spxs_keepdrops++; 1814 cb = spx_drop(cb, ETIMEDOUT); 1815 break; 1816 } 1817 return (cb); 1818} 1819