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