|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)spp_usrreq.c 7.14 (Berkeley) 6/28/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "user.h" ! 26: #include "malloc.h" ! 27: #include "mbuf.h" ! 28: #include "protosw.h" ! 29: #include "socket.h" ! 30: #include "socketvar.h" ! 31: #include "errno.h" ! 32: ! 33: #include "../net/if.h" ! 34: #include "../net/route.h" ! 35: #include "../netinet/tcp_fsm.h" ! 36: ! 37: #include "ns.h" ! 38: #include "ns_pcb.h" ! 39: #include "idp.h" ! 40: #include "idp_var.h" ! 41: #include "ns_error.h" ! 42: #include "sp.h" ! 43: #include "spidp.h" ! 44: #include "spp_timer.h" ! 45: #include "spp_var.h" ! 46: #include "spp_debug.h" ! 47: ! 48: /* ! 49: * SP protocol implementation. ! 50: */ ! 51: spp_init() ! 52: { ! 53: ! 54: spp_iss = 1; /* WRONG !! should fish it out of TODR */ ! 55: } ! 56: struct spidp spp_savesi; ! 57: int traceallspps = 0; ! 58: extern int sppconsdebug; ! 59: int spp_hardnosed; ! 60: int spp_use_delack = 0; ! 61: u_short spp_newchecks[50]; ! 62: ! 63: /*ARGSUSED*/ ! 64: spp_input(m, nsp) ! 65: register struct mbuf *m; ! 66: register struct nspcb *nsp; ! 67: { ! 68: register struct sppcb *cb; ! 69: register struct spidp *si = mtod(m, struct spidp *); ! 70: register struct socket *so; ! 71: short ostate; ! 72: int dropsocket = 0; ! 73: ! 74: ! 75: sppstat.spps_rcvtotal++; ! 76: if (nsp == 0) { ! 77: panic("No nspcb in spp_input\n"); ! 78: return; ! 79: } ! 80: ! 81: cb = nstosppcb(nsp); ! 82: if (cb == 0) goto bad; ! 83: ! 84: if (m->m_len < sizeof(*si)) { ! 85: if ((m = m_pullup(m, sizeof(*si))) == 0) { ! 86: sppstat.spps_rcvshort++; ! 87: return; ! 88: } ! 89: si = mtod(m, struct spidp *); ! 90: } ! 91: si->si_seq = ntohs(si->si_seq); ! 92: si->si_ack = ntohs(si->si_ack); ! 93: si->si_alo = ntohs(si->si_alo); ! 94: ! 95: so = nsp->nsp_socket; ! 96: if (so->so_options & SO_DEBUG || traceallspps) { ! 97: ostate = cb->s_state; ! 98: spp_savesi = *si; ! 99: } ! 100: if (so->so_options & SO_ACCEPTCONN) { ! 101: struct sppcb *ocb = cb; ! 102: ! 103: so = sonewconn(so, 0); ! 104: if (so == 0) { ! 105: goto drop; ! 106: } ! 107: /* ! 108: * This is ugly, but .... ! 109: * ! 110: * Mark socket as temporary until we're ! 111: * committed to keeping it. The code at ! 112: * ``drop'' and ``dropwithreset'' check the ! 113: * flag dropsocket to see if the temporary ! 114: * socket created here should be discarded. ! 115: * We mark the socket as discardable until ! 116: * we're committed to it below in TCPS_LISTEN. ! 117: */ ! 118: dropsocket++; ! 119: nsp = (struct nspcb *)so->so_pcb; ! 120: nsp->nsp_laddr = si->si_dna; ! 121: cb = nstosppcb(nsp); ! 122: cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ ! 123: cb->s_flags = ocb->s_flags; /* preserve sockopts */ ! 124: cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ ! 125: cb->s_state = TCPS_LISTEN; ! 126: } ! 127: ! 128: /* ! 129: * Packet received on connection. ! 130: * reset idle time and keep-alive timer; ! 131: */ ! 132: cb->s_idle = 0; ! 133: cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; ! 134: ! 135: switch (cb->s_state) { ! 136: ! 137: case TCPS_LISTEN:{ ! 138: struct mbuf *am; ! 139: register struct sockaddr_ns *sns; ! 140: struct ns_addr laddr; ! 141: ! 142: /* ! 143: * If somebody here was carying on a conversation ! 144: * and went away, and his pen pal thinks he can ! 145: * still talk, we get the misdirected packet. ! 146: */ ! 147: if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { ! 148: spp_istat.gonawy++; ! 149: goto dropwithreset; ! 150: } ! 151: am = m_get(M_DONTWAIT, MT_SONAME); ! 152: if (am == NULL) ! 153: goto drop; ! 154: am->m_len = sizeof (struct sockaddr_ns); ! 155: sns = mtod(am, struct sockaddr_ns *); ! 156: sns->sns_len = sizeof(*sns); ! 157: sns->sns_family = AF_NS; ! 158: sns->sns_addr = si->si_sna; ! 159: laddr = nsp->nsp_laddr; ! 160: if (ns_nullhost(laddr)) ! 161: nsp->nsp_laddr = si->si_dna; ! 162: if (ns_pcbconnect(nsp, am)) { ! 163: nsp->nsp_laddr = laddr; ! 164: (void) m_free(am); ! 165: spp_istat.noconn++; ! 166: goto drop; ! 167: } ! 168: (void) m_free(am); ! 169: spp_template(cb); ! 170: dropsocket = 0; /* committed to socket */ ! 171: cb->s_did = si->si_sid; ! 172: cb->s_rack = si->si_ack; ! 173: cb->s_ralo = si->si_alo; ! 174: #define THREEWAYSHAKE ! 175: #ifdef THREEWAYSHAKE ! 176: cb->s_state = TCPS_SYN_RECEIVED; ! 177: cb->s_force = 1 + SPPT_KEEP; ! 178: sppstat.spps_accepts++; ! 179: cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; ! 180: } ! 181: break; ! 182: /* ! 183: * This state means that we have heard a response ! 184: * to our acceptance of their connection ! 185: * It is probably logically unnecessary in this ! 186: * implementation. ! 187: */ ! 188: case TCPS_SYN_RECEIVED: { ! 189: if (si->si_did!=cb->s_sid) { ! 190: spp_istat.wrncon++; ! 191: goto drop; ! 192: } ! 193: #endif ! 194: nsp->nsp_fport = si->si_sport; ! 195: cb->s_timer[SPPT_REXMT] = 0; ! 196: cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; ! 197: soisconnected(so); ! 198: cb->s_state = TCPS_ESTABLISHED; ! 199: sppstat.spps_accepts++; ! 200: } ! 201: break; ! 202: ! 203: /* ! 204: * This state means that we have gotten a response ! 205: * to our attempt to establish a connection. ! 206: * We fill in the data from the other side, ! 207: * telling us which port to respond to, instead of the well- ! 208: * known one we might have sent to in the first place. ! 209: * We also require that this is a response to our ! 210: * connection id. ! 211: */ ! 212: case TCPS_SYN_SENT: ! 213: if (si->si_did!=cb->s_sid) { ! 214: spp_istat.notme++; ! 215: goto drop; ! 216: } ! 217: sppstat.spps_connects++; ! 218: cb->s_did = si->si_sid; ! 219: cb->s_rack = si->si_ack; ! 220: cb->s_ralo = si->si_alo; ! 221: cb->s_dport = nsp->nsp_fport = si->si_sport; ! 222: cb->s_timer[SPPT_REXMT] = 0; ! 223: cb->s_flags |= SF_ACKNOW; ! 224: soisconnected(so); ! 225: cb->s_state = TCPS_ESTABLISHED; ! 226: /* Use roundtrip time of connection request for initial rtt */ ! 227: if (cb->s_rtt) { ! 228: cb->s_srtt = cb->s_rtt << 3; ! 229: cb->s_rttvar = cb->s_rtt << 1; ! 230: SPPT_RANGESET(cb->s_rxtcur, ! 231: ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, ! 232: SPPTV_MIN, SPPTV_REXMTMAX); ! 233: cb->s_rtt = 0; ! 234: } ! 235: } ! 236: if (so->so_options & SO_DEBUG || traceallspps) ! 237: spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0); ! 238: ! 239: m->m_len -= sizeof (struct idp); ! 240: m->m_pkthdr.len -= sizeof (struct idp); ! 241: m->m_data += sizeof (struct idp); ! 242: ! 243: if (spp_reass(cb, si)) { ! 244: (void) m_freem(m); ! 245: } ! 246: if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) ! 247: (void) spp_output(cb, (struct mbuf *)0); ! 248: cb->s_flags &= ~(SF_WIN|SF_RXT); ! 249: return; ! 250: ! 251: dropwithreset: ! 252: if (dropsocket) ! 253: (void) soabort(so); ! 254: si->si_seq = ntohs(si->si_seq); ! 255: si->si_ack = ntohs(si->si_ack); ! 256: si->si_alo = ntohs(si->si_alo); ! 257: ns_error(dtom(si), NS_ERR_NOSOCK, 0); ! 258: if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) ! 259: spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); ! 260: return; ! 261: ! 262: drop: ! 263: bad: ! 264: if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || ! 265: traceallspps) ! 266: spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); ! 267: m_freem(m); ! 268: } ! 269: ! 270: int spprexmtthresh = 3; ! 271: ! 272: /* ! 273: * This is structurally similar to the tcp reassembly routine ! 274: * but its function is somewhat different: It merely queues ! 275: * packets up, and suppresses duplicates. ! 276: */ ! 277: spp_reass(cb, si) ! 278: register struct sppcb *cb; ! 279: register struct spidp *si; ! 280: { ! 281: register struct spidp_q *q; ! 282: register struct mbuf *m; ! 283: register struct socket *so = cb->s_nspcb->nsp_socket; ! 284: char packetp = cb->s_flags & SF_HI; ! 285: int incr; ! 286: char wakeup = 0; ! 287: ! 288: if (si == SI(0)) ! 289: goto present; ! 290: /* ! 291: * Update our news from them. ! 292: */ ! 293: if (si->si_cc & SP_SA) ! 294: cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_ACKNOW); ! 295: if (SSEQ_GT(si->si_alo, cb->s_ralo)) ! 296: cb->s_flags |= SF_WIN; ! 297: if (SSEQ_LEQ(si->si_ack, cb->s_rack)) { ! 298: if ((si->si_cc & SP_SP) && cb->s_rack != (cb->s_smax + 1)) { ! 299: sppstat.spps_rcvdupack++; ! 300: /* ! 301: * If this is a completely duplicate ack ! 302: * and other conditions hold, we assume ! 303: * a packet has been dropped and retransmit ! 304: * it exactly as in tcp_input(). ! 305: */ ! 306: if (si->si_ack != cb->s_rack || ! 307: si->si_alo != cb->s_ralo) ! 308: cb->s_dupacks = 0; ! 309: else if (++cb->s_dupacks == spprexmtthresh) { ! 310: u_short onxt = cb->s_snxt; ! 311: int cwnd = cb->s_cwnd; ! 312: ! 313: cb->s_snxt = si->si_ack; ! 314: cb->s_cwnd = CUNIT; ! 315: cb->s_force = 1 + SPPT_REXMT; ! 316: (void) spp_output(cb, (struct mbuf *)0); ! 317: cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; ! 318: cb->s_rtt = 0; ! 319: if (cwnd >= 4 * CUNIT) ! 320: cb->s_cwnd = cwnd / 2; ! 321: if (SSEQ_GT(onxt, cb->s_snxt)) ! 322: cb->s_snxt = onxt; ! 323: return (1); ! 324: } ! 325: } else ! 326: cb->s_dupacks = 0; ! 327: goto update_window; ! 328: } ! 329: cb->s_dupacks = 0; ! 330: /* ! 331: * If our correspondent acknowledges data we haven't sent ! 332: * TCP would drop the packet after acking. We'll be a little ! 333: * more permissive ! 334: */ ! 335: if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) { ! 336: sppstat.spps_rcvacktoomuch++; ! 337: si->si_ack = cb->s_smax + 1; ! 338: } ! 339: sppstat.spps_rcvackpack++; ! 340: /* ! 341: * If transmit timer is running and timed sequence ! 342: * number was acked, update smoothed round trip time. ! 343: * See discussion of algorithm in tcp_input.c ! 344: */ ! 345: if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { ! 346: sppstat.spps_rttupdated++; ! 347: if (cb->s_srtt != 0) { ! 348: register short delta; ! 349: delta = cb->s_rtt - (cb->s_srtt >> 3); ! 350: if ((cb->s_srtt += delta) <= 0) ! 351: cb->s_srtt = 1; ! 352: if (delta < 0) ! 353: delta = -delta; ! 354: delta -= (cb->s_rttvar >> 2); ! 355: if ((cb->s_rttvar += delta) <= 0) ! 356: cb->s_rttvar = 1; ! 357: } else { ! 358: /* ! 359: * No rtt measurement yet ! 360: */ ! 361: cb->s_srtt = cb->s_rtt << 3; ! 362: cb->s_rttvar = cb->s_rtt << 1; ! 363: } ! 364: cb->s_rtt = 0; ! 365: cb->s_rxtshift = 0; ! 366: SPPT_RANGESET(cb->s_rxtcur, ! 367: ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, ! 368: SPPTV_MIN, SPPTV_REXMTMAX); ! 369: } ! 370: /* ! 371: * If all outstanding data is acked, stop retransmit ! 372: * timer and remember to restart (more output or persist). ! 373: * If there is more data to be acked, restart retransmit ! 374: * timer, using current (possibly backed-off) value; ! 375: */ ! 376: if (si->si_ack == cb->s_smax + 1) { ! 377: cb->s_timer[SPPT_REXMT] = 0; ! 378: cb->s_flags |= SF_RXT; ! 379: } else if (cb->s_timer[SPPT_PERSIST] == 0) ! 380: cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; ! 381: /* ! 382: * When new data is acked, open the congestion window. ! 383: * If the window gives us less than ssthresh packets ! 384: * in flight, open exponentially (maxseg at a time). ! 385: * Otherwise open linearly (maxseg^2 / cwnd at a time). ! 386: */ ! 387: incr = CUNIT; ! 388: if (cb->s_cwnd > cb->s_ssthresh) ! 389: incr = max(incr * incr / cb->s_cwnd, 1); ! 390: cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx); ! 391: /* ! 392: * Trim Acked data from output queue. ! 393: */ ! 394: while ((m = so->so_snd.sb_mb) != NULL) { ! 395: if (SSEQ_LT((mtod(m, struct spidp *))->si_seq, si->si_ack)) ! 396: sbdroprecord(&so->so_snd); ! 397: else ! 398: break; ! 399: } ! 400: sowwakeup(so); ! 401: cb->s_rack = si->si_ack; ! 402: update_window: ! 403: if (SSEQ_LT(cb->s_snxt, cb->s_rack)) ! 404: cb->s_snxt = cb->s_rack; ! 405: if (SSEQ_LT(cb->s_swl1, si->si_seq) || cb->s_swl1 == si->si_seq && ! 406: (SSEQ_LT(cb->s_swl2, si->si_ack) || ! 407: cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))) { ! 408: /* keep track of pure window updates */ ! 409: if ((si->si_cc & SP_SP) && cb->s_swl2 == si->si_ack ! 410: && SSEQ_LT(cb->s_ralo, si->si_alo)) { ! 411: sppstat.spps_rcvwinupd++; ! 412: sppstat.spps_rcvdupack--; ! 413: } ! 414: cb->s_ralo = si->si_alo; ! 415: cb->s_swl1 = si->si_seq; ! 416: cb->s_swl2 = si->si_ack; ! 417: cb->s_swnd = (1 + si->si_alo - si->si_ack); ! 418: if (cb->s_swnd > cb->s_smxw) ! 419: cb->s_smxw = cb->s_swnd; ! 420: cb->s_flags |= SF_WIN; ! 421: } ! 422: /* ! 423: * If this packet number is higher than that which ! 424: * we have allocated refuse it, unless urgent ! 425: */ ! 426: if (SSEQ_GT(si->si_seq, cb->s_alo)) { ! 427: if (si->si_cc & SP_SP) { ! 428: sppstat.spps_rcvwinprobe++; ! 429: return (1); ! 430: } else ! 431: sppstat.spps_rcvpackafterwin++; ! 432: if (si->si_cc & SP_OB) { ! 433: if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { ! 434: ns_error(dtom(si), NS_ERR_FULLUP, 0); ! 435: return (0); ! 436: } /* else queue this packet; */ ! 437: } else { ! 438: /*register struct socket *so = cb->s_nspcb->nsp_socket; ! 439: if (so->so_state && SS_NOFDREF) { ! 440: ns_error(dtom(si), NS_ERR_NOSOCK, 0); ! 441: (void)spp_close(cb); ! 442: } else ! 443: would crash system*/ ! 444: spp_istat.notyet++; ! 445: ns_error(dtom(si), NS_ERR_FULLUP, 0); ! 446: return (0); ! 447: } ! 448: } ! 449: /* ! 450: * If this is a system packet, we don't need to ! 451: * queue it up, and won't update acknowledge # ! 452: */ ! 453: if (si->si_cc & SP_SP) { ! 454: return (1); ! 455: } ! 456: /* ! 457: * We have already seen this packet, so drop. ! 458: */ ! 459: if (SSEQ_LT(si->si_seq, cb->s_ack)) { ! 460: spp_istat.bdreas++; ! 461: sppstat.spps_rcvduppack++; ! 462: if (si->si_seq == cb->s_ack - 1) ! 463: spp_istat.lstdup++; ! 464: return (1); ! 465: } ! 466: /* ! 467: * Loop through all packets queued up to insert in ! 468: * appropriate sequence. ! 469: */ ! 470: for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { ! 471: if (si->si_seq == SI(q)->si_seq) { ! 472: sppstat.spps_rcvduppack++; ! 473: return (1); ! 474: } ! 475: if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { ! 476: sppstat.spps_rcvoopack++; ! 477: break; ! 478: } ! 479: } ! 480: insque(si, q->si_prev); ! 481: /* ! 482: * If this packet is urgent, inform process ! 483: */ ! 484: if (si->si_cc & SP_OB) { ! 485: cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; ! 486: sohasoutofband(so); ! 487: cb->s_oobflags |= SF_IOOB; ! 488: } ! 489: present: ! 490: #define SPINC sizeof(struct sphdr) ! 491: /* ! 492: * Loop through all packets queued up to update acknowledge ! 493: * number, and present all acknowledged data to user; ! 494: * If in packet interface mode, show packet headers. ! 495: */ ! 496: for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { ! 497: if (SI(q)->si_seq == cb->s_ack) { ! 498: cb->s_ack++; ! 499: m = dtom(q); ! 500: if (SI(q)->si_cc & SP_OB) { ! 501: cb->s_oobflags &= ~SF_IOOB; ! 502: if (so->so_rcv.sb_cc) ! 503: so->so_oobmark = so->so_rcv.sb_cc; ! 504: else ! 505: so->so_state |= SS_RCVATMARK; ! 506: } ! 507: q = q->si_prev; ! 508: remque(q->si_next); ! 509: wakeup = 1; ! 510: sppstat.spps_rcvpack++; ! 511: #ifdef SF_NEWCALL ! 512: if (cb->s_flags2 & SF_NEWCALL) { ! 513: struct sphdr *sp = mtod(m, struct sphdr *); ! 514: u_char dt = sp->sp_dt; ! 515: spp_newchecks[4]++; ! 516: if (dt != cb->s_rhdr.sp_dt) { ! 517: struct mbuf *mm = ! 518: m_getclr(M_DONTWAIT, MT_CONTROL); ! 519: spp_newchecks[0]++; ! 520: if (mm != NULL) { ! 521: u_short *s = ! 522: mtod(mm, u_short *); ! 523: cb->s_rhdr.sp_dt = dt; ! 524: mm->m_len = 5; /*XXX*/ ! 525: s[0] = 5; ! 526: s[1] = 1; ! 527: *(u_char *)(&s[2]) = dt; ! 528: sbappend(&so->so_rcv, mm); ! 529: } ! 530: } ! 531: if (sp->sp_cc & SP_OB) { ! 532: MCHTYPE(m, MT_OOBDATA); ! 533: spp_newchecks[1]++; ! 534: so->so_oobmark = 0; ! 535: so->so_state &= ~SS_RCVATMARK; ! 536: } ! 537: if (packetp == 0) { ! 538: m->m_data += SPINC; ! 539: m->m_len -= SPINC; ! 540: m->m_pkthdr.len -= SPINC; ! 541: } ! 542: if ((sp->sp_cc & SP_EM) || packetp) { ! 543: sbappendrecord(&so->so_rcv, m); ! 544: spp_newchecks[9]++; ! 545: } else ! 546: sbappend(&so->so_rcv, m); ! 547: } else ! 548: #endif ! 549: if (packetp) { ! 550: sbappendrecord(&so->so_rcv, m); ! 551: } else { ! 552: cb->s_rhdr = *mtod(m, struct sphdr *); ! 553: m->m_data += SPINC; ! 554: m->m_len -= SPINC; ! 555: m->m_pkthdr.len -= SPINC; ! 556: sbappend(&so->so_rcv, m); ! 557: } ! 558: } else ! 559: break; ! 560: } ! 561: if (wakeup) sorwakeup(so); ! 562: return (0); ! 563: } ! 564: ! 565: spp_ctlinput(cmd, arg) ! 566: int cmd; ! 567: caddr_t arg; ! 568: { ! 569: struct ns_addr *na; ! 570: extern u_char nsctlerrmap[]; ! 571: extern spp_abort(), spp_quench(); ! 572: extern struct nspcb *idp_drop(); ! 573: struct ns_errp *errp; ! 574: struct nspcb *nsp; ! 575: struct sockaddr_ns *sns; ! 576: int type; ! 577: ! 578: if (cmd < 0 || cmd > PRC_NCMDS) ! 579: return; ! 580: type = NS_ERR_UNREACH_HOST; ! 581: ! 582: switch (cmd) { ! 583: ! 584: case PRC_ROUTEDEAD: ! 585: return; ! 586: ! 587: case PRC_IFDOWN: ! 588: case PRC_HOSTDEAD: ! 589: case PRC_HOSTUNREACH: ! 590: sns = (struct sockaddr_ns *)arg; ! 591: if (sns->sns_family != AF_NS) ! 592: return; ! 593: na = &sns->sns_addr; ! 594: break; ! 595: ! 596: default: ! 597: errp = (struct ns_errp *)arg; ! 598: na = &errp->ns_err_idp.idp_dna; ! 599: type = errp->ns_err_num; ! 600: type = ntohs((u_short)type); ! 601: } ! 602: switch (type) { ! 603: ! 604: case NS_ERR_UNREACH_HOST: ! 605: ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0); ! 606: break; ! 607: ! 608: case NS_ERR_TOO_BIG: ! 609: case NS_ERR_NOSOCK: ! 610: nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port, ! 611: NS_WILDCARD); ! 612: if (nsp) { ! 613: if(nsp->nsp_pcb) ! 614: (void) spp_drop((struct sppcb *)nsp->nsp_pcb, ! 615: (int)nsctlerrmap[cmd]); ! 616: else ! 617: (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); ! 618: } ! 619: break; ! 620: ! 621: case NS_ERR_FULLUP: ! 622: ns_pcbnotify(na, 0, spp_quench, (long) 0); ! 623: } ! 624: } ! 625: /* ! 626: * When a source quench is received, close congestion window ! 627: * to one packet. We will gradually open it again as we proceed. ! 628: */ ! 629: spp_quench(nsp) ! 630: struct nspcb *nsp; ! 631: { ! 632: struct sppcb *cb = nstosppcb(nsp); ! 633: ! 634: if (cb) ! 635: cb->s_cwnd = CUNIT; ! 636: } ! 637: ! 638: #ifdef notdef ! 639: int ! 640: spp_fixmtu(nsp) ! 641: register struct nspcb *nsp; ! 642: { ! 643: register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); ! 644: register struct mbuf *m; ! 645: register struct spidp *si; ! 646: struct ns_errp *ep; ! 647: struct sockbuf *sb; ! 648: int badseq, len; ! 649: struct mbuf *firstbad, *m0; ! 650: ! 651: if (cb) { ! 652: /* ! 653: * The notification that we have sent ! 654: * too much is bad news -- we will ! 655: * have to go through queued up so far ! 656: * splitting ones which are too big and ! 657: * reassigning sequence numbers and checksums. ! 658: * we should then retransmit all packets from ! 659: * one above the offending packet to the last one ! 660: * we had sent (or our allocation) ! 661: * then the offending one so that the any queued ! 662: * data at our destination will be discarded. ! 663: */ ! 664: ep = (struct ns_errp *)nsp->nsp_notify_param; ! 665: sb = &nsp->nsp_socket->so_snd; ! 666: cb->s_mtu = ep->ns_err_param; ! 667: badseq = SI(&ep->ns_err_idp)->si_seq; ! 668: for (m = sb->sb_mb; m; m = m->m_act) { ! 669: si = mtod(m, struct spidp *); ! 670: if (si->si_seq == badseq) ! 671: break; ! 672: } ! 673: if (m == 0) return; ! 674: firstbad = m; ! 675: /*for (;;) {*/ ! 676: /* calculate length */ ! 677: for (m0 = m, len = 0; m ; m = m->m_next) ! 678: len += m->m_len; ! 679: if (len > cb->s_mtu) { ! 680: } ! 681: /* FINISH THIS ! 682: } */ ! 683: } ! 684: } ! 685: #endif ! 686: ! 687: spp_output(cb, m0) ! 688: register struct sppcb *cb; ! 689: struct mbuf *m0; ! 690: { ! 691: struct socket *so = cb->s_nspcb->nsp_socket; ! 692: register struct mbuf *m; ! 693: register struct spidp *si = (struct spidp *) 0; ! 694: register struct sockbuf *sb = &so->so_snd; ! 695: int len = 0, win, rcv_win; ! 696: short span, off, recordp = 0; ! 697: u_short alo; ! 698: int error = 0, sendalot; ! 699: #ifdef notdef ! 700: int idle; ! 701: #endif ! 702: struct mbuf *mprev; ! 703: extern int idpcksum; ! 704: ! 705: if (m0) { ! 706: int mtu = cb->s_mtu; ! 707: int datalen; ! 708: /* ! 709: * Make sure that packet isn't too big. ! 710: */ ! 711: for (m = m0; m ; m = m->m_next) { ! 712: mprev = m; ! 713: len += m->m_len; ! 714: if (m->m_flags & M_EOR) ! 715: recordp = 1; ! 716: } ! 717: datalen = (cb->s_flags & SF_HO) ? ! 718: len - sizeof (struct sphdr) : len; ! 719: if (datalen > mtu) { ! 720: if (cb->s_flags & SF_PI) { ! 721: m_freem(m0); ! 722: return (EMSGSIZE); ! 723: } else { ! 724: int oldEM = cb->s_cc & SP_EM; ! 725: ! 726: cb->s_cc &= ~SP_EM; ! 727: while (len > mtu) { ! 728: /* ! 729: * Here we are only being called ! 730: * from usrreq(), so it is OK to ! 731: * block. ! 732: */ ! 733: m = m_copym(m0, 0, mtu, M_WAIT); ! 734: if (cb->s_flags & SF_NEWCALL) { ! 735: struct mbuf *mm = m; ! 736: spp_newchecks[7]++; ! 737: while (mm) { ! 738: mm->m_flags &= ~M_EOR; ! 739: mm = mm->m_next; ! 740: } ! 741: } ! 742: error = spp_output(cb, m); ! 743: if (error) { ! 744: cb->s_cc |= oldEM; ! 745: m_freem(m0); ! 746: return(error); ! 747: } ! 748: m_adj(m0, mtu); ! 749: len -= mtu; ! 750: } ! 751: cb->s_cc |= oldEM; ! 752: } ! 753: } ! 754: /* ! 755: * Force length even, by adding a "garbage byte" if ! 756: * necessary. ! 757: */ ! 758: if (len & 1) { ! 759: m = mprev; ! 760: if (M_TRAILINGSPACE(m) >= 1) ! 761: m->m_len++; ! 762: else { ! 763: struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); ! 764: ! 765: if (m1 == 0) { ! 766: m_freem(m0); ! 767: return (ENOBUFS); ! 768: } ! 769: m1->m_len = 1; ! 770: *(mtod(m1, u_char *)) = 0; ! 771: m->m_next = m1; ! 772: } ! 773: } ! 774: m = m_gethdr(M_DONTWAIT, MT_HEADER); ! 775: if (m == 0) { ! 776: m_freem(m0); ! 777: return (ENOBUFS); ! 778: } ! 779: /* ! 780: * Fill in mbuf with extended SP header ! 781: * and addresses and length put into network format. ! 782: */ ! 783: MH_ALIGN(m, sizeof (struct spidp)); ! 784: m->m_len = sizeof (struct spidp); ! 785: m->m_next = m0; ! 786: si = mtod(m, struct spidp *); ! 787: si->si_i = *cb->s_idp; ! 788: si->si_s = cb->s_shdr; ! 789: if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { ! 790: register struct sphdr *sh; ! 791: if (m0->m_len < sizeof (*sh)) { ! 792: if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { ! 793: (void) m_free(m); ! 794: m_freem(m0); ! 795: return (EINVAL); ! 796: } ! 797: m->m_next = m0; ! 798: } ! 799: sh = mtod(m0, struct sphdr *); ! 800: si->si_dt = sh->sp_dt; ! 801: si->si_cc |= sh->sp_cc & SP_EM; ! 802: m0->m_len -= sizeof (*sh); ! 803: m0->m_data += sizeof (*sh); ! 804: len -= sizeof (*sh); ! 805: } ! 806: len += sizeof(*si); ! 807: if ((cb->s_flags2 & SF_NEWCALL) && recordp) { ! 808: si->si_cc |= SP_EM; ! 809: spp_newchecks[8]++; ! 810: } ! 811: if (cb->s_oobflags & SF_SOOB) { ! 812: /* ! 813: * Per jqj@cornell: ! 814: * make sure OB packets convey exactly 1 byte. ! 815: * If the packet is 1 byte or larger, we ! 816: * have already guaranted there to be at least ! 817: * one garbage byte for the checksum, and ! 818: * extra bytes shouldn't hurt! ! 819: */ ! 820: if (len > sizeof(*si)) { ! 821: si->si_cc |= SP_OB; ! 822: len = (1 + sizeof(*si)); ! 823: } ! 824: } ! 825: si->si_len = htons((u_short)len); ! 826: m->m_pkthdr.len = ((len - 1) | 1) + 1; ! 827: /* ! 828: * queue stuff up for output ! 829: */ ! 830: sbappendrecord(sb, m); ! 831: cb->s_seq++; ! 832: } ! 833: #ifdef notdef ! 834: idle = (cb->s_smax == (cb->s_rack - 1)); ! 835: #endif ! 836: again: ! 837: sendalot = 0; ! 838: off = cb->s_snxt - cb->s_rack; ! 839: win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)); ! 840: ! 841: /* ! 842: * If in persist timeout with window of 0, send a probe. ! 843: * Otherwise, if window is small but nonzero ! 844: * and timer expired, send what we can and go into ! 845: * transmit state. ! 846: */ ! 847: if (cb->s_force == 1 + SPPT_PERSIST) { ! 848: if (win != 0) { ! 849: cb->s_timer[SPPT_PERSIST] = 0; ! 850: cb->s_rxtshift = 0; ! 851: } ! 852: } ! 853: span = cb->s_seq - cb->s_rack; ! 854: len = min(span, win) - off; ! 855: ! 856: if (len < 0) { ! 857: /* ! 858: * Window shrank after we went into it. ! 859: * If window shrank to 0, cancel pending ! 860: * restransmission and pull s_snxt back ! 861: * to (closed) window. We will enter persist ! 862: * state below. If the widndow didn't close completely, ! 863: * just wait for an ACK. ! 864: */ ! 865: len = 0; ! 866: if (win == 0) { ! 867: cb->s_timer[SPPT_REXMT] = 0; ! 868: cb->s_snxt = cb->s_rack; ! 869: } ! 870: } ! 871: if (len > 1) ! 872: sendalot = 1; ! 873: rcv_win = sbspace(&so->so_rcv); ! 874: ! 875: /* ! 876: * Send if we owe peer an ACK. ! 877: */ ! 878: if (cb->s_oobflags & SF_SOOB) { ! 879: /* ! 880: * must transmit this out of band packet ! 881: */ ! 882: cb->s_oobflags &= ~ SF_SOOB; ! 883: sendalot = 1; ! 884: sppstat.spps_sndurg++; ! 885: goto found; ! 886: } ! 887: if (cb->s_flags & SF_ACKNOW) ! 888: goto send; ! 889: if (cb->s_state < TCPS_ESTABLISHED) ! 890: goto send; ! 891: /* ! 892: * Silly window can't happen in spp. ! 893: * Code from tcp deleted. ! 894: */ ! 895: if (len) ! 896: goto send; ! 897: /* ! 898: * Compare available window to amount of window ! 899: * known to peer (as advertised window less ! 900: * next expected input.) If the difference is at least two ! 901: * packets or at least 35% of the mximum possible window, ! 902: * then want to send a window update to peer. ! 903: */ ! 904: if (rcv_win > 0) { ! 905: u_short delta = 1 + cb->s_alo - cb->s_ack; ! 906: int adv = rcv_win - (delta * cb->s_mtu); ! 907: ! 908: if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || ! 909: (100 * adv / so->so_rcv.sb_hiwat >= 35)) { ! 910: sppstat.spps_sndwinup++; ! 911: cb->s_flags |= SF_ACKNOW; ! 912: goto send; ! 913: } ! 914: ! 915: } ! 916: /* ! 917: * Many comments from tcp_output.c are appropriate here ! 918: * including . . . ! 919: * If send window is too small, there is data to transmit, and no ! 920: * retransmit or persist is pending, then go to persist state. ! 921: * If nothing happens soon, send when timer expires: ! 922: * if window is nonzero, transmit what we can, ! 923: * otherwise send a probe. ! 924: */ ! 925: if (so->so_snd.sb_cc && cb->s_timer[SPPT_REXMT] == 0 && ! 926: cb->s_timer[SPPT_PERSIST] == 0) { ! 927: cb->s_rxtshift = 0; ! 928: spp_setpersist(cb); ! 929: } ! 930: /* ! 931: * No reason to send a packet, just return. ! 932: */ ! 933: cb->s_outx = 1; ! 934: return (0); ! 935: ! 936: send: ! 937: /* ! 938: * Find requested packet. ! 939: */ ! 940: si = 0; ! 941: if (len > 0) { ! 942: cb->s_want = cb->s_snxt; ! 943: for (m = sb->sb_mb; m; m = m->m_act) { ! 944: si = mtod(m, struct spidp *); ! 945: if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) ! 946: break; ! 947: } ! 948: found: ! 949: if (si) { ! 950: if (si->si_seq == cb->s_snxt) ! 951: cb->s_snxt++; ! 952: else ! 953: sppstat.spps_sndvoid++, si = 0; ! 954: } ! 955: } ! 956: /* ! 957: * update window ! 958: */ ! 959: if (rcv_win < 0) ! 960: rcv_win = 0; ! 961: alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); ! 962: if (SSEQ_LT(alo, cb->s_alo)) ! 963: alo = cb->s_alo; ! 964: ! 965: if (si) { ! 966: /* ! 967: * must make a copy of this packet for ! 968: * idp_output to monkey with ! 969: */ ! 970: m = m_copy(dtom(si), 0, (int)M_COPYALL); ! 971: if (m == NULL) { ! 972: return (ENOBUFS); ! 973: } ! 974: si = mtod(m, struct spidp *); ! 975: if (SSEQ_LT(si->si_seq, cb->s_smax)) ! 976: sppstat.spps_sndrexmitpack++; ! 977: else ! 978: sppstat.spps_sndpack++; ! 979: } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { ! 980: /* ! 981: * Must send an acknowledgement or a probe ! 982: */ ! 983: if (cb->s_force) ! 984: sppstat.spps_sndprobe++; ! 985: if (cb->s_flags & SF_ACKNOW) ! 986: sppstat.spps_sndacks++; ! 987: m = m_gethdr(M_DONTWAIT, MT_HEADER); ! 988: if (m == 0) ! 989: return (ENOBUFS); ! 990: /* ! 991: * Fill in mbuf with extended SP header ! 992: * and addresses and length put into network format. ! 993: */ ! 994: MH_ALIGN(m, sizeof (struct spidp)); ! 995: m->m_len = sizeof (*si); ! 996: m->m_pkthdr.len = sizeof (*si); ! 997: si = mtod(m, struct spidp *); ! 998: si->si_i = *cb->s_idp; ! 999: si->si_s = cb->s_shdr; ! 1000: si->si_seq = cb->s_smax + 1; ! 1001: si->si_len = htons(sizeof (*si)); ! 1002: si->si_cc |= SP_SP; ! 1003: } else { ! 1004: cb->s_outx = 3; ! 1005: if (so->so_options & SO_DEBUG || traceallspps) ! 1006: spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); ! 1007: return (0); ! 1008: } ! 1009: /* ! 1010: * Stuff checksum and output datagram. ! 1011: */ ! 1012: if ((si->si_cc & SP_SP) == 0) { ! 1013: if (cb->s_force != (1 + SPPT_PERSIST) || ! 1014: cb->s_timer[SPPT_PERSIST] == 0) { ! 1015: /* ! 1016: * If this is a new packet and we are not currently ! 1017: * timing anything, time this one. ! 1018: */ ! 1019: if (SSEQ_LT(cb->s_smax, si->si_seq)) { ! 1020: cb->s_smax = si->si_seq; ! 1021: if (cb->s_rtt == 0) { ! 1022: sppstat.spps_segstimed++; ! 1023: cb->s_rtseq = si->si_seq; ! 1024: cb->s_rtt = 1; ! 1025: } ! 1026: } ! 1027: /* ! 1028: * Set rexmt timer if not currently set, ! 1029: * Initial value for retransmit timer is smoothed ! 1030: * round-trip time + 2 * round-trip time variance. ! 1031: * Initialize shift counter which is used for backoff ! 1032: * of retransmit time. ! 1033: */ ! 1034: if (cb->s_timer[SPPT_REXMT] == 0 && ! 1035: cb->s_snxt != cb->s_rack) { ! 1036: cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; ! 1037: if (cb->s_timer[SPPT_PERSIST]) { ! 1038: cb->s_timer[SPPT_PERSIST] = 0; ! 1039: cb->s_rxtshift = 0; ! 1040: } ! 1041: } ! 1042: } else if (SSEQ_LT(cb->s_smax, si->si_seq)) { ! 1043: cb->s_smax = si->si_seq; ! 1044: } ! 1045: } else if (cb->s_state < TCPS_ESTABLISHED) { ! 1046: if (cb->s_rtt == 0) ! 1047: cb->s_rtt = 1; /* Time initial handshake */ ! 1048: if (cb->s_timer[SPPT_REXMT] == 0) ! 1049: cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; ! 1050: } ! 1051: { ! 1052: /* ! 1053: * Do not request acks when we ack their data packets or ! 1054: * when we do a gratuitous window update. ! 1055: */ ! 1056: if (((si->si_cc & SP_SP) == 0) || cb->s_force) ! 1057: si->si_cc |= SP_SA; ! 1058: si->si_seq = htons(si->si_seq); ! 1059: si->si_alo = htons(alo); ! 1060: si->si_ack = htons(cb->s_ack); ! 1061: ! 1062: if (idpcksum) { ! 1063: si->si_sum = 0; ! 1064: len = ntohs(si->si_len); ! 1065: if (len & 1) ! 1066: len++; ! 1067: si->si_sum = ns_cksum(m, len); ! 1068: } else ! 1069: si->si_sum = 0xffff; ! 1070: ! 1071: cb->s_outx = 4; ! 1072: if (so->so_options & SO_DEBUG || traceallspps) ! 1073: spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); ! 1074: ! 1075: if (so->so_options & SO_DONTROUTE) ! 1076: error = ns_output(m, (struct route *)0, NS_ROUTETOIF); ! 1077: else ! 1078: error = ns_output(m, &cb->s_nspcb->nsp_route, 0); ! 1079: } ! 1080: if (error) { ! 1081: return (error); ! 1082: } ! 1083: sppstat.spps_sndtotal++; ! 1084: /* ! 1085: * Data sent (as far as we can tell). ! 1086: * If this advertises a larger window than any other segment, ! 1087: * then remember the size of the advertized window. ! 1088: * Any pending ACK has now been sent. ! 1089: */ ! 1090: cb->s_force = 0; ! 1091: cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); ! 1092: if (SSEQ_GT(alo, cb->s_alo)) ! 1093: cb->s_alo = alo; ! 1094: if (sendalot) ! 1095: goto again; ! 1096: cb->s_outx = 5; ! 1097: return (0); ! 1098: } ! 1099: ! 1100: int spp_do_persist_panics = 0; ! 1101: ! 1102: spp_setpersist(cb) ! 1103: register struct sppcb *cb; ! 1104: { ! 1105: register t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; ! 1106: extern int spp_backoff[]; ! 1107: ! 1108: if (cb->s_timer[SPPT_REXMT] && spp_do_persist_panics) ! 1109: panic("spp_output REXMT"); ! 1110: /* ! 1111: * Start/restart persistance timer. ! 1112: */ ! 1113: SPPT_RANGESET(cb->s_timer[SPPT_PERSIST], ! 1114: t*spp_backoff[cb->s_rxtshift], ! 1115: SPPTV_PERSMIN, SPPTV_PERSMAX); ! 1116: if (cb->s_rxtshift < SPP_MAXRXTSHIFT) ! 1117: cb->s_rxtshift++; ! 1118: } ! 1119: /*ARGSUSED*/ ! 1120: spp_ctloutput(req, so, level, name, value) ! 1121: int req; ! 1122: struct socket *so; ! 1123: int name; ! 1124: struct mbuf **value; ! 1125: { ! 1126: register struct mbuf *m; ! 1127: struct nspcb *nsp = sotonspcb(so); ! 1128: register struct sppcb *cb; ! 1129: int mask, error = 0; ! 1130: ! 1131: if (level != NSPROTO_SPP) { ! 1132: /* This will have to be changed when we do more general ! 1133: stacking of protocols */ ! 1134: return (idp_ctloutput(req, so, level, name, value)); ! 1135: } ! 1136: if (nsp == NULL) { ! 1137: error = EINVAL; ! 1138: goto release; ! 1139: } else ! 1140: cb = nstosppcb(nsp); ! 1141: ! 1142: switch (req) { ! 1143: ! 1144: case PRCO_GETOPT: ! 1145: if (value == NULL) ! 1146: return (EINVAL); ! 1147: m = m_get(M_DONTWAIT, MT_DATA); ! 1148: if (m == NULL) ! 1149: return (ENOBUFS); ! 1150: switch (name) { ! 1151: ! 1152: case SO_HEADERS_ON_INPUT: ! 1153: mask = SF_HI; ! 1154: goto get_flags; ! 1155: ! 1156: case SO_HEADERS_ON_OUTPUT: ! 1157: mask = SF_HO; ! 1158: get_flags: ! 1159: m->m_len = sizeof(short); ! 1160: *mtod(m, short *) = cb->s_flags & mask; ! 1161: break; ! 1162: ! 1163: case SO_MTU: ! 1164: m->m_len = sizeof(u_short); ! 1165: *mtod(m, short *) = cb->s_mtu; ! 1166: break; ! 1167: ! 1168: case SO_LAST_HEADER: ! 1169: m->m_len = sizeof(struct sphdr); ! 1170: *mtod(m, struct sphdr *) = cb->s_rhdr; ! 1171: break; ! 1172: ! 1173: case SO_DEFAULT_HEADERS: ! 1174: m->m_len = sizeof(struct spidp); ! 1175: *mtod(m, struct sphdr *) = cb->s_shdr; ! 1176: break; ! 1177: ! 1178: default: ! 1179: error = EINVAL; ! 1180: } ! 1181: *value = m; ! 1182: break; ! 1183: ! 1184: case PRCO_SETOPT: ! 1185: if (value == 0 || *value == 0) { ! 1186: error = EINVAL; ! 1187: break; ! 1188: } ! 1189: switch (name) { ! 1190: int *ok; ! 1191: ! 1192: case SO_HEADERS_ON_INPUT: ! 1193: mask = SF_HI; ! 1194: goto set_head; ! 1195: ! 1196: case SO_HEADERS_ON_OUTPUT: ! 1197: mask = SF_HO; ! 1198: set_head: ! 1199: if (cb->s_flags & SF_PI) { ! 1200: ok = mtod(*value, int *); ! 1201: if (*ok) ! 1202: cb->s_flags |= mask; ! 1203: else ! 1204: cb->s_flags &= ~mask; ! 1205: } else error = EINVAL; ! 1206: break; ! 1207: ! 1208: case SO_MTU: ! 1209: cb->s_mtu = *(mtod(*value, u_short *)); ! 1210: break; ! 1211: ! 1212: #ifdef SF_NEWCALL ! 1213: case SO_NEWCALL: ! 1214: ok = mtod(*value, int *); ! 1215: if (*ok) { ! 1216: cb->s_flags2 |= SF_NEWCALL; ! 1217: spp_newchecks[5]++; ! 1218: } else { ! 1219: cb->s_flags2 &= ~SF_NEWCALL; ! 1220: spp_newchecks[6]++; ! 1221: } ! 1222: break; ! 1223: #endif ! 1224: ! 1225: case SO_DEFAULT_HEADERS: ! 1226: { ! 1227: register struct sphdr *sp ! 1228: = mtod(*value, struct sphdr *); ! 1229: cb->s_dt = sp->sp_dt; ! 1230: cb->s_cc = sp->sp_cc & SP_EM; ! 1231: } ! 1232: break; ! 1233: ! 1234: default: ! 1235: error = EINVAL; ! 1236: } ! 1237: m_freem(*value); ! 1238: break; ! 1239: } ! 1240: release: ! 1241: return (error); ! 1242: } ! 1243: ! 1244: /*ARGSUSED*/ ! 1245: spp_usrreq(so, req, m, nam, controlp) ! 1246: struct socket *so; ! 1247: int req; ! 1248: struct mbuf *m, *nam, *controlp; ! 1249: { ! 1250: struct nspcb *nsp = sotonspcb(so); ! 1251: register struct sppcb *cb; ! 1252: int s = splnet(); ! 1253: int error = 0, ostate; ! 1254: struct mbuf *mm; ! 1255: register struct sockbuf *sb; ! 1256: ! 1257: if (req == PRU_CONTROL) ! 1258: return (ns_control(so, (int)m, (caddr_t)nam, ! 1259: (struct ifnet *)controlp)); ! 1260: if (nsp == NULL) { ! 1261: if (req != PRU_ATTACH) { ! 1262: error = EINVAL; ! 1263: goto release; ! 1264: } ! 1265: } else ! 1266: cb = nstosppcb(nsp); ! 1267: ! 1268: ostate = cb ? cb->s_state : 0; ! 1269: ! 1270: switch (req) { ! 1271: ! 1272: case PRU_ATTACH: ! 1273: if (nsp != NULL) { ! 1274: error = EISCONN; ! 1275: break; ! 1276: } ! 1277: error = ns_pcballoc(so, &nspcb); ! 1278: if (error) ! 1279: break; ! 1280: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { ! 1281: error = soreserve(so, (u_long) 3072, (u_long) 3072); ! 1282: if (error) ! 1283: break; ! 1284: } ! 1285: nsp = sotonspcb(so); ! 1286: ! 1287: mm = m_getclr(M_DONTWAIT, MT_PCB); ! 1288: sb = &so->so_snd; ! 1289: ! 1290: if (mm == NULL) { ! 1291: error = ENOBUFS; ! 1292: break; ! 1293: } ! 1294: cb = mtod(mm, struct sppcb *); ! 1295: mm = m_getclr(M_DONTWAIT, MT_HEADER); ! 1296: if (mm == NULL) { ! 1297: (void) m_free(dtom(m)); ! 1298: error = ENOBUFS; ! 1299: break; ! 1300: } ! 1301: cb->s_idp = mtod(mm, struct idp *); ! 1302: cb->s_state = TCPS_LISTEN; ! 1303: cb->s_smax = -1; ! 1304: cb->s_swl1 = -1; ! 1305: cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; ! 1306: cb->s_nspcb = nsp; ! 1307: cb->s_mtu = 576 - sizeof (struct spidp); ! 1308: cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; ! 1309: cb->s_ssthresh = cb->s_cwnd; ! 1310: cb->s_cwmx = sbspace(sb) * CUNIT / ! 1311: (2 * sizeof (struct spidp)); ! 1312: /* Above is recomputed when connecting to account ! 1313: for changed buffering or mtu's */ ! 1314: cb->s_rtt = SPPTV_SRTTBASE; ! 1315: cb->s_rttvar = SPPTV_SRTTDFLT << 2; ! 1316: SPPT_RANGESET(cb->s_rxtcur, ! 1317: ((SPPTV_SRTTBASE >> 2) + (SPPTV_SRTTDFLT << 2)) >> 1, ! 1318: SPPTV_MIN, SPPTV_REXMTMAX); ! 1319: nsp->nsp_pcb = (caddr_t) cb; ! 1320: break; ! 1321: ! 1322: case PRU_DETACH: ! 1323: if (nsp == NULL) { ! 1324: error = ENOTCONN; ! 1325: break; ! 1326: } ! 1327: if (cb->s_state > TCPS_LISTEN) ! 1328: cb = spp_disconnect(cb); ! 1329: else ! 1330: cb = spp_close(cb); ! 1331: break; ! 1332: ! 1333: case PRU_BIND: ! 1334: error = ns_pcbbind(nsp, nam); ! 1335: break; ! 1336: ! 1337: case PRU_LISTEN: ! 1338: if (nsp->nsp_lport == 0) ! 1339: error = ns_pcbbind(nsp, (struct mbuf *)0); ! 1340: if (error == 0) ! 1341: cb->s_state = TCPS_LISTEN; ! 1342: break; ! 1343: ! 1344: /* ! 1345: * Initiate connection to peer. ! 1346: * Enter SYN_SENT state, and mark socket as connecting. ! 1347: * Start keep-alive timer, setup prototype header, ! 1348: * Send initial system packet requesting connection. ! 1349: */ ! 1350: case PRU_CONNECT: ! 1351: if (nsp->nsp_lport == 0) { ! 1352: error = ns_pcbbind(nsp, (struct mbuf *)0); ! 1353: if (error) ! 1354: break; ! 1355: } ! 1356: error = ns_pcbconnect(nsp, nam); ! 1357: if (error) ! 1358: break; ! 1359: soisconnecting(so); ! 1360: sppstat.spps_connattempt++; ! 1361: cb->s_state = TCPS_SYN_SENT; ! 1362: cb->s_did = 0; ! 1363: spp_template(cb); ! 1364: cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; ! 1365: cb->s_force = 1 + SPPTV_KEEP; ! 1366: /* ! 1367: * Other party is required to respond to ! 1368: * the port I send from, but he is not ! 1369: * required to answer from where I am sending to, ! 1370: * so allow wildcarding. ! 1371: * original port I am sending to is still saved in ! 1372: * cb->s_dport. ! 1373: */ ! 1374: nsp->nsp_fport = 0; ! 1375: error = spp_output(cb, (struct mbuf *) 0); ! 1376: break; ! 1377: ! 1378: case PRU_CONNECT2: ! 1379: error = EOPNOTSUPP; ! 1380: break; ! 1381: ! 1382: /* ! 1383: * We may decide later to implement connection closing ! 1384: * handshaking at the spp level optionally. ! 1385: * here is the hook to do it: ! 1386: */ ! 1387: case PRU_DISCONNECT: ! 1388: cb = spp_disconnect(cb); ! 1389: break; ! 1390: ! 1391: /* ! 1392: * Accept a connection. Essentially all the work is ! 1393: * done at higher levels; just return the address ! 1394: * of the peer, storing through addr. ! 1395: */ ! 1396: case PRU_ACCEPT: { ! 1397: struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); ! 1398: ! 1399: nam->m_len = sizeof (struct sockaddr_ns); ! 1400: sns->sns_family = AF_NS; ! 1401: sns->sns_addr = nsp->nsp_faddr; ! 1402: break; ! 1403: } ! 1404: ! 1405: case PRU_SHUTDOWN: ! 1406: socantsendmore(so); ! 1407: cb = spp_usrclosed(cb); ! 1408: if (cb) ! 1409: error = spp_output(cb, (struct mbuf *) 0); ! 1410: break; ! 1411: ! 1412: /* ! 1413: * After a receive, possibly send acknowledgment ! 1414: * updating allocation. ! 1415: */ ! 1416: case PRU_RCVD: ! 1417: cb->s_flags |= SF_RVD; ! 1418: (void) spp_output(cb, (struct mbuf *) 0); ! 1419: cb->s_flags &= ~SF_RVD; ! 1420: break; ! 1421: ! 1422: case PRU_ABORT: ! 1423: (void) spp_drop(cb, ECONNABORTED); ! 1424: break; ! 1425: ! 1426: case PRU_SENSE: ! 1427: case PRU_CONTROL: ! 1428: m = NULL; ! 1429: error = EOPNOTSUPP; ! 1430: break; ! 1431: ! 1432: case PRU_RCVOOB: ! 1433: if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || ! 1434: (so->so_state & SS_RCVATMARK)) { ! 1435: m->m_len = 1; ! 1436: *mtod(m, caddr_t) = cb->s_iobc; ! 1437: break; ! 1438: } ! 1439: error = EINVAL; ! 1440: break; ! 1441: ! 1442: case PRU_SENDOOB: ! 1443: if (sbspace(&so->so_snd) < -512) { ! 1444: error = ENOBUFS; ! 1445: break; ! 1446: } ! 1447: cb->s_oobflags |= SF_SOOB; ! 1448: /* fall into */ ! 1449: case PRU_SEND: ! 1450: if (controlp) { ! 1451: u_short *p = mtod(controlp, u_short *); ! 1452: spp_newchecks[2]++; ! 1453: if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */ ! 1454: cb->s_shdr.sp_dt = *(u_char *)(&p[2]); ! 1455: spp_newchecks[3]++; ! 1456: } ! 1457: m_freem(controlp); ! 1458: } ! 1459: controlp = NULL; ! 1460: error = spp_output(cb, m); ! 1461: m = NULL; ! 1462: break; ! 1463: ! 1464: case PRU_SOCKADDR: ! 1465: ns_setsockaddr(nsp, nam); ! 1466: break; ! 1467: ! 1468: case PRU_PEERADDR: ! 1469: ns_setpeeraddr(nsp, nam); ! 1470: break; ! 1471: ! 1472: case PRU_SLOWTIMO: ! 1473: cb = spp_timers(cb, (int)nam); ! 1474: req |= ((int)nam) << 8; ! 1475: break; ! 1476: ! 1477: case PRU_FASTTIMO: ! 1478: case PRU_PROTORCV: ! 1479: case PRU_PROTOSEND: ! 1480: error = EOPNOTSUPP; ! 1481: break; ! 1482: ! 1483: default: ! 1484: panic("sp_usrreq"); ! 1485: } ! 1486: if (cb && (so->so_options & SO_DEBUG || traceallspps)) ! 1487: spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); ! 1488: release: ! 1489: if (controlp != NULL) ! 1490: m_freem(controlp); ! 1491: if (m != NULL) ! 1492: m_freem(m); ! 1493: splx(s); ! 1494: return (error); ! 1495: } ! 1496: ! 1497: spp_usrreq_sp(so, req, m, nam, controlp) ! 1498: struct socket *so; ! 1499: int req; ! 1500: struct mbuf *m, *nam, *controlp; ! 1501: { ! 1502: int error = spp_usrreq(so, req, m, nam, controlp); ! 1503: ! 1504: if (req == PRU_ATTACH && error == 0) { ! 1505: struct nspcb *nsp = sotonspcb(so); ! 1506: ((struct sppcb *)nsp->nsp_pcb)->s_flags |= ! 1507: (SF_HI | SF_HO | SF_PI); ! 1508: } ! 1509: return (error); ! 1510: } ! 1511: ! 1512: /* ! 1513: * Create template to be used to send spp packets on a connection. ! 1514: * Called after host entry created, fills ! 1515: * in a skeletal spp header (choosing connection id), ! 1516: * minimizing the amount of work necessary when the connection is used. ! 1517: */ ! 1518: spp_template(cb) ! 1519: register struct sppcb *cb; ! 1520: { ! 1521: register struct nspcb *nsp = cb->s_nspcb; ! 1522: register struct idp *idp = cb->s_idp; ! 1523: register struct sockbuf *sb = &(nsp->nsp_socket->so_snd); ! 1524: ! 1525: idp->idp_pt = NSPROTO_SPP; ! 1526: idp->idp_sna = nsp->nsp_laddr; ! 1527: idp->idp_dna = nsp->nsp_faddr; ! 1528: cb->s_sid = htons(spp_iss); ! 1529: spp_iss += SPP_ISSINCR/2; ! 1530: cb->s_alo = 1; ! 1531: cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; ! 1532: cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement ! 1533: of large packets */ ! 1534: cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spidp)); ! 1535: cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); ! 1536: /* But allow for lots of little packets as well */ ! 1537: } ! 1538: ! 1539: /* ! 1540: * Close a SPIP control block: ! 1541: * discard spp control block itself ! 1542: * discard ns protocol control block ! 1543: * wake up any sleepers ! 1544: */ ! 1545: struct sppcb * ! 1546: spp_close(cb) ! 1547: register struct sppcb *cb; ! 1548: { ! 1549: register struct spidp_q *s; ! 1550: struct nspcb *nsp = cb->s_nspcb; ! 1551: struct socket *so = nsp->nsp_socket; ! 1552: register struct mbuf *m; ! 1553: ! 1554: s = cb->s_q.si_next; ! 1555: while (s != &(cb->s_q)) { ! 1556: s = s->si_next; ! 1557: m = dtom(s->si_prev); ! 1558: remque(s->si_prev); ! 1559: m_freem(m); ! 1560: } ! 1561: (void) m_free(dtom(cb->s_idp)); ! 1562: (void) m_free(dtom(cb)); ! 1563: nsp->nsp_pcb = 0; ! 1564: soisdisconnected(so); ! 1565: ns_pcbdetach(nsp); ! 1566: sppstat.spps_closed++; ! 1567: return ((struct sppcb *)0); ! 1568: } ! 1569: /* ! 1570: * Someday we may do level 3 handshaking ! 1571: * to close a connection or send a xerox style error. ! 1572: * For now, just close. ! 1573: */ ! 1574: struct sppcb * ! 1575: spp_usrclosed(cb) ! 1576: register struct sppcb *cb; ! 1577: { ! 1578: return (spp_close(cb)); ! 1579: } ! 1580: struct sppcb * ! 1581: spp_disconnect(cb) ! 1582: register struct sppcb *cb; ! 1583: { ! 1584: return (spp_close(cb)); ! 1585: } ! 1586: /* ! 1587: * Drop connection, reporting ! 1588: * the specified error. ! 1589: */ ! 1590: struct sppcb * ! 1591: spp_drop(cb, errno) ! 1592: register struct sppcb *cb; ! 1593: int errno; ! 1594: { ! 1595: struct socket *so = cb->s_nspcb->nsp_socket; ! 1596: ! 1597: /* ! 1598: * someday, in the xerox world ! 1599: * we will generate error protocol packets ! 1600: * announcing that the socket has gone away. ! 1601: */ ! 1602: if (TCPS_HAVERCVDSYN(cb->s_state)) { ! 1603: sppstat.spps_drops++; ! 1604: cb->s_state = TCPS_CLOSED; ! 1605: /*(void) tcp_output(cb);*/ ! 1606: } else ! 1607: sppstat.spps_conndrops++; ! 1608: so->so_error = errno; ! 1609: return (spp_close(cb)); ! 1610: } ! 1611: ! 1612: spp_abort(nsp) ! 1613: struct nspcb *nsp; ! 1614: { ! 1615: ! 1616: (void) spp_close((struct sppcb *)nsp->nsp_pcb); ! 1617: } ! 1618: ! 1619: int spp_backoff[SPP_MAXRXTSHIFT+1] = ! 1620: { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; ! 1621: /* ! 1622: * Fast timeout routine for processing delayed acks ! 1623: */ ! 1624: spp_fasttimo() ! 1625: { ! 1626: register struct nspcb *nsp; ! 1627: register struct sppcb *cb; ! 1628: int s = splnet(); ! 1629: ! 1630: nsp = nspcb.nsp_next; ! 1631: if (nsp) ! 1632: for (; nsp != &nspcb; nsp = nsp->nsp_next) ! 1633: if ((cb = (struct sppcb *)nsp->nsp_pcb) && ! 1634: (cb->s_flags & SF_DELACK)) { ! 1635: cb->s_flags &= ~SF_DELACK; ! 1636: cb->s_flags |= SF_ACKNOW; ! 1637: sppstat.spps_delack++; ! 1638: (void) spp_output(cb, (struct mbuf *) 0); ! 1639: } ! 1640: splx(s); ! 1641: } ! 1642: ! 1643: /* ! 1644: * spp protocol timeout routine called every 500 ms. ! 1645: * Updates the timers in all active pcb's and ! 1646: * causes finite state machine actions if timers expire. ! 1647: */ ! 1648: spp_slowtimo() ! 1649: { ! 1650: register struct nspcb *ip, *ipnxt; ! 1651: register struct sppcb *cb; ! 1652: int s = splnet(); ! 1653: register int i; ! 1654: ! 1655: /* ! 1656: * Search through tcb's and update active timers. ! 1657: */ ! 1658: ip = nspcb.nsp_next; ! 1659: if (ip == 0) { ! 1660: splx(s); ! 1661: return; ! 1662: } ! 1663: while (ip != &nspcb) { ! 1664: cb = nstosppcb(ip); ! 1665: ipnxt = ip->nsp_next; ! 1666: if (cb == 0) ! 1667: goto tpgone; ! 1668: for (i = 0; i < SPPT_NTIMERS; i++) { ! 1669: if (cb->s_timer[i] && --cb->s_timer[i] == 0) { ! 1670: (void) spp_usrreq(cb->s_nspcb->nsp_socket, ! 1671: PRU_SLOWTIMO, (struct mbuf *)0, ! 1672: (struct mbuf *)i, (struct mbuf *)0, ! 1673: (struct mbuf *)0); ! 1674: if (ipnxt->nsp_prev != ip) ! 1675: goto tpgone; ! 1676: } ! 1677: } ! 1678: cb->s_idle++; ! 1679: if (cb->s_rtt) ! 1680: cb->s_rtt++; ! 1681: tpgone: ! 1682: ip = ipnxt; ! 1683: } ! 1684: spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ ! 1685: splx(s); ! 1686: } ! 1687: /* ! 1688: * SPP timer processing. ! 1689: */ ! 1690: struct sppcb * ! 1691: spp_timers(cb, timer) ! 1692: register struct sppcb *cb; ! 1693: int timer; ! 1694: { ! 1695: long rexmt; ! 1696: int win; ! 1697: ! 1698: cb->s_force = 1 + timer; ! 1699: switch (timer) { ! 1700: ! 1701: /* ! 1702: * 2 MSL timeout in shutdown went off. TCP deletes connection ! 1703: * control block. ! 1704: */ ! 1705: case SPPT_2MSL: ! 1706: printf("spp: SPPT_2MSL went off for no reason\n"); ! 1707: cb->s_timer[timer] = 0; ! 1708: break; ! 1709: ! 1710: /* ! 1711: * Retransmission timer went off. Message has not ! 1712: * been acked within retransmit interval. Back off ! 1713: * to a longer retransmit interval and retransmit one packet. ! 1714: */ ! 1715: case SPPT_REXMT: ! 1716: if (++cb->s_rxtshift > SPP_MAXRXTSHIFT) { ! 1717: cb->s_rxtshift = SPP_MAXRXTSHIFT; ! 1718: sppstat.spps_timeoutdrop++; ! 1719: cb = spp_drop(cb, ETIMEDOUT); ! 1720: break; ! 1721: } ! 1722: sppstat.spps_rexmttimeo++; ! 1723: rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; ! 1724: rexmt *= spp_backoff[cb->s_rxtshift]; ! 1725: SPPT_RANGESET(cb->s_rxtcur, rexmt, SPPTV_MIN, SPPTV_REXMTMAX); ! 1726: cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; ! 1727: /* ! 1728: * If we have backed off fairly far, our srtt ! 1729: * estimate is probably bogus. Clobber it ! 1730: * so we'll take the next rtt measurement as our srtt; ! 1731: * move the current srtt into rttvar to keep the current ! 1732: * retransmit times until then. ! 1733: */ ! 1734: if (cb->s_rxtshift > SPP_MAXRXTSHIFT / 4 ) { ! 1735: cb->s_rttvar += (cb->s_srtt >> 2); ! 1736: cb->s_srtt = 0; ! 1737: } ! 1738: cb->s_snxt = cb->s_rack; ! 1739: /* ! 1740: * If timing a packet, stop the timer. ! 1741: */ ! 1742: cb->s_rtt = 0; ! 1743: /* ! 1744: * See very long discussion in tcp_timer.c about congestion ! 1745: * window and sstrhesh ! 1746: */ ! 1747: win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; ! 1748: if (win < 2) ! 1749: win = 2; ! 1750: cb->s_cwnd = CUNIT; ! 1751: cb->s_ssthresh = win * CUNIT; ! 1752: (void) spp_output(cb, (struct mbuf *) 0); ! 1753: break; ! 1754: ! 1755: /* ! 1756: * Persistance timer into zero window. ! 1757: * Force a probe to be sent. ! 1758: */ ! 1759: case SPPT_PERSIST: ! 1760: sppstat.spps_persisttimeo++; ! 1761: spp_setpersist(cb); ! 1762: (void) spp_output(cb, (struct mbuf *) 0); ! 1763: break; ! 1764: ! 1765: /* ! 1766: * Keep-alive timer went off; send something ! 1767: * or drop connection if idle for too long. ! 1768: */ ! 1769: case SPPT_KEEP: ! 1770: sppstat.spps_keeptimeo++; ! 1771: if (cb->s_state < TCPS_ESTABLISHED) ! 1772: goto dropit; ! 1773: if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { ! 1774: if (cb->s_idle >= SPPTV_MAXIDLE) ! 1775: goto dropit; ! 1776: sppstat.spps_keepprobe++; ! 1777: (void) spp_output(cb, (struct mbuf *) 0); ! 1778: } else ! 1779: cb->s_idle = 0; ! 1780: cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; ! 1781: break; ! 1782: dropit: ! 1783: sppstat.spps_keepdrops++; ! 1784: cb = spp_drop(cb, ETIMEDOUT); ! 1785: break; ! 1786: } ! 1787: return (cb); ! 1788: } ! 1789: #ifndef lint ! 1790: int SppcbSize = sizeof (struct sppcb); ! 1791: int NspcbSize = sizeof (struct nspcb); ! 1792: #endif lint
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.