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