spx_reass.c revision 43711
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 * 3412057Sjulian * @(#)spx_usrreq.h 3512057Sjulian * 3643711Sjhay * $Id: spx_usrreq.c,v 1.24 1999/01/28 00:57:51 dillon Exp $ 3711819Sjulian */ 3811819Sjulian 3911819Sjulian#include <sys/param.h> 4011819Sjulian#include <sys/systm.h> 4129024Sbde#include <sys/malloc.h> 4211819Sjulian#include <sys/mbuf.h> 4325345Sjhay#include <sys/proc.h> 4411819Sjulian#include <sys/protosw.h> 4511819Sjulian#include <sys/socket.h> 4611819Sjulian#include <sys/socketvar.h> 4711819Sjulian 4811819Sjulian#include <net/route.h> 4911819Sjulian#include <netinet/tcp_fsm.h> 5011819Sjulian 5111819Sjulian#include <netipx/ipx.h> 5211819Sjulian#include <netipx/ipx_pcb.h> 5311819Sjulian#include <netipx/ipx_var.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 */ 6233181Seivindstatic u_short spx_iss; 6333181Seivindstatic u_short spx_newchecks[50]; 6433181Seivindstatic int spx_hardnosed; 6533181Seivindstatic int spx_use_delack = 0; 6633181Seivindstatic int traceallspxs = 0; 6733181Seivindstatic struct spx spx_savesi; 6833181Seivindstatic struct spx_istat spx_istat; 6911819Sjulian 7025652Sjhay/* Following was struct spxstat spxstat; */ 7125652Sjhay#ifndef spxstat 7225652Sjhay#define spxstat spx_istat.newstats 7325652Sjhay#endif 7411819Sjulian 7533181Seivindstatic int spx_backoff[SPX_MAXRXTSHIFT+1] = 7625652Sjhay { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 7711819Sjulian 7825652Sjhaystatic struct spxpcb *spx_close(struct spxpcb *cb); 7925652Sjhaystatic struct spxpcb *spx_disconnect(struct spxpcb *cb); 8025652Sjhaystatic struct spxpcb *spx_drop(struct spxpcb *cb, int errno); 8125652Sjhaystatic int spx_output(struct spxpcb *cb, struct mbuf *m0); 8225652Sjhaystatic int spx_reass(struct spxpcb *cb, struct spx *si); 8325652Sjhaystatic void spx_setpersist(struct spxpcb *cb); 8425652Sjhaystatic void spx_template(struct spxpcb *cb); 8525652Sjhaystatic struct spxpcb *spx_timers(struct spxpcb *cb, int timer); 8625652Sjhaystatic struct spxpcb *spx_usrclosed(struct spxpcb *cb); 8725652Sjhay 8824659Sjhaystatic int spx_usr_abort(struct socket *so); 8928270Swollmanstatic int spx_accept(struct socket *so, struct sockaddr **nam); 9025345Sjhaystatic int spx_attach(struct socket *so, int proto, struct proc *p); 9128270Swollmanstatic int spx_bind(struct socket *so, struct sockaddr *nam, struct proc *p); 9228270Swollmanstatic int spx_connect(struct socket *so, struct sockaddr *nam, 9328270Swollman struct proc *p); 9424659Sjhaystatic int spx_detach(struct socket *so); 9524659Sjhaystatic int spx_usr_disconnect(struct socket *so); 9625345Sjhaystatic int spx_listen(struct socket *so, struct proc *p); 9724659Sjhaystatic int spx_rcvd(struct socket *so, int flags); 9824659Sjhaystatic int spx_rcvoob(struct socket *so, struct mbuf *m, int flags); 9924659Sjhaystatic int spx_send(struct socket *so, int flags, struct mbuf *m, 10028270Swollman struct sockaddr *addr, struct mbuf *control, 10128270Swollman struct proc *p); 10224659Sjhaystatic int spx_shutdown(struct socket *so); 10325345Sjhaystatic int spx_sp_attach(struct socket *so, int proto, struct proc *p); 10424659Sjhay 10524659Sjhaystruct pr_usrreqs spx_usrreqs = { 10624659Sjhay spx_usr_abort, spx_accept, spx_attach, spx_bind, 10724659Sjhay spx_connect, pru_connect2_notsupp, ipx_control, spx_detach, 10824659Sjhay spx_usr_disconnect, spx_listen, ipx_peeraddr, spx_rcvd, 10924659Sjhay spx_rcvoob, spx_send, pru_sense_null, spx_shutdown, 11029366Speter ipx_sockaddr, sosend, soreceive, sopoll 11124659Sjhay}; 11224659Sjhay 11324659Sjhaystruct pr_usrreqs spx_usrreq_sps = { 11424659Sjhay spx_usr_abort, spx_accept, spx_sp_attach, spx_bind, 11524659Sjhay spx_connect, pru_connect2_notsupp, ipx_control, spx_detach, 11624659Sjhay spx_usr_disconnect, spx_listen, ipx_peeraddr, spx_rcvd, 11724659Sjhay spx_rcvoob, spx_send, pru_sense_null, spx_shutdown, 11829366Speter ipx_sockaddr, sosend, soreceive, sopoll 11924659Sjhay}; 12024659Sjhay 12111819Sjulianvoid 12211819Sjulianspx_init() 12311819Sjulian{ 12411819Sjulian 12511819Sjulian spx_iss = 1; /* WRONG !! should fish it out of TODR */ 12611819Sjulian} 12711819Sjulian 12811819Sjulianvoid 12911819Sjulianspx_input(m, ipxp) 13011819Sjulian register struct mbuf *m; 13111819Sjulian register struct ipxpcb *ipxp; 13211819Sjulian{ 13311819Sjulian register struct spxpcb *cb; 13411819Sjulian register struct spx *si = mtod(m, struct spx *); 13511819Sjulian register struct socket *so; 13611819Sjulian int dropsocket = 0; 13711819Sjulian short ostate = 0; 13811819Sjulian 13911819Sjulian spxstat.spxs_rcvtotal++; 14025652Sjhay if (ipxp == NULL) { 14111819Sjulian panic("No ipxpcb in spx_input\n"); 14211819Sjulian return; 14311819Sjulian } 14411819Sjulian 14511819Sjulian cb = ipxtospxpcb(ipxp); 14625652Sjhay if (cb == NULL) 14725652Sjhay goto bad; 14811819Sjulian 14911819Sjulian if (m->m_len < sizeof(*si)) { 15025652Sjhay if ((m = m_pullup(m, sizeof(*si))) == NULL) { 15111819Sjulian spxstat.spxs_rcvshort++; 15211819Sjulian return; 15311819Sjulian } 15411819Sjulian si = mtod(m, struct spx *); 15511819Sjulian } 15611819Sjulian si->si_seq = ntohs(si->si_seq); 15711819Sjulian si->si_ack = ntohs(si->si_ack); 15811819Sjulian si->si_alo = ntohs(si->si_alo); 15911819Sjulian 16011819Sjulian so = ipxp->ipxp_socket; 16111819Sjulian 16211819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) { 16311819Sjulian ostate = cb->s_state; 16411819Sjulian spx_savesi = *si; 16511819Sjulian } 16611819Sjulian if (so->so_options & SO_ACCEPTCONN) { 16711819Sjulian struct spxpcb *ocb = cb; 16811819Sjulian 16911819Sjulian so = sonewconn(so, 0); 17025652Sjhay if (so == NULL) { 17111819Sjulian goto drop; 17211819Sjulian } 17311819Sjulian /* 17411819Sjulian * This is ugly, but .... 17511819Sjulian * 17611819Sjulian * Mark socket as temporary until we're 17711819Sjulian * committed to keeping it. The code at 17811819Sjulian * ``drop'' and ``dropwithreset'' check the 17911819Sjulian * flag dropsocket to see if the temporary 18011819Sjulian * socket created here should be discarded. 18111819Sjulian * We mark the socket as discardable until 18211819Sjulian * we're committed to it below in TCPS_LISTEN. 18311819Sjulian */ 18411819Sjulian dropsocket++; 18511819Sjulian ipxp = (struct ipxpcb *)so->so_pcb; 18611819Sjulian ipxp->ipxp_laddr = si->si_dna; 18711819Sjulian cb = ipxtospxpcb(ipxp); 18811819Sjulian cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ 18911819Sjulian cb->s_flags = ocb->s_flags; /* preserve sockopts */ 19011819Sjulian cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ 19111819Sjulian cb->s_state = TCPS_LISTEN; 19211819Sjulian } 19311819Sjulian 19411819Sjulian /* 19511819Sjulian * Packet received on connection. 19611819Sjulian * reset idle time and keep-alive timer; 19711819Sjulian */ 19811819Sjulian cb->s_idle = 0; 19911819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 20011819Sjulian 20111819Sjulian switch (cb->s_state) { 20211819Sjulian 20311819Sjulian case TCPS_LISTEN:{ 20428270Swollman struct sockaddr_ipx *sipx, ssipx; 20511819Sjulian struct ipx_addr laddr; 20611819Sjulian 20711819Sjulian /* 20811819Sjulian * If somebody here was carying on a conversation 20911819Sjulian * and went away, and his pen pal thinks he can 21011819Sjulian * still talk, we get the misdirected packet. 21111819Sjulian */ 21211819Sjulian if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 21311819Sjulian spx_istat.gonawy++; 21411819Sjulian goto dropwithreset; 21511819Sjulian } 21628270Swollman sipx = &ssipx; 21728270Swollman bzero(sipx, sizeof *sipx); 21811819Sjulian sipx->sipx_len = sizeof(*sipx); 21911819Sjulian sipx->sipx_family = AF_IPX; 22011819Sjulian sipx->sipx_addr = si->si_sna; 22111819Sjulian laddr = ipxp->ipxp_laddr; 22211819Sjulian if (ipx_nullhost(laddr)) 22311819Sjulian ipxp->ipxp_laddr = si->si_dna; 22428270Swollman if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &proc0)) { 22511819Sjulian ipxp->ipxp_laddr = laddr; 22611819Sjulian spx_istat.noconn++; 22711819Sjulian goto drop; 22811819Sjulian } 22911819Sjulian spx_template(cb); 23011819Sjulian dropsocket = 0; /* committed to socket */ 23111819Sjulian cb->s_did = si->si_sid; 23211819Sjulian cb->s_rack = si->si_ack; 23311819Sjulian cb->s_ralo = si->si_alo; 23411819Sjulian#define THREEWAYSHAKE 23511819Sjulian#ifdef THREEWAYSHAKE 23611819Sjulian cb->s_state = TCPS_SYN_RECEIVED; 23711819Sjulian cb->s_force = 1 + SPXT_KEEP; 23811819Sjulian spxstat.spxs_accepts++; 23911819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 24011819Sjulian } 24111819Sjulian break; 24211819Sjulian /* 24311819Sjulian * This state means that we have heard a response 24411819Sjulian * to our acceptance of their connection 24511819Sjulian * It is probably logically unnecessary in this 24611819Sjulian * implementation. 24711819Sjulian */ 24811819Sjulian case TCPS_SYN_RECEIVED: { 24925652Sjhay if (si->si_did != cb->s_sid) { 25011819Sjulian spx_istat.wrncon++; 25111819Sjulian goto drop; 25211819Sjulian } 25311819Sjulian#endif 25411819Sjulian ipxp->ipxp_fport = si->si_sport; 25511819Sjulian cb->s_timer[SPXT_REXMT] = 0; 25611819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 25711819Sjulian soisconnected(so); 25811819Sjulian cb->s_state = TCPS_ESTABLISHED; 25911819Sjulian spxstat.spxs_accepts++; 26011819Sjulian } 26111819Sjulian break; 26211819Sjulian 26311819Sjulian /* 26411819Sjulian * This state means that we have gotten a response 26511819Sjulian * to our attempt to establish a connection. 26611819Sjulian * We fill in the data from the other side, 26711819Sjulian * telling us which port to respond to, instead of the well- 26811819Sjulian * known one we might have sent to in the first place. 26911819Sjulian * We also require that this is a response to our 27011819Sjulian * connection id. 27111819Sjulian */ 27211819Sjulian case TCPS_SYN_SENT: 27325652Sjhay if (si->si_did != cb->s_sid) { 27411819Sjulian spx_istat.notme++; 27511819Sjulian goto drop; 27611819Sjulian } 27711819Sjulian spxstat.spxs_connects++; 27811819Sjulian cb->s_did = si->si_sid; 27911819Sjulian cb->s_rack = si->si_ack; 28011819Sjulian cb->s_ralo = si->si_alo; 28111819Sjulian cb->s_dport = ipxp->ipxp_fport = si->si_sport; 28211819Sjulian cb->s_timer[SPXT_REXMT] = 0; 28311819Sjulian cb->s_flags |= SF_ACKNOW; 28411819Sjulian soisconnected(so); 28511819Sjulian cb->s_state = TCPS_ESTABLISHED; 28611819Sjulian /* Use roundtrip time of connection request for initial rtt */ 28711819Sjulian if (cb->s_rtt) { 28811819Sjulian cb->s_srtt = cb->s_rtt << 3; 28911819Sjulian cb->s_rttvar = cb->s_rtt << 1; 29011819Sjulian SPXT_RANGESET(cb->s_rxtcur, 29111819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 29211819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 29311819Sjulian cb->s_rtt = 0; 29411819Sjulian } 29511819Sjulian } 29611819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) 29711819Sjulian spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0); 29811819Sjulian 29925652Sjhay m->m_len -= sizeof(struct ipx); 30025652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 30125652Sjhay m->m_data += sizeof(struct ipx); 30211819Sjulian 30311819Sjulian if (spx_reass(cb, si)) { 30425652Sjhay m_freem(m); 30511819Sjulian } 30611819Sjulian if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) 30725652Sjhay spx_output(cb, (struct mbuf *)NULL); 30811819Sjulian cb->s_flags &= ~(SF_WIN|SF_RXT); 30911819Sjulian return; 31011819Sjulian 31111819Sjuliandropwithreset: 31211819Sjulian if (dropsocket) 31325652Sjhay soabort(so); 31411819Sjulian si->si_seq = ntohs(si->si_seq); 31511819Sjulian si->si_ack = ntohs(si->si_ack); 31611819Sjulian si->si_alo = ntohs(si->si_alo); 31725652Sjhay m_freem(dtom(si)); 31811819Sjulian if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs) 31911819Sjulian spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 32011819Sjulian return; 32111819Sjulian 32211819Sjuliandrop: 32311819Sjulianbad: 32411819Sjulian if (cb == 0 || cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || 32511819Sjulian traceallspxs) 32611819Sjulian spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 32711819Sjulian m_freem(m); 32811819Sjulian} 32911819Sjulian 33033181Seivindstatic int spxrexmtthresh = 3; 33111819Sjulian 33211819Sjulian/* 33311819Sjulian * This is structurally similar to the tcp reassembly routine 33411819Sjulian * but its function is somewhat different: It merely queues 33511819Sjulian * packets up, and suppresses duplicates. 33611819Sjulian */ 33725652Sjhaystatic int 33811819Sjulianspx_reass(cb, si) 33911819Sjulianregister struct spxpcb *cb; 34011819Sjulianregister struct spx *si; 34111819Sjulian{ 34211819Sjulian register struct spx_q *q; 34311819Sjulian register struct mbuf *m; 34411819Sjulian register struct socket *so = cb->s_ipxpcb->ipxp_socket; 34511819Sjulian char packetp = cb->s_flags & SF_HI; 34611819Sjulian int incr; 34711819Sjulian char wakeup = 0; 34811819Sjulian 34911819Sjulian if (si == SI(0)) 35011819Sjulian goto present; 35111819Sjulian /* 35211819Sjulian * Update our news from them. 35311819Sjulian */ 35411819Sjulian if (si->si_cc & SPX_SA) 35511819Sjulian cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW); 35611819Sjulian if (SSEQ_GT(si->si_alo, cb->s_ralo)) 35711819Sjulian cb->s_flags |= SF_WIN; 35811819Sjulian if (SSEQ_LEQ(si->si_ack, cb->s_rack)) { 35911819Sjulian if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) { 36011819Sjulian spxstat.spxs_rcvdupack++; 36111819Sjulian /* 36211819Sjulian * If this is a completely duplicate ack 36311819Sjulian * and other conditions hold, we assume 36411819Sjulian * a packet has been dropped and retransmit 36511819Sjulian * it exactly as in tcp_input(). 36611819Sjulian */ 36711819Sjulian if (si->si_ack != cb->s_rack || 36811819Sjulian si->si_alo != cb->s_ralo) 36911819Sjulian cb->s_dupacks = 0; 37011819Sjulian else if (++cb->s_dupacks == spxrexmtthresh) { 37111819Sjulian u_short onxt = cb->s_snxt; 37211819Sjulian int cwnd = cb->s_cwnd; 37311819Sjulian 37411819Sjulian cb->s_snxt = si->si_ack; 37511819Sjulian cb->s_cwnd = CUNIT; 37611819Sjulian cb->s_force = 1 + SPXT_REXMT; 37725652Sjhay spx_output(cb, (struct mbuf *)NULL); 37811819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 37911819Sjulian cb->s_rtt = 0; 38011819Sjulian if (cwnd >= 4 * CUNIT) 38111819Sjulian cb->s_cwnd = cwnd / 2; 38211819Sjulian if (SSEQ_GT(onxt, cb->s_snxt)) 38311819Sjulian cb->s_snxt = onxt; 38411819Sjulian return (1); 38511819Sjulian } 38611819Sjulian } else 38711819Sjulian cb->s_dupacks = 0; 38811819Sjulian goto update_window; 38911819Sjulian } 39011819Sjulian cb->s_dupacks = 0; 39111819Sjulian /* 39211819Sjulian * If our correspondent acknowledges data we haven't sent 39311819Sjulian * TCP would drop the packet after acking. We'll be a little 39411819Sjulian * more permissive 39511819Sjulian */ 39611819Sjulian if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) { 39711819Sjulian spxstat.spxs_rcvacktoomuch++; 39811819Sjulian si->si_ack = cb->s_smax + 1; 39911819Sjulian } 40011819Sjulian spxstat.spxs_rcvackpack++; 40111819Sjulian /* 40211819Sjulian * If transmit timer is running and timed sequence 40311819Sjulian * number was acked, update smoothed round trip time. 40411819Sjulian * See discussion of algorithm in tcp_input.c 40511819Sjulian */ 40611819Sjulian if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 40711819Sjulian spxstat.spxs_rttupdated++; 40811819Sjulian if (cb->s_srtt != 0) { 40911819Sjulian register short delta; 41011819Sjulian delta = cb->s_rtt - (cb->s_srtt >> 3); 41111819Sjulian if ((cb->s_srtt += delta) <= 0) 41211819Sjulian cb->s_srtt = 1; 41311819Sjulian if (delta < 0) 41411819Sjulian delta = -delta; 41511819Sjulian delta -= (cb->s_rttvar >> 2); 41611819Sjulian if ((cb->s_rttvar += delta) <= 0) 41711819Sjulian cb->s_rttvar = 1; 41811819Sjulian } else { 41911819Sjulian /* 42011819Sjulian * No rtt measurement yet 42111819Sjulian */ 42211819Sjulian cb->s_srtt = cb->s_rtt << 3; 42311819Sjulian cb->s_rttvar = cb->s_rtt << 1; 42411819Sjulian } 42511819Sjulian cb->s_rtt = 0; 42611819Sjulian cb->s_rxtshift = 0; 42711819Sjulian SPXT_RANGESET(cb->s_rxtcur, 42811819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 42911819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 43011819Sjulian } 43111819Sjulian /* 43211819Sjulian * If all outstanding data is acked, stop retransmit 43311819Sjulian * timer and remember to restart (more output or persist). 43411819Sjulian * If there is more data to be acked, restart retransmit 43511819Sjulian * timer, using current (possibly backed-off) value; 43611819Sjulian */ 43711819Sjulian if (si->si_ack == cb->s_smax + 1) { 43811819Sjulian cb->s_timer[SPXT_REXMT] = 0; 43911819Sjulian cb->s_flags |= SF_RXT; 44011819Sjulian } else if (cb->s_timer[SPXT_PERSIST] == 0) 44111819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 44211819Sjulian /* 44311819Sjulian * When new data is acked, open the congestion window. 44411819Sjulian * If the window gives us less than ssthresh packets 44511819Sjulian * in flight, open exponentially (maxseg at a time). 44611819Sjulian * Otherwise open linearly (maxseg^2 / cwnd at a time). 44711819Sjulian */ 44811819Sjulian incr = CUNIT; 44911819Sjulian if (cb->s_cwnd > cb->s_ssthresh) 45011819Sjulian incr = max(incr * incr / cb->s_cwnd, 1); 45111819Sjulian cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx); 45211819Sjulian /* 45311819Sjulian * Trim Acked data from output queue. 45411819Sjulian */ 45511819Sjulian while ((m = so->so_snd.sb_mb) != NULL) { 45611819Sjulian if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack)) 45711819Sjulian sbdroprecord(&so->so_snd); 45811819Sjulian else 45911819Sjulian break; 46011819Sjulian } 46111819Sjulian sowwakeup(so); 46211819Sjulian cb->s_rack = si->si_ack; 46311819Sjulianupdate_window: 46411819Sjulian if (SSEQ_LT(cb->s_snxt, cb->s_rack)) 46511819Sjulian cb->s_snxt = cb->s_rack; 46643311Sdillon if (SSEQ_LT(cb->s_swl1, si->si_seq) || ((cb->s_swl1 == si->si_seq && 46743311Sdillon (SSEQ_LT(cb->s_swl2, si->si_ack))) || 46843305Sdillon (cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo)))) { 46911819Sjulian /* keep track of pure window updates */ 47011819Sjulian if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack 47111819Sjulian && SSEQ_LT(cb->s_ralo, si->si_alo)) { 47211819Sjulian spxstat.spxs_rcvwinupd++; 47311819Sjulian spxstat.spxs_rcvdupack--; 47411819Sjulian } 47511819Sjulian cb->s_ralo = si->si_alo; 47611819Sjulian cb->s_swl1 = si->si_seq; 47711819Sjulian cb->s_swl2 = si->si_ack; 47811819Sjulian cb->s_swnd = (1 + si->si_alo - si->si_ack); 47911819Sjulian if (cb->s_swnd > cb->s_smxw) 48011819Sjulian cb->s_smxw = cb->s_swnd; 48111819Sjulian cb->s_flags |= SF_WIN; 48211819Sjulian } 48311819Sjulian /* 48411819Sjulian * If this packet number is higher than that which 48511819Sjulian * we have allocated refuse it, unless urgent 48611819Sjulian */ 48711819Sjulian if (SSEQ_GT(si->si_seq, cb->s_alo)) { 48811819Sjulian if (si->si_cc & SPX_SP) { 48911819Sjulian spxstat.spxs_rcvwinprobe++; 49011819Sjulian return (1); 49111819Sjulian } else 49211819Sjulian spxstat.spxs_rcvpackafterwin++; 49311819Sjulian if (si->si_cc & SPX_OB) { 49411819Sjulian if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { 49525652Sjhay m_freem(dtom(si)); 49611819Sjulian return (0); 49711819Sjulian } /* else queue this packet; */ 49811819Sjulian } else { 49911819Sjulian /*register struct socket *so = cb->s_ipxpcb->ipxp_socket; 50011819Sjulian if (so->so_state && SS_NOFDREF) { 50125652Sjhay spx_close(cb); 50211819Sjulian } else 50311819Sjulian would crash system*/ 50411819Sjulian spx_istat.notyet++; 50525652Sjhay m_freem(dtom(si)); 50611819Sjulian return (0); 50711819Sjulian } 50811819Sjulian } 50911819Sjulian /* 51011819Sjulian * If this is a system packet, we don't need to 51111819Sjulian * queue it up, and won't update acknowledge # 51211819Sjulian */ 51311819Sjulian if (si->si_cc & SPX_SP) { 51411819Sjulian return (1); 51511819Sjulian } 51611819Sjulian /* 51711819Sjulian * We have already seen this packet, so drop. 51811819Sjulian */ 51911819Sjulian if (SSEQ_LT(si->si_seq, cb->s_ack)) { 52011819Sjulian spx_istat.bdreas++; 52111819Sjulian spxstat.spxs_rcvduppack++; 52211819Sjulian if (si->si_seq == cb->s_ack - 1) 52311819Sjulian spx_istat.lstdup++; 52411819Sjulian return (1); 52511819Sjulian } 52611819Sjulian /* 52711819Sjulian * Loop through all packets queued up to insert in 52811819Sjulian * appropriate sequence. 52911819Sjulian */ 53025652Sjhay for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { 53111819Sjulian if (si->si_seq == SI(q)->si_seq) { 53211819Sjulian spxstat.spxs_rcvduppack++; 53311819Sjulian return (1); 53411819Sjulian } 53511819Sjulian if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { 53611819Sjulian spxstat.spxs_rcvoopack++; 53711819Sjulian break; 53811819Sjulian } 53911819Sjulian } 54011819Sjulian insque(si, q->si_prev); 54111819Sjulian /* 54211819Sjulian * If this packet is urgent, inform process 54311819Sjulian */ 54411819Sjulian if (si->si_cc & SPX_OB) { 54511819Sjulian cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 54611819Sjulian sohasoutofband(so); 54711819Sjulian cb->s_oobflags |= SF_IOOB; 54811819Sjulian } 54911819Sjulianpresent: 55011819Sjulian#define SPINC sizeof(struct spxhdr) 55111819Sjulian /* 55211819Sjulian * Loop through all packets queued up to update acknowledge 55311819Sjulian * number, and present all acknowledged data to user; 55411819Sjulian * If in packet interface mode, show packet headers. 55511819Sjulian */ 55625652Sjhay for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { 55711819Sjulian if (SI(q)->si_seq == cb->s_ack) { 55811819Sjulian cb->s_ack++; 55911819Sjulian m = dtom(q); 56011819Sjulian if (SI(q)->si_cc & SPX_OB) { 56111819Sjulian cb->s_oobflags &= ~SF_IOOB; 56211819Sjulian if (so->so_rcv.sb_cc) 56311819Sjulian so->so_oobmark = so->so_rcv.sb_cc; 56411819Sjulian else 56511819Sjulian so->so_state |= SS_RCVATMARK; 56611819Sjulian } 56711819Sjulian q = q->si_prev; 56811819Sjulian remque(q->si_next); 56911819Sjulian wakeup = 1; 57011819Sjulian spxstat.spxs_rcvpack++; 57111819Sjulian#ifdef SF_NEWCALL 57211819Sjulian if (cb->s_flags2 & SF_NEWCALL) { 57311819Sjulian struct spxhdr *sp = mtod(m, struct spxhdr *); 57411819Sjulian u_char dt = sp->spx_dt; 57511819Sjulian spx_newchecks[4]++; 57611819Sjulian if (dt != cb->s_rhdr.spx_dt) { 57711819Sjulian struct mbuf *mm = 57811819Sjulian m_getclr(M_DONTWAIT, MT_CONTROL); 57911819Sjulian spx_newchecks[0]++; 58011819Sjulian if (mm != NULL) { 58111819Sjulian u_short *s = 58211819Sjulian mtod(mm, u_short *); 58311819Sjulian cb->s_rhdr.spx_dt = dt; 58411819Sjulian mm->m_len = 5; /*XXX*/ 58511819Sjulian s[0] = 5; 58611819Sjulian s[1] = 1; 58711819Sjulian *(u_char *)(&s[2]) = dt; 58811819Sjulian sbappend(&so->so_rcv, mm); 58911819Sjulian } 59011819Sjulian } 59111819Sjulian if (sp->spx_cc & SPX_OB) { 59211819Sjulian MCHTYPE(m, MT_OOBDATA); 59311819Sjulian spx_newchecks[1]++; 59411819Sjulian so->so_oobmark = 0; 59511819Sjulian so->so_state &= ~SS_RCVATMARK; 59611819Sjulian } 59711819Sjulian if (packetp == 0) { 59811819Sjulian m->m_data += SPINC; 59911819Sjulian m->m_len -= SPINC; 60011819Sjulian m->m_pkthdr.len -= SPINC; 60111819Sjulian } 60211819Sjulian if ((sp->spx_cc & SPX_EM) || packetp) { 60311819Sjulian sbappendrecord(&so->so_rcv, m); 60411819Sjulian spx_newchecks[9]++; 60511819Sjulian } else 60611819Sjulian sbappend(&so->so_rcv, m); 60711819Sjulian } else 60811819Sjulian#endif 60911819Sjulian if (packetp) { 61011819Sjulian sbappendrecord(&so->so_rcv, m); 61111819Sjulian } else { 61211819Sjulian cb->s_rhdr = *mtod(m, struct spxhdr *); 61311819Sjulian m->m_data += SPINC; 61411819Sjulian m->m_len -= SPINC; 61511819Sjulian m->m_pkthdr.len -= SPINC; 61611819Sjulian sbappend(&so->so_rcv, m); 61711819Sjulian } 61811819Sjulian } else 61911819Sjulian break; 62011819Sjulian } 62125652Sjhay if (wakeup) 62225652Sjhay sorwakeup(so); 62311819Sjulian return (0); 62411819Sjulian} 62511819Sjulian 62611819Sjulianvoid 62712881Sbdespx_ctlinput(cmd, arg_as_sa, dummy) 62811819Sjulian int cmd; 62912881Sbde struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */ 63012881Sbde void *dummy; 63111819Sjulian{ 63212881Sbde caddr_t arg = (/* XXX */ caddr_t)arg_as_sa; 63311819Sjulian struct ipx_addr *na; 63425652Sjhay struct sockaddr_ipx *sipx; 63511819Sjulian 63611819Sjulian if (cmd < 0 || cmd > PRC_NCMDS) 63711819Sjulian return; 63825652Sjhay 63911819Sjulian switch (cmd) { 64011819Sjulian 64111819Sjulian case PRC_ROUTEDEAD: 64211819Sjulian return; 64311819Sjulian 64411819Sjulian case PRC_IFDOWN: 64511819Sjulian case PRC_HOSTDEAD: 64611819Sjulian case PRC_HOSTUNREACH: 64711819Sjulian sipx = (struct sockaddr_ipx *)arg; 64811819Sjulian if (sipx->sipx_family != AF_IPX) 64911819Sjulian return; 65011819Sjulian na = &sipx->sipx_addr; 65111819Sjulian break; 65211819Sjulian 65311819Sjulian default: 65411819Sjulian break; 65511819Sjulian } 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 67125652Sjhay if (cb != NULL) { 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; 68825652Sjhay for (m = sb->sb_mb; m != NULL; m = m->m_act) { 68911819Sjulian si = mtod(m, struct spx *); 69011819Sjulian if (si->si_seq == badseq) 69111819Sjulian break; 69211819Sjulian } 69325652Sjhay if (m == NULL) 69425652Sjhay return; 69511819Sjulian firstbad = m; 69611819Sjulian /*for (;;) {*/ 69711819Sjulian /* calculate length */ 69825652Sjhay for (m0 = m, len = 0; m != NULL; m = m->m_next) 69911819Sjulian len += m->m_len; 70011819Sjulian if (len > cb->s_mtu) { 70111819Sjulian } 70211819Sjulian /* FINISH THIS 70311819Sjulian } */ 70411819Sjulian } 70511819Sjulian} 70611819Sjulian#endif 70711819Sjulian 70825652Sjhaystatic int 70911819Sjulianspx_output(cb, m0) 71011819Sjulian register struct spxpcb *cb; 71111819Sjulian struct mbuf *m0; 71211819Sjulian{ 71311819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 71411819Sjulian register struct mbuf *m; 71525652Sjhay register struct spx *si = (struct spx *)NULL; 71611819Sjulian register struct sockbuf *sb = &so->so_snd; 71711819Sjulian int len = 0, win, rcv_win; 71811819Sjulian short span, off, recordp = 0; 71911819Sjulian u_short alo; 72011819Sjulian int error = 0, sendalot; 72111819Sjulian#ifdef notdef 72211819Sjulian int idle; 72311819Sjulian#endif 72411819Sjulian struct mbuf *mprev; 72511819Sjulian 72625652Sjhay if (m0 != NULL) { 72711819Sjulian int mtu = cb->s_mtu; 72811819Sjulian int datalen; 72911819Sjulian /* 73011819Sjulian * Make sure that packet isn't too big. 73111819Sjulian */ 73225652Sjhay for (m = m0; m != NULL; m = m->m_next) { 73311819Sjulian mprev = m; 73411819Sjulian len += m->m_len; 73511819Sjulian if (m->m_flags & M_EOR) 73611819Sjulian recordp = 1; 73711819Sjulian } 73811819Sjulian datalen = (cb->s_flags & SF_HO) ? 73925652Sjhay len - sizeof(struct spxhdr) : len; 74011819Sjulian if (datalen > mtu) { 74111819Sjulian if (cb->s_flags & SF_PI) { 74211819Sjulian m_freem(m0); 74311819Sjulian return (EMSGSIZE); 74411819Sjulian } else { 74511819Sjulian int oldEM = cb->s_cc & SPX_EM; 74611819Sjulian 74711819Sjulian cb->s_cc &= ~SPX_EM; 74811819Sjulian while (len > mtu) { 74911819Sjulian /* 75011819Sjulian * Here we are only being called 75111819Sjulian * from usrreq(), so it is OK to 75211819Sjulian * block. 75311819Sjulian */ 75411819Sjulian m = m_copym(m0, 0, mtu, M_WAIT); 75511819Sjulian if (cb->s_flags & SF_NEWCALL) { 75611819Sjulian struct mbuf *mm = m; 75711819Sjulian spx_newchecks[7]++; 75825652Sjhay while (mm != NULL) { 75911819Sjulian mm->m_flags &= ~M_EOR; 76011819Sjulian mm = mm->m_next; 76111819Sjulian } 76211819Sjulian } 76311819Sjulian error = spx_output(cb, m); 76411819Sjulian if (error) { 76511819Sjulian cb->s_cc |= oldEM; 76611819Sjulian m_freem(m0); 76725652Sjhay return (error); 76811819Sjulian } 76911819Sjulian m_adj(m0, mtu); 77011819Sjulian len -= mtu; 77111819Sjulian } 77211819Sjulian cb->s_cc |= oldEM; 77311819Sjulian } 77411819Sjulian } 77511819Sjulian /* 77611819Sjulian * Force length even, by adding a "garbage byte" if 77711819Sjulian * necessary. 77811819Sjulian */ 77911819Sjulian if (len & 1) { 78011819Sjulian m = mprev; 78111819Sjulian if (M_TRAILINGSPACE(m) >= 1) 78211819Sjulian m->m_len++; 78311819Sjulian else { 78411819Sjulian struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 78511819Sjulian 78625652Sjhay if (m1 == NULL) { 78711819Sjulian m_freem(m0); 78811819Sjulian return (ENOBUFS); 78911819Sjulian } 79011819Sjulian m1->m_len = 1; 79111819Sjulian *(mtod(m1, u_char *)) = 0; 79211819Sjulian m->m_next = m1; 79311819Sjulian } 79411819Sjulian } 79511819Sjulian m = m_gethdr(M_DONTWAIT, MT_HEADER); 79625652Sjhay if (m == NULL) { 79711819Sjulian m_freem(m0); 79811819Sjulian return (ENOBUFS); 79911819Sjulian } 80011819Sjulian /* 80111819Sjulian * Fill in mbuf with extended SP header 80211819Sjulian * and addresses and length put into network format. 80311819Sjulian */ 80425652Sjhay MH_ALIGN(m, sizeof(struct spx)); 80525652Sjhay m->m_len = sizeof(struct spx); 80611819Sjulian m->m_next = m0; 80711819Sjulian si = mtod(m, struct spx *); 80811819Sjulian si->si_i = *cb->s_ipx; 80911819Sjulian si->si_s = cb->s_shdr; 81011819Sjulian if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 81111819Sjulian register struct spxhdr *sh; 81225652Sjhay if (m0->m_len < sizeof(*sh)) { 81311819Sjulian if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 81425652Sjhay m_free(m); 81511819Sjulian m_freem(m0); 81611819Sjulian return (EINVAL); 81711819Sjulian } 81811819Sjulian m->m_next = m0; 81911819Sjulian } 82011819Sjulian sh = mtod(m0, struct spxhdr *); 82111819Sjulian si->si_dt = sh->spx_dt; 82211819Sjulian si->si_cc |= sh->spx_cc & SPX_EM; 82325652Sjhay m0->m_len -= sizeof(*sh); 82425652Sjhay m0->m_data += sizeof(*sh); 82525652Sjhay len -= sizeof(*sh); 82611819Sjulian } 82711819Sjulian len += sizeof(*si); 82811819Sjulian if ((cb->s_flags2 & SF_NEWCALL) && recordp) { 82925652Sjhay si->si_cc |= SPX_EM; 83011819Sjulian spx_newchecks[8]++; 83111819Sjulian } 83211819Sjulian if (cb->s_oobflags & SF_SOOB) { 83311819Sjulian /* 83411819Sjulian * Per jqj@cornell: 83511819Sjulian * make sure OB packets convey exactly 1 byte. 83611819Sjulian * If the packet is 1 byte or larger, we 83711819Sjulian * have already guaranted there to be at least 83811819Sjulian * one garbage byte for the checksum, and 83911819Sjulian * extra bytes shouldn't hurt! 84011819Sjulian */ 84111819Sjulian if (len > sizeof(*si)) { 84211819Sjulian si->si_cc |= SPX_OB; 84311819Sjulian len = (1 + sizeof(*si)); 84411819Sjulian } 84511819Sjulian } 84611819Sjulian si->si_len = htons((u_short)len); 84711819Sjulian m->m_pkthdr.len = ((len - 1) | 1) + 1; 84811819Sjulian /* 84911819Sjulian * queue stuff up for output 85011819Sjulian */ 85111819Sjulian sbappendrecord(sb, m); 85211819Sjulian cb->s_seq++; 85311819Sjulian } 85411819Sjulian#ifdef notdef 85511819Sjulian idle = (cb->s_smax == (cb->s_rack - 1)); 85611819Sjulian#endif 85711819Sjulianagain: 85811819Sjulian sendalot = 0; 85911819Sjulian off = cb->s_snxt - cb->s_rack; 86025652Sjhay win = min(cb->s_swnd, (cb->s_cwnd / CUNIT)); 86111819Sjulian 86211819Sjulian /* 86311819Sjulian * If in persist timeout with window of 0, send a probe. 86411819Sjulian * Otherwise, if window is small but nonzero 86511819Sjulian * and timer expired, send what we can and go into 86611819Sjulian * transmit state. 86711819Sjulian */ 86811819Sjulian if (cb->s_force == 1 + SPXT_PERSIST) { 86911819Sjulian if (win != 0) { 87011819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 87111819Sjulian cb->s_rxtshift = 0; 87211819Sjulian } 87311819Sjulian } 87411819Sjulian span = cb->s_seq - cb->s_rack; 87511819Sjulian len = min(span, win) - off; 87611819Sjulian 87711819Sjulian if (len < 0) { 87811819Sjulian /* 87911819Sjulian * Window shrank after we went into it. 88011819Sjulian * If window shrank to 0, cancel pending 88111819Sjulian * restransmission and pull s_snxt back 88211819Sjulian * to (closed) window. We will enter persist 88311819Sjulian * state below. If the widndow didn't close completely, 88411819Sjulian * just wait for an ACK. 88511819Sjulian */ 88611819Sjulian len = 0; 88711819Sjulian if (win == 0) { 88811819Sjulian cb->s_timer[SPXT_REXMT] = 0; 88911819Sjulian cb->s_snxt = cb->s_rack; 89011819Sjulian } 89111819Sjulian } 89211819Sjulian if (len > 1) 89311819Sjulian sendalot = 1; 89411819Sjulian rcv_win = sbspace(&so->so_rcv); 89511819Sjulian 89611819Sjulian /* 89711819Sjulian * Send if we owe peer an ACK. 89811819Sjulian */ 89911819Sjulian if (cb->s_oobflags & SF_SOOB) { 90011819Sjulian /* 90111819Sjulian * must transmit this out of band packet 90211819Sjulian */ 90311819Sjulian cb->s_oobflags &= ~ SF_SOOB; 90411819Sjulian sendalot = 1; 90511819Sjulian spxstat.spxs_sndurg++; 90611819Sjulian goto found; 90711819Sjulian } 90811819Sjulian if (cb->s_flags & SF_ACKNOW) 90911819Sjulian goto send; 91011819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 91111819Sjulian goto send; 91211819Sjulian /* 91311819Sjulian * Silly window can't happen in spx. 91411819Sjulian * Code from tcp deleted. 91511819Sjulian */ 91611819Sjulian if (len) 91711819Sjulian goto send; 91811819Sjulian /* 91911819Sjulian * Compare available window to amount of window 92011819Sjulian * known to peer (as advertised window less 92111819Sjulian * next expected input.) If the difference is at least two 92211819Sjulian * packets or at least 35% of the mximum possible window, 92311819Sjulian * then want to send a window update to peer. 92411819Sjulian */ 92511819Sjulian if (rcv_win > 0) { 92611819Sjulian u_short delta = 1 + cb->s_alo - cb->s_ack; 92711819Sjulian int adv = rcv_win - (delta * cb->s_mtu); 92811819Sjulian 92911819Sjulian if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || 93011819Sjulian (100 * adv / so->so_rcv.sb_hiwat >= 35)) { 93111819Sjulian spxstat.spxs_sndwinup++; 93211819Sjulian cb->s_flags |= SF_ACKNOW; 93311819Sjulian goto send; 93411819Sjulian } 93511819Sjulian 93611819Sjulian } 93711819Sjulian /* 93811819Sjulian * Many comments from tcp_output.c are appropriate here 93911819Sjulian * including . . . 94011819Sjulian * If send window is too small, there is data to transmit, and no 94111819Sjulian * retransmit or persist is pending, then go to persist state. 94211819Sjulian * If nothing happens soon, send when timer expires: 94311819Sjulian * if window is nonzero, transmit what we can, 94411819Sjulian * otherwise send a probe. 94511819Sjulian */ 94611819Sjulian if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 && 94711819Sjulian cb->s_timer[SPXT_PERSIST] == 0) { 94811819Sjulian cb->s_rxtshift = 0; 94911819Sjulian spx_setpersist(cb); 95011819Sjulian } 95111819Sjulian /* 95211819Sjulian * No reason to send a packet, just return. 95311819Sjulian */ 95411819Sjulian cb->s_outx = 1; 95511819Sjulian return (0); 95611819Sjulian 95711819Sjuliansend: 95811819Sjulian /* 95911819Sjulian * Find requested packet. 96011819Sjulian */ 96111819Sjulian si = 0; 96211819Sjulian if (len > 0) { 96311819Sjulian cb->s_want = cb->s_snxt; 96425652Sjhay for (m = sb->sb_mb; m != NULL; m = m->m_act) { 96511819Sjulian si = mtod(m, struct spx *); 96611819Sjulian if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) 96711819Sjulian break; 96811819Sjulian } 96911819Sjulian found: 97025652Sjhay if (si != NULL) { 97111819Sjulian if (si->si_seq == cb->s_snxt) 97211819Sjulian cb->s_snxt++; 97311819Sjulian else 97411819Sjulian spxstat.spxs_sndvoid++, si = 0; 97511819Sjulian } 97611819Sjulian } 97711819Sjulian /* 97811819Sjulian * update window 97911819Sjulian */ 98011819Sjulian if (rcv_win < 0) 98111819Sjulian rcv_win = 0; 98211819Sjulian alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); 98311819Sjulian if (SSEQ_LT(alo, cb->s_alo)) 98411819Sjulian alo = cb->s_alo; 98511819Sjulian 98625652Sjhay if (si != NULL) { 98711819Sjulian /* 98811819Sjulian * must make a copy of this packet for 98911819Sjulian * ipx_output to monkey with 99011819Sjulian */ 99111819Sjulian m = m_copy(dtom(si), 0, (int)M_COPYALL); 99211819Sjulian if (m == NULL) { 99311819Sjulian return (ENOBUFS); 99411819Sjulian } 99511819Sjulian si = mtod(m, struct spx *); 99611819Sjulian if (SSEQ_LT(si->si_seq, cb->s_smax)) 99711819Sjulian spxstat.spxs_sndrexmitpack++; 99811819Sjulian else 99911819Sjulian spxstat.spxs_sndpack++; 100011819Sjulian } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { 100111819Sjulian /* 100211819Sjulian * Must send an acknowledgement or a probe 100311819Sjulian */ 100411819Sjulian if (cb->s_force) 100511819Sjulian spxstat.spxs_sndprobe++; 100611819Sjulian if (cb->s_flags & SF_ACKNOW) 100711819Sjulian spxstat.spxs_sndacks++; 100811819Sjulian m = m_gethdr(M_DONTWAIT, MT_HEADER); 100925652Sjhay if (m == NULL) 101011819Sjulian return (ENOBUFS); 101111819Sjulian /* 101211819Sjulian * Fill in mbuf with extended SP header 101311819Sjulian * and addresses and length put into network format. 101411819Sjulian */ 101525652Sjhay MH_ALIGN(m, sizeof(struct spx)); 101625652Sjhay m->m_len = sizeof(*si); 101725652Sjhay m->m_pkthdr.len = sizeof(*si); 101811819Sjulian si = mtod(m, struct spx *); 101911819Sjulian si->si_i = *cb->s_ipx; 102011819Sjulian si->si_s = cb->s_shdr; 102111819Sjulian si->si_seq = cb->s_smax + 1; 102225652Sjhay si->si_len = htons(sizeof(*si)); 102311819Sjulian si->si_cc |= SPX_SP; 102411819Sjulian } else { 102511819Sjulian cb->s_outx = 3; 102611819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) 102711819Sjulian spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 102811819Sjulian return (0); 102911819Sjulian } 103011819Sjulian /* 103111819Sjulian * Stuff checksum and output datagram. 103211819Sjulian */ 103311819Sjulian if ((si->si_cc & SPX_SP) == 0) { 103411819Sjulian if (cb->s_force != (1 + SPXT_PERSIST) || 103511819Sjulian cb->s_timer[SPXT_PERSIST] == 0) { 103611819Sjulian /* 103711819Sjulian * If this is a new packet and we are not currently 103811819Sjulian * timing anything, time this one. 103911819Sjulian */ 104011819Sjulian if (SSEQ_LT(cb->s_smax, si->si_seq)) { 104111819Sjulian cb->s_smax = si->si_seq; 104211819Sjulian if (cb->s_rtt == 0) { 104311819Sjulian spxstat.spxs_segstimed++; 104411819Sjulian cb->s_rtseq = si->si_seq; 104511819Sjulian cb->s_rtt = 1; 104611819Sjulian } 104711819Sjulian } 104811819Sjulian /* 104911819Sjulian * Set rexmt timer if not currently set, 105011819Sjulian * Initial value for retransmit timer is smoothed 105111819Sjulian * round-trip time + 2 * round-trip time variance. 105211819Sjulian * Initialize shift counter which is used for backoff 105311819Sjulian * of retransmit time. 105411819Sjulian */ 105511819Sjulian if (cb->s_timer[SPXT_REXMT] == 0 && 105611819Sjulian cb->s_snxt != cb->s_rack) { 105711819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 105811819Sjulian if (cb->s_timer[SPXT_PERSIST]) { 105911819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 106011819Sjulian cb->s_rxtshift = 0; 106111819Sjulian } 106211819Sjulian } 106311819Sjulian } else if (SSEQ_LT(cb->s_smax, si->si_seq)) { 106411819Sjulian cb->s_smax = si->si_seq; 106511819Sjulian } 106611819Sjulian } else if (cb->s_state < TCPS_ESTABLISHED) { 106711819Sjulian if (cb->s_rtt == 0) 106811819Sjulian cb->s_rtt = 1; /* Time initial handshake */ 106911819Sjulian if (cb->s_timer[SPXT_REXMT] == 0) 107011819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 107111819Sjulian } 107211819Sjulian { 107311819Sjulian /* 107411819Sjulian * Do not request acks when we ack their data packets or 107511819Sjulian * when we do a gratuitous window update. 107611819Sjulian */ 107711819Sjulian if (((si->si_cc & SPX_SP) == 0) || cb->s_force) 107811819Sjulian si->si_cc |= SPX_SA; 107911819Sjulian si->si_seq = htons(si->si_seq); 108011819Sjulian si->si_alo = htons(alo); 108111819Sjulian si->si_ack = htons(cb->s_ack); 108211819Sjulian 108311819Sjulian if (ipxcksum) { 108411819Sjulian si->si_sum = 0; 108511819Sjulian len = ntohs(si->si_len); 108611819Sjulian if (len & 1) 108711819Sjulian len++; 108811819Sjulian si->si_sum = ipx_cksum(m, len); 108911819Sjulian } else 109011819Sjulian si->si_sum = 0xffff; 109111819Sjulian 109211819Sjulian cb->s_outx = 4; 109311819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) 109411819Sjulian spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 109511819Sjulian 109611819Sjulian if (so->so_options & SO_DONTROUTE) 109725652Sjhay error = ipx_outputfl(m, (struct route *)NULL, IPX_ROUTETOIF); 109811819Sjulian else 109911819Sjulian error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0); 110011819Sjulian } 110111819Sjulian if (error) { 110211819Sjulian return (error); 110311819Sjulian } 110411819Sjulian spxstat.spxs_sndtotal++; 110511819Sjulian /* 110611819Sjulian * Data sent (as far as we can tell). 110711819Sjulian * If this advertises a larger window than any other segment, 110811819Sjulian * then remember the size of the advertized window. 110911819Sjulian * Any pending ACK has now been sent. 111011819Sjulian */ 111111819Sjulian cb->s_force = 0; 111211819Sjulian cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); 111311819Sjulian if (SSEQ_GT(alo, cb->s_alo)) 111411819Sjulian cb->s_alo = alo; 111511819Sjulian if (sendalot) 111611819Sjulian goto again; 111711819Sjulian cb->s_outx = 5; 111811819Sjulian return (0); 111911819Sjulian} 112011819Sjulian 112133181Seivindstatic int spx_do_persist_panics = 0; 112211819Sjulian 112325652Sjhaystatic void 112411819Sjulianspx_setpersist(cb) 112511819Sjulian register struct spxpcb *cb; 112611819Sjulian{ 112735599Sbde register int t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 112811819Sjulian 112911819Sjulian if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics) 113011819Sjulian panic("spx_output REXMT"); 113111819Sjulian /* 113211819Sjulian * Start/restart persistance timer. 113311819Sjulian */ 113411819Sjulian SPXT_RANGESET(cb->s_timer[SPXT_PERSIST], 113511819Sjulian t*spx_backoff[cb->s_rxtshift], 113611819Sjulian SPXTV_PERSMIN, SPXTV_PERSMAX); 113711819Sjulian if (cb->s_rxtshift < SPX_MAXRXTSHIFT) 113811819Sjulian cb->s_rxtshift++; 113911819Sjulian} 114025652Sjhay 114111819Sjulianint 114238482Swollmanspx_ctloutput(so, sopt) 114311819Sjulian struct socket *so; 114438482Swollman struct sockopt *sopt; 114511819Sjulian{ 114611819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 114711819Sjulian register struct spxpcb *cb; 114838482Swollman int mask, error; 114938482Swollman short soptval; 115038482Swollman u_short usoptval; 115138482Swollman int optval; 115211819Sjulian 115338482Swollman error = 0; 115438482Swollman 115538482Swollman if (sopt->sopt_level != IPXPROTO_SPX) { 115611819Sjulian /* This will have to be changed when we do more general 115711819Sjulian stacking of protocols */ 115838482Swollman return (ipx_ctloutput(so, sopt)); 115911819Sjulian } 116038482Swollman if (ipxp == NULL) 116138482Swollman return (EINVAL); 116238482Swollman else 116311819Sjulian cb = ipxtospxpcb(ipxp); 116411819Sjulian 116538482Swollman switch (sopt->sopt_dir) { 116638482Swollman case SOPT_GET: 116738482Swollman switch (sopt->sopt_name) { 116811819Sjulian case SO_HEADERS_ON_INPUT: 116911819Sjulian mask = SF_HI; 117011819Sjulian goto get_flags; 117111819Sjulian 117211819Sjulian case SO_HEADERS_ON_OUTPUT: 117311819Sjulian mask = SF_HO; 117411819Sjulian get_flags: 117538482Swollman soptval = cb->s_flags & mask; 117638482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 117711819Sjulian break; 117811819Sjulian 117911819Sjulian case SO_MTU: 118038482Swollman usoptval = cb->s_mtu; 118138482Swollman error = sooptcopyout(sopt, &usoptval, sizeof usoptval); 118211819Sjulian break; 118311819Sjulian 118411819Sjulian case SO_LAST_HEADER: 118538482Swollman error = sooptcopyout(sopt, &cb->s_rhdr, 118638482Swollman sizeof cb->s_rhdr); 118711819Sjulian break; 118811819Sjulian 118911819Sjulian case SO_DEFAULT_HEADERS: 119038482Swollman error = sooptcopyout(sopt, &cb->s_shdr, 119138482Swollman sizeof cb->s_shdr); 119211819Sjulian break; 119311819Sjulian 119411819Sjulian default: 119538482Swollman error = ENOPROTOOPT; 119611819Sjulian } 119711819Sjulian break; 119811819Sjulian 119938482Swollman case SOPT_SET: 120038482Swollman switch (sopt->sopt_name) { 120138482Swollman /* XXX why are these shorts on get and ints on set? 120238482Swollman that doesn't make any sense... */ 120311819Sjulian case SO_HEADERS_ON_INPUT: 120411819Sjulian mask = SF_HI; 120511819Sjulian goto set_head; 120611819Sjulian 120711819Sjulian case SO_HEADERS_ON_OUTPUT: 120811819Sjulian mask = SF_HO; 120911819Sjulian set_head: 121038482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 121138482Swollman sizeof optval); 121238482Swollman if (error) 121338482Swollman break; 121438482Swollman 121511819Sjulian if (cb->s_flags & SF_PI) { 121638482Swollman if (optval) 121711819Sjulian cb->s_flags |= mask; 121811819Sjulian else 121911819Sjulian cb->s_flags &= ~mask; 122011819Sjulian } else error = EINVAL; 122111819Sjulian break; 122211819Sjulian 122311819Sjulian case SO_MTU: 122438482Swollman error = sooptcopyin(sopt, &usoptval, sizeof usoptval, 122538482Swollman sizeof usoptval); 122638482Swollman if (error) 122738482Swollman break; 122838482Swollman cb->s_mtu = usoptval; 122911819Sjulian break; 123011819Sjulian 123111819Sjulian#ifdef SF_NEWCALL 123211819Sjulian case SO_NEWCALL: 123338482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 123438482Swollman sizeof optval); 123538482Swollman if (error) 123638482Swollman break; 123738482Swollman if (optval) { 123811819Sjulian cb->s_flags2 |= SF_NEWCALL; 123911819Sjulian spx_newchecks[5]++; 124011819Sjulian } else { 124111819Sjulian cb->s_flags2 &= ~SF_NEWCALL; 124211819Sjulian spx_newchecks[6]++; 124311819Sjulian } 124411819Sjulian break; 124511819Sjulian#endif 124611819Sjulian 124711819Sjulian case SO_DEFAULT_HEADERS: 124811819Sjulian { 124938482Swollman struct spxhdr sp; 125038482Swollman 125138482Swollman error = sooptcopyin(sopt, &sp, sizeof sp, 125238482Swollman sizeof sp); 125338482Swollman if (error) 125438482Swollman break; 125538482Swollman cb->s_dt = sp.spx_dt; 125638482Swollman cb->s_cc = sp.spx_cc & SPX_EM; 125711819Sjulian } 125811819Sjulian break; 125911819Sjulian 126011819Sjulian default: 126138482Swollman error = ENOPROTOOPT; 126211819Sjulian } 126311819Sjulian break; 126411819Sjulian } 126538482Swollman return (error); 126611819Sjulian} 126711819Sjulian 126824659Sjhaystatic int 126924659Sjhayspx_usr_abort(so) 127011819Sjulian struct socket *so; 127111819Sjulian{ 127224659Sjhay int s; 127324659Sjhay struct ipxpcb *ipxp; 127424659Sjhay struct spxpcb *cb; 127511819Sjulian 127624659Sjhay ipxp = sotoipxpcb(so); 127724659Sjhay cb = ipxtospxpcb(ipxp); 127811819Sjulian 127924659Sjhay s = splnet(); 128024659Sjhay spx_drop(cb, ECONNABORTED); 128124659Sjhay splx(s); 128224659Sjhay return (0); 128324659Sjhay} 128411819Sjulian 128524659Sjhay/* 128624659Sjhay * Accept a connection. Essentially all the work is 128724659Sjhay * done at higher levels; just return the address 128824659Sjhay * of the peer, storing through addr. 128924659Sjhay */ 129024659Sjhaystatic int 129124659Sjhayspx_accept(so, nam) 129224659Sjhay struct socket *so; 129328270Swollman struct sockaddr **nam; 129424659Sjhay{ 129524659Sjhay struct ipxpcb *ipxp; 129628270Swollman struct sockaddr_ipx *sipx, ssipx; 129711819Sjulian 129824659Sjhay ipxp = sotoipxpcb(so); 129928270Swollman sipx = &ssipx; 130028270Swollman bzero(sipx, sizeof *sipx); 130128270Swollman sipx->sipx_len = sizeof *sipx; 130224659Sjhay sipx->sipx_family = AF_IPX; 130324659Sjhay sipx->sipx_addr = ipxp->ipxp_faddr; 130428270Swollman *nam = dup_sockaddr((struct sockaddr *)sipx, 0); 130524659Sjhay return (0); 130624659Sjhay} 130724659Sjhay 130824659Sjhaystatic int 130925345Sjhayspx_attach(so, proto, p) 131024659Sjhay struct socket *so; 131124659Sjhay int proto; 131225345Sjhay struct proc *p; 131324659Sjhay{ 131424659Sjhay int error; 131524659Sjhay int s; 131624659Sjhay struct ipxpcb *ipxp; 131724659Sjhay struct spxpcb *cb; 131824659Sjhay struct mbuf *mm; 131924659Sjhay struct sockbuf *sb; 132024659Sjhay 132124659Sjhay ipxp = sotoipxpcb(so); 132224659Sjhay cb = ipxtospxpcb(ipxp); 132324659Sjhay 132424659Sjhay if (ipxp != NULL) 132524659Sjhay return (EISCONN); 132624659Sjhay s = splnet(); 132725345Sjhay error = ipx_pcballoc(so, &ipxpcb, p); 132824659Sjhay if (error) 132924659Sjhay goto spx_attach_end; 133024659Sjhay if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 133124659Sjhay error = soreserve(so, (u_long) 3072, (u_long) 3072); 133211819Sjulian if (error) 133324659Sjhay goto spx_attach_end; 133424659Sjhay } 133524659Sjhay ipxp = sotoipxpcb(so); 133611819Sjulian 133728270Swollman MALLOC(cb, struct spxpcb *, sizeof *cb, M_PCB, M_NOWAIT); 133811819Sjulian 133928270Swollman if (cb == NULL) { 134024659Sjhay error = ENOBUFS; 134124659Sjhay goto spx_attach_end; 134224659Sjhay } 134343711Sjhay bzero(cb, sizeof *cb); 134443711Sjhay sb = &so->so_snd; 134528270Swollman 134624659Sjhay mm = m_getclr(M_DONTWAIT, MT_HEADER); 134724659Sjhay if (mm == NULL) { 134828270Swollman FREE(cb, M_PCB); 134924659Sjhay error = ENOBUFS; 135024659Sjhay goto spx_attach_end; 135124659Sjhay } 135224659Sjhay cb->s_ipx = mtod(mm, struct ipx *); 135324659Sjhay cb->s_state = TCPS_LISTEN; 135424659Sjhay cb->s_smax = -1; 135524659Sjhay cb->s_swl1 = -1; 135624659Sjhay cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 135724659Sjhay cb->s_ipxpcb = ipxp; 135825652Sjhay cb->s_mtu = 576 - sizeof(struct spx); 135924659Sjhay cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; 136024659Sjhay cb->s_ssthresh = cb->s_cwnd; 136125652Sjhay cb->s_cwmx = sbspace(sb) * CUNIT / (2 * sizeof(struct spx)); 136224659Sjhay /* Above is recomputed when connecting to account 136324659Sjhay for changed buffering or mtu's */ 136424659Sjhay cb->s_rtt = SPXTV_SRTTBASE; 136524659Sjhay cb->s_rttvar = SPXTV_SRTTDFLT << 2; 136624659Sjhay SPXT_RANGESET(cb->s_rxtcur, 136724659Sjhay ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1, 136824659Sjhay SPXTV_MIN, SPXTV_REXMTMAX); 136925652Sjhay ipxp->ipxp_pcb = (caddr_t)cb; 137024659Sjhayspx_attach_end: 137124659Sjhay splx(s); 137224659Sjhay return (error); 137324659Sjhay} 137411819Sjulian 137524659Sjhaystatic int 137625345Sjhayspx_bind(so, nam, p) 137724659Sjhay struct socket *so; 137828270Swollman struct sockaddr *nam; 137925345Sjhay struct proc *p; 138024659Sjhay{ 138124659Sjhay struct ipxpcb *ipxp; 138211819Sjulian 138324659Sjhay ipxp = sotoipxpcb(so); 138411819Sjulian 138525345Sjhay return (ipx_pcbbind(ipxp, nam, p)); 138624659Sjhay} 138724659Sjhay 138824659Sjhay/* 138924659Sjhay * Initiate connection to peer. 139024659Sjhay * Enter SYN_SENT state, and mark socket as connecting. 139124659Sjhay * Start keep-alive timer, setup prototype header, 139224659Sjhay * Send initial system packet requesting connection. 139324659Sjhay */ 139424659Sjhaystatic int 139525345Sjhayspx_connect(so, nam, p) 139624659Sjhay struct socket *so; 139728270Swollman struct sockaddr *nam; 139825345Sjhay struct proc *p; 139924659Sjhay{ 140024659Sjhay int error; 140124659Sjhay int s; 140224659Sjhay struct ipxpcb *ipxp; 140324659Sjhay struct spxpcb *cb; 140411819Sjulian 140524659Sjhay ipxp = sotoipxpcb(so); 140624659Sjhay cb = ipxtospxpcb(ipxp); 140724659Sjhay 140824659Sjhay s = splnet(); 140924659Sjhay if (ipxp->ipxp_lport == 0) { 141028270Swollman error = ipx_pcbbind(ipxp, (struct sockaddr *)NULL, p); 141124659Sjhay if (error) 141224659Sjhay goto spx_connect_end; 141324659Sjhay } 141425345Sjhay error = ipx_pcbconnect(ipxp, nam, p); 141524659Sjhay if (error) 141624659Sjhay goto spx_connect_end; 141724659Sjhay soisconnecting(so); 141824659Sjhay spxstat.spxs_connattempt++; 141924659Sjhay cb->s_state = TCPS_SYN_SENT; 142024659Sjhay cb->s_did = 0; 142124659Sjhay spx_template(cb); 142224659Sjhay cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 142324659Sjhay cb->s_force = 1 + SPXTV_KEEP; 142411819Sjulian /* 142524659Sjhay * Other party is required to respond to 142624659Sjhay * the port I send from, but he is not 142724659Sjhay * required to answer from where I am sending to, 142824659Sjhay * so allow wildcarding. 142924659Sjhay * original port I am sending to is still saved in 143024659Sjhay * cb->s_dport. 143111819Sjulian */ 143224659Sjhay ipxp->ipxp_fport = 0; 143325652Sjhay error = spx_output(cb, (struct mbuf *)NULL); 143424659Sjhayspx_connect_end: 143524659Sjhay splx(s); 143624659Sjhay return (error); 143724659Sjhay} 143811819Sjulian 143924659Sjhaystatic int 144024659Sjhayspx_detach(so) 144124659Sjhay struct socket *so; 144224659Sjhay{ 144324659Sjhay int s; 144424659Sjhay struct ipxpcb *ipxp; 144524659Sjhay struct spxpcb *cb; 144611819Sjulian 144724659Sjhay ipxp = sotoipxpcb(so); 144824659Sjhay cb = ipxtospxpcb(ipxp); 144911819Sjulian 145024659Sjhay if (ipxp == NULL) 145124659Sjhay return (ENOTCONN); 145224659Sjhay s = splnet(); 145324659Sjhay if (cb->s_state > TCPS_LISTEN) 145424659Sjhay spx_disconnect(cb); 145524659Sjhay else 145624659Sjhay spx_close(cb); 145724659Sjhay splx(s); 145824659Sjhay return (0); 145924659Sjhay} 146011819Sjulian 146124659Sjhay/* 146224659Sjhay * We may decide later to implement connection closing 146324659Sjhay * handshaking at the spx level optionally. 146424659Sjhay * here is the hook to do it: 146524659Sjhay */ 146624659Sjhaystatic int 146724659Sjhayspx_usr_disconnect(so) 146824659Sjhay struct socket *so; 146924659Sjhay{ 147024659Sjhay int s; 147124659Sjhay struct ipxpcb *ipxp; 147224659Sjhay struct spxpcb *cb; 147311819Sjulian 147424659Sjhay ipxp = sotoipxpcb(so); 147524659Sjhay cb = ipxtospxpcb(ipxp); 147611819Sjulian 147724659Sjhay s = splnet(); 147824659Sjhay spx_disconnect(cb); 147924659Sjhay splx(s); 148024659Sjhay return (0); 148124659Sjhay} 148211819Sjulian 148324659Sjhaystatic int 148425345Sjhayspx_listen(so, p) 148524659Sjhay struct socket *so; 148625345Sjhay struct proc *p; 148724659Sjhay{ 148824659Sjhay int error; 148924659Sjhay struct ipxpcb *ipxp; 149024659Sjhay struct spxpcb *cb; 149111819Sjulian 149224659Sjhay error = 0; 149324659Sjhay ipxp = sotoipxpcb(so); 149424659Sjhay cb = ipxtospxpcb(ipxp); 149511819Sjulian 149624659Sjhay if (ipxp->ipxp_lport == 0) 149728270Swollman error = ipx_pcbbind(ipxp, (struct sockaddr *)NULL, p); 149824659Sjhay if (error == 0) 149924659Sjhay cb->s_state = TCPS_LISTEN; 150024659Sjhay return (error); 150124659Sjhay} 150211819Sjulian 150324659Sjhay/* 150424659Sjhay * After a receive, possibly send acknowledgment 150524659Sjhay * updating allocation. 150624659Sjhay */ 150724659Sjhaystatic int 150824659Sjhayspx_rcvd(so, flags) 150924659Sjhay struct socket *so; 151024659Sjhay int flags; 151124659Sjhay{ 151224659Sjhay int s; 151324659Sjhay struct ipxpcb *ipxp; 151424659Sjhay struct spxpcb *cb; 151511819Sjulian 151624659Sjhay ipxp = sotoipxpcb(so); 151724659Sjhay cb = ipxtospxpcb(ipxp); 151811819Sjulian 151924659Sjhay s = splnet(); 152024659Sjhay cb->s_flags |= SF_RVD; 152125652Sjhay spx_output(cb, (struct mbuf *)NULL); 152224659Sjhay cb->s_flags &= ~SF_RVD; 152324659Sjhay splx(s); 152424659Sjhay return (0); 152524659Sjhay} 152611819Sjulian 152724659Sjhaystatic int 152824659Sjhayspx_rcvoob(so, m, flags) 152924659Sjhay struct socket *so; 153024659Sjhay struct mbuf *m; 153124659Sjhay int flags; 153224659Sjhay{ 153324659Sjhay struct ipxpcb *ipxp; 153424659Sjhay struct spxpcb *cb; 153511819Sjulian 153624659Sjhay ipxp = sotoipxpcb(so); 153724659Sjhay cb = ipxtospxpcb(ipxp); 153811819Sjulian 153924659Sjhay if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 154024659Sjhay (so->so_state & SS_RCVATMARK)) { 154124659Sjhay m->m_len = 1; 154224659Sjhay *mtod(m, caddr_t) = cb->s_iobc; 154324659Sjhay return (0); 154411819Sjulian } 154524659Sjhay return (EINVAL); 154624659Sjhay} 154724659Sjhay 154824659Sjhaystatic int 154925345Sjhayspx_send(so, flags, m, addr, controlp, p) 155024659Sjhay struct socket *so; 155124659Sjhay int flags; 155224659Sjhay struct mbuf *m; 155328270Swollman struct sockaddr *addr; 155424659Sjhay struct mbuf *controlp; 155525345Sjhay struct proc *p; 155624659Sjhay{ 155724659Sjhay int error; 155824659Sjhay int s; 155924659Sjhay struct ipxpcb *ipxp; 156024659Sjhay struct spxpcb *cb; 156124659Sjhay 156224659Sjhay error = 0; 156324659Sjhay ipxp = sotoipxpcb(so); 156424659Sjhay cb = ipxtospxpcb(ipxp); 156524659Sjhay 156624659Sjhay s = splnet(); 156724659Sjhay if (flags & PRUS_OOB) { 156824659Sjhay if (sbspace(&so->so_snd) < -512) { 156924659Sjhay error = ENOBUFS; 157024659Sjhay goto spx_send_end; 157124659Sjhay } 157224659Sjhay cb->s_oobflags |= SF_SOOB; 157324659Sjhay } 157425652Sjhay if (controlp != NULL) { 157524659Sjhay u_short *p = mtod(controlp, u_short *); 157624659Sjhay spx_newchecks[2]++; 157725652Sjhay if ((p[0] == 5) && (p[1] == 1)) { /* XXXX, for testing */ 157824659Sjhay cb->s_shdr.spx_dt = *(u_char *)(&p[2]); 157924659Sjhay spx_newchecks[3]++; 158024659Sjhay } 158124659Sjhay m_freem(controlp); 158224659Sjhay } 158324659Sjhay controlp = NULL; 158424659Sjhay error = spx_output(cb, m); 158524659Sjhay m = NULL; 158624659Sjhayspx_send_end: 158711819Sjulian if (controlp != NULL) 158811819Sjulian m_freem(controlp); 158911819Sjulian if (m != NULL) 159011819Sjulian m_freem(m); 159111819Sjulian splx(s); 159211819Sjulian return (error); 159311819Sjulian} 159411819Sjulian 159524659Sjhaystatic int 159624659Sjhayspx_shutdown(so) 159724659Sjhay struct socket *so; 159824659Sjhay{ 159924659Sjhay int error; 160024659Sjhay int s; 160124659Sjhay struct ipxpcb *ipxp; 160224659Sjhay struct spxpcb *cb; 160324659Sjhay 160424659Sjhay error = 0; 160524659Sjhay ipxp = sotoipxpcb(so); 160624659Sjhay cb = ipxtospxpcb(ipxp); 160724659Sjhay 160824659Sjhay s = splnet(); 160924659Sjhay socantsendmore(so); 161024659Sjhay cb = spx_usrclosed(cb); 161125652Sjhay if (cb != NULL) 161225652Sjhay error = spx_output(cb, (struct mbuf *)NULL); 161324659Sjhay splx(s); 161424659Sjhay return (error); 161524659Sjhay} 161624659Sjhay 161724659Sjhaystatic int 161825345Sjhayspx_sp_attach(so, proto, p) 161911819Sjulian struct socket *so; 162024659Sjhay int proto; 162125345Sjhay struct proc *p; 162211819Sjulian{ 162324659Sjhay int error; 162424659Sjhay struct ipxpcb *ipxp; 162511819Sjulian 162625345Sjhay error = spx_attach(so, proto, p); 162724659Sjhay if (error == 0) { 162824659Sjhay ipxp = sotoipxpcb(so); 162911819Sjulian ((struct spxpcb *)ipxp->ipxp_pcb)->s_flags |= 163011819Sjulian (SF_HI | SF_HO | SF_PI); 163111819Sjulian } 163211819Sjulian return (error); 163311819Sjulian} 163411819Sjulian 163511819Sjulian/* 163611819Sjulian * Create template to be used to send spx packets on a connection. 163711819Sjulian * Called after host entry created, fills 163811819Sjulian * in a skeletal spx header (choosing connection id), 163911819Sjulian * minimizing the amount of work necessary when the connection is used. 164011819Sjulian */ 164125652Sjhaystatic void 164211819Sjulianspx_template(cb) 164311819Sjulian register struct spxpcb *cb; 164411819Sjulian{ 164511819Sjulian register struct ipxpcb *ipxp = cb->s_ipxpcb; 164611819Sjulian register struct ipx *ipx = cb->s_ipx; 164711819Sjulian register struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd); 164811819Sjulian 164911819Sjulian ipx->ipx_pt = IPXPROTO_SPX; 165011819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 165111819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 165211819Sjulian cb->s_sid = htons(spx_iss); 165311819Sjulian spx_iss += SPX_ISSINCR/2; 165411819Sjulian cb->s_alo = 1; 165511819Sjulian cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; 165611819Sjulian cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement 165711819Sjulian of large packets */ 165811819Sjulian cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx)); 165911819Sjulian cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); 166011819Sjulian /* But allow for lots of little packets as well */ 166111819Sjulian} 166211819Sjulian 166311819Sjulian/* 166411819Sjulian * Close a SPIP control block: 166511819Sjulian * discard spx control block itself 166611819Sjulian * discard ipx protocol control block 166711819Sjulian * wake up any sleepers 166811819Sjulian */ 166925652Sjhaystatic struct spxpcb * 167011819Sjulianspx_close(cb) 167111819Sjulian register struct spxpcb *cb; 167211819Sjulian{ 167311819Sjulian register struct spx_q *s; 167411819Sjulian struct ipxpcb *ipxp = cb->s_ipxpcb; 167511819Sjulian struct socket *so = ipxp->ipxp_socket; 167611819Sjulian register struct mbuf *m; 167711819Sjulian 167811819Sjulian s = cb->s_q.si_next; 167911819Sjulian while (s != &(cb->s_q)) { 168011819Sjulian s = s->si_next; 168111819Sjulian m = dtom(s->si_prev); 168211819Sjulian remque(s->si_prev); 168311819Sjulian m_freem(m); 168411819Sjulian } 168525652Sjhay m_free(dtom(cb->s_ipx)); 168628270Swollman FREE(cb, M_PCB); 168711819Sjulian ipxp->ipxp_pcb = 0; 168811819Sjulian soisdisconnected(so); 168911819Sjulian ipx_pcbdetach(ipxp); 169011819Sjulian spxstat.spxs_closed++; 169125652Sjhay return ((struct spxpcb *)NULL); 169211819Sjulian} 169325652Sjhay 169411819Sjulian/* 169511819Sjulian * Someday we may do level 3 handshaking 169611819Sjulian * to close a connection or send a xerox style error. 169711819Sjulian * For now, just close. 169811819Sjulian */ 169925652Sjhaystatic struct spxpcb * 170011819Sjulianspx_usrclosed(cb) 170111819Sjulian register struct spxpcb *cb; 170211819Sjulian{ 170311819Sjulian return (spx_close(cb)); 170411819Sjulian} 170525652Sjhay 170625652Sjhaystatic struct spxpcb * 170711819Sjulianspx_disconnect(cb) 170811819Sjulian register struct spxpcb *cb; 170911819Sjulian{ 171011819Sjulian return (spx_close(cb)); 171111819Sjulian} 171225652Sjhay 171311819Sjulian/* 171411819Sjulian * Drop connection, reporting 171511819Sjulian * the specified error. 171611819Sjulian */ 171725652Sjhaystatic struct spxpcb * 171811819Sjulianspx_drop(cb, errno) 171911819Sjulian register struct spxpcb *cb; 172011819Sjulian int errno; 172111819Sjulian{ 172211819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 172311819Sjulian 172411819Sjulian /* 172511819Sjulian * someday, in the xerox world 172611819Sjulian * we will generate error protocol packets 172711819Sjulian * announcing that the socket has gone away. 172811819Sjulian */ 172911819Sjulian if (TCPS_HAVERCVDSYN(cb->s_state)) { 173011819Sjulian spxstat.spxs_drops++; 173111819Sjulian cb->s_state = TCPS_CLOSED; 173225652Sjhay /*tcp_output(cb);*/ 173311819Sjulian } else 173411819Sjulian spxstat.spxs_conndrops++; 173511819Sjulian so->so_error = errno; 173611819Sjulian return (spx_close(cb)); 173711819Sjulian} 173811819Sjulian 173911819Sjulian/* 174011819Sjulian * Fast timeout routine for processing delayed acks 174111819Sjulian */ 174211819Sjulianvoid 174311819Sjulianspx_fasttimo() 174411819Sjulian{ 174511819Sjulian register struct ipxpcb *ipxp; 174611819Sjulian register struct spxpcb *cb; 174711819Sjulian int s = splnet(); 174811819Sjulian 174911819Sjulian ipxp = ipxpcb.ipxp_next; 175025652Sjhay if (ipxp != NULL) 175111819Sjulian for (; ipxp != &ipxpcb; ipxp = ipxp->ipxp_next) 175225652Sjhay if ((cb = (struct spxpcb *)ipxp->ipxp_pcb) != NULL && 175311819Sjulian (cb->s_flags & SF_DELACK)) { 175411819Sjulian cb->s_flags &= ~SF_DELACK; 175511819Sjulian cb->s_flags |= SF_ACKNOW; 175611819Sjulian spxstat.spxs_delack++; 175725652Sjhay spx_output(cb, (struct mbuf *)NULL); 175811819Sjulian } 175911819Sjulian splx(s); 176011819Sjulian} 176111819Sjulian 176211819Sjulian/* 176311819Sjulian * spx protocol timeout routine called every 500 ms. 176411819Sjulian * Updates the timers in all active pcb's and 176511819Sjulian * causes finite state machine actions if timers expire. 176611819Sjulian */ 176711819Sjulianvoid 176811819Sjulianspx_slowtimo() 176911819Sjulian{ 177011819Sjulian register struct ipxpcb *ip, *ipnxt; 177111819Sjulian register struct spxpcb *cb; 177211819Sjulian int s = splnet(); 177311819Sjulian register int i; 177411819Sjulian 177511819Sjulian /* 177611819Sjulian * Search through tcb's and update active timers. 177711819Sjulian */ 177811819Sjulian ip = ipxpcb.ipxp_next; 177925652Sjhay if (ip == NULL) { 178011819Sjulian splx(s); 178111819Sjulian return; 178211819Sjulian } 178311819Sjulian while (ip != &ipxpcb) { 178411819Sjulian cb = ipxtospxpcb(ip); 178511819Sjulian ipnxt = ip->ipxp_next; 178625652Sjhay if (cb == NULL) 178711819Sjulian goto tpgone; 178811819Sjulian for (i = 0; i < SPXT_NTIMERS; i++) { 178911819Sjulian if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 179024659Sjhay spx_timers(cb, i); 179111819Sjulian if (ipnxt->ipxp_prev != ip) 179211819Sjulian goto tpgone; 179311819Sjulian } 179411819Sjulian } 179511819Sjulian cb->s_idle++; 179611819Sjulian if (cb->s_rtt) 179711819Sjulian cb->s_rtt++; 179811819Sjuliantpgone: 179911819Sjulian ip = ipnxt; 180011819Sjulian } 180111819Sjulian spx_iss += SPX_ISSINCR/PR_SLOWHZ; /* increment iss */ 180211819Sjulian splx(s); 180311819Sjulian} 180425652Sjhay 180511819Sjulian/* 180611819Sjulian * SPX timer processing. 180711819Sjulian */ 180825652Sjhaystatic struct spxpcb * 180911819Sjulianspx_timers(cb, timer) 181011819Sjulian register struct spxpcb *cb; 181111819Sjulian int timer; 181211819Sjulian{ 181311819Sjulian long rexmt; 181411819Sjulian int win; 181511819Sjulian 181611819Sjulian cb->s_force = 1 + timer; 181711819Sjulian switch (timer) { 181811819Sjulian 181911819Sjulian /* 182011819Sjulian * 2 MSL timeout in shutdown went off. TCP deletes connection 182111819Sjulian * control block. 182211819Sjulian */ 182311819Sjulian case SPXT_2MSL: 182411819Sjulian printf("spx: SPXT_2MSL went off for no reason\n"); 182511819Sjulian cb->s_timer[timer] = 0; 182611819Sjulian break; 182711819Sjulian 182811819Sjulian /* 182911819Sjulian * Retransmission timer went off. Message has not 183011819Sjulian * been acked within retransmit interval. Back off 183111819Sjulian * to a longer retransmit interval and retransmit one packet. 183211819Sjulian */ 183311819Sjulian case SPXT_REXMT: 183411819Sjulian if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) { 183511819Sjulian cb->s_rxtshift = SPX_MAXRXTSHIFT; 183611819Sjulian spxstat.spxs_timeoutdrop++; 183711819Sjulian cb = spx_drop(cb, ETIMEDOUT); 183811819Sjulian break; 183911819Sjulian } 184011819Sjulian spxstat.spxs_rexmttimeo++; 184111819Sjulian rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 184211819Sjulian rexmt *= spx_backoff[cb->s_rxtshift]; 184311819Sjulian SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX); 184411819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 184511819Sjulian /* 184611819Sjulian * If we have backed off fairly far, our srtt 184711819Sjulian * estimate is probably bogus. Clobber it 184811819Sjulian * so we'll take the next rtt measurement as our srtt; 184911819Sjulian * move the current srtt into rttvar to keep the current 185011819Sjulian * retransmit times until then. 185111819Sjulian */ 185211819Sjulian if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) { 185311819Sjulian cb->s_rttvar += (cb->s_srtt >> 2); 185411819Sjulian cb->s_srtt = 0; 185511819Sjulian } 185611819Sjulian cb->s_snxt = cb->s_rack; 185711819Sjulian /* 185811819Sjulian * If timing a packet, stop the timer. 185911819Sjulian */ 186011819Sjulian cb->s_rtt = 0; 186111819Sjulian /* 186211819Sjulian * See very long discussion in tcp_timer.c about congestion 186311819Sjulian * window and sstrhesh 186411819Sjulian */ 186511819Sjulian win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; 186611819Sjulian if (win < 2) 186711819Sjulian win = 2; 186811819Sjulian cb->s_cwnd = CUNIT; 186911819Sjulian cb->s_ssthresh = win * CUNIT; 187025652Sjhay spx_output(cb, (struct mbuf *)NULL); 187111819Sjulian break; 187211819Sjulian 187311819Sjulian /* 187411819Sjulian * Persistance timer into zero window. 187511819Sjulian * Force a probe to be sent. 187611819Sjulian */ 187711819Sjulian case SPXT_PERSIST: 187811819Sjulian spxstat.spxs_persisttimeo++; 187911819Sjulian spx_setpersist(cb); 188025652Sjhay spx_output(cb, (struct mbuf *)NULL); 188111819Sjulian break; 188211819Sjulian 188311819Sjulian /* 188411819Sjulian * Keep-alive timer went off; send something 188511819Sjulian * or drop connection if idle for too long. 188611819Sjulian */ 188711819Sjulian case SPXT_KEEP: 188811819Sjulian spxstat.spxs_keeptimeo++; 188911819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 189011819Sjulian goto dropit; 189111819Sjulian if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) { 189211819Sjulian if (cb->s_idle >= SPXTV_MAXIDLE) 189311819Sjulian goto dropit; 189411819Sjulian spxstat.spxs_keepprobe++; 189525652Sjhay spx_output(cb, (struct mbuf *)NULL); 189611819Sjulian } else 189711819Sjulian cb->s_idle = 0; 189811819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 189911819Sjulian break; 190011819Sjulian dropit: 190111819Sjulian spxstat.spxs_keepdrops++; 190211819Sjulian cb = spx_drop(cb, ETIMEDOUT); 190311819Sjulian break; 190411819Sjulian } 190511819Sjulian return (cb); 190611819Sjulian} 1907