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