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