1 /* 2 * Copyright (c) 1984, 1985, 1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)spp_usrreq.c 7.2 (Berkeley) 10/28/86 7 */ 8 9 #include "param.h" 10 #include "systm.h" 11 #include "dir.h" 12 #include "user.h" 13 #include "mbuf.h" 14 #include "protosw.h" 15 #include "socket.h" 16 #include "socketvar.h" 17 #include "errno.h" 18 19 #include "../net/if.h" 20 #include "../net/route.h" 21 #include "../netinet/tcp_fsm.h" 22 #include "../netinet/tcp_timer.h" 23 24 #include "ns.h" 25 #include "ns_pcb.h" 26 #include "idp.h" 27 #include "idp_var.h" 28 #include "ns_error.h" 29 #include "sp.h" 30 #include "spidp.h" 31 #include "spp_var.h" 32 #include "spp_debug.h" 33 34 /* 35 * SP protocol implementation. 36 */ 37 spp_init() 38 { 39 40 spp_iss = 1; /* WRONG !! should fish it out of TODR */ 41 } 42 struct spidp spp_savesi; 43 int traceallspps = 0; 44 extern int sppconsdebug; 45 int spp_hardnosed; 46 int spp_use_delack = 0; 47 48 /*ARGSUSED*/ 49 spp_input(m, nsp, ifp) 50 register struct mbuf *m; 51 register struct nspcb *nsp; 52 struct ifnet *ifp; 53 { 54 register struct sppcb *cb; 55 register struct spidp *si = mtod(m, struct spidp *); 56 register struct socket *so; 57 short ostate; 58 int dropsocket = 0; 59 60 61 if (nsp == 0) { 62 panic("No nspcb in spp_input\n"); 63 return; 64 } 65 66 cb = nstosppcb(nsp); 67 if (cb == 0) goto bad; 68 69 if (m->m_len < sizeof(*si)) { 70 if ((m = m_pullup(m, sizeof(*si))) == 0) { 71 spp_istat.hdrops++; 72 return; 73 } 74 si = mtod(m, struct spidp *); 75 } 76 si->si_seq = ntohs(si->si_seq); 77 si->si_ack = ntohs(si->si_ack); 78 si->si_alo = ntohs(si->si_alo); 79 80 so = nsp->nsp_socket; 81 if (so->so_options & SO_DEBUG || traceallspps) { 82 ostate = cb->s_state; 83 spp_savesi = *si; 84 } 85 if (so->so_options & SO_ACCEPTCONN) { 86 so = sonewconn(so); 87 if (so == 0) { 88 spp_istat.nonucn++; 89 goto drop; 90 } 91 /* 92 * This is ugly, but .... 93 * 94 * Mark socket as temporary until we're 95 * committed to keeping it. The code at 96 * ``drop'' and ``dropwithreset'' check the 97 * flag dropsocket to see if the temporary 98 * socket created here should be discarded. 99 * We mark the socket as discardable until 100 * we're committed to it below in TCPS_LISTEN. 101 */ 102 dropsocket++; 103 nsp = (struct nspcb *)so->so_pcb; 104 nsp->nsp_laddr = si->si_dna; 105 cb = nstosppcb(nsp); 106 cb->s_state = TCPS_LISTEN; 107 } 108 109 /* 110 * Packet received on connection. 111 * reset idle time and keep-alive timer; 112 */ 113 cb->s_idle = 0; 114 cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 115 116 switch (cb->s_state) { 117 118 case TCPS_LISTEN:{ 119 struct mbuf *am; 120 register struct sockaddr_ns *sns; 121 struct ns_addr laddr; 122 123 /* 124 * If somebody here was carying on a conversation 125 * and went away, and his pen pal thinks he can 126 * still talk, we get the misdirected packet. 127 */ 128 if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 129 spp_istat.gonawy++; 130 goto dropwithreset; 131 } 132 am = m_get(M_DONTWAIT, MT_SONAME); 133 if (am == NULL) 134 goto drop; 135 am->m_len = sizeof (struct sockaddr_ns); 136 sns = mtod(am, struct sockaddr_ns *); 137 sns->sns_family = AF_NS; 138 sns->sns_addr = si->si_sna; 139 laddr = nsp->nsp_laddr; 140 if (ns_nullhost(laddr)) 141 nsp->nsp_laddr = si->si_dna; 142 if (ns_pcbconnect(nsp, am)) { 143 nsp->nsp_laddr = laddr; 144 (void) m_free(am); 145 spp_istat.noconn++; 146 goto drop; 147 } 148 (void) m_free(am); 149 spp_template(cb); 150 dropsocket = 0; /* committed to socket */ 151 cb->s_did = si->si_sid; 152 cb->s_rack = si->si_ack; 153 cb->s_ralo = si->si_alo; 154 #define THREEWAYSHAKE 155 #ifdef THREEWAYSHAKE 156 cb->s_state = TCPS_SYN_RECEIVED; 157 cb->s_force = 1 + TCPT_REXMT; 158 cb->s_timer[TCPT_REXMT] = 2 * TCPTV_MIN; 159 } 160 break; 161 /* 162 * This state means that we have heard a response 163 * to our acceptance of their connection 164 * It is probably logically unnecessary in this 165 * implementation. 166 */ 167 case TCPS_SYN_RECEIVED: 168 if (si->si_did!=cb->s_sid) { 169 spp_istat.wrncon++; 170 goto drop; 171 } 172 #endif 173 nsp->nsp_fport = si->si_sport; 174 cb->s_timer[TCPT_REXMT] = 0; 175 cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 176 soisconnected(so); 177 cb->s_state = TCPS_ESTABLISHED; 178 break; 179 180 /* 181 * This state means that we have gotten a response 182 * to our attempt to establish a connection. 183 * We fill in the data from the other side, 184 * telling us which port to respond to, instead of the well- 185 * known one we might have sent to in the first place. 186 * We also require that this is a response to our 187 * connection id. 188 */ 189 case TCPS_SYN_SENT: 190 if (si->si_did!=cb->s_sid) { 191 spp_istat.notme++; 192 goto drop; 193 } 194 cb->s_did = si->si_sid; 195 cb->s_rack = si->si_ack; 196 cb->s_ralo = si->si_alo; 197 cb->s_dport = nsp->nsp_fport = si->si_sport; 198 cb->s_timer[TCPT_REXMT] = 0; 199 cb->s_flags |= SF_AK; 200 soisconnected(so); 201 cb->s_state = TCPS_ESTABLISHED; 202 } 203 if (so->so_options & SO_DEBUG || traceallspps) 204 spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0); 205 206 m->m_len -= sizeof (struct idp); 207 m->m_off += sizeof (struct idp); 208 209 if (spp_reass(cb, si)) { 210 m_freem(m); 211 } 212 (void) spp_output(cb, (struct mbuf *)0); 213 return; 214 215 dropwithreset: 216 if (dropsocket) 217 (void) soabort(so); 218 si->si_seq = ntohs(si->si_seq); 219 si->si_ack = ntohs(si->si_ack); 220 si->si_alo = ntohs(si->si_alo); 221 ns_error(dtom(si), NS_ERR_NOSOCK, 0); 222 if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 223 spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 224 return; 225 226 drop: 227 bad: 228 if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 229 spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 230 m_freem(m); 231 } 232 233 /* 234 * This is structurally similar to the tcp reassembly routine 235 * but its function is somewhat different: It merely queues 236 * packets up, and suppresses duplicates. 237 */ 238 spp_reass(cb, si) 239 register struct sppcb *cb; 240 register struct spidp *si; 241 { 242 register struct spidp_q *q; 243 register struct mbuf *m; 244 struct socket *so = cb->s_nspcb->nsp_socket; 245 struct sockbuf *sb = & (so->so_rcv); 246 char packetp = cb->s_flags & SF_HI; 247 char wakeup = 0; 248 249 250 if (si == SI(0)) 251 goto present; 252 /* 253 * Update our news from them. 254 */ 255 if (si->si_cc & SP_SA) 256 cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_AK); 257 if (SSEQ_GT(si->si_ack, cb->s_rack)) { 258 cb->s_rack = si->si_ack; 259 /* 260 * If there are other packets outstanding, 261 * restart the timer for them. 262 */ 263 if (SSEQ_GEQ(cb->s_snt, si->si_ack)) { 264 TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 265 tcp_beta * cb->s_srtt, TCPTV_MIN, 266 TCPTV_MAX); 267 cb->s_rxtshift = 0; 268 } else 269 cb->s_timer[TCPT_REXMT] = 0; 270 /* 271 * If transmit timer is running and timed sequence 272 * number was acked, update smoothed round trip time. 273 */ 274 if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 275 if (cb->s_srtt == 0) 276 cb->s_srtt = cb->s_rtt; 277 else 278 cb->s_srtt = 279 tcp_alpha * cb->s_srtt + 280 (1 - tcp_alpha) * cb->s_rtt; 281 cb->s_rtt = 0; 282 } 283 } 284 if (SSEQ_GT(si->si_alo, cb->s_ralo)) { 285 cb->s_ralo = si->si_alo; 286 cb->s_timer[TCPT_PERSIST] = 0; 287 } 288 /* 289 * If this is a system packet, we don't need to 290 * queue it up, and won't update acknowledge # 291 */ 292 if (si->si_cc & SP_SP) { 293 m_freem(dtom(si)); 294 return (0); 295 } 296 297 /* 298 * If this packet number has a sequence number less 299 * than that of the first packet not yet seen coming 300 * from them, this must be a duplicate, so drop. 301 */ 302 if (SSEQ_LT(si->si_seq, cb->s_ack)) { 303 spp_istat.bdreas++; 304 if (si->si_seq == cb->s_ack-1) 305 spp_istat.lstdup++; 306 return (1); 307 } 308 /* 309 * If this packet number is higher than that which 310 * we have allocated refuse it, unless urgent 311 */ 312 if (SSEQ_GT(si->si_seq, cb->s_alo)) { 313 if (si->si_cc & SP_OB) { 314 if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { 315 ns_error(dtom(si), NS_ERR_FULLUP, 0); 316 return (0); 317 } /* else queue this packet; */ 318 } else { 319 spp_istat.notyet++; 320 return (1); 321 } 322 } 323 324 /* 325 * Loop through all packets queued up to insert in 326 * appropriate sequence. 327 */ 328 329 for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 330 if (si->si_seq == SI(q)->si_seq) return (1); /*duplicate */ 331 if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) break; 332 } 333 insque(si, q->si_prev); 334 /* 335 * If this packet is urgent, inform process 336 */ 337 if (si->si_cc & SP_OB) { 338 cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 339 sohasoutofband(so); 340 cb->s_oobflags |= SF_IOOB; 341 } 342 present: 343 #define SPINC sizeof(struct sphdr) 344 /* 345 * Loop through all packets queued up to update acknowledge 346 * number, and present all acknowledged data to user; 347 * If in packet interface mode, show packet headers. 348 */ 349 for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 350 if (SI(q)->si_seq == cb->s_ack) { 351 cb->s_ack++; 352 m = dtom(q); 353 if (SI(q)->si_cc & SP_OB) { 354 cb->s_oobflags &= ~SF_IOOB; 355 if (sb->sb_cc) 356 so->so_oobmark = sb->sb_cc; 357 else 358 so->so_state |= SS_RCVATMARK; 359 } 360 q = q->si_prev; 361 remque(q->si_next); 362 wakeup = 1; 363 if (packetp) { 364 sbappendrecord(sb, m); 365 } else { 366 cb->s_rhdr = *mtod(m, struct sphdr *); 367 m->m_off += SPINC; 368 m->m_len -= SPINC; 369 sbappend(sb, m); 370 } 371 } else 372 break; 373 } 374 if (wakeup) sorwakeup(so); 375 return (0); 376 } 377 378 spp_ctlinput(cmd, arg) 379 int cmd; 380 caddr_t arg; 381 { 382 struct ns_addr *na; 383 extern u_char nsctlerrmap[]; 384 extern spp_abort(); 385 extern struct nspcb *idp_drop(); 386 struct ns_errp *errp; 387 struct nspcb *nsp; 388 struct sockaddr_ns *sns; 389 int type; 390 391 if (cmd < 0 || cmd > PRC_NCMDS) 392 return; 393 type = NS_ERR_UNREACH_HOST; 394 395 switch (cmd) { 396 397 case PRC_ROUTEDEAD: 398 case PRC_QUENCH: 399 break; 400 401 case PRC_IFDOWN: 402 case PRC_HOSTDEAD: 403 case PRC_HOSTUNREACH: 404 sns = (struct sockaddr_ns *)arg; 405 if (sns->sns_family != AF_NS) 406 return; 407 na = &sns->sns_addr; 408 break; 409 410 default: 411 errp = (struct ns_errp *)arg; 412 na = &errp->ns_err_idp.idp_dna; 413 type = errp->ns_err_num; 414 type = ntohs((u_short)type); 415 } 416 switch (type) { 417 418 case NS_ERR_UNREACH_HOST: 419 ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0); 420 break; 421 422 case NS_ERR_TOO_BIG: 423 case NS_ERR_NOSOCK: 424 nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port, 425 NS_WILDCARD); 426 if (nsp) { 427 if(nsp->nsp_pcb) 428 (void) spp_drop((struct sppcb *)nsp->nsp_pcb, 429 (int)nsctlerrmap[cmd]); 430 else 431 (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); 432 } 433 } 434 } 435 436 #ifdef notdef 437 int 438 spp_fixmtu(nsp) 439 register struct nspcb *nsp; 440 { 441 register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); 442 register struct mbuf *m; 443 register struct spidp *si; 444 struct ns_errp *ep; 445 struct sockbuf *sb; 446 int badseq, len; 447 struct mbuf *firstbad, *m0; 448 449 if (cb) { 450 /* 451 * The notification that we have sent 452 * too much is bad news -- we will 453 * have to go through queued up so far 454 * splitting ones which are too big and 455 * reassigning sequence numbers and checksums. 456 * we should then retransmit all packets from 457 * one above the offending packet to the last one 458 * we had sent (or our allocation) 459 * then the offending one so that the any queued 460 * data at our destination will be discarded. 461 */ 462 ep = (struct ns_errp *)nsp->nsp_notify_param; 463 sb = &nsp->nsp_socket->so_snd; 464 cb->s_mtu = ep->ns_err_param; 465 badseq = SI(&ep->ns_err_idp)->si_seq; 466 for (m = sb->sb_mb; m; m = m->m_act) { 467 si = mtod(m, struct spidp *); 468 if (si->si_seq == badseq) 469 break; 470 } 471 if (m == 0) return; 472 firstbad = m; 473 /*for (;;) {*/ 474 /* calculate length */ 475 for (m0 = m, len = 0; m ; m = m->m_next) 476 len += m->m_len; 477 if (len > cb->s_mtu) { 478 } 479 /* FINISH THIS 480 } */ 481 } 482 } 483 #endif 484 485 int spp_output_cnt = 0; 486 487 spp_output(cb, m0) 488 register struct sppcb *cb; 489 struct mbuf *m0; 490 { 491 struct socket *so = cb->s_nspcb->nsp_socket; 492 register struct mbuf *m; 493 register struct spidp *si = (struct spidp *) 0; 494 register struct sockbuf *sb = &(so->so_snd); 495 register int len = 0; 496 int error = 0; 497 u_short lookfor = 0; 498 struct mbuf *mprev; 499 extern int idpcksum; 500 501 if (m0) { 502 int mtu = cb->s_mtu; 503 int datalen; 504 /* 505 * Make sure that packet isn't too big. 506 */ 507 for (m = m0; m ; m = m->m_next) { 508 mprev = m; 509 len += m->m_len; 510 } 511 datalen = (cb->s_flags & SF_HO) ? 512 len - sizeof (struct sphdr) : len; 513 if (datalen > mtu) { 514 if (cb->s_flags & SF_PI) { 515 m_freem(m0); 516 return (EMSGSIZE); 517 } else { 518 int off = 0; 519 int oldEM = cb->s_cc & SP_EM; 520 521 cb->s_cc &= ~SP_EM; 522 while (len > mtu) { 523 m = m_copy(m0, off, mtu); 524 if (m == NULL) { 525 error = ENOBUFS; 526 goto bad_copy; 527 } 528 error = spp_output(cb, m); 529 if (error) { 530 bad_copy: 531 cb->s_cc |= oldEM; 532 m_freem(m0); 533 return(error); 534 } 535 m_adj(m0, mtu); 536 len -= mtu; 537 } 538 cb->s_cc |= oldEM; 539 } 540 } 541 /* 542 * Force length even, by adding a "garbage byte" if 543 * necessary. 544 */ 545 if (len & 1) { 546 m = mprev; 547 if (m->m_len + m->m_off < MMAXOFF) 548 m->m_len++; 549 else { 550 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 551 552 if (m1 == 0) { 553 m_freem(m0); 554 return (ENOBUFS); 555 } 556 m1->m_len = 1; 557 m1->m_off = MMAXOFF - 1; 558 m->m_next = m1; 559 } 560 } 561 m = m_get(M_DONTWAIT, MT_HEADER); 562 if (m == 0) { 563 m_freem(m0); 564 return (ENOBUFS); 565 } 566 /* 567 * Fill in mbuf with extended SP header 568 * and addresses and length put into network format. 569 * Long align so prepended ip headers will work on Gould. 570 */ 571 m->m_off = MMAXOFF - sizeof (struct spidp) - 2; 572 m->m_len = sizeof (struct spidp); 573 m->m_next = m0; 574 si = mtod(m, struct spidp *); 575 *si = cb->s_shdr; 576 if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 577 register struct sphdr *sh; 578 if (m0->m_len < sizeof (*sh)) { 579 if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 580 (void) m_free(m); 581 m_freem(m0); 582 return (EINVAL); 583 } 584 m->m_next = m0; 585 } 586 sh = mtod(m0, struct sphdr *); 587 si->si_dt = sh->sp_dt; 588 si->si_cc |= sh->sp_cc & SP_EM; 589 m0->m_len -= sizeof (*sh); 590 m0->m_off += sizeof (*sh); 591 len -= sizeof (*sh); 592 } 593 len += sizeof(*si); 594 if (cb->s_oobflags & SF_SOOB) { 595 /* 596 * Per jqj@cornell: 597 * make sure OB packets convey exactly 1 byte. 598 * If the packet is 1 byte or larger, we 599 * have already guaranted there to be at least 600 * one garbage byte for the checksum, and 601 * extra bytes shouldn't hurt! 602 */ 603 if (len > sizeof(*si)) { 604 si->si_cc |= SP_OB; 605 len = (1 + sizeof(*si)); 606 } 607 } 608 si->si_len = htons((u_short)len); 609 /* 610 * queue stuff up for output 611 */ 612 sbappendrecord(sb, m); 613 cb->s_seq++; 614 } 615 /* 616 * update window 617 */ 618 { 619 register struct sockbuf *sb2 = &so->so_rcv; 620 int credit = ((((int)sb2->sb_mbmax) - (int)sb2->sb_mbcnt) / 621 ((short)cb->s_mtu)); 622 int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1; 623 624 if (cb->s_alo < alo) { 625 /* If the amount we are raising the window 626 is more than his remaining headroom, tell 627 him about it. In particular, if he is at 628 his limit, any amount at all will do! */ 629 u_short raise = alo - cb->s_alo; 630 u_short headroom = 1 + cb->s_alo - cb->s_ack; 631 632 if(SSEQ_LT(headroom, raise)) 633 cb->s_flags |= SF_AK; 634 cb->s_alo = alo; 635 } 636 } 637 638 if (cb->s_oobflags & SF_SOOB) { 639 /* 640 * must transmit this out of band packet 641 */ 642 cb->s_oobflags &= ~ SF_SOOB; 643 } else { 644 /* 645 * Decide what to transmit: 646 * If it is time to retransmit a packet, 647 * send that. 648 * If we have a new packet, send that 649 * (So long as it is in our allocation) 650 * Otherwise, see if it time to bang on them 651 * to ask for our current allocation. 652 */ 653 if (cb->s_force == (1+TCPT_REXMT)) { 654 lookfor = cb->s_rack; 655 } else if (SSEQ_LT(cb->s_snt, cb->s_ralo)) { 656 lookfor = cb->s_snt + 1; 657 } else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) { 658 lookfor = 0; 659 if (cb->s_timer[TCPT_PERSIST] == 0) { 660 spp_setpersist(cb); 661 /* tcp has cb->s_rxtshift = 0; here */ 662 } 663 } 664 m = sb->sb_mb; 665 while (m) { 666 si = mtod(m, struct spidp *); 667 m = m->m_act; 668 if (SSEQ_LT(si->si_seq, cb->s_rack)) { 669 if ((sb->sb_flags & SB_WAIT) 670 || so->so_snd.sb_sel) 671 sowwakeup(so); 672 sbdroprecord(sb); 673 si = 0; 674 continue; 675 } 676 if (SSEQ_LT(si->si_seq, lookfor)) 677 continue; 678 break; 679 } 680 if (si && (si->si_seq != lookfor)) 681 si = 0; 682 } 683 cb->s_want = lookfor; 684 685 if (si) { 686 /* 687 * must make a copy of this packet for 688 * idp_output to monkey with 689 */ 690 m = m_copy(dtom(si), 0, (int)M_COPYALL); 691 if (m == NULL) 692 return (ENOBUFS); 693 m0 = m; 694 si = mtod(m, struct spidp *); 695 } else if (cb->s_force || cb->s_flags & SF_AK) { 696 /* 697 * Must send an acknowledgement or a probe 698 */ 699 m = m_get(M_DONTWAIT, MT_HEADER); 700 if (m == 0) 701 return (ENOBUFS); 702 /* 703 * Fill in mbuf with extended SP header 704 * and addresses and length put into network format. 705 */ 706 m->m_off = MMAXOFF - sizeof (struct spidp); 707 m->m_len = sizeof (*si); 708 m->m_next = 0; 709 si = mtod(m, struct spidp *); 710 *si = cb->s_shdr; 711 si->si_seq = cb->s_snt + 1; 712 si->si_len = htons(sizeof (*si)); 713 si->si_cc |= SP_SP; 714 } 715 /* 716 * Stuff checksum and output datagram. 717 */ 718 if (si) { 719 if (cb->s_flags & (SF_AK|SF_DELACK)) 720 cb->s_flags &= ~(SF_AK|SF_DELACK); 721 /* 722 * If we are almost out of allocation 723 * or one of the timers has gone off 724 * request an ack. 725 */ 726 if (SSEQ_GEQ(cb->s_seq, cb->s_ralo)) 727 si->si_cc |= SP_SA; 728 if (cb->s_force) { 729 si->si_cc |= SP_SA; 730 cb->s_force = 0; 731 } 732 /* 733 * If this is a new packet (and not a system packet), 734 * and we are not currently timing anything, 735 * time this one and ask for an ack. 736 */ 737 if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) { 738 cb->s_snt = si->si_seq; 739 if (cb->s_rtt == 0) { 740 cb->s_rtseq = si->si_seq; 741 cb->s_rtt = 1; 742 si->si_cc |= SP_SA; 743 } 744 /* 745 * If the retransmit timer has not been set 746 * and this is a real packet 747 * then start the retransmit timer 748 */ 749 if (cb->s_timer[TCPT_REXMT] == 0) { 750 TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 751 tcp_beta * cb->s_srtt, TCPTV_MIN, 752 TCPTV_MAX); 753 cb->s_rxtshift = 0; 754 } 755 } 756 si->si_seq = htons(si->si_seq); 757 si->si_alo = htons(cb->s_alo); 758 si->si_ack = htons(cb->s_ack); 759 760 if (idpcksum) { 761 si->si_sum = 0; 762 len = ntohs(si->si_len); 763 if (len & 1) 764 len++; 765 si->si_sum = ns_cksum(dtom(si), len); 766 } else 767 si->si_sum = 0xffff; 768 769 if (so->so_options & SO_DEBUG || traceallspps) 770 spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 771 spp_output_cnt++; 772 if (so->so_options & SO_DONTROUTE) 773 error = ns_output(m, (struct route *)0, NS_ROUTETOIF); 774 else 775 error = ns_output(m, &cb->s_nspcb->nsp_route, 0); 776 if (traceallspps && sppconsdebug) { 777 printf("spp_out: %x\n", error); 778 } 779 if (so->so_options & SO_DEBUG || traceallspps) 780 spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 781 } 782 return (error); 783 } 784 785 /*ARGSUSED*/ 786 spp_ctloutput(req, so, level, name, value) 787 int req; 788 struct socket *so; 789 int name; 790 struct mbuf **value; 791 { 792 register struct mbuf *m; 793 struct nspcb *nsp = sotonspcb(so); 794 register struct sppcb *cb; 795 int mask, error = 0; 796 797 if (level != NSPROTO_SPP) { 798 /* This will have to be changed when we do more general 799 stacking of protocols */ 800 return (idp_ctloutput(req, so, level, name, value)); 801 } 802 if (nsp == NULL) { 803 error = EINVAL; 804 goto release; 805 } else 806 cb = nstosppcb(nsp); 807 808 switch (req) { 809 810 case PRCO_GETOPT: 811 if (value == NULL) 812 return (EINVAL); 813 m = m_get(M_DONTWAIT, MT_DATA); 814 if (m == NULL) 815 return (ENOBUFS); 816 switch (name) { 817 818 case SO_HEADERS_ON_INPUT: 819 mask = SF_HI; 820 goto get_flags; 821 822 case SO_HEADERS_ON_OUTPUT: 823 mask = SF_HO; 824 get_flags: 825 m->m_len = sizeof(short); 826 m->m_off = MMAXOFF - sizeof(short); 827 *mtod(m, short *) = cb->s_flags & mask; 828 break; 829 830 case SO_MTU: 831 m->m_len = sizeof(u_short); 832 m->m_off = MMAXOFF - sizeof(short); 833 *mtod(m, short *) = cb->s_mtu; 834 break; 835 836 case SO_LAST_HEADER: 837 m->m_len = sizeof(struct sphdr); 838 m->m_off = MMAXOFF - sizeof(struct sphdr); 839 *mtod(m, struct sphdr *) = cb->s_rhdr; 840 break; 841 842 case SO_DEFAULT_HEADERS: 843 m->m_len = sizeof(struct spidp); 844 m->m_off = MMAXOFF - sizeof(struct sphdr); 845 *mtod(m, struct sphdr *) = cb->s_shdr.si_s; 846 break; 847 848 default: 849 error = EINVAL; 850 } 851 *value = m; 852 break; 853 854 case PRCO_SETOPT: 855 if (value == 0 || *value == 0) { 856 error = EINVAL; 857 break; 858 } 859 switch (name) { 860 int *ok; 861 862 case SO_HEADERS_ON_INPUT: 863 mask = SF_HI; 864 goto set_head; 865 866 case SO_HEADERS_ON_OUTPUT: 867 mask = SF_HO; 868 set_head: 869 if (cb->s_flags & SF_PI) { 870 ok = mtod(*value, int *); 871 if (*ok) 872 cb->s_flags |= mask; 873 else 874 cb->s_flags &= ~mask; 875 } else error = EINVAL; 876 break; 877 878 case SO_MTU: 879 cb->s_mtu = *(mtod(*value, u_short *)); 880 break; 881 882 case SO_DEFAULT_HEADERS: 883 { 884 register struct sphdr *sp 885 = mtod(*value, struct sphdr *); 886 cb->s_dt = sp->sp_dt; 887 cb->s_cc = sp->sp_cc & SP_EM; 888 } 889 break; 890 891 default: 892 error = EINVAL; 893 } 894 m_freem(*value); 895 break; 896 } 897 release: 898 return (error); 899 } 900 901 /*ARGSUSED*/ 902 spp_usrreq(so, req, m, nam, rights) 903 struct socket *so; 904 int req; 905 struct mbuf *m, *nam, *rights; 906 { 907 struct nspcb *nsp = sotonspcb(so); 908 register struct sppcb *cb; 909 int s = splnet(); 910 int error = 0, ostate; 911 912 if (req == PRU_CONTROL) 913 return (ns_control(so, (int)m, (caddr_t)nam, 914 (struct ifnet *)rights)); 915 if (rights && rights->m_len) { 916 error = EINVAL; 917 goto release; 918 } 919 if (nsp == NULL) { 920 if (req != PRU_ATTACH) { 921 error = EINVAL; 922 goto release; 923 } 924 } else 925 cb = nstosppcb(nsp); 926 927 ostate = cb ? cb->s_state : 0; 928 929 switch (req) { 930 931 case PRU_ATTACH: 932 if (nsp != NULL) { 933 error = EISCONN; 934 break; 935 } 936 error = ns_pcballoc(so, &nspcb); 937 if (error) 938 break; 939 error = soreserve(so, 2048, 2048); 940 if (error) 941 break; 942 nsp = sotonspcb(so); 943 { 944 struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB); 945 946 if (mm == NULL) { 947 error = ENOBUFS; 948 break; 949 } 950 cb = mtod(mm, struct sppcb *); 951 cb->s_state = TCPS_LISTEN; 952 cb->s_snt = -1; 953 cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 954 cb->s_nspcb = nsp; 955 nsp->nsp_pcb = (caddr_t) cb; 956 } 957 break; 958 959 case PRU_DETACH: 960 if (nsp == NULL) { 961 error = ENOTCONN; 962 break; 963 } 964 if (cb->s_state > TCPS_LISTEN) 965 cb = spp_disconnect(cb); 966 else 967 cb = spp_close(cb); 968 break; 969 970 case PRU_BIND: 971 error = ns_pcbbind(nsp, nam); 972 break; 973 974 case PRU_LISTEN: 975 if (nsp->nsp_lport == 0) 976 error = ns_pcbbind(nsp, (struct mbuf *)0); 977 if (error == 0) 978 cb->s_state = TCPS_LISTEN; 979 break; 980 981 /* 982 * Initiate connection to peer. 983 * Enter SYN_SENT state, and mark socket as connecting. 984 * Start keep-alive timer, setup prototype header, 985 * Send initial system packet requesting connection. 986 */ 987 case PRU_CONNECT: 988 if (nsp->nsp_lport == 0) { 989 error = ns_pcbbind(nsp, (struct mbuf *)0); 990 if (error) 991 break; 992 } 993 error = ns_pcbconnect(nsp, nam); 994 if (error) 995 break; 996 soisconnecting(so); 997 cb->s_state = TCPS_SYN_SENT; 998 cb->s_did = 0; 999 spp_template(cb); 1000 cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 1001 cb->s_force = 1 + TCPTV_KEEP; 1002 /* 1003 * Other party is required to respond to 1004 * the port I send from, but he is not 1005 * required to answer from where I am sending to, 1006 * so allow wildcarding. 1007 * original port I am sending to is still saved in 1008 * cb->s_dport. 1009 */ 1010 nsp->nsp_fport = 0; 1011 error = spp_output(cb, (struct mbuf *) 0); 1012 break; 1013 1014 case PRU_CONNECT2: 1015 error = EOPNOTSUPP; 1016 break; 1017 1018 /* 1019 * We may decide later to implement connection closing 1020 * handshaking at the spp level optionally. 1021 * here is the hook to do it: 1022 */ 1023 case PRU_DISCONNECT: 1024 cb = spp_disconnect(cb); 1025 break; 1026 1027 /* 1028 * Accept a connection. Essentially all the work is 1029 * done at higher levels; just return the address 1030 * of the peer, storing through addr. 1031 */ 1032 case PRU_ACCEPT: { 1033 struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 1034 1035 nam->m_len = sizeof (struct sockaddr_ns); 1036 sns->sns_family = AF_NS; 1037 sns->sns_addr = nsp->nsp_faddr; 1038 break; 1039 } 1040 1041 case PRU_SHUTDOWN: 1042 socantsendmore(so); 1043 cb = spp_usrclosed(cb); 1044 if (cb) 1045 error = spp_output(cb, (struct mbuf *) 0); 1046 break; 1047 1048 /* 1049 * After a receive, possibly send acknowledgment 1050 * updating allocation. 1051 */ 1052 case PRU_RCVD: 1053 (void) spp_output(cb, (struct mbuf *) 0); 1054 break; 1055 1056 case PRU_ABORT: 1057 (void) spp_drop(cb, ECONNABORTED); 1058 break; 1059 1060 case PRU_SENSE: 1061 case PRU_CONTROL: 1062 m = NULL; 1063 error = EOPNOTSUPP; 1064 break; 1065 1066 case PRU_RCVOOB: 1067 if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 1068 (so->so_state & SS_RCVATMARK)) { 1069 m->m_len = 1; 1070 *mtod(m, caddr_t) = cb->s_iobc; 1071 break; 1072 } 1073 error = EINVAL; 1074 break; 1075 1076 case PRU_SENDOOB: 1077 if (sbspace(&so->so_snd) < -512) { 1078 error = ENOBUFS; 1079 break; 1080 } 1081 cb->s_oobflags |= SF_SOOB; 1082 /* fall into */ 1083 case PRU_SEND: 1084 error = spp_output(cb, m); 1085 m = NULL; 1086 break; 1087 1088 case PRU_SOCKADDR: 1089 ns_setsockaddr(nsp, nam); 1090 break; 1091 1092 case PRU_PEERADDR: 1093 ns_setpeeraddr(nsp, nam); 1094 break; 1095 1096 case PRU_SLOWTIMO: 1097 cb = spp_timers(cb, (int)nam); 1098 break; 1099 1100 case PRU_FASTTIMO: 1101 case PRU_PROTORCV: 1102 case PRU_PROTOSEND: 1103 error = EOPNOTSUPP; 1104 break; 1105 1106 default: 1107 panic("sp_usrreq"); 1108 } 1109 if (cb && (so->so_options & SO_DEBUG || traceallspps)) 1110 spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); 1111 release: 1112 if (m != NULL) 1113 m_freem(m); 1114 splx(s); 1115 return (error); 1116 } 1117 1118 spp_usrreq_sp(so, req, m, nam, rights) 1119 struct socket *so; 1120 int req; 1121 struct mbuf *m, *nam, *rights; 1122 { 1123 int error = spp_usrreq(so, req, m, nam, rights); 1124 1125 if (req == PRU_ATTACH && error == 0) { 1126 struct nspcb *nsp = sotonspcb(so); 1127 ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 1128 (SF_HI | SF_HO | SF_PI); 1129 } 1130 return (error); 1131 } 1132 1133 /* 1134 * Create template to be used to send spp packets on a connection. 1135 * Called after host entry created, fills 1136 * in a skeletal spp header (choosing connection id), 1137 * minimizing the amount of work necessary when the connection is used. 1138 */ 1139 spp_template(cb) 1140 struct sppcb *cb; 1141 { 1142 register struct nspcb *nsp = cb->s_nspcb; 1143 register struct spidp *n = &(cb->s_shdr); 1144 1145 cb->s_mtu = 576 - sizeof (struct spidp); 1146 n->si_pt = NSPROTO_SPP; 1147 n->si_sna = nsp->nsp_laddr; 1148 n->si_dna = nsp->nsp_faddr; 1149 n->si_sid = htons(spp_iss); 1150 spp_iss += SPP_ISSINCR/2; 1151 n->si_alo = 1; 1152 } 1153 1154 /* 1155 * Close a SPIP control block: 1156 * discard spp control block itself 1157 * discard ns protocol control block 1158 * wake up any sleepers 1159 */ 1160 struct sppcb * 1161 spp_close(cb) 1162 register struct sppcb *cb; 1163 { 1164 register struct spidp_q *s; 1165 struct nspcb *nsp = cb->s_nspcb; 1166 struct socket *so = nsp->nsp_socket; 1167 register struct mbuf *m; 1168 1169 s = cb->s_q.si_next; 1170 while (s != &(cb->s_q)) { 1171 s = s->si_next; 1172 m = dtom(s->si_prev); 1173 remque(s->si_prev); 1174 m_freem(m); 1175 } 1176 (void) m_free(dtom(cb)); 1177 nsp->nsp_pcb = 0; 1178 soisdisconnected(so); 1179 ns_pcbdetach(nsp); 1180 return ((struct sppcb *)0); 1181 } 1182 /* 1183 * Someday we may do level 3 handshaking 1184 * to close a connection or send a xerox style error. 1185 * For now, just close. 1186 */ 1187 struct sppcb * 1188 spp_usrclosed(cb) 1189 register struct sppcb *cb; 1190 { 1191 return (spp_close(cb)); 1192 } 1193 struct sppcb * 1194 spp_disconnect(cb) 1195 register struct sppcb *cb; 1196 { 1197 return (spp_close(cb)); 1198 } 1199 /* 1200 * Drop connection, reporting 1201 * the specified error. 1202 */ 1203 struct sppcb * 1204 spp_drop(cb, errno) 1205 register struct sppcb *cb; 1206 int errno; 1207 { 1208 struct socket *so = cb->s_nspcb->nsp_socket; 1209 1210 /* 1211 * someday, in the xerox world 1212 * we will generate error protocol packets 1213 * announcing that the socket has gone away. 1214 */ 1215 /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 1216 tp->t_state = TCPS_CLOSED; 1217 (void) tcp_output(tp); 1218 }*/ 1219 so->so_error = errno; 1220 return (spp_close(cb)); 1221 } 1222 1223 spp_abort(nsp) 1224 struct nspcb *nsp; 1225 { 1226 1227 (void) spp_close((struct sppcb *)nsp->nsp_pcb); 1228 } 1229 1230 spp_setpersist(cb) 1231 register struct sppcb *cb; 1232 { 1233 1234 /*if (cb->s_timer[TCPT_REXMT]) 1235 panic("spp_output REXMT");*/ 1236 /* 1237 * Start/restart persistance timer. 1238 */ 1239 TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 1240 ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 1241 TCPTV_PERSMIN, TCPTV_MAX); 1242 cb->s_rxtshift++; 1243 if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 1244 cb->s_rxtshift = 0; 1245 } 1246 /* 1247 * Fast timeout routine for processing delayed acks 1248 */ 1249 int spp_ftcnt; 1250 spp_fasttimo() 1251 { 1252 register struct nspcb *nsp; 1253 register struct sppcb *cb; 1254 int s = splnet(); 1255 1256 nsp = nspcb.nsp_next; 1257 spp_ftcnt++; 1258 if (nsp) 1259 for (; nsp != &nspcb; nsp = nsp->nsp_next) 1260 if ((cb = (struct sppcb *)nsp->nsp_pcb) && 1261 (cb->s_flags & SF_DELACK)) { 1262 cb->s_flags &= ~SF_DELACK; 1263 cb->s_flags |= SF_AK; 1264 (void) spp_output(cb, (struct mbuf *) 0); 1265 } 1266 splx(s); 1267 } 1268 1269 /* 1270 * spp protocol timeout routine called every 500 ms. 1271 * Updates the timers in all active pcb's and 1272 * causes finite state machine actions if timers expire. 1273 */ 1274 spp_slowtimo() 1275 { 1276 register struct nspcb *ip, *ipnxt; 1277 register struct sppcb *cb; 1278 int s = splnet(); 1279 register int i; 1280 1281 /* 1282 * Search through tcb's and update active timers. 1283 */ 1284 ip = nspcb.nsp_next; 1285 if (ip == 0) { 1286 splx(s); 1287 return; 1288 } 1289 while (ip != &nspcb) { 1290 cb = nstosppcb(ip); 1291 ipnxt = ip->nsp_next; 1292 if (cb == 0) 1293 goto tpgone; 1294 for (i = 0; i < TCPT_NTIMERS; i++) { 1295 if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 1296 (void) spp_usrreq(cb->s_nspcb->nsp_socket, 1297 PRU_SLOWTIMO, (struct mbuf *)0, 1298 (struct mbuf *)i, (struct mbuf *)0); 1299 if (ipnxt->nsp_prev != ip) 1300 goto tpgone; 1301 } 1302 } 1303 cb->s_idle++; 1304 if (cb->s_rtt) 1305 cb->s_rtt++; 1306 tpgone: 1307 ip = ipnxt; 1308 } 1309 spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 1310 splx(s); 1311 } 1312 1313 float spp_backoff[TCP_MAXRXTSHIFT] = 1314 { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 1315 int sppexprexmtbackoff = 0; 1316 /* 1317 * SPP timer processing. 1318 */ 1319 struct sppcb * 1320 spp_timers(cb, timer) 1321 register struct sppcb *cb; 1322 int timer; 1323 { 1324 1325 cb->s_force = 1 + timer; 1326 switch (timer) { 1327 1328 /* 1329 * 2 MSL timeout in shutdown went off. Delete connection 1330 * control block. 1331 */ 1332 case TCPT_2MSL: 1333 cb = spp_close(cb); 1334 break; 1335 1336 /* 1337 * Retransmission timer went off. Message has not 1338 * been acked within retransmit interval. Back off 1339 * to a longer retransmit interval and retransmit all 1340 * unacknowledged messages in the window. 1341 */ 1342 case TCPT_REXMT: 1343 cb->s_rxtshift++; 1344 if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 1345 cb = spp_drop(cb, ETIMEDOUT); 1346 break; 1347 } 1348 (void) spp_output(cb, (struct mbuf *) 0); 1349 TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 1350 (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 1351 if (sppexprexmtbackoff) { 1352 TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 1353 cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 1354 TCPTV_MIN, TCPTV_MAX); 1355 } else { 1356 TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 1357 cb->s_timer[TCPT_REXMT] * 1358 spp_backoff[cb->s_rxtshift - 1], 1359 TCPTV_MIN, TCPTV_MAX); 1360 } 1361 break; 1362 1363 /* 1364 * Persistance timer into zero window. 1365 * Force a probe to be sent. 1366 */ 1367 case TCPT_PERSIST: 1368 (void) spp_output(cb, (struct mbuf *) 0); 1369 spp_setpersist(cb); 1370 break; 1371 1372 /* 1373 * Keep-alive timer went off; send something 1374 * or drop connection if idle for too long. 1375 */ 1376 case TCPT_KEEP: 1377 if (cb->s_state < TCPS_ESTABLISHED) 1378 goto dropit; 1379 if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 1380 if (cb->s_idle >= TCPTV_MAXIDLE) 1381 goto dropit; 1382 (void) spp_output(cb, (struct mbuf *) 0); 1383 } else 1384 cb->s_idle = 0; 1385 cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 1386 break; 1387 dropit: 1388 cb = spp_drop(cb, ETIMEDOUT); 1389 break; 1390 } 1391 return (cb); 1392 } 1393