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.14 (Berkeley) 10/11/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 it is time to retransmit a packet, 645 * send that. 646 * If we have a new packet, send that 647 * (So long as it is in our allocation) 648 * Otherwise, see if it time to bang on them 649 * to ask for our current allocation. 650 */ 651 if (cb->s_force == (1+TCPT_REXMT)) { 652 lookfor = cb->s_rack; 653 } else if (SSEQ_LT(cb->s_snt, cb->s_ralo)) { 654 lookfor = cb->s_snt + 1; 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 if (so->so_options & SO_DEBUG || traceallspps) 778 spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 779 } 780 return (error); 781 } 782 783 /*ARGSUSED*/ 784 spp_ctloutput(req, so, level, name, value) 785 int req; 786 struct socket *so; 787 int name; 788 struct mbuf **value; 789 { 790 register struct mbuf *m; 791 struct nspcb *nsp = sotonspcb(so); 792 register struct sppcb *cb; 793 int mask, error = 0; 794 795 if (level != NSPROTO_SPP) { 796 /* This will have to be changed when we do more general 797 stacking of protocols */ 798 return (idp_ctloutput(req, so, level, name, value)); 799 } 800 if (nsp == NULL) { 801 error = EINVAL; 802 goto release; 803 } else 804 cb = nstosppcb(nsp); 805 806 switch (req) { 807 808 case PRCO_GETOPT: 809 if (value == NULL) 810 return (EINVAL); 811 m = m_get(M_DONTWAIT, MT_DATA); 812 if (m == NULL) 813 return (ENOBUFS); 814 switch (name) { 815 816 case SO_HEADERS_ON_INPUT: 817 mask = SF_HI; 818 goto get_flags; 819 820 case SO_HEADERS_ON_OUTPUT: 821 mask = SF_HO; 822 get_flags: 823 m->m_len = sizeof(short); 824 m->m_off = MMAXOFF - sizeof(short); 825 *mtod(m, short *) = cb->s_flags & mask; 826 break; 827 828 case SO_MTU: 829 m->m_len = sizeof(u_short); 830 m->m_off = MMAXOFF - sizeof(short); 831 *mtod(m, short *) = cb->s_mtu; 832 break; 833 834 case SO_LAST_HEADER: 835 m->m_len = sizeof(struct sphdr); 836 m->m_off = MMAXOFF - sizeof(struct sphdr); 837 *mtod(m, struct sphdr *) = cb->s_rhdr; 838 break; 839 840 case SO_DEFAULT_HEADERS: 841 m->m_len = sizeof(struct spidp); 842 m->m_off = MMAXOFF - sizeof(struct sphdr); 843 *mtod(m, struct sphdr *) = cb->s_shdr.si_s; 844 } 845 *value = m; 846 break; 847 848 case PRCO_SETOPT: 849 if (value == 0 || *value == 0) { 850 error = EINVAL; 851 break; 852 } 853 switch (name) { 854 int *ok; 855 856 case SO_HEADERS_ON_INPUT: 857 mask = SF_HI; 858 goto set_head; 859 860 case SO_HEADERS_ON_OUTPUT: 861 mask = SF_HO; 862 set_head: 863 if (cb->s_flags & SF_PI) { 864 ok = mtod(*value, int *); 865 if (*ok) 866 cb->s_flags |= mask; 867 else 868 cb->s_flags &= ~mask; 869 } else error = EINVAL; 870 break; 871 872 case SO_MTU: 873 cb->s_mtu = *(mtod(*value, u_short *)); 874 break; 875 876 case SO_DEFAULT_HEADERS: 877 { 878 register struct sphdr *sp 879 = mtod(*value, struct sphdr *); 880 cb->s_dt = sp->sp_dt; 881 cb->s_cc = sp->sp_cc & SP_EM; 882 } 883 } 884 m_freem(*value); 885 break; 886 } 887 release: 888 return (error); 889 } 890 891 /*ARGSUSED*/ 892 spp_usrreq(so, req, m, nam, rights) 893 struct socket *so; 894 int req; 895 struct mbuf *m, *nam, *rights; 896 { 897 struct nspcb *nsp = sotonspcb(so); 898 register struct sppcb *cb; 899 int s = splnet(); 900 int error = 0, ostate; 901 902 if (req == PRU_CONTROL) 903 return (ns_control(so, (int)m, (caddr_t)nam, 904 (struct ifnet *)rights)); 905 if (rights && rights->m_len) { 906 error = EINVAL; 907 goto release; 908 } 909 if (nsp == NULL) { 910 if (req != PRU_ATTACH) { 911 error = EINVAL; 912 goto release; 913 } 914 } else 915 cb = nstosppcb(nsp); 916 917 ostate = cb ? cb->s_state : 0; 918 919 switch (req) { 920 921 case PRU_ATTACH: 922 if (nsp != NULL) { 923 error = EISCONN; 924 break; 925 } 926 error = ns_pcballoc(so, &nspcb); 927 if (error) 928 break; 929 error = soreserve(so, 2048, 2048); 930 if (error) 931 break; 932 nsp = sotonspcb(so); 933 { 934 struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB); 935 936 if (mm == NULL) { 937 error = ENOBUFS; 938 break; 939 } 940 cb = mtod(mm, struct sppcb *); 941 cb->s_state = TCPS_LISTEN; 942 cb->s_snt = -1; 943 cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 944 cb->s_nspcb = nsp; 945 nsp->nsp_pcb = (caddr_t) cb; 946 } 947 break; 948 949 case PRU_DETACH: 950 if (nsp == NULL) { 951 error = ENOTCONN; 952 break; 953 } 954 if (cb->s_state > TCPS_LISTEN) 955 cb = spp_disconnect(cb); 956 else 957 cb = spp_close(cb); 958 break; 959 960 case PRU_BIND: 961 error = ns_pcbbind(nsp, nam); 962 break; 963 964 case PRU_LISTEN: 965 if (nsp->nsp_lport == 0) 966 error = ns_pcbbind(nsp, (struct mbuf *)0); 967 if (error == 0) 968 cb->s_state = TCPS_LISTEN; 969 break; 970 971 /* 972 * Initiate connection to peer. 973 * Enter SYN_SENT state, and mark socket as connecting. 974 * Start keep-alive timer, setup prototype header, 975 * Send initial system packet requesting connection. 976 */ 977 case PRU_CONNECT: 978 if (nsp->nsp_lport == 0) { 979 error = ns_pcbbind(nsp, (struct mbuf *)0); 980 if (error) 981 break; 982 } 983 error = ns_pcbconnect(nsp, nam); 984 if (error) 985 break; 986 soisconnecting(so); 987 cb->s_state = TCPS_SYN_SENT; 988 cb->s_did = 0; 989 spp_template(cb); 990 cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 991 cb->s_force = 1 + TCPTV_KEEP; 992 /* 993 * Other party is required to respond to 994 * the port I send from, but he is not 995 * required to answer from where I am sending to, 996 * so allow wildcarding. 997 * original port I am sending to is still saved in 998 * cb->s_dport. 999 */ 1000 nsp->nsp_fport = 0; 1001 error = spp_output(cb, (struct mbuf *) 0); 1002 break; 1003 1004 case PRU_CONNECT2: 1005 error = EOPNOTSUPP; 1006 break; 1007 1008 /* 1009 * We may decide later to implement connection closing 1010 * handshaking at the spp level optionally. 1011 * here is the hook to do it: 1012 */ 1013 case PRU_DISCONNECT: 1014 cb = spp_disconnect(cb); 1015 break; 1016 1017 /* 1018 * Accept a connection. Essentially all the work is 1019 * done at higher levels; just return the address 1020 * of the peer, storing through addr. 1021 */ 1022 case PRU_ACCEPT: { 1023 struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 1024 1025 nam->m_len = sizeof (struct sockaddr_ns); 1026 sns->sns_family = AF_NS; 1027 sns->sns_addr = nsp->nsp_faddr; 1028 break; 1029 } 1030 1031 case PRU_SHUTDOWN: 1032 socantsendmore(so); 1033 cb = spp_usrclosed(cb); 1034 if (cb) 1035 error = spp_output(cb, (struct mbuf *) 0); 1036 break; 1037 1038 /* 1039 * After a receive, possibly send acknowledgment 1040 * updating allocation. 1041 */ 1042 case PRU_RCVD: 1043 (void) spp_output(cb, (struct mbuf *) 0); 1044 break; 1045 1046 case PRU_SEND: 1047 error = spp_output(cb, m); 1048 m = NULL; 1049 break; 1050 1051 case PRU_ABORT: 1052 (void) spp_drop(cb, ECONNABORTED); 1053 break; 1054 1055 case PRU_SENSE: 1056 case PRU_CONTROL: 1057 m = NULL; 1058 error = EOPNOTSUPP; 1059 break; 1060 1061 case PRU_RCVOOB: 1062 if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 1063 (so->so_state & SS_RCVATMARK)) { 1064 m->m_len = 1; 1065 *mtod(m, caddr_t) = cb->s_iobc; 1066 break; 1067 } 1068 error = EINVAL; 1069 break; 1070 1071 case PRU_SENDOOB: 1072 if (sbspace(&so->so_snd) < -512) { 1073 m_freem(m); 1074 error = ENOBUFS; 1075 break; 1076 } 1077 cb->s_oobflags |= SF_SOOB; 1078 error = spp_output(cb, m); 1079 m = NULL; 1080 break; 1081 1082 case PRU_SOCKADDR: 1083 ns_setsockaddr(nsp, nam); 1084 break; 1085 1086 case PRU_PEERADDR: 1087 ns_setpeeraddr(nsp, nam); 1088 break; 1089 1090 case PRU_SLOWTIMO: 1091 cb = spp_timers(cb, (int)nam); 1092 break; 1093 1094 case PRU_FASTTIMO: 1095 case PRU_PROTORCV: 1096 case PRU_PROTOSEND: 1097 error = EOPNOTSUPP; 1098 break; 1099 1100 default: 1101 panic("sp_usrreq"); 1102 } 1103 if (cb && (so->so_options & SO_DEBUG || traceallspps)) 1104 spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); 1105 release: 1106 if (m != NULL) 1107 m_freem(m); 1108 splx(s); 1109 return (error); 1110 } 1111 1112 spp_usrreq_sp(so, req, m, nam, rights) 1113 struct socket *so; 1114 int req; 1115 struct mbuf *m, *nam, *rights; 1116 { 1117 int error = spp_usrreq(so, req, m, nam, rights); 1118 1119 if (req == PRU_ATTACH && error == 0) { 1120 struct nspcb *nsp = sotonspcb(so); 1121 ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 1122 (SF_HI | SF_HO | SF_PI); 1123 } 1124 return (error); 1125 } 1126 1127 /* 1128 * Create template to be used to send spp packets on a connection. 1129 * Called after host entry created, fills 1130 * in a skeletal spp header (choosing connection id), 1131 * minimizing the amount of work necessary when the connection is used. 1132 */ 1133 spp_template(cb) 1134 struct sppcb *cb; 1135 { 1136 register struct nspcb *nsp = cb->s_nspcb; 1137 register struct spidp *n = &(cb->s_shdr); 1138 1139 cb->s_mtu = 576 - sizeof (struct spidp); 1140 n->si_pt = NSPROTO_SPP; 1141 n->si_sna = nsp->nsp_laddr; 1142 n->si_dna = nsp->nsp_faddr; 1143 n->si_sid = htons(spp_iss); 1144 spp_iss += SPP_ISSINCR/2; 1145 n->si_alo = 1; 1146 } 1147 1148 /* 1149 * Close a SPIP control block: 1150 * discard spp control block itself 1151 * discard ns protocol control block 1152 * wake up any sleepers 1153 */ 1154 struct sppcb * 1155 spp_close(cb) 1156 register struct sppcb *cb; 1157 { 1158 register struct spidp_q *s; 1159 struct nspcb *nsp = cb->s_nspcb; 1160 struct socket *so = nsp->nsp_socket; 1161 register struct mbuf *m; 1162 1163 s = cb->s_q.si_next; 1164 while (s != &(cb->s_q)) { 1165 s = s->si_next; 1166 m = dtom(s->si_prev); 1167 remque(s->si_prev); 1168 m_freem(m); 1169 } 1170 (void) m_free(dtom(cb)); 1171 nsp->nsp_pcb = 0; 1172 soisdisconnected(so); 1173 ns_pcbdetach(nsp); 1174 return ((struct sppcb *)0); 1175 } 1176 /* 1177 * Someday we may do level 3 handshaking 1178 * to close a connection or send a xerox style error. 1179 * For now, just close. 1180 */ 1181 struct sppcb * 1182 spp_usrclosed(cb) 1183 register struct sppcb *cb; 1184 { 1185 return (spp_close(cb)); 1186 } 1187 struct sppcb * 1188 spp_disconnect(cb) 1189 register struct sppcb *cb; 1190 { 1191 return (spp_close(cb)); 1192 } 1193 /* 1194 * Drop connection, reporting 1195 * the specified error. 1196 */ 1197 struct sppcb * 1198 spp_drop(cb, errno) 1199 register struct sppcb *cb; 1200 int errno; 1201 { 1202 struct socket *so = cb->s_nspcb->nsp_socket; 1203 1204 /* 1205 * someday, in the xerox world 1206 * we will generate error protocol packets 1207 * announcing that the socket has gone away. 1208 */ 1209 /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 1210 tp->t_state = TCPS_CLOSED; 1211 (void) tcp_output(tp); 1212 }*/ 1213 so->so_error = errno; 1214 return (spp_close(cb)); 1215 } 1216 1217 spp_abort(nsp) 1218 struct nspcb *nsp; 1219 { 1220 1221 (void) spp_close((struct sppcb *)nsp->nsp_pcb); 1222 } 1223 1224 spp_setpersist(cb) 1225 register struct sppcb *cb; 1226 { 1227 1228 /*if (cb->s_timer[TCPT_REXMT]) 1229 panic("spp_output REXMT");*/ 1230 /* 1231 * Start/restart persistance timer. 1232 */ 1233 TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 1234 ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 1235 TCPTV_PERSMIN, TCPTV_MAX); 1236 cb->s_rxtshift++; 1237 if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 1238 cb->s_rxtshift = 0; 1239 } 1240 /* 1241 * Fast timeout routine for processing delayed acks 1242 */ 1243 int spp_ftcnt; 1244 spp_fasttimo() 1245 { 1246 register struct nspcb *nsp; 1247 register struct sppcb *cb; 1248 int s = splnet(); 1249 1250 nsp = nspcb.nsp_next; 1251 spp_ftcnt++; 1252 if (nsp) 1253 for (; nsp != &nspcb; nsp = nsp->nsp_next) 1254 if ((cb = (struct sppcb *)nsp->nsp_pcb) && 1255 (cb->s_flags & SF_DELACK)) { 1256 cb->s_flags &= ~SF_DELACK; 1257 cb->s_flags |= SF_AK; 1258 (void) spp_output(cb, (struct mbuf *) 0); 1259 } 1260 splx(s); 1261 } 1262 1263 /* 1264 * spp protocol timeout routine called every 500 ms. 1265 * Updates the timers in all active pcb's and 1266 * causes finite state machine actions if timers expire. 1267 */ 1268 spp_slowtimo() 1269 { 1270 register struct nspcb *ip, *ipnxt; 1271 register struct sppcb *cb; 1272 int s = splnet(); 1273 register int i; 1274 1275 /* 1276 * Search through tcb's and update active timers. 1277 */ 1278 ip = nspcb.nsp_next; 1279 if (ip == 0) { 1280 splx(s); 1281 return; 1282 } 1283 while (ip != &nspcb) { 1284 cb = nstosppcb(ip); 1285 ipnxt = ip->nsp_next; 1286 if (cb == 0) 1287 goto tpgone; 1288 for (i = 0; i < TCPT_NTIMERS; i++) { 1289 if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 1290 (void) spp_usrreq(cb->s_nspcb->nsp_socket, 1291 PRU_SLOWTIMO, (struct mbuf *)0, 1292 (struct mbuf *)i, (struct mbuf *)0); 1293 if (ipnxt->nsp_prev != ip) 1294 goto tpgone; 1295 } 1296 } 1297 cb->s_idle++; 1298 if (cb->s_rtt) 1299 cb->s_rtt++; 1300 tpgone: 1301 ip = ipnxt; 1302 } 1303 spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 1304 splx(s); 1305 } 1306 1307 float spp_backoff[TCP_MAXRXTSHIFT] = 1308 { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 1309 int sppexprexmtbackoff = 0; 1310 /* 1311 * SPP timer processing. 1312 */ 1313 struct sppcb * 1314 spp_timers(cb, timer) 1315 register struct sppcb *cb; 1316 int timer; 1317 { 1318 1319 cb->s_force = 1 + timer; 1320 switch (timer) { 1321 1322 /* 1323 * 2 MSL timeout in shutdown went off. Delete connection 1324 * control block. 1325 */ 1326 case TCPT_2MSL: 1327 cb = spp_close(cb); 1328 break; 1329 1330 /* 1331 * Retransmission timer went off. Message has not 1332 * been acked within retransmit interval. Back off 1333 * to a longer retransmit interval and retransmit all 1334 * unacknowledged messages in the window. 1335 */ 1336 case TCPT_REXMT: 1337 cb->s_rxtshift++; 1338 if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 1339 cb = spp_drop(cb, ETIMEDOUT); 1340 break; 1341 } 1342 (void) spp_output(cb, (struct mbuf *) 0); 1343 TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 1344 (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 1345 if (sppexprexmtbackoff) { 1346 TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 1347 cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 1348 TCPTV_MIN, TCPTV_MAX); 1349 } else { 1350 TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 1351 cb->s_timer[TCPT_REXMT] * 1352 spp_backoff[cb->s_rxtshift - 1], 1353 TCPTV_MIN, TCPTV_MAX); 1354 } 1355 break; 1356 1357 /* 1358 * Persistance timer into zero window. 1359 * Force a probe to be sent. 1360 */ 1361 case TCPT_PERSIST: 1362 (void) spp_output(cb, (struct mbuf *) 0); 1363 spp_setpersist(cb); 1364 break; 1365 1366 /* 1367 * Keep-alive timer went off; send something 1368 * or drop connection if idle for too long. 1369 */ 1370 case TCPT_KEEP: 1371 if (cb->s_state < TCPS_ESTABLISHED) 1372 goto dropit; 1373 if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 1374 if (cb->s_idle >= TCPTV_MAXIDLE) 1375 goto dropit; 1376 (void) spp_output(cb, (struct mbuf *) 0); 1377 } else 1378 cb->s_idle = 0; 1379 cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 1380 break; 1381 dropit: 1382 cb = spp_drop(cb, ETIMEDOUT); 1383 break; 1384 } 1385 return (cb); 1386 } 1387