spx_reass.c revision 179410
1139823Simp/*- 2157067Srwatson * Copyright (c) 1984, 1985, 1986, 1987, 1993 3157067Srwatson * The Regents of the University of California. 4157067Srwatson * Copyright (c) 2004-2006 Robert N. M. Watson 5157067Srwatson * All rights reserved. 611819Sjulian * 711819Sjulian * Redistribution and use in source and binary forms, with or without 811819Sjulian * modification, are permitted provided that the following conditions 911819Sjulian * are met: 1011819Sjulian * 1. Redistributions of source code must retain the above copyright 1111819Sjulian * notice, this list of conditions and the following disclaimer. 1211819Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1311819Sjulian * notice, this list of conditions and the following disclaimer in the 1411819Sjulian * documentation and/or other materials provided with the distribution. 15165899Srwatson * 4. Neither the name of the University nor the names of its contributors 16165899Srwatson * may be used to endorse or promote products derived from this software 17165899Srwatson * without specific prior written permission. 18165899Srwatson * 19165899Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20165899Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21165899Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22165899Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23165899Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24165899Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25165899Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26165899Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27165899Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28165899Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29165899Srwatson * SUCH DAMAGE. 30165899Srwatson * 31165899Srwatson * Copyright (c) 1995, Mike Mitchell 32165899Srwatson * All rights reserved. 33165899Srwatson * 34165899Srwatson * Redistribution and use in source and binary forms, with or without 35165899Srwatson * modification, are permitted provided that the following conditions 36165899Srwatson * are met: 37165899Srwatson * 1. Redistributions of source code must retain the above copyright 38165899Srwatson * notice, this list of conditions and the following disclaimer. 39165899Srwatson * 2. Redistributions in binary form must reproduce the above copyright 40165899Srwatson * notice, this list of conditions and the following disclaimer in the 41165899Srwatson * documentation and/or other materials provided with the distribution. 4211819Sjulian * 3. All advertising materials mentioning features or use of this software 4311819Sjulian * must display the following acknowledgement: 4411819Sjulian * This product includes software developed by the University of 4511819Sjulian * California, Berkeley and its contributors. 4611819Sjulian * 4. Neither the name of the University nor the names of its contributors 4711819Sjulian * may be used to endorse or promote products derived from this software 4811819Sjulian * without specific prior written permission. 4911819Sjulian * 5011819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5111819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5211819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5311819Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5411819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5511819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5611819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5711819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5811819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5911819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6011819Sjulian * SUCH DAMAGE. 6111819Sjulian * 6212057Sjulian * @(#)spx_usrreq.h 6311819Sjulian */ 6411819Sjulian 65116189Sobrien#include <sys/cdefs.h> 66116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/spx_usrreq.c 179410 2008-05-29 07:18:43Z rwatson $"); 67116189Sobrien 6811819Sjulian#include <sys/param.h> 6976166Smarkm#include <sys/lock.h> 7029024Sbde#include <sys/malloc.h> 7111819Sjulian#include <sys/mbuf.h> 7276166Smarkm#include <sys/mutex.h> 7325345Sjhay#include <sys/proc.h> 7411819Sjulian#include <sys/protosw.h> 7595759Stanimura#include <sys/signalvar.h> 7611819Sjulian#include <sys/socket.h> 7711819Sjulian#include <sys/socketvar.h> 7895759Stanimura#include <sys/sx.h> 7995759Stanimura#include <sys/systm.h> 8011819Sjulian 8111819Sjulian#include <net/route.h> 8211819Sjulian#include <netinet/tcp_fsm.h> 8311819Sjulian 8411819Sjulian#include <netipx/ipx.h> 8511819Sjulian#include <netipx/ipx_pcb.h> 8611819Sjulian#include <netipx/ipx_var.h> 8711819Sjulian#include <netipx/spx.h> 8895759Stanimura#include <netipx/spx_debug.h> 8911819Sjulian#include <netipx/spx_timer.h> 9011819Sjulian#include <netipx/spx_var.h> 9111819Sjulian 9211819Sjulian/* 9311819Sjulian * SPX protocol implementation. 9411819Sjulian */ 95157069Srwatsonstatic struct mtx spx_mtx; /* Protects only spx_iss. */ 9633181Seivindstatic u_short spx_iss; 9733181Seivindstatic u_short spx_newchecks[50]; 9833181Seivindstatic int spx_hardnosed; 9933181Seivindstatic int spx_use_delack = 0; 10033181Seivindstatic int traceallspxs = 0; 10133181Seivindstatic struct spx_istat spx_istat; 102157068Srwatsonstatic int spxrexmtthresh = 3; 10311819Sjulian 104157069Srwatson#define SPX_LOCK_INIT() mtx_init(&spx_mtx, "spx_mtx", NULL, MTX_DEF) 105157069Srwatson#define SPX_LOCK() mtx_lock(&spx_mtx) 106157069Srwatson#define SPX_UNLOCK() mtx_unlock(&spx_mtx) 107157069Srwatson 10825652Sjhay/* Following was struct spxstat spxstat; */ 109139584Srwatson#ifndef spxstat 11025652Sjhay#define spxstat spx_istat.newstats 111139584Srwatson#endif 11211819Sjulian 113132045Srwatsonstatic const int spx_backoff[SPX_MAXRXTSHIFT+1] = 11425652Sjhay { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 11511819Sjulian 116139931Srwatsonstatic void spx_close(struct spxpcb *cb); 117139931Srwatsonstatic void spx_disconnect(struct spxpcb *cb); 118139931Srwatsonstatic void spx_drop(struct spxpcb *cb, int errno); 11925652Sjhaystatic int spx_output(struct spxpcb *cb, struct mbuf *m0); 12025652Sjhaystatic int spx_reass(struct spxpcb *cb, struct spx *si); 12125652Sjhaystatic void spx_setpersist(struct spxpcb *cb); 12225652Sjhaystatic void spx_template(struct spxpcb *cb); 123157128Srwatsonstatic void spx_timers(struct spxpcb *cb, int timer); 124139931Srwatsonstatic void spx_usrclosed(struct spxpcb *cb); 12525652Sjhay 126157366Srwatsonstatic void spx_usr_abort(struct socket *so); 12728270Swollmanstatic int spx_accept(struct socket *so, struct sockaddr **nam); 12883366Sjulianstatic int spx_attach(struct socket *so, int proto, struct thread *td); 12983366Sjulianstatic int spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 130160549Srwatsonstatic void spx_usr_close(struct socket *so); 13128270Swollmanstatic int spx_connect(struct socket *so, struct sockaddr *nam, 13283366Sjulian struct thread *td); 133157370Srwatsonstatic void spx_detach(struct socket *so); 134157128Srwatsonstatic void spx_pcbdetach(struct ipxpcb *ipxp); 13524659Sjhaystatic int spx_usr_disconnect(struct socket *so); 136151888Srwatsonstatic int spx_listen(struct socket *so, int backlog, struct thread *td); 13724659Sjhaystatic int spx_rcvd(struct socket *so, int flags); 13824659Sjhaystatic int spx_rcvoob(struct socket *so, struct mbuf *m, int flags); 13924659Sjhaystatic int spx_send(struct socket *so, int flags, struct mbuf *m, 140139584Srwatson struct sockaddr *addr, struct mbuf *control, 14183366Sjulian struct thread *td); 14224659Sjhaystatic int spx_shutdown(struct socket *so); 14383366Sjulianstatic int spx_sp_attach(struct socket *so, int proto, struct thread *td); 14424659Sjhay 14524659Sjhaystruct pr_usrreqs spx_usrreqs = { 146137386Sphk .pru_abort = spx_usr_abort, 147137386Sphk .pru_accept = spx_accept, 148137386Sphk .pru_attach = spx_attach, 149137386Sphk .pru_bind = spx_bind, 150137386Sphk .pru_connect = spx_connect, 151137386Sphk .pru_control = ipx_control, 152137386Sphk .pru_detach = spx_detach, 153137386Sphk .pru_disconnect = spx_usr_disconnect, 154137386Sphk .pru_listen = spx_listen, 155137386Sphk .pru_peeraddr = ipx_peeraddr, 156137386Sphk .pru_rcvd = spx_rcvd, 157137386Sphk .pru_rcvoob = spx_rcvoob, 158137386Sphk .pru_send = spx_send, 159137386Sphk .pru_shutdown = spx_shutdown, 160137386Sphk .pru_sockaddr = ipx_sockaddr, 161160549Srwatson .pru_close = spx_usr_close, 16224659Sjhay}; 16324659Sjhay 16424659Sjhaystruct pr_usrreqs spx_usrreq_sps = { 165137386Sphk .pru_abort = spx_usr_abort, 166137386Sphk .pru_accept = spx_accept, 167137386Sphk .pru_attach = spx_sp_attach, 168137386Sphk .pru_bind = spx_bind, 169137386Sphk .pru_connect = spx_connect, 170137386Sphk .pru_control = ipx_control, 171137386Sphk .pru_detach = spx_detach, 172137386Sphk .pru_disconnect = spx_usr_disconnect, 173137386Sphk .pru_listen = spx_listen, 174137386Sphk .pru_peeraddr = ipx_peeraddr, 175137386Sphk .pru_rcvd = spx_rcvd, 176137386Sphk .pru_rcvoob = spx_rcvoob, 177137386Sphk .pru_send = spx_send, 178137386Sphk .pru_shutdown = spx_shutdown, 179137386Sphk .pru_sockaddr = ipx_sockaddr, 180160549Srwatson .pru_close = spx_usr_close, 18124659Sjhay}; 18224659Sjhay 18311819Sjulianvoid 184157067Srwatsonspx_init(void) 18511819Sjulian{ 18611819Sjulian 187157069Srwatson SPX_LOCK_INIT(); 18811819Sjulian spx_iss = 1; /* WRONG !! should fish it out of TODR */ 18911819Sjulian} 19011819Sjulian 19111819Sjulianvoid 192157067Srwatsonspx_input(struct mbuf *m, struct ipxpcb *ipxp) 19311819Sjulian{ 194157067Srwatson struct spxpcb *cb; 195157067Srwatson struct spx *si = mtod(m, struct spx *); 196157067Srwatson struct socket *so; 197157051Srwatson struct spx spx_savesi; 19811819Sjulian int dropsocket = 0; 19911819Sjulian short ostate = 0; 20011819Sjulian 20111819Sjulian spxstat.spxs_rcvtotal++; 202157094Srwatson KASSERT(ipxp != NULL, ("spx_input: ipxpcb == NULL")); 20311819Sjulian 204139932Srwatson /* 205139932Srwatson * spx_input() assumes that the caller will hold both the pcb list 206139932Srwatson * lock and also the ipxp lock. spx_input() will release both before 207139932Srwatson * returning, and may in fact trade in the ipxp lock for another pcb 208139932Srwatson * lock following sonewconn(). 209139932Srwatson */ 210139932Srwatson IPX_LIST_LOCK_ASSERT(); 211139932Srwatson IPX_LOCK_ASSERT(ipxp); 212139932Srwatson 21311819Sjulian cb = ipxtospxpcb(ipxp); 214157128Srwatson KASSERT(cb != NULL, ("spx_input: cb == NULL")); 21511819Sjulian 216157128Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) 217157128Srwatson goto drop; 218157128Srwatson 21911819Sjulian if (m->m_len < sizeof(*si)) { 22025652Sjhay if ((m = m_pullup(m, sizeof(*si))) == NULL) { 221139932Srwatson IPX_UNLOCK(ipxp); 222139932Srwatson IPX_LIST_UNLOCK(); 22311819Sjulian spxstat.spxs_rcvshort++; 22411819Sjulian return; 22511819Sjulian } 22611819Sjulian si = mtod(m, struct spx *); 22711819Sjulian } 22811819Sjulian si->si_seq = ntohs(si->si_seq); 22911819Sjulian si->si_ack = ntohs(si->si_ack); 23011819Sjulian si->si_alo = ntohs(si->si_alo); 23111819Sjulian 23211819Sjulian so = ipxp->ipxp_socket; 233157094Srwatson KASSERT(so != NULL, ("spx_input: so == NULL")); 23411819Sjulian 23511819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) { 23611819Sjulian ostate = cb->s_state; 23711819Sjulian spx_savesi = *si; 23811819Sjulian } 23911819Sjulian if (so->so_options & SO_ACCEPTCONN) { 24011819Sjulian struct spxpcb *ocb = cb; 24111819Sjulian 24211819Sjulian so = sonewconn(so, 0); 243157094Srwatson if (so == NULL) 24411819Sjulian goto drop; 245157094Srwatson 24611819Sjulian /* 24711819Sjulian * This is ugly, but .... 24811819Sjulian * 249157094Srwatson * Mark socket as temporary until we're committed to keeping 250157094Srwatson * it. The code at ``drop'' and ``dropwithreset'' check the 251157094Srwatson * flag dropsocket to see if the temporary socket created 252157094Srwatson * here should be discarded. We mark the socket as 253157094Srwatson * discardable until we're committed to it below in 254157094Srwatson * TCPS_LISTEN. 255157128Srwatson * 256157128Srwatson * XXXRW: In the new world order of real kernel parallelism, 257157128Srwatson * temporarily allocating the socket when we're "not sure" 258157128Srwatson * seems like a bad idea, as we might race to remove it if 259157128Srwatson * the listen socket is closed...? 260157128Srwatson * 261157128Srwatson * We drop the lock of the listen socket ipxp, and acquire 262157128Srwatson * the lock of the new socket ippx. 26311819Sjulian */ 26411819Sjulian dropsocket++; 265139932Srwatson IPX_UNLOCK(ipxp); 26611819Sjulian ipxp = (struct ipxpcb *)so->so_pcb; 267139932Srwatson IPX_LOCK(ipxp); 26811819Sjulian ipxp->ipxp_laddr = si->si_dna; 26911819Sjulian cb = ipxtospxpcb(ipxp); 27011819Sjulian cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ 27111819Sjulian cb->s_flags = ocb->s_flags; /* preserve sockopts */ 27211819Sjulian cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ 27311819Sjulian cb->s_state = TCPS_LISTEN; 27497658Stanimura } 275157094Srwatson IPX_LOCK_ASSERT(ipxp); 27611819Sjulian 27711819Sjulian /* 278157094Srwatson * Packet received on connection. Reset idle time and keep-alive 279157094Srwatson * timer. 28011819Sjulian */ 28111819Sjulian cb->s_idle = 0; 28211819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 28311819Sjulian 28411819Sjulian switch (cb->s_state) { 28511819Sjulian case TCPS_LISTEN:{ 28628270Swollman struct sockaddr_ipx *sipx, ssipx; 28711819Sjulian struct ipx_addr laddr; 28811819Sjulian 28911819Sjulian /* 290157094Srwatson * If somebody here was carying on a conversation and went 291157094Srwatson * away, and his pen pal thinks he can still talk, we get the 292157094Srwatson * misdirected packet. 29311819Sjulian */ 29411819Sjulian if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 29511819Sjulian spx_istat.gonawy++; 29611819Sjulian goto dropwithreset; 29711819Sjulian } 29828270Swollman sipx = &ssipx; 29928270Swollman bzero(sipx, sizeof *sipx); 30011819Sjulian sipx->sipx_len = sizeof(*sipx); 30111819Sjulian sipx->sipx_family = AF_IPX; 30211819Sjulian sipx->sipx_addr = si->si_sna; 30311819Sjulian laddr = ipxp->ipxp_laddr; 30411819Sjulian if (ipx_nullhost(laddr)) 30511819Sjulian ipxp->ipxp_laddr = si->si_dna; 30690361Sjulian if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &thread0)) { 30711819Sjulian ipxp->ipxp_laddr = laddr; 30811819Sjulian spx_istat.noconn++; 30911819Sjulian goto drop; 31011819Sjulian } 31111819Sjulian spx_template(cb); 31211819Sjulian dropsocket = 0; /* committed to socket */ 31311819Sjulian cb->s_did = si->si_sid; 31411819Sjulian cb->s_rack = si->si_ack; 31511819Sjulian cb->s_ralo = si->si_alo; 31611819Sjulian#define THREEWAYSHAKE 31711819Sjulian#ifdef THREEWAYSHAKE 31811819Sjulian cb->s_state = TCPS_SYN_RECEIVED; 31911819Sjulian cb->s_force = 1 + SPXT_KEEP; 32011819Sjulian spxstat.spxs_accepts++; 32111819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 32211819Sjulian } 32311819Sjulian break; 324157094Srwatson 32511819Sjulian case TCPS_SYN_RECEIVED: { 326157094Srwatson /* 327157094Srwatson * This state means that we have heard a response to our 328157094Srwatson * acceptance of their connection. It is probably logically 329157094Srwatson * unnecessary in this implementation. 330157094Srwatson */ 33125652Sjhay if (si->si_did != cb->s_sid) { 33211819Sjulian spx_istat.wrncon++; 33311819Sjulian goto drop; 33411819Sjulian } 33511819Sjulian#endif 33611819Sjulian ipxp->ipxp_fport = si->si_sport; 33711819Sjulian cb->s_timer[SPXT_REXMT] = 0; 33811819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 33911819Sjulian soisconnected(so); 34011819Sjulian cb->s_state = TCPS_ESTABLISHED; 34111819Sjulian spxstat.spxs_accepts++; 34211819Sjulian } 34311819Sjulian break; 34411819Sjulian 34511819Sjulian case TCPS_SYN_SENT: 346157094Srwatson /* 347157094Srwatson * This state means that we have gotten a response to our 348157094Srwatson * attempt to establish a connection. We fill in the data 349157094Srwatson * from the other side, telling us which port to respond to, 350157094Srwatson * instead of the well-known one we might have sent to in the 351157094Srwatson * first place. We also require that this is a response to 352157094Srwatson * our connection id. 353157094Srwatson */ 35425652Sjhay if (si->si_did != cb->s_sid) { 35511819Sjulian spx_istat.notme++; 35611819Sjulian goto drop; 35711819Sjulian } 35811819Sjulian spxstat.spxs_connects++; 35911819Sjulian cb->s_did = si->si_sid; 36011819Sjulian cb->s_rack = si->si_ack; 36111819Sjulian cb->s_ralo = si->si_alo; 36211819Sjulian cb->s_dport = ipxp->ipxp_fport = si->si_sport; 36311819Sjulian cb->s_timer[SPXT_REXMT] = 0; 36411819Sjulian cb->s_flags |= SF_ACKNOW; 36511819Sjulian soisconnected(so); 36611819Sjulian cb->s_state = TCPS_ESTABLISHED; 367179408Srwatson 368157094Srwatson /* 369157094Srwatson * Use roundtrip time of connection request for initial rtt. 370157094Srwatson */ 37111819Sjulian if (cb->s_rtt) { 37211819Sjulian cb->s_srtt = cb->s_rtt << 3; 37311819Sjulian cb->s_rttvar = cb->s_rtt << 1; 37411819Sjulian SPXT_RANGESET(cb->s_rxtcur, 37511819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 37611819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 37711819Sjulian cb->s_rtt = 0; 37811819Sjulian } 37911819Sjulian } 380157094Srwatson 38197658Stanimura if (so->so_options & SO_DEBUG || traceallspxs) 38211819Sjulian spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0); 38311819Sjulian 38425652Sjhay m->m_len -= sizeof(struct ipx); 38525652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 38625652Sjhay m->m_data += sizeof(struct ipx); 38711819Sjulian 388157094Srwatson if (spx_reass(cb, si)) 38925652Sjhay m_freem(m); 39011819Sjulian if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) 391139579Srwatson spx_output(cb, NULL); 39211819Sjulian cb->s_flags &= ~(SF_WIN|SF_RXT); 393139932Srwatson IPX_UNLOCK(ipxp); 394139932Srwatson IPX_LIST_UNLOCK(); 39511819Sjulian return; 39611819Sjulian 39711819Sjuliandropwithreset: 398157094Srwatson IPX_LOCK_ASSERT(ipxp); 399157164Srwatson if (cb == NULL || (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || 400157128Srwatson traceallspxs)) 401157128Srwatson spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 402139932Srwatson IPX_UNLOCK(ipxp); 403130822Srwatson if (dropsocket) { 404130822Srwatson struct socket *head; 405130822Srwatson ACCEPT_LOCK(); 406130822Srwatson KASSERT((so->so_qstate & SQ_INCOMP) != 0, 407130822Srwatson ("spx_input: nascent socket not SQ_INCOMP on soabort()")); 408130822Srwatson head = so->so_head; 409130822Srwatson TAILQ_REMOVE(&head->so_incomp, so, so_list); 410130822Srwatson head->so_incqlen--; 411130822Srwatson so->so_qstate &= ~SQ_INCOMP; 412130822Srwatson so->so_head = NULL; 413130822Srwatson ACCEPT_UNLOCK(); 41425652Sjhay soabort(so); 415130822Srwatson } 416139932Srwatson IPX_LIST_UNLOCK(); 417179332Srwatson m_freem(m); 41811819Sjulian return; 41911819Sjulian 42011819Sjuliandrop: 421157094Srwatson IPX_LOCK_ASSERT(ipxp); 422157128Srwatson if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs) 42311819Sjulian spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 424139932Srwatson IPX_UNLOCK(ipxp); 425139932Srwatson IPX_LIST_UNLOCK(); 42611819Sjulian m_freem(m); 42711819Sjulian} 42811819Sjulian 42911819Sjulian/* 430157094Srwatson * This is structurally similar to the tcp reassembly routine but its 431179408Srwatson * function is somewhat different: it merely queues packets up, and 432157094Srwatson * suppresses duplicates. 43311819Sjulian */ 43425652Sjhaystatic int 435157067Srwatsonspx_reass(struct spxpcb *cb, struct spx *si) 43611819Sjulian{ 437157067Srwatson struct spx_q *q; 438157067Srwatson struct mbuf *m; 439157067Srwatson struct socket *so = cb->s_ipxpcb->ipxp_socket; 44011819Sjulian char packetp = cb->s_flags & SF_HI; 44111819Sjulian int incr; 44211819Sjulian char wakeup = 0; 44311819Sjulian 444139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 445139932Srwatson 44611819Sjulian if (si == SI(0)) 44711819Sjulian goto present; 448179408Srwatson 44911819Sjulian /* 45011819Sjulian * Update our news from them. 45111819Sjulian */ 45211819Sjulian if (si->si_cc & SPX_SA) 45311819Sjulian cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW); 45411819Sjulian if (SSEQ_GT(si->si_alo, cb->s_ralo)) 45511819Sjulian cb->s_flags |= SF_WIN; 45611819Sjulian if (SSEQ_LEQ(si->si_ack, cb->s_rack)) { 45711819Sjulian if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) { 45811819Sjulian spxstat.spxs_rcvdupack++; 459179408Srwatson 46011819Sjulian /* 461157094Srwatson * If this is a completely duplicate ack and other 462157094Srwatson * conditions hold, we assume a packet has been 463157094Srwatson * dropped and retransmit it exactly as in 464157094Srwatson * tcp_input(). 46511819Sjulian */ 46611819Sjulian if (si->si_ack != cb->s_rack || 46711819Sjulian si->si_alo != cb->s_ralo) 46811819Sjulian cb->s_dupacks = 0; 46911819Sjulian else if (++cb->s_dupacks == spxrexmtthresh) { 47011819Sjulian u_short onxt = cb->s_snxt; 47111819Sjulian int cwnd = cb->s_cwnd; 47211819Sjulian 47311819Sjulian cb->s_snxt = si->si_ack; 47411819Sjulian cb->s_cwnd = CUNIT; 47511819Sjulian cb->s_force = 1 + SPXT_REXMT; 476139579Srwatson spx_output(cb, NULL); 47711819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 47811819Sjulian cb->s_rtt = 0; 47911819Sjulian if (cwnd >= 4 * CUNIT) 48011819Sjulian cb->s_cwnd = cwnd / 2; 48111819Sjulian if (SSEQ_GT(onxt, cb->s_snxt)) 48211819Sjulian cb->s_snxt = onxt; 48311819Sjulian return (1); 48411819Sjulian } 48511819Sjulian } else 48611819Sjulian cb->s_dupacks = 0; 48711819Sjulian goto update_window; 48811819Sjulian } 48911819Sjulian cb->s_dupacks = 0; 490157094Srwatson 49111819Sjulian /* 492157094Srwatson * If our correspondent acknowledges data we haven't sent TCP would 493157094Srwatson * drop the packet after acking. We'll be a little more permissive. 49411819Sjulian */ 49511819Sjulian if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) { 49611819Sjulian spxstat.spxs_rcvacktoomuch++; 49711819Sjulian si->si_ack = cb->s_smax + 1; 49811819Sjulian } 49911819Sjulian spxstat.spxs_rcvackpack++; 500157094Srwatson 50111819Sjulian /* 502157094Srwatson * If transmit timer is running and timed sequence number was acked, 503157094Srwatson * update smoothed round trip time. See discussion of algorithm in 504157094Srwatson * tcp_input.c 50511819Sjulian */ 50611819Sjulian if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 50711819Sjulian spxstat.spxs_rttupdated++; 50811819Sjulian if (cb->s_srtt != 0) { 509157067Srwatson short delta; 51011819Sjulian delta = cb->s_rtt - (cb->s_srtt >> 3); 51111819Sjulian if ((cb->s_srtt += delta) <= 0) 51211819Sjulian cb->s_srtt = 1; 51311819Sjulian if (delta < 0) 51411819Sjulian delta = -delta; 51511819Sjulian delta -= (cb->s_rttvar >> 2); 51611819Sjulian if ((cb->s_rttvar += delta) <= 0) 51711819Sjulian cb->s_rttvar = 1; 51811819Sjulian } else { 51911819Sjulian /* 520157094Srwatson * No rtt measurement yet. 52111819Sjulian */ 52211819Sjulian cb->s_srtt = cb->s_rtt << 3; 52311819Sjulian cb->s_rttvar = cb->s_rtt << 1; 52411819Sjulian } 52511819Sjulian cb->s_rtt = 0; 52611819Sjulian cb->s_rxtshift = 0; 52711819Sjulian SPXT_RANGESET(cb->s_rxtcur, 52811819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 52911819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 53011819Sjulian } 531157094Srwatson 53211819Sjulian /* 533157094Srwatson * If all outstanding data is acked, stop retransmit timer and 534157094Srwatson * remember to restart (more output or persist). If there is more 535157094Srwatson * data to be acked, restart retransmit timer, using current 536157094Srwatson * (possibly backed-off) value; 53711819Sjulian */ 53811819Sjulian if (si->si_ack == cb->s_smax + 1) { 53911819Sjulian cb->s_timer[SPXT_REXMT] = 0; 54011819Sjulian cb->s_flags |= SF_RXT; 54111819Sjulian } else if (cb->s_timer[SPXT_PERSIST] == 0) 54211819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 543157094Srwatson 54411819Sjulian /* 545157094Srwatson * When new data is acked, open the congestion window. If the window 546157094Srwatson * gives us less than ssthresh packets in flight, open exponentially 547157094Srwatson * (maxseg at a time). Otherwise open linearly (maxseg^2 / cwnd at a 548157094Srwatson * time). 54911819Sjulian */ 55011819Sjulian incr = CUNIT; 55111819Sjulian if (cb->s_cwnd > cb->s_ssthresh) 55211819Sjulian incr = max(incr * incr / cb->s_cwnd, 1); 55311819Sjulian cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx); 554157094Srwatson 55511819Sjulian /* 55611819Sjulian * Trim Acked data from output queue. 55711819Sjulian */ 558139589Srwatson SOCKBUF_LOCK(&so->so_snd); 55911819Sjulian while ((m = so->so_snd.sb_mb) != NULL) { 56011819Sjulian if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack)) 561139589Srwatson sbdroprecord_locked(&so->so_snd); 56211819Sjulian else 56311819Sjulian break; 56411819Sjulian } 565139589Srwatson sowwakeup_locked(so); 56611819Sjulian cb->s_rack = si->si_ack; 56711819Sjulianupdate_window: 56811819Sjulian if (SSEQ_LT(cb->s_snxt, cb->s_rack)) 56911819Sjulian cb->s_snxt = cb->s_rack; 57043311Sdillon if (SSEQ_LT(cb->s_swl1, si->si_seq) || ((cb->s_swl1 == si->si_seq && 57143311Sdillon (SSEQ_LT(cb->s_swl2, si->si_ack))) || 57243305Sdillon (cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo)))) { 57311819Sjulian /* keep track of pure window updates */ 57411819Sjulian if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack 57511819Sjulian && SSEQ_LT(cb->s_ralo, si->si_alo)) { 57611819Sjulian spxstat.spxs_rcvwinupd++; 57711819Sjulian spxstat.spxs_rcvdupack--; 57811819Sjulian } 57911819Sjulian cb->s_ralo = si->si_alo; 58011819Sjulian cb->s_swl1 = si->si_seq; 58111819Sjulian cb->s_swl2 = si->si_ack; 58211819Sjulian cb->s_swnd = (1 + si->si_alo - si->si_ack); 58311819Sjulian if (cb->s_swnd > cb->s_smxw) 58411819Sjulian cb->s_smxw = cb->s_swnd; 58511819Sjulian cb->s_flags |= SF_WIN; 58611819Sjulian } 587157094Srwatson 58811819Sjulian /* 589157094Srwatson * If this packet number is higher than that which we have allocated 590157094Srwatson * refuse it, unless urgent. 59111819Sjulian */ 59211819Sjulian if (SSEQ_GT(si->si_seq, cb->s_alo)) { 59311819Sjulian if (si->si_cc & SPX_SP) { 59411819Sjulian spxstat.spxs_rcvwinprobe++; 59511819Sjulian return (1); 59611819Sjulian } else 59711819Sjulian spxstat.spxs_rcvpackafterwin++; 59811819Sjulian if (si->si_cc & SPX_OB) { 599179410Srwatson if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) 600179410Srwatson return (1); /* else queue this packet; */ 60111819Sjulian } else { 602139579Srwatson#ifdef BROKEN 603139579Srwatson /* 604139579Srwatson * XXXRW: This is broken on at least one count: 605139579Srwatson * spx_close() will free the ipxp and related parts, 606139579Srwatson * which are then touched by spx_input() after the 607139579Srwatson * return from spx_reass(). 608139579Srwatson */ 609157067Srwatson /*struct socket *so = cb->s_ipxpcb->ipxp_socket; 61011819Sjulian if (so->so_state && SS_NOFDREF) { 61125652Sjhay spx_close(cb); 61297658Stanimura } else 61397658Stanimura would crash system*/ 614139579Srwatson#endif 61511819Sjulian spx_istat.notyet++; 616179410Srwatson return (1); 61711819Sjulian } 61811819Sjulian } 619157094Srwatson 62011819Sjulian /* 621157094Srwatson * If this is a system packet, we don't need to queue it up, and 622157094Srwatson * won't update acknowledge #. 62311819Sjulian */ 624157128Srwatson if (si->si_cc & SPX_SP) 62511819Sjulian return (1); 626157094Srwatson 62711819Sjulian /* 62811819Sjulian * We have already seen this packet, so drop. 62911819Sjulian */ 63011819Sjulian if (SSEQ_LT(si->si_seq, cb->s_ack)) { 63111819Sjulian spx_istat.bdreas++; 63211819Sjulian spxstat.spxs_rcvduppack++; 63311819Sjulian if (si->si_seq == cb->s_ack - 1) 63411819Sjulian spx_istat.lstdup++; 63511819Sjulian return (1); 63611819Sjulian } 637157094Srwatson 63811819Sjulian /* 639157094Srwatson * Loop through all packets queued up to insert in appropriate 640157094Srwatson * sequence. 64111819Sjulian */ 64225652Sjhay for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { 64311819Sjulian if (si->si_seq == SI(q)->si_seq) { 64411819Sjulian spxstat.spxs_rcvduppack++; 64511819Sjulian return (1); 64611819Sjulian } 64711819Sjulian if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { 64811819Sjulian spxstat.spxs_rcvoopack++; 64911819Sjulian break; 65011819Sjulian } 65111819Sjulian } 65211819Sjulian insque(si, q->si_prev); 653179408Srwatson 65411819Sjulian /* 65511819Sjulian * If this packet is urgent, inform process 65611819Sjulian */ 65711819Sjulian if (si->si_cc & SPX_OB) { 65811819Sjulian cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 65911819Sjulian sohasoutofband(so); 66011819Sjulian cb->s_oobflags |= SF_IOOB; 66111819Sjulian } 66211819Sjulianpresent: 66311819Sjulian#define SPINC sizeof(struct spxhdr) 664139590Srwatson SOCKBUF_LOCK(&so->so_rcv); 665157094Srwatson 66611819Sjulian /* 667157094Srwatson * Loop through all packets queued up to update acknowledge number, 668157094Srwatson * and present all acknowledged data to user; if in packet interface 669157094Srwatson * mode, show packet headers. 67011819Sjulian */ 67125652Sjhay for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { 67211819Sjulian if (SI(q)->si_seq == cb->s_ack) { 67311819Sjulian cb->s_ack++; 67411819Sjulian m = dtom(q); 67511819Sjulian if (SI(q)->si_cc & SPX_OB) { 67611819Sjulian cb->s_oobflags &= ~SF_IOOB; 67711819Sjulian if (so->so_rcv.sb_cc) 67811819Sjulian so->so_oobmark = so->so_rcv.sb_cc; 679131031Srwatson else 680130480Srwatson so->so_rcv.sb_state |= SBS_RCVATMARK; 68111819Sjulian } 68211819Sjulian q = q->si_prev; 68311819Sjulian remque(q->si_next); 68411819Sjulian wakeup = 1; 68511819Sjulian spxstat.spxs_rcvpack++; 68611819Sjulian#ifdef SF_NEWCALL 68711819Sjulian if (cb->s_flags2 & SF_NEWCALL) { 68811819Sjulian struct spxhdr *sp = mtod(m, struct spxhdr *); 68911819Sjulian u_char dt = sp->spx_dt; 69011819Sjulian spx_newchecks[4]++; 69111819Sjulian if (dt != cb->s_rhdr.spx_dt) { 69211819Sjulian struct mbuf *mm = 693111119Simp m_getclr(M_DONTWAIT, MT_CONTROL); 69411819Sjulian spx_newchecks[0]++; 69511819Sjulian if (mm != NULL) { 69611819Sjulian u_short *s = 69711819Sjulian mtod(mm, u_short *); 69811819Sjulian cb->s_rhdr.spx_dt = dt; 69911819Sjulian mm->m_len = 5; /*XXX*/ 70011819Sjulian s[0] = 5; 70111819Sjulian s[1] = 1; 70211819Sjulian *(u_char *)(&s[2]) = dt; 703139590Srwatson sbappend_locked(&so->so_rcv, mm); 70411819Sjulian } 70511819Sjulian } 70611819Sjulian if (sp->spx_cc & SPX_OB) { 70711819Sjulian MCHTYPE(m, MT_OOBDATA); 70811819Sjulian spx_newchecks[1]++; 70911819Sjulian so->so_oobmark = 0; 710130480Srwatson so->so_rcv.sb_state &= ~SBS_RCVATMARK; 71111819Sjulian } 71211819Sjulian if (packetp == 0) { 71311819Sjulian m->m_data += SPINC; 71411819Sjulian m->m_len -= SPINC; 71511819Sjulian m->m_pkthdr.len -= SPINC; 71611819Sjulian } 71711819Sjulian if ((sp->spx_cc & SPX_EM) || packetp) { 718139590Srwatson sbappendrecord_locked(&so->so_rcv, m); 71911819Sjulian spx_newchecks[9]++; 72011819Sjulian } else 721139590Srwatson sbappend_locked(&so->so_rcv, m); 72211819Sjulian } else 72311819Sjulian#endif 724157128Srwatson if (packetp) 725139590Srwatson sbappendrecord_locked(&so->so_rcv, m); 726157128Srwatson else { 72711819Sjulian cb->s_rhdr = *mtod(m, struct spxhdr *); 72811819Sjulian m->m_data += SPINC; 72911819Sjulian m->m_len -= SPINC; 73011819Sjulian m->m_pkthdr.len -= SPINC; 731139590Srwatson sbappend_locked(&so->so_rcv, m); 73211819Sjulian } 73311819Sjulian } else 73411819Sjulian break; 73511819Sjulian } 73697658Stanimura if (wakeup) 737139590Srwatson sorwakeup_locked(so); 738139590Srwatson else 739139590Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 74011819Sjulian return (0); 74111819Sjulian} 74211819Sjulian 74311819Sjulianvoid 744157067Srwatsonspx_ctlinput(int cmd, struct sockaddr *arg_as_sa, void *dummy) 74511819Sjulian{ 74611819Sjulian 747157050Srwatson /* Currently, nothing. */ 74811819Sjulian} 74911819Sjulian 75025652Sjhaystatic int 751157067Srwatsonspx_output(struct spxpcb *cb, struct mbuf *m0) 75211819Sjulian{ 75311819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 754157067Srwatson struct mbuf *m; 755157067Srwatson struct spx *si = NULL; 756157067Srwatson struct sockbuf *sb = &so->so_snd; 75711819Sjulian int len = 0, win, rcv_win; 75811819Sjulian short span, off, recordp = 0; 75911819Sjulian u_short alo; 76011819Sjulian int error = 0, sendalot; 76111819Sjulian#ifdef notdef 76211819Sjulian int idle; 76311819Sjulian#endif 76411819Sjulian struct mbuf *mprev; 76511819Sjulian 766139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 767139932Srwatson 76825652Sjhay if (m0 != NULL) { 76911819Sjulian int mtu = cb->s_mtu; 77011819Sjulian int datalen; 771157094Srwatson 77211819Sjulian /* 77311819Sjulian * Make sure that packet isn't too big. 77411819Sjulian */ 77525652Sjhay for (m = m0; m != NULL; m = m->m_next) { 77611819Sjulian mprev = m; 77711819Sjulian len += m->m_len; 77811819Sjulian if (m->m_flags & M_EOR) 77911819Sjulian recordp = 1; 78011819Sjulian } 78111819Sjulian datalen = (cb->s_flags & SF_HO) ? 78225652Sjhay len - sizeof(struct spxhdr) : len; 78311819Sjulian if (datalen > mtu) { 78411819Sjulian if (cb->s_flags & SF_PI) { 78511819Sjulian m_freem(m0); 78611819Sjulian return (EMSGSIZE); 78711819Sjulian } else { 78811819Sjulian int oldEM = cb->s_cc & SPX_EM; 78911819Sjulian 79011819Sjulian cb->s_cc &= ~SPX_EM; 79111819Sjulian while (len > mtu) { 792157167Srwatson m = m_copym(m0, 0, mtu, M_DONTWAIT); 793157167Srwatson if (m == NULL) { 794157167Srwatson cb->s_cc |= oldEM; 795157167Srwatson m_freem(m0); 796157167Srwatson return (ENOBUFS); 797157167Srwatson } 79811819Sjulian if (cb->s_flags & SF_NEWCALL) { 79911819Sjulian struct mbuf *mm = m; 80011819Sjulian spx_newchecks[7]++; 80125652Sjhay while (mm != NULL) { 80211819Sjulian mm->m_flags &= ~M_EOR; 80311819Sjulian mm = mm->m_next; 80411819Sjulian } 80511819Sjulian } 80611819Sjulian error = spx_output(cb, m); 80711819Sjulian if (error) { 80811819Sjulian cb->s_cc |= oldEM; 80911819Sjulian m_freem(m0); 81025652Sjhay return (error); 81111819Sjulian } 81211819Sjulian m_adj(m0, mtu); 81311819Sjulian len -= mtu; 81411819Sjulian } 81511819Sjulian cb->s_cc |= oldEM; 81611819Sjulian } 81711819Sjulian } 818157094Srwatson 81911819Sjulian /* 82011819Sjulian * Force length even, by adding a "garbage byte" if 82111819Sjulian * necessary. 82211819Sjulian */ 82311819Sjulian if (len & 1) { 82411819Sjulian m = mprev; 82511819Sjulian if (M_TRAILINGSPACE(m) >= 1) 82611819Sjulian m->m_len++; 82711819Sjulian else { 828111119Simp struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 82911819Sjulian 83025652Sjhay if (m1 == NULL) { 83111819Sjulian m_freem(m0); 83211819Sjulian return (ENOBUFS); 83311819Sjulian } 83411819Sjulian m1->m_len = 1; 83511819Sjulian *(mtod(m1, u_char *)) = 0; 83611819Sjulian m->m_next = m1; 83711819Sjulian } 83811819Sjulian } 839151967Sandre m = m_gethdr(M_DONTWAIT, MT_DATA); 84025652Sjhay if (m == NULL) { 84111819Sjulian m_freem(m0); 84211819Sjulian return (ENOBUFS); 84311819Sjulian } 844157094Srwatson 84511819Sjulian /* 846157094Srwatson * Fill in mbuf with extended SP header and addresses and 847157094Srwatson * length put into network format. 84811819Sjulian */ 84925652Sjhay MH_ALIGN(m, sizeof(struct spx)); 85025652Sjhay m->m_len = sizeof(struct spx); 85111819Sjulian m->m_next = m0; 85211819Sjulian si = mtod(m, struct spx *); 85311819Sjulian si->si_i = *cb->s_ipx; 85411819Sjulian si->si_s = cb->s_shdr; 85511819Sjulian if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 856157067Srwatson struct spxhdr *sh; 85725652Sjhay if (m0->m_len < sizeof(*sh)) { 85811819Sjulian if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 85925652Sjhay m_free(m); 86011819Sjulian m_freem(m0); 86111819Sjulian return (EINVAL); 86211819Sjulian } 86311819Sjulian m->m_next = m0; 86411819Sjulian } 86511819Sjulian sh = mtod(m0, struct spxhdr *); 86611819Sjulian si->si_dt = sh->spx_dt; 86711819Sjulian si->si_cc |= sh->spx_cc & SPX_EM; 86825652Sjhay m0->m_len -= sizeof(*sh); 86925652Sjhay m0->m_data += sizeof(*sh); 87025652Sjhay len -= sizeof(*sh); 87111819Sjulian } 87211819Sjulian len += sizeof(*si); 87311819Sjulian if ((cb->s_flags2 & SF_NEWCALL) && recordp) { 87425652Sjhay si->si_cc |= SPX_EM; 87511819Sjulian spx_newchecks[8]++; 87611819Sjulian } 87711819Sjulian if (cb->s_oobflags & SF_SOOB) { 87811819Sjulian /* 879157094Srwatson * Per jqj@cornell: Make sure OB packets convey 880157094Srwatson * exactly 1 byte. If the packet is 1 byte or 881157094Srwatson * larger, we have already guaranted there to be at 882157094Srwatson * least one garbage byte for the checksum, and extra 883157094Srwatson * bytes shouldn't hurt! 88411819Sjulian */ 88511819Sjulian if (len > sizeof(*si)) { 88611819Sjulian si->si_cc |= SPX_OB; 88711819Sjulian len = (1 + sizeof(*si)); 88811819Sjulian } 88911819Sjulian } 89011819Sjulian si->si_len = htons((u_short)len); 89111819Sjulian m->m_pkthdr.len = ((len - 1) | 1) + 1; 892157094Srwatson 89311819Sjulian /* 894157094Srwatson * Queue stuff up for output. 89511819Sjulian */ 89611819Sjulian sbappendrecord(sb, m); 89711819Sjulian cb->s_seq++; 89811819Sjulian } 89911819Sjulian#ifdef notdef 90011819Sjulian idle = (cb->s_smax == (cb->s_rack - 1)); 90111819Sjulian#endif 90211819Sjulianagain: 90311819Sjulian sendalot = 0; 90411819Sjulian off = cb->s_snxt - cb->s_rack; 90525652Sjhay win = min(cb->s_swnd, (cb->s_cwnd / CUNIT)); 90611819Sjulian 90711819Sjulian /* 908157094Srwatson * If in persist timeout with window of 0, send a probe. Otherwise, 909179408Srwatson * if window is small but non-zero and timer expired, send what we 910179408Srwatson * can and go into transmit state. 91111819Sjulian */ 91211819Sjulian if (cb->s_force == 1 + SPXT_PERSIST) { 91311819Sjulian if (win != 0) { 91411819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 91511819Sjulian cb->s_rxtshift = 0; 91611819Sjulian } 91711819Sjulian } 91811819Sjulian span = cb->s_seq - cb->s_rack; 91911819Sjulian len = min(span, win) - off; 92011819Sjulian 92111819Sjulian if (len < 0) { 92211819Sjulian /* 923157094Srwatson * Window shrank after we went into it. If window shrank to 924157094Srwatson * 0, cancel pending restransmission and pull s_snxt back to 925157094Srwatson * (closed) window. We will enter persist state below. If 926157094Srwatson * the widndow didn't close completely, just wait for an ACK. 92711819Sjulian */ 92811819Sjulian len = 0; 92911819Sjulian if (win == 0) { 93011819Sjulian cb->s_timer[SPXT_REXMT] = 0; 93111819Sjulian cb->s_snxt = cb->s_rack; 93211819Sjulian } 93311819Sjulian } 93411819Sjulian if (len > 1) 93511819Sjulian sendalot = 1; 93611819Sjulian rcv_win = sbspace(&so->so_rcv); 93711819Sjulian 93811819Sjulian /* 93911819Sjulian * Send if we owe peer an ACK. 94011819Sjulian */ 94111819Sjulian if (cb->s_oobflags & SF_SOOB) { 94211819Sjulian /* 943157094Srwatson * Must transmit this out of band packet. 94411819Sjulian */ 94511819Sjulian cb->s_oobflags &= ~ SF_SOOB; 94611819Sjulian sendalot = 1; 94711819Sjulian spxstat.spxs_sndurg++; 94811819Sjulian goto found; 94911819Sjulian } 95011819Sjulian if (cb->s_flags & SF_ACKNOW) 95111819Sjulian goto send; 95211819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 95311819Sjulian goto send; 954157094Srwatson 95511819Sjulian /* 956157094Srwatson * Silly window can't happen in spx. Code from TCP deleted. 95711819Sjulian */ 95811819Sjulian if (len) 95911819Sjulian goto send; 960157094Srwatson 96111819Sjulian /* 962157094Srwatson * Compare available window to amount of window known to peer (as 963157094Srwatson * advertised window less next expected input.) If the difference is 964157094Srwatson * at least two packets or at least 35% of the mximum possible 965157094Srwatson * window, then want to send a window update to peer. 96611819Sjulian */ 96711819Sjulian if (rcv_win > 0) { 96811819Sjulian u_short delta = 1 + cb->s_alo - cb->s_ack; 96911819Sjulian int adv = rcv_win - (delta * cb->s_mtu); 970139584Srwatson 97111819Sjulian if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || 97211819Sjulian (100 * adv / so->so_rcv.sb_hiwat >= 35)) { 97311819Sjulian spxstat.spxs_sndwinup++; 97411819Sjulian cb->s_flags |= SF_ACKNOW; 97511819Sjulian goto send; 97611819Sjulian } 97711819Sjulian 97811819Sjulian } 979157094Srwatson 98011819Sjulian /* 981157094Srwatson * Many comments from tcp_output.c are appropriate here including ... 98211819Sjulian * If send window is too small, there is data to transmit, and no 983157094Srwatson * retransmit or persist is pending, then go to persist state. If 984157094Srwatson * nothing happens soon, send when timer expires: if window is 985179408Srwatson * non-zero, transmit what we can, otherwise send a probe. 98611819Sjulian */ 98711819Sjulian if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 && 988157128Srwatson cb->s_timer[SPXT_PERSIST] == 0) { 989157128Srwatson cb->s_rxtshift = 0; 990157128Srwatson spx_setpersist(cb); 99111819Sjulian } 992157094Srwatson 99311819Sjulian /* 99411819Sjulian * No reason to send a packet, just return. 99511819Sjulian */ 99611819Sjulian cb->s_outx = 1; 99711819Sjulian return (0); 99811819Sjulian 99911819Sjuliansend: 100011819Sjulian /* 100111819Sjulian * Find requested packet. 100211819Sjulian */ 100311819Sjulian si = 0; 100411819Sjulian if (len > 0) { 100511819Sjulian cb->s_want = cb->s_snxt; 100625652Sjhay for (m = sb->sb_mb; m != NULL; m = m->m_act) { 100711819Sjulian si = mtod(m, struct spx *); 100811819Sjulian if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) 100911819Sjulian break; 101011819Sjulian } 101111819Sjulian found: 101225652Sjhay if (si != NULL) { 101311819Sjulian if (si->si_seq == cb->s_snxt) 101411819Sjulian cb->s_snxt++; 101511819Sjulian else 101611819Sjulian spxstat.spxs_sndvoid++, si = 0; 101711819Sjulian } 101811819Sjulian } 1019157094Srwatson 102011819Sjulian /* 1021157094Srwatson * Update window. 102211819Sjulian */ 102311819Sjulian if (rcv_win < 0) 102411819Sjulian rcv_win = 0; 102511819Sjulian alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); 1026139584Srwatson if (SSEQ_LT(alo, cb->s_alo)) 102711819Sjulian alo = cb->s_alo; 102811819Sjulian 102925652Sjhay if (si != NULL) { 103011819Sjulian /* 1031157094Srwatson * Must make a copy of this packet for ipx_output to monkey 1032157094Srwatson * with. 103311819Sjulian */ 103411819Sjulian m = m_copy(dtom(si), 0, (int)M_COPYALL); 1035157094Srwatson if (m == NULL) 103611819Sjulian return (ENOBUFS); 103711819Sjulian si = mtod(m, struct spx *); 103811819Sjulian if (SSEQ_LT(si->si_seq, cb->s_smax)) 103911819Sjulian spxstat.spxs_sndrexmitpack++; 104011819Sjulian else 104111819Sjulian spxstat.spxs_sndpack++; 104211819Sjulian } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { 104311819Sjulian /* 1044157094Srwatson * Must send an acknowledgement or a probe. 104511819Sjulian */ 104611819Sjulian if (cb->s_force) 104711819Sjulian spxstat.spxs_sndprobe++; 104811819Sjulian if (cb->s_flags & SF_ACKNOW) 104911819Sjulian spxstat.spxs_sndacks++; 1050151967Sandre m = m_gethdr(M_DONTWAIT, MT_DATA); 105125652Sjhay if (m == NULL) 105211819Sjulian return (ENOBUFS); 1053157094Srwatson 105411819Sjulian /* 1055157094Srwatson * Fill in mbuf with extended SP header and addresses and 1056157094Srwatson * length put into network format. 105711819Sjulian */ 105825652Sjhay MH_ALIGN(m, sizeof(struct spx)); 105925652Sjhay m->m_len = sizeof(*si); 106025652Sjhay m->m_pkthdr.len = sizeof(*si); 106111819Sjulian si = mtod(m, struct spx *); 106211819Sjulian si->si_i = *cb->s_ipx; 106311819Sjulian si->si_s = cb->s_shdr; 106411819Sjulian si->si_seq = cb->s_smax + 1; 106525652Sjhay si->si_len = htons(sizeof(*si)); 106611819Sjulian si->si_cc |= SPX_SP; 106711819Sjulian } else { 106811819Sjulian cb->s_outx = 3; 106997658Stanimura if (so->so_options & SO_DEBUG || traceallspxs) 107011819Sjulian spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 107111819Sjulian return (0); 107211819Sjulian } 1073179408Srwatson 107411819Sjulian /* 107511819Sjulian * Stuff checksum and output datagram. 107611819Sjulian */ 107711819Sjulian if ((si->si_cc & SPX_SP) == 0) { 107811819Sjulian if (cb->s_force != (1 + SPXT_PERSIST) || 107911819Sjulian cb->s_timer[SPXT_PERSIST] == 0) { 108011819Sjulian /* 1081139584Srwatson * If this is a new packet and we are not currently 108211819Sjulian * timing anything, time this one. 108311819Sjulian */ 108411819Sjulian if (SSEQ_LT(cb->s_smax, si->si_seq)) { 108511819Sjulian cb->s_smax = si->si_seq; 108611819Sjulian if (cb->s_rtt == 0) { 108711819Sjulian spxstat.spxs_segstimed++; 108811819Sjulian cb->s_rtseq = si->si_seq; 108911819Sjulian cb->s_rtt = 1; 109011819Sjulian } 109111819Sjulian } 1092157094Srwatson 109311819Sjulian /* 1094157094Srwatson * Set rexmt timer if not currently set, initial 1095157094Srwatson * value for retransmit timer is smoothed round-trip 1096157094Srwatson * time + 2 * round-trip time variance. Initialize 1097157094Srwatson * shift counter which is used for backoff of 1098157094Srwatson * retransmit time. 109911819Sjulian */ 110011819Sjulian if (cb->s_timer[SPXT_REXMT] == 0 && 110111819Sjulian cb->s_snxt != cb->s_rack) { 110211819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 110311819Sjulian if (cb->s_timer[SPXT_PERSIST]) { 110411819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 110511819Sjulian cb->s_rxtshift = 0; 110611819Sjulian } 110711819Sjulian } 1108157094Srwatson } else if (SSEQ_LT(cb->s_smax, si->si_seq)) 110911819Sjulian cb->s_smax = si->si_seq; 111011819Sjulian } else if (cb->s_state < TCPS_ESTABLISHED) { 111111819Sjulian if (cb->s_rtt == 0) 111211819Sjulian cb->s_rtt = 1; /* Time initial handshake */ 111311819Sjulian if (cb->s_timer[SPXT_REXMT] == 0) 111411819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 111511819Sjulian } 111611819Sjulian 1117157094Srwatson /* 1118157094Srwatson * Do not request acks when we ack their data packets or when we do a 1119157094Srwatson * gratuitous window update. 1120157094Srwatson */ 1121157094Srwatson if (((si->si_cc & SPX_SP) == 0) || cb->s_force) 1122157094Srwatson si->si_cc |= SPX_SA; 1123157094Srwatson si->si_seq = htons(si->si_seq); 1124157094Srwatson si->si_alo = htons(alo); 1125157094Srwatson si->si_ack = htons(cb->s_ack); 112611819Sjulian 1127157094Srwatson if (ipxcksum) 1128157094Srwatson si->si_sum = ipx_cksum(m, ntohs(si->si_len)); 1129157094Srwatson else 1130157094Srwatson si->si_sum = 0xffff; 113111819Sjulian 1132157094Srwatson cb->s_outx = 4; 1133157094Srwatson if (so->so_options & SO_DEBUG || traceallspxs) 1134157094Srwatson spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 1135157094Srwatson 1136157094Srwatson if (so->so_options & SO_DONTROUTE) 1137157094Srwatson error = ipx_outputfl(m, NULL, IPX_ROUTETOIF); 1138157094Srwatson else 1139157094Srwatson error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0); 1140157094Srwatson if (error) 114111819Sjulian return (error); 114211819Sjulian spxstat.spxs_sndtotal++; 1143157094Srwatson 114411819Sjulian /* 1145157094Srwatson * Data sent (as far as we can tell). If this advertises a larger 1146157094Srwatson * window than any other segment, then remember the size of the 1147157094Srwatson * advertized window. Any pending ACK has now been sent. 114811819Sjulian */ 114911819Sjulian cb->s_force = 0; 115011819Sjulian cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); 115111819Sjulian if (SSEQ_GT(alo, cb->s_alo)) 115211819Sjulian cb->s_alo = alo; 115311819Sjulian if (sendalot) 115411819Sjulian goto again; 115511819Sjulian cb->s_outx = 5; 115611819Sjulian return (0); 115711819Sjulian} 115811819Sjulian 115933181Seivindstatic int spx_do_persist_panics = 0; 116011819Sjulian 116125652Sjhaystatic void 1162157067Srwatsonspx_setpersist(struct spxpcb *cb) 116311819Sjulian{ 1164157067Srwatson int t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 116511819Sjulian 1166139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 1167139932Srwatson 116811819Sjulian if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics) 116911819Sjulian panic("spx_output REXMT"); 1170157094Srwatson 117111819Sjulian /* 117211819Sjulian * Start/restart persistance timer. 117311819Sjulian */ 117411819Sjulian SPXT_RANGESET(cb->s_timer[SPXT_PERSIST], 117511819Sjulian t*spx_backoff[cb->s_rxtshift], 117611819Sjulian SPXTV_PERSMIN, SPXTV_PERSMAX); 117711819Sjulian if (cb->s_rxtshift < SPX_MAXRXTSHIFT) 117811819Sjulian cb->s_rxtshift++; 117911819Sjulian} 118025652Sjhay 118111819Sjulianint 1182157067Srwatsonspx_ctloutput(struct socket *so, struct sockopt *sopt) 118311819Sjulian{ 1184157125Srwatson struct spxhdr spxhdr; 1185157125Srwatson struct ipxpcb *ipxp; 1186157067Srwatson struct spxpcb *cb; 118738482Swollman int mask, error; 118838482Swollman short soptval; 118938482Swollman u_short usoptval; 119038482Swollman int optval; 119111819Sjulian 1192157128Srwatson ipxp = sotoipxpcb(so); 1193157128Srwatson KASSERT(ipxp != NULL, ("spx_ctloutput: ipxp == NULL")); 1194157128Srwatson 1195157094Srwatson /* 1196157094Srwatson * This will have to be changed when we do more general stacking of 1197157094Srwatson * protocols. 1198157094Srwatson */ 1199157094Srwatson if (sopt->sopt_level != IPXPROTO_SPX) 120038482Swollman return (ipx_ctloutput(so, sopt)); 1201157125Srwatson 1202157128Srwatson IPX_LOCK(ipxp); 1203157128Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1204157128Srwatson IPX_UNLOCK(ipxp); 1205157128Srwatson return (ECONNRESET); 1206157128Srwatson } 1207157125Srwatson 1208157125Srwatson IPX_LOCK(ipxp); 1209157125Srwatson cb = ipxtospxpcb(ipxp); 1210157094Srwatson KASSERT(cb != NULL, ("spx_ctloutput: cb == NULL")); 121111819Sjulian 1212157125Srwatson error = 0; 121338482Swollman switch (sopt->sopt_dir) { 121438482Swollman case SOPT_GET: 121538482Swollman switch (sopt->sopt_name) { 121611819Sjulian case SO_HEADERS_ON_INPUT: 121711819Sjulian mask = SF_HI; 121811819Sjulian goto get_flags; 121911819Sjulian 122011819Sjulian case SO_HEADERS_ON_OUTPUT: 122111819Sjulian mask = SF_HO; 122211819Sjulian get_flags: 122338482Swollman soptval = cb->s_flags & mask; 1224157125Srwatson IPX_UNLOCK(ipxp); 1225157125Srwatson error = sooptcopyout(sopt, &soptval, 1226157125Srwatson sizeof(soptval)); 122711819Sjulian break; 122811819Sjulian 122911819Sjulian case SO_MTU: 123038482Swollman usoptval = cb->s_mtu; 1231157125Srwatson IPX_UNLOCK(ipxp); 1232157125Srwatson error = sooptcopyout(sopt, &usoptval, 1233157125Srwatson sizeof(usoptval)); 123411819Sjulian break; 123511819Sjulian 123611819Sjulian case SO_LAST_HEADER: 1237157125Srwatson spxhdr = cb->s_rhdr; 1238157125Srwatson IPX_UNLOCK(ipxp); 1239157125Srwatson error = sooptcopyout(sopt, &spxhdr, sizeof(spxhdr)); 124011819Sjulian break; 124111819Sjulian 124211819Sjulian case SO_DEFAULT_HEADERS: 1243157125Srwatson spxhdr = cb->s_shdr; 1244157125Srwatson IPX_UNLOCK(ipxp); 1245157125Srwatson error = sooptcopyout(sopt, &spxhdr, sizeof(spxhdr)); 124611819Sjulian break; 124711819Sjulian 124811819Sjulian default: 1249157125Srwatson IPX_UNLOCK(ipxp); 125038482Swollman error = ENOPROTOOPT; 125111819Sjulian } 125211819Sjulian break; 125311819Sjulian 125438482Swollman case SOPT_SET: 1255157094Srwatson /* 1256157094Srwatson * XXX Why are these shorts on get and ints on set? That 1257157094Srwatson * doesn't make any sense... 1258157128Srwatson * 1259157128Srwatson * XXXRW: Note, when we re-acquire the ipxp lock, we should 1260157128Srwatson * re-check that it's not dropped. 1261157094Srwatson */ 1262157125Srwatson IPX_UNLOCK(ipxp); 126338482Swollman switch (sopt->sopt_name) { 126411819Sjulian case SO_HEADERS_ON_INPUT: 126511819Sjulian mask = SF_HI; 126611819Sjulian goto set_head; 126711819Sjulian 126811819Sjulian case SO_HEADERS_ON_OUTPUT: 126911819Sjulian mask = SF_HO; 127011819Sjulian set_head: 127138482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 127238482Swollman sizeof optval); 127338482Swollman if (error) 127438482Swollman break; 127538482Swollman 1276139932Srwatson IPX_LOCK(ipxp); 127711819Sjulian if (cb->s_flags & SF_PI) { 127838482Swollman if (optval) 127911819Sjulian cb->s_flags |= mask; 128011819Sjulian else 128111819Sjulian cb->s_flags &= ~mask; 128211819Sjulian } else error = EINVAL; 1283139932Srwatson IPX_UNLOCK(ipxp); 128411819Sjulian break; 128511819Sjulian 128611819Sjulian case SO_MTU: 128738482Swollman error = sooptcopyin(sopt, &usoptval, sizeof usoptval, 128838482Swollman sizeof usoptval); 128938482Swollman if (error) 129038482Swollman break; 1291139932Srwatson /* Unlocked write. */ 129238482Swollman cb->s_mtu = usoptval; 129311819Sjulian break; 129411819Sjulian 129511819Sjulian#ifdef SF_NEWCALL 129611819Sjulian case SO_NEWCALL: 129738482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 129838482Swollman sizeof optval); 129938482Swollman if (error) 130038482Swollman break; 1301139932Srwatson IPX_LOCK(ipxp); 130238482Swollman if (optval) { 130311819Sjulian cb->s_flags2 |= SF_NEWCALL; 130411819Sjulian spx_newchecks[5]++; 130511819Sjulian } else { 130611819Sjulian cb->s_flags2 &= ~SF_NEWCALL; 130711819Sjulian spx_newchecks[6]++; 130811819Sjulian } 1309139932Srwatson IPX_UNLOCK(ipxp); 131011819Sjulian break; 131111819Sjulian#endif 131211819Sjulian 131311819Sjulian case SO_DEFAULT_HEADERS: 131411819Sjulian { 131538482Swollman struct spxhdr sp; 131638482Swollman 131738482Swollman error = sooptcopyin(sopt, &sp, sizeof sp, 131838482Swollman sizeof sp); 131938482Swollman if (error) 132038482Swollman break; 1321139932Srwatson IPX_LOCK(ipxp); 132238482Swollman cb->s_dt = sp.spx_dt; 132338482Swollman cb->s_cc = sp.spx_cc & SPX_EM; 1324139932Srwatson IPX_UNLOCK(ipxp); 132511819Sjulian } 132611819Sjulian break; 132711819Sjulian 132811819Sjulian default: 132938482Swollman error = ENOPROTOOPT; 133011819Sjulian } 133111819Sjulian break; 1332157125Srwatson 1333157125Srwatson default: 1334157125Srwatson panic("spx_ctloutput: bad socket option direction"); 133511819Sjulian } 133638482Swollman return (error); 133711819Sjulian} 133811819Sjulian 1339157366Srwatsonstatic void 1340157067Srwatsonspx_usr_abort(struct socket *so) 134111819Sjulian{ 134224659Sjhay struct ipxpcb *ipxp; 134324659Sjhay struct spxpcb *cb; 134411819Sjulian 134524659Sjhay ipxp = sotoipxpcb(so); 1346157094Srwatson KASSERT(ipxp != NULL, ("spx_usr_abort: ipxp == NULL")); 1347157094Srwatson 134824659Sjhay cb = ipxtospxpcb(ipxp); 1349157094Srwatson KASSERT(cb != NULL, ("spx_usr_abort: cb == NULL")); 135011819Sjulian 1351139932Srwatson IPX_LIST_LOCK(); 1352139932Srwatson IPX_LOCK(ipxp); 135324659Sjhay spx_drop(cb, ECONNABORTED); 1354160549Srwatson IPX_UNLOCK(ipxp); 1355139932Srwatson IPX_LIST_UNLOCK(); 135624659Sjhay} 135711819Sjulian 135824659Sjhay/* 1359157094Srwatson * Accept a connection. Essentially all the work is done at higher levels; 1360157094Srwatson * just return the address of the peer, storing through addr. 136124659Sjhay */ 136224659Sjhaystatic int 1363157067Srwatsonspx_accept(struct socket *so, struct sockaddr **nam) 136424659Sjhay{ 136524659Sjhay struct ipxpcb *ipxp; 136628270Swollman struct sockaddr_ipx *sipx, ssipx; 136711819Sjulian 136824659Sjhay ipxp = sotoipxpcb(so); 1369157154Srwatson KASSERT(ipxp != NULL, ("spx_accept: ipxp == NULL")); 1370157094Srwatson 137128270Swollman sipx = &ssipx; 137228270Swollman bzero(sipx, sizeof *sipx); 137328270Swollman sipx->sipx_len = sizeof *sipx; 137424659Sjhay sipx->sipx_family = AF_IPX; 1375139932Srwatson IPX_LOCK(ipxp); 137624659Sjhay sipx->sipx_addr = ipxp->ipxp_faddr; 1377139932Srwatson IPX_UNLOCK(ipxp); 1378139932Srwatson *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK); 137924659Sjhay return (0); 138024659Sjhay} 138124659Sjhay 138224659Sjhaystatic int 1383157067Srwatsonspx_attach(struct socket *so, int proto, struct thread *td) 138424659Sjhay{ 138524659Sjhay struct ipxpcb *ipxp; 138624659Sjhay struct spxpcb *cb; 138724659Sjhay struct mbuf *mm; 138824659Sjhay struct sockbuf *sb; 1389139932Srwatson int error; 139024659Sjhay 139124659Sjhay ipxp = sotoipxpcb(so); 1392157094Srwatson KASSERT(ipxp == NULL, ("spx_attach: ipxp != NULL")); 139324659Sjhay 139424659Sjhay if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 139524659Sjhay error = soreserve(so, (u_long) 3072, (u_long) 3072); 139611819Sjulian if (error) 1397157127Srwatson return (error); 139824659Sjhay } 139911819Sjulian 140069781Sdwmalone MALLOC(cb, struct spxpcb *, sizeof *cb, M_PCB, M_NOWAIT | M_ZERO); 1401157127Srwatson if (cb == NULL) 1402157127Srwatson return (ENOBUFS); 1403151967Sandre mm = m_getclr(M_DONTWAIT, MT_DATA); 140424659Sjhay if (mm == NULL) { 140528270Swollman FREE(cb, M_PCB); 1406157127Srwatson return (ENOBUFS); 140724659Sjhay } 1408157127Srwatson 1409157127Srwatson IPX_LIST_LOCK(); 1410157127Srwatson error = ipx_pcballoc(so, &ipxpcb_list, td); 1411157127Srwatson if (error) { 1412157127Srwatson IPX_LIST_UNLOCK(); 1413157127Srwatson m_free(mm); 1414157127Srwatson FREE(cb, M_PCB); 1415157127Srwatson return (error); 1416157127Srwatson } 1417157127Srwatson ipxp = sotoipxpcb(so); 1418157145Srwatson ipxp->ipxp_flags |= IPXP_SPX; 1419157127Srwatson 142024659Sjhay cb->s_ipx = mtod(mm, struct ipx *); 142124659Sjhay cb->s_state = TCPS_LISTEN; 142224659Sjhay cb->s_smax = -1; 142324659Sjhay cb->s_swl1 = -1; 142424659Sjhay cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 142524659Sjhay cb->s_ipxpcb = ipxp; 142625652Sjhay cb->s_mtu = 576 - sizeof(struct spx); 1427157094Srwatson sb = &so->so_snd; 142824659Sjhay cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; 142924659Sjhay cb->s_ssthresh = cb->s_cwnd; 143025652Sjhay cb->s_cwmx = sbspace(sb) * CUNIT / (2 * sizeof(struct spx)); 1431179408Srwatson 1432157094Srwatson /* 1433157094Srwatson * Above is recomputed when connecting to account for changed 1434157094Srwatson * buffering or mtu's. 1435157094Srwatson */ 143624659Sjhay cb->s_rtt = SPXTV_SRTTBASE; 143724659Sjhay cb->s_rttvar = SPXTV_SRTTDFLT << 2; 143824659Sjhay SPXT_RANGESET(cb->s_rxtcur, 143924659Sjhay ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1, 144024659Sjhay SPXTV_MIN, SPXTV_REXMTMAX); 1441139584Srwatson ipxp->ipxp_pcb = (caddr_t)cb; 1442139932Srwatson IPX_LIST_UNLOCK(); 1443157128Srwatson return (0); 144424659Sjhay} 144511819Sjulian 1446157128Srwatsonstatic void 1447157128Srwatsonspx_pcbdetach(struct ipxpcb *ipxp) 1448157128Srwatson{ 1449157128Srwatson struct spxpcb *cb; 1450157128Srwatson struct spx_q *s; 1451157128Srwatson struct mbuf *m; 1452157128Srwatson 1453157128Srwatson IPX_LOCK_ASSERT(ipxp); 1454157128Srwatson 1455157128Srwatson cb = ipxtospxpcb(ipxp); 1456157128Srwatson KASSERT(cb != NULL, ("spx_pcbdetach: cb == NULL")); 1457157128Srwatson 1458157140Srwatson s = cb->s_q.si_next; 1459157140Srwatson while (s != &(cb->s_q)) { 1460157140Srwatson s = s->si_next; 1461157128Srwatson remque(s); 1462157128Srwatson m = dtom(s); 1463157128Srwatson m_freem(m); 1464157128Srwatson } 1465157128Srwatson m_free(dtom(cb->s_ipx)); 1466157128Srwatson FREE(cb, M_PCB); 1467157128Srwatson ipxp->ipxp_pcb = NULL; 1468157128Srwatson} 1469157128Srwatson 147024659Sjhaystatic int 1471157067Srwatsonspx_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 1472139584Srwatson{ 147324659Sjhay struct ipxpcb *ipxp; 1474139932Srwatson int error; 147511819Sjulian 147624659Sjhay ipxp = sotoipxpcb(so); 1477157094Srwatson KASSERT(ipxp != NULL, ("spx_bind: ipxp == NULL")); 147811819Sjulian 1479139932Srwatson IPX_LIST_LOCK(); 1480139932Srwatson IPX_LOCK(ipxp); 1481157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1482157153Srwatson error = EINVAL; 1483157153Srwatson goto out; 1484157153Srwatson } 1485139932Srwatson error = ipx_pcbbind(ipxp, nam, td); 1486157153Srwatsonout: 1487139932Srwatson IPX_UNLOCK(ipxp); 1488139932Srwatson IPX_LIST_UNLOCK(); 1489139932Srwatson return (error); 1490139584Srwatson} 1491139584Srwatson 1492160549Srwatsonstatic void 1493160549Srwatsonspx_usr_close(struct socket *so) 1494160549Srwatson{ 1495160549Srwatson struct ipxpcb *ipxp; 1496160549Srwatson struct spxpcb *cb; 1497160549Srwatson 1498160549Srwatson ipxp = sotoipxpcb(so); 1499160549Srwatson KASSERT(ipxp != NULL, ("spx_usr_close: ipxp == NULL")); 1500160549Srwatson 1501160549Srwatson cb = ipxtospxpcb(ipxp); 1502160549Srwatson KASSERT(cb != NULL, ("spx_usr_close: cb == NULL")); 1503160549Srwatson 1504160549Srwatson IPX_LIST_LOCK(); 1505160549Srwatson IPX_LOCK(ipxp); 1506160549Srwatson if (cb->s_state > TCPS_LISTEN) 1507160549Srwatson spx_disconnect(cb); 1508160549Srwatson else 1509160549Srwatson spx_close(cb); 1510160549Srwatson IPX_UNLOCK(ipxp); 1511160549Srwatson IPX_LIST_UNLOCK(); 1512160549Srwatson} 1513160549Srwatson 151424659Sjhay/* 1515157094Srwatson * Initiate connection to peer. Enter SYN_SENT state, and mark socket as 1516157094Srwatson * connecting. Start keep-alive timer, setup prototype header, send initial 1517157094Srwatson * system packet requesting connection. 151824659Sjhay */ 151924659Sjhaystatic int 1520157067Srwatsonspx_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 152124659Sjhay{ 152224659Sjhay struct ipxpcb *ipxp; 152324659Sjhay struct spxpcb *cb; 1524139932Srwatson int error; 152511819Sjulian 152624659Sjhay ipxp = sotoipxpcb(so); 1527157094Srwatson KASSERT(ipxp != NULL, ("spx_connect: ipxp == NULL")); 1528157094Srwatson 152924659Sjhay cb = ipxtospxpcb(ipxp); 1530157094Srwatson KASSERT(cb != NULL, ("spx_connect: cb == NULL")); 153124659Sjhay 1532139932Srwatson IPX_LIST_LOCK(); 1533139932Srwatson IPX_LOCK(ipxp); 1534157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1535157153Srwatson error = EINVAL; 1536157153Srwatson goto spx_connect_end; 1537157153Srwatson } 153824659Sjhay if (ipxp->ipxp_lport == 0) { 1539139579Srwatson error = ipx_pcbbind(ipxp, NULL, td); 154024659Sjhay if (error) 154124659Sjhay goto spx_connect_end; 154224659Sjhay } 154383366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 154424659Sjhay if (error) 154524659Sjhay goto spx_connect_end; 154624659Sjhay soisconnecting(so); 154724659Sjhay spxstat.spxs_connattempt++; 154824659Sjhay cb->s_state = TCPS_SYN_SENT; 154924659Sjhay cb->s_did = 0; 155024659Sjhay spx_template(cb); 155124659Sjhay cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 155224659Sjhay cb->s_force = 1 + SPXTV_KEEP; 1553179408Srwatson 155411819Sjulian /* 1555157094Srwatson * Other party is required to respond to the port I send from, but he 1556157094Srwatson * is not required to answer from where I am sending to, so allow 1557157094Srwatson * wildcarding. Original port I am sending to is still saved in 155824659Sjhay * cb->s_dport. 155911819Sjulian */ 156024659Sjhay ipxp->ipxp_fport = 0; 1561139579Srwatson error = spx_output(cb, NULL); 156224659Sjhayspx_connect_end: 1563139932Srwatson IPX_UNLOCK(ipxp); 1564139932Srwatson IPX_LIST_UNLOCK(); 156524659Sjhay return (error); 156624659Sjhay} 156711819Sjulian 1568157370Srwatsonstatic void 1569157067Srwatsonspx_detach(struct socket *so) 157024659Sjhay{ 157124659Sjhay struct ipxpcb *ipxp; 157224659Sjhay struct spxpcb *cb; 157311819Sjulian 1574160549Srwatson /* 1575160549Srwatson * XXXRW: Should assert appropriately detached. 1576160549Srwatson */ 157724659Sjhay ipxp = sotoipxpcb(so); 1578157094Srwatson KASSERT(ipxp != NULL, ("spx_detach: ipxp == NULL")); 1579157094Srwatson 158024659Sjhay cb = ipxtospxpcb(ipxp); 1581157094Srwatson KASSERT(cb != NULL, ("spx_detach: cb == NULL")); 158211819Sjulian 1583139932Srwatson IPX_LIST_LOCK(); 1584139932Srwatson IPX_LOCK(ipxp); 1585157128Srwatson spx_pcbdetach(ipxp); 1586157128Srwatson ipx_pcbfree(ipxp); 1587139932Srwatson IPX_LIST_UNLOCK(); 158824659Sjhay} 158911819Sjulian 159024659Sjhay/* 1591157094Srwatson * We may decide later to implement connection closing handshaking at the spx 1592157094Srwatson * level optionally. Here is the hook to do it: 159324659Sjhay */ 159424659Sjhaystatic int 1595157067Srwatsonspx_usr_disconnect(struct socket *so) 159624659Sjhay{ 159724659Sjhay struct ipxpcb *ipxp; 159824659Sjhay struct spxpcb *cb; 1599157153Srwatson int error; 160011819Sjulian 160124659Sjhay ipxp = sotoipxpcb(so); 1602157094Srwatson KASSERT(ipxp != NULL, ("spx_usr_disconnect: ipxp == NULL")); 1603157094Srwatson 160424659Sjhay cb = ipxtospxpcb(ipxp); 1605157094Srwatson KASSERT(cb != NULL, ("spx_usr_disconnect: cb == NULL")); 160611819Sjulian 1607139932Srwatson IPX_LIST_LOCK(); 1608139932Srwatson IPX_LOCK(ipxp); 1609157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1610157153Srwatson error = EINVAL; 1611157153Srwatson goto out; 1612157153Srwatson } 161324659Sjhay spx_disconnect(cb); 1614157153Srwatson error = 0; 1615157153Srwatsonout: 1616157128Srwatson IPX_UNLOCK(ipxp); 1617139932Srwatson IPX_LIST_UNLOCK(); 1618157153Srwatson return (error); 161924659Sjhay} 162011819Sjulian 162124659Sjhaystatic int 1622157067Srwatsonspx_listen(struct socket *so, int backlog, struct thread *td) 162324659Sjhay{ 162424659Sjhay int error; 162524659Sjhay struct ipxpcb *ipxp; 162624659Sjhay struct spxpcb *cb; 162711819Sjulian 162824659Sjhay error = 0; 162924659Sjhay ipxp = sotoipxpcb(so); 1630157094Srwatson KASSERT(ipxp != NULL, ("spx_listen: ipxp == NULL")); 1631157094Srwatson 163224659Sjhay cb = ipxtospxpcb(ipxp); 1633157094Srwatson KASSERT(cb != NULL, ("spx_listen: cb == NULL")); 163411819Sjulian 1635139932Srwatson IPX_LIST_LOCK(); 1636139932Srwatson IPX_LOCK(ipxp); 1637157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1638157153Srwatson error = EINVAL; 1639157153Srwatson goto out; 1640157153Srwatson } 1641142190Srwatson SOCK_LOCK(so); 1642142190Srwatson error = solisten_proto_check(so); 1643142190Srwatson if (error == 0 && ipxp->ipxp_lport == 0) 1644139579Srwatson error = ipx_pcbbind(ipxp, NULL, td); 1645142190Srwatson if (error == 0) { 164624659Sjhay cb->s_state = TCPS_LISTEN; 1647151888Srwatson solisten_proto(so, backlog); 1648142190Srwatson } 1649142190Srwatson SOCK_UNLOCK(so); 1650157153Srwatsonout: 1651139932Srwatson IPX_UNLOCK(ipxp); 1652139932Srwatson IPX_LIST_UNLOCK(); 165324659Sjhay return (error); 165424659Sjhay} 165511819Sjulian 165624659Sjhay/* 1657157094Srwatson * After a receive, possibly send acknowledgment updating allocation. 165824659Sjhay */ 165924659Sjhaystatic int 1660157067Srwatsonspx_rcvd(struct socket *so, int flags) 166124659Sjhay{ 166224659Sjhay struct ipxpcb *ipxp; 166324659Sjhay struct spxpcb *cb; 1664157153Srwatson int error; 166511819Sjulian 166624659Sjhay ipxp = sotoipxpcb(so); 1667157094Srwatson KASSERT(ipxp != NULL, ("spx_rcvd: ipxp == NULL")); 1668157094Srwatson 166924659Sjhay cb = ipxtospxpcb(ipxp); 1670157094Srwatson KASSERT(cb != NULL, ("spx_rcvd: cb == NULL")); 167111819Sjulian 1672139932Srwatson IPX_LOCK(ipxp); 1673157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1674157153Srwatson error = EINVAL; 1675157153Srwatson goto out; 1676157153Srwatson } 167724659Sjhay cb->s_flags |= SF_RVD; 1678139579Srwatson spx_output(cb, NULL); 167924659Sjhay cb->s_flags &= ~SF_RVD; 1680157153Srwatson error = 0; 1681157153Srwatsonout: 1682139932Srwatson IPX_UNLOCK(ipxp); 1683157153Srwatson return (error); 168424659Sjhay} 168511819Sjulian 168624659Sjhaystatic int 1687157067Srwatsonspx_rcvoob(struct socket *so, struct mbuf *m, int flags) 168824659Sjhay{ 168924659Sjhay struct ipxpcb *ipxp; 169024659Sjhay struct spxpcb *cb; 1691157153Srwatson int error; 169211819Sjulian 169324659Sjhay ipxp = sotoipxpcb(so); 1694157094Srwatson KASSERT(ipxp != NULL, ("spx_rcvoob: ipxp == NULL")); 1695157094Srwatson 169624659Sjhay cb = ipxtospxpcb(ipxp); 1697157094Srwatson KASSERT(cb != NULL, ("spx_rcvoob: cb == NULL")); 169811819Sjulian 1699157128Srwatson IPX_LOCK(ipxp); 1700157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1701157153Srwatson error = EINVAL; 1702157153Srwatson goto out; 1703157153Srwatson } 1704139591Srwatson SOCKBUF_LOCK(&so->so_rcv); 170524659Sjhay if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 1706130480Srwatson (so->so_rcv.sb_state & SBS_RCVATMARK)) { 1707139591Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 170824659Sjhay m->m_len = 1; 170924659Sjhay *mtod(m, caddr_t) = cb->s_iobc; 1710157153Srwatson error = 0; 1711157153Srwatson goto out; 171211819Sjulian } 1713139591Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 1714157153Srwatson error = EINVAL; 1715157153Srwatsonout: 1716157128Srwatson IPX_UNLOCK(ipxp); 1717157153Srwatson return (error); 171824659Sjhay} 171924659Sjhay 172024659Sjhaystatic int 1721157067Srwatsonspx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 1722157067Srwatson struct mbuf *controlp, struct thread *td) 172324659Sjhay{ 172424659Sjhay struct ipxpcb *ipxp; 172524659Sjhay struct spxpcb *cb; 1726157153Srwatson int error; 172724659Sjhay 172824659Sjhay ipxp = sotoipxpcb(so); 1729157094Srwatson KASSERT(ipxp != NULL, ("spx_send: ipxp == NULL")); 1730157094Srwatson 173124659Sjhay cb = ipxtospxpcb(ipxp); 1732157094Srwatson KASSERT(cb != NULL, ("spx_send: cb == NULL")); 173324659Sjhay 1734157094Srwatson error = 0; 1735139932Srwatson IPX_LOCK(ipxp); 1736157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1737157153Srwatson error = ECONNRESET; 1738157153Srwatson goto spx_send_end; 1739157153Srwatson } 174024659Sjhay if (flags & PRUS_OOB) { 174124659Sjhay if (sbspace(&so->so_snd) < -512) { 174224659Sjhay error = ENOBUFS; 174324659Sjhay goto spx_send_end; 174424659Sjhay } 174524659Sjhay cb->s_oobflags |= SF_SOOB; 174624659Sjhay } 174725652Sjhay if (controlp != NULL) { 174824659Sjhay u_short *p = mtod(controlp, u_short *); 174924659Sjhay spx_newchecks[2]++; 175025652Sjhay if ((p[0] == 5) && (p[1] == 1)) { /* XXXX, for testing */ 175124659Sjhay cb->s_shdr.spx_dt = *(u_char *)(&p[2]); 175224659Sjhay spx_newchecks[3]++; 175324659Sjhay } 175424659Sjhay m_freem(controlp); 175524659Sjhay } 175624659Sjhay controlp = NULL; 175724659Sjhay error = spx_output(cb, m); 175824659Sjhay m = NULL; 175924659Sjhayspx_send_end: 1760139932Srwatson IPX_UNLOCK(ipxp); 176111819Sjulian if (controlp != NULL) 176211819Sjulian m_freem(controlp); 176311819Sjulian if (m != NULL) 176411819Sjulian m_freem(m); 176511819Sjulian return (error); 176611819Sjulian} 176711819Sjulian 176824659Sjhaystatic int 1769157067Srwatsonspx_shutdown(struct socket *so) 177024659Sjhay{ 177124659Sjhay struct ipxpcb *ipxp; 177224659Sjhay struct spxpcb *cb; 1773157153Srwatson int error; 177424659Sjhay 177524659Sjhay ipxp = sotoipxpcb(so); 1776157094Srwatson KASSERT(ipxp != NULL, ("spx_shutdown: ipxp == NULL")); 1777157094Srwatson 177824659Sjhay cb = ipxtospxpcb(ipxp); 1779157094Srwatson KASSERT(cb != NULL, ("spx_shutdown: cb == NULL")); 178024659Sjhay 178124659Sjhay socantsendmore(so); 1782139932Srwatson IPX_LIST_LOCK(); 1783139932Srwatson IPX_LOCK(ipxp); 1784157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1785157153Srwatson error = EINVAL; 1786157153Srwatson goto out; 1787157153Srwatson } 1788139931Srwatson spx_usrclosed(cb); 1789157153Srwatson error = 0; 1790157153Srwatsonout: 1791157128Srwatson IPX_UNLOCK(ipxp); 1792139932Srwatson IPX_LIST_UNLOCK(); 1793157153Srwatson return (error); 179424659Sjhay} 179524659Sjhay 179624659Sjhaystatic int 1797157067Srwatsonspx_sp_attach(struct socket *so, int proto, struct thread *td) 179811819Sjulian{ 1799157127Srwatson struct ipxpcb *ipxp; 1800157127Srwatson struct spxpcb *cb; 180124659Sjhay int error; 180211819Sjulian 1803157127Srwatson KASSERT(so->so_pcb == NULL, ("spx_sp_attach: so_pcb != NULL")); 1804157127Srwatson 180583366Sjulian error = spx_attach(so, proto, td); 1806157127Srwatson if (error) 1807157127Srwatson return (error); 1808157127Srwatson 1809157127Srwatson ipxp = sotoipxpcb(so); 1810157127Srwatson KASSERT(ipxp != NULL, ("spx_sp_attach: ipxp == NULL")); 1811157127Srwatson 1812157127Srwatson cb = ipxtospxpcb(ipxp); 1813157127Srwatson KASSERT(cb != NULL, ("spx_sp_attach: cb == NULL")); 1814157127Srwatson 1815157127Srwatson IPX_LOCK(ipxp); 1816157127Srwatson cb->s_flags |= (SF_HI | SF_HO | SF_PI); 1817157127Srwatson IPX_UNLOCK(ipxp); 1818157127Srwatson return (0); 181911819Sjulian} 182011819Sjulian 182111819Sjulian/* 1822157094Srwatson * Create template to be used to send spx packets on a connection. Called 1823157094Srwatson * after host entry created, fills in a skeletal spx header (choosing 1824157094Srwatson * connection id), minimizing the amount of work necessary when the 1825157094Srwatson * connection is used. 182611819Sjulian */ 182725652Sjhaystatic void 1828157067Srwatsonspx_template(struct spxpcb *cb) 182911819Sjulian{ 1830157067Srwatson struct ipxpcb *ipxp = cb->s_ipxpcb; 1831157067Srwatson struct ipx *ipx = cb->s_ipx; 1832157067Srwatson struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd); 183311819Sjulian 1834139932Srwatson IPX_LOCK_ASSERT(ipxp); 1835139932Srwatson 183611819Sjulian ipx->ipx_pt = IPXPROTO_SPX; 183711819Sjulian ipx->ipx_sna = ipxp->ipxp_laddr; 183811819Sjulian ipx->ipx_dna = ipxp->ipxp_faddr; 1839157069Srwatson SPX_LOCK(); 184011819Sjulian cb->s_sid = htons(spx_iss); 184111819Sjulian spx_iss += SPX_ISSINCR/2; 1842157069Srwatson SPX_UNLOCK(); 184311819Sjulian cb->s_alo = 1; 184411819Sjulian cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; 1845179408Srwatson 1846179408Srwatson /* 1847179408Srwatson * Try to expand fast to full complement of large packets. 1848179408Srwatson */ 1849157094Srwatson cb->s_ssthresh = cb->s_cwnd; 185011819Sjulian cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx)); 1851179408Srwatson 1852179408Srwatson /* 1853179408Srwatson * But allow for lots of little packets as well. 1854179408Srwatson */ 185511819Sjulian cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); 185611819Sjulian} 185711819Sjulian 185811819Sjulian/* 1859157128Srwatson * Close a SPIP control block. Wake up any sleepers. We used to free any 1860157128Srwatson * queued packets and cb->s_ipx here, but now we defer that until the pcb is 1861157128Srwatson * discarded. 186211819Sjulian */ 1863139931Srwatsonvoid 1864157067Srwatsonspx_close(struct spxpcb *cb) 186511819Sjulian{ 186611819Sjulian struct ipxpcb *ipxp = cb->s_ipxpcb; 186711819Sjulian struct socket *so = ipxp->ipxp_socket; 186811819Sjulian 1869157094Srwatson KASSERT(ipxp != NULL, ("spx_close: ipxp == NULL")); 1870139932Srwatson IPX_LIST_LOCK_ASSERT(); 1871139932Srwatson IPX_LOCK_ASSERT(ipxp); 1872139932Srwatson 1873157128Srwatson ipxp->ipxp_flags |= IPXP_DROPPED; 187411819Sjulian soisdisconnected(so); 187511819Sjulian spxstat.spxs_closed++; 187611819Sjulian} 187725652Sjhay 187811819Sjulian/* 1879157094Srwatson * Someday we may do level 3 handshaking to close a connection or send a 1880157094Srwatson * xerox style error. For now, just close. cb will always be invalid after 1881157094Srwatson * this call. 188211819Sjulian */ 1883139931Srwatsonstatic void 1884157067Srwatsonspx_usrclosed(struct spxpcb *cb) 188511819Sjulian{ 1886139931Srwatson 1887139932Srwatson IPX_LIST_LOCK_ASSERT(); 1888139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 1889139932Srwatson 1890139931Srwatson spx_close(cb); 189111819Sjulian} 189225652Sjhay 1893139931Srwatson/* 1894139931Srwatson * cb will always be invalid after this call. 1895139931Srwatson */ 1896139931Srwatsonstatic void 1897157067Srwatsonspx_disconnect(struct spxpcb *cb) 189811819Sjulian{ 1899139931Srwatson 1900139932Srwatson IPX_LIST_LOCK_ASSERT(); 1901139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 1902139932Srwatson 1903139931Srwatson spx_close(cb); 190411819Sjulian} 190525652Sjhay 190611819Sjulian/* 1907157094Srwatson * Drop connection, reporting the specified error. cb will always be invalid 1908157094Srwatson * after this call. 190911819Sjulian */ 1910139931Srwatsonstatic void 1911157067Srwatsonspx_drop(struct spxpcb *cb, int errno) 191211819Sjulian{ 191311819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 191411819Sjulian 1915139932Srwatson IPX_LIST_LOCK_ASSERT(); 1916139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 1917139932Srwatson 191811819Sjulian /* 1919157094Srwatson * Someday, in the xerox world we will generate error protocol 1920157094Srwatson * packets announcing that the socket has gone away. 192111819Sjulian */ 192211819Sjulian if (TCPS_HAVERCVDSYN(cb->s_state)) { 192311819Sjulian spxstat.spxs_drops++; 192411819Sjulian cb->s_state = TCPS_CLOSED; 192525652Sjhay /*tcp_output(cb);*/ 192611819Sjulian } else 192711819Sjulian spxstat.spxs_conndrops++; 192811819Sjulian so->so_error = errno; 1929139931Srwatson spx_close(cb); 193011819Sjulian} 193111819Sjulian 193211819Sjulian/* 1933157094Srwatson * Fast timeout routine for processing delayed acks. 193411819Sjulian */ 193511819Sjulianvoid 1936157067Srwatsonspx_fasttimo(void) 193711819Sjulian{ 1938139932Srwatson struct ipxpcb *ipxp; 1939139932Srwatson struct spxpcb *cb; 194011819Sjulian 1941139932Srwatson IPX_LIST_LOCK(); 1942139444Srwatson LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 1943139932Srwatson IPX_LOCK(ipxp); 1944157145Srwatson if (!(ipxp->ipxp_flags & IPXP_SPX) || 1945157145Srwatson (ipxp->ipxp_flags & IPXP_DROPPED)) { 1946157145Srwatson IPX_UNLOCK(ipxp); 1947157145Srwatson continue; 194811819Sjulian } 1949157145Srwatson cb = ipxtospxpcb(ipxp); 1950157145Srwatson if (cb->s_flags & SF_DELACK) { 1951157145Srwatson cb->s_flags &= ~SF_DELACK; 1952157145Srwatson cb->s_flags |= SF_ACKNOW; 1953157145Srwatson spxstat.spxs_delack++; 1954157145Srwatson spx_output(cb, NULL); 1955157145Srwatson } 1956139932Srwatson IPX_UNLOCK(ipxp); 1957139444Srwatson } 1958139932Srwatson IPX_LIST_UNLOCK(); 195911819Sjulian} 196011819Sjulian 196111819Sjulian/* 1962157094Srwatson * spx protocol timeout routine called every 500 ms. Updates the timers in 1963157094Srwatson * all active pcb's and causes finite state machine actions if timers expire. 196411819Sjulian */ 196511819Sjulianvoid 1966157067Srwatsonspx_slowtimo(void) 196711819Sjulian{ 1968157128Srwatson struct ipxpcb *ipxp; 1969139932Srwatson struct spxpcb *cb; 1970139932Srwatson int i; 197111819Sjulian 197211819Sjulian /* 1973157128Srwatson * Search through tcb's and update active timers. Once, timers could 1974157128Srwatson * free ipxp's, but now we do that only when detaching a socket. 197511819Sjulian */ 1976139932Srwatson IPX_LIST_LOCK(); 1977157128Srwatson LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 1978157128Srwatson IPX_LOCK(ipxp); 1979157145Srwatson if (!(ipxp->ipxp_flags & IPXP_SPX) || 1980157145Srwatson (ipxp->ipxp_flags & IPXP_DROPPED)) { 1981157128Srwatson IPX_UNLOCK(ipxp); 1982139444Srwatson continue; 1983157128Srwatson } 1984157128Srwatson 1985157128Srwatson cb = (struct spxpcb *)ipxp->ipxp_pcb; 1986157128Srwatson KASSERT(cb != NULL, ("spx_slowtimo: cb == NULL")); 198711819Sjulian for (i = 0; i < SPXT_NTIMERS; i++) { 198811819Sjulian if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 1989157128Srwatson spx_timers(cb, i); 1990157128Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) 1991139581Srwatson break; 199211819Sjulian } 199311819Sjulian } 1994157128Srwatson if (!(ipxp->ipxp_flags & IPXP_DROPPED)) { 1995139581Srwatson cb->s_idle++; 1996139581Srwatson if (cb->s_rtt) 1997139581Srwatson cb->s_rtt++; 1998139581Srwatson } 1999157128Srwatson IPX_UNLOCK(ipxp); 200011819Sjulian } 2001157069Srwatson IPX_LIST_UNLOCK(); 2002157069Srwatson SPX_LOCK(); 200311819Sjulian spx_iss += SPX_ISSINCR/PR_SLOWHZ; /* increment iss */ 2004157069Srwatson SPX_UNLOCK(); 200511819Sjulian} 200625652Sjhay 200711819Sjulian/* 200811819Sjulian * SPX timer processing. 200911819Sjulian */ 2010157128Srwatsonstatic void 2011157067Srwatsonspx_timers(struct spxpcb *cb, int timer) 201211819Sjulian{ 201311819Sjulian long rexmt; 201411819Sjulian int win; 201511819Sjulian 2016139932Srwatson IPX_LIST_LOCK_ASSERT(); 2017139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 2018139932Srwatson 201911819Sjulian cb->s_force = 1 + timer; 202011819Sjulian switch (timer) { 202111819Sjulian case SPXT_2MSL: 2022157124Srwatson /* 2023157124Srwatson * 2 MSL timeout in shutdown went off. TCP deletes 2024157124Srwatson * connection control block. 2025157124Srwatson */ 202611819Sjulian printf("spx: SPXT_2MSL went off for no reason\n"); 202711819Sjulian cb->s_timer[timer] = 0; 202811819Sjulian break; 202911819Sjulian 203011819Sjulian case SPXT_REXMT: 2031157124Srwatson /* 2032157124Srwatson * Retransmission timer went off. Message has not been acked 2033157124Srwatson * within retransmit interval. Back off to a longer 2034157124Srwatson * retransmit interval and retransmit one packet. 2035157124Srwatson */ 203611819Sjulian if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) { 203711819Sjulian cb->s_rxtshift = SPX_MAXRXTSHIFT; 203811819Sjulian spxstat.spxs_timeoutdrop++; 2039139931Srwatson spx_drop(cb, ETIMEDOUT); 204011819Sjulian break; 204111819Sjulian } 204211819Sjulian spxstat.spxs_rexmttimeo++; 204311819Sjulian rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 204411819Sjulian rexmt *= spx_backoff[cb->s_rxtshift]; 204511819Sjulian SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX); 204611819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 2047157094Srwatson 204811819Sjulian /* 2049157094Srwatson * If we have backed off fairly far, our srtt estimate is 2050157094Srwatson * probably bogus. Clobber it so we'll take the next rtt 2051157094Srwatson * measurement as our srtt; move the current srtt into rttvar 2052157094Srwatson * to keep the current retransmit times until then. 205311819Sjulian */ 205411819Sjulian if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) { 205511819Sjulian cb->s_rttvar += (cb->s_srtt >> 2); 205611819Sjulian cb->s_srtt = 0; 205711819Sjulian } 205811819Sjulian cb->s_snxt = cb->s_rack; 2059157094Srwatson 206011819Sjulian /* 206111819Sjulian * If timing a packet, stop the timer. 206211819Sjulian */ 206311819Sjulian cb->s_rtt = 0; 2064157094Srwatson 206511819Sjulian /* 206611819Sjulian * See very long discussion in tcp_timer.c about congestion 2067157094Srwatson * window and sstrhesh. 206811819Sjulian */ 206911819Sjulian win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; 207011819Sjulian if (win < 2) 207111819Sjulian win = 2; 207211819Sjulian cb->s_cwnd = CUNIT; 207311819Sjulian cb->s_ssthresh = win * CUNIT; 2074139579Srwatson spx_output(cb, NULL); 207511819Sjulian break; 207611819Sjulian 207711819Sjulian case SPXT_PERSIST: 2078157094Srwatson /* 2079157094Srwatson * Persistance timer into zero window. Force a probe to be 2080157094Srwatson * sent. 2081157094Srwatson */ 208211819Sjulian spxstat.spxs_persisttimeo++; 208311819Sjulian spx_setpersist(cb); 2084139579Srwatson spx_output(cb, NULL); 208511819Sjulian break; 208611819Sjulian 208711819Sjulian case SPXT_KEEP: 2088157094Srwatson /* 2089157094Srwatson * Keep-alive timer went off; send something or drop 2090157094Srwatson * connection if idle for too long. 2091157094Srwatson */ 209211819Sjulian spxstat.spxs_keeptimeo++; 209311819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 209411819Sjulian goto dropit; 209511819Sjulian if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) { 209611819Sjulian if (cb->s_idle >= SPXTV_MAXIDLE) 209711819Sjulian goto dropit; 209811819Sjulian spxstat.spxs_keepprobe++; 2099139579Srwatson spx_output(cb, NULL); 210097658Stanimura } else 210111819Sjulian cb->s_idle = 0; 210211819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 210311819Sjulian break; 2104157094Srwatson 210511819Sjulian dropit: 210611819Sjulian spxstat.spxs_keepdrops++; 2107139931Srwatson spx_drop(cb, ETIMEDOUT); 210811819Sjulian break; 2109157124Srwatson 2110157124Srwatson default: 2111157124Srwatson panic("spx_timers: unknown timer %d", timer); 211211819Sjulian } 211311819Sjulian} 2114