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