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