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

Defined functions

spp_abort defined in line 1222; used 2 times
spp_close defined in line 1159; used 7 times
spp_ctlinput defined in line 377; used 4 times
spp_ctloutput defined in line 785; used 3 times
spp_disconnect defined in line 1192; used 3 times
spp_drop defined in line 1202; used 5 times
spp_fasttimo defined in line 1249; used 2 times
spp_fixmtu defined in line 436; never used
spp_init defined in line 36; used 2 times
spp_input defined in line 48; used 4 times
spp_output defined in line 486; used 10 times
spp_reass defined in line 237; used 1 times
spp_setpersist defined in line 1229; used 2 times
spp_slowtimo defined in line 1273; used 2 times
spp_template defined in line 1138; used 2 times
spp_timers defined in line 1318; used 2 times
spp_usrclosed defined in line 1186; used 2 times
spp_usrreq defined in line 901; used 4 times
spp_usrreq_sp defined in line 1117; used 2 times

Defined variables

spp_backoff defined in line 1312; used 1 times
spp_ftcnt defined in line 1248; used 1 times
spp_hardnosed defined in line 44; used 1 times
spp_output_cnt defined in line 484; used 1 times
spp_savesi defined in line 41; used 4 times
spp_use_delack defined in line 45; used 1 times
sppexprexmtbackoff defined in line 1314; used 1 times
traceallspps defined in line 42; used 8 times

Defined macros

SPINC defined in line 342; used 2 times
THREEWAYSHAKE defined in line 153; used 1 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4059
Valid CSS Valid XHTML 1.0 Strict