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