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