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