spx_reass.c revision 130480
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 3511819Sjulian */ 3611819Sjulian 37116189Sobrien#include <sys/cdefs.h> 38116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/spx_usrreq.c 130480 2004-06-14 18:16:22Z rwatson $"); 39116189Sobrien 4011819Sjulian#include <sys/param.h> 4176166Smarkm#include <sys/lock.h> 4229024Sbde#include <sys/malloc.h> 4311819Sjulian#include <sys/mbuf.h> 4476166Smarkm#include <sys/mutex.h> 4525345Sjhay#include <sys/proc.h> 4611819Sjulian#include <sys/protosw.h> 4795759Stanimura#include <sys/signalvar.h> 4811819Sjulian#include <sys/socket.h> 4911819Sjulian#include <sys/socketvar.h> 5095759Stanimura#include <sys/sx.h> 5195759Stanimura#include <sys/systm.h> 5211819Sjulian 5311819Sjulian#include <net/route.h> 5411819Sjulian#include <netinet/tcp_fsm.h> 5511819Sjulian 5611819Sjulian#include <netipx/ipx.h> 5711819Sjulian#include <netipx/ipx_pcb.h> 5811819Sjulian#include <netipx/ipx_var.h> 5911819Sjulian#include <netipx/spx.h> 6095759Stanimura#include <netipx/spx_debug.h> 6111819Sjulian#include <netipx/spx_timer.h> 6211819Sjulian#include <netipx/spx_var.h> 6311819Sjulian 6411819Sjulian/* 6511819Sjulian * SPX protocol implementation. 6611819Sjulian */ 6733181Seivindstatic u_short spx_iss; 6833181Seivindstatic u_short spx_newchecks[50]; 6933181Seivindstatic int spx_hardnosed; 7033181Seivindstatic int spx_use_delack = 0; 7133181Seivindstatic int traceallspxs = 0; 7233181Seivindstatic struct spx spx_savesi; 7333181Seivindstatic struct spx_istat spx_istat; 7411819Sjulian 7525652Sjhay/* Following was struct spxstat spxstat; */ 7625652Sjhay#ifndef spxstat 7725652Sjhay#define spxstat spx_istat.newstats 7825652Sjhay#endif 7911819Sjulian 8033181Seivindstatic int spx_backoff[SPX_MAXRXTSHIFT+1] = 8125652Sjhay { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 8211819Sjulian 8325652Sjhaystatic struct spxpcb *spx_close(struct spxpcb *cb); 8425652Sjhaystatic struct spxpcb *spx_disconnect(struct spxpcb *cb); 8525652Sjhaystatic struct spxpcb *spx_drop(struct spxpcb *cb, int errno); 8625652Sjhaystatic int spx_output(struct spxpcb *cb, struct mbuf *m0); 8725652Sjhaystatic int spx_reass(struct spxpcb *cb, struct spx *si); 8825652Sjhaystatic void spx_setpersist(struct spxpcb *cb); 8925652Sjhaystatic void spx_template(struct spxpcb *cb); 9025652Sjhaystatic struct spxpcb *spx_timers(struct spxpcb *cb, int timer); 9125652Sjhaystatic struct spxpcb *spx_usrclosed(struct spxpcb *cb); 9225652Sjhay 9324659Sjhaystatic int spx_usr_abort(struct socket *so); 9428270Swollmanstatic int spx_accept(struct socket *so, struct sockaddr **nam); 9583366Sjulianstatic int spx_attach(struct socket *so, int proto, struct thread *td); 9683366Sjulianstatic int spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 9728270Swollmanstatic int spx_connect(struct socket *so, struct sockaddr *nam, 9883366Sjulian struct thread *td); 9924659Sjhaystatic int spx_detach(struct socket *so); 10024659Sjhaystatic int spx_usr_disconnect(struct socket *so); 10183366Sjulianstatic int spx_listen(struct socket *so, struct thread *td); 10224659Sjhaystatic int spx_rcvd(struct socket *so, int flags); 10324659Sjhaystatic int spx_rcvoob(struct socket *so, struct mbuf *m, int flags); 10424659Sjhaystatic int spx_send(struct socket *so, int flags, struct mbuf *m, 10528270Swollman struct sockaddr *addr, struct mbuf *control, 10683366Sjulian struct thread *td); 10724659Sjhaystatic int spx_shutdown(struct socket *so); 10883366Sjulianstatic int spx_sp_attach(struct socket *so, int proto, struct thread *td); 10924659Sjhay 11024659Sjhaystruct pr_usrreqs spx_usrreqs = { 11124659Sjhay spx_usr_abort, spx_accept, spx_attach, spx_bind, 11224659Sjhay spx_connect, pru_connect2_notsupp, ipx_control, spx_detach, 11324659Sjhay spx_usr_disconnect, spx_listen, ipx_peeraddr, spx_rcvd, 11424659Sjhay spx_rcvoob, spx_send, pru_sense_null, spx_shutdown, 115122875Srwatson ipx_sockaddr, sosend, soreceive, sopoll, pru_sosetlabel_null 11624659Sjhay}; 11724659Sjhay 11824659Sjhaystruct pr_usrreqs spx_usrreq_sps = { 11924659Sjhay spx_usr_abort, spx_accept, spx_sp_attach, spx_bind, 12024659Sjhay spx_connect, pru_connect2_notsupp, ipx_control, spx_detach, 12124659Sjhay spx_usr_disconnect, spx_listen, ipx_peeraddr, spx_rcvd, 12224659Sjhay spx_rcvoob, spx_send, pru_sense_null, spx_shutdown, 123122875Srwatson ipx_sockaddr, sosend, soreceive, sopoll, pru_sosetlabel_null 12424659Sjhay}; 12524659Sjhay 12611819Sjulianvoid 12711819Sjulianspx_init() 12811819Sjulian{ 12911819Sjulian 13011819Sjulian spx_iss = 1; /* WRONG !! should fish it out of TODR */ 13111819Sjulian} 13211819Sjulian 13311819Sjulianvoid 13411819Sjulianspx_input(m, ipxp) 13511819Sjulian register struct mbuf *m; 13611819Sjulian register struct ipxpcb *ipxp; 13711819Sjulian{ 13811819Sjulian register struct spxpcb *cb; 13911819Sjulian register struct spx *si = mtod(m, struct spx *); 14011819Sjulian register struct socket *so; 14111819Sjulian int dropsocket = 0; 14211819Sjulian short ostate = 0; 14311819Sjulian 14411819Sjulian spxstat.spxs_rcvtotal++; 14525652Sjhay if (ipxp == NULL) { 14611819Sjulian panic("No ipxpcb in spx_input\n"); 14711819Sjulian return; 14811819Sjulian } 14911819Sjulian 15011819Sjulian cb = ipxtospxpcb(ipxp); 15125652Sjhay if (cb == NULL) 15225652Sjhay goto bad; 15311819Sjulian 15411819Sjulian if (m->m_len < sizeof(*si)) { 15525652Sjhay if ((m = m_pullup(m, sizeof(*si))) == NULL) { 15611819Sjulian spxstat.spxs_rcvshort++; 15711819Sjulian return; 15811819Sjulian } 15911819Sjulian si = mtod(m, struct spx *); 16011819Sjulian } 16111819Sjulian si->si_seq = ntohs(si->si_seq); 16211819Sjulian si->si_ack = ntohs(si->si_ack); 16311819Sjulian si->si_alo = ntohs(si->si_alo); 16411819Sjulian 16511819Sjulian so = ipxp->ipxp_socket; 16611819Sjulian 16711819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) { 16811819Sjulian ostate = cb->s_state; 16911819Sjulian spx_savesi = *si; 17011819Sjulian } 17111819Sjulian if (so->so_options & SO_ACCEPTCONN) { 17211819Sjulian struct spxpcb *ocb = cb; 17311819Sjulian 17411819Sjulian so = sonewconn(so, 0); 17525652Sjhay if (so == NULL) { 17611819Sjulian goto drop; 17711819Sjulian } 17811819Sjulian /* 17911819Sjulian * This is ugly, but .... 18011819Sjulian * 18111819Sjulian * Mark socket as temporary until we're 18211819Sjulian * committed to keeping it. The code at 18311819Sjulian * ``drop'' and ``dropwithreset'' check the 18411819Sjulian * flag dropsocket to see if the temporary 18511819Sjulian * socket created here should be discarded. 18611819Sjulian * We mark the socket as discardable until 18711819Sjulian * we're committed to it below in TCPS_LISTEN. 18811819Sjulian */ 18911819Sjulian dropsocket++; 19011819Sjulian ipxp = (struct ipxpcb *)so->so_pcb; 19111819Sjulian ipxp->ipxp_laddr = si->si_dna; 19211819Sjulian cb = ipxtospxpcb(ipxp); 19311819Sjulian cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ 19411819Sjulian cb->s_flags = ocb->s_flags; /* preserve sockopts */ 19511819Sjulian cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ 19611819Sjulian cb->s_state = TCPS_LISTEN; 19797658Stanimura } 19811819Sjulian 19911819Sjulian /* 20011819Sjulian * Packet received on connection. 20111819Sjulian * reset idle time and keep-alive timer; 20211819Sjulian */ 20311819Sjulian cb->s_idle = 0; 20411819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 20511819Sjulian 20611819Sjulian switch (cb->s_state) { 20711819Sjulian 20811819Sjulian case TCPS_LISTEN:{ 20928270Swollman struct sockaddr_ipx *sipx, ssipx; 21011819Sjulian struct ipx_addr laddr; 21111819Sjulian 21211819Sjulian /* 21311819Sjulian * If somebody here was carying on a conversation 21411819Sjulian * and went away, and his pen pal thinks he can 21511819Sjulian * still talk, we get the misdirected packet. 21611819Sjulian */ 21711819Sjulian if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 21811819Sjulian spx_istat.gonawy++; 21911819Sjulian goto dropwithreset; 22011819Sjulian } 22128270Swollman sipx = &ssipx; 22228270Swollman bzero(sipx, sizeof *sipx); 22311819Sjulian sipx->sipx_len = sizeof(*sipx); 22411819Sjulian sipx->sipx_family = AF_IPX; 22511819Sjulian sipx->sipx_addr = si->si_sna; 22611819Sjulian laddr = ipxp->ipxp_laddr; 22711819Sjulian if (ipx_nullhost(laddr)) 22811819Sjulian ipxp->ipxp_laddr = si->si_dna; 22990361Sjulian if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &thread0)) { 23011819Sjulian ipxp->ipxp_laddr = laddr; 23111819Sjulian spx_istat.noconn++; 23211819Sjulian goto drop; 23311819Sjulian } 23411819Sjulian spx_template(cb); 23511819Sjulian dropsocket = 0; /* committed to socket */ 23611819Sjulian cb->s_did = si->si_sid; 23711819Sjulian cb->s_rack = si->si_ack; 23811819Sjulian cb->s_ralo = si->si_alo; 23911819Sjulian#define THREEWAYSHAKE 24011819Sjulian#ifdef THREEWAYSHAKE 24111819Sjulian cb->s_state = TCPS_SYN_RECEIVED; 24211819Sjulian cb->s_force = 1 + SPXT_KEEP; 24311819Sjulian spxstat.spxs_accepts++; 24411819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 24511819Sjulian } 24611819Sjulian break; 24711819Sjulian /* 24811819Sjulian * This state means that we have heard a response 24911819Sjulian * to our acceptance of their connection 25011819Sjulian * It is probably logically unnecessary in this 25111819Sjulian * implementation. 25211819Sjulian */ 25311819Sjulian case TCPS_SYN_RECEIVED: { 25425652Sjhay if (si->si_did != cb->s_sid) { 25511819Sjulian spx_istat.wrncon++; 25611819Sjulian goto drop; 25711819Sjulian } 25811819Sjulian#endif 25911819Sjulian ipxp->ipxp_fport = si->si_sport; 26011819Sjulian cb->s_timer[SPXT_REXMT] = 0; 26111819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 26211819Sjulian soisconnected(so); 26311819Sjulian cb->s_state = TCPS_ESTABLISHED; 26411819Sjulian spxstat.spxs_accepts++; 26511819Sjulian } 26611819Sjulian break; 26711819Sjulian 26811819Sjulian /* 26911819Sjulian * This state means that we have gotten a response 27011819Sjulian * to our attempt to establish a connection. 27111819Sjulian * We fill in the data from the other side, 27211819Sjulian * telling us which port to respond to, instead of the well- 27311819Sjulian * known one we might have sent to in the first place. 27411819Sjulian * We also require that this is a response to our 27511819Sjulian * connection id. 27611819Sjulian */ 27711819Sjulian case TCPS_SYN_SENT: 27825652Sjhay if (si->si_did != cb->s_sid) { 27911819Sjulian spx_istat.notme++; 28011819Sjulian goto drop; 28111819Sjulian } 28211819Sjulian spxstat.spxs_connects++; 28311819Sjulian cb->s_did = si->si_sid; 28411819Sjulian cb->s_rack = si->si_ack; 28511819Sjulian cb->s_ralo = si->si_alo; 28611819Sjulian cb->s_dport = ipxp->ipxp_fport = si->si_sport; 28711819Sjulian cb->s_timer[SPXT_REXMT] = 0; 28811819Sjulian cb->s_flags |= SF_ACKNOW; 28911819Sjulian soisconnected(so); 29011819Sjulian cb->s_state = TCPS_ESTABLISHED; 29111819Sjulian /* Use roundtrip time of connection request for initial rtt */ 29211819Sjulian if (cb->s_rtt) { 29311819Sjulian cb->s_srtt = cb->s_rtt << 3; 29411819Sjulian cb->s_rttvar = cb->s_rtt << 1; 29511819Sjulian SPXT_RANGESET(cb->s_rxtcur, 29611819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 29711819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 29811819Sjulian cb->s_rtt = 0; 29911819Sjulian } 30011819Sjulian } 30197658Stanimura if (so->so_options & SO_DEBUG || traceallspxs) 30211819Sjulian spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0); 30311819Sjulian 30425652Sjhay m->m_len -= sizeof(struct ipx); 30525652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 30625652Sjhay m->m_data += sizeof(struct ipx); 30711819Sjulian 30811819Sjulian if (spx_reass(cb, si)) { 30925652Sjhay m_freem(m); 31011819Sjulian } 31111819Sjulian if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) 31225652Sjhay spx_output(cb, (struct mbuf *)NULL); 31311819Sjulian cb->s_flags &= ~(SF_WIN|SF_RXT); 31411819Sjulian return; 31511819Sjulian 31611819Sjuliandropwithreset: 31711819Sjulian if (dropsocket) 31825652Sjhay soabort(so); 31911819Sjulian si->si_seq = ntohs(si->si_seq); 32011819Sjulian si->si_ack = ntohs(si->si_ack); 32111819Sjulian si->si_alo = ntohs(si->si_alo); 32225652Sjhay m_freem(dtom(si)); 32397658Stanimura if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs) 32411819Sjulian spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 32511819Sjulian return; 32611819Sjulian 32711819Sjuliandrop: 32811819Sjulianbad: 32911819Sjulian if (cb == 0 || cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || 33097658Stanimura traceallspxs) 33111819Sjulian spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 33211819Sjulian m_freem(m); 33311819Sjulian} 33411819Sjulian 33533181Seivindstatic int spxrexmtthresh = 3; 33611819Sjulian 33711819Sjulian/* 33811819Sjulian * This is structurally similar to the tcp reassembly routine 33911819Sjulian * but its function is somewhat different: It merely queues 34011819Sjulian * packets up, and suppresses duplicates. 34111819Sjulian */ 34225652Sjhaystatic int 34311819Sjulianspx_reass(cb, si) 34411819Sjulianregister struct spxpcb *cb; 34511819Sjulianregister struct spx *si; 34611819Sjulian{ 34711819Sjulian register struct spx_q *q; 34811819Sjulian register struct mbuf *m; 34911819Sjulian register struct socket *so = cb->s_ipxpcb->ipxp_socket; 35011819Sjulian char packetp = cb->s_flags & SF_HI; 35111819Sjulian int incr; 35211819Sjulian char wakeup = 0; 35311819Sjulian 35411819Sjulian if (si == SI(0)) 35511819Sjulian goto present; 35611819Sjulian /* 35711819Sjulian * Update our news from them. 35811819Sjulian */ 35911819Sjulian if (si->si_cc & SPX_SA) 36011819Sjulian cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW); 36111819Sjulian if (SSEQ_GT(si->si_alo, cb->s_ralo)) 36211819Sjulian cb->s_flags |= SF_WIN; 36311819Sjulian if (SSEQ_LEQ(si->si_ack, cb->s_rack)) { 36411819Sjulian if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) { 36511819Sjulian spxstat.spxs_rcvdupack++; 36611819Sjulian /* 36711819Sjulian * If this is a completely duplicate ack 36811819Sjulian * and other conditions hold, we assume 36911819Sjulian * a packet has been dropped and retransmit 37011819Sjulian * it exactly as in tcp_input(). 37111819Sjulian */ 37211819Sjulian if (si->si_ack != cb->s_rack || 37311819Sjulian si->si_alo != cb->s_ralo) 37411819Sjulian cb->s_dupacks = 0; 37511819Sjulian else if (++cb->s_dupacks == spxrexmtthresh) { 37611819Sjulian u_short onxt = cb->s_snxt; 37711819Sjulian int cwnd = cb->s_cwnd; 37811819Sjulian 37911819Sjulian cb->s_snxt = si->si_ack; 38011819Sjulian cb->s_cwnd = CUNIT; 38111819Sjulian cb->s_force = 1 + SPXT_REXMT; 38225652Sjhay spx_output(cb, (struct mbuf *)NULL); 38311819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 38411819Sjulian cb->s_rtt = 0; 38511819Sjulian if (cwnd >= 4 * CUNIT) 38611819Sjulian cb->s_cwnd = cwnd / 2; 38711819Sjulian if (SSEQ_GT(onxt, cb->s_snxt)) 38811819Sjulian cb->s_snxt = onxt; 38911819Sjulian return (1); 39011819Sjulian } 39111819Sjulian } else 39211819Sjulian cb->s_dupacks = 0; 39311819Sjulian goto update_window; 39411819Sjulian } 39511819Sjulian cb->s_dupacks = 0; 39611819Sjulian /* 39711819Sjulian * If our correspondent acknowledges data we haven't sent 39811819Sjulian * TCP would drop the packet after acking. We'll be a little 39911819Sjulian * more permissive 40011819Sjulian */ 40111819Sjulian if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) { 40211819Sjulian spxstat.spxs_rcvacktoomuch++; 40311819Sjulian si->si_ack = cb->s_smax + 1; 40411819Sjulian } 40511819Sjulian spxstat.spxs_rcvackpack++; 40611819Sjulian /* 40711819Sjulian * If transmit timer is running and timed sequence 40811819Sjulian * number was acked, update smoothed round trip time. 40911819Sjulian * See discussion of algorithm in tcp_input.c 41011819Sjulian */ 41111819Sjulian if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 41211819Sjulian spxstat.spxs_rttupdated++; 41311819Sjulian if (cb->s_srtt != 0) { 41411819Sjulian register short delta; 41511819Sjulian delta = cb->s_rtt - (cb->s_srtt >> 3); 41611819Sjulian if ((cb->s_srtt += delta) <= 0) 41711819Sjulian cb->s_srtt = 1; 41811819Sjulian if (delta < 0) 41911819Sjulian delta = -delta; 42011819Sjulian delta -= (cb->s_rttvar >> 2); 42111819Sjulian if ((cb->s_rttvar += delta) <= 0) 42211819Sjulian cb->s_rttvar = 1; 42311819Sjulian } else { 42411819Sjulian /* 42511819Sjulian * No rtt measurement yet 42611819Sjulian */ 42711819Sjulian cb->s_srtt = cb->s_rtt << 3; 42811819Sjulian cb->s_rttvar = cb->s_rtt << 1; 42911819Sjulian } 43011819Sjulian cb->s_rtt = 0; 43111819Sjulian cb->s_rxtshift = 0; 43211819Sjulian SPXT_RANGESET(cb->s_rxtcur, 43311819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 43411819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 43511819Sjulian } 43611819Sjulian /* 43711819Sjulian * If all outstanding data is acked, stop retransmit 43811819Sjulian * timer and remember to restart (more output or persist). 43911819Sjulian * If there is more data to be acked, restart retransmit 44011819Sjulian * timer, using current (possibly backed-off) value; 44111819Sjulian */ 44211819Sjulian if (si->si_ack == cb->s_smax + 1) { 44311819Sjulian cb->s_timer[SPXT_REXMT] = 0; 44411819Sjulian cb->s_flags |= SF_RXT; 44511819Sjulian } else if (cb->s_timer[SPXT_PERSIST] == 0) 44611819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 44711819Sjulian /* 44811819Sjulian * When new data is acked, open the congestion window. 44911819Sjulian * If the window gives us less than ssthresh packets 45011819Sjulian * in flight, open exponentially (maxseg at a time). 45111819Sjulian * Otherwise open linearly (maxseg^2 / cwnd at a time). 45211819Sjulian */ 45311819Sjulian incr = CUNIT; 45411819Sjulian if (cb->s_cwnd > cb->s_ssthresh) 45511819Sjulian incr = max(incr * incr / cb->s_cwnd, 1); 45611819Sjulian cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx); 45711819Sjulian /* 45811819Sjulian * Trim Acked data from output queue. 45911819Sjulian */ 46011819Sjulian while ((m = so->so_snd.sb_mb) != NULL) { 46111819Sjulian if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack)) 46211819Sjulian sbdroprecord(&so->so_snd); 46311819Sjulian else 46411819Sjulian break; 46511819Sjulian } 46611819Sjulian sowwakeup(so); 46711819Sjulian cb->s_rack = si->si_ack; 46811819Sjulianupdate_window: 46911819Sjulian if (SSEQ_LT(cb->s_snxt, cb->s_rack)) 47011819Sjulian cb->s_snxt = cb->s_rack; 47143311Sdillon if (SSEQ_LT(cb->s_swl1, si->si_seq) || ((cb->s_swl1 == si->si_seq && 47243311Sdillon (SSEQ_LT(cb->s_swl2, si->si_ack))) || 47343305Sdillon (cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo)))) { 47411819Sjulian /* keep track of pure window updates */ 47511819Sjulian if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack 47611819Sjulian && SSEQ_LT(cb->s_ralo, si->si_alo)) { 47711819Sjulian spxstat.spxs_rcvwinupd++; 47811819Sjulian spxstat.spxs_rcvdupack--; 47911819Sjulian } 48011819Sjulian cb->s_ralo = si->si_alo; 48111819Sjulian cb->s_swl1 = si->si_seq; 48211819Sjulian cb->s_swl2 = si->si_ack; 48311819Sjulian cb->s_swnd = (1 + si->si_alo - si->si_ack); 48411819Sjulian if (cb->s_swnd > cb->s_smxw) 48511819Sjulian cb->s_smxw = cb->s_swnd; 48611819Sjulian cb->s_flags |= SF_WIN; 48711819Sjulian } 48811819Sjulian /* 48911819Sjulian * If this packet number is higher than that which 49011819Sjulian * we have allocated refuse it, unless urgent 49111819Sjulian */ 49211819Sjulian if (SSEQ_GT(si->si_seq, cb->s_alo)) { 49311819Sjulian if (si->si_cc & SPX_SP) { 49411819Sjulian spxstat.spxs_rcvwinprobe++; 49511819Sjulian return (1); 49611819Sjulian } else 49711819Sjulian spxstat.spxs_rcvpackafterwin++; 49811819Sjulian if (si->si_cc & SPX_OB) { 49911819Sjulian if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { 50025652Sjhay m_freem(dtom(si)); 50111819Sjulian return (0); 50211819Sjulian } /* else queue this packet; */ 50311819Sjulian } else { 50411819Sjulian /*register struct socket *so = cb->s_ipxpcb->ipxp_socket; 50511819Sjulian if (so->so_state && SS_NOFDREF) { 50625652Sjhay spx_close(cb); 50797658Stanimura } else 50897658Stanimura would crash system*/ 50911819Sjulian spx_istat.notyet++; 51025652Sjhay m_freem(dtom(si)); 51111819Sjulian return (0); 51211819Sjulian } 51311819Sjulian } 51411819Sjulian /* 51511819Sjulian * If this is a system packet, we don't need to 51611819Sjulian * queue it up, and won't update acknowledge # 51711819Sjulian */ 51811819Sjulian if (si->si_cc & SPX_SP) { 51911819Sjulian return (1); 52011819Sjulian } 52111819Sjulian /* 52211819Sjulian * We have already seen this packet, so drop. 52311819Sjulian */ 52411819Sjulian if (SSEQ_LT(si->si_seq, cb->s_ack)) { 52511819Sjulian spx_istat.bdreas++; 52611819Sjulian spxstat.spxs_rcvduppack++; 52711819Sjulian if (si->si_seq == cb->s_ack - 1) 52811819Sjulian spx_istat.lstdup++; 52911819Sjulian return (1); 53011819Sjulian } 53111819Sjulian /* 53211819Sjulian * Loop through all packets queued up to insert in 53311819Sjulian * appropriate sequence. 53411819Sjulian */ 53525652Sjhay for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { 53611819Sjulian if (si->si_seq == SI(q)->si_seq) { 53711819Sjulian spxstat.spxs_rcvduppack++; 53811819Sjulian return (1); 53911819Sjulian } 54011819Sjulian if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { 54111819Sjulian spxstat.spxs_rcvoopack++; 54211819Sjulian break; 54311819Sjulian } 54411819Sjulian } 54511819Sjulian insque(si, q->si_prev); 54611819Sjulian /* 54711819Sjulian * If this packet is urgent, inform process 54811819Sjulian */ 54911819Sjulian if (si->si_cc & SPX_OB) { 55011819Sjulian cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 55111819Sjulian sohasoutofband(so); 55211819Sjulian cb->s_oobflags |= SF_IOOB; 55311819Sjulian } 55411819Sjulianpresent: 55511819Sjulian#define SPINC sizeof(struct spxhdr) 55611819Sjulian /* 55711819Sjulian * Loop through all packets queued up to update acknowledge 55811819Sjulian * number, and present all acknowledged data to user; 55911819Sjulian * If in packet interface mode, show packet headers. 56011819Sjulian */ 56125652Sjhay for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { 56211819Sjulian if (SI(q)->si_seq == cb->s_ack) { 56311819Sjulian cb->s_ack++; 56411819Sjulian m = dtom(q); 56511819Sjulian if (SI(q)->si_cc & SPX_OB) { 56611819Sjulian cb->s_oobflags &= ~SF_IOOB; 56711819Sjulian if (so->so_rcv.sb_cc) 56811819Sjulian so->so_oobmark = so->so_rcv.sb_cc; 56997658Stanimura else 570130480Srwatson so->so_rcv.sb_state |= SBS_RCVATMARK; 57111819Sjulian } 57211819Sjulian q = q->si_prev; 57311819Sjulian remque(q->si_next); 57411819Sjulian wakeup = 1; 57511819Sjulian spxstat.spxs_rcvpack++; 57611819Sjulian#ifdef SF_NEWCALL 57711819Sjulian if (cb->s_flags2 & SF_NEWCALL) { 57811819Sjulian struct spxhdr *sp = mtod(m, struct spxhdr *); 57911819Sjulian u_char dt = sp->spx_dt; 58011819Sjulian spx_newchecks[4]++; 58111819Sjulian if (dt != cb->s_rhdr.spx_dt) { 58211819Sjulian struct mbuf *mm = 583111119Simp m_getclr(M_DONTWAIT, MT_CONTROL); 58411819Sjulian spx_newchecks[0]++; 58511819Sjulian if (mm != NULL) { 58611819Sjulian u_short *s = 58711819Sjulian mtod(mm, u_short *); 58811819Sjulian cb->s_rhdr.spx_dt = dt; 58911819Sjulian mm->m_len = 5; /*XXX*/ 59011819Sjulian s[0] = 5; 59111819Sjulian s[1] = 1; 59211819Sjulian *(u_char *)(&s[2]) = dt; 59311819Sjulian sbappend(&so->so_rcv, mm); 59411819Sjulian } 59511819Sjulian } 59611819Sjulian if (sp->spx_cc & SPX_OB) { 59711819Sjulian MCHTYPE(m, MT_OOBDATA); 59811819Sjulian spx_newchecks[1]++; 59911819Sjulian so->so_oobmark = 0; 600130480Srwatson so->so_rcv.sb_state &= ~SBS_RCVATMARK; 60111819Sjulian } 60211819Sjulian if (packetp == 0) { 60311819Sjulian m->m_data += SPINC; 60411819Sjulian m->m_len -= SPINC; 60511819Sjulian m->m_pkthdr.len -= SPINC; 60611819Sjulian } 60711819Sjulian if ((sp->spx_cc & SPX_EM) || packetp) { 60811819Sjulian sbappendrecord(&so->so_rcv, m); 60911819Sjulian spx_newchecks[9]++; 61011819Sjulian } else 61111819Sjulian sbappend(&so->so_rcv, m); 61211819Sjulian } else 61311819Sjulian#endif 61411819Sjulian if (packetp) { 61511819Sjulian sbappendrecord(&so->so_rcv, m); 61611819Sjulian } else { 61711819Sjulian cb->s_rhdr = *mtod(m, struct spxhdr *); 61811819Sjulian m->m_data += SPINC; 61911819Sjulian m->m_len -= SPINC; 62011819Sjulian m->m_pkthdr.len -= SPINC; 62111819Sjulian sbappend(&so->so_rcv, m); 62211819Sjulian } 62311819Sjulian } else 62411819Sjulian break; 62511819Sjulian } 62697658Stanimura if (wakeup) 62725652Sjhay sorwakeup(so); 62811819Sjulian return (0); 62911819Sjulian} 63011819Sjulian 63111819Sjulianvoid 63212881Sbdespx_ctlinput(cmd, arg_as_sa, dummy) 63311819Sjulian int cmd; 63412881Sbde struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */ 63512881Sbde void *dummy; 63611819Sjulian{ 63712881Sbde caddr_t arg = (/* XXX */ caddr_t)arg_as_sa; 63811819Sjulian struct ipx_addr *na; 63925652Sjhay struct sockaddr_ipx *sipx; 64011819Sjulian 641119995Sru if (cmd < 0 || cmd >= PRC_NCMDS) 64211819Sjulian return; 64325652Sjhay 64411819Sjulian switch (cmd) { 64511819Sjulian 64611819Sjulian case PRC_ROUTEDEAD: 64711819Sjulian return; 64811819Sjulian 64911819Sjulian case PRC_IFDOWN: 65011819Sjulian case PRC_HOSTDEAD: 65111819Sjulian case PRC_HOSTUNREACH: 65211819Sjulian sipx = (struct sockaddr_ipx *)arg; 65311819Sjulian if (sipx->sipx_family != AF_IPX) 65411819Sjulian return; 65511819Sjulian na = &sipx->sipx_addr; 65611819Sjulian break; 65711819Sjulian 65811819Sjulian default: 65911819Sjulian break; 66011819Sjulian } 66111819Sjulian} 66211819Sjulian 66311819Sjulian#ifdef notdef 66411819Sjulianint 66511819Sjulianspx_fixmtu(ipxp) 66611819Sjulianregister struct ipxpcb *ipxp; 66711819Sjulian{ 66811819Sjulian register struct spxpcb *cb = (struct spxpcb *)(ipxp->ipxp_pcb); 66911819Sjulian register struct mbuf *m; 67011819Sjulian register struct spx *si; 67111819Sjulian struct ipx_errp *ep; 67211819Sjulian struct sockbuf *sb; 67311819Sjulian int badseq, len; 67411819Sjulian struct mbuf *firstbad, *m0; 67511819Sjulian 67625652Sjhay if (cb != NULL) { 67711819Sjulian /* 67811819Sjulian * The notification that we have sent 67911819Sjulian * too much is bad news -- we will 68011819Sjulian * have to go through queued up so far 68111819Sjulian * splitting ones which are too big and 68211819Sjulian * reassigning sequence numbers and checksums. 68311819Sjulian * we should then retransmit all packets from 68411819Sjulian * one above the offending packet to the last one 68511819Sjulian * we had sent (or our allocation) 68611819Sjulian * then the offending one so that the any queued 68711819Sjulian * data at our destination will be discarded. 68811819Sjulian */ 68911819Sjulian ep = (struct ipx_errp *)ipxp->ipxp_notify_param; 69011819Sjulian sb = &ipxp->ipxp_socket->so_snd; 69111819Sjulian cb->s_mtu = ep->ipx_err_param; 69211819Sjulian badseq = SI(&ep->ipx_err_ipx)->si_seq; 69325652Sjhay for (m = sb->sb_mb; m != NULL; m = m->m_act) { 69411819Sjulian si = mtod(m, struct spx *); 69511819Sjulian if (si->si_seq == badseq) 69611819Sjulian break; 69711819Sjulian } 69825652Sjhay if (m == NULL) 69925652Sjhay return; 70011819Sjulian firstbad = m; 70111819Sjulian /*for (;;) {*/ 70211819Sjulian /* calculate length */ 70325652Sjhay for (m0 = m, len = 0; m != NULL; m = m->m_next) 70411819Sjulian len += m->m_len; 70511819Sjulian if (len > cb->s_mtu) { 70611819Sjulian } 70711819Sjulian /* FINISH THIS 70811819Sjulian } */ 70911819Sjulian } 71011819Sjulian} 71111819Sjulian#endif 71211819Sjulian 71325652Sjhaystatic int 71411819Sjulianspx_output(cb, m0) 71511819Sjulian register struct spxpcb *cb; 71611819Sjulian struct mbuf *m0; 71711819Sjulian{ 71811819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 71911819Sjulian register struct mbuf *m; 72025652Sjhay register struct spx *si = (struct spx *)NULL; 72111819Sjulian register struct sockbuf *sb = &so->so_snd; 72211819Sjulian int len = 0, win, rcv_win; 72311819Sjulian short span, off, recordp = 0; 72411819Sjulian u_short alo; 72511819Sjulian int error = 0, sendalot; 72611819Sjulian#ifdef notdef 72711819Sjulian int idle; 72811819Sjulian#endif 72911819Sjulian struct mbuf *mprev; 73011819Sjulian 73125652Sjhay if (m0 != NULL) { 73211819Sjulian int mtu = cb->s_mtu; 73311819Sjulian int datalen; 73411819Sjulian /* 73511819Sjulian * Make sure that packet isn't too big. 73611819Sjulian */ 73725652Sjhay for (m = m0; m != NULL; m = m->m_next) { 73811819Sjulian mprev = m; 73911819Sjulian len += m->m_len; 74011819Sjulian if (m->m_flags & M_EOR) 74111819Sjulian recordp = 1; 74211819Sjulian } 74311819Sjulian datalen = (cb->s_flags & SF_HO) ? 74425652Sjhay len - sizeof(struct spxhdr) : len; 74511819Sjulian if (datalen > mtu) { 74611819Sjulian if (cb->s_flags & SF_PI) { 74711819Sjulian m_freem(m0); 74811819Sjulian return (EMSGSIZE); 74911819Sjulian } else { 75011819Sjulian int oldEM = cb->s_cc & SPX_EM; 75111819Sjulian 75211819Sjulian cb->s_cc &= ~SPX_EM; 75311819Sjulian while (len > mtu) { 75411819Sjulian /* 75511819Sjulian * Here we are only being called 75611819Sjulian * from usrreq(), so it is OK to 75711819Sjulian * block. 75811819Sjulian */ 759111119Simp m = m_copym(m0, 0, mtu, M_TRYWAIT); 76011819Sjulian if (cb->s_flags & SF_NEWCALL) { 76111819Sjulian struct mbuf *mm = m; 76211819Sjulian spx_newchecks[7]++; 76325652Sjhay while (mm != NULL) { 76411819Sjulian mm->m_flags &= ~M_EOR; 76511819Sjulian mm = mm->m_next; 76611819Sjulian } 76711819Sjulian } 76811819Sjulian error = spx_output(cb, m); 76911819Sjulian if (error) { 77011819Sjulian cb->s_cc |= oldEM; 77111819Sjulian m_freem(m0); 77225652Sjhay return (error); 77311819Sjulian } 77411819Sjulian m_adj(m0, mtu); 77511819Sjulian len -= mtu; 77611819Sjulian } 77711819Sjulian cb->s_cc |= oldEM; 77811819Sjulian } 77911819Sjulian } 78011819Sjulian /* 78111819Sjulian * Force length even, by adding a "garbage byte" if 78211819Sjulian * necessary. 78311819Sjulian */ 78411819Sjulian if (len & 1) { 78511819Sjulian m = mprev; 78611819Sjulian if (M_TRAILINGSPACE(m) >= 1) 78711819Sjulian m->m_len++; 78811819Sjulian else { 789111119Simp struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 79011819Sjulian 79125652Sjhay if (m1 == NULL) { 79211819Sjulian m_freem(m0); 79311819Sjulian return (ENOBUFS); 79411819Sjulian } 79511819Sjulian m1->m_len = 1; 79611819Sjulian *(mtod(m1, u_char *)) = 0; 79711819Sjulian m->m_next = m1; 79811819Sjulian } 79911819Sjulian } 800111119Simp m = m_gethdr(M_DONTWAIT, MT_HEADER); 80125652Sjhay if (m == NULL) { 80211819Sjulian m_freem(m0); 80311819Sjulian return (ENOBUFS); 80411819Sjulian } 80511819Sjulian /* 80611819Sjulian * Fill in mbuf with extended SP header 80711819Sjulian * and addresses and length put into network format. 80811819Sjulian */ 80925652Sjhay MH_ALIGN(m, sizeof(struct spx)); 81025652Sjhay m->m_len = sizeof(struct spx); 81111819Sjulian m->m_next = m0; 81211819Sjulian si = mtod(m, struct spx *); 81311819Sjulian si->si_i = *cb->s_ipx; 81411819Sjulian si->si_s = cb->s_shdr; 81511819Sjulian if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 81611819Sjulian register struct spxhdr *sh; 81725652Sjhay if (m0->m_len < sizeof(*sh)) { 81811819Sjulian if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 81925652Sjhay m_free(m); 82011819Sjulian m_freem(m0); 82111819Sjulian return (EINVAL); 82211819Sjulian } 82311819Sjulian m->m_next = m0; 82411819Sjulian } 82511819Sjulian sh = mtod(m0, struct spxhdr *); 82611819Sjulian si->si_dt = sh->spx_dt; 82711819Sjulian si->si_cc |= sh->spx_cc & SPX_EM; 82825652Sjhay m0->m_len -= sizeof(*sh); 82925652Sjhay m0->m_data += sizeof(*sh); 83025652Sjhay len -= sizeof(*sh); 83111819Sjulian } 83211819Sjulian len += sizeof(*si); 83311819Sjulian if ((cb->s_flags2 & SF_NEWCALL) && recordp) { 83425652Sjhay si->si_cc |= SPX_EM; 83511819Sjulian spx_newchecks[8]++; 83611819Sjulian } 83711819Sjulian if (cb->s_oobflags & SF_SOOB) { 83811819Sjulian /* 83911819Sjulian * Per jqj@cornell: 84011819Sjulian * make sure OB packets convey exactly 1 byte. 84111819Sjulian * If the packet is 1 byte or larger, we 84211819Sjulian * have already guaranted there to be at least 84311819Sjulian * one garbage byte for the checksum, and 84411819Sjulian * extra bytes shouldn't hurt! 84511819Sjulian */ 84611819Sjulian if (len > sizeof(*si)) { 84711819Sjulian si->si_cc |= SPX_OB; 84811819Sjulian len = (1 + sizeof(*si)); 84911819Sjulian } 85011819Sjulian } 85111819Sjulian si->si_len = htons((u_short)len); 85211819Sjulian m->m_pkthdr.len = ((len - 1) | 1) + 1; 85311819Sjulian /* 85411819Sjulian * queue stuff up for output 85511819Sjulian */ 85611819Sjulian sbappendrecord(sb, m); 85711819Sjulian cb->s_seq++; 85811819Sjulian } 85911819Sjulian#ifdef notdef 86011819Sjulian idle = (cb->s_smax == (cb->s_rack - 1)); 86111819Sjulian#endif 86211819Sjulianagain: 86311819Sjulian sendalot = 0; 86411819Sjulian off = cb->s_snxt - cb->s_rack; 86525652Sjhay win = min(cb->s_swnd, (cb->s_cwnd / CUNIT)); 86611819Sjulian 86711819Sjulian /* 86811819Sjulian * If in persist timeout with window of 0, send a probe. 86911819Sjulian * Otherwise, if window is small but nonzero 87011819Sjulian * and timer expired, send what we can and go into 87111819Sjulian * transmit state. 87211819Sjulian */ 87311819Sjulian if (cb->s_force == 1 + SPXT_PERSIST) { 87411819Sjulian if (win != 0) { 87511819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 87611819Sjulian cb->s_rxtshift = 0; 87711819Sjulian } 87811819Sjulian } 87911819Sjulian span = cb->s_seq - cb->s_rack; 88011819Sjulian len = min(span, win) - off; 88111819Sjulian 88211819Sjulian if (len < 0) { 88311819Sjulian /* 88411819Sjulian * Window shrank after we went into it. 88511819Sjulian * If window shrank to 0, cancel pending 88611819Sjulian * restransmission and pull s_snxt back 88711819Sjulian * to (closed) window. We will enter persist 88811819Sjulian * state below. If the widndow didn't close completely, 88911819Sjulian * just wait for an ACK. 89011819Sjulian */ 89111819Sjulian len = 0; 89211819Sjulian if (win == 0) { 89311819Sjulian cb->s_timer[SPXT_REXMT] = 0; 89411819Sjulian cb->s_snxt = cb->s_rack; 89511819Sjulian } 89611819Sjulian } 89711819Sjulian if (len > 1) 89811819Sjulian sendalot = 1; 89911819Sjulian rcv_win = sbspace(&so->so_rcv); 90011819Sjulian 90111819Sjulian /* 90211819Sjulian * Send if we owe peer an ACK. 90311819Sjulian */ 90411819Sjulian if (cb->s_oobflags & SF_SOOB) { 90511819Sjulian /* 90611819Sjulian * must transmit this out of band packet 90711819Sjulian */ 90811819Sjulian cb->s_oobflags &= ~ SF_SOOB; 90911819Sjulian sendalot = 1; 91011819Sjulian spxstat.spxs_sndurg++; 91111819Sjulian goto found; 91211819Sjulian } 91311819Sjulian if (cb->s_flags & SF_ACKNOW) 91411819Sjulian goto send; 91511819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 91611819Sjulian goto send; 91711819Sjulian /* 91811819Sjulian * Silly window can't happen in spx. 91911819Sjulian * Code from tcp deleted. 92011819Sjulian */ 92111819Sjulian if (len) 92211819Sjulian goto send; 92311819Sjulian /* 92411819Sjulian * Compare available window to amount of window 92511819Sjulian * known to peer (as advertised window less 92611819Sjulian * next expected input.) If the difference is at least two 92711819Sjulian * packets or at least 35% of the mximum possible window, 92811819Sjulian * then want to send a window update to peer. 92911819Sjulian */ 93011819Sjulian if (rcv_win > 0) { 93111819Sjulian u_short delta = 1 + cb->s_alo - cb->s_ack; 93211819Sjulian int adv = rcv_win - (delta * cb->s_mtu); 93311819Sjulian 93411819Sjulian if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || 93511819Sjulian (100 * adv / so->so_rcv.sb_hiwat >= 35)) { 93611819Sjulian spxstat.spxs_sndwinup++; 93711819Sjulian cb->s_flags |= SF_ACKNOW; 93811819Sjulian goto send; 93911819Sjulian } 94011819Sjulian 94111819Sjulian } 94211819Sjulian /* 94311819Sjulian * Many comments from tcp_output.c are appropriate here 94411819Sjulian * including . . . 94511819Sjulian * If send window is too small, there is data to transmit, and no 94611819Sjulian * retransmit or persist is pending, then go to persist state. 94711819Sjulian * If nothing happens soon, send when timer expires: 94811819Sjulian * if window is nonzero, transmit what we can, 94911819Sjulian * otherwise send a probe. 95011819Sjulian */ 95111819Sjulian if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 && 95211819Sjulian cb->s_timer[SPXT_PERSIST] == 0) { 95311819Sjulian cb->s_rxtshift = 0; 95411819Sjulian spx_setpersist(cb); 95511819Sjulian } 95611819Sjulian /* 95711819Sjulian * No reason to send a packet, just return. 95811819Sjulian */ 95911819Sjulian cb->s_outx = 1; 96011819Sjulian return (0); 96111819Sjulian 96211819Sjuliansend: 96311819Sjulian /* 96411819Sjulian * Find requested packet. 96511819Sjulian */ 96611819Sjulian si = 0; 96711819Sjulian if (len > 0) { 96811819Sjulian cb->s_want = cb->s_snxt; 96925652Sjhay for (m = sb->sb_mb; m != NULL; m = m->m_act) { 97011819Sjulian si = mtod(m, struct spx *); 97111819Sjulian if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) 97211819Sjulian break; 97311819Sjulian } 97411819Sjulian found: 97525652Sjhay if (si != NULL) { 97611819Sjulian if (si->si_seq == cb->s_snxt) 97711819Sjulian cb->s_snxt++; 97811819Sjulian else 97911819Sjulian spxstat.spxs_sndvoid++, si = 0; 98011819Sjulian } 98111819Sjulian } 98211819Sjulian /* 98311819Sjulian * update window 98411819Sjulian */ 98511819Sjulian if (rcv_win < 0) 98611819Sjulian rcv_win = 0; 98711819Sjulian alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); 98811819Sjulian if (SSEQ_LT(alo, cb->s_alo)) 98911819Sjulian alo = cb->s_alo; 99011819Sjulian 99125652Sjhay if (si != NULL) { 99211819Sjulian /* 99311819Sjulian * must make a copy of this packet for 99411819Sjulian * ipx_output to monkey with 99511819Sjulian */ 99611819Sjulian m = m_copy(dtom(si), 0, (int)M_COPYALL); 99711819Sjulian if (m == NULL) { 99811819Sjulian return (ENOBUFS); 99911819Sjulian } 100011819Sjulian si = mtod(m, struct spx *); 100111819Sjulian if (SSEQ_LT(si->si_seq, cb->s_smax)) 100211819Sjulian spxstat.spxs_sndrexmitpack++; 100311819Sjulian else 100411819Sjulian spxstat.spxs_sndpack++; 100511819Sjulian } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { 100611819Sjulian /* 100711819Sjulian * Must send an acknowledgement or a probe 100811819Sjulian */ 100911819Sjulian if (cb->s_force) 101011819Sjulian spxstat.spxs_sndprobe++; 101111819Sjulian if (cb->s_flags & SF_ACKNOW) 101211819Sjulian spxstat.spxs_sndacks++; 1013111119Simp m = m_gethdr(M_DONTWAIT, MT_HEADER); 101425652Sjhay if (m == NULL) 101511819Sjulian return (ENOBUFS); 101611819Sjulian /* 101711819Sjulian * Fill in mbuf with extended SP header 101811819Sjulian * and addresses and length put into network format. 101911819Sjulian */ 102025652Sjhay MH_ALIGN(m, sizeof(struct spx)); 102125652Sjhay m->m_len = sizeof(*si); 102225652Sjhay m->m_pkthdr.len = sizeof(*si); 102311819Sjulian si = mtod(m, struct spx *); 102411819Sjulian si->si_i = *cb->s_ipx; 102511819Sjulian si->si_s = cb->s_shdr; 102611819Sjulian si->si_seq = cb->s_smax + 1; 102725652Sjhay si->si_len = htons(sizeof(*si)); 102811819Sjulian si->si_cc |= SPX_SP; 102911819Sjulian } else { 103011819Sjulian cb->s_outx = 3; 103197658Stanimura if (so->so_options & SO_DEBUG || traceallspxs) 103211819Sjulian spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 103311819Sjulian return (0); 103411819Sjulian } 103511819Sjulian /* 103611819Sjulian * Stuff checksum and output datagram. 103711819Sjulian */ 103811819Sjulian if ((si->si_cc & SPX_SP) == 0) { 103911819Sjulian if (cb->s_force != (1 + SPXT_PERSIST) || 104011819Sjulian cb->s_timer[SPXT_PERSIST] == 0) { 104111819Sjulian /* 104211819Sjulian * If this is a new packet and we are not currently 104311819Sjulian * timing anything, time this one. 104411819Sjulian */ 104511819Sjulian if (SSEQ_LT(cb->s_smax, si->si_seq)) { 104611819Sjulian cb->s_smax = si->si_seq; 104711819Sjulian if (cb->s_rtt == 0) { 104811819Sjulian spxstat.spxs_segstimed++; 104911819Sjulian cb->s_rtseq = si->si_seq; 105011819Sjulian cb->s_rtt = 1; 105111819Sjulian } 105211819Sjulian } 105311819Sjulian /* 105411819Sjulian * Set rexmt timer if not currently set, 105511819Sjulian * Initial value for retransmit timer is smoothed 105611819Sjulian * round-trip time + 2 * round-trip time variance. 105711819Sjulian * Initialize shift counter which is used for backoff 105811819Sjulian * of retransmit time. 105911819Sjulian */ 106011819Sjulian if (cb->s_timer[SPXT_REXMT] == 0 && 106111819Sjulian cb->s_snxt != cb->s_rack) { 106211819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 106311819Sjulian if (cb->s_timer[SPXT_PERSIST]) { 106411819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 106511819Sjulian cb->s_rxtshift = 0; 106611819Sjulian } 106711819Sjulian } 106811819Sjulian } else if (SSEQ_LT(cb->s_smax, si->si_seq)) { 106911819Sjulian cb->s_smax = si->si_seq; 107011819Sjulian } 107111819Sjulian } else if (cb->s_state < TCPS_ESTABLISHED) { 107211819Sjulian if (cb->s_rtt == 0) 107311819Sjulian cb->s_rtt = 1; /* Time initial handshake */ 107411819Sjulian if (cb->s_timer[SPXT_REXMT] == 0) 107511819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 107611819Sjulian } 107711819Sjulian { 107811819Sjulian /* 107911819Sjulian * Do not request acks when we ack their data packets or 108011819Sjulian * when we do a gratuitous window update. 108111819Sjulian */ 108211819Sjulian if (((si->si_cc & SPX_SP) == 0) || cb->s_force) 108311819Sjulian si->si_cc |= SPX_SA; 108411819Sjulian si->si_seq = htons(si->si_seq); 108511819Sjulian si->si_alo = htons(alo); 108611819Sjulian si->si_ack = htons(cb->s_ack); 108711819Sjulian 108811819Sjulian if (ipxcksum) { 108950519Sjhay si->si_sum = ipx_cksum(m, ntohs(si->si_len)); 109011819Sjulian } else 109111819Sjulian si->si_sum = 0xffff; 109211819Sjulian 109311819Sjulian cb->s_outx = 4; 109497658Stanimura if (so->so_options & SO_DEBUG || traceallspxs) 109511819Sjulian spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 109611819Sjulian 109797658Stanimura if (so->so_options & SO_DONTROUTE) 109825652Sjhay error = ipx_outputfl(m, (struct route *)NULL, IPX_ROUTETOIF); 109997658Stanimura else 110011819Sjulian error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0); 110111819Sjulian } 110211819Sjulian if (error) { 110311819Sjulian return (error); 110411819Sjulian } 110511819Sjulian spxstat.spxs_sndtotal++; 110611819Sjulian /* 110711819Sjulian * Data sent (as far as we can tell). 110811819Sjulian * If this advertises a larger window than any other segment, 110911819Sjulian * then remember the size of the advertized window. 111011819Sjulian * Any pending ACK has now been sent. 111111819Sjulian */ 111211819Sjulian cb->s_force = 0; 111311819Sjulian cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); 111411819Sjulian if (SSEQ_GT(alo, cb->s_alo)) 111511819Sjulian cb->s_alo = alo; 111611819Sjulian if (sendalot) 111711819Sjulian goto again; 111811819Sjulian cb->s_outx = 5; 111911819Sjulian return (0); 112011819Sjulian} 112111819Sjulian 112233181Seivindstatic int spx_do_persist_panics = 0; 112311819Sjulian 112425652Sjhaystatic void 112511819Sjulianspx_setpersist(cb) 112611819Sjulian register struct spxpcb *cb; 112711819Sjulian{ 112835599Sbde register int t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 112911819Sjulian 113011819Sjulian if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics) 113111819Sjulian panic("spx_output REXMT"); 113211819Sjulian /* 113311819Sjulian * Start/restart persistance timer. 113411819Sjulian */ 113511819Sjulian SPXT_RANGESET(cb->s_timer[SPXT_PERSIST], 113611819Sjulian t*spx_backoff[cb->s_rxtshift], 113711819Sjulian SPXTV_PERSMIN, SPXTV_PERSMAX); 113811819Sjulian if (cb->s_rxtshift < SPX_MAXRXTSHIFT) 113911819Sjulian cb->s_rxtshift++; 114011819Sjulian} 114125652Sjhay 114211819Sjulianint 114338482Swollmanspx_ctloutput(so, sopt) 114411819Sjulian struct socket *so; 114538482Swollman struct sockopt *sopt; 114611819Sjulian{ 114711819Sjulian struct ipxpcb *ipxp = sotoipxpcb(so); 114811819Sjulian register struct spxpcb *cb; 114938482Swollman int mask, error; 115038482Swollman short soptval; 115138482Swollman u_short usoptval; 115238482Swollman int optval; 115311819Sjulian 115438482Swollman error = 0; 115538482Swollman 115638482Swollman if (sopt->sopt_level != IPXPROTO_SPX) { 115711819Sjulian /* This will have to be changed when we do more general 115811819Sjulian stacking of protocols */ 115938482Swollman return (ipx_ctloutput(so, sopt)); 116011819Sjulian } 116138482Swollman if (ipxp == NULL) 116238482Swollman return (EINVAL); 116338482Swollman else 116411819Sjulian cb = ipxtospxpcb(ipxp); 116511819Sjulian 116638482Swollman switch (sopt->sopt_dir) { 116738482Swollman case SOPT_GET: 116838482Swollman switch (sopt->sopt_name) { 116911819Sjulian case SO_HEADERS_ON_INPUT: 117011819Sjulian mask = SF_HI; 117111819Sjulian goto get_flags; 117211819Sjulian 117311819Sjulian case SO_HEADERS_ON_OUTPUT: 117411819Sjulian mask = SF_HO; 117511819Sjulian get_flags: 117638482Swollman soptval = cb->s_flags & mask; 117738482Swollman error = sooptcopyout(sopt, &soptval, sizeof soptval); 117811819Sjulian break; 117911819Sjulian 118011819Sjulian case SO_MTU: 118138482Swollman usoptval = cb->s_mtu; 118238482Swollman error = sooptcopyout(sopt, &usoptval, sizeof usoptval); 118311819Sjulian break; 118411819Sjulian 118511819Sjulian case SO_LAST_HEADER: 118638482Swollman error = sooptcopyout(sopt, &cb->s_rhdr, 118738482Swollman sizeof cb->s_rhdr); 118811819Sjulian break; 118911819Sjulian 119011819Sjulian case SO_DEFAULT_HEADERS: 119138482Swollman error = sooptcopyout(sopt, &cb->s_shdr, 119238482Swollman sizeof cb->s_shdr); 119311819Sjulian break; 119411819Sjulian 119511819Sjulian default: 119638482Swollman error = ENOPROTOOPT; 119711819Sjulian } 119811819Sjulian break; 119911819Sjulian 120038482Swollman case SOPT_SET: 120138482Swollman switch (sopt->sopt_name) { 120238482Swollman /* XXX why are these shorts on get and ints on set? 120338482Swollman that doesn't make any sense... */ 120411819Sjulian case SO_HEADERS_ON_INPUT: 120511819Sjulian mask = SF_HI; 120611819Sjulian goto set_head; 120711819Sjulian 120811819Sjulian case SO_HEADERS_ON_OUTPUT: 120911819Sjulian mask = SF_HO; 121011819Sjulian set_head: 121138482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 121238482Swollman sizeof optval); 121338482Swollman if (error) 121438482Swollman break; 121538482Swollman 121611819Sjulian if (cb->s_flags & SF_PI) { 121738482Swollman if (optval) 121811819Sjulian cb->s_flags |= mask; 121911819Sjulian else 122011819Sjulian cb->s_flags &= ~mask; 122111819Sjulian } else error = EINVAL; 122211819Sjulian break; 122311819Sjulian 122411819Sjulian case SO_MTU: 122538482Swollman error = sooptcopyin(sopt, &usoptval, sizeof usoptval, 122638482Swollman sizeof usoptval); 122738482Swollman if (error) 122838482Swollman break; 122938482Swollman cb->s_mtu = usoptval; 123011819Sjulian break; 123111819Sjulian 123211819Sjulian#ifdef SF_NEWCALL 123311819Sjulian case SO_NEWCALL: 123438482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 123538482Swollman sizeof optval); 123638482Swollman if (error) 123738482Swollman break; 123838482Swollman if (optval) { 123911819Sjulian cb->s_flags2 |= SF_NEWCALL; 124011819Sjulian spx_newchecks[5]++; 124111819Sjulian } else { 124211819Sjulian cb->s_flags2 &= ~SF_NEWCALL; 124311819Sjulian spx_newchecks[6]++; 124411819Sjulian } 124511819Sjulian break; 124611819Sjulian#endif 124711819Sjulian 124811819Sjulian case SO_DEFAULT_HEADERS: 124911819Sjulian { 125038482Swollman struct spxhdr sp; 125138482Swollman 125238482Swollman error = sooptcopyin(sopt, &sp, sizeof sp, 125338482Swollman sizeof sp); 125438482Swollman if (error) 125538482Swollman break; 125638482Swollman cb->s_dt = sp.spx_dt; 125738482Swollman cb->s_cc = sp.spx_cc & SPX_EM; 125811819Sjulian } 125911819Sjulian break; 126011819Sjulian 126111819Sjulian default: 126238482Swollman error = ENOPROTOOPT; 126311819Sjulian } 126411819Sjulian break; 126511819Sjulian } 126638482Swollman return (error); 126711819Sjulian} 126811819Sjulian 126924659Sjhaystatic int 127024659Sjhayspx_usr_abort(so) 127111819Sjulian struct socket *so; 127211819Sjulian{ 127324659Sjhay int s; 127424659Sjhay struct ipxpcb *ipxp; 127524659Sjhay struct spxpcb *cb; 127611819Sjulian 127724659Sjhay ipxp = sotoipxpcb(so); 127824659Sjhay cb = ipxtospxpcb(ipxp); 127911819Sjulian 128024659Sjhay s = splnet(); 128124659Sjhay spx_drop(cb, ECONNABORTED); 128224659Sjhay splx(s); 128324659Sjhay return (0); 128424659Sjhay} 128511819Sjulian 128624659Sjhay/* 128724659Sjhay * Accept a connection. Essentially all the work is 128824659Sjhay * done at higher levels; just return the address 128924659Sjhay * of the peer, storing through addr. 129024659Sjhay */ 129124659Sjhaystatic int 129224659Sjhayspx_accept(so, nam) 129324659Sjhay struct socket *so; 129428270Swollman struct sockaddr **nam; 129524659Sjhay{ 129624659Sjhay struct ipxpcb *ipxp; 129728270Swollman struct sockaddr_ipx *sipx, ssipx; 129811819Sjulian 129924659Sjhay ipxp = sotoipxpcb(so); 130028270Swollman sipx = &ssipx; 130128270Swollman bzero(sipx, sizeof *sipx); 130228270Swollman sipx->sipx_len = sizeof *sipx; 130324659Sjhay sipx->sipx_family = AF_IPX; 130424659Sjhay sipx->sipx_addr = ipxp->ipxp_faddr; 1305126425Srwatson *nam = sodupsockaddr((struct sockaddr *)sipx, M_NOWAIT); 130624659Sjhay return (0); 130724659Sjhay} 130824659Sjhay 130924659Sjhaystatic int 131083366Sjulianspx_attach(so, proto, td) 131124659Sjhay struct socket *so; 131224659Sjhay int proto; 131383366Sjulian struct thread *td; 131424659Sjhay{ 131524659Sjhay int error; 131624659Sjhay int s; 131724659Sjhay struct ipxpcb *ipxp; 131824659Sjhay struct spxpcb *cb; 131924659Sjhay struct mbuf *mm; 132024659Sjhay struct sockbuf *sb; 132124659Sjhay 132224659Sjhay ipxp = sotoipxpcb(so); 132324659Sjhay cb = ipxtospxpcb(ipxp); 132424659Sjhay 132524659Sjhay if (ipxp != NULL) 132624659Sjhay return (EISCONN); 132724659Sjhay s = splnet(); 132883366Sjulian error = ipx_pcballoc(so, &ipxpcb, td); 132924659Sjhay if (error) 133024659Sjhay goto spx_attach_end; 133124659Sjhay if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 133224659Sjhay error = soreserve(so, (u_long) 3072, (u_long) 3072); 133311819Sjulian if (error) 133424659Sjhay goto spx_attach_end; 133524659Sjhay } 133624659Sjhay ipxp = sotoipxpcb(so); 133711819Sjulian 133869781Sdwmalone MALLOC(cb, struct spxpcb *, sizeof *cb, M_PCB, M_NOWAIT | M_ZERO); 133911819Sjulian 134028270Swollman if (cb == NULL) { 134124659Sjhay error = ENOBUFS; 134224659Sjhay goto spx_attach_end; 134324659Sjhay } 134443711Sjhay sb = &so->so_snd; 134528270Swollman 1346111119Simp 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 137683366Sjulianspx_bind(so, nam, td) 137724659Sjhay struct socket *so; 137828270Swollman struct sockaddr *nam; 137983366Sjulian struct thread *td; 138024659Sjhay{ 138124659Sjhay struct ipxpcb *ipxp; 138211819Sjulian 138324659Sjhay ipxp = sotoipxpcb(so); 138411819Sjulian 138583366Sjulian return (ipx_pcbbind(ipxp, nam, td)); 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 139583366Sjulianspx_connect(so, nam, td) 139624659Sjhay struct socket *so; 139728270Swollman struct sockaddr *nam; 139883366Sjulian struct thread *td; 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) { 141083366Sjulian error = ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td); 141124659Sjhay if (error) 141224659Sjhay goto spx_connect_end; 141324659Sjhay } 141483366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 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 148483366Sjulianspx_listen(so, td) 148524659Sjhay struct socket *so; 148683366Sjulian struct thread *td; 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) 149783366Sjulian error = ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td); 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 || 1540130480Srwatson (so->so_rcv.sb_state & SBS_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 154983366Sjulianspx_send(so, flags, m, addr, controlp, td) 155024659Sjhay struct socket *so; 155124659Sjhay int flags; 155224659Sjhay struct mbuf *m; 155328270Swollman struct sockaddr *addr; 155424659Sjhay struct mbuf *controlp; 155583366Sjulian struct thread *td; 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 161883366Sjulianspx_sp_attach(so, proto, td) 161911819Sjulian struct socket *so; 162024659Sjhay int proto; 162183366Sjulian struct thread *td; 162211819Sjulian{ 162324659Sjhay int error; 162424659Sjhay struct ipxpcb *ipxp; 162511819Sjulian 162683366Sjulian error = spx_attach(so, proto, td); 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); 189697658Stanimura } 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