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