# 2.11BSD#431 - /usr/src/sys/netns/spp_usrreq.c

##### Functions

    spp_abort         X
    spp_close         X
    spp_ctlinput      X
    spp_ctloutput     X
    spp_disconnect    X
    spp_drop          X
    spp_fasttimo      X
    spp_fixmtu        X
    spp_init          X
    spp_input         X
    spp_output        X
    spp_quench        X
    spp_reass         X
    spp_setpersist    X
    spp_slowtimo      X
    spp_template      X
    spp_timers        X
    spp_usrclosed     X
    spp_usrreq        X
    spp_usrreq_sp     X

##### Variables

    NspcbSize         X
    SppcbSize         X
    spp_backoff       X
    spp_do_persist_panicsX
    spp_hardnosed     X
    spp_savesi        X
    spp_use_delack    X
    spprexmtthresh    X
    traceallspps      X

##### Macros

    SPINC             X
    THREEWAYSHAKE     X

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

#### Defined functions

spp_abort defined in line 1533; used 2 times

- in line 526, 560

spp_close defined in line 1466; used 5 times

- in line 1263, 1499, 1505, 1530, 1537

spp_ctlinput defined in line 520; never used
spp_ctloutput defined in line 1060; never used
spp_disconnect defined in line 1501; used 2 times

- in line 1261, 1321

spp_drop defined in line 1511; used 4 times

- in line 569, 1356, 1639, 1704

spp_fasttimo defined in line 1545; never used
spp_fixmtu defined in line 594; never used
spp_init defined in line 43; never used
spp_input defined in line 55; never used
spp_output defined in line 642; used 11 times

- in line 240, 309, 683, 1308, 1342, 1351, 1383, 1559, 1672, 1682, 1697

spp_quench defined in line 584; used 2 times

- in line 526, 577

spp_reass defined in line 270; used 1 times

- in line 236

spp_setpersist defined in line 1042; used 2 times

- in line 864, 1681

spp_slowtimo defined in line 1569; never used
spp_template defined in line 1439; used 2 times

- in line 163, 1296

spp_timers defined in line 1610; used 1 times

- in line 1396

spp_usrclosed defined in line 1495; used 1 times

- in line 1340

spp_usrreq defined in line 1176; used 2 times

- in line 1423, 1591

spp_usrreq_sp defined in line 1418; never used

#### Defined variables

NspcbSize defined in line 1711; never used
SppcbSize defined in line 1710; never used
spp_backoff defined in line 1540; used 3 times

- in line 1046, 1054, 1644

spp_do_persist_panics defined in line 1040; used 1 times

- in line 1048

spp_hardnosed defined in line 51; used 1 times

- in line 142

spp_savesi defined in line 48; used 4 times

- in line 90, 231, 252, 259

spp_use_delack defined in line 52; used 1 times

- in line 287

spprexmtthresh defined in line 263; used 1 times

- in line 302

traceallspps defined in line 49; used 7 times

- in line 88, 230, 251, 258, 945, 1012, 1409

#### Defined macros

SPINC defined in line 484; used 2 times

- in line 509-510(2)

THREEWAYSHAKE defined in line 168; used 1 times

- in line 169

Last modified: 1988-04-29 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 4491 |