spx_reass.c revision 11819
111819Sjulian/* 211819Sjulian * Copyright (c) 1995, Mike Mitchell 311819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993 411819Sjulian * The Regents of the University of California. All rights reserved. 511819Sjulian * 611819Sjulian * Redistribution and use in source and binary forms, with or without 711819Sjulian * modification, are permitted provided that the following conditions 811819Sjulian * are met: 911819Sjulian * 1. Redistributions of source code must retain the above copyright 1011819Sjulian * notice, this list of conditions and the following disclaimer. 1111819Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1211819Sjulian * notice, this list of conditions and the following disclaimer in the 1311819Sjulian * documentation and/or other materials provided with the distribution. 1411819Sjulian * 3. All advertising materials mentioning features or use of this software 1511819Sjulian * must display the following acknowledgement: 1611819Sjulian * This product includes software developed by the University of 1711819Sjulian * California, Berkeley and its contributors. 1811819Sjulian * 4. Neither the name of the University nor the names of its contributors 1911819Sjulian * may be used to endorse or promote products derived from this software 2011819Sjulian * without specific prior written permission. 2111819Sjulian * 2211819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2311819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2411819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2511819Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2611819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2711819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2811819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2911819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3011819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3111819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3211819Sjulian * SUCH DAMAGE. 3311819Sjulian * 3411819Sjulian * @(#)spx_usrreq.h 3511819Sjulian */ 3611819Sjulian 3711819Sjulian#include <sys/param.h> 3811819Sjulian#include <sys/systm.h> 3911819Sjulian#include <sys/malloc.h> 4011819Sjulian#include <sys/mbuf.h> 4111819Sjulian#include <sys/protosw.h> 4211819Sjulian#include <sys/socket.h> 4311819Sjulian#include <sys/socketvar.h> 4411819Sjulian#include <sys/errno.h> 4511819Sjulian 4611819Sjulian#include <net/if.h> 4711819Sjulian#include <net/route.h> 4811819Sjulian#include <netinet/tcp_fsm.h> 4911819Sjulian 5011819Sjulian#include <netipx/ipx.h> 5111819Sjulian#include <netipx/ipx_pcb.h> 5211819Sjulian#include <netipx/ipx_var.h> 5311819Sjulian#include <netipx/ipx_error.h> 5411819Sjulian#include <netipx/spx.h> 5511819Sjulian#include <netipx/spx_timer.h> 5611819Sjulian#include <netipx/spx_var.h> 5711819Sjulian#include <netipx/spx_debug.h> 5811819Sjulian 5911819Sjulian/* 6011819Sjulian * SPX protocol implementation. 6111819Sjulian */ 6211819Sjulian 6311819Sjulianstruct spx spx_savesi; 6411819Sjulianint traceallspxs = 0; 6511819Sjulianextern int spxconsdebug; 6611819Sjulianint spx_hardnosed; 6711819Sjulianint spx_use_delack = 0; 6811819Sjulianu_short spx_newchecks[50]; 6911819Sjulian 7011819Sjulianstruct spx_istat spx_istat; 7111819Sjulianu_short spx_iss; 7211819Sjulian 7311819Sjulianvoid 7411819Sjulianspx_init() 7511819Sjulian{ 7611819Sjulian 7711819Sjulian spx_iss = 1; /* WRONG !! should fish it out of TODR */ 7811819Sjulian} 7911819Sjulian 8011819Sjulian/*ARGSUSED*/ 8111819Sjulianvoid 8211819Sjulianspx_input(m, ipxp) 8311819Sjulian register struct mbuf *m; 8411819Sjulian register struct ipxpcb *ipxp; 8511819Sjulian{ 8611819Sjulian register struct spxpcb *cb; 8711819Sjulian register struct spx *si = mtod(m, struct spx *); 8811819Sjulian register struct socket *so; 8911819Sjulian int dropsocket = 0; 9011819Sjulian short ostate = 0; 9111819Sjulian 9211819Sjulian spxstat.spxs_rcvtotal++; 9311819Sjulian if (ipxp == 0) { 9411819Sjulian panic("No ipxpcb in spx_input\n"); 9511819Sjulian return; 9611819Sjulian } 9711819Sjulian 9811819Sjulian cb = ipxtospxpcb(ipxp); 9911819Sjulian if (cb == 0) goto bad; 10011819Sjulian 10111819Sjulian if (m->m_len < sizeof(*si)) { 10211819Sjulian if ((m = m_pullup(m, sizeof(*si))) == 0) { 10311819Sjulian spxstat.spxs_rcvshort++; 10411819Sjulian return; 10511819Sjulian } 10611819Sjulian si = mtod(m, struct spx *); 10711819Sjulian } 10811819Sjulian si->si_seq = ntohs(si->si_seq); 10911819Sjulian si->si_ack = ntohs(si->si_ack); 11011819Sjulian si->si_alo = ntohs(si->si_alo); 11111819Sjulian 11211819Sjulian so = ipxp->ipxp_socket; 11311819Sjulian 11411819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) { 11511819Sjulian ostate = cb->s_state; 11611819Sjulian spx_savesi = *si; 11711819Sjulian } 11811819Sjulian if (so->so_options & SO_ACCEPTCONN) { 11911819Sjulian struct spxpcb *ocb = cb; 12011819Sjulian 12111819Sjulian so = sonewconn(so, 0); 12211819Sjulian if (so == 0) { 12311819Sjulian goto drop; 12411819Sjulian } 12511819Sjulian /* 12611819Sjulian * This is ugly, but .... 12711819Sjulian * 12811819Sjulian * Mark socket as temporary until we're 12911819Sjulian * committed to keeping it. The code at 13011819Sjulian * ``drop'' and ``dropwithreset'' check the 13111819Sjulian * flag dropsocket to see if the temporary 13211819Sjulian * socket created here should be discarded. 13311819Sjulian * We mark the socket as discardable until 13411819Sjulian * we're committed to it below in TCPS_LISTEN. 13511819Sjulian */ 13611819Sjulian dropsocket++; 13711819Sjulian ipxp = (struct ipxpcb *)so->so_pcb; 13811819Sjulian ipxp->ipxp_laddr = si->si_dna; 13911819Sjulian cb = ipxtospxpcb(ipxp); 14011819Sjulian cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ 14111819Sjulian cb->s_flags = ocb->s_flags; /* preserve sockopts */ 14211819Sjulian cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ 14311819Sjulian cb->s_state = TCPS_LISTEN; 14411819Sjulian } 14511819Sjulian 14611819Sjulian /* 14711819Sjulian * Packet received on connection. 14811819Sjulian * reset idle time and keep-alive timer; 14911819Sjulian */ 15011819Sjulian cb->s_idle = 0; 15111819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 15211819Sjulian 15311819Sjulian switch (cb->s_state) { 15411819Sjulian 15511819Sjulian case TCPS_LISTEN:{ 15611819Sjulian struct mbuf *am; 15711819Sjulian register struct sockaddr_ipx *sipx; 15811819Sjulian struct ipx_addr laddr; 15911819Sjulian 16011819Sjulian /* 16111819Sjulian * If somebody here was carying on a conversation 16211819Sjulian * and went away, and his pen pal thinks he can 16311819Sjulian * still talk, we get the misdirected packet. 16411819Sjulian */ 16511819Sjulian if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 16611819Sjulian spx_istat.gonawy++; 16711819Sjulian goto dropwithreset; 16811819Sjulian } 16911819Sjulian am = m_get(M_DONTWAIT, MT_SONAME); 17011819Sjulian if (am == NULL) 17111819Sjulian goto drop; 17211819Sjulian am->m_len = sizeof (struct sockaddr_ipx); 17311819Sjulian sipx = mtod(am, struct sockaddr_ipx *); 17411819Sjulian sipx->sipx_len = sizeof(*sipx); 17511819Sjulian sipx->sipx_family = AF_IPX; 17611819Sjulian sipx->sipx_addr = si->si_sna; 17711819Sjulian laddr = ipxp->ipxp_laddr; 17811819Sjulian if (ipx_nullhost(laddr)) 17911819Sjulian ipxp->ipxp_laddr = si->si_dna; 18011819Sjulian if (ipx_pcbconnect(ipxp, am)) { 18111819Sjulian ipxp->ipxp_laddr = laddr; 18211819Sjulian (void) m_free(am); 18311819Sjulian spx_istat.noconn++; 18411819Sjulian goto drop; 18511819Sjulian } 18611819Sjulian (void) m_free(am); 18711819Sjulian spx_template(cb); 18811819Sjulian dropsocket = 0; /* committed to socket */ 18911819Sjulian cb->s_did = si->si_sid; 19011819Sjulian cb->s_rack = si->si_ack; 19111819Sjulian cb->s_ralo = si->si_alo; 19211819Sjulian#define THREEWAYSHAKE 19311819Sjulian#ifdef THREEWAYSHAKE 19411819Sjulian cb->s_state = TCPS_SYN_RECEIVED; 19511819Sjulian cb->s_force = 1 + SPXT_KEEP; 19611819Sjulian spxstat.spxs_accepts++; 19711819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 19811819Sjulian } 19911819Sjulian break; 20011819Sjulian /* 20111819Sjulian * This state means that we have heard a response 20211819Sjulian * to our acceptance of their connection 20311819Sjulian * It is probably logically unnecessary in this 20411819Sjulian * implementation. 20511819Sjulian */ 20611819Sjulian case TCPS_SYN_RECEIVED: { 20711819Sjulian if (si->si_did!=cb->s_sid) { 20811819Sjulian spx_istat.wrncon++; 20911819Sjulian goto drop; 21011819Sjulian } 21111819Sjulian#endif 21211819Sjulian ipxp->ipxp_fport = si->si_sport; 21311819Sjulian cb->s_timer[SPXT_REXMT] = 0; 21411819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 21511819Sjulian soisconnected(so); 21611819Sjulian cb->s_state = TCPS_ESTABLISHED; 21711819Sjulian spxstat.spxs_accepts++; 21811819Sjulian } 21911819Sjulian break; 22011819Sjulian 22111819Sjulian /* 22211819Sjulian * This state means that we have gotten a response 22311819Sjulian * to our attempt to establish a connection. 22411819Sjulian * We fill in the data from the other side, 22511819Sjulian * telling us which port to respond to, instead of the well- 22611819Sjulian * known one we might have sent to in the first place. 22711819Sjulian * We also require that this is a response to our 22811819Sjulian * connection id. 22911819Sjulian */ 23011819Sjulian case TCPS_SYN_SENT: 23111819Sjulian if (si->si_did!=cb->s_sid) { 23211819Sjulian spx_istat.notme++; 23311819Sjulian goto drop; 23411819Sjulian } 23511819Sjulian spxstat.spxs_connects++; 23611819Sjulian cb->s_did = si->si_sid; 23711819Sjulian cb->s_rack = si->si_ack; 23811819Sjulian cb->s_ralo = si->si_alo; 23911819Sjulian cb->s_dport = ipxp->ipxp_fport = si->si_sport; 24011819Sjulian cb->s_timer[SPXT_REXMT] = 0; 24111819Sjulian cb->s_flags |= SF_ACKNOW; 24211819Sjulian soisconnected(so); 24311819Sjulian cb->s_state = TCPS_ESTABLISHED; 24411819Sjulian /* Use roundtrip time of connection request for initial rtt */ 24511819Sjulian if (cb->s_rtt) { 24611819Sjulian cb->s_srtt = cb->s_rtt << 3; 24711819Sjulian cb->s_rttvar = cb->s_rtt << 1; 24811819Sjulian SPXT_RANGESET(cb->s_rxtcur, 24911819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 25011819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 25111819Sjulian cb->s_rtt = 0; 25211819Sjulian } 25311819Sjulian } 25411819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) 25511819Sjulian spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0); 25611819Sjulian 25711819Sjulian m->m_len -= sizeof (struct ipx); 25811819Sjulian m->m_pkthdr.len -= sizeof (struct ipx); 25911819Sjulian m->m_data += sizeof (struct ipx); 26011819Sjulian 26111819Sjulian if (spx_reass(cb, si)) { 26211819Sjulian (void) m_freem(m); 26311819Sjulian } 26411819Sjulian if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) 26511819Sjulian (void) spx_output(cb, (struct mbuf *)0); 26611819Sjulian cb->s_flags &= ~(SF_WIN|SF_RXT); 26711819Sjulian return; 26811819Sjulian 26911819Sjuliandropwithreset: 27011819Sjulian if (dropsocket) 27111819Sjulian (void) soabort(so); 27211819Sjulian si->si_seq = ntohs(si->si_seq); 27311819Sjulian si->si_ack = ntohs(si->si_ack); 27411819Sjulian si->si_alo = ntohs(si->si_alo); 27511819Sjulian ipx_error(dtom(si), IPX_ERR_NOSOCK, 0); 27611819Sjulian if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs) 27711819Sjulian spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 27811819Sjulian return; 27911819Sjulian 28011819Sjuliandrop: 28111819Sjulianbad: 28211819Sjulian if (cb == 0 || cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || 28311819Sjulian traceallspxs) 28411819Sjulian spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 28511819Sjulian m_freem(m); 28611819Sjulian} 28711819Sjulian 28811819Sjulianint spxrexmtthresh = 3; 28911819Sjulian 29011819Sjulian/* 29111819Sjulian * This is structurally similar to the tcp reassembly routine 29211819Sjulian * but its function is somewhat different: It merely queues 29311819Sjulian * packets up, and suppresses duplicates. 29411819Sjulian */ 29511819Sjulianint 29611819Sjulianspx_reass(cb, si) 29711819Sjulianregister struct spxpcb *cb; 29811819Sjulianregister struct spx *si; 29911819Sjulian{ 30011819Sjulian register struct spx_q *q; 30111819Sjulian register struct mbuf *m; 30211819Sjulian register struct socket *so = cb->s_ipxpcb->ipxp_socket; 30311819Sjulian char packetp = cb->s_flags & SF_HI; 30411819Sjulian int incr; 30511819Sjulian char wakeup = 0; 30611819Sjulian 30711819Sjulian if (si == SI(0)) 30811819Sjulian goto present; 30911819Sjulian /* 31011819Sjulian * Update our news from them. 31111819Sjulian */ 31211819Sjulian if (si->si_cc & SPX_SA) 31311819Sjulian cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW); 31411819Sjulian if (SSEQ_GT(si->si_alo, cb->s_ralo)) 31511819Sjulian cb->s_flags |= SF_WIN; 31611819Sjulian if (SSEQ_LEQ(si->si_ack, cb->s_rack)) { 31711819Sjulian if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) { 31811819Sjulian spxstat.spxs_rcvdupack++; 31911819Sjulian /* 32011819Sjulian * If this is a completely duplicate ack 32111819Sjulian * and other conditions hold, we assume 32211819Sjulian * a packet has been dropped and retransmit 32311819Sjulian * it exactly as in tcp_input(). 32411819Sjulian */ 32511819Sjulian if (si->si_ack != cb->s_rack || 32611819Sjulian si->si_alo != cb->s_ralo) 32711819Sjulian cb->s_dupacks = 0; 32811819Sjulian else if (++cb->s_dupacks == spxrexmtthresh) { 32911819Sjulian u_short onxt = cb->s_snxt; 33011819Sjulian int cwnd = cb->s_cwnd; 33111819Sjulian 33211819Sjulian cb->s_snxt = si->si_ack; 33311819Sjulian cb->s_cwnd = CUNIT; 33411819Sjulian cb->s_force = 1 + SPXT_REXMT; 33511819Sjulian (void) spx_output(cb, (struct mbuf *)0); 33611819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 33711819Sjulian cb->s_rtt = 0; 33811819Sjulian if (cwnd >= 4 * CUNIT) 33911819Sjulian cb->s_cwnd = cwnd / 2; 34011819Sjulian if (SSEQ_GT(onxt, cb->s_snxt)) 34111819Sjulian cb->s_snxt = onxt; 34211819Sjulian return (1); 34311819Sjulian } 34411819Sjulian } else 34511819Sjulian cb->s_dupacks = 0; 34611819Sjulian goto update_window; 34711819Sjulian } 34811819Sjulian cb->s_dupacks = 0; 34911819Sjulian /* 35011819Sjulian * If our correspondent acknowledges data we haven't sent 35111819Sjulian * TCP would drop the packet after acking. We'll be a little 35211819Sjulian * more permissive 35311819Sjulian */ 35411819Sjulian if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) { 35511819Sjulian spxstat.spxs_rcvacktoomuch++; 35611819Sjulian si->si_ack = cb->s_smax + 1; 35711819Sjulian } 35811819Sjulian spxstat.spxs_rcvackpack++; 35911819Sjulian /* 36011819Sjulian * If transmit timer is running and timed sequence 36111819Sjulian * number was acked, update smoothed round trip time. 36211819Sjulian * See discussion of algorithm in tcp_input.c 36311819Sjulian */ 36411819Sjulian if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 36511819Sjulian spxstat.spxs_rttupdated++; 36611819Sjulian if (cb->s_srtt != 0) { 36711819Sjulian register short delta; 36811819Sjulian delta = cb->s_rtt - (cb->s_srtt >> 3); 36911819Sjulian if ((cb->s_srtt += delta) <= 0) 37011819Sjulian cb->s_srtt = 1; 37111819Sjulian if (delta < 0) 37211819Sjulian delta = -delta; 37311819Sjulian delta -= (cb->s_rttvar >> 2); 37411819Sjulian if ((cb->s_rttvar += delta) <= 0) 37511819Sjulian cb->s_rttvar = 1; 37611819Sjulian } else { 37711819Sjulian /* 37811819Sjulian * No rtt measurement yet 37911819Sjulian */ 38011819Sjulian cb->s_srtt = cb->s_rtt << 3; 38111819Sjulian cb->s_rttvar = cb->s_rtt << 1; 38211819Sjulian } 38311819Sjulian cb->s_rtt = 0; 38411819Sjulian cb->s_rxtshift = 0; 38511819Sjulian SPXT_RANGESET(cb->s_rxtcur, 38611819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 38711819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 38811819Sjulian } 38911819Sjulian /* 39011819Sjulian * If all outstanding data is acked, stop retransmit 39111819Sjulian * timer and remember to restart (more output or persist). 39211819Sjulian * If there is more data to be acked, restart retransmit 39311819Sjulian * timer, using current (possibly backed-off) value; 39411819Sjulian */ 39511819Sjulian if (si->si_ack == cb->s_smax + 1) { 39611819Sjulian cb->s_timer[SPXT_REXMT] = 0; 39711819Sjulian cb->s_flags |= SF_RXT; 39811819Sjulian } else if (cb->s_timer[SPXT_PERSIST] == 0) 39911819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 40011819Sjulian /* 40111819Sjulian * When new data is acked, open the congestion window. 40211819Sjulian * If the window gives us less than ssthresh packets 40311819Sjulian * in flight, open exponentially (maxseg at a time). 40411819Sjulian * Otherwise open linearly (maxseg^2 / cwnd at a time). 40511819Sjulian */ 40611819Sjulian incr = CUNIT; 40711819Sjulian if (cb->s_cwnd > cb->s_ssthresh) 40811819Sjulian incr = max(incr * incr / cb->s_cwnd, 1); 40911819Sjulian cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx); 41011819Sjulian /* 41111819Sjulian * Trim Acked data from output queue. 41211819Sjulian */ 41311819Sjulian while ((m = so->so_snd.sb_mb) != NULL) { 41411819Sjulian if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack)) 41511819Sjulian sbdroprecord(&so->so_snd); 41611819Sjulian else 41711819Sjulian break; 41811819Sjulian } 41911819Sjulian sowwakeup(so); 42011819Sjulian cb->s_rack = si->si_ack; 42111819Sjulianupdate_window: 42211819Sjulian if (SSEQ_LT(cb->s_snxt, cb->s_rack)) 42311819Sjulian cb->s_snxt = cb->s_rack; 42411819Sjulian if (SSEQ_LT(cb->s_swl1, si->si_seq) || cb->s_swl1 == si->si_seq && 42511819Sjulian (SSEQ_LT(cb->s_swl2, si->si_ack) || 42611819Sjulian cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))) { 42711819Sjulian /* keep track of pure window updates */ 42811819Sjulian if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack 42911819Sjulian && SSEQ_LT(cb->s_ralo, si->si_alo)) { 43011819Sjulian spxstat.spxs_rcvwinupd++; 43111819Sjulian spxstat.spxs_rcvdupack--; 43211819Sjulian } 43311819Sjulian cb->s_ralo = si->si_alo; 43411819Sjulian cb->s_swl1 = si->si_seq; 43511819Sjulian cb->s_swl2 = si->si_ack; 43611819Sjulian cb->s_swnd = (1 + si->si_alo - si->si_ack); 43711819Sjulian if (cb->s_swnd > cb->s_smxw) 43811819Sjulian cb->s_smxw = cb->s_swnd; 43911819Sjulian cb->s_flags |= SF_WIN; 44011819Sjulian } 44111819Sjulian /* 44211819Sjulian * If this packet number is higher than that which 44311819Sjulian * we have allocated refuse it, unless urgent 44411819Sjulian */ 44511819Sjulian if (SSEQ_GT(si->si_seq, cb->s_alo)) { 44611819Sjulian if (si->si_cc & SPX_SP) { 44711819Sjulian spxstat.spxs_rcvwinprobe++; 44811819Sjulian return (1); 44911819Sjulian } else 45011819Sjulian spxstat.spxs_rcvpackafterwin++; 45111819Sjulian if (si->si_cc & SPX_OB) { 45211819Sjulian if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { 45311819Sjulian ipx_error(dtom(si), IPX_ERR_FULLUP, 0); 45411819Sjulian return (0); 45511819Sjulian } /* else queue this packet; */ 45611819Sjulian } else { 45711819Sjulian /*register struct socket *so = cb->s_ipxpcb->ipxp_socket; 45811819Sjulian if (so->so_state && SS_NOFDREF) { 45911819Sjulian ipx_error(dtom(si), IPX_ERR_NOSOCK, 0); 46011819Sjulian (void)spx_close(cb); 46111819Sjulian } else 46211819Sjulian would crash system*/ 46311819Sjulian spx_istat.notyet++; 46411819Sjulian ipx_error(dtom(si), IPX_ERR_FULLUP, 0); 46511819Sjulian return (0); 46611819Sjulian } 46711819Sjulian } 46811819Sjulian /* 46911819Sjulian * If this is a system packet, we don't need to 47011819Sjulian * queue it up, and won't update acknowledge # 47111819Sjulian */ 47211819Sjulian if (si->si_cc & SPX_SP) { 47311819Sjulian return (1); 47411819Sjulian } 47511819Sjulian /* 47611819Sjulian * We have already seen this packet, so drop. 47711819Sjulian */ 47811819Sjulian if (SSEQ_LT(si->si_seq, cb->s_ack)) { 47911819Sjulian spx_istat.bdreas++; 48011819Sjulian spxstat.spxs_rcvduppack++; 48111819Sjulian if (si->si_seq == cb->s_ack - 1) 48211819Sjulian spx_istat.lstdup++; 48311819Sjulian return (1); 48411819Sjulian } 48511819Sjulian /* 48611819Sjulian * Loop through all packets queued up to insert in 48711819Sjulian * appropriate sequence. 48811819Sjulian */ 48911819Sjulian for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 49011819Sjulian if (si->si_seq == SI(q)->si_seq) { 49111819Sjulian spxstat.spxs_rcvduppack++; 49211819Sjulian return (1); 49311819Sjulian } 49411819Sjulian if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { 49511819Sjulian spxstat.spxs_rcvoopack++; 49611819Sjulian break; 49711819Sjulian } 49811819Sjulian } 49911819Sjulian insque(si, q->si_prev); 50011819Sjulian /* 50111819Sjulian * If this packet is urgent, inform process 50211819Sjulian */ 50311819Sjulian if (si->si_cc & SPX_OB) { 50411819Sjulian cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 50511819Sjulian sohasoutofband(so); 50611819Sjulian cb->s_oobflags |= SF_IOOB; 50711819Sjulian } 50811819Sjulianpresent: 50911819Sjulian#define SPINC sizeof(struct spxhdr) 51011819Sjulian /* 51111819Sjulian * Loop through all packets queued up to update acknowledge 51211819Sjulian * number, and present all acknowledged data to user; 51311819Sjulian * If in packet interface mode, show packet headers. 51411819Sjulian */ 51511819Sjulian for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 51611819Sjulian if (SI(q)->si_seq == cb->s_ack) { 51711819Sjulian cb->s_ack++; 51811819Sjulian m = dtom(q); 51911819Sjulian if (SI(q)->si_cc & SPX_OB) { 52011819Sjulian cb->s_oobflags &= ~SF_IOOB; 52111819Sjulian if (so->so_rcv.sb_cc) 52211819Sjulian so->so_oobmark = so->so_rcv.sb_cc; 52311819Sjulian else 52411819Sjulian so->so_state |= SS_RCVATMARK; 52511819Sjulian } 52611819Sjulian q = q->si_prev; 52711819Sjulian remque(q->si_next); 52811819Sjulian wakeup = 1; 52911819Sjulian spxstat.spxs_rcvpack++; 53011819Sjulian#ifdef SF_NEWCALL 53111819Sjulian if (cb->s_flags2 & SF_NEWCALL) { 53211819Sjulian struct spxhdr *sp = mtod(m, struct spxhdr *); 53311819Sjulian u_char dt = sp->spx_dt; 53411819Sjulian spx_newchecks[4]++; 53511819Sjulian if (dt != cb->s_rhdr.spx_dt) { 53611819Sjulian struct mbuf *mm = 53711819Sjulian m_getclr(M_DONTWAIT, MT_CONTROL); 53811819Sjulian spx_newchecks[0]++; 53911819Sjulian if (mm != NULL) { 54011819Sjulian u_short *s = 54111819Sjulian mtod(mm, u_short *); 54211819Sjulian cb->s_rhdr.spx_dt = dt; 54311819Sjulian mm->m_len = 5; /*XXX*/ 54411819Sjulian s[0] = 5; 54511819Sjulian s[1] = 1; 54611819Sjulian *(u_char *)(&s[2]) = dt; 54711819Sjulian sbappend(&so->so_rcv, mm); 54811819Sjulian } 54911819Sjulian } 55011819Sjulian if (sp->spx_cc & SPX_OB) { 55111819Sjulian MCHTYPE(m, MT_OOBDATA); 55211819Sjulian spx_newchecks[1]++; 55311819Sjulian so->so_oobmark = 0; 55411819Sjulian so->so_state &= ~SS_RCVATMARK; 55511819Sjulian } 55611819Sjulian if (packetp == 0) { 55711819Sjulian m->m_data += SPINC; 55811819Sjulian m->m_len -= SPINC; 55911819Sjulian m->m_pkthdr.len -= SPINC; 56011819Sjulian } 56111819Sjulian if ((sp->spx_cc & SPX_EM) || packetp) { 56211819Sjulian sbappendrecord(&so->so_rcv, m); 56311819Sjulian spx_newchecks[9]++; 56411819Sjulian } else 56511819Sjulian sbappend(&so->so_rcv, m); 56611819Sjulian } else 56711819Sjulian#endif 56811819Sjulian if (packetp) { 56911819Sjulian sbappendrecord(&so->so_rcv, m); 57011819Sjulian } else { 57111819Sjulian cb->s_rhdr = *mtod(m, struct spxhdr *); 57211819Sjulian m->m_data += SPINC; 57311819Sjulian m->m_len -= SPINC; 57411819Sjulian m->m_pkthdr.len -= SPINC; 57511819Sjulian sbappend(&so->so_rcv, m); 57611819Sjulian } 57711819Sjulian } else 57811819Sjulian break; 57911819Sjulian } 58011819Sjulian if (wakeup) sorwakeup(so); 58111819Sjulian return (0); 58211819Sjulian} 58311819Sjulian 58411819Sjulianvoid 58511819Sjulianspx_ctlinput(cmd, arg) 58611819Sjulian int cmd; 58711819Sjulian caddr_t arg; 58811819Sjulian{ 58911819Sjulian struct ipx_addr *na; 59011819Sjulian struct ipx_errp *errp = (struct ipx_errp *)arg; 59111819Sjulian struct ipxpcb *ipxp; 59211819Sjulian struct sockaddr_ipx *sipx; 59311819Sjulian int type; 59411819Sjulian 59511819Sjulian if (cmd < 0 || cmd > PRC_NCMDS) 59611819Sjulian return; 59711819Sjulian type = IPX_ERR_UNREACH_HOST; 59811819Sjulian 59911819Sjulian switch (cmd) { 60011819Sjulian 60111819Sjulian case PRC_ROUTEDEAD: 60211819Sjulian return; 60311819Sjulian 60411819Sjulian case PRC_IFDOWN: 60511819Sjulian case PRC_HOSTDEAD: 60611819Sjulian case PRC_HOSTUNREACH: 60711819Sjulian sipx = (struct sockaddr_ipx *)arg; 60811819Sjulian if (sipx->sipx_family != AF_IPX) 60911819Sjulian return; 61011819Sjulian na = &sipx->sipx_addr; 61111819Sjulian break; 61211819Sjulian 61311819Sjulian default: 61411819Sjulian errp = (struct ipx_errp *)arg; 61511819Sjulian na = &errp->ipx_err_ipx.ipx_dna; 61611819Sjulian type = errp->ipx_err_num; 61711819Sjulian type = ntohs((u_short)type); 61811819Sjulian break; 61911819Sjulian } 62011819Sjulian switch (type) { 62111819Sjulian 62211819Sjulian case IPX_ERR_UNREACH_HOST: 62311819Sjulian ipx_pcbnotify(na, (int)ipxctlerrmap[cmd], spx_abort, (long) 0); 62411819Sjulian break; 62511819Sjulian 62611819Sjulian case IPX_ERR_TOO_BIG: 62711819Sjulian case IPX_ERR_NOSOCK: 62811819Sjulian ipxp = ipx_pcblookup(na, errp->ipx_err_ipx.ipx_sna.x_port, 62911819Sjulian IPX_WILDCARD); 63011819Sjulian if (ipxp) { 63111819Sjulian if(ipxp->ipxp_pcb) 63211819Sjulian (void) spx_drop((struct spxpcb *)ipxp->ipxp_pcb, 63311819Sjulian (int)ipxctlerrmap[cmd]); 63411819Sjulian else 63511819Sjulian (void) ipx_drop(ipxp, (int)ipxctlerrmap[cmd]); 63611819Sjulian } 63711819Sjulian break; 63811819Sjulian 63911819Sjulian case IPX_ERR_FULLUP: 64011819Sjulian ipx_pcbnotify(na, 0, spx_quench, (long) 0); 64111819Sjulian break; 64211819Sjulian } 64311819Sjulian} 64411819Sjulian/* 64511819Sjulian * When a source quench is received, close congestion window 64611819Sjulian * to one packet. We will gradually open it again as we proceed. 64711819Sjulian */ 64811819Sjulianvoid 64911819Sjulianspx_quench(ipxp) 65011819Sjulian struct ipxpcb *ipxp; 65111819Sjulian{ 65211819Sjulian struct spxpcb *cb = ipxtospxpcb(ipxp); 65311819Sjulian 65411819Sjulian if (cb) 65511819Sjulian cb->s_cwnd = CUNIT; 65611819Sjulian} 65711819Sjulian 65811819Sjulian#ifdef notdef 65911819Sjulianint 66011819Sjulianspx_fixmtu(ipxp) 66111819Sjulianregister struct ipxpcb *ipxp; 66211819Sjulian{ 66311819Sjulian register struct spxpcb *cb = (struct spxpcb *)(ipxp->ipxp_pcb); 66411819Sjulian register struct mbuf *m; 66511819Sjulian register struct spx *si; 66611819Sjulian struct ipx_errp *ep; 66711819Sjulian struct sockbuf *sb; 66811819Sjulian int badseq, len; 66911819Sjulian struct mbuf *firstbad, *m0; 67011819Sjulian 67111819Sjulian if (cb) { 67211819Sjulian /* 67311819Sjulian * The notification that we have sent 67411819Sjulian * too much is bad news -- we will 67511819Sjulian * have to go through queued up so far 67611819Sjulian * splitting ones which are too big and 67711819Sjulian * reassigning sequence numbers and checksums. 67811819Sjulian * we should then retransmit all packets from 67911819Sjulian * one above the offending packet to the last one 68011819Sjulian * we had sent (or our allocation) 68111819Sjulian * then the offending one so that the any queued 68211819Sjulian * data at our destination will be discarded. 68311819Sjulian */ 68411819Sjulian ep = (struct ipx_errp *)ipxp->ipxp_notify_param; 68511819Sjulian sb = &ipxp->ipxp_socket->so_snd; 68611819Sjulian cb->s_mtu = ep->ipx_err_param; 68711819Sjulian badseq = SI(&ep->ipx_err_ipx)->si_seq; 68811819Sjulian for (m = sb->sb_mb; m; m = m->m_act) { 68911819Sjulian si = mtod(m, struct spx *); 69011819Sjulian if (si->si_seq == badseq) 69111819Sjulian break; 69211819Sjulian } 69311819Sjulian if (m == 0) return; 69411819Sjulian firstbad = m; 69511819Sjulian /*for (;;) {*/ 69611819Sjulian /* calculate length */ 69711819Sjulian for (m0 = m, len = 0; m ; m = m->m_next) 69811819Sjulian len += m->m_len; 69911819Sjulian if (len > cb->s_mtu) { 70011819Sjulian } 70111819Sjulian /* FINISH THIS 70211819Sjulian } */ 70311819Sjulian } 70411819Sjulian} 70511819Sjulian#endif 70611819Sjulian 70711819Sjulianint 70811819Sjulianspx_output(cb, m0) 70911819Sjulian register struct spxpcb *cb; 71011819Sjulian struct mbuf *m0; 71111819Sjulian{ 71211819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 71311819Sjulian register struct mbuf *m; 71411819Sjulian register struct spx *si = (struct spx *) 0; 71511819Sjulian register struct sockbuf *sb = &so->so_snd; 71611819Sjulian int len = 0, win, rcv_win; 71711819Sjulian short span, off, recordp = 0; 71811819Sjulian u_short alo; 71911819Sjulian int error = 0, sendalot; 72011819Sjulian#ifdef notdef 72111819Sjulian int idle; 72211819Sjulian#endif 72311819Sjulian struct mbuf *mprev; 72411819Sjulian 72511819Sjulian if (m0) { 72611819Sjulian int mtu = cb->s_mtu; 72711819Sjulian int datalen; 72811819Sjulian /* 72911819Sjulian * Make sure that packet isn't too big. 73011819Sjulian */ 73111819Sjulian for (m = m0; m ; m = m->m_next) { 73211819Sjulian mprev = m; 73311819Sjulian len += m->m_len; 73411819Sjulian if (m->m_flags & M_EOR) 73511819Sjulian recordp = 1; 73611819Sjulian } 73711819Sjulian datalen = (cb->s_flags & SF_HO) ? 73811819Sjulian len - sizeof (struct spxhdr) : len; 73911819Sjulian if (datalen > mtu) { 74011819Sjulian if (cb->s_flags & SF_PI) { 74111819Sjulian m_freem(m0); 74211819Sjulian return (EMSGSIZE); 74311819Sjulian } else { 74411819Sjulian int oldEM = cb->s_cc & SPX_EM; 74511819Sjulian 74611819Sjulian cb->s_cc &= ~SPX_EM; 74711819Sjulian while (len > mtu) { 74811819Sjulian /* 74911819Sjulian * Here we are only being called 75011819Sjulian * from usrreq(), so it is OK to 75111819Sjulian * block. 75211819Sjulian */ 75311819Sjulian m = m_copym(m0, 0, mtu, M_WAIT); 75411819Sjulian if (cb->s_flags & SF_NEWCALL) { 75511819Sjulian struct mbuf *mm = m; 75611819Sjulian spx_newchecks[7]++; 75711819Sjulian while (mm) { 75811819Sjulian mm->m_flags &= ~M_EOR; 75911819Sjulian mm = mm->m_next; 76011819Sjulian } 76111819Sjulian } 76211819Sjulian error = spx_output(cb, m); 76311819Sjulian if (error) { 76411819Sjulian cb->s_cc |= oldEM; 76511819Sjulian m_freem(m0); 76611819Sjulian return(error); 76711819Sjulian } 76811819Sjulian m_adj(m0, mtu); 76911819Sjulian len -= mtu; 77011819Sjulian } 77111819Sjulian cb->s_cc |= oldEM; 77211819Sjulian } 77311819Sjulian } 77411819Sjulian /* 77511819Sjulian * Force length even, by adding a "garbage byte" if 77611819Sjulian * necessary. 77711819Sjulian */ 77811819Sjulian if (len & 1) { 77911819Sjulian m = mprev; 78011819Sjulian if (M_TRAILINGSPACE(m) >= 1) 78111819Sjulian m->m_len++; 78211819Sjulian else { 78311819Sjulian struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 78411819Sjulian 78511819Sjulian if (m1 == 0) { 78611819Sjulian m_freem(m0); 78711819Sjulian return (ENOBUFS); 78811819Sjulian } 78911819Sjulian m1->m_len = 1; 79011819Sjulian *(mtod(m1, u_char *)) = 0; 79111819Sjulian m->m_next = m1; 79211819Sjulian } 79311819Sjulian } 79411819Sjulian m = m_gethdr(M_DONTWAIT, MT_HEADER); 79511819Sjulian if (m == 0) { 79611819Sjulian m_freem(m0); 79711819Sjulian return (ENOBUFS); 79811819Sjulian } 79911819Sjulian /* 80011819Sjulian * Fill in mbuf with extended SP header 80111819Sjulian * and addresses and length put into network format. 80211819Sjulian */ 80311819Sjulian MH_ALIGN(m, sizeof (struct spx)); 80411819Sjulian m->m_len = sizeof (struct spx); 80511819Sjulian m->m_next = m0; 80611819Sjulian si = mtod(m, struct spx *); 80711819Sjulian si->si_i = *cb->s_ipx; 80811819Sjulian si->si_s = cb->s_shdr; 80911819Sjulian if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 81011819Sjulian register struct spxhdr *sh; 81111819Sjulian if (m0->m_len < sizeof (*sh)) { 81211819Sjulian if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 81311819Sjulian (void) m_free(m); 81411819Sjulian m_freem(m0); 81511819Sjulian return (EINVAL); 81611819Sjulian } 81711819Sjulian m->m_next = m0; 81811819Sjulian } 81911819Sjulian sh = mtod(m0, struct spxhdr *); 82011819Sjulian si->si_dt = sh->spx_dt; 82111819Sjulian si->si_cc |= sh->spx_cc & SPX_EM; 82211819Sjulian m0->m_len -= sizeof (*sh); 82311819Sjulian m0->m_data += sizeof (*sh); 82411819Sjulian len -= sizeof (*sh); 82511819Sjulian } 82611819Sjulian len += sizeof(*si); 82711819Sjulian if ((cb->s_flags2 & SF_NEWCALL) && recordp) { 82811819Sjulian si->si_cc |= SPX_EM; 82911819Sjulian spx_newchecks[8]++; 83011819Sjulian } 83111819Sjulian if (cb->s_oobflags & SF_SOOB) { 83211819Sjulian /* 83311819Sjulian * Per jqj@cornell: 83411819Sjulian * make sure OB packets convey exactly 1 byte. 83511819Sjulian * If the packet is 1 byte or larger, we 83611819Sjulian * have already guaranted there to be at least 83711819Sjulian * one garbage byte for the checksum, and 83811819Sjulian * extra bytes shouldn't hurt! 83911819Sjulian */ 84011819Sjulian if (len > sizeof(*si)) { 84111819Sjulian si->si_cc |= SPX_OB; 84211819Sjulian len = (1 + sizeof(*si)); 84311819Sjulian } 84411819Sjulian } 84511819Sjulian si->si_len = htons((u_short)len); 84611819Sjulian m->m_pkthdr.len = ((len - 1) | 1) + 1; 84711819Sjulian /* 84811819Sjulian * queue stuff up for output 84911819Sjulian */ 85011819Sjulian sbappendrecord(sb, m); 85111819Sjulian cb->s_seq++; 85211819Sjulian } 85311819Sjulian#ifdef notdef 85411819Sjulian idle = (cb->s_smax == (cb->s_rack - 1)); 85511819Sjulian#endif 85611819Sjulianagain: 85711819Sjulian sendalot = 0; 85811819Sjulian off = cb->s_snxt - cb->s_rack; 85911819Sjulian win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)); 86011819Sjulian 86111819Sjulian /* 86211819Sjulian * If in persist timeout with window of 0, send a probe. 86311819Sjulian * Otherwise, if window is small but nonzero 86411819Sjulian * and timer expired, send what we can and go into 86511819Sjulian * transmit state. 86611819Sjulian */ 86711819Sjulian if (cb->s_force == 1 + SPXT_PERSIST) { 86811819Sjulian if (win != 0) { 86911819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 87011819Sjulian cb->s_rxtshift = 0; 87111819Sjulian } 87211819Sjulian } 87311819Sjulian span = cb->s_seq - cb->s_rack; 87411819Sjulian len = min(span, win) - off; 87511819Sjulian 87611819Sjulian if (len < 0) { 87711819Sjulian /* 87811819Sjulian * Window shrank after we went into it. 87911819Sjulian * If window shrank to 0, cancel pending 88011819Sjulian * restransmission and pull s_snxt back 88111819Sjulian * to (closed) window. We will enter persist 88211819Sjulian * state below. If the widndow didn't close completely, 88311819Sjulian * just wait for an ACK. 88411819Sjulian */ 88511819Sjulian len = 0; 88611819Sjulian if (win == 0) { 88711819Sjulian cb->s_timer[SPXT_REXMT] = 0; 88811819Sjulian cb->s_snxt = cb->s_rack; 88911819Sjulian } 89011819Sjulian } 89111819Sjulian if (len > 1) 89211819Sjulian sendalot = 1; 89311819Sjulian rcv_win = sbspace(&so->so_rcv); 89411819Sjulian 89511819Sjulian /* 89611819Sjulian * Send if we owe peer an ACK. 89711819Sjulian */ 89811819Sjulian if (cb->s_oobflags & SF_SOOB) { 89911819Sjulian /* 90011819Sjulian * must transmit this out of band packet 90111819Sjulian */ 90211819Sjulian cb->s_oobflags &= ~ SF_SOOB; 90311819Sjulian sendalot = 1; 90411819Sjulian spxstat.spxs_sndurg++; 90511819Sjulian goto found; 90611819Sjulian } 90711819Sjulian if (cb->s_flags & SF_ACKNOW) 90811819Sjulian goto send; 90911819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 91011819Sjulian goto send; 91111819Sjulian /* 91211819Sjulian * Silly window can't happen in spx. 91311819Sjulian * Code from tcp deleted. 91411819Sjulian */ 91511819Sjulian if (len) 91611819Sjulian goto send; 91711819Sjulian /* 91811819Sjulian * Compare available window to amount of window 91911819Sjulian * known to peer (as advertised window less 92011819Sjulian * next expected input.) If the difference is at least two 92111819Sjulian * packets or at least 35% of the mximum possible window, 92211819Sjulian * then want to send a window update to peer. 92311819Sjulian */ 92411819Sjulian if (rcv_win > 0) { 92511819Sjulian u_short delta = 1 + cb->s_alo - cb->s_ack; 92611819Sjulian int adv = rcv_win - (delta * cb->s_mtu); 92711819Sjulian 92811819Sjulian if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || 92911819Sjulian (100 * adv / so->so_rcv.sb_hiwat >= 35)) { 93011819Sjulian spxstat.spxs_sndwinup++; 93111819Sjulian cb->s_flags |= SF_ACKNOW; 93211819Sjulian goto send; 93311819Sjulian } 93411819Sjulian 93511819Sjulian } 93611819Sjulian /* 93711819Sjulian * Many comments from tcp_output.c are appropriate here 93811819Sjulian * including . . . 93911819Sjulian * If send window is too small, there is data to transmit, and no 94011819Sjulian * retransmit or persist is pending, then go to persist state. 94111819Sjulian * If nothing happens soon, send when timer expires: 94211819Sjulian * if window is nonzero, transmit what we can, 94311819Sjulian * otherwise send a probe. 94411819Sjulian */ 94511819Sjulian if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 && 94611819Sjulian cb->s_timer[SPXT_PERSIST] == 0) { 94711819Sjulian cb->s_rxtshift = 0; 94811819Sjulian spx_setpersist(cb); 94911819Sjulian } 95011819Sjulian /* 95111819Sjulian * No reason to send a packet, just return. 95211819Sjulian */ 95311819Sjulian cb->s_outx = 1; 95411819Sjulian return (0); 95511819Sjulian 95611819Sjuliansend: 95711819Sjulian /* 95811819Sjulian * Find requested packet. 95911819Sjulian */ 96011819Sjulian si = 0; 96111819Sjulian if (len > 0) { 96211819Sjulian cb->s_want = cb->s_snxt; 96311819Sjulian for (m = sb->sb_mb; m; m = m->m_act) { 96411819Sjulian si = mtod(m, struct spx *); 96511819Sjulian if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) 96611819Sjulian break; 96711819Sjulian } 96811819Sjulian found: 96911819Sjulian if (si) { 97011819Sjulian if (si->si_seq == cb->s_snxt) 97111819Sjulian cb->s_snxt++; 97211819Sjulian else 97311819Sjulian spxstat.spxs_sndvoid++, si = 0; 97411819Sjulian } 97511819Sjulian } 97611819Sjulian /* 97711819Sjulian * update window 97811819Sjulian */ 97911819Sjulian if (rcv_win < 0) 98011819Sjulian rcv_win = 0; 98111819Sjulian alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); 98211819Sjulian if (SSEQ_LT(alo, cb->s_alo)) 98311819Sjulian alo = cb->s_alo; 98411819Sjulian 98511819Sjulian if (si) { 98611819Sjulian /* 98711819Sjulian * must make a copy of this packet for 98811819Sjulian * ipx_output to monkey with 98911819Sjulian */ 99011819Sjulian m = m_copy(dtom(si), 0, (int)M_COPYALL); 99111819Sjulian if (m == NULL) { 99211819Sjulian return (ENOBUFS); 99311819Sjulian } 99411819Sjulian si = mtod(m, struct spx *); 99511819Sjulian if (SSEQ_LT(si->si_seq, cb->s_smax)) 99611819Sjulian spxstat.spxs_sndrexmitpack++; 99711819Sjulian else 99811819Sjulian spxstat.spxs_sndpack++; 99911819Sjulian } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { 100011819Sjulian /* 100111819Sjulian * Must send an acknowledgement or a probe 100211819Sjulian */ 100311819Sjulian if (cb->s_force) 100411819Sjulian spxstat.spxs_sndprobe++; 100511819Sjulian if (cb->s_flags & SF_ACKNOW) 100611819Sjulian spxstat.spxs_sndacks++; 100711819Sjulian m = m_gethdr(M_DONTWAIT, MT_HEADER); 100811819Sjulian if (m == 0) 100911819Sjulian return (ENOBUFS); 101011819Sjulian /* 101111819Sjulian * Fill in mbuf with extended SP header 101211819Sjulian * and addresses and length put into network format. 101311819Sjulian */ 101411819Sjulian MH_ALIGN(m, sizeof (struct spx)); 101511819Sjulian m->m_len = sizeof (*si); 101611819Sjulian m->m_pkthdr.len = sizeof (*si); 101711819Sjulian si = mtod(m, struct spx *); 101811819Sjulian si->si_i = *cb->s_ipx; 101911819Sjulian si->si_s = cb->s_shdr; 102011819Sjulian si->si_seq = cb->s_smax + 1; 102111819Sjulian si->si_len = htons(sizeof (*si)); 102211819Sjulian si->si_cc |= SPX_SP; 102311819Sjulian } else { 102411819Sjulian cb->s_outx = 3; 102511819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) 102611819Sjulian spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 102711819Sjulian return (0); 102811819Sjulian } 102911819Sjulian /* 103011819Sjulian * Stuff checksum and output datagram. 103111819Sjulian */ 103211819Sjulian if ((si->si_cc & SPX_SP) == 0) { 103311819Sjulian if (cb->s_force != (1 + SPXT_PERSIST) || 103411819Sjulian cb->s_timer[SPXT_PERSIST] == 0) { 103511819Sjulian /* 103611819Sjulian * If this is a new packet and we are not currently 103711819Sjulian * timing anything, time this one. 103811819Sjulian */ 103911819Sjulian if (SSEQ_LT(cb->s_smax, si->si_seq)) { 104011819Sjulian cb->s_smax = si->si_seq; 104111819Sjulian if (cb->s_rtt == 0) { 104211819Sjulian spxstat.spxs_segstimed++; 104311819Sjulian cb->s_rtseq = si->si_seq; 104411819Sjulian cb->s_rtt = 1; 104511819Sjulian } 104611819Sjulian } 104711819Sjulian /* 104811819Sjulian * Set rexmt timer if not currently set, 104911819Sjulian * Initial value for retransmit timer is smoothed 105011819Sjulian * round-trip time + 2 * round-trip time variance. 105111819Sjulian * Initialize shift counter which is used for backoff 105211819Sjulian * of retransmit time. 105311819Sjulian */ 105411819Sjulian if (cb->s_timer[SPXT_REXMT] == 0 && 105511819Sjulian cb->s_snxt != cb->s_rack) { 105611819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 105711819Sjulian if (cb->s_timer[SPXT_PERSIST]) { 105811819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 105911819Sjulian cb->s_rxtshift = 0; 106011819Sjulian } 106111819Sjulian } 106211819Sjulian } else if (SSEQ_LT(cb->s_smax, si->si_seq)) { 106311819Sjulian cb->s_smax = si->si_seq; 106411819Sjulian } 106511819Sjulian } else if (cb->s_state < TCPS_ESTABLISHED) { 106611819Sjulian if (cb->s_rtt == 0) 106711819Sjulian cb->s_rtt = 1; /* Time initial handshake */ 106811819Sjulian if (cb->s_timer[SPXT_REXMT] == 0) 106911819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 107011819Sjulian } 107111819Sjulian { 107211819Sjulian /* 107311819Sjulian * Do not request acks when we ack their data packets or 107411819Sjulian * when we do a gratuitous window update. 107511819Sjulian */ 107611819Sjulian if (((si->si_cc & SPX_SP) == 0) || cb->s_force) 107711819Sjulian si->si_cc |= SPX_SA; 107811819Sjulian si->si_seq = htons(si->si_seq); 107911819Sjulian si->si_alo = htons(alo); 108011819Sjulian si->si_ack = htons(cb->s_ack); 108111819Sjulian 108211819Sjulian if (ipxcksum) { 108311819Sjulian si->si_sum = 0; 108411819Sjulian len = ntohs(si->si_len); 108511819Sjulian if (len & 1) 108611819Sjulian len++; 108711819Sjulian si->si_sum = ipx_cksum(m, len); 108811819Sjulian } else 108911819Sjulian si->si_sum = 0xffff; 109011819Sjulian 109111819Sjulian cb->s_outx = 4; 109211819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) 109311819Sjulian spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 109411819Sjulian 109511819Sjulian if (so->so_options & SO_DONTROUTE) 109611819Sjulian error = ipx_outputfl(m, (struct route *)0, IPX_ROUTETOIF); 109711819Sjulian else 109811819Sjulian error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0); 109911819Sjulian } 110011819Sjulian if (error) { 110111819Sjulian return (error); 110211819Sjulian } 110311819Sjulian spxstat.spxs_sndtotal++; 110411819Sjulian /* 110511819Sjulian * Data sent (as far as we can tell). 110611819Sjulian * If this advertises a larger window than any other segment, 110711819Sjulian * then remember the size of the advertized window. 110811819Sjulian * Any pending ACK has now been sent. 110911819Sjulian */ 111011819Sjulian cb->s_force = 0; 111111819Sjulian cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); 111211819Sjulian if (SSEQ_GT(alo, cb->s_alo)) 111311819Sjulian cb->s_alo = alo; 111411819Sjulian if (sendalot) 111511819Sjulian goto again; 111611819Sjulian cb->s_outx = 5; 111711819Sjulian return (0); 111811819Sjulian} 111911819Sjulian 112011819Sjulianint spx_do_persist_panics = 0; 112111819Sjulian 112211819Sjulianvoid 112311819Sjulianspx_setpersist(cb) 112411819Sjulian register struct spxpcb *cb; 112511819Sjulian{ 112611819Sjulian register t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 112711819Sjulian 112811819Sjulian if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics) 112911819Sjulian panic("spx_output REXMT"); 113011819Sjulian /* 113111819Sjulian * Start/restart persistance timer. 113211819Sjulian */ 113311819Sjulian SPXT_RANGESET(cb->s_timer[SPXT_PERSIST], 113411819Sjulian t*spx_backoff[cb->s_rxtshift], 113511819Sjulian SPXTV_PERSMIN, SPXTV_PERSMAX); 113611819Sjulian if (cb->s_rxtshift < SPX_MAXRXTSHIFT) 113711819Sjulian cb->s_rxtshift++; 113811819Sjulian} 113911819Sjulian/*ARGSUSED*/ 114011819Sjulianint 114111819Sjulianspx_ctloutput(req, so, level, name, value) 114211819Sjulian int req; 114311819Sjulian struct socket *so; 114411819Sjulian int level, name; 114511819Sjulian struct mbuf **value; 114611819Sjulian{ 114711819Sjulian register struct mbuf *m; 114811819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 114911819Sjulian register struct spxpcb *cb; 115011819Sjulian int mask, error = 0; 115111819Sjulian 115211819Sjulian if (level != IPXPROTO_SPX) { 115311819Sjulian /* This will have to be changed when we do more general 115411819Sjulian stacking of protocols */ 115511819Sjulian return (ipx_ctloutput(req, so, level, name, value)); 115611819Sjulian } 115711819Sjulian if (ipxp == NULL) { 115811819Sjulian error = EINVAL; 115911819Sjulian goto release; 116011819Sjulian } else 116111819Sjulian cb = ipxtospxpcb(ipxp); 116211819Sjulian 116311819Sjulian switch (req) { 116411819Sjulian 116511819Sjulian case PRCO_GETOPT: 116611819Sjulian if (value == NULL) 116711819Sjulian return (EINVAL); 116811819Sjulian m = m_get(M_DONTWAIT, MT_DATA); 116911819Sjulian if (m == NULL) 117011819Sjulian return (ENOBUFS); 117111819Sjulian switch (name) { 117211819Sjulian 117311819Sjulian case SO_HEADERS_ON_INPUT: 117411819Sjulian mask = SF_HI; 117511819Sjulian goto get_flags; 117611819Sjulian 117711819Sjulian case SO_HEADERS_ON_OUTPUT: 117811819Sjulian mask = SF_HO; 117911819Sjulian get_flags: 118011819Sjulian m->m_len = sizeof(short); 118111819Sjulian *mtod(m, short *) = cb->s_flags & mask; 118211819Sjulian break; 118311819Sjulian 118411819Sjulian case SO_MTU: 118511819Sjulian m->m_len = sizeof(u_short); 118611819Sjulian *mtod(m, short *) = cb->s_mtu; 118711819Sjulian break; 118811819Sjulian 118911819Sjulian case SO_LAST_HEADER: 119011819Sjulian m->m_len = sizeof(struct spxhdr); 119111819Sjulian *mtod(m, struct spxhdr *) = cb->s_rhdr; 119211819Sjulian break; 119311819Sjulian 119411819Sjulian case SO_DEFAULT_HEADERS: 119511819Sjulian m->m_len = sizeof(struct spx); 119611819Sjulian *mtod(m, struct spxhdr *) = cb->s_shdr; 119711819Sjulian break; 119811819Sjulian 119911819Sjulian default: 120011819Sjulian error = EINVAL; 120111819Sjulian } 120211819Sjulian *value = m; 120311819Sjulian break; 120411819Sjulian 120511819Sjulian case PRCO_SETOPT: 120611819Sjulian if (value == 0 || *value == 0) { 120711819Sjulian error = EINVAL; 120811819Sjulian break; 120911819Sjulian } 121011819Sjulian switch (name) { 121111819Sjulian int *ok; 121211819Sjulian 121311819Sjulian case SO_HEADERS_ON_INPUT: 121411819Sjulian mask = SF_HI; 121511819Sjulian goto set_head; 121611819Sjulian 121711819Sjulian case SO_HEADERS_ON_OUTPUT: 121811819Sjulian mask = SF_HO; 121911819Sjulian set_head: 122011819Sjulian if (cb->s_flags & SF_PI) { 122111819Sjulian ok = mtod(*value, int *); 122211819Sjulian if (*ok) 122311819Sjulian cb->s_flags |= mask; 122411819Sjulian else 122511819Sjulian cb->s_flags &= ~mask; 122611819Sjulian } else error = EINVAL; 122711819Sjulian break; 122811819Sjulian 122911819Sjulian case SO_MTU: 123011819Sjulian cb->s_mtu = *(mtod(*value, u_short *)); 123111819Sjulian break; 123211819Sjulian 123311819Sjulian#ifdef SF_NEWCALL 123411819Sjulian case SO_NEWCALL: 123511819Sjulian ok = mtod(*value, int *); 123611819Sjulian if (*ok) { 123711819Sjulian cb->s_flags2 |= SF_NEWCALL; 123811819Sjulian spx_newchecks[5]++; 123911819Sjulian } else { 124011819Sjulian cb->s_flags2 &= ~SF_NEWCALL; 124111819Sjulian spx_newchecks[6]++; 124211819Sjulian } 124311819Sjulian break; 124411819Sjulian#endif 124511819Sjulian 124611819Sjulian case SO_DEFAULT_HEADERS: 124711819Sjulian { 124811819Sjulian register struct spxhdr *sp 124911819Sjulian = mtod(*value, struct spxhdr *); 125011819Sjulian cb->s_dt = sp->spx_dt; 125111819Sjulian cb->s_cc = sp->spx_cc & SPX_EM; 125211819Sjulian } 125311819Sjulian break; 125411819Sjulian 125511819Sjulian default: 125611819Sjulian error = EINVAL; 125711819Sjulian } 125811819Sjulian m_freem(*value); 125911819Sjulian break; 126011819Sjulian } 126111819Sjulian release: 126211819Sjulian return (error); 126311819Sjulian} 126411819Sjulian 126511819Sjulian/*ARGSUSED*/ 126611819Sjulianint 126711819Sjulianspx_usrreq(so, req, m, nam, controlp) 126811819Sjulian struct socket *so; 126911819Sjulian int req; 127011819Sjulian struct mbuf *m, *nam, *controlp; 127111819Sjulian{ 127211819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 127311819Sjulian register struct spxpcb *cb = NULL; 127411819Sjulian int s = splnet(); 127511819Sjulian int error = 0, ostate; 127611819Sjulian struct mbuf *mm; 127711819Sjulian register struct sockbuf *sb; 127811819Sjulian 127911819Sjulian if (req == PRU_CONTROL) 128011819Sjulian return (ipx_control(so, (int)m, (caddr_t)nam, 128111819Sjulian (struct ifnet *)controlp)); 128211819Sjulian if (ipxp == NULL) { 128311819Sjulian if (req != PRU_ATTACH) { 128411819Sjulian error = EINVAL; 128511819Sjulian goto release; 128611819Sjulian } 128711819Sjulian } else 128811819Sjulian cb = ipxtospxpcb(ipxp); 128911819Sjulian 129011819Sjulian ostate = cb ? cb->s_state : 0; 129111819Sjulian 129211819Sjulian switch (req) { 129311819Sjulian 129411819Sjulian case PRU_ATTACH: 129511819Sjulian if (ipxp != NULL) { 129611819Sjulian error = EISCONN; 129711819Sjulian break; 129811819Sjulian } 129911819Sjulian error = ipx_pcballoc(so, &ipxpcb); 130011819Sjulian if (error) 130111819Sjulian break; 130211819Sjulian if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 130311819Sjulian error = soreserve(so, (u_long) 3072, (u_long) 3072); 130411819Sjulian if (error) 130511819Sjulian break; 130611819Sjulian } 130711819Sjulian ipxp = sotoipxpcb(so); 130811819Sjulian 130911819Sjulian mm = m_getclr(M_DONTWAIT, MT_PCB); 131011819Sjulian sb = &so->so_snd; 131111819Sjulian 131211819Sjulian if (mm == NULL) { 131311819Sjulian error = ENOBUFS; 131411819Sjulian break; 131511819Sjulian } 131611819Sjulian cb = mtod(mm, struct spxpcb *); 131711819Sjulian mm = m_getclr(M_DONTWAIT, MT_HEADER); 131811819Sjulian if (mm == NULL) { 131911819Sjulian (void) m_free(dtom(m)); 132011819Sjulian error = ENOBUFS; 132111819Sjulian break; 132211819Sjulian } 132311819Sjulian cb->s_ipx = mtod(mm, struct ipx *); 132411819Sjulian cb->s_state = TCPS_LISTEN; 132511819Sjulian cb->s_smax = -1; 132611819Sjulian cb->s_swl1 = -1; 132711819Sjulian cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 132811819Sjulian cb->s_ipxpcb = ipxp; 132911819Sjulian cb->s_mtu = 576 - sizeof (struct spx); 133011819Sjulian cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; 133111819Sjulian cb->s_ssthresh = cb->s_cwnd; 133211819Sjulian cb->s_cwmx = sbspace(sb) * CUNIT / 133311819Sjulian (2 * sizeof (struct spx)); 133411819Sjulian /* Above is recomputed when connecting to account 133511819Sjulian for changed buffering or mtu's */ 133611819Sjulian cb->s_rtt = SPXTV_SRTTBASE; 133711819Sjulian cb->s_rttvar = SPXTV_SRTTDFLT << 2; 133811819Sjulian SPXT_RANGESET(cb->s_rxtcur, 133911819Sjulian ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1, 134011819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 134111819Sjulian ipxp->ipxp_pcb = (caddr_t) cb; 134211819Sjulian break; 134311819Sjulian 134411819Sjulian case PRU_DETACH: 134511819Sjulian if (ipxp == NULL) { 134611819Sjulian error = ENOTCONN; 134711819Sjulian break; 134811819Sjulian } 134911819Sjulian if (cb->s_state > TCPS_LISTEN) 135011819Sjulian cb = spx_disconnect(cb); 135111819Sjulian else 135211819Sjulian cb = spx_close(cb); 135311819Sjulian break; 135411819Sjulian 135511819Sjulian case PRU_BIND: 135611819Sjulian error = ipx_pcbbind(ipxp, nam); 135711819Sjulian break; 135811819Sjulian 135911819Sjulian case PRU_LISTEN: 136011819Sjulian if (ipxp->ipxp_lport == 0) 136111819Sjulian error = ipx_pcbbind(ipxp, (struct mbuf *)0); 136211819Sjulian if (error == 0) 136311819Sjulian cb->s_state = TCPS_LISTEN; 136411819Sjulian break; 136511819Sjulian 136611819Sjulian /* 136711819Sjulian * Initiate connection to peer. 136811819Sjulian * Enter SYN_SENT state, and mark socket as connecting. 136911819Sjulian * Start keep-alive timer, setup prototype header, 137011819Sjulian * Send initial system packet requesting connection. 137111819Sjulian */ 137211819Sjulian case PRU_CONNECT: 137311819Sjulian if (ipxp->ipxp_lport == 0) { 137411819Sjulian error = ipx_pcbbind(ipxp, (struct mbuf *)0); 137511819Sjulian if (error) 137611819Sjulian break; 137711819Sjulian } 137811819Sjulian error = ipx_pcbconnect(ipxp, nam); 137911819Sjulian if (error) 138011819Sjulian break; 138111819Sjulian soisconnecting(so); 138211819Sjulian spxstat.spxs_connattempt++; 138311819Sjulian cb->s_state = TCPS_SYN_SENT; 138411819Sjulian cb->s_did = 0; 138511819Sjulian spx_template(cb); 138611819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 138711819Sjulian cb->s_force = 1 + SPXTV_KEEP; 138811819Sjulian /* 138911819Sjulian * Other party is required to respond to 139011819Sjulian * the port I send from, but he is not 139111819Sjulian * required to answer from where I am sending to, 139211819Sjulian * so allow wildcarding. 139311819Sjulian * original port I am sending to is still saved in 139411819Sjulian * cb->s_dport. 139511819Sjulian */ 139611819Sjulian ipxp->ipxp_fport = 0; 139711819Sjulian error = spx_output(cb, (struct mbuf *) 0); 139811819Sjulian break; 139911819Sjulian 140011819Sjulian case PRU_CONNECT2: 140111819Sjulian error = EOPNOTSUPP; 140211819Sjulian break; 140311819Sjulian 140411819Sjulian /* 140511819Sjulian * We may decide later to implement connection closing 140611819Sjulian * handshaking at the spx level optionally. 140711819Sjulian * here is the hook to do it: 140811819Sjulian */ 140911819Sjulian case PRU_DISCONNECT: 141011819Sjulian cb = spx_disconnect(cb); 141111819Sjulian break; 141211819Sjulian 141311819Sjulian /* 141411819Sjulian * Accept a connection. Essentially all the work is 141511819Sjulian * done at higher levels; just return the address 141611819Sjulian * of the peer, storing through addr. 141711819Sjulian */ 141811819Sjulian case PRU_ACCEPT: { 141911819Sjulian struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *); 142011819Sjulian 142111819Sjulian nam->m_len = sizeof (struct sockaddr_ipx); 142211819Sjulian sipx->sipx_family = AF_IPX; 142311819Sjulian sipx->sipx_addr = ipxp->ipxp_faddr; 142411819Sjulian break; 142511819Sjulian } 142611819Sjulian 142711819Sjulian case PRU_SHUTDOWN: 142811819Sjulian socantsendmore(so); 142911819Sjulian cb = spx_usrclosed(cb); 143011819Sjulian if (cb) 143111819Sjulian error = spx_output(cb, (struct mbuf *) 0); 143211819Sjulian break; 143311819Sjulian 143411819Sjulian /* 143511819Sjulian * After a receive, possibly send acknowledgment 143611819Sjulian * updating allocation. 143711819Sjulian */ 143811819Sjulian case PRU_RCVD: 143911819Sjulian cb->s_flags |= SF_RVD; 144011819Sjulian (void) spx_output(cb, (struct mbuf *) 0); 144111819Sjulian cb->s_flags &= ~SF_RVD; 144211819Sjulian break; 144311819Sjulian 144411819Sjulian case PRU_ABORT: 144511819Sjulian (void) spx_drop(cb, ECONNABORTED); 144611819Sjulian break; 144711819Sjulian 144811819Sjulian case PRU_SENSE: 144911819Sjulian case PRU_CONTROL: 145011819Sjulian m = NULL; 145111819Sjulian error = EOPNOTSUPP; 145211819Sjulian break; 145311819Sjulian 145411819Sjulian case PRU_RCVOOB: 145511819Sjulian if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 145611819Sjulian (so->so_state & SS_RCVATMARK)) { 145711819Sjulian m->m_len = 1; 145811819Sjulian *mtod(m, caddr_t) = cb->s_iobc; 145911819Sjulian break; 146011819Sjulian } 146111819Sjulian error = EINVAL; 146211819Sjulian break; 146311819Sjulian 146411819Sjulian case PRU_SENDOOB: 146511819Sjulian if (sbspace(&so->so_snd) < -512) { 146611819Sjulian error = ENOBUFS; 146711819Sjulian break; 146811819Sjulian } 146911819Sjulian cb->s_oobflags |= SF_SOOB; 147011819Sjulian /* fall into */ 147111819Sjulian case PRU_SEND: 147211819Sjulian if (controlp) { 147311819Sjulian u_short *p = mtod(controlp, u_short *); 147411819Sjulian spx_newchecks[2]++; 147511819Sjulian if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */ 147611819Sjulian cb->s_shdr.spx_dt = *(u_char *)(&p[2]); 147711819Sjulian spx_newchecks[3]++; 147811819Sjulian } 147911819Sjulian m_freem(controlp); 148011819Sjulian } 148111819Sjulian controlp = NULL; 148211819Sjulian error = spx_output(cb, m); 148311819Sjulian m = NULL; 148411819Sjulian break; 148511819Sjulian 148611819Sjulian case PRU_SOCKADDR: 148711819Sjulian ipx_setsockaddr(ipxp, nam); 148811819Sjulian break; 148911819Sjulian 149011819Sjulian case PRU_PEERADDR: 149111819Sjulian ipx_setpeeraddr(ipxp, nam); 149211819Sjulian break; 149311819Sjulian 149411819Sjulian case PRU_SLOWTIMO: 149511819Sjulian cb = spx_timers(cb, (int)nam); 149611819Sjulian req |= ((int)nam) << 8; 149711819Sjulian break; 149811819Sjulian 149911819Sjulian case PRU_FASTTIMO: 150011819Sjulian case PRU_PROTORCV: 150111819Sjulian case PRU_PROTOSEND: 150211819Sjulian error = EOPNOTSUPP; 150311819Sjulian break; 150411819Sjulian 150511819Sjulian default: 150611819Sjulian panic("spx_usrreq"); 150711819Sjulian } 150811819Sjulian if (cb && (so->so_options & SO_DEBUG || traceallspxs)) 150911819Sjulian spx_trace(SA_USER, (u_char)ostate, cb, (struct spx *)0, req); 151011819Sjulianrelease: 151111819Sjulian if (controlp != NULL) 151211819Sjulian m_freem(controlp); 151311819Sjulian if (m != NULL) 151411819Sjulian m_freem(m); 151511819Sjulian splx(s); 151611819Sjulian return (error); 151711819Sjulian} 151811819Sjulian 151911819Sjulianint 152011819Sjulianspx_usrreq_sp(so, req, m, nam, controlp) 152111819Sjulian struct socket *so; 152211819Sjulian int req; 152311819Sjulian struct mbuf *m, *nam, *controlp; 152411819Sjulian{ 152511819Sjulian int error = spx_usrreq(so, req, m, nam, controlp); 152611819Sjulian 152711819Sjulian if (req == PRU_ATTACH && error == 0) { 152811819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 152911819Sjulian ((struct spxpcb *)ipxp->ipxp_pcb)->s_flags |= 153011819Sjulian (SF_HI | SF_HO | SF_PI); 153111819Sjulian } 153211819Sjulian return (error); 153311819Sjulian} 153411819Sjulian 153511819Sjulian/* 153611819Sjulian * Create template to be used to send spx packets on a connection. 153711819Sjulian * Called after host entry created, fills 153811819Sjulian * in a skeletal spx header (choosing connection id), 153911819Sjulian * minimizing the amount of work necessary when the connection is used. 154011819Sjulian */ 154111819Sjulianvoid 154211819Sjulianspx_template(cb) 154311819Sjulian register struct spxpcb *cb; 154411819Sjulian{ 154511819Sjulian register struct ipxpcb *ipxp = cb->s_ipxpcb; 154611819Sjulian register struct ipx *ipx = cb->s_ipx; 154711819Sjulian register struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd); 154811819Sjulian 154911819Sjulian ipx->ipx_pt = IPXPROTO_SPX; 155011819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 155111819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 155211819Sjulian cb->s_sid = htons(spx_iss); 155311819Sjulian spx_iss += SPX_ISSINCR/2; 155411819Sjulian cb->s_alo = 1; 155511819Sjulian cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; 155611819Sjulian cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement 155711819Sjulian of large packets */ 155811819Sjulian cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx)); 155911819Sjulian cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); 156011819Sjulian /* But allow for lots of little packets as well */ 156111819Sjulian} 156211819Sjulian 156311819Sjulian/* 156411819Sjulian * Close a SPIP control block: 156511819Sjulian * discard spx control block itself 156611819Sjulian * discard ipx protocol control block 156711819Sjulian * wake up any sleepers 156811819Sjulian */ 156911819Sjulianstruct spxpcb * 157011819Sjulianspx_close(cb) 157111819Sjulian register struct spxpcb *cb; 157211819Sjulian{ 157311819Sjulian register struct spx_q *s; 157411819Sjulian struct ipxpcb *ipxp = cb->s_ipxpcb; 157511819Sjulian struct socket *so = ipxp->ipxp_socket; 157611819Sjulian register struct mbuf *m; 157711819Sjulian 157811819Sjulian s = cb->s_q.si_next; 157911819Sjulian while (s != &(cb->s_q)) { 158011819Sjulian s = s->si_next; 158111819Sjulian m = dtom(s->si_prev); 158211819Sjulian remque(s->si_prev); 158311819Sjulian m_freem(m); 158411819Sjulian } 158511819Sjulian (void) m_free(dtom(cb->s_ipx)); 158611819Sjulian (void) m_free(dtom(cb)); 158711819Sjulian ipxp->ipxp_pcb = 0; 158811819Sjulian soisdisconnected(so); 158911819Sjulian ipx_pcbdetach(ipxp); 159011819Sjulian spxstat.spxs_closed++; 159111819Sjulian return ((struct spxpcb *)0); 159211819Sjulian} 159311819Sjulian/* 159411819Sjulian * Someday we may do level 3 handshaking 159511819Sjulian * to close a connection or send a xerox style error. 159611819Sjulian * For now, just close. 159711819Sjulian */ 159811819Sjulianstruct spxpcb * 159911819Sjulianspx_usrclosed(cb) 160011819Sjulian register struct spxpcb *cb; 160111819Sjulian{ 160211819Sjulian return (spx_close(cb)); 160311819Sjulian} 160411819Sjulianstruct spxpcb * 160511819Sjulianspx_disconnect(cb) 160611819Sjulian register struct spxpcb *cb; 160711819Sjulian{ 160811819Sjulian return (spx_close(cb)); 160911819Sjulian} 161011819Sjulian/* 161111819Sjulian * Drop connection, reporting 161211819Sjulian * the specified error. 161311819Sjulian */ 161411819Sjulianstruct spxpcb * 161511819Sjulianspx_drop(cb, errno) 161611819Sjulian register struct spxpcb *cb; 161711819Sjulian int errno; 161811819Sjulian{ 161911819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 162011819Sjulian 162111819Sjulian /* 162211819Sjulian * someday, in the xerox world 162311819Sjulian * we will generate error protocol packets 162411819Sjulian * announcing that the socket has gone away. 162511819Sjulian */ 162611819Sjulian if (TCPS_HAVERCVDSYN(cb->s_state)) { 162711819Sjulian spxstat.spxs_drops++; 162811819Sjulian cb->s_state = TCPS_CLOSED; 162911819Sjulian /*(void) tcp_output(cb);*/ 163011819Sjulian } else 163111819Sjulian spxstat.spxs_conndrops++; 163211819Sjulian so->so_error = errno; 163311819Sjulian return (spx_close(cb)); 163411819Sjulian} 163511819Sjulian 163611819Sjulianvoid 163711819Sjulianspx_abort(ipxp) 163811819Sjulian struct ipxpcb *ipxp; 163911819Sjulian{ 164011819Sjulian 164111819Sjulian (void) spx_close((struct spxpcb *)ipxp->ipxp_pcb); 164211819Sjulian} 164311819Sjulian 164411819Sjulianint spx_backoff[SPX_MAXRXTSHIFT+1] = 164511819Sjulian { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 164611819Sjulian/* 164711819Sjulian * Fast timeout routine for processing delayed acks 164811819Sjulian */ 164911819Sjulianvoid 165011819Sjulianspx_fasttimo() 165111819Sjulian{ 165211819Sjulian register struct ipxpcb *ipxp; 165311819Sjulian register struct spxpcb *cb; 165411819Sjulian int s = splnet(); 165511819Sjulian 165611819Sjulian ipxp = ipxpcb.ipxp_next; 165711819Sjulian if (ipxp) 165811819Sjulian for (; ipxp != &ipxpcb; ipxp = ipxp->ipxp_next) 165911819Sjulian if ((cb = (struct spxpcb *)ipxp->ipxp_pcb) && 166011819Sjulian (cb->s_flags & SF_DELACK)) { 166111819Sjulian cb->s_flags &= ~SF_DELACK; 166211819Sjulian cb->s_flags |= SF_ACKNOW; 166311819Sjulian spxstat.spxs_delack++; 166411819Sjulian (void) spx_output(cb, (struct mbuf *) 0); 166511819Sjulian } 166611819Sjulian splx(s); 166711819Sjulian} 166811819Sjulian 166911819Sjulian/* 167011819Sjulian * spx protocol timeout routine called every 500 ms. 167111819Sjulian * Updates the timers in all active pcb's and 167211819Sjulian * causes finite state machine actions if timers expire. 167311819Sjulian */ 167411819Sjulianvoid 167511819Sjulianspx_slowtimo() 167611819Sjulian{ 167711819Sjulian register struct ipxpcb *ip, *ipnxt; 167811819Sjulian register struct spxpcb *cb; 167911819Sjulian int s = splnet(); 168011819Sjulian register int i; 168111819Sjulian 168211819Sjulian /* 168311819Sjulian * Search through tcb's and update active timers. 168411819Sjulian */ 168511819Sjulian ip = ipxpcb.ipxp_next; 168611819Sjulian if (ip == 0) { 168711819Sjulian splx(s); 168811819Sjulian return; 168911819Sjulian } 169011819Sjulian while (ip != &ipxpcb) { 169111819Sjulian cb = ipxtospxpcb(ip); 169211819Sjulian ipnxt = ip->ipxp_next; 169311819Sjulian if (cb == 0) 169411819Sjulian goto tpgone; 169511819Sjulian for (i = 0; i < SPXT_NTIMERS; i++) { 169611819Sjulian if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 169711819Sjulian (void) spx_usrreq(cb->s_ipxpcb->ipxp_socket, 169811819Sjulian PRU_SLOWTIMO, (struct mbuf *)0, 169911819Sjulian (struct mbuf *)i, (struct mbuf *)0, 170011819Sjulian (struct mbuf *)0); 170111819Sjulian if (ipnxt->ipxp_prev != ip) 170211819Sjulian goto tpgone; 170311819Sjulian } 170411819Sjulian } 170511819Sjulian cb->s_idle++; 170611819Sjulian if (cb->s_rtt) 170711819Sjulian cb->s_rtt++; 170811819Sjuliantpgone: 170911819Sjulian ip = ipnxt; 171011819Sjulian } 171111819Sjulian spx_iss += SPX_ISSINCR/PR_SLOWHZ; /* increment iss */ 171211819Sjulian splx(s); 171311819Sjulian} 171411819Sjulian/* 171511819Sjulian * SPX timer processing. 171611819Sjulian */ 171711819Sjulianstruct spxpcb * 171811819Sjulianspx_timers(cb, timer) 171911819Sjulian register struct spxpcb *cb; 172011819Sjulian int timer; 172111819Sjulian{ 172211819Sjulian long rexmt; 172311819Sjulian int win; 172411819Sjulian 172511819Sjulian cb->s_force = 1 + timer; 172611819Sjulian switch (timer) { 172711819Sjulian 172811819Sjulian /* 172911819Sjulian * 2 MSL timeout in shutdown went off. TCP deletes connection 173011819Sjulian * control block. 173111819Sjulian */ 173211819Sjulian case SPXT_2MSL: 173311819Sjulian printf("spx: SPXT_2MSL went off for no reason\n"); 173411819Sjulian cb->s_timer[timer] = 0; 173511819Sjulian break; 173611819Sjulian 173711819Sjulian /* 173811819Sjulian * Retransmission timer went off. Message has not 173911819Sjulian * been acked within retransmit interval. Back off 174011819Sjulian * to a longer retransmit interval and retransmit one packet. 174111819Sjulian */ 174211819Sjulian case SPXT_REXMT: 174311819Sjulian if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) { 174411819Sjulian cb->s_rxtshift = SPX_MAXRXTSHIFT; 174511819Sjulian spxstat.spxs_timeoutdrop++; 174611819Sjulian cb = spx_drop(cb, ETIMEDOUT); 174711819Sjulian break; 174811819Sjulian } 174911819Sjulian spxstat.spxs_rexmttimeo++; 175011819Sjulian rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 175111819Sjulian rexmt *= spx_backoff[cb->s_rxtshift]; 175211819Sjulian SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX); 175311819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 175411819Sjulian /* 175511819Sjulian * If we have backed off fairly far, our srtt 175611819Sjulian * estimate is probably bogus. Clobber it 175711819Sjulian * so we'll take the next rtt measurement as our srtt; 175811819Sjulian * move the current srtt into rttvar to keep the current 175911819Sjulian * retransmit times until then. 176011819Sjulian */ 176111819Sjulian if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) { 176211819Sjulian cb->s_rttvar += (cb->s_srtt >> 2); 176311819Sjulian cb->s_srtt = 0; 176411819Sjulian } 176511819Sjulian cb->s_snxt = cb->s_rack; 176611819Sjulian /* 176711819Sjulian * If timing a packet, stop the timer. 176811819Sjulian */ 176911819Sjulian cb->s_rtt = 0; 177011819Sjulian /* 177111819Sjulian * See very long discussion in tcp_timer.c about congestion 177211819Sjulian * window and sstrhesh 177311819Sjulian */ 177411819Sjulian win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; 177511819Sjulian if (win < 2) 177611819Sjulian win = 2; 177711819Sjulian cb->s_cwnd = CUNIT; 177811819Sjulian cb->s_ssthresh = win * CUNIT; 177911819Sjulian (void) spx_output(cb, (struct mbuf *) 0); 178011819Sjulian break; 178111819Sjulian 178211819Sjulian /* 178311819Sjulian * Persistance timer into zero window. 178411819Sjulian * Force a probe to be sent. 178511819Sjulian */ 178611819Sjulian case SPXT_PERSIST: 178711819Sjulian spxstat.spxs_persisttimeo++; 178811819Sjulian spx_setpersist(cb); 178911819Sjulian (void) spx_output(cb, (struct mbuf *) 0); 179011819Sjulian break; 179111819Sjulian 179211819Sjulian /* 179311819Sjulian * Keep-alive timer went off; send something 179411819Sjulian * or drop connection if idle for too long. 179511819Sjulian */ 179611819Sjulian case SPXT_KEEP: 179711819Sjulian spxstat.spxs_keeptimeo++; 179811819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 179911819Sjulian goto dropit; 180011819Sjulian if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) { 180111819Sjulian if (cb->s_idle >= SPXTV_MAXIDLE) 180211819Sjulian goto dropit; 180311819Sjulian spxstat.spxs_keepprobe++; 180411819Sjulian (void) spx_output(cb, (struct mbuf *) 0); 180511819Sjulian } else 180611819Sjulian cb->s_idle = 0; 180711819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 180811819Sjulian break; 180911819Sjulian dropit: 181011819Sjulian spxstat.spxs_keepdrops++; 181111819Sjulian cb = spx_drop(cb, ETIMEDOUT); 181211819Sjulian break; 181311819Sjulian } 181411819Sjulian return (cb); 181511819Sjulian} 1816