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