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