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