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