123215Smckusick /* 232597Ssklower * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 333371Ssklower * All rights reserved. 423215Smckusick * 533371Ssklower * Redistribution and use in source and binary forms are permitted 633371Ssklower * provided that this notice is preserved and that due credit is given 733371Ssklower * to the University of California at Berkeley. The name of the University 833371Ssklower * may not be used to endorse or promote products derived from this 933371Ssklower * software without specific prior written permission. This software 1033371Ssklower * is provided ``as is'' without express or implied warranty. 1133371Ssklower * 12*34486Skarels * @(#)spp_usrreq.c 7.7 (Berkeley) 05/25/88 1323215Smckusick */ 1421496Ssklower 1521496Ssklower #include "param.h" 1629925Skarels #include "systm.h" 1721496Ssklower #include "dir.h" 1821496Ssklower #include "user.h" 1921496Ssklower #include "mbuf.h" 2021496Ssklower #include "protosw.h" 2121496Ssklower #include "socket.h" 2221496Ssklower #include "socketvar.h" 2321496Ssklower #include "errno.h" 2421496Ssklower 2521496Ssklower #include "../net/if.h" 2621496Ssklower #include "../net/route.h" 2721496Ssklower #include "../netinet/tcp_fsm.h" 2821496Ssklower 2921496Ssklower #include "ns.h" 3021496Ssklower #include "ns_pcb.h" 3121496Ssklower #include "idp.h" 3221496Ssklower #include "idp_var.h" 3321496Ssklower #include "ns_error.h" 3421496Ssklower #include "sp.h" 3521496Ssklower #include "spidp.h" 3633719Skarels #include "spp_timer.h" 3721496Ssklower #include "spp_var.h" 3821496Ssklower #include "spp_debug.h" 3921496Ssklower 4021496Ssklower /* 4121496Ssklower * SP protocol implementation. 4221496Ssklower */ 4321496Ssklower spp_init() 4421496Ssklower { 4521496Ssklower 4621496Ssklower spp_iss = 1; /* WRONG !! should fish it out of TODR */ 4721496Ssklower } 4821496Ssklower struct spidp spp_savesi; 4921496Ssklower int traceallspps = 0; 5021496Ssklower extern int sppconsdebug; 5124615Ssklower int spp_hardnosed; 5225037Ssklower int spp_use_delack = 0; 5321496Ssklower 5424615Ssklower /*ARGSUSED*/ 5524615Ssklower spp_input(m, nsp, ifp) 5621496Ssklower register struct mbuf *m; 5724047Ssklower register struct nspcb *nsp; 5824615Ssklower struct ifnet *ifp; 5921496Ssklower { 6021496Ssklower register struct sppcb *cb; 6121496Ssklower register struct spidp *si = mtod(m, struct spidp *); 6221496Ssklower register struct socket *so; 6324225Ssklower short ostate; 6421496Ssklower int dropsocket = 0; 6521496Ssklower 6621496Ssklower 6732597Ssklower sppstat.spps_rcvtotal++; 6824330Ssklower if (nsp == 0) { 6924047Ssklower panic("No nspcb in spp_input\n"); 7023979Ssklower return; 7123979Ssklower } 7221496Ssklower 7321496Ssklower cb = nstosppcb(nsp); 7421496Ssklower if (cb == 0) goto bad; 7521496Ssklower 7624047Ssklower if (m->m_len < sizeof(*si)) { 7724330Ssklower if ((m = m_pullup(m, sizeof(*si))) == 0) { 7832597Ssklower sppstat.spps_rcvshort++; 7924047Ssklower return; 8024047Ssklower } 8124047Ssklower si = mtod(m, struct spidp *); 8224047Ssklower } 8321496Ssklower si->si_seq = ntohs(si->si_seq); 8421496Ssklower si->si_ack = ntohs(si->si_ack); 8521496Ssklower si->si_alo = ntohs(si->si_alo); 8621496Ssklower 8721496Ssklower so = nsp->nsp_socket; 8821496Ssklower if (so->so_options & SO_DEBUG || traceallspps) { 8921496Ssklower ostate = cb->s_state; 9021496Ssklower spp_savesi = *si; 9121496Ssklower } 9221496Ssklower if (so->so_options & SO_ACCEPTCONN) { 9332597Ssklower struct sppcb *ocb = cb; 94*34486Skarels 9521496Ssklower so = sonewconn(so); 9621496Ssklower if (so == 0) { 9721496Ssklower goto drop; 9821496Ssklower } 9921496Ssklower /* 10021496Ssklower * This is ugly, but .... 10121496Ssklower * 10221496Ssklower * Mark socket as temporary until we're 10321496Ssklower * committed to keeping it. The code at 10421496Ssklower * ``drop'' and ``dropwithreset'' check the 10521496Ssklower * flag dropsocket to see if the temporary 10621496Ssklower * socket created here should be discarded. 10721496Ssklower * We mark the socket as discardable until 10821496Ssklower * we're committed to it below in TCPS_LISTEN. 10921496Ssklower */ 11021496Ssklower dropsocket++; 11121496Ssklower nsp = (struct nspcb *)so->so_pcb; 11221496Ssklower nsp->nsp_laddr = si->si_dna; 11321496Ssklower cb = nstosppcb(nsp); 11432597Ssklower cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ 11532597Ssklower cb->s_flags = ocb->s_flags; /* preserve sockopts */ 11621496Ssklower cb->s_state = TCPS_LISTEN; 11721496Ssklower } 11821496Ssklower 11921496Ssklower /* 12021496Ssklower * Packet received on connection. 12121496Ssklower * reset idle time and keep-alive timer; 12221496Ssklower */ 12321496Ssklower cb->s_idle = 0; 12433719Skarels cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; 12521496Ssklower 12621496Ssklower switch (cb->s_state) { 12723515Ssklower 12821496Ssklower case TCPS_LISTEN:{ 12921496Ssklower struct mbuf *am; 13021496Ssklower register struct sockaddr_ns *sns; 13121496Ssklower struct ns_addr laddr; 13221496Ssklower 13321496Ssklower /* 13421496Ssklower * If somebody here was carying on a conversation 13521496Ssklower * and went away, and his pen pal thinks he can 13621496Ssklower * still talk, we get the misdirected packet. 13721496Ssklower */ 13821496Ssklower if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 13921496Ssklower spp_istat.gonawy++; 14021496Ssklower goto dropwithreset; 14121496Ssklower } 14221496Ssklower am = m_get(M_DONTWAIT, MT_SONAME); 14321496Ssklower if (am == NULL) 14421496Ssklower goto drop; 14521496Ssklower am->m_len = sizeof (struct sockaddr_ns); 14621496Ssklower sns = mtod(am, struct sockaddr_ns *); 14721496Ssklower sns->sns_family = AF_NS; 14821496Ssklower sns->sns_addr = si->si_sna; 14921496Ssklower laddr = nsp->nsp_laddr; 15021496Ssklower if (ns_nullhost(laddr)) 15121496Ssklower nsp->nsp_laddr = si->si_dna; 15221496Ssklower if (ns_pcbconnect(nsp, am)) { 15321496Ssklower nsp->nsp_laddr = laddr; 15421496Ssklower (void) m_free(am); 15521496Ssklower spp_istat.noconn++; 15621496Ssklower goto drop; 15721496Ssklower } 15821496Ssklower (void) m_free(am); 15921496Ssklower spp_template(cb); 16024732Ssklower dropsocket = 0; /* committed to socket */ 16121496Ssklower cb->s_did = si->si_sid; 16221496Ssklower cb->s_rack = si->si_ack; 16321496Ssklower cb->s_ralo = si->si_alo; 16424732Ssklower #define THREEWAYSHAKE 16524732Ssklower #ifdef THREEWAYSHAKE 16624732Ssklower cb->s_state = TCPS_SYN_RECEIVED; 16733719Skarels cb->s_force = 1 + SPPT_KEEP; 16832597Ssklower sppstat.spps_accepts++; 16933719Skarels cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; 17021496Ssklower } 17121496Ssklower break; 17224732Ssklower /* 17324732Ssklower * This state means that we have heard a response 17424732Ssklower * to our acceptance of their connection 17524732Ssklower * It is probably logically unnecessary in this 17624732Ssklower * implementation. 17724732Ssklower */ 17832597Ssklower case TCPS_SYN_RECEIVED: { 17924732Ssklower if (si->si_did!=cb->s_sid) { 18024732Ssklower spp_istat.wrncon++; 18124732Ssklower goto drop; 18224732Ssklower } 18324732Ssklower #endif 18424732Ssklower nsp->nsp_fport = si->si_sport; 18533719Skarels cb->s_timer[SPPT_REXMT] = 0; 18633719Skarels cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; 18724732Ssklower soisconnected(so); 18824732Ssklower cb->s_state = TCPS_ESTABLISHED; 18932597Ssklower sppstat.spps_accepts++; 19032597Ssklower } 19124732Ssklower break; 19221496Ssklower 19321496Ssklower /* 19421496Ssklower * This state means that we have gotten a response 19521496Ssklower * to our attempt to establish a connection. 19623979Ssklower * We fill in the data from the other side, 19723979Ssklower * telling us which port to respond to, instead of the well- 19823979Ssklower * known one we might have sent to in the first place. 19921496Ssklower * We also require that this is a response to our 20023979Ssklower * connection id. 20121496Ssklower */ 20221496Ssklower case TCPS_SYN_SENT: 20321496Ssklower if (si->si_did!=cb->s_sid) { 20421496Ssklower spp_istat.notme++; 20521496Ssklower goto drop; 20621496Ssklower } 20732597Ssklower sppstat.spps_connects++; 20821496Ssklower cb->s_did = si->si_sid; 20921496Ssklower cb->s_rack = si->si_ack; 21021496Ssklower cb->s_ralo = si->si_alo; 21121496Ssklower cb->s_dport = nsp->nsp_fport = si->si_sport; 21233719Skarels cb->s_timer[SPPT_REXMT] = 0; 21332597Ssklower cb->s_flags |= SF_ACKNOW; 21421496Ssklower soisconnected(so); 21521496Ssklower cb->s_state = TCPS_ESTABLISHED; 21632597Ssklower /* Use roundtrip time of connection request for initial rtt */ 21732597Ssklower if (cb->s_rtt) { 21832597Ssklower cb->s_srtt = cb->s_rtt << 3; 21932597Ssklower cb->s_rttvar = cb->s_rtt << 1; 22033719Skarels SPPT_RANGESET(cb->s_rxtcur, 22132597Ssklower ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 22233719Skarels SPPTV_MIN, SPPTV_REXMTMAX); 22332597Ssklower cb->s_rtt = 0; 22432597Ssklower } 22521496Ssklower } 22621496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 22724225Ssklower spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0); 22821496Ssklower 22921496Ssklower m->m_len -= sizeof (struct idp); 23021496Ssklower m->m_off += sizeof (struct idp); 23121496Ssklower 23225037Ssklower if (spp_reass(cb, si)) { 23333637Ssklower (void) m_freem(m); 23421496Ssklower } 23532597Ssklower if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) 23632597Ssklower (void) spp_output(cb, (struct mbuf *)0); 23732597Ssklower cb->s_flags &= ~(SF_WIN|SF_RXT); 23821496Ssklower return; 23921496Ssklower 24021496Ssklower dropwithreset: 24121496Ssklower if (dropsocket) 24221496Ssklower (void) soabort(so); 24321496Ssklower si->si_seq = ntohs(si->si_seq); 24421496Ssklower si->si_ack = ntohs(si->si_ack); 24521496Ssklower si->si_alo = ntohs(si->si_alo); 24621496Ssklower ns_error(dtom(si), NS_ERR_NOSOCK, 0); 24721496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 24824225Ssklower spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 24921496Ssklower return; 25021496Ssklower 25121496Ssklower drop: 25221496Ssklower bad: 25332597Ssklower if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || 25432597Ssklower traceallspps) 25524225Ssklower spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 25621496Ssklower m_freem(m); 25721496Ssklower } 25821496Ssklower 25932597Ssklower int spprexmtthresh = 3; 26032597Ssklower 26121496Ssklower /* 26221496Ssklower * This is structurally similar to the tcp reassembly routine 26321496Ssklower * but its function is somewhat different: It merely queues 26421496Ssklower * packets up, and suppresses duplicates. 26521496Ssklower */ 26625037Ssklower spp_reass(cb, si) 26721496Ssklower register struct sppcb *cb; 26821496Ssklower register struct spidp *si; 26921496Ssklower { 27021496Ssklower register struct spidp_q *q; 27121496Ssklower register struct mbuf *m; 27232597Ssklower register struct socket *so = cb->s_nspcb->nsp_socket; 27321496Ssklower char packetp = cb->s_flags & SF_HI; 27432597Ssklower int incr; 27521496Ssklower char wakeup = 0; 27621496Ssklower 27724330Ssklower if (si == SI(0)) 27821496Ssklower goto present; 27921496Ssklower /* 28021496Ssklower * Update our news from them. 28121496Ssklower */ 28221496Ssklower if (si->si_cc & SP_SA) 28332597Ssklower cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_ACKNOW); 28432597Ssklower if (SSEQ_GT(si->si_alo, cb->s_ralo)) 28532597Ssklower cb->s_flags |= SF_WIN; 28632597Ssklower if (SSEQ_LEQ(si->si_ack, cb->s_rack)) { 28733637Ssklower if ((si->si_cc & SP_SP) && cb->s_rack != (cb->s_smax + 1)) { 28832597Ssklower sppstat.spps_rcvdupack++; 28932597Ssklower /* 29032597Ssklower * If this is a completely duplicate ack 29132597Ssklower * and other conditions hold, we assume 29232597Ssklower * a packet has been dropped and retransmit 29332597Ssklower * it exactly as in tcp_input(). 29432597Ssklower */ 29532597Ssklower if (si->si_ack != cb->s_rack || 29632597Ssklower si->si_alo != cb->s_ralo) 29732597Ssklower cb->s_dupacks = 0; 29832597Ssklower else if (++cb->s_dupacks == spprexmtthresh) { 29932597Ssklower u_short onxt = cb->s_snxt; 30032597Ssklower int cwnd = cb->s_cwnd; 30132597Ssklower 30232597Ssklower cb->s_snxt = si->si_ack; 30332597Ssklower cb->s_cwnd = CUNIT; 30433719Skarels cb->s_force = 1 + SPPT_REXMT; 30533637Ssklower (void) spp_output(cb, (struct mbuf *)0); 30633719Skarels cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; 30732597Ssklower cb->s_rtt = 0; 30832597Ssklower if (cwnd >= 4 * CUNIT) 30932597Ssklower cb->s_cwnd = cwnd / 2; 31032597Ssklower if (SSEQ_GT(onxt, cb->s_snxt)) 31132597Ssklower cb->s_snxt = onxt; 31232597Ssklower return (1); 31332597Ssklower } 31425037Ssklower } else 31532597Ssklower cb->s_dupacks = 0; 31632597Ssklower goto update_window; 31721496Ssklower } 31832597Ssklower cb->s_dupacks = 0; 31932597Ssklower /* 32032597Ssklower * If our correspondent acknowledges data we haven't sent 32132597Ssklower * TCP would drop the packet after acking. We'll be a little 32232597Ssklower * more permissive 32332597Ssklower */ 32432597Ssklower if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) { 32532597Ssklower sppstat.spps_rcvacktoomuch++; 32632597Ssklower si->si_ack = cb->s_smax + 1; 32721496Ssklower } 32832597Ssklower sppstat.spps_rcvackpack++; 32921496Ssklower /* 33032597Ssklower * If transmit timer is running and timed sequence 33132597Ssklower * number was acked, update smoothed round trip time. 33232597Ssklower * See discussion of algorithm in tcp_input.c 33321496Ssklower */ 33432597Ssklower if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 33532597Ssklower sppstat.spps_rttupdated++; 33632597Ssklower if (cb->s_srtt != 0) { 33732597Ssklower register short delta; 33832597Ssklower delta = cb->s_rtt - (cb->s_srtt >> 3); 33932597Ssklower if ((cb->s_srtt += delta) <= 0) 34032597Ssklower cb->s_srtt = 1; 34132597Ssklower if (delta < 0) 34232597Ssklower delta = -delta; 34332597Ssklower delta -= (cb->s_rttvar >> 2); 34432597Ssklower if ((cb->s_rttvar += delta) <= 0) 34532597Ssklower cb->s_rttvar = 1; 34632597Ssklower } else { 34732597Ssklower /* 34832597Ssklower * No rtt measurement yet 34932597Ssklower */ 35032597Ssklower cb->s_srtt = cb->s_rtt << 3; 35132597Ssklower cb->s_rttvar = cb->s_rtt << 1; 35232597Ssklower } 35332597Ssklower cb->s_rtt = 0; 35432597Ssklower cb->s_rxtshift = 0; 35533719Skarels SPPT_RANGESET(cb->s_rxtcur, 35632597Ssklower ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 35733719Skarels SPPTV_MIN, SPPTV_REXMTMAX); 35823561Ssklower } 35921496Ssklower /* 36032597Ssklower * If all outstanding data is acked, stop retransmit 36132597Ssklower * timer and remember to restart (more output or persist). 36232597Ssklower * If there is more data to be acked, restart retransmit 36332597Ssklower * timer, using current (possibly backed-off) value; 36421496Ssklower */ 36532597Ssklower if (si->si_ack == cb->s_smax + 1) { 36633719Skarels cb->s_timer[SPPT_REXMT] = 0; 36732597Ssklower cb->s_flags |= SF_RXT; 36833719Skarels } else if (cb->s_timer[SPPT_PERSIST] == 0) 36933719Skarels cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; 37032597Ssklower /* 37132597Ssklower * When new data is acked, open the congestion window. 37232597Ssklower * If the window gives us less than ssthresh packets 37332597Ssklower * in flight, open exponentially (maxseg at a time). 37432597Ssklower * Otherwise open linearly (maxseg^2 / cwnd at a time). 37532597Ssklower */ 37632597Ssklower incr = CUNIT; 37732597Ssklower if (cb->s_cwnd > cb->s_ssthresh) 37832597Ssklower incr = MAX(incr * incr / cb->s_cwnd, 1); 37932597Ssklower cb->s_cwnd = MIN(cb->s_cwnd + incr, cb->s_cwmx); 38032597Ssklower /* 38132597Ssklower * Trim Acked data from output queue. 38232597Ssklower */ 38333637Ssklower while ((m = so->so_snd.sb_mb) != NULL) { 38432597Ssklower if (SSEQ_LT((mtod(m, struct spidp *))->si_seq, si->si_ack)) 38532597Ssklower sbdroprecord(&so->so_snd); 38632597Ssklower else 38732597Ssklower break; 38823979Ssklower } 38932597Ssklower if ((so->so_snd.sb_flags & SB_WAIT) || so->so_snd.sb_sel) 39032597Ssklower sowwakeup(so); 39132597Ssklower cb->s_rack = si->si_ack; 39232597Ssklower update_window: 39332597Ssklower if (SSEQ_LT(cb->s_snxt, cb->s_rack)) 39432597Ssklower cb->s_snxt = cb->s_rack; 39532597Ssklower if (SSEQ_LT(cb->s_swl1, si->si_seq) || cb->s_swl1 == si->si_seq && 39632597Ssklower (SSEQ_LT(cb->s_swl2, si->si_ack) || 39732597Ssklower cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))) { 39832597Ssklower /* keep track of pure window updates */ 39932597Ssklower if ((si->si_cc & SP_SP) && cb->s_swl2 == si->si_ack 40032597Ssklower && SSEQ_LT(cb->s_ralo, si->si_alo)) { 40132597Ssklower sppstat.spps_rcvwinupd++; 40232597Ssklower sppstat.spps_rcvdupack--; 40332597Ssklower } 40432597Ssklower cb->s_ralo = si->si_alo; 40532597Ssklower cb->s_swl1 = si->si_seq; 40632597Ssklower cb->s_swl2 = si->si_ack; 40732597Ssklower cb->s_swnd = (1 + si->si_alo - si->si_ack); 40832597Ssklower if (cb->s_swnd > cb->s_smxw) 40932597Ssklower cb->s_smxw = cb->s_swnd; 41032597Ssklower cb->s_flags |= SF_WIN; 41132597Ssklower } 41221496Ssklower /* 41321496Ssklower * If this packet number is higher than that which 41421496Ssklower * we have allocated refuse it, unless urgent 41521496Ssklower */ 41625037Ssklower if (SSEQ_GT(si->si_seq, cb->s_alo)) { 41732597Ssklower if (si->si_cc & SP_SP) { 41832597Ssklower sppstat.spps_rcvwinprobe++; 41932597Ssklower return (1); 42032597Ssklower } else 42132597Ssklower sppstat.spps_rcvpackafterwin++; 42225037Ssklower if (si->si_cc & SP_OB) { 42325037Ssklower if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { 42425037Ssklower ns_error(dtom(si), NS_ERR_FULLUP, 0); 42525037Ssklower return (0); 42625037Ssklower } /* else queue this packet; */ 42725037Ssklower } else { 42832597Ssklower /*register struct socket *so = cb->s_nspcb->nsp_socket; 42932597Ssklower if (so->so_state && SS_NOFDREF) { 43032597Ssklower ns_error(dtom(si), NS_ERR_NOSOCK, 0); 43132597Ssklower (void)spp_close(cb); 43232597Ssklower } else 43332597Ssklower would crash system*/ 43425037Ssklower spp_istat.notyet++; 43532597Ssklower ns_error(dtom(si), NS_ERR_FULLUP, 0); 43632597Ssklower return (0); 43725037Ssklower } 43821496Ssklower } 43921496Ssklower /* 44032597Ssklower * If this is a system packet, we don't need to 44132597Ssklower * queue it up, and won't update acknowledge # 44232597Ssklower */ 44332597Ssklower if (si->si_cc & SP_SP) { 44432597Ssklower return (1); 44532597Ssklower } 44632597Ssklower /* 44732597Ssklower * We have already seen this packet, so drop. 44832597Ssklower */ 44932597Ssklower if (SSEQ_LT(si->si_seq, cb->s_ack)) { 45032597Ssklower spp_istat.bdreas++; 45132597Ssklower sppstat.spps_rcvduppack++; 45232597Ssklower if (si->si_seq == cb->s_ack - 1) 45332597Ssklower spp_istat.lstdup++; 45432597Ssklower return (1); 45532597Ssklower } 45632597Ssklower /* 45721496Ssklower * Loop through all packets queued up to insert in 45821496Ssklower * appropriate sequence. 45921496Ssklower */ 46021496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 46132597Ssklower if (si->si_seq == SI(q)->si_seq) { 46232597Ssklower sppstat.spps_rcvduppack++; 46332597Ssklower return (1); 46432597Ssklower } 46532597Ssklower if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { 46632597Ssklower sppstat.spps_rcvoopack++; 46732597Ssklower break; 46832597Ssklower } 46921496Ssklower } 47025037Ssklower insque(si, q->si_prev); 47125037Ssklower /* 47225037Ssklower * If this packet is urgent, inform process 47325037Ssklower */ 47425037Ssklower if (si->si_cc & SP_OB) { 47525037Ssklower cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 47625037Ssklower sohasoutofband(so); 47725037Ssklower cb->s_oobflags |= SF_IOOB; 47825037Ssklower } 47921496Ssklower present: 48021496Ssklower #define SPINC sizeof(struct sphdr) 48121496Ssklower /* 48221496Ssklower * Loop through all packets queued up to update acknowledge 48321496Ssklower * number, and present all acknowledged data to user; 48421496Ssklower * If in packet interface mode, show packet headers. 48521496Ssklower */ 48621496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 48724330Ssklower if (SI(q)->si_seq == cb->s_ack) { 48821496Ssklower cb->s_ack++; 48921496Ssklower m = dtom(q); 49021496Ssklower if (SI(q)->si_cc & SP_OB) { 49125037Ssklower cb->s_oobflags &= ~SF_IOOB; 49232597Ssklower if (so->so_rcv.sb_cc) 49332597Ssklower so->so_oobmark = so->so_rcv.sb_cc; 49421496Ssklower else 49521496Ssklower so->so_state |= SS_RCVATMARK; 49621496Ssklower } 49721496Ssklower q = q->si_prev; 49821496Ssklower remque(q->si_next); 49921496Ssklower wakeup = 1; 50032597Ssklower sppstat.spps_rcvpack++; 50121496Ssklower if (packetp) { 50232597Ssklower sbappendrecord(&so->so_rcv, m); 50321496Ssklower } else { 50421496Ssklower cb->s_rhdr = *mtod(m, struct sphdr *); 50521496Ssklower m->m_off += SPINC; 50621496Ssklower m->m_len -= SPINC; 50732597Ssklower sbappend(&so->so_rcv, m); 50821496Ssklower } 50921496Ssklower } else 51021496Ssklower break; 51121496Ssklower } 51221496Ssklower if (wakeup) sorwakeup(so); 51323515Ssklower return (0); 51421496Ssklower } 51521496Ssklower 51621496Ssklower spp_ctlinput(cmd, arg) 51721496Ssklower int cmd; 51821496Ssklower caddr_t arg; 51921496Ssklower { 52021496Ssklower struct ns_addr *na; 52121496Ssklower extern u_char nsctlerrmap[]; 52232597Ssklower extern spp_abort(), spp_quench(); 52324225Ssklower extern struct nspcb *idp_drop(); 52423979Ssklower struct ns_errp *errp; 52523979Ssklower struct nspcb *nsp; 52624615Ssklower struct sockaddr_ns *sns; 52721496Ssklower int type; 52821496Ssklower 52921496Ssklower if (cmd < 0 || cmd > PRC_NCMDS) 53021496Ssklower return; 53121496Ssklower type = NS_ERR_UNREACH_HOST; 53221496Ssklower 53321496Ssklower switch (cmd) { 53423515Ssklower 53521496Ssklower case PRC_ROUTEDEAD: 53632597Ssklower return; 53721496Ssklower 53821496Ssklower case PRC_IFDOWN: 53921496Ssklower case PRC_HOSTDEAD: 54021496Ssklower case PRC_HOSTUNREACH: 54124615Ssklower sns = (struct sockaddr_ns *)arg; 54224615Ssklower if (sns->sns_family != AF_NS) 54324615Ssklower return; 54424615Ssklower na = &sns->sns_addr; 54521496Ssklower break; 54621496Ssklower 54721496Ssklower default: 54823979Ssklower errp = (struct ns_errp *)arg; 54923979Ssklower na = &errp->ns_err_idp.idp_dna; 55023979Ssklower type = errp->ns_err_num; 55124225Ssklower type = ntohs((u_short)type); 55221496Ssklower } 55321496Ssklower switch (type) { 55423515Ssklower 55521496Ssklower case NS_ERR_UNREACH_HOST: 55623979Ssklower ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0); 55721496Ssklower break; 55823515Ssklower 55921496Ssklower case NS_ERR_TOO_BIG: 56023979Ssklower case NS_ERR_NOSOCK: 56123979Ssklower nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port, 56223979Ssklower NS_WILDCARD); 56323979Ssklower if (nsp) { 56423979Ssklower if(nsp->nsp_pcb) 56524225Ssklower (void) spp_drop((struct sppcb *)nsp->nsp_pcb, 56624225Ssklower (int)nsctlerrmap[cmd]); 56723979Ssklower else 56824225Ssklower (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); 56923979Ssklower } 57032597Ssklower break; 57132597Ssklower 57232597Ssklower case NS_ERR_FULLUP: 57332597Ssklower ns_pcbnotify(na, 0, spp_quench, (long) 0); 57421496Ssklower } 57521496Ssklower } 57632597Ssklower /* 57732597Ssklower * When a source quench is received, close congestion window 57832597Ssklower * to one packet. We will gradually open it again as we proceed. 57932597Ssklower */ 58032597Ssklower spp_quench(nsp) 58132597Ssklower struct nspcb *nsp; 58232597Ssklower { 58332597Ssklower struct sppcb *cb = nstosppcb(nsp); 58421496Ssklower 58532597Ssklower if (cb) 58632597Ssklower cb->s_cwnd = CUNIT; 58732597Ssklower } 58832597Ssklower 58924225Ssklower #ifdef notdef 59021496Ssklower int 59121496Ssklower spp_fixmtu(nsp) 59221496Ssklower register struct nspcb *nsp; 59321496Ssklower { 59421496Ssklower register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); 59521496Ssklower register struct mbuf *m; 59621496Ssklower register struct spidp *si; 59721496Ssklower struct ns_errp *ep; 59821496Ssklower struct sockbuf *sb; 59921496Ssklower int badseq, len; 60021496Ssklower struct mbuf *firstbad, *m0; 60121496Ssklower 60221496Ssklower if (cb) { 60321496Ssklower /* 60421496Ssklower * The notification that we have sent 60521496Ssklower * too much is bad news -- we will 60621496Ssklower * have to go through queued up so far 60721496Ssklower * splitting ones which are too big and 60821496Ssklower * reassigning sequence numbers and checksums. 60921496Ssklower * we should then retransmit all packets from 61021496Ssklower * one above the offending packet to the last one 61121496Ssklower * we had sent (or our allocation) 61221496Ssklower * then the offending one so that the any queued 61321496Ssklower * data at our destination will be discarded. 61421496Ssklower */ 61521496Ssklower ep = (struct ns_errp *)nsp->nsp_notify_param; 61621496Ssklower sb = &nsp->nsp_socket->so_snd; 61721496Ssklower cb->s_mtu = ep->ns_err_param; 61821496Ssklower badseq = SI(&ep->ns_err_idp)->si_seq; 61921496Ssklower for (m = sb->sb_mb; m; m = m->m_act) { 62021496Ssklower si = mtod(m, struct spidp *); 62121496Ssklower if (si->si_seq == badseq) 62221496Ssklower break; 62321496Ssklower } 62424330Ssklower if (m == 0) return; 62521496Ssklower firstbad = m; 62621496Ssklower /*for (;;) {*/ 62721496Ssklower /* calculate length */ 62821496Ssklower for (m0 = m, len = 0; m ; m = m->m_next) 62921496Ssklower len += m->m_len; 63021496Ssklower if (len > cb->s_mtu) { 63121496Ssklower } 63221496Ssklower /* FINISH THIS 63321496Ssklower } */ 63421496Ssklower } 63521496Ssklower } 63624225Ssklower #endif 63721496Ssklower 63821496Ssklower spp_output(cb, m0) 63921496Ssklower register struct sppcb *cb; 64021496Ssklower struct mbuf *m0; 64121496Ssklower { 64221496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 64321496Ssklower register struct mbuf *m; 64421496Ssklower register struct spidp *si = (struct spidp *) 0; 64532597Ssklower register struct sockbuf *sb = &so->so_snd; 64632597Ssklower int len = 0, win, rcv_win; 64732597Ssklower short span, off; 64833637Ssklower u_short alo; 649*34486Skarels int error = 0, sendalot; 650*34486Skarels #ifdef notdef 651*34486Skarels int idle; 652*34486Skarels #endif 65321496Ssklower struct mbuf *mprev; 65421496Ssklower extern int idpcksum; 65521496Ssklower 65624330Ssklower if (m0) { 65724615Ssklower int mtu = cb->s_mtu; 65824615Ssklower int datalen; 65924615Ssklower /* 66024615Ssklower * Make sure that packet isn't too big. 66124615Ssklower */ 66221496Ssklower for (m = m0; m ; m = m->m_next) { 66321496Ssklower mprev = m; 66421496Ssklower len += m->m_len; 66521496Ssklower } 66624615Ssklower datalen = (cb->s_flags & SF_HO) ? 66724615Ssklower len - sizeof (struct sphdr) : len; 66824615Ssklower if (datalen > mtu) { 66921496Ssklower if (cb->s_flags & SF_PI) { 67021496Ssklower m_freem(m0); 67123515Ssklower return (EMSGSIZE); 67221496Ssklower } else { 67324615Ssklower int oldEM = cb->s_cc & SP_EM; 67424615Ssklower 67524615Ssklower cb->s_cc &= ~SP_EM; 67621496Ssklower while (len > mtu) { 67733637Ssklower m = m_copy(m0, 0, mtu); 67824330Ssklower if (m == NULL) { 67924615Ssklower error = ENOBUFS; 68024615Ssklower goto bad_copy; 68123515Ssklower } 68221496Ssklower error = spp_output(cb, m); 68321496Ssklower if (error) { 68424615Ssklower bad_copy: 68524615Ssklower cb->s_cc |= oldEM; 68621496Ssklower m_freem(m0); 68724615Ssklower return(error); 68821496Ssklower } 68921496Ssklower m_adj(m0, mtu); 69021496Ssklower len -= mtu; 69121496Ssklower } 69224615Ssklower cb->s_cc |= oldEM; 69321496Ssklower } 69421496Ssklower } 69524330Ssklower /* 69624330Ssklower * Force length even, by adding a "garbage byte" if 69724330Ssklower * necessary. 69824330Ssklower */ 69921496Ssklower if (len & 1) { 70023979Ssklower m = mprev; 70124330Ssklower if (m->m_len + m->m_off < MMAXOFF) 70221496Ssklower m->m_len++; 70324330Ssklower else { 70421496Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 70521496Ssklower 70621496Ssklower if (m1 == 0) { 70721496Ssklower m_freem(m0); 70821496Ssklower return (ENOBUFS); 70921496Ssklower } 71021496Ssklower m1->m_len = 1; 71121496Ssklower m1->m_off = MMAXOFF - 1; 71224330Ssklower m->m_next = m1; 71321496Ssklower } 71421496Ssklower } 71521496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 71621496Ssklower if (m == 0) { 71721496Ssklower m_freem(m0); 71823515Ssklower return (ENOBUFS); 71921496Ssklower } 72021496Ssklower /* 72121496Ssklower * Fill in mbuf with extended SP header 72221496Ssklower * and addresses and length put into network format. 72325623Ssklower * Long align so prepended ip headers will work on Gould. 72421496Ssklower */ 72525623Ssklower m->m_off = MMAXOFF - sizeof (struct spidp) - 2; 72621496Ssklower m->m_len = sizeof (struct spidp); 72721496Ssklower m->m_next = m0; 72821496Ssklower si = mtod(m, struct spidp *); 72932597Ssklower si->si_i = *cb->s_idp; 73032597Ssklower si->si_s = cb->s_shdr; 73121496Ssklower if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 73224330Ssklower register struct sphdr *sh; 73324330Ssklower if (m0->m_len < sizeof (*sh)) { 73424330Ssklower if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 73524330Ssklower (void) m_free(m); 73624330Ssklower m_freem(m0); 73724330Ssklower return (EINVAL); 73824330Ssklower } 73924330Ssklower m->m_next = m0; 74024330Ssklower } 74124330Ssklower sh = mtod(m0, struct sphdr *); 74221496Ssklower si->si_dt = sh->sp_dt; 74321496Ssklower si->si_cc |= sh->sp_cc & SP_EM; 74421496Ssklower m0->m_len -= sizeof (*sh); 74521496Ssklower m0->m_off += sizeof (*sh); 74621496Ssklower len -= sizeof (*sh); 74721496Ssklower } 74821496Ssklower len += sizeof(*si); 74923979Ssklower if (cb->s_oobflags & SF_SOOB) { 75023979Ssklower /* 75123979Ssklower * Per jqj@cornell: 75223979Ssklower * make sure OB packets convey exactly 1 byte. 75323979Ssklower * If the packet is 1 byte or larger, we 75423979Ssklower * have already guaranted there to be at least 75523979Ssklower * one garbage byte for the checksum, and 75623979Ssklower * extra bytes shouldn't hurt! 75723979Ssklower */ 75823979Ssklower if (len > sizeof(*si)) { 75923979Ssklower si->si_cc |= SP_OB; 76023979Ssklower len = (1 + sizeof(*si)); 76123979Ssklower } 76223979Ssklower } 76324225Ssklower si->si_len = htons((u_short)len); 76421496Ssklower /* 76521496Ssklower * queue stuff up for output 76621496Ssklower */ 76725037Ssklower sbappendrecord(sb, m); 76821496Ssklower cb->s_seq++; 76921496Ssklower } 770*34486Skarels #ifdef notdef 77132597Ssklower idle = (cb->s_smax == (cb->s_rack - 1)); 772*34486Skarels #endif 77332597Ssklower again: 77432597Ssklower sendalot = 0; 77532597Ssklower off = cb->s_snxt - cb->s_rack; 77632597Ssklower win = MIN(cb->s_swnd, (cb->s_cwnd/CUNIT)); 77732597Ssklower 77821496Ssklower /* 77932597Ssklower * If in persist timeout with window of 0, send a probe. 78032597Ssklower * Otherwise, if window is small but nonzero 78132597Ssklower * and timer expired, send what we can and go into 78232597Ssklower * transmit state. 78321496Ssklower */ 78433719Skarels if (cb->s_force == 1 + SPPT_PERSIST) { 78532597Ssklower if (win != 0) { 78633719Skarels cb->s_timer[SPPT_PERSIST] = 0; 78732597Ssklower cb->s_rxtshift = 0; 78832597Ssklower } 78932597Ssklower } 79032597Ssklower span = cb->s_seq - cb->s_rack; 79132597Ssklower len = MIN(span, win) - off; 79221496Ssklower 79332597Ssklower if (len < 0) { 79432597Ssklower /* 79532597Ssklower * Window shrank after we went into it. 79632597Ssklower * If window shrank to 0, cancel pending 79732597Ssklower * restransmission and pull s_snxt back 79832597Ssklower * to (closed) window. We will enter persist 79932597Ssklower * state below. If the widndow didn't close completely, 80032597Ssklower * just wait for an ACK. 80132597Ssklower */ 80232597Ssklower len = 0; 80332597Ssklower if (win == 0) { 80433719Skarels cb->s_timer[SPPT_REXMT] = 0; 80532597Ssklower cb->s_snxt = cb->s_rack; 80624732Ssklower } 80721496Ssklower } 80832597Ssklower if (len > 1) 80932597Ssklower sendalot = 1; 81032597Ssklower rcv_win = sbspace(&so->so_rcv); 81121496Ssklower 81232597Ssklower /* 81332597Ssklower * Send if we owe peer an ACK. 81432597Ssklower */ 81521496Ssklower if (cb->s_oobflags & SF_SOOB) { 81621496Ssklower /* 81721496Ssklower * must transmit this out of band packet 81821496Ssklower */ 81921496Ssklower cb->s_oobflags &= ~ SF_SOOB; 82032597Ssklower sendalot = 1; 82132597Ssklower sppstat.spps_sndurg++; 82232597Ssklower goto found; 82332597Ssklower } 82432597Ssklower if (cb->s_flags & SF_ACKNOW) 82532597Ssklower goto send; 82632597Ssklower if (cb->s_state < TCPS_ESTABLISHED) 82732597Ssklower goto send; 82832597Ssklower /* 82932597Ssklower * Silly window can't happen in spp. 83032597Ssklower * Code from tcp deleted. 83132597Ssklower */ 83232597Ssklower if (len) 83332597Ssklower goto send; 83432597Ssklower /* 83532597Ssklower * Compare available window to amount of window 83632597Ssklower * known to peer (as advertised window less 83732597Ssklower * next expected input.) If the difference is at least two 83832597Ssklower * packets or at least 35% of the mximum possible window, 83932597Ssklower * then want to send a window update to peer. 84032597Ssklower */ 84132597Ssklower if (rcv_win > 0) { 84232597Ssklower u_short delta = 1 + cb->s_alo - cb->s_ack; 84332597Ssklower int adv = rcv_win - (delta * cb->s_mtu); 84432597Ssklower 84532597Ssklower if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || 84632597Ssklower (100 * adv / so->so_rcv.sb_hiwat >= 35)) { 84732597Ssklower sppstat.spps_sndwinup++; 84832597Ssklower cb->s_flags |= SF_ACKNOW; 84932597Ssklower goto send; 85021496Ssklower } 85132597Ssklower 85232597Ssklower } 85332597Ssklower /* 85432597Ssklower * Many comments from tcp_output.c are appropriate here 85532597Ssklower * including . . . 85632597Ssklower * If send window is too small, there is data to transmit, and no 85732597Ssklower * retransmit or persist is pending, then go to persist state. 85832597Ssklower * If nothing happens soon, send when timer expires: 85932597Ssklower * if window is nonzero, transmit what we can, 86032597Ssklower * otherwise send a probe. 86132597Ssklower */ 86233719Skarels if (so->so_snd.sb_cc && cb->s_timer[SPPT_REXMT] == 0 && 86333719Skarels cb->s_timer[SPPT_PERSIST] == 0) { 86432597Ssklower cb->s_rxtshift = 0; 86532597Ssklower spp_setpersist(cb); 86632597Ssklower } 86732597Ssklower /* 86832597Ssklower * No reason to send a packet, just return. 86932597Ssklower */ 87032597Ssklower cb->s_outx = 1; 87132597Ssklower return (0); 87232597Ssklower 87332597Ssklower send: 87432597Ssklower /* 87532597Ssklower * Find requested packet. 87632597Ssklower */ 87732597Ssklower si = 0; 87832597Ssklower if (len > 0) { 87932597Ssklower cb->s_want = cb->s_snxt; 88032597Ssklower for (m = sb->sb_mb; m; m = m->m_act) { 88121496Ssklower si = mtod(m, struct spidp *); 88232597Ssklower if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) 88332597Ssklower break; 88421496Ssklower } 88532597Ssklower found: 88632597Ssklower if (si) { 88732597Ssklower if (si->si_seq == cb->s_snxt) 88832597Ssklower cb->s_snxt++; 88932597Ssklower else 89032597Ssklower sppstat.spps_sndvoid++, si = 0; 89132597Ssklower } 89221496Ssklower } 89332597Ssklower /* 89432597Ssklower * update window 89532597Ssklower */ 89632597Ssklower if (rcv_win < 0) 89732597Ssklower rcv_win = 0; 89833637Ssklower alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); 89932597Ssklower if (SSEQ_LT(alo, cb->s_alo)) 90032597Ssklower alo = cb->s_alo; 90121496Ssklower 90221496Ssklower if (si) { 90321496Ssklower /* 90421496Ssklower * must make a copy of this packet for 90521496Ssklower * idp_output to monkey with 90621496Ssklower */ 90732597Ssklower m = m_copy(dtom(si), 0, (int)M_COPYALL); 90832597Ssklower if (m == NULL) { 90923515Ssklower return (ENOBUFS); 91032597Ssklower } 91132597Ssklower m0 = m; 91232597Ssklower si = mtod(m, struct spidp *); 91332597Ssklower if (SSEQ_LT(si->si_seq, cb->s_smax)) 91432597Ssklower sppstat.spps_sndrexmitpack++; 91532597Ssklower else 91632597Ssklower sppstat.spps_sndpack++; 91732597Ssklower } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { 91821496Ssklower /* 91921496Ssklower * Must send an acknowledgement or a probe 92021496Ssklower */ 92132597Ssklower if (cb->s_force) 92232597Ssklower sppstat.spps_sndprobe++; 92332597Ssklower if (cb->s_flags & SF_ACKNOW) 92432597Ssklower sppstat.spps_sndacks++; 92521496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 92632597Ssklower if (m == 0) { 92723515Ssklower return (ENOBUFS); 92832597Ssklower } 92921496Ssklower /* 93021496Ssklower * Fill in mbuf with extended SP header 93121496Ssklower * and addresses and length put into network format. 93232597Ssklower * Allign beginning of packet to long to prepend 93332597Ssklower * ifp's on loopback, or NSIP encaspulation for fussy cpu's. 93421496Ssklower */ 93532597Ssklower m->m_off = MMAXOFF - sizeof (struct spidp) - 2; 93621496Ssklower m->m_len = sizeof (*si); 93721496Ssklower m->m_next = 0; 93821496Ssklower si = mtod(m, struct spidp *); 93932597Ssklower si->si_i = *cb->s_idp; 94032597Ssklower si->si_s = cb->s_shdr; 94132597Ssklower si->si_seq = cb->s_smax + 1; 94223979Ssklower si->si_len = htons(sizeof (*si)); 94321496Ssklower si->si_cc |= SP_SP; 94432597Ssklower } else { 94532597Ssklower cb->s_outx = 3; 94632597Ssklower if (so->so_options & SO_DEBUG || traceallspps) 94732597Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 94832597Ssklower return (0); 94921496Ssklower } 95021496Ssklower /* 95121496Ssklower * Stuff checksum and output datagram. 95221496Ssklower */ 95332597Ssklower if ((si->si_cc & SP_SP) == 0) { 95433719Skarels if (cb->s_force != (1 + SPPT_PERSIST) || 95533719Skarels cb->s_timer[SPPT_PERSIST] == 0) { 95632597Ssklower /* 95732597Ssklower * If this is a new packet and we are not currently 95832597Ssklower * timing anything, time this one. 95932597Ssklower */ 96032597Ssklower if (SSEQ_LT(cb->s_smax, si->si_seq)) { 96132597Ssklower cb->s_smax = si->si_seq; 96232597Ssklower if (cb->s_rtt == 0) { 96332597Ssklower sppstat.spps_segstimed++; 96432597Ssklower cb->s_rtseq = si->si_seq; 96532597Ssklower cb->s_rtt = 1; 96632597Ssklower } 96721496Ssklower } 96821496Ssklower /* 96932597Ssklower * Set rexmt timer if not currently set, 97032597Ssklower * Initial value for retransmit timer is smoothed 97132597Ssklower * round-trip time + 2 * round-trip time variance. 97232597Ssklower * Initialize shift counter which is used for backoff 97332597Ssklower * of retransmit time. 97421496Ssklower */ 97533719Skarels if (cb->s_timer[SPPT_REXMT] == 0 && 97632597Ssklower cb->s_snxt != cb->s_rack) { 97733719Skarels cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; 97833719Skarels if (cb->s_timer[SPPT_PERSIST]) { 97933719Skarels cb->s_timer[SPPT_PERSIST] = 0; 98032597Ssklower cb->s_rxtshift = 0; 98132597Ssklower } 98221496Ssklower } 98332597Ssklower } else if (SSEQ_LT(cb->s_smax, si->si_seq)) { 98432597Ssklower cb->s_smax = si->si_seq; 98521496Ssklower } 98632597Ssklower } else if (cb->s_state < TCPS_ESTABLISHED) { 98732597Ssklower if (cb->s_rtt == 0) 98832597Ssklower cb->s_rtt = 1; /* Time initial handshake */ 98933719Skarels if (cb->s_timer[SPPT_REXMT] == 0) 99033719Skarels cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; 99132597Ssklower } 99232597Ssklower { 99332597Ssklower /* 99432597Ssklower * Do not request acks when we ack their data packets or 99532597Ssklower * when we do a gratuitous window update. 99632597Ssklower */ 99732597Ssklower if (((si->si_cc & SP_SP) == 0) || cb->s_force) 99832597Ssklower si->si_cc |= SP_SA; 99921496Ssklower si->si_seq = htons(si->si_seq); 100032597Ssklower si->si_alo = htons(alo); 100121496Ssklower si->si_ack = htons(cb->s_ack); 100221496Ssklower 100321496Ssklower if (idpcksum) { 100421496Ssklower si->si_sum = 0; 100523979Ssklower len = ntohs(si->si_len); 100624330Ssklower if (len & 1) 100724330Ssklower len++; 100821496Ssklower si->si_sum = ns_cksum(dtom(si), len); 100921496Ssklower } else 101021496Ssklower si->si_sum = 0xffff; 101121496Ssklower 101232597Ssklower cb->s_outx = 4; 101321496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 101421496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 101532597Ssklower 101621496Ssklower if (so->so_options & SO_DONTROUTE) 101721496Ssklower error = ns_output(m, (struct route *)0, NS_ROUTETOIF); 101821496Ssklower else 101921496Ssklower error = ns_output(m, &cb->s_nspcb->nsp_route, 0); 102021496Ssklower } 102132597Ssklower if (error) { 102232597Ssklower return (error); 102332597Ssklower } 102432597Ssklower sppstat.spps_sndtotal++; 102532597Ssklower /* 102632597Ssklower * Data sent (as far as we can tell). 102732597Ssklower * If this advertises a larger window than any other segment, 102832597Ssklower * then remember the size of the advertized window. 102932597Ssklower * Any pending ACK has now been sent. 103032597Ssklower */ 103132597Ssklower cb->s_force = 0; 103232597Ssklower cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); 103332597Ssklower if (SSEQ_GT(alo, cb->s_alo)) 103432597Ssklower cb->s_alo = alo; 103532597Ssklower if (sendalot) 103632597Ssklower goto again; 103732597Ssklower cb->s_outx = 5; 103832597Ssklower return (0); 103921496Ssklower } 104021496Ssklower 104132597Ssklower int spp_do_persist_panics = 0; 104232597Ssklower 104332597Ssklower spp_setpersist(cb) 104432597Ssklower register struct sppcb *cb; 104532597Ssklower { 104632597Ssklower register t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 104732597Ssklower extern int spp_backoff[]; 104832597Ssklower 104933719Skarels if (cb->s_timer[SPPT_REXMT] && spp_do_persist_panics) 105032597Ssklower panic("spp_output REXMT"); 105132597Ssklower /* 105232597Ssklower * Start/restart persistance timer. 105332597Ssklower */ 105433719Skarels SPPT_RANGESET(cb->s_timer[SPPT_PERSIST], 105532597Ssklower t*spp_backoff[cb->s_rxtshift], 105633719Skarels SPPTV_PERSMIN, SPPTV_PERSMAX); 105733719Skarels if (cb->s_rxtshift < SPP_MAXRXTSHIFT) 105832597Ssklower cb->s_rxtshift++; 105932597Ssklower } 106021496Ssklower /*ARGSUSED*/ 106121496Ssklower spp_ctloutput(req, so, level, name, value) 106221496Ssklower int req; 106321496Ssklower struct socket *so; 106421496Ssklower int name; 106521496Ssklower struct mbuf **value; 106621496Ssklower { 106721496Ssklower register struct mbuf *m; 106821496Ssklower struct nspcb *nsp = sotonspcb(so); 106921496Ssklower register struct sppcb *cb; 107021496Ssklower int mask, error = 0; 107121496Ssklower 107221496Ssklower if (level != NSPROTO_SPP) { 107321496Ssklower /* This will have to be changed when we do more general 107421496Ssklower stacking of protocols */ 107523515Ssklower return (idp_ctloutput(req, so, level, name, value)); 107621496Ssklower } 107721496Ssklower if (nsp == NULL) { 107821496Ssklower error = EINVAL; 107921496Ssklower goto release; 108021496Ssklower } else 108121496Ssklower cb = nstosppcb(nsp); 108221496Ssklower 108321496Ssklower switch (req) { 108423515Ssklower 108521496Ssklower case PRCO_GETOPT: 108624330Ssklower if (value == NULL) 108723515Ssklower return (EINVAL); 108821496Ssklower m = m_get(M_DONTWAIT, MT_DATA); 108924330Ssklower if (m == NULL) 109023515Ssklower return (ENOBUFS); 109121496Ssklower switch (name) { 109223515Ssklower 109321496Ssklower case SO_HEADERS_ON_INPUT: 109421496Ssklower mask = SF_HI; 109521496Ssklower goto get_flags; 109623515Ssklower 109721496Ssklower case SO_HEADERS_ON_OUTPUT: 109821496Ssklower mask = SF_HO; 109921496Ssklower get_flags: 110021496Ssklower m->m_len = sizeof(short); 110121496Ssklower m->m_off = MMAXOFF - sizeof(short); 110221496Ssklower *mtod(m, short *) = cb->s_flags & mask; 110321496Ssklower break; 110423515Ssklower 110524615Ssklower case SO_MTU: 110624615Ssklower m->m_len = sizeof(u_short); 110724615Ssklower m->m_off = MMAXOFF - sizeof(short); 110824615Ssklower *mtod(m, short *) = cb->s_mtu; 110924615Ssklower break; 111024615Ssklower 111121496Ssklower case SO_LAST_HEADER: 111221496Ssklower m->m_len = sizeof(struct sphdr); 111321496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 111421496Ssklower *mtod(m, struct sphdr *) = cb->s_rhdr; 111521496Ssklower break; 111623515Ssklower 111721496Ssklower case SO_DEFAULT_HEADERS: 111821496Ssklower m->m_len = sizeof(struct spidp); 111921496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 112032597Ssklower *mtod(m, struct sphdr *) = cb->s_shdr; 112125334Ssklower break; 112225334Ssklower 112325334Ssklower default: 112425334Ssklower error = EINVAL; 112521496Ssklower } 112621496Ssklower *value = m; 112721496Ssklower break; 112823515Ssklower 112921496Ssklower case PRCO_SETOPT: 113024615Ssklower if (value == 0 || *value == 0) { 113124615Ssklower error = EINVAL; 113224615Ssklower break; 113324615Ssklower } 113421496Ssklower switch (name) { 113524225Ssklower int *ok; 113621496Ssklower 113721496Ssklower case SO_HEADERS_ON_INPUT: 113821496Ssklower mask = SF_HI; 113921496Ssklower goto set_head; 114023515Ssklower 114121496Ssklower case SO_HEADERS_ON_OUTPUT: 114221496Ssklower mask = SF_HO; 114321496Ssklower set_head: 114424615Ssklower if (cb->s_flags & SF_PI) { 114521496Ssklower ok = mtod(*value, int *); 114621496Ssklower if (*ok) 114721496Ssklower cb->s_flags |= mask; 114821496Ssklower else 114921496Ssklower cb->s_flags &= ~mask; 115021496Ssklower } else error = EINVAL; 115121496Ssklower break; 115223515Ssklower 115324615Ssklower case SO_MTU: 115424615Ssklower cb->s_mtu = *(mtod(*value, u_short *)); 115524615Ssklower break; 115624615Ssklower 115721496Ssklower case SO_DEFAULT_HEADERS: 115821496Ssklower { 115921496Ssklower register struct sphdr *sp 116021496Ssklower = mtod(*value, struct sphdr *); 116121496Ssklower cb->s_dt = sp->sp_dt; 116221496Ssklower cb->s_cc = sp->sp_cc & SP_EM; 116321496Ssklower } 116425334Ssklower break; 116525334Ssklower 116625334Ssklower default: 116725334Ssklower error = EINVAL; 116821496Ssklower } 116924615Ssklower m_freem(*value); 117021496Ssklower break; 117121496Ssklower } 117221496Ssklower release: 117323515Ssklower return (error); 117421496Ssklower } 117521496Ssklower 117621496Ssklower /*ARGSUSED*/ 117721496Ssklower spp_usrreq(so, req, m, nam, rights) 117821496Ssklower struct socket *so; 117921496Ssklower int req; 118021496Ssklower struct mbuf *m, *nam, *rights; 118121496Ssklower { 118221496Ssklower struct nspcb *nsp = sotonspcb(so); 118321496Ssklower register struct sppcb *cb; 118421496Ssklower int s = splnet(); 118521496Ssklower int error = 0, ostate; 118632597Ssklower struct mbuf *mm; 118732597Ssklower register struct sockbuf *sb; 118821496Ssklower 118921496Ssklower if (req == PRU_CONTROL) 119021496Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 119121496Ssklower (struct ifnet *)rights)); 119221496Ssklower if (rights && rights->m_len) { 119321496Ssklower error = EINVAL; 119421496Ssklower goto release; 119521496Ssklower } 119621496Ssklower if (nsp == NULL) { 119721496Ssklower if (req != PRU_ATTACH) { 119821496Ssklower error = EINVAL; 119921496Ssklower goto release; 120021496Ssklower } 120121496Ssklower } else 120221496Ssklower cb = nstosppcb(nsp); 120321496Ssklower 120421496Ssklower ostate = cb ? cb->s_state : 0; 120521496Ssklower 120621496Ssklower switch (req) { 120723515Ssklower 120821496Ssklower case PRU_ATTACH: 120921496Ssklower if (nsp != NULL) { 121021496Ssklower error = EISCONN; 121121496Ssklower break; 121221496Ssklower } 121321496Ssklower error = ns_pcballoc(so, &nspcb); 121421496Ssklower if (error) 121521496Ssklower break; 1216*34486Skarels if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 1217*34486Skarels error = soreserve(so, (u_long) 3072, (u_long) 3072); 1218*34486Skarels if (error) 1219*34486Skarels break; 1220*34486Skarels } 122121496Ssklower nsp = sotonspcb(so); 122221496Ssklower 122332597Ssklower mm = m_getclr(M_DONTWAIT, MT_PCB); 122432597Ssklower sb = &so->so_snd; 122532597Ssklower 122632597Ssklower if (mm == NULL) { 122732597Ssklower error = ENOBUFS; 122832597Ssklower break; 122921496Ssklower } 123032597Ssklower cb = mtod(mm, struct sppcb *); 123132597Ssklower mm = m_getclr(M_DONTWAIT, MT_HEADER); 123232597Ssklower if (mm == NULL) { 1233*34486Skarels (void) m_free(dtom(m)); 123432597Ssklower error = ENOBUFS; 123532597Ssklower break; 123632597Ssklower } 123732597Ssklower cb->s_idp = mtod(mm, struct idp *); 123832597Ssklower cb->s_state = TCPS_LISTEN; 123932597Ssklower cb->s_smax = -1; 124032597Ssklower cb->s_swl1 = -1; 124132597Ssklower cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 124232597Ssklower cb->s_nspcb = nsp; 124332597Ssklower cb->s_mtu = 576 - sizeof (struct spidp); 124432597Ssklower cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; 124532597Ssklower cb->s_ssthresh = cb->s_cwnd; 124632597Ssklower cb->s_cwmx = sb->sb_mbmax * CUNIT / 124732597Ssklower (2 * sizeof (struct spidp)); 124832597Ssklower /* Above is recomputed when connecting to account 124932597Ssklower for changed buffering or mtu's */ 125033719Skarels cb->s_rtt = SPPTV_SRTTBASE; 125133719Skarels cb->s_rttvar = SPPTV_SRTTDFLT << 2; 125233719Skarels SPPT_RANGESET(cb->s_rxtcur, 125333719Skarels ((SPPTV_SRTTBASE >> 2) + (SPPTV_SRTTDFLT << 2)) >> 1, 125433719Skarels SPPTV_MIN, SPPTV_REXMTMAX); 125532597Ssklower nsp->nsp_pcb = (caddr_t) cb; 125621496Ssklower break; 125721496Ssklower 125821496Ssklower case PRU_DETACH: 125921496Ssklower if (nsp == NULL) { 126021496Ssklower error = ENOTCONN; 126121496Ssklower break; 126221496Ssklower } 126321496Ssklower if (cb->s_state > TCPS_LISTEN) 126421496Ssklower cb = spp_disconnect(cb); 126521496Ssklower else 126621496Ssklower cb = spp_close(cb); 126721496Ssklower break; 126821496Ssklower 126921496Ssklower case PRU_BIND: 127021496Ssklower error = ns_pcbbind(nsp, nam); 127121496Ssklower break; 127221496Ssklower 127321496Ssklower case PRU_LISTEN: 127421496Ssklower if (nsp->nsp_lport == 0) 127521496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 127621496Ssklower if (error == 0) 127721496Ssklower cb->s_state = TCPS_LISTEN; 127821496Ssklower break; 127921496Ssklower 128021496Ssklower /* 128121496Ssklower * Initiate connection to peer. 128221496Ssklower * Enter SYN_SENT state, and mark socket as connecting. 128321496Ssklower * Start keep-alive timer, setup prototype header, 128421496Ssklower * Send initial system packet requesting connection. 128521496Ssklower */ 128621496Ssklower case PRU_CONNECT: 128721496Ssklower if (nsp->nsp_lport == 0) { 128821496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 128921496Ssklower if (error) 129021496Ssklower break; 129121496Ssklower } 129221496Ssklower error = ns_pcbconnect(nsp, nam); 129321496Ssklower if (error) 129421496Ssklower break; 129521496Ssklower soisconnecting(so); 129632597Ssklower sppstat.spps_connattempt++; 129721496Ssklower cb->s_state = TCPS_SYN_SENT; 129821496Ssklower cb->s_did = 0; 129921496Ssklower spp_template(cb); 130033719Skarels cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; 130133719Skarels cb->s_force = 1 + SPPTV_KEEP; 130221496Ssklower /* 130321496Ssklower * Other party is required to respond to 130421496Ssklower * the port I send from, but he is not 130521496Ssklower * required to answer from where I am sending to, 130621496Ssklower * so allow wildcarding. 130721496Ssklower * original port I am sending to is still saved in 130821496Ssklower * cb->s_dport. 130921496Ssklower */ 131021496Ssklower nsp->nsp_fport = 0; 131121496Ssklower error = spp_output(cb, (struct mbuf *) 0); 131221496Ssklower break; 131321496Ssklower 131421496Ssklower case PRU_CONNECT2: 131521496Ssklower error = EOPNOTSUPP; 131621496Ssklower break; 131721496Ssklower 131821496Ssklower /* 131921496Ssklower * We may decide later to implement connection closing 132021496Ssklower * handshaking at the spp level optionally. 132121496Ssklower * here is the hook to do it: 132221496Ssklower */ 132321496Ssklower case PRU_DISCONNECT: 132421496Ssklower cb = spp_disconnect(cb); 132521496Ssklower break; 132621496Ssklower 132721496Ssklower /* 132821496Ssklower * Accept a connection. Essentially all the work is 132921496Ssklower * done at higher levels; just return the address 133021496Ssklower * of the peer, storing through addr. 133121496Ssklower */ 133221496Ssklower case PRU_ACCEPT: { 133321496Ssklower struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 133421496Ssklower 133521496Ssklower nam->m_len = sizeof (struct sockaddr_ns); 133621496Ssklower sns->sns_family = AF_NS; 133721496Ssklower sns->sns_addr = nsp->nsp_faddr; 133821496Ssklower break; 133921496Ssklower } 134021496Ssklower 134121496Ssklower case PRU_SHUTDOWN: 134221496Ssklower socantsendmore(so); 134321496Ssklower cb = spp_usrclosed(cb); 134421496Ssklower if (cb) 134521496Ssklower error = spp_output(cb, (struct mbuf *) 0); 134621496Ssklower break; 134721496Ssklower 134821496Ssklower /* 134921496Ssklower * After a receive, possibly send acknowledgment 135021496Ssklower * updating allocation. 135121496Ssklower */ 135221496Ssklower case PRU_RCVD: 135332597Ssklower cb->s_flags |= SF_RVD; 135421496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 135532597Ssklower cb->s_flags &= ~SF_RVD; 135621496Ssklower break; 135721496Ssklower 135821496Ssklower case PRU_ABORT: 135924225Ssklower (void) spp_drop(cb, ECONNABORTED); 136021496Ssklower break; 136121496Ssklower 136221496Ssklower case PRU_SENSE: 136321496Ssklower case PRU_CONTROL: 136421496Ssklower m = NULL; 136521496Ssklower error = EOPNOTSUPP; 136621496Ssklower break; 136721496Ssklower 136821496Ssklower case PRU_RCVOOB: 136925037Ssklower if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 137025037Ssklower (so->so_state & SS_RCVATMARK)) { 137125037Ssklower m->m_len = 1; 137225037Ssklower *mtod(m, caddr_t) = cb->s_iobc; 137324732Ssklower break; 137424732Ssklower } 137525037Ssklower error = EINVAL; 137621496Ssklower break; 137721496Ssklower 137821496Ssklower case PRU_SENDOOB: 137921496Ssklower if (sbspace(&so->so_snd) < -512) { 138021496Ssklower error = ENOBUFS; 138121496Ssklower break; 138221496Ssklower } 138321496Ssklower cb->s_oobflags |= SF_SOOB; 138425623Ssklower /* fall into */ 138525623Ssklower case PRU_SEND: 138621496Ssklower error = spp_output(cb, m); 138721496Ssklower m = NULL; 138821496Ssklower break; 138921496Ssklower 139021496Ssklower case PRU_SOCKADDR: 139121496Ssklower ns_setsockaddr(nsp, nam); 139221496Ssklower break; 139321496Ssklower 139421496Ssklower case PRU_PEERADDR: 139521496Ssklower ns_setpeeraddr(nsp, nam); 139621496Ssklower break; 139721496Ssklower 139821496Ssklower case PRU_SLOWTIMO: 139921496Ssklower cb = spp_timers(cb, (int)nam); 140032597Ssklower req |= ((int)nam) << 8; 140121496Ssklower break; 140221496Ssklower 140321496Ssklower case PRU_FASTTIMO: 140421496Ssklower case PRU_PROTORCV: 140521496Ssklower case PRU_PROTOSEND: 140621496Ssklower error = EOPNOTSUPP; 140721496Ssklower break; 140821496Ssklower 140921496Ssklower default: 141021496Ssklower panic("sp_usrreq"); 141121496Ssklower } 141221496Ssklower if (cb && (so->so_options & SO_DEBUG || traceallspps)) 141324225Ssklower spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); 141421496Ssklower release: 141521496Ssklower if (m != NULL) 141621496Ssklower m_freem(m); 141721496Ssklower splx(s); 141821496Ssklower return (error); 141921496Ssklower } 142021496Ssklower 142121496Ssklower spp_usrreq_sp(so, req, m, nam, rights) 142221496Ssklower struct socket *so; 142321496Ssklower int req; 142421496Ssklower struct mbuf *m, *nam, *rights; 142521496Ssklower { 142621496Ssklower int error = spp_usrreq(so, req, m, nam, rights); 142721496Ssklower 142824330Ssklower if (req == PRU_ATTACH && error == 0) { 142921496Ssklower struct nspcb *nsp = sotonspcb(so); 143021496Ssklower ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 143121496Ssklower (SF_HI | SF_HO | SF_PI); 143221496Ssklower } 143323515Ssklower return (error); 143421496Ssklower } 143521496Ssklower 143621496Ssklower /* 143721496Ssklower * Create template to be used to send spp packets on a connection. 143821496Ssklower * Called after host entry created, fills 143921496Ssklower * in a skeletal spp header (choosing connection id), 144021496Ssklower * minimizing the amount of work necessary when the connection is used. 144121496Ssklower */ 144221496Ssklower spp_template(cb) 144332597Ssklower register struct sppcb *cb; 144421496Ssklower { 144521496Ssklower register struct nspcb *nsp = cb->s_nspcb; 144632597Ssklower register struct idp *idp = cb->s_idp; 144732597Ssklower register struct sockbuf *sb = &(nsp->nsp_socket->so_snd); 144821496Ssklower 144932597Ssklower idp->idp_pt = NSPROTO_SPP; 145032597Ssklower idp->idp_sna = nsp->nsp_laddr; 145132597Ssklower idp->idp_dna = nsp->nsp_faddr; 145232597Ssklower cb->s_sid = htons(spp_iss); 145321496Ssklower spp_iss += SPP_ISSINCR/2; 145432597Ssklower cb->s_alo = 1; 145532597Ssklower cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; 145632597Ssklower cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement 145732597Ssklower of large packets */ 145832597Ssklower cb->s_cwmx = (sb->sb_mbmax * CUNIT) / (2 * sizeof(struct spidp)); 145932597Ssklower cb->s_cwmx = MAX(cb->s_cwmx, cb->s_cwnd); 146032597Ssklower /* But allow for lots of little packets as well */ 146121496Ssklower } 146221496Ssklower 146321496Ssklower /* 146421496Ssklower * Close a SPIP control block: 146521496Ssklower * discard spp control block itself 146621496Ssklower * discard ns protocol control block 146721496Ssklower * wake up any sleepers 146821496Ssklower */ 146921496Ssklower struct sppcb * 147021496Ssklower spp_close(cb) 147121496Ssklower register struct sppcb *cb; 147221496Ssklower { 147321496Ssklower register struct spidp_q *s; 147421496Ssklower struct nspcb *nsp = cb->s_nspcb; 147521496Ssklower struct socket *so = nsp->nsp_socket; 147621496Ssklower register struct mbuf *m; 147721496Ssklower 147821496Ssklower s = cb->s_q.si_next; 147921496Ssklower while (s != &(cb->s_q)) { 148021496Ssklower s = s->si_next; 148121496Ssklower m = dtom(s->si_prev); 148221496Ssklower remque(s->si_prev); 148321496Ssklower m_freem(m); 148421496Ssklower } 148532597Ssklower (void) m_free(dtom(cb->s_idp)); 148621496Ssklower (void) m_free(dtom(cb)); 148721496Ssklower nsp->nsp_pcb = 0; 148821496Ssklower soisdisconnected(so); 148921496Ssklower ns_pcbdetach(nsp); 149032597Ssklower sppstat.spps_closed++; 149123515Ssklower return ((struct sppcb *)0); 149221496Ssklower } 149321496Ssklower /* 149421496Ssklower * Someday we may do level 3 handshaking 149521496Ssklower * to close a connection or send a xerox style error. 149621496Ssklower * For now, just close. 149721496Ssklower */ 149821496Ssklower struct sppcb * 149921496Ssklower spp_usrclosed(cb) 150021496Ssklower register struct sppcb *cb; 150121496Ssklower { 150223515Ssklower return (spp_close(cb)); 150321496Ssklower } 150421496Ssklower struct sppcb * 150521496Ssklower spp_disconnect(cb) 150621496Ssklower register struct sppcb *cb; 150721496Ssklower { 150823515Ssklower return (spp_close(cb)); 150921496Ssklower } 151021496Ssklower /* 151121496Ssklower * Drop connection, reporting 151221496Ssklower * the specified error. 151321496Ssklower */ 151421496Ssklower struct sppcb * 151521496Ssklower spp_drop(cb, errno) 151621496Ssklower register struct sppcb *cb; 151721496Ssklower int errno; 151821496Ssklower { 151921496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 152021496Ssklower 152121496Ssklower /* 152221496Ssklower * someday, in the xerox world 152321496Ssklower * we will generate error protocol packets 152421496Ssklower * announcing that the socket has gone away. 152521496Ssklower */ 152632597Ssklower if (TCPS_HAVERCVDSYN(cb->s_state)) { 152732597Ssklower sppstat.spps_drops++; 152832597Ssklower cb->s_state = TCPS_CLOSED; 152932597Ssklower /*(void) tcp_output(cb);*/ 153032597Ssklower } else 153132597Ssklower sppstat.spps_conndrops++; 153221496Ssklower so->so_error = errno; 153321496Ssklower return (spp_close(cb)); 153421496Ssklower } 153521496Ssklower 153621496Ssklower spp_abort(nsp) 153721496Ssklower struct nspcb *nsp; 153821496Ssklower { 153921496Ssklower 154024225Ssklower (void) spp_close((struct sppcb *)nsp->nsp_pcb); 154121496Ssklower } 154221496Ssklower 154333719Skarels int spp_backoff[SPP_MAXRXTSHIFT+1] = 154432597Ssklower { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 154521496Ssklower /* 154621496Ssklower * Fast timeout routine for processing delayed acks 154721496Ssklower */ 154821496Ssklower spp_fasttimo() 154921496Ssklower { 155021496Ssklower register struct nspcb *nsp; 155121496Ssklower register struct sppcb *cb; 155221496Ssklower int s = splnet(); 155321496Ssklower 155421496Ssklower nsp = nspcb.nsp_next; 155521496Ssklower if (nsp) 155621496Ssklower for (; nsp != &nspcb; nsp = nsp->nsp_next) 155721496Ssklower if ((cb = (struct sppcb *)nsp->nsp_pcb) && 155821496Ssklower (cb->s_flags & SF_DELACK)) { 155921496Ssklower cb->s_flags &= ~SF_DELACK; 156032597Ssklower cb->s_flags |= SF_ACKNOW; 156132597Ssklower sppstat.spps_delack++; 156221496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 156321496Ssklower } 156421496Ssklower splx(s); 156521496Ssklower } 156621496Ssklower 156721496Ssklower /* 156821496Ssklower * spp protocol timeout routine called every 500 ms. 156921496Ssklower * Updates the timers in all active pcb's and 157021496Ssklower * causes finite state machine actions if timers expire. 157121496Ssklower */ 157221496Ssklower spp_slowtimo() 157321496Ssklower { 157421496Ssklower register struct nspcb *ip, *ipnxt; 157521496Ssklower register struct sppcb *cb; 157621496Ssklower int s = splnet(); 157721496Ssklower register int i; 157821496Ssklower 157921496Ssklower /* 158021496Ssklower * Search through tcb's and update active timers. 158121496Ssklower */ 158221496Ssklower ip = nspcb.nsp_next; 158321496Ssklower if (ip == 0) { 158421496Ssklower splx(s); 158521496Ssklower return; 158621496Ssklower } 158721496Ssklower while (ip != &nspcb) { 158821496Ssklower cb = nstosppcb(ip); 158921496Ssklower ipnxt = ip->nsp_next; 159021496Ssklower if (cb == 0) 159121496Ssklower goto tpgone; 159233719Skarels for (i = 0; i < SPPT_NTIMERS; i++) { 159321496Ssklower if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 159421496Ssklower (void) spp_usrreq(cb->s_nspcb->nsp_socket, 159521496Ssklower PRU_SLOWTIMO, (struct mbuf *)0, 159621496Ssklower (struct mbuf *)i, (struct mbuf *)0); 159721496Ssklower if (ipnxt->nsp_prev != ip) 159821496Ssklower goto tpgone; 159921496Ssklower } 160021496Ssklower } 160121496Ssklower cb->s_idle++; 160221496Ssklower if (cb->s_rtt) 160321496Ssklower cb->s_rtt++; 160421496Ssklower tpgone: 160521496Ssklower ip = ipnxt; 160621496Ssklower } 160721496Ssklower spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 160821496Ssklower splx(s); 160921496Ssklower } 161021496Ssklower /* 161124615Ssklower * SPP timer processing. 161221496Ssklower */ 161321496Ssklower struct sppcb * 161421496Ssklower spp_timers(cb, timer) 161521496Ssklower register struct sppcb *cb; 161621496Ssklower int timer; 161721496Ssklower { 161832597Ssklower long rexmt; 161932597Ssklower int win; 162021496Ssklower 162121496Ssklower cb->s_force = 1 + timer; 162221496Ssklower switch (timer) { 162321496Ssklower 162421496Ssklower /* 162532597Ssklower * 2 MSL timeout in shutdown went off. TCP deletes connection 162621496Ssklower * control block. 162721496Ssklower */ 162833719Skarels case SPPT_2MSL: 162933719Skarels printf("spp: SPPT_2MSL went off for no reason\n"); 163032597Ssklower cb->s_timer[timer] = 0; 163121496Ssklower break; 163221496Ssklower 163321496Ssklower /* 163421496Ssklower * Retransmission timer went off. Message has not 163521496Ssklower * been acked within retransmit interval. Back off 163632597Ssklower * to a longer retransmit interval and retransmit one packet. 163721496Ssklower */ 163833719Skarels case SPPT_REXMT: 163933719Skarels if (++cb->s_rxtshift > SPP_MAXRXTSHIFT) { 164033719Skarels cb->s_rxtshift = SPP_MAXRXTSHIFT; 164132597Ssklower sppstat.spps_timeoutdrop++; 164221496Ssklower cb = spp_drop(cb, ETIMEDOUT); 164321496Ssklower break; 164421496Ssklower } 164532597Ssklower sppstat.spps_rexmttimeo++; 164632597Ssklower rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 164732597Ssklower rexmt *= spp_backoff[cb->s_rxtshift]; 164833719Skarels SPPT_RANGESET(cb->s_rxtcur, rexmt, SPPTV_MIN, SPPTV_REXMTMAX); 164933719Skarels cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; 165032597Ssklower /* 165132597Ssklower * If we have backed off fairly far, our srtt 165232597Ssklower * estimate is probably bogus. Clobber it 165332597Ssklower * so we'll take the next rtt measurement as our srtt; 165432597Ssklower * move the current srtt into rttvar to keep the current 165532597Ssklower * retransmit times until then. 165632597Ssklower */ 165733719Skarels if (cb->s_rxtshift > SPP_MAXRXTSHIFT / 4 ) { 165832597Ssklower cb->s_rttvar += (cb->s_srtt >> 2); 165932597Ssklower cb->s_srtt = 0; 166032597Ssklower } 166132597Ssklower cb->s_snxt = cb->s_rack; 166232597Ssklower /* 166332597Ssklower * If timing a packet, stop the timer. 166432597Ssklower */ 166532597Ssklower cb->s_rtt = 0; 166632597Ssklower /* 166732597Ssklower * See very long discussion in tcp_timer.c about congestion 166832597Ssklower * window and sstrhesh 166932597Ssklower */ 167032597Ssklower win = MIN(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; 167132597Ssklower if (win < 2) 167232597Ssklower win = 2; 167332597Ssklower cb->s_cwnd = CUNIT; 167433637Ssklower cb->s_ssthresh = win * CUNIT; 167521496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 167621496Ssklower break; 167721496Ssklower 167821496Ssklower /* 167921496Ssklower * Persistance timer into zero window. 168021496Ssklower * Force a probe to be sent. 168121496Ssklower */ 168233719Skarels case SPPT_PERSIST: 168332597Ssklower sppstat.spps_persisttimeo++; 168432597Ssklower spp_setpersist(cb); 168521496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 168621496Ssklower break; 168721496Ssklower 168821496Ssklower /* 168921496Ssklower * Keep-alive timer went off; send something 169021496Ssklower * or drop connection if idle for too long. 169121496Ssklower */ 169233719Skarels case SPPT_KEEP: 169332597Ssklower sppstat.spps_keeptimeo++; 169421496Ssklower if (cb->s_state < TCPS_ESTABLISHED) 169521496Ssklower goto dropit; 169621496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 169733719Skarels if (cb->s_idle >= SPPTV_MAXIDLE) 169821496Ssklower goto dropit; 169932597Ssklower sppstat.spps_keepprobe++; 170021496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 170121496Ssklower } else 170221496Ssklower cb->s_idle = 0; 170333719Skarels cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; 170421496Ssklower break; 170521496Ssklower dropit: 170632597Ssklower sppstat.spps_keepdrops++; 170721496Ssklower cb = spp_drop(cb, ETIMEDOUT); 170821496Ssklower break; 170921496Ssklower } 171021496Ssklower return (cb); 171121496Ssklower } 171233637Ssklower #ifndef lint 171332597Ssklower int SppcbSize = sizeof (struct sppcb); 171432597Ssklower int NspcbSize = sizeof (struct nspcb); 171533637Ssklower #endif lint 1716