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