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