spx_reass.c revision 29024
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 * 3629024Sbde * $Id: spx_usrreq.c,v 1.15 1997/08/16 19:15:47 wollman 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 */ 6225652Sjhayu_short spx_iss; 6325652Sjhayu_short spx_newchecks[50]; 6425652Sjhayint spx_hardnosed; 6525652Sjhayint spx_use_delack = 0; 6625652Sjhayint traceallspxs = 0; 6725652Sjhaystruct spx spx_savesi; 6825652Sjhaystruct spx_istat spx_istat; 6911819Sjulian 7025652Sjhay/* Following was struct spxstat spxstat; */ 7125652Sjhay#ifndef spxstat 7225652Sjhay#define spxstat spx_istat.newstats 7325652Sjhay#endif 7411819Sjulian 7525652Sjhayint spx_backoff[SPX_MAXRXTSHIFT+1] = 7625652Sjhay { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 7711819Sjulian 7825652Sjhaystatic void spx_abort(struct ipxpcb *ipxp); 7925652Sjhaystatic struct spxpcb *spx_close(struct spxpcb *cb); 8025652Sjhaystatic struct spxpcb *spx_disconnect(struct spxpcb *cb); 8125652Sjhaystatic struct spxpcb *spx_drop(struct spxpcb *cb, int errno); 8225652Sjhaystatic int spx_output(struct spxpcb *cb, struct mbuf *m0); 8325652Sjhaystatic void spx_quench(struct ipxpcb *ipxp); 8425652Sjhaystatic int spx_reass(struct spxpcb *cb, struct spx *si); 8525652Sjhaystatic void spx_setpersist(struct spxpcb *cb); 8625652Sjhaystatic void spx_template(struct spxpcb *cb); 8725652Sjhaystatic struct spxpcb *spx_timers(struct spxpcb *cb, int timer); 8825652Sjhaystatic struct spxpcb *spx_usrclosed(struct spxpcb *cb); 8925652Sjhay 9024659Sjhaystatic int spx_usr_abort(struct socket *so); 9128270Swollmanstatic int spx_accept(struct socket *so, struct sockaddr **nam); 9225345Sjhaystatic int spx_attach(struct socket *so, int proto, struct proc *p); 9328270Swollmanstatic int spx_bind(struct socket *so, struct sockaddr *nam, struct proc *p); 9428270Swollmanstatic int spx_connect(struct socket *so, struct sockaddr *nam, 9528270Swollman struct proc *p); 9624659Sjhaystatic int spx_detach(struct socket *so); 9724659Sjhaystatic int spx_usr_disconnect(struct socket *so); 9825345Sjhaystatic int spx_listen(struct socket *so, struct proc *p); 9924659Sjhaystatic int spx_rcvd(struct socket *so, int flags); 10024659Sjhaystatic int spx_rcvoob(struct socket *so, struct mbuf *m, int flags); 10124659Sjhaystatic int spx_send(struct socket *so, int flags, struct mbuf *m, 10228270Swollman struct sockaddr *addr, struct mbuf *control, 10328270Swollman struct proc *p); 10424659Sjhaystatic int spx_shutdown(struct socket *so); 10525345Sjhaystatic int spx_sp_attach(struct socket *so, int proto, struct proc *p); 10624659Sjhay 10724659Sjhaystruct pr_usrreqs spx_usrreqs = { 10824659Sjhay spx_usr_abort, spx_accept, spx_attach, spx_bind, 10924659Sjhay spx_connect, pru_connect2_notsupp, ipx_control, spx_detach, 11024659Sjhay spx_usr_disconnect, spx_listen, ipx_peeraddr, spx_rcvd, 11124659Sjhay spx_rcvoob, spx_send, pru_sense_null, spx_shutdown, 11225652Sjhay ipx_sockaddr, sosend, soreceive, soselect 11324659Sjhay}; 11424659Sjhay 11524659Sjhaystruct pr_usrreqs spx_usrreq_sps = { 11624659Sjhay spx_usr_abort, spx_accept, spx_sp_attach, spx_bind, 11724659Sjhay spx_connect, pru_connect2_notsupp, ipx_control, spx_detach, 11824659Sjhay spx_usr_disconnect, spx_listen, ipx_peeraddr, spx_rcvd, 11924659Sjhay spx_rcvoob, spx_send, pru_sense_null, spx_shutdown, 12025652Sjhay ipx_sockaddr, sosend, soreceive, soselect 12124659Sjhay}; 12224659Sjhay 12311819Sjulianvoid 12411819Sjulianspx_init() 12511819Sjulian{ 12611819Sjulian 12711819Sjulian spx_iss = 1; /* WRONG !! should fish it out of TODR */ 12811819Sjulian} 12911819Sjulian 13011819Sjulianvoid 13111819Sjulianspx_input(m, ipxp) 13211819Sjulian register struct mbuf *m; 13311819Sjulian register struct ipxpcb *ipxp; 13411819Sjulian{ 13511819Sjulian register struct spxpcb *cb; 13611819Sjulian register struct spx *si = mtod(m, struct spx *); 13711819Sjulian register struct socket *so; 13811819Sjulian int dropsocket = 0; 13911819Sjulian short ostate = 0; 14011819Sjulian 14111819Sjulian spxstat.spxs_rcvtotal++; 14225652Sjhay if (ipxp == NULL) { 14311819Sjulian panic("No ipxpcb in spx_input\n"); 14411819Sjulian return; 14511819Sjulian } 14611819Sjulian 14711819Sjulian cb = ipxtospxpcb(ipxp); 14825652Sjhay if (cb == NULL) 14925652Sjhay goto bad; 15011819Sjulian 15111819Sjulian if (m->m_len < sizeof(*si)) { 15225652Sjhay if ((m = m_pullup(m, sizeof(*si))) == NULL) { 15311819Sjulian spxstat.spxs_rcvshort++; 15411819Sjulian return; 15511819Sjulian } 15611819Sjulian si = mtod(m, struct spx *); 15711819Sjulian } 15811819Sjulian si->si_seq = ntohs(si->si_seq); 15911819Sjulian si->si_ack = ntohs(si->si_ack); 16011819Sjulian si->si_alo = ntohs(si->si_alo); 16111819Sjulian 16211819Sjulian so = ipxp->ipxp_socket; 16311819Sjulian 16411819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) { 16511819Sjulian ostate = cb->s_state; 16611819Sjulian spx_savesi = *si; 16711819Sjulian } 16811819Sjulian if (so->so_options & SO_ACCEPTCONN) { 16911819Sjulian struct spxpcb *ocb = cb; 17011819Sjulian 17111819Sjulian so = sonewconn(so, 0); 17225652Sjhay if (so == NULL) { 17311819Sjulian goto drop; 17411819Sjulian } 17511819Sjulian /* 17611819Sjulian * This is ugly, but .... 17711819Sjulian * 17811819Sjulian * Mark socket as temporary until we're 17911819Sjulian * committed to keeping it. The code at 18011819Sjulian * ``drop'' and ``dropwithreset'' check the 18111819Sjulian * flag dropsocket to see if the temporary 18211819Sjulian * socket created here should be discarded. 18311819Sjulian * We mark the socket as discardable until 18411819Sjulian * we're committed to it below in TCPS_LISTEN. 18511819Sjulian */ 18611819Sjulian dropsocket++; 18711819Sjulian ipxp = (struct ipxpcb *)so->so_pcb; 18811819Sjulian ipxp->ipxp_laddr = si->si_dna; 18911819Sjulian cb = ipxtospxpcb(ipxp); 19011819Sjulian cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ 19111819Sjulian cb->s_flags = ocb->s_flags; /* preserve sockopts */ 19211819Sjulian cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ 19311819Sjulian cb->s_state = TCPS_LISTEN; 19411819Sjulian } 19511819Sjulian 19611819Sjulian /* 19711819Sjulian * Packet received on connection. 19811819Sjulian * reset idle time and keep-alive timer; 19911819Sjulian */ 20011819Sjulian cb->s_idle = 0; 20111819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 20211819Sjulian 20311819Sjulian switch (cb->s_state) { 20411819Sjulian 20511819Sjulian case TCPS_LISTEN:{ 20628270Swollman struct sockaddr_ipx *sipx, ssipx; 20711819Sjulian struct ipx_addr laddr; 20811819Sjulian 20911819Sjulian /* 21011819Sjulian * If somebody here was carying on a conversation 21111819Sjulian * and went away, and his pen pal thinks he can 21211819Sjulian * still talk, we get the misdirected packet. 21311819Sjulian */ 21411819Sjulian if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 21511819Sjulian spx_istat.gonawy++; 21611819Sjulian goto dropwithreset; 21711819Sjulian } 21828270Swollman sipx = &ssipx; 21928270Swollman bzero(sipx, sizeof *sipx); 22011819Sjulian sipx->sipx_len = sizeof(*sipx); 22111819Sjulian sipx->sipx_family = AF_IPX; 22211819Sjulian sipx->sipx_addr = si->si_sna; 22311819Sjulian laddr = ipxp->ipxp_laddr; 22411819Sjulian if (ipx_nullhost(laddr)) 22511819Sjulian ipxp->ipxp_laddr = si->si_dna; 22628270Swollman if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &proc0)) { 22711819Sjulian ipxp->ipxp_laddr = laddr; 22811819Sjulian spx_istat.noconn++; 22911819Sjulian goto drop; 23011819Sjulian } 23111819Sjulian spx_template(cb); 23211819Sjulian dropsocket = 0; /* committed to socket */ 23311819Sjulian cb->s_did = si->si_sid; 23411819Sjulian cb->s_rack = si->si_ack; 23511819Sjulian cb->s_ralo = si->si_alo; 23611819Sjulian#define THREEWAYSHAKE 23711819Sjulian#ifdef THREEWAYSHAKE 23811819Sjulian cb->s_state = TCPS_SYN_RECEIVED; 23911819Sjulian cb->s_force = 1 + SPXT_KEEP; 24011819Sjulian spxstat.spxs_accepts++; 24111819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 24211819Sjulian } 24311819Sjulian break; 24411819Sjulian /* 24511819Sjulian * This state means that we have heard a response 24611819Sjulian * to our acceptance of their connection 24711819Sjulian * It is probably logically unnecessary in this 24811819Sjulian * implementation. 24911819Sjulian */ 25011819Sjulian case TCPS_SYN_RECEIVED: { 25125652Sjhay if (si->si_did != cb->s_sid) { 25211819Sjulian spx_istat.wrncon++; 25311819Sjulian goto drop; 25411819Sjulian } 25511819Sjulian#endif 25611819Sjulian ipxp->ipxp_fport = si->si_sport; 25711819Sjulian cb->s_timer[SPXT_REXMT] = 0; 25811819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 25911819Sjulian soisconnected(so); 26011819Sjulian cb->s_state = TCPS_ESTABLISHED; 26111819Sjulian spxstat.spxs_accepts++; 26211819Sjulian } 26311819Sjulian break; 26411819Sjulian 26511819Sjulian /* 26611819Sjulian * This state means that we have gotten a response 26711819Sjulian * to our attempt to establish a connection. 26811819Sjulian * We fill in the data from the other side, 26911819Sjulian * telling us which port to respond to, instead of the well- 27011819Sjulian * known one we might have sent to in the first place. 27111819Sjulian * We also require that this is a response to our 27211819Sjulian * connection id. 27311819Sjulian */ 27411819Sjulian case TCPS_SYN_SENT: 27525652Sjhay if (si->si_did != cb->s_sid) { 27611819Sjulian spx_istat.notme++; 27711819Sjulian goto drop; 27811819Sjulian } 27911819Sjulian spxstat.spxs_connects++; 28011819Sjulian cb->s_did = si->si_sid; 28111819Sjulian cb->s_rack = si->si_ack; 28211819Sjulian cb->s_ralo = si->si_alo; 28311819Sjulian cb->s_dport = ipxp->ipxp_fport = si->si_sport; 28411819Sjulian cb->s_timer[SPXT_REXMT] = 0; 28511819Sjulian cb->s_flags |= SF_ACKNOW; 28611819Sjulian soisconnected(so); 28711819Sjulian cb->s_state = TCPS_ESTABLISHED; 28811819Sjulian /* Use roundtrip time of connection request for initial rtt */ 28911819Sjulian if (cb->s_rtt) { 29011819Sjulian cb->s_srtt = cb->s_rtt << 3; 29111819Sjulian cb->s_rttvar = cb->s_rtt << 1; 29211819Sjulian SPXT_RANGESET(cb->s_rxtcur, 29311819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 29411819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 29511819Sjulian cb->s_rtt = 0; 29611819Sjulian } 29711819Sjulian } 29811819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) 29911819Sjulian spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0); 30011819Sjulian 30125652Sjhay m->m_len -= sizeof(struct ipx); 30225652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 30325652Sjhay m->m_data += sizeof(struct ipx); 30411819Sjulian 30511819Sjulian if (spx_reass(cb, si)) { 30625652Sjhay m_freem(m); 30711819Sjulian } 30811819Sjulian if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) 30925652Sjhay spx_output(cb, (struct mbuf *)NULL); 31011819Sjulian cb->s_flags &= ~(SF_WIN|SF_RXT); 31111819Sjulian return; 31211819Sjulian 31311819Sjuliandropwithreset: 31411819Sjulian if (dropsocket) 31525652Sjhay soabort(so); 31611819Sjulian si->si_seq = ntohs(si->si_seq); 31711819Sjulian si->si_ack = ntohs(si->si_ack); 31811819Sjulian si->si_alo = ntohs(si->si_alo); 31925652Sjhay m_freem(dtom(si)); 32011819Sjulian if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs) 32111819Sjulian spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 32211819Sjulian return; 32311819Sjulian 32411819Sjuliandrop: 32511819Sjulianbad: 32611819Sjulian if (cb == 0 || cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || 32711819Sjulian traceallspxs) 32811819Sjulian spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 32911819Sjulian m_freem(m); 33011819Sjulian} 33111819Sjulian 33211819Sjulianint spxrexmtthresh = 3; 33311819Sjulian 33411819Sjulian/* 33511819Sjulian * This is structurally similar to the tcp reassembly routine 33611819Sjulian * but its function is somewhat different: It merely queues 33711819Sjulian * packets up, and suppresses duplicates. 33811819Sjulian */ 33925652Sjhaystatic int 34011819Sjulianspx_reass(cb, si) 34111819Sjulianregister struct spxpcb *cb; 34211819Sjulianregister struct spx *si; 34311819Sjulian{ 34411819Sjulian register struct spx_q *q; 34511819Sjulian register struct mbuf *m; 34611819Sjulian register struct socket *so = cb->s_ipxpcb->ipxp_socket; 34711819Sjulian char packetp = cb->s_flags & SF_HI; 34811819Sjulian int incr; 34911819Sjulian char wakeup = 0; 35011819Sjulian 35111819Sjulian if (si == SI(0)) 35211819Sjulian goto present; 35311819Sjulian /* 35411819Sjulian * Update our news from them. 35511819Sjulian */ 35611819Sjulian if (si->si_cc & SPX_SA) 35711819Sjulian cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW); 35811819Sjulian if (SSEQ_GT(si->si_alo, cb->s_ralo)) 35911819Sjulian cb->s_flags |= SF_WIN; 36011819Sjulian if (SSEQ_LEQ(si->si_ack, cb->s_rack)) { 36111819Sjulian if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) { 36211819Sjulian spxstat.spxs_rcvdupack++; 36311819Sjulian /* 36411819Sjulian * If this is a completely duplicate ack 36511819Sjulian * and other conditions hold, we assume 36611819Sjulian * a packet has been dropped and retransmit 36711819Sjulian * it exactly as in tcp_input(). 36811819Sjulian */ 36911819Sjulian if (si->si_ack != cb->s_rack || 37011819Sjulian si->si_alo != cb->s_ralo) 37111819Sjulian cb->s_dupacks = 0; 37211819Sjulian else if (++cb->s_dupacks == spxrexmtthresh) { 37311819Sjulian u_short onxt = cb->s_snxt; 37411819Sjulian int cwnd = cb->s_cwnd; 37511819Sjulian 37611819Sjulian cb->s_snxt = si->si_ack; 37711819Sjulian cb->s_cwnd = CUNIT; 37811819Sjulian cb->s_force = 1 + SPXT_REXMT; 37925652Sjhay spx_output(cb, (struct mbuf *)NULL); 38011819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 38111819Sjulian cb->s_rtt = 0; 38211819Sjulian if (cwnd >= 4 * CUNIT) 38311819Sjulian cb->s_cwnd = cwnd / 2; 38411819Sjulian if (SSEQ_GT(onxt, cb->s_snxt)) 38511819Sjulian cb->s_snxt = onxt; 38611819Sjulian return (1); 38711819Sjulian } 38811819Sjulian } else 38911819Sjulian cb->s_dupacks = 0; 39011819Sjulian goto update_window; 39111819Sjulian } 39211819Sjulian cb->s_dupacks = 0; 39311819Sjulian /* 39411819Sjulian * If our correspondent acknowledges data we haven't sent 39511819Sjulian * TCP would drop the packet after acking. We'll be a little 39611819Sjulian * more permissive 39711819Sjulian */ 39811819Sjulian if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) { 39911819Sjulian spxstat.spxs_rcvacktoomuch++; 40011819Sjulian si->si_ack = cb->s_smax + 1; 40111819Sjulian } 40211819Sjulian spxstat.spxs_rcvackpack++; 40311819Sjulian /* 40411819Sjulian * If transmit timer is running and timed sequence 40511819Sjulian * number was acked, update smoothed round trip time. 40611819Sjulian * See discussion of algorithm in tcp_input.c 40711819Sjulian */ 40811819Sjulian if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 40911819Sjulian spxstat.spxs_rttupdated++; 41011819Sjulian if (cb->s_srtt != 0) { 41111819Sjulian register short delta; 41211819Sjulian delta = cb->s_rtt - (cb->s_srtt >> 3); 41311819Sjulian if ((cb->s_srtt += delta) <= 0) 41411819Sjulian cb->s_srtt = 1; 41511819Sjulian if (delta < 0) 41611819Sjulian delta = -delta; 41711819Sjulian delta -= (cb->s_rttvar >> 2); 41811819Sjulian if ((cb->s_rttvar += delta) <= 0) 41911819Sjulian cb->s_rttvar = 1; 42011819Sjulian } else { 42111819Sjulian /* 42211819Sjulian * No rtt measurement yet 42311819Sjulian */ 42411819Sjulian cb->s_srtt = cb->s_rtt << 3; 42511819Sjulian cb->s_rttvar = cb->s_rtt << 1; 42611819Sjulian } 42711819Sjulian cb->s_rtt = 0; 42811819Sjulian cb->s_rxtshift = 0; 42911819Sjulian SPXT_RANGESET(cb->s_rxtcur, 43011819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 43111819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 43211819Sjulian } 43311819Sjulian /* 43411819Sjulian * If all outstanding data is acked, stop retransmit 43511819Sjulian * timer and remember to restart (more output or persist). 43611819Sjulian * If there is more data to be acked, restart retransmit 43711819Sjulian * timer, using current (possibly backed-off) value; 43811819Sjulian */ 43911819Sjulian if (si->si_ack == cb->s_smax + 1) { 44011819Sjulian cb->s_timer[SPXT_REXMT] = 0; 44111819Sjulian cb->s_flags |= SF_RXT; 44211819Sjulian } else if (cb->s_timer[SPXT_PERSIST] == 0) 44311819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 44411819Sjulian /* 44511819Sjulian * When new data is acked, open the congestion window. 44611819Sjulian * If the window gives us less than ssthresh packets 44711819Sjulian * in flight, open exponentially (maxseg at a time). 44811819Sjulian * Otherwise open linearly (maxseg^2 / cwnd at a time). 44911819Sjulian */ 45011819Sjulian incr = CUNIT; 45111819Sjulian if (cb->s_cwnd > cb->s_ssthresh) 45211819Sjulian incr = max(incr * incr / cb->s_cwnd, 1); 45311819Sjulian cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx); 45411819Sjulian /* 45511819Sjulian * Trim Acked data from output queue. 45611819Sjulian */ 45711819Sjulian while ((m = so->so_snd.sb_mb) != NULL) { 45811819Sjulian if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack)) 45911819Sjulian sbdroprecord(&so->so_snd); 46011819Sjulian else 46111819Sjulian break; 46211819Sjulian } 46311819Sjulian sowwakeup(so); 46411819Sjulian cb->s_rack = si->si_ack; 46511819Sjulianupdate_window: 46611819Sjulian if (SSEQ_LT(cb->s_snxt, cb->s_rack)) 46711819Sjulian cb->s_snxt = cb->s_rack; 46811819Sjulian if (SSEQ_LT(cb->s_swl1, si->si_seq) || cb->s_swl1 == si->si_seq && 46911819Sjulian (SSEQ_LT(cb->s_swl2, si->si_ack) || 47011819Sjulian cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))) { 47111819Sjulian /* keep track of pure window updates */ 47211819Sjulian if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack 47311819Sjulian && SSEQ_LT(cb->s_ralo, si->si_alo)) { 47411819Sjulian spxstat.spxs_rcvwinupd++; 47511819Sjulian spxstat.spxs_rcvdupack--; 47611819Sjulian } 47711819Sjulian cb->s_ralo = si->si_alo; 47811819Sjulian cb->s_swl1 = si->si_seq; 47911819Sjulian cb->s_swl2 = si->si_ack; 48011819Sjulian cb->s_swnd = (1 + si->si_alo - si->si_ack); 48111819Sjulian if (cb->s_swnd > cb->s_smxw) 48211819Sjulian cb->s_smxw = cb->s_swnd; 48311819Sjulian cb->s_flags |= SF_WIN; 48411819Sjulian } 48511819Sjulian /* 48611819Sjulian * If this packet number is higher than that which 48711819Sjulian * we have allocated refuse it, unless urgent 48811819Sjulian */ 48911819Sjulian if (SSEQ_GT(si->si_seq, cb->s_alo)) { 49011819Sjulian if (si->si_cc & SPX_SP) { 49111819Sjulian spxstat.spxs_rcvwinprobe++; 49211819Sjulian return (1); 49311819Sjulian } else 49411819Sjulian spxstat.spxs_rcvpackafterwin++; 49511819Sjulian if (si->si_cc & SPX_OB) { 49611819Sjulian if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { 49725652Sjhay m_freem(dtom(si)); 49811819Sjulian return (0); 49911819Sjulian } /* else queue this packet; */ 50011819Sjulian } else { 50111819Sjulian /*register struct socket *so = cb->s_ipxpcb->ipxp_socket; 50211819Sjulian if (so->so_state && SS_NOFDREF) { 50325652Sjhay spx_close(cb); 50411819Sjulian } else 50511819Sjulian would crash system*/ 50611819Sjulian spx_istat.notyet++; 50725652Sjhay m_freem(dtom(si)); 50811819Sjulian return (0); 50911819Sjulian } 51011819Sjulian } 51111819Sjulian /* 51211819Sjulian * If this is a system packet, we don't need to 51311819Sjulian * queue it up, and won't update acknowledge # 51411819Sjulian */ 51511819Sjulian if (si->si_cc & SPX_SP) { 51611819Sjulian return (1); 51711819Sjulian } 51811819Sjulian /* 51911819Sjulian * We have already seen this packet, so drop. 52011819Sjulian */ 52111819Sjulian if (SSEQ_LT(si->si_seq, cb->s_ack)) { 52211819Sjulian spx_istat.bdreas++; 52311819Sjulian spxstat.spxs_rcvduppack++; 52411819Sjulian if (si->si_seq == cb->s_ack - 1) 52511819Sjulian spx_istat.lstdup++; 52611819Sjulian return (1); 52711819Sjulian } 52811819Sjulian /* 52911819Sjulian * Loop through all packets queued up to insert in 53011819Sjulian * appropriate sequence. 53111819Sjulian */ 53225652Sjhay for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { 53311819Sjulian if (si->si_seq == SI(q)->si_seq) { 53411819Sjulian spxstat.spxs_rcvduppack++; 53511819Sjulian return (1); 53611819Sjulian } 53711819Sjulian if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { 53811819Sjulian spxstat.spxs_rcvoopack++; 53911819Sjulian break; 54011819Sjulian } 54111819Sjulian } 54211819Sjulian insque(si, q->si_prev); 54311819Sjulian /* 54411819Sjulian * If this packet is urgent, inform process 54511819Sjulian */ 54611819Sjulian if (si->si_cc & SPX_OB) { 54711819Sjulian cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 54811819Sjulian sohasoutofband(so); 54911819Sjulian cb->s_oobflags |= SF_IOOB; 55011819Sjulian } 55111819Sjulianpresent: 55211819Sjulian#define SPINC sizeof(struct spxhdr) 55311819Sjulian /* 55411819Sjulian * Loop through all packets queued up to update acknowledge 55511819Sjulian * number, and present all acknowledged data to user; 55611819Sjulian * If in packet interface mode, show packet headers. 55711819Sjulian */ 55825652Sjhay for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { 55911819Sjulian if (SI(q)->si_seq == cb->s_ack) { 56011819Sjulian cb->s_ack++; 56111819Sjulian m = dtom(q); 56211819Sjulian if (SI(q)->si_cc & SPX_OB) { 56311819Sjulian cb->s_oobflags &= ~SF_IOOB; 56411819Sjulian if (so->so_rcv.sb_cc) 56511819Sjulian so->so_oobmark = so->so_rcv.sb_cc; 56611819Sjulian else 56711819Sjulian so->so_state |= SS_RCVATMARK; 56811819Sjulian } 56911819Sjulian q = q->si_prev; 57011819Sjulian remque(q->si_next); 57111819Sjulian wakeup = 1; 57211819Sjulian spxstat.spxs_rcvpack++; 57311819Sjulian#ifdef SF_NEWCALL 57411819Sjulian if (cb->s_flags2 & SF_NEWCALL) { 57511819Sjulian struct spxhdr *sp = mtod(m, struct spxhdr *); 57611819Sjulian u_char dt = sp->spx_dt; 57711819Sjulian spx_newchecks[4]++; 57811819Sjulian if (dt != cb->s_rhdr.spx_dt) { 57911819Sjulian struct mbuf *mm = 58011819Sjulian m_getclr(M_DONTWAIT, MT_CONTROL); 58111819Sjulian spx_newchecks[0]++; 58211819Sjulian if (mm != NULL) { 58311819Sjulian u_short *s = 58411819Sjulian mtod(mm, u_short *); 58511819Sjulian cb->s_rhdr.spx_dt = dt; 58611819Sjulian mm->m_len = 5; /*XXX*/ 58711819Sjulian s[0] = 5; 58811819Sjulian s[1] = 1; 58911819Sjulian *(u_char *)(&s[2]) = dt; 59011819Sjulian sbappend(&so->so_rcv, mm); 59111819Sjulian } 59211819Sjulian } 59311819Sjulian if (sp->spx_cc & SPX_OB) { 59411819Sjulian MCHTYPE(m, MT_OOBDATA); 59511819Sjulian spx_newchecks[1]++; 59611819Sjulian so->so_oobmark = 0; 59711819Sjulian so->so_state &= ~SS_RCVATMARK; 59811819Sjulian } 59911819Sjulian if (packetp == 0) { 60011819Sjulian m->m_data += SPINC; 60111819Sjulian m->m_len -= SPINC; 60211819Sjulian m->m_pkthdr.len -= SPINC; 60311819Sjulian } 60411819Sjulian if ((sp->spx_cc & SPX_EM) || packetp) { 60511819Sjulian sbappendrecord(&so->so_rcv, m); 60611819Sjulian spx_newchecks[9]++; 60711819Sjulian } else 60811819Sjulian sbappend(&so->so_rcv, m); 60911819Sjulian } else 61011819Sjulian#endif 61111819Sjulian if (packetp) { 61211819Sjulian sbappendrecord(&so->so_rcv, m); 61311819Sjulian } else { 61411819Sjulian cb->s_rhdr = *mtod(m, struct spxhdr *); 61511819Sjulian m->m_data += SPINC; 61611819Sjulian m->m_len -= SPINC; 61711819Sjulian m->m_pkthdr.len -= SPINC; 61811819Sjulian sbappend(&so->so_rcv, m); 61911819Sjulian } 62011819Sjulian } else 62111819Sjulian break; 62211819Sjulian } 62325652Sjhay if (wakeup) 62425652Sjhay sorwakeup(so); 62511819Sjulian return (0); 62611819Sjulian} 62711819Sjulian 62811819Sjulianvoid 62912881Sbdespx_ctlinput(cmd, arg_as_sa, dummy) 63011819Sjulian int cmd; 63112881Sbde struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */ 63212881Sbde void *dummy; 63311819Sjulian{ 63412881Sbde caddr_t arg = (/* XXX */ caddr_t)arg_as_sa; 63511819Sjulian struct ipx_addr *na; 63625652Sjhay struct sockaddr_ipx *sipx; 63711819Sjulian 63811819Sjulian if (cmd < 0 || cmd > PRC_NCMDS) 63911819Sjulian return; 64025652Sjhay 64111819Sjulian switch (cmd) { 64211819Sjulian 64311819Sjulian case PRC_ROUTEDEAD: 64411819Sjulian return; 64511819Sjulian 64611819Sjulian case PRC_IFDOWN: 64711819Sjulian case PRC_HOSTDEAD: 64811819Sjulian case PRC_HOSTUNREACH: 64911819Sjulian sipx = (struct sockaddr_ipx *)arg; 65011819Sjulian if (sipx->sipx_family != AF_IPX) 65111819Sjulian return; 65211819Sjulian na = &sipx->sipx_addr; 65311819Sjulian break; 65411819Sjulian 65511819Sjulian default: 65611819Sjulian break; 65711819Sjulian } 65811819Sjulian} 65911819Sjulian/* 66011819Sjulian * When a source quench is received, close congestion window 66111819Sjulian * to one packet. We will gradually open it again as we proceed. 66211819Sjulian */ 66325652Sjhaystatic void 66411819Sjulianspx_quench(ipxp) 66511819Sjulian struct ipxpcb *ipxp; 66611819Sjulian{ 66711819Sjulian struct spxpcb *cb = ipxtospxpcb(ipxp); 66811819Sjulian 66925652Sjhay if (cb != NULL) 67011819Sjulian cb->s_cwnd = CUNIT; 67111819Sjulian} 67211819Sjulian 67311819Sjulian#ifdef notdef 67411819Sjulianint 67511819Sjulianspx_fixmtu(ipxp) 67611819Sjulianregister struct ipxpcb *ipxp; 67711819Sjulian{ 67811819Sjulian register struct spxpcb *cb = (struct spxpcb *)(ipxp->ipxp_pcb); 67911819Sjulian register struct mbuf *m; 68011819Sjulian register struct spx *si; 68111819Sjulian struct ipx_errp *ep; 68211819Sjulian struct sockbuf *sb; 68311819Sjulian int badseq, len; 68411819Sjulian struct mbuf *firstbad, *m0; 68511819Sjulian 68625652Sjhay if (cb != NULL) { 68711819Sjulian /* 68811819Sjulian * The notification that we have sent 68911819Sjulian * too much is bad news -- we will 69011819Sjulian * have to go through queued up so far 69111819Sjulian * splitting ones which are too big and 69211819Sjulian * reassigning sequence numbers and checksums. 69311819Sjulian * we should then retransmit all packets from 69411819Sjulian * one above the offending packet to the last one 69511819Sjulian * we had sent (or our allocation) 69611819Sjulian * then the offending one so that the any queued 69711819Sjulian * data at our destination will be discarded. 69811819Sjulian */ 69911819Sjulian ep = (struct ipx_errp *)ipxp->ipxp_notify_param; 70011819Sjulian sb = &ipxp->ipxp_socket->so_snd; 70111819Sjulian cb->s_mtu = ep->ipx_err_param; 70211819Sjulian badseq = SI(&ep->ipx_err_ipx)->si_seq; 70325652Sjhay for (m = sb->sb_mb; m != NULL; m = m->m_act) { 70411819Sjulian si = mtod(m, struct spx *); 70511819Sjulian if (si->si_seq == badseq) 70611819Sjulian break; 70711819Sjulian } 70825652Sjhay if (m == NULL) 70925652Sjhay return; 71011819Sjulian firstbad = m; 71111819Sjulian /*for (;;) {*/ 71211819Sjulian /* calculate length */ 71325652Sjhay for (m0 = m, len = 0; m != NULL; m = m->m_next) 71411819Sjulian len += m->m_len; 71511819Sjulian if (len > cb->s_mtu) { 71611819Sjulian } 71711819Sjulian /* FINISH THIS 71811819Sjulian } */ 71911819Sjulian } 72011819Sjulian} 72111819Sjulian#endif 72211819Sjulian 72325652Sjhaystatic int 72411819Sjulianspx_output(cb, m0) 72511819Sjulian register struct spxpcb *cb; 72611819Sjulian struct mbuf *m0; 72711819Sjulian{ 72811819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 72911819Sjulian register struct mbuf *m; 73025652Sjhay register struct spx *si = (struct spx *)NULL; 73111819Sjulian register struct sockbuf *sb = &so->so_snd; 73211819Sjulian int len = 0, win, rcv_win; 73311819Sjulian short span, off, recordp = 0; 73411819Sjulian u_short alo; 73511819Sjulian int error = 0, sendalot; 73611819Sjulian#ifdef notdef 73711819Sjulian int idle; 73811819Sjulian#endif 73911819Sjulian struct mbuf *mprev; 74011819Sjulian 74125652Sjhay if (m0 != NULL) { 74211819Sjulian int mtu = cb->s_mtu; 74311819Sjulian int datalen; 74411819Sjulian /* 74511819Sjulian * Make sure that packet isn't too big. 74611819Sjulian */ 74725652Sjhay for (m = m0; m != NULL; m = m->m_next) { 74811819Sjulian mprev = m; 74911819Sjulian len += m->m_len; 75011819Sjulian if (m->m_flags & M_EOR) 75111819Sjulian recordp = 1; 75211819Sjulian } 75311819Sjulian datalen = (cb->s_flags & SF_HO) ? 75425652Sjhay len - sizeof(struct spxhdr) : len; 75511819Sjulian if (datalen > mtu) { 75611819Sjulian if (cb->s_flags & SF_PI) { 75711819Sjulian m_freem(m0); 75811819Sjulian return (EMSGSIZE); 75911819Sjulian } else { 76011819Sjulian int oldEM = cb->s_cc & SPX_EM; 76111819Sjulian 76211819Sjulian cb->s_cc &= ~SPX_EM; 76311819Sjulian while (len > mtu) { 76411819Sjulian /* 76511819Sjulian * Here we are only being called 76611819Sjulian * from usrreq(), so it is OK to 76711819Sjulian * block. 76811819Sjulian */ 76911819Sjulian m = m_copym(m0, 0, mtu, M_WAIT); 77011819Sjulian if (cb->s_flags & SF_NEWCALL) { 77111819Sjulian struct mbuf *mm = m; 77211819Sjulian spx_newchecks[7]++; 77325652Sjhay while (mm != NULL) { 77411819Sjulian mm->m_flags &= ~M_EOR; 77511819Sjulian mm = mm->m_next; 77611819Sjulian } 77711819Sjulian } 77811819Sjulian error = spx_output(cb, m); 77911819Sjulian if (error) { 78011819Sjulian cb->s_cc |= oldEM; 78111819Sjulian m_freem(m0); 78225652Sjhay return (error); 78311819Sjulian } 78411819Sjulian m_adj(m0, mtu); 78511819Sjulian len -= mtu; 78611819Sjulian } 78711819Sjulian cb->s_cc |= oldEM; 78811819Sjulian } 78911819Sjulian } 79011819Sjulian /* 79111819Sjulian * Force length even, by adding a "garbage byte" if 79211819Sjulian * necessary. 79311819Sjulian */ 79411819Sjulian if (len & 1) { 79511819Sjulian m = mprev; 79611819Sjulian if (M_TRAILINGSPACE(m) >= 1) 79711819Sjulian m->m_len++; 79811819Sjulian else { 79911819Sjulian struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 80011819Sjulian 80125652Sjhay if (m1 == NULL) { 80211819Sjulian m_freem(m0); 80311819Sjulian return (ENOBUFS); 80411819Sjulian } 80511819Sjulian m1->m_len = 1; 80611819Sjulian *(mtod(m1, u_char *)) = 0; 80711819Sjulian m->m_next = m1; 80811819Sjulian } 80911819Sjulian } 81011819Sjulian m = m_gethdr(M_DONTWAIT, MT_HEADER); 81125652Sjhay if (m == NULL) { 81211819Sjulian m_freem(m0); 81311819Sjulian return (ENOBUFS); 81411819Sjulian } 81511819Sjulian /* 81611819Sjulian * Fill in mbuf with extended SP header 81711819Sjulian * and addresses and length put into network format. 81811819Sjulian */ 81925652Sjhay MH_ALIGN(m, sizeof(struct spx)); 82025652Sjhay m->m_len = sizeof(struct spx); 82111819Sjulian m->m_next = m0; 82211819Sjulian si = mtod(m, struct spx *); 82311819Sjulian si->si_i = *cb->s_ipx; 82411819Sjulian si->si_s = cb->s_shdr; 82511819Sjulian if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 82611819Sjulian register struct spxhdr *sh; 82725652Sjhay if (m0->m_len < sizeof(*sh)) { 82811819Sjulian if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 82925652Sjhay m_free(m); 83011819Sjulian m_freem(m0); 83111819Sjulian return (EINVAL); 83211819Sjulian } 83311819Sjulian m->m_next = m0; 83411819Sjulian } 83511819Sjulian sh = mtod(m0, struct spxhdr *); 83611819Sjulian si->si_dt = sh->spx_dt; 83711819Sjulian si->si_cc |= sh->spx_cc & SPX_EM; 83825652Sjhay m0->m_len -= sizeof(*sh); 83925652Sjhay m0->m_data += sizeof(*sh); 84025652Sjhay len -= sizeof(*sh); 84111819Sjulian } 84211819Sjulian len += sizeof(*si); 84311819Sjulian if ((cb->s_flags2 & SF_NEWCALL) && recordp) { 84425652Sjhay si->si_cc |= SPX_EM; 84511819Sjulian spx_newchecks[8]++; 84611819Sjulian } 84711819Sjulian if (cb->s_oobflags & SF_SOOB) { 84811819Sjulian /* 84911819Sjulian * Per jqj@cornell: 85011819Sjulian * make sure OB packets convey exactly 1 byte. 85111819Sjulian * If the packet is 1 byte or larger, we 85211819Sjulian * have already guaranted there to be at least 85311819Sjulian * one garbage byte for the checksum, and 85411819Sjulian * extra bytes shouldn't hurt! 85511819Sjulian */ 85611819Sjulian if (len > sizeof(*si)) { 85711819Sjulian si->si_cc |= SPX_OB; 85811819Sjulian len = (1 + sizeof(*si)); 85911819Sjulian } 86011819Sjulian } 86111819Sjulian si->si_len = htons((u_short)len); 86211819Sjulian m->m_pkthdr.len = ((len - 1) | 1) + 1; 86311819Sjulian /* 86411819Sjulian * queue stuff up for output 86511819Sjulian */ 86611819Sjulian sbappendrecord(sb, m); 86711819Sjulian cb->s_seq++; 86811819Sjulian } 86911819Sjulian#ifdef notdef 87011819Sjulian idle = (cb->s_smax == (cb->s_rack - 1)); 87111819Sjulian#endif 87211819Sjulianagain: 87311819Sjulian sendalot = 0; 87411819Sjulian off = cb->s_snxt - cb->s_rack; 87525652Sjhay win = min(cb->s_swnd, (cb->s_cwnd / CUNIT)); 87611819Sjulian 87711819Sjulian /* 87811819Sjulian * If in persist timeout with window of 0, send a probe. 87911819Sjulian * Otherwise, if window is small but nonzero 88011819Sjulian * and timer expired, send what we can and go into 88111819Sjulian * transmit state. 88211819Sjulian */ 88311819Sjulian if (cb->s_force == 1 + SPXT_PERSIST) { 88411819Sjulian if (win != 0) { 88511819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 88611819Sjulian cb->s_rxtshift = 0; 88711819Sjulian } 88811819Sjulian } 88911819Sjulian span = cb->s_seq - cb->s_rack; 89011819Sjulian len = min(span, win) - off; 89111819Sjulian 89211819Sjulian if (len < 0) { 89311819Sjulian /* 89411819Sjulian * Window shrank after we went into it. 89511819Sjulian * If window shrank to 0, cancel pending 89611819Sjulian * restransmission and pull s_snxt back 89711819Sjulian * to (closed) window. We will enter persist 89811819Sjulian * state below. If the widndow didn't close completely, 89911819Sjulian * just wait for an ACK. 90011819Sjulian */ 90111819Sjulian len = 0; 90211819Sjulian if (win == 0) { 90311819Sjulian cb->s_timer[SPXT_REXMT] = 0; 90411819Sjulian cb->s_snxt = cb->s_rack; 90511819Sjulian } 90611819Sjulian } 90711819Sjulian if (len > 1) 90811819Sjulian sendalot = 1; 90911819Sjulian rcv_win = sbspace(&so->so_rcv); 91011819Sjulian 91111819Sjulian /* 91211819Sjulian * Send if we owe peer an ACK. 91311819Sjulian */ 91411819Sjulian if (cb->s_oobflags & SF_SOOB) { 91511819Sjulian /* 91611819Sjulian * must transmit this out of band packet 91711819Sjulian */ 91811819Sjulian cb->s_oobflags &= ~ SF_SOOB; 91911819Sjulian sendalot = 1; 92011819Sjulian spxstat.spxs_sndurg++; 92111819Sjulian goto found; 92211819Sjulian } 92311819Sjulian if (cb->s_flags & SF_ACKNOW) 92411819Sjulian goto send; 92511819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 92611819Sjulian goto send; 92711819Sjulian /* 92811819Sjulian * Silly window can't happen in spx. 92911819Sjulian * Code from tcp deleted. 93011819Sjulian */ 93111819Sjulian if (len) 93211819Sjulian goto send; 93311819Sjulian /* 93411819Sjulian * Compare available window to amount of window 93511819Sjulian * known to peer (as advertised window less 93611819Sjulian * next expected input.) If the difference is at least two 93711819Sjulian * packets or at least 35% of the mximum possible window, 93811819Sjulian * then want to send a window update to peer. 93911819Sjulian */ 94011819Sjulian if (rcv_win > 0) { 94111819Sjulian u_short delta = 1 + cb->s_alo - cb->s_ack; 94211819Sjulian int adv = rcv_win - (delta * cb->s_mtu); 94311819Sjulian 94411819Sjulian if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || 94511819Sjulian (100 * adv / so->so_rcv.sb_hiwat >= 35)) { 94611819Sjulian spxstat.spxs_sndwinup++; 94711819Sjulian cb->s_flags |= SF_ACKNOW; 94811819Sjulian goto send; 94911819Sjulian } 95011819Sjulian 95111819Sjulian } 95211819Sjulian /* 95311819Sjulian * Many comments from tcp_output.c are appropriate here 95411819Sjulian * including . . . 95511819Sjulian * If send window is too small, there is data to transmit, and no 95611819Sjulian * retransmit or persist is pending, then go to persist state. 95711819Sjulian * If nothing happens soon, send when timer expires: 95811819Sjulian * if window is nonzero, transmit what we can, 95911819Sjulian * otherwise send a probe. 96011819Sjulian */ 96111819Sjulian if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 && 96211819Sjulian cb->s_timer[SPXT_PERSIST] == 0) { 96311819Sjulian cb->s_rxtshift = 0; 96411819Sjulian spx_setpersist(cb); 96511819Sjulian } 96611819Sjulian /* 96711819Sjulian * No reason to send a packet, just return. 96811819Sjulian */ 96911819Sjulian cb->s_outx = 1; 97011819Sjulian return (0); 97111819Sjulian 97211819Sjuliansend: 97311819Sjulian /* 97411819Sjulian * Find requested packet. 97511819Sjulian */ 97611819Sjulian si = 0; 97711819Sjulian if (len > 0) { 97811819Sjulian cb->s_want = cb->s_snxt; 97925652Sjhay for (m = sb->sb_mb; m != NULL; m = m->m_act) { 98011819Sjulian si = mtod(m, struct spx *); 98111819Sjulian if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) 98211819Sjulian break; 98311819Sjulian } 98411819Sjulian found: 98525652Sjhay if (si != NULL) { 98611819Sjulian if (si->si_seq == cb->s_snxt) 98711819Sjulian cb->s_snxt++; 98811819Sjulian else 98911819Sjulian spxstat.spxs_sndvoid++, si = 0; 99011819Sjulian } 99111819Sjulian } 99211819Sjulian /* 99311819Sjulian * update window 99411819Sjulian */ 99511819Sjulian if (rcv_win < 0) 99611819Sjulian rcv_win = 0; 99711819Sjulian alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); 99811819Sjulian if (SSEQ_LT(alo, cb->s_alo)) 99911819Sjulian alo = cb->s_alo; 100011819Sjulian 100125652Sjhay if (si != NULL) { 100211819Sjulian /* 100311819Sjulian * must make a copy of this packet for 100411819Sjulian * ipx_output to monkey with 100511819Sjulian */ 100611819Sjulian m = m_copy(dtom(si), 0, (int)M_COPYALL); 100711819Sjulian if (m == NULL) { 100811819Sjulian return (ENOBUFS); 100911819Sjulian } 101011819Sjulian si = mtod(m, struct spx *); 101111819Sjulian if (SSEQ_LT(si->si_seq, cb->s_smax)) 101211819Sjulian spxstat.spxs_sndrexmitpack++; 101311819Sjulian else 101411819Sjulian spxstat.spxs_sndpack++; 101511819Sjulian } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { 101611819Sjulian /* 101711819Sjulian * Must send an acknowledgement or a probe 101811819Sjulian */ 101911819Sjulian if (cb->s_force) 102011819Sjulian spxstat.spxs_sndprobe++; 102111819Sjulian if (cb->s_flags & SF_ACKNOW) 102211819Sjulian spxstat.spxs_sndacks++; 102311819Sjulian m = m_gethdr(M_DONTWAIT, MT_HEADER); 102425652Sjhay if (m == NULL) 102511819Sjulian return (ENOBUFS); 102611819Sjulian /* 102711819Sjulian * Fill in mbuf with extended SP header 102811819Sjulian * and addresses and length put into network format. 102911819Sjulian */ 103025652Sjhay MH_ALIGN(m, sizeof(struct spx)); 103125652Sjhay m->m_len = sizeof(*si); 103225652Sjhay m->m_pkthdr.len = sizeof(*si); 103311819Sjulian si = mtod(m, struct spx *); 103411819Sjulian si->si_i = *cb->s_ipx; 103511819Sjulian si->si_s = cb->s_shdr; 103611819Sjulian si->si_seq = cb->s_smax + 1; 103725652Sjhay si->si_len = htons(sizeof(*si)); 103811819Sjulian si->si_cc |= SPX_SP; 103911819Sjulian } else { 104011819Sjulian cb->s_outx = 3; 104111819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) 104211819Sjulian spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 104311819Sjulian return (0); 104411819Sjulian } 104511819Sjulian /* 104611819Sjulian * Stuff checksum and output datagram. 104711819Sjulian */ 104811819Sjulian if ((si->si_cc & SPX_SP) == 0) { 104911819Sjulian if (cb->s_force != (1 + SPXT_PERSIST) || 105011819Sjulian cb->s_timer[SPXT_PERSIST] == 0) { 105111819Sjulian /* 105211819Sjulian * If this is a new packet and we are not currently 105311819Sjulian * timing anything, time this one. 105411819Sjulian */ 105511819Sjulian if (SSEQ_LT(cb->s_smax, si->si_seq)) { 105611819Sjulian cb->s_smax = si->si_seq; 105711819Sjulian if (cb->s_rtt == 0) { 105811819Sjulian spxstat.spxs_segstimed++; 105911819Sjulian cb->s_rtseq = si->si_seq; 106011819Sjulian cb->s_rtt = 1; 106111819Sjulian } 106211819Sjulian } 106311819Sjulian /* 106411819Sjulian * Set rexmt timer if not currently set, 106511819Sjulian * Initial value for retransmit timer is smoothed 106611819Sjulian * round-trip time + 2 * round-trip time variance. 106711819Sjulian * Initialize shift counter which is used for backoff 106811819Sjulian * of retransmit time. 106911819Sjulian */ 107011819Sjulian if (cb->s_timer[SPXT_REXMT] == 0 && 107111819Sjulian cb->s_snxt != cb->s_rack) { 107211819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 107311819Sjulian if (cb->s_timer[SPXT_PERSIST]) { 107411819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 107511819Sjulian cb->s_rxtshift = 0; 107611819Sjulian } 107711819Sjulian } 107811819Sjulian } else if (SSEQ_LT(cb->s_smax, si->si_seq)) { 107911819Sjulian cb->s_smax = si->si_seq; 108011819Sjulian } 108111819Sjulian } else if (cb->s_state < TCPS_ESTABLISHED) { 108211819Sjulian if (cb->s_rtt == 0) 108311819Sjulian cb->s_rtt = 1; /* Time initial handshake */ 108411819Sjulian if (cb->s_timer[SPXT_REXMT] == 0) 108511819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 108611819Sjulian } 108711819Sjulian { 108811819Sjulian /* 108911819Sjulian * Do not request acks when we ack their data packets or 109011819Sjulian * when we do a gratuitous window update. 109111819Sjulian */ 109211819Sjulian if (((si->si_cc & SPX_SP) == 0) || cb->s_force) 109311819Sjulian si->si_cc |= SPX_SA; 109411819Sjulian si->si_seq = htons(si->si_seq); 109511819Sjulian si->si_alo = htons(alo); 109611819Sjulian si->si_ack = htons(cb->s_ack); 109711819Sjulian 109811819Sjulian if (ipxcksum) { 109911819Sjulian si->si_sum = 0; 110011819Sjulian len = ntohs(si->si_len); 110111819Sjulian if (len & 1) 110211819Sjulian len++; 110311819Sjulian si->si_sum = ipx_cksum(m, len); 110411819Sjulian } else 110511819Sjulian si->si_sum = 0xffff; 110611819Sjulian 110711819Sjulian cb->s_outx = 4; 110811819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) 110911819Sjulian spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 111011819Sjulian 111111819Sjulian if (so->so_options & SO_DONTROUTE) 111225652Sjhay error = ipx_outputfl(m, (struct route *)NULL, IPX_ROUTETOIF); 111311819Sjulian else 111411819Sjulian error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0); 111511819Sjulian } 111611819Sjulian if (error) { 111711819Sjulian return (error); 111811819Sjulian } 111911819Sjulian spxstat.spxs_sndtotal++; 112011819Sjulian /* 112111819Sjulian * Data sent (as far as we can tell). 112211819Sjulian * If this advertises a larger window than any other segment, 112311819Sjulian * then remember the size of the advertized window. 112411819Sjulian * Any pending ACK has now been sent. 112511819Sjulian */ 112611819Sjulian cb->s_force = 0; 112711819Sjulian cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); 112811819Sjulian if (SSEQ_GT(alo, cb->s_alo)) 112911819Sjulian cb->s_alo = alo; 113011819Sjulian if (sendalot) 113111819Sjulian goto again; 113211819Sjulian cb->s_outx = 5; 113311819Sjulian return (0); 113411819Sjulian} 113511819Sjulian 113611819Sjulianint spx_do_persist_panics = 0; 113711819Sjulian 113825652Sjhaystatic void 113911819Sjulianspx_setpersist(cb) 114011819Sjulian register struct spxpcb *cb; 114111819Sjulian{ 114211819Sjulian register t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 114311819Sjulian 114411819Sjulian if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics) 114511819Sjulian panic("spx_output REXMT"); 114611819Sjulian /* 114711819Sjulian * Start/restart persistance timer. 114811819Sjulian */ 114911819Sjulian SPXT_RANGESET(cb->s_timer[SPXT_PERSIST], 115011819Sjulian t*spx_backoff[cb->s_rxtshift], 115111819Sjulian SPXTV_PERSMIN, SPXTV_PERSMAX); 115211819Sjulian if (cb->s_rxtshift < SPX_MAXRXTSHIFT) 115311819Sjulian cb->s_rxtshift++; 115411819Sjulian} 115525652Sjhay 115611819Sjulianint 115725345Sjhayspx_ctloutput(req, so, level, name, value, p) 115811819Sjulian int req; 115911819Sjulian struct socket *so; 116011819Sjulian int level, name; 116111819Sjulian struct mbuf **value; 116225345Sjhay struct proc *p; 116311819Sjulian{ 116411819Sjulian register struct mbuf *m; 116511819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 116611819Sjulian register struct spxpcb *cb; 116711819Sjulian int mask, error = 0; 116811819Sjulian 116911819Sjulian if (level != IPXPROTO_SPX) { 117011819Sjulian /* This will have to be changed when we do more general 117111819Sjulian stacking of protocols */ 117225345Sjhay return (ipx_ctloutput(req, so, level, name, value, p)); 117311819Sjulian } 117411819Sjulian if (ipxp == NULL) { 117511819Sjulian error = EINVAL; 117611819Sjulian goto release; 117711819Sjulian } else 117811819Sjulian cb = ipxtospxpcb(ipxp); 117911819Sjulian 118011819Sjulian switch (req) { 118111819Sjulian 118211819Sjulian case PRCO_GETOPT: 118311819Sjulian if (value == NULL) 118411819Sjulian return (EINVAL); 118511819Sjulian m = m_get(M_DONTWAIT, MT_DATA); 118611819Sjulian if (m == NULL) 118711819Sjulian return (ENOBUFS); 118811819Sjulian switch (name) { 118911819Sjulian 119011819Sjulian case SO_HEADERS_ON_INPUT: 119111819Sjulian mask = SF_HI; 119211819Sjulian goto get_flags; 119311819Sjulian 119411819Sjulian case SO_HEADERS_ON_OUTPUT: 119511819Sjulian mask = SF_HO; 119611819Sjulian get_flags: 119711819Sjulian m->m_len = sizeof(short); 119811819Sjulian *mtod(m, short *) = cb->s_flags & mask; 119911819Sjulian break; 120011819Sjulian 120111819Sjulian case SO_MTU: 120211819Sjulian m->m_len = sizeof(u_short); 120311819Sjulian *mtod(m, short *) = cb->s_mtu; 120411819Sjulian break; 120511819Sjulian 120611819Sjulian case SO_LAST_HEADER: 120711819Sjulian m->m_len = sizeof(struct spxhdr); 120811819Sjulian *mtod(m, struct spxhdr *) = cb->s_rhdr; 120911819Sjulian break; 121011819Sjulian 121111819Sjulian case SO_DEFAULT_HEADERS: 121211819Sjulian m->m_len = sizeof(struct spx); 121311819Sjulian *mtod(m, struct spxhdr *) = cb->s_shdr; 121411819Sjulian break; 121511819Sjulian 121611819Sjulian default: 121711819Sjulian error = EINVAL; 121811819Sjulian } 121911819Sjulian *value = m; 122011819Sjulian break; 122111819Sjulian 122211819Sjulian case PRCO_SETOPT: 122311819Sjulian if (value == 0 || *value == 0) { 122411819Sjulian error = EINVAL; 122511819Sjulian break; 122611819Sjulian } 122711819Sjulian switch (name) { 122811819Sjulian int *ok; 122911819Sjulian 123011819Sjulian case SO_HEADERS_ON_INPUT: 123111819Sjulian mask = SF_HI; 123211819Sjulian goto set_head; 123311819Sjulian 123411819Sjulian case SO_HEADERS_ON_OUTPUT: 123511819Sjulian mask = SF_HO; 123611819Sjulian set_head: 123711819Sjulian if (cb->s_flags & SF_PI) { 123811819Sjulian ok = mtod(*value, int *); 123911819Sjulian if (*ok) 124011819Sjulian cb->s_flags |= mask; 124111819Sjulian else 124211819Sjulian cb->s_flags &= ~mask; 124311819Sjulian } else error = EINVAL; 124411819Sjulian break; 124511819Sjulian 124611819Sjulian case SO_MTU: 124711819Sjulian cb->s_mtu = *(mtod(*value, u_short *)); 124811819Sjulian break; 124911819Sjulian 125011819Sjulian#ifdef SF_NEWCALL 125111819Sjulian case SO_NEWCALL: 125211819Sjulian ok = mtod(*value, int *); 125311819Sjulian if (*ok) { 125411819Sjulian cb->s_flags2 |= SF_NEWCALL; 125511819Sjulian spx_newchecks[5]++; 125611819Sjulian } else { 125711819Sjulian cb->s_flags2 &= ~SF_NEWCALL; 125811819Sjulian spx_newchecks[6]++; 125911819Sjulian } 126011819Sjulian break; 126111819Sjulian#endif 126211819Sjulian 126311819Sjulian case SO_DEFAULT_HEADERS: 126411819Sjulian { 126511819Sjulian register struct spxhdr *sp 126611819Sjulian = mtod(*value, struct spxhdr *); 126711819Sjulian cb->s_dt = sp->spx_dt; 126811819Sjulian cb->s_cc = sp->spx_cc & SPX_EM; 126911819Sjulian } 127011819Sjulian break; 127111819Sjulian 127211819Sjulian default: 127311819Sjulian error = EINVAL; 127411819Sjulian } 127511819Sjulian m_freem(*value); 127611819Sjulian break; 127711819Sjulian } 127811819Sjulian release: 127911819Sjulian return (error); 128011819Sjulian} 128111819Sjulian 128224659Sjhaystatic int 128324659Sjhayspx_usr_abort(so) 128411819Sjulian struct socket *so; 128511819Sjulian{ 128624659Sjhay int s; 128724659Sjhay struct ipxpcb *ipxp; 128824659Sjhay struct spxpcb *cb; 128911819Sjulian 129024659Sjhay ipxp = sotoipxpcb(so); 129124659Sjhay cb = ipxtospxpcb(ipxp); 129211819Sjulian 129324659Sjhay s = splnet(); 129424659Sjhay spx_drop(cb, ECONNABORTED); 129524659Sjhay splx(s); 129624659Sjhay return (0); 129724659Sjhay} 129811819Sjulian 129924659Sjhay/* 130024659Sjhay * Accept a connection. Essentially all the work is 130124659Sjhay * done at higher levels; just return the address 130224659Sjhay * of the peer, storing through addr. 130324659Sjhay */ 130424659Sjhaystatic int 130524659Sjhayspx_accept(so, nam) 130624659Sjhay struct socket *so; 130728270Swollman struct sockaddr **nam; 130824659Sjhay{ 130924659Sjhay struct ipxpcb *ipxp; 131028270Swollman struct sockaddr_ipx *sipx, ssipx; 131111819Sjulian 131224659Sjhay ipxp = sotoipxpcb(so); 131328270Swollman sipx = &ssipx; 131428270Swollman bzero(sipx, sizeof *sipx); 131528270Swollman sipx->sipx_len = sizeof *sipx; 131624659Sjhay sipx->sipx_family = AF_IPX; 131724659Sjhay sipx->sipx_addr = ipxp->ipxp_faddr; 131828270Swollman *nam = dup_sockaddr((struct sockaddr *)sipx, 0); 131924659Sjhay return (0); 132024659Sjhay} 132124659Sjhay 132224659Sjhaystatic int 132325345Sjhayspx_attach(so, proto, p) 132424659Sjhay struct socket *so; 132524659Sjhay int proto; 132625345Sjhay struct proc *p; 132724659Sjhay{ 132824659Sjhay int error; 132924659Sjhay int s; 133024659Sjhay struct ipxpcb *ipxp; 133124659Sjhay struct spxpcb *cb; 133224659Sjhay struct mbuf *mm; 133324659Sjhay struct sockbuf *sb; 133424659Sjhay 133524659Sjhay ipxp = sotoipxpcb(so); 133624659Sjhay cb = ipxtospxpcb(ipxp); 133724659Sjhay 133824659Sjhay if (ipxp != NULL) 133924659Sjhay return (EISCONN); 134024659Sjhay s = splnet(); 134125345Sjhay error = ipx_pcballoc(so, &ipxpcb, p); 134224659Sjhay if (error) 134324659Sjhay goto spx_attach_end; 134424659Sjhay if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 134524659Sjhay error = soreserve(so, (u_long) 3072, (u_long) 3072); 134611819Sjulian if (error) 134724659Sjhay goto spx_attach_end; 134824659Sjhay } 134924659Sjhay ipxp = sotoipxpcb(so); 135011819Sjulian 135128270Swollman MALLOC(cb, struct spxpcb *, sizeof *cb, M_PCB, M_NOWAIT); 135228270Swollman bzero(cb, sizeof *cb); 135324659Sjhay sb = &so->so_snd; 135411819Sjulian 135528270Swollman if (cb == NULL) { 135624659Sjhay error = ENOBUFS; 135724659Sjhay goto spx_attach_end; 135824659Sjhay } 135928270Swollman 136024659Sjhay mm = m_getclr(M_DONTWAIT, MT_HEADER); 136124659Sjhay if (mm == NULL) { 136228270Swollman FREE(cb, M_PCB); 136324659Sjhay error = ENOBUFS; 136424659Sjhay goto spx_attach_end; 136524659Sjhay } 136624659Sjhay cb->s_ipx = mtod(mm, struct ipx *); 136724659Sjhay cb->s_state = TCPS_LISTEN; 136824659Sjhay cb->s_smax = -1; 136924659Sjhay cb->s_swl1 = -1; 137024659Sjhay cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 137124659Sjhay cb->s_ipxpcb = ipxp; 137225652Sjhay cb->s_mtu = 576 - sizeof(struct spx); 137324659Sjhay cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; 137424659Sjhay cb->s_ssthresh = cb->s_cwnd; 137525652Sjhay cb->s_cwmx = sbspace(sb) * CUNIT / (2 * sizeof(struct spx)); 137624659Sjhay /* Above is recomputed when connecting to account 137724659Sjhay for changed buffering or mtu's */ 137824659Sjhay cb->s_rtt = SPXTV_SRTTBASE; 137924659Sjhay cb->s_rttvar = SPXTV_SRTTDFLT << 2; 138024659Sjhay SPXT_RANGESET(cb->s_rxtcur, 138124659Sjhay ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1, 138224659Sjhay SPXTV_MIN, SPXTV_REXMTMAX); 138325652Sjhay ipxp->ipxp_pcb = (caddr_t)cb; 138424659Sjhayspx_attach_end: 138524659Sjhay splx(s); 138624659Sjhay return (error); 138724659Sjhay} 138811819Sjulian 138924659Sjhaystatic int 139025345Sjhayspx_bind(so, nam, p) 139124659Sjhay struct socket *so; 139228270Swollman struct sockaddr *nam; 139325345Sjhay struct proc *p; 139424659Sjhay{ 139524659Sjhay struct ipxpcb *ipxp; 139611819Sjulian 139724659Sjhay ipxp = sotoipxpcb(so); 139811819Sjulian 139925345Sjhay return (ipx_pcbbind(ipxp, nam, p)); 140024659Sjhay} 140124659Sjhay 140224659Sjhay/* 140324659Sjhay * Initiate connection to peer. 140424659Sjhay * Enter SYN_SENT state, and mark socket as connecting. 140524659Sjhay * Start keep-alive timer, setup prototype header, 140624659Sjhay * Send initial system packet requesting connection. 140724659Sjhay */ 140824659Sjhaystatic int 140925345Sjhayspx_connect(so, nam, p) 141024659Sjhay struct socket *so; 141128270Swollman struct sockaddr *nam; 141225345Sjhay struct proc *p; 141324659Sjhay{ 141424659Sjhay int error; 141524659Sjhay int s; 141624659Sjhay struct ipxpcb *ipxp; 141724659Sjhay struct spxpcb *cb; 141811819Sjulian 141924659Sjhay ipxp = sotoipxpcb(so); 142024659Sjhay cb = ipxtospxpcb(ipxp); 142124659Sjhay 142224659Sjhay s = splnet(); 142324659Sjhay if (ipxp->ipxp_lport == 0) { 142428270Swollman error = ipx_pcbbind(ipxp, (struct sockaddr *)NULL, p); 142524659Sjhay if (error) 142624659Sjhay goto spx_connect_end; 142724659Sjhay } 142825345Sjhay error = ipx_pcbconnect(ipxp, nam, p); 142924659Sjhay if (error) 143024659Sjhay goto spx_connect_end; 143124659Sjhay soisconnecting(so); 143224659Sjhay spxstat.spxs_connattempt++; 143324659Sjhay cb->s_state = TCPS_SYN_SENT; 143424659Sjhay cb->s_did = 0; 143524659Sjhay spx_template(cb); 143624659Sjhay cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 143724659Sjhay cb->s_force = 1 + SPXTV_KEEP; 143811819Sjulian /* 143924659Sjhay * Other party is required to respond to 144024659Sjhay * the port I send from, but he is not 144124659Sjhay * required to answer from where I am sending to, 144224659Sjhay * so allow wildcarding. 144324659Sjhay * original port I am sending to is still saved in 144424659Sjhay * cb->s_dport. 144511819Sjulian */ 144624659Sjhay ipxp->ipxp_fport = 0; 144725652Sjhay error = spx_output(cb, (struct mbuf *)NULL); 144824659Sjhayspx_connect_end: 144924659Sjhay splx(s); 145024659Sjhay return (error); 145124659Sjhay} 145211819Sjulian 145324659Sjhaystatic int 145424659Sjhayspx_detach(so) 145524659Sjhay struct socket *so; 145624659Sjhay{ 145724659Sjhay int s; 145824659Sjhay struct ipxpcb *ipxp; 145924659Sjhay struct spxpcb *cb; 146011819Sjulian 146124659Sjhay ipxp = sotoipxpcb(so); 146224659Sjhay cb = ipxtospxpcb(ipxp); 146311819Sjulian 146424659Sjhay if (ipxp == NULL) 146524659Sjhay return (ENOTCONN); 146624659Sjhay s = splnet(); 146724659Sjhay if (cb->s_state > TCPS_LISTEN) 146824659Sjhay spx_disconnect(cb); 146924659Sjhay else 147024659Sjhay spx_close(cb); 147124659Sjhay splx(s); 147224659Sjhay return (0); 147324659Sjhay} 147411819Sjulian 147524659Sjhay/* 147624659Sjhay * We may decide later to implement connection closing 147724659Sjhay * handshaking at the spx level optionally. 147824659Sjhay * here is the hook to do it: 147924659Sjhay */ 148024659Sjhaystatic int 148124659Sjhayspx_usr_disconnect(so) 148224659Sjhay struct socket *so; 148324659Sjhay{ 148424659Sjhay int s; 148524659Sjhay struct ipxpcb *ipxp; 148624659Sjhay struct spxpcb *cb; 148711819Sjulian 148824659Sjhay ipxp = sotoipxpcb(so); 148924659Sjhay cb = ipxtospxpcb(ipxp); 149011819Sjulian 149124659Sjhay s = splnet(); 149224659Sjhay spx_disconnect(cb); 149324659Sjhay splx(s); 149424659Sjhay return (0); 149524659Sjhay} 149611819Sjulian 149724659Sjhaystatic int 149825345Sjhayspx_listen(so, p) 149924659Sjhay struct socket *so; 150025345Sjhay struct proc *p; 150124659Sjhay{ 150224659Sjhay int error; 150324659Sjhay struct ipxpcb *ipxp; 150424659Sjhay struct spxpcb *cb; 150511819Sjulian 150624659Sjhay error = 0; 150724659Sjhay ipxp = sotoipxpcb(so); 150824659Sjhay cb = ipxtospxpcb(ipxp); 150911819Sjulian 151024659Sjhay if (ipxp->ipxp_lport == 0) 151128270Swollman error = ipx_pcbbind(ipxp, (struct sockaddr *)NULL, p); 151224659Sjhay if (error == 0) 151324659Sjhay cb->s_state = TCPS_LISTEN; 151424659Sjhay return (error); 151524659Sjhay} 151611819Sjulian 151724659Sjhay/* 151824659Sjhay * After a receive, possibly send acknowledgment 151924659Sjhay * updating allocation. 152024659Sjhay */ 152124659Sjhaystatic int 152224659Sjhayspx_rcvd(so, flags) 152324659Sjhay struct socket *so; 152424659Sjhay int flags; 152524659Sjhay{ 152624659Sjhay int s; 152724659Sjhay struct ipxpcb *ipxp; 152824659Sjhay struct spxpcb *cb; 152911819Sjulian 153024659Sjhay ipxp = sotoipxpcb(so); 153124659Sjhay cb = ipxtospxpcb(ipxp); 153211819Sjulian 153324659Sjhay s = splnet(); 153424659Sjhay cb->s_flags |= SF_RVD; 153525652Sjhay spx_output(cb, (struct mbuf *)NULL); 153624659Sjhay cb->s_flags &= ~SF_RVD; 153724659Sjhay splx(s); 153824659Sjhay return (0); 153924659Sjhay} 154011819Sjulian 154124659Sjhaystatic int 154224659Sjhayspx_rcvoob(so, m, flags) 154324659Sjhay struct socket *so; 154424659Sjhay struct mbuf *m; 154524659Sjhay int flags; 154624659Sjhay{ 154724659Sjhay struct ipxpcb *ipxp; 154824659Sjhay struct spxpcb *cb; 154911819Sjulian 155024659Sjhay ipxp = sotoipxpcb(so); 155124659Sjhay cb = ipxtospxpcb(ipxp); 155211819Sjulian 155324659Sjhay if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 155424659Sjhay (so->so_state & SS_RCVATMARK)) { 155524659Sjhay m->m_len = 1; 155624659Sjhay *mtod(m, caddr_t) = cb->s_iobc; 155724659Sjhay return (0); 155811819Sjulian } 155924659Sjhay return (EINVAL); 156024659Sjhay} 156124659Sjhay 156224659Sjhaystatic int 156325345Sjhayspx_send(so, flags, m, addr, controlp, p) 156424659Sjhay struct socket *so; 156524659Sjhay int flags; 156624659Sjhay struct mbuf *m; 156728270Swollman struct sockaddr *addr; 156824659Sjhay struct mbuf *controlp; 156925345Sjhay struct proc *p; 157024659Sjhay{ 157124659Sjhay int error; 157224659Sjhay int s; 157324659Sjhay struct ipxpcb *ipxp; 157424659Sjhay struct spxpcb *cb; 157524659Sjhay 157624659Sjhay error = 0; 157724659Sjhay ipxp = sotoipxpcb(so); 157824659Sjhay cb = ipxtospxpcb(ipxp); 157924659Sjhay 158024659Sjhay s = splnet(); 158124659Sjhay if (flags & PRUS_OOB) { 158224659Sjhay if (sbspace(&so->so_snd) < -512) { 158324659Sjhay error = ENOBUFS; 158424659Sjhay goto spx_send_end; 158524659Sjhay } 158624659Sjhay cb->s_oobflags |= SF_SOOB; 158724659Sjhay } 158825652Sjhay if (controlp != NULL) { 158924659Sjhay u_short *p = mtod(controlp, u_short *); 159024659Sjhay spx_newchecks[2]++; 159125652Sjhay if ((p[0] == 5) && (p[1] == 1)) { /* XXXX, for testing */ 159224659Sjhay cb->s_shdr.spx_dt = *(u_char *)(&p[2]); 159324659Sjhay spx_newchecks[3]++; 159424659Sjhay } 159524659Sjhay m_freem(controlp); 159624659Sjhay } 159724659Sjhay controlp = NULL; 159824659Sjhay error = spx_output(cb, m); 159924659Sjhay m = NULL; 160024659Sjhayspx_send_end: 160111819Sjulian if (controlp != NULL) 160211819Sjulian m_freem(controlp); 160311819Sjulian if (m != NULL) 160411819Sjulian m_freem(m); 160511819Sjulian splx(s); 160611819Sjulian return (error); 160711819Sjulian} 160811819Sjulian 160924659Sjhaystatic int 161024659Sjhayspx_shutdown(so) 161124659Sjhay struct socket *so; 161224659Sjhay{ 161324659Sjhay int error; 161424659Sjhay int s; 161524659Sjhay struct ipxpcb *ipxp; 161624659Sjhay struct spxpcb *cb; 161724659Sjhay 161824659Sjhay error = 0; 161924659Sjhay ipxp = sotoipxpcb(so); 162024659Sjhay cb = ipxtospxpcb(ipxp); 162124659Sjhay 162224659Sjhay s = splnet(); 162324659Sjhay socantsendmore(so); 162424659Sjhay cb = spx_usrclosed(cb); 162525652Sjhay if (cb != NULL) 162625652Sjhay error = spx_output(cb, (struct mbuf *)NULL); 162724659Sjhay splx(s); 162824659Sjhay return (error); 162924659Sjhay} 163024659Sjhay 163124659Sjhaystatic int 163225345Sjhayspx_sp_attach(so, proto, p) 163311819Sjulian struct socket *so; 163424659Sjhay int proto; 163525345Sjhay struct proc *p; 163611819Sjulian{ 163724659Sjhay int error; 163824659Sjhay struct ipxpcb *ipxp; 163911819Sjulian 164025345Sjhay error = spx_attach(so, proto, p); 164124659Sjhay if (error == 0) { 164224659Sjhay ipxp = sotoipxpcb(so); 164311819Sjulian ((struct spxpcb *)ipxp->ipxp_pcb)->s_flags |= 164411819Sjulian (SF_HI | SF_HO | SF_PI); 164511819Sjulian } 164611819Sjulian return (error); 164711819Sjulian} 164811819Sjulian 164911819Sjulian/* 165011819Sjulian * Create template to be used to send spx packets on a connection. 165111819Sjulian * Called after host entry created, fills 165211819Sjulian * in a skeletal spx header (choosing connection id), 165311819Sjulian * minimizing the amount of work necessary when the connection is used. 165411819Sjulian */ 165525652Sjhaystatic void 165611819Sjulianspx_template(cb) 165711819Sjulian register struct spxpcb *cb; 165811819Sjulian{ 165911819Sjulian register struct ipxpcb *ipxp = cb->s_ipxpcb; 166011819Sjulian register struct ipx *ipx = cb->s_ipx; 166111819Sjulian register struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd); 166211819Sjulian 166311819Sjulian ipx->ipx_pt = IPXPROTO_SPX; 166411819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 166511819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 166611819Sjulian cb->s_sid = htons(spx_iss); 166711819Sjulian spx_iss += SPX_ISSINCR/2; 166811819Sjulian cb->s_alo = 1; 166911819Sjulian cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; 167011819Sjulian cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement 167111819Sjulian of large packets */ 167211819Sjulian cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx)); 167311819Sjulian cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); 167411819Sjulian /* But allow for lots of little packets as well */ 167511819Sjulian} 167611819Sjulian 167711819Sjulian/* 167811819Sjulian * Close a SPIP control block: 167911819Sjulian * discard spx control block itself 168011819Sjulian * discard ipx protocol control block 168111819Sjulian * wake up any sleepers 168211819Sjulian */ 168325652Sjhaystatic struct spxpcb * 168411819Sjulianspx_close(cb) 168511819Sjulian register struct spxpcb *cb; 168611819Sjulian{ 168711819Sjulian register struct spx_q *s; 168811819Sjulian struct ipxpcb *ipxp = cb->s_ipxpcb; 168911819Sjulian struct socket *so = ipxp->ipxp_socket; 169011819Sjulian register struct mbuf *m; 169111819Sjulian 169211819Sjulian s = cb->s_q.si_next; 169311819Sjulian while (s != &(cb->s_q)) { 169411819Sjulian s = s->si_next; 169511819Sjulian m = dtom(s->si_prev); 169611819Sjulian remque(s->si_prev); 169711819Sjulian m_freem(m); 169811819Sjulian } 169925652Sjhay m_free(dtom(cb->s_ipx)); 170028270Swollman FREE(cb, M_PCB); 170111819Sjulian ipxp->ipxp_pcb = 0; 170211819Sjulian soisdisconnected(so); 170311819Sjulian ipx_pcbdetach(ipxp); 170411819Sjulian spxstat.spxs_closed++; 170525652Sjhay return ((struct spxpcb *)NULL); 170611819Sjulian} 170725652Sjhay 170811819Sjulian/* 170911819Sjulian * Someday we may do level 3 handshaking 171011819Sjulian * to close a connection or send a xerox style error. 171111819Sjulian * For now, just close. 171211819Sjulian */ 171325652Sjhaystatic struct spxpcb * 171411819Sjulianspx_usrclosed(cb) 171511819Sjulian register struct spxpcb *cb; 171611819Sjulian{ 171711819Sjulian return (spx_close(cb)); 171811819Sjulian} 171925652Sjhay 172025652Sjhaystatic struct spxpcb * 172111819Sjulianspx_disconnect(cb) 172211819Sjulian register struct spxpcb *cb; 172311819Sjulian{ 172411819Sjulian return (spx_close(cb)); 172511819Sjulian} 172625652Sjhay 172711819Sjulian/* 172811819Sjulian * Drop connection, reporting 172911819Sjulian * the specified error. 173011819Sjulian */ 173125652Sjhaystatic struct spxpcb * 173211819Sjulianspx_drop(cb, errno) 173311819Sjulian register struct spxpcb *cb; 173411819Sjulian int errno; 173511819Sjulian{ 173611819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 173711819Sjulian 173811819Sjulian /* 173911819Sjulian * someday, in the xerox world 174011819Sjulian * we will generate error protocol packets 174111819Sjulian * announcing that the socket has gone away. 174211819Sjulian */ 174311819Sjulian if (TCPS_HAVERCVDSYN(cb->s_state)) { 174411819Sjulian spxstat.spxs_drops++; 174511819Sjulian cb->s_state = TCPS_CLOSED; 174625652Sjhay /*tcp_output(cb);*/ 174711819Sjulian } else 174811819Sjulian spxstat.spxs_conndrops++; 174911819Sjulian so->so_error = errno; 175011819Sjulian return (spx_close(cb)); 175111819Sjulian} 175211819Sjulian 175325652Sjhaystatic void 175411819Sjulianspx_abort(ipxp) 175511819Sjulian struct ipxpcb *ipxp; 175611819Sjulian{ 175711819Sjulian 175825652Sjhay spx_close((struct spxpcb *)ipxp->ipxp_pcb); 175911819Sjulian} 176011819Sjulian 176111819Sjulian/* 176211819Sjulian * Fast timeout routine for processing delayed acks 176311819Sjulian */ 176411819Sjulianvoid 176511819Sjulianspx_fasttimo() 176611819Sjulian{ 176711819Sjulian register struct ipxpcb *ipxp; 176811819Sjulian register struct spxpcb *cb; 176911819Sjulian int s = splnet(); 177011819Sjulian 177111819Sjulian ipxp = ipxpcb.ipxp_next; 177225652Sjhay if (ipxp != NULL) 177311819Sjulian for (; ipxp != &ipxpcb; ipxp = ipxp->ipxp_next) 177425652Sjhay if ((cb = (struct spxpcb *)ipxp->ipxp_pcb) != NULL && 177511819Sjulian (cb->s_flags & SF_DELACK)) { 177611819Sjulian cb->s_flags &= ~SF_DELACK; 177711819Sjulian cb->s_flags |= SF_ACKNOW; 177811819Sjulian spxstat.spxs_delack++; 177925652Sjhay spx_output(cb, (struct mbuf *)NULL); 178011819Sjulian } 178111819Sjulian splx(s); 178211819Sjulian} 178311819Sjulian 178411819Sjulian/* 178511819Sjulian * spx protocol timeout routine called every 500 ms. 178611819Sjulian * Updates the timers in all active pcb's and 178711819Sjulian * causes finite state machine actions if timers expire. 178811819Sjulian */ 178911819Sjulianvoid 179011819Sjulianspx_slowtimo() 179111819Sjulian{ 179211819Sjulian register struct ipxpcb *ip, *ipnxt; 179311819Sjulian register struct spxpcb *cb; 179411819Sjulian int s = splnet(); 179511819Sjulian register int i; 179611819Sjulian 179711819Sjulian /* 179811819Sjulian * Search through tcb's and update active timers. 179911819Sjulian */ 180011819Sjulian ip = ipxpcb.ipxp_next; 180125652Sjhay if (ip == NULL) { 180211819Sjulian splx(s); 180311819Sjulian return; 180411819Sjulian } 180511819Sjulian while (ip != &ipxpcb) { 180611819Sjulian cb = ipxtospxpcb(ip); 180711819Sjulian ipnxt = ip->ipxp_next; 180825652Sjhay if (cb == NULL) 180911819Sjulian goto tpgone; 181011819Sjulian for (i = 0; i < SPXT_NTIMERS; i++) { 181111819Sjulian if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 181224659Sjhay spx_timers(cb, i); 181311819Sjulian if (ipnxt->ipxp_prev != ip) 181411819Sjulian goto tpgone; 181511819Sjulian } 181611819Sjulian } 181711819Sjulian cb->s_idle++; 181811819Sjulian if (cb->s_rtt) 181911819Sjulian cb->s_rtt++; 182011819Sjuliantpgone: 182111819Sjulian ip = ipnxt; 182211819Sjulian } 182311819Sjulian spx_iss += SPX_ISSINCR/PR_SLOWHZ; /* increment iss */ 182411819Sjulian splx(s); 182511819Sjulian} 182625652Sjhay 182711819Sjulian/* 182811819Sjulian * SPX timer processing. 182911819Sjulian */ 183025652Sjhaystatic struct spxpcb * 183111819Sjulianspx_timers(cb, timer) 183211819Sjulian register struct spxpcb *cb; 183311819Sjulian int timer; 183411819Sjulian{ 183511819Sjulian long rexmt; 183611819Sjulian int win; 183711819Sjulian 183811819Sjulian cb->s_force = 1 + timer; 183911819Sjulian switch (timer) { 184011819Sjulian 184111819Sjulian /* 184211819Sjulian * 2 MSL timeout in shutdown went off. TCP deletes connection 184311819Sjulian * control block. 184411819Sjulian */ 184511819Sjulian case SPXT_2MSL: 184611819Sjulian printf("spx: SPXT_2MSL went off for no reason\n"); 184711819Sjulian cb->s_timer[timer] = 0; 184811819Sjulian break; 184911819Sjulian 185011819Sjulian /* 185111819Sjulian * Retransmission timer went off. Message has not 185211819Sjulian * been acked within retransmit interval. Back off 185311819Sjulian * to a longer retransmit interval and retransmit one packet. 185411819Sjulian */ 185511819Sjulian case SPXT_REXMT: 185611819Sjulian if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) { 185711819Sjulian cb->s_rxtshift = SPX_MAXRXTSHIFT; 185811819Sjulian spxstat.spxs_timeoutdrop++; 185911819Sjulian cb = spx_drop(cb, ETIMEDOUT); 186011819Sjulian break; 186111819Sjulian } 186211819Sjulian spxstat.spxs_rexmttimeo++; 186311819Sjulian rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 186411819Sjulian rexmt *= spx_backoff[cb->s_rxtshift]; 186511819Sjulian SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX); 186611819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 186711819Sjulian /* 186811819Sjulian * If we have backed off fairly far, our srtt 186911819Sjulian * estimate is probably bogus. Clobber it 187011819Sjulian * so we'll take the next rtt measurement as our srtt; 187111819Sjulian * move the current srtt into rttvar to keep the current 187211819Sjulian * retransmit times until then. 187311819Sjulian */ 187411819Sjulian if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) { 187511819Sjulian cb->s_rttvar += (cb->s_srtt >> 2); 187611819Sjulian cb->s_srtt = 0; 187711819Sjulian } 187811819Sjulian cb->s_snxt = cb->s_rack; 187911819Sjulian /* 188011819Sjulian * If timing a packet, stop the timer. 188111819Sjulian */ 188211819Sjulian cb->s_rtt = 0; 188311819Sjulian /* 188411819Sjulian * See very long discussion in tcp_timer.c about congestion 188511819Sjulian * window and sstrhesh 188611819Sjulian */ 188711819Sjulian win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; 188811819Sjulian if (win < 2) 188911819Sjulian win = 2; 189011819Sjulian cb->s_cwnd = CUNIT; 189111819Sjulian cb->s_ssthresh = win * CUNIT; 189225652Sjhay spx_output(cb, (struct mbuf *)NULL); 189311819Sjulian break; 189411819Sjulian 189511819Sjulian /* 189611819Sjulian * Persistance timer into zero window. 189711819Sjulian * Force a probe to be sent. 189811819Sjulian */ 189911819Sjulian case SPXT_PERSIST: 190011819Sjulian spxstat.spxs_persisttimeo++; 190111819Sjulian spx_setpersist(cb); 190225652Sjhay spx_output(cb, (struct mbuf *)NULL); 190311819Sjulian break; 190411819Sjulian 190511819Sjulian /* 190611819Sjulian * Keep-alive timer went off; send something 190711819Sjulian * or drop connection if idle for too long. 190811819Sjulian */ 190911819Sjulian case SPXT_KEEP: 191011819Sjulian spxstat.spxs_keeptimeo++; 191111819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 191211819Sjulian goto dropit; 191311819Sjulian if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) { 191411819Sjulian if (cb->s_idle >= SPXTV_MAXIDLE) 191511819Sjulian goto dropit; 191611819Sjulian spxstat.spxs_keepprobe++; 191725652Sjhay spx_output(cb, (struct mbuf *)NULL); 191811819Sjulian } else 191911819Sjulian cb->s_idle = 0; 192011819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 192111819Sjulian break; 192211819Sjulian dropit: 192311819Sjulian spxstat.spxs_keepdrops++; 192411819Sjulian cb = spx_drop(cb, ETIMEDOUT); 192511819Sjulian break; 192611819Sjulian } 192711819Sjulian return (cb); 192811819Sjulian} 1929