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