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