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