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