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