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