1139823Simp/*- 2157067Srwatson * Copyright (c) 1984, 1985, 1986, 1987, 1993 3157067Srwatson * The Regents of the University of California. 4192753Srwatson * Copyright (c) 2004-2009 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$"); 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 92194545Srwatson#include <security/mac/mac_framework.h> 93194545Srwatson 9411819Sjulian/* 9511819Sjulian * SPX protocol implementation. 9611819Sjulian */ 97157069Srwatsonstatic struct mtx spx_mtx; /* Protects only spx_iss. */ 9833181Seivindstatic u_short spx_iss; 99192746Srwatsonu_short spx_newchecks[50]; 10033181Seivindstatic int spx_hardnosed; 10133181Seivindstatic int traceallspxs = 0; 102192746Srwatsonstruct spx_istat spx_istat; 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 108132045Srwatsonstatic const int spx_backoff[SPX_MAXRXTSHIFT+1] = 10925652Sjhay { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 11011819Sjulian 111139931Srwatsonstatic void spx_close(struct spxpcb *cb); 112139931Srwatsonstatic void spx_disconnect(struct spxpcb *cb); 113139931Srwatsonstatic void spx_drop(struct spxpcb *cb, int errno); 11425652Sjhaystatic void spx_setpersist(struct spxpcb *cb); 11525652Sjhaystatic void spx_template(struct spxpcb *cb); 116157128Srwatsonstatic void spx_timers(struct spxpcb *cb, int timer); 117139931Srwatsonstatic void spx_usrclosed(struct spxpcb *cb); 11825652Sjhay 119157366Srwatsonstatic void spx_usr_abort(struct socket *so); 12028270Swollmanstatic int spx_accept(struct socket *so, struct sockaddr **nam); 12183366Sjulianstatic int spx_attach(struct socket *so, int proto, struct thread *td); 12283366Sjulianstatic int spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 123160549Srwatsonstatic void spx_usr_close(struct socket *so); 12428270Swollmanstatic int spx_connect(struct socket *so, struct sockaddr *nam, 12583366Sjulian struct thread *td); 126157370Srwatsonstatic void spx_detach(struct socket *so); 127157128Srwatsonstatic void spx_pcbdetach(struct ipxpcb *ipxp); 12824659Sjhaystatic int spx_usr_disconnect(struct socket *so); 129151888Srwatsonstatic int spx_listen(struct socket *so, int backlog, struct thread *td); 13024659Sjhaystatic int spx_rcvd(struct socket *so, int flags); 13124659Sjhaystatic int spx_rcvoob(struct socket *so, struct mbuf *m, int flags); 13224659Sjhaystatic int spx_send(struct socket *so, int flags, struct mbuf *m, 133139584Srwatson struct sockaddr *addr, struct mbuf *control, 13483366Sjulian struct thread *td); 13524659Sjhaystatic int spx_shutdown(struct socket *so); 13683366Sjulianstatic int spx_sp_attach(struct socket *so, int proto, struct thread *td); 13724659Sjhay 13824659Sjhaystruct pr_usrreqs spx_usrreqs = { 139137386Sphk .pru_abort = spx_usr_abort, 140137386Sphk .pru_accept = spx_accept, 141137386Sphk .pru_attach = spx_attach, 142137386Sphk .pru_bind = spx_bind, 143137386Sphk .pru_connect = spx_connect, 144137386Sphk .pru_control = ipx_control, 145137386Sphk .pru_detach = spx_detach, 146137386Sphk .pru_disconnect = spx_usr_disconnect, 147137386Sphk .pru_listen = spx_listen, 148137386Sphk .pru_peeraddr = ipx_peeraddr, 149137386Sphk .pru_rcvd = spx_rcvd, 150137386Sphk .pru_rcvoob = spx_rcvoob, 151137386Sphk .pru_send = spx_send, 152137386Sphk .pru_shutdown = spx_shutdown, 153137386Sphk .pru_sockaddr = ipx_sockaddr, 154160549Srwatson .pru_close = spx_usr_close, 15524659Sjhay}; 15624659Sjhay 15724659Sjhaystruct pr_usrreqs spx_usrreq_sps = { 158137386Sphk .pru_abort = spx_usr_abort, 159137386Sphk .pru_accept = spx_accept, 160137386Sphk .pru_attach = spx_sp_attach, 161137386Sphk .pru_bind = spx_bind, 162137386Sphk .pru_connect = spx_connect, 163137386Sphk .pru_control = ipx_control, 164137386Sphk .pru_detach = spx_detach, 165137386Sphk .pru_disconnect = spx_usr_disconnect, 166137386Sphk .pru_listen = spx_listen, 167137386Sphk .pru_peeraddr = ipx_peeraddr, 168137386Sphk .pru_rcvd = spx_rcvd, 169137386Sphk .pru_rcvoob = spx_rcvoob, 170137386Sphk .pru_send = spx_send, 171137386Sphk .pru_shutdown = spx_shutdown, 172137386Sphk .pru_sockaddr = ipx_sockaddr, 173160549Srwatson .pru_close = spx_usr_close, 17424659Sjhay}; 17524659Sjhay 17611819Sjulianvoid 177157067Srwatsonspx_init(void) 17811819Sjulian{ 17911819Sjulian 180157069Srwatson SPX_LOCK_INIT(); 18111819Sjulian spx_iss = 1; /* WRONG !! should fish it out of TODR */ 18211819Sjulian} 18311819Sjulian 18411819Sjulianvoid 185157067Srwatsonspx_input(struct mbuf *m, struct ipxpcb *ipxp) 18611819Sjulian{ 187157067Srwatson struct spxpcb *cb; 188157067Srwatson struct spx *si = mtod(m, struct spx *); 189157067Srwatson struct socket *so; 190157051Srwatson struct spx spx_savesi; 19111819Sjulian int dropsocket = 0; 19211819Sjulian short ostate = 0; 19311819Sjulian 19411819Sjulian spxstat.spxs_rcvtotal++; 195157094Srwatson KASSERT(ipxp != NULL, ("spx_input: ipxpcb == NULL")); 19611819Sjulian 197139932Srwatson /* 198139932Srwatson * spx_input() assumes that the caller will hold both the pcb list 199139932Srwatson * lock and also the ipxp lock. spx_input() will release both before 200139932Srwatson * returning, and may in fact trade in the ipxp lock for another pcb 201139932Srwatson * lock following sonewconn(). 202139932Srwatson */ 203139932Srwatson IPX_LIST_LOCK_ASSERT(); 204139932Srwatson IPX_LOCK_ASSERT(ipxp); 205139932Srwatson 20611819Sjulian cb = ipxtospxpcb(ipxp); 207157128Srwatson KASSERT(cb != NULL, ("spx_input: cb == NULL")); 20811819Sjulian 209157128Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) 210157128Srwatson goto drop; 211157128Srwatson 21211819Sjulian if (m->m_len < sizeof(*si)) { 21325652Sjhay if ((m = m_pullup(m, sizeof(*si))) == NULL) { 214139932Srwatson IPX_UNLOCK(ipxp); 215139932Srwatson IPX_LIST_UNLOCK(); 21611819Sjulian spxstat.spxs_rcvshort++; 21711819Sjulian return; 21811819Sjulian } 21911819Sjulian si = mtod(m, struct spx *); 22011819Sjulian } 22111819Sjulian si->si_seq = ntohs(si->si_seq); 22211819Sjulian si->si_ack = ntohs(si->si_ack); 22311819Sjulian si->si_alo = ntohs(si->si_alo); 22411819Sjulian 22511819Sjulian so = ipxp->ipxp_socket; 226157094Srwatson KASSERT(so != NULL, ("spx_input: so == NULL")); 22711819Sjulian 228194561Srwatson#ifdef MAC 229194561Srwatson if (mac_socket_check_deliver(so, m) != 0) 230194561Srwatson goto drop; 231194561Srwatson#endif 232194561Srwatson 23311819Sjulian if (so->so_options & SO_DEBUG || traceallspxs) { 23411819Sjulian ostate = cb->s_state; 23511819Sjulian spx_savesi = *si; 23611819Sjulian } 23711819Sjulian if (so->so_options & SO_ACCEPTCONN) { 23811819Sjulian struct spxpcb *ocb = cb; 23911819Sjulian 24011819Sjulian so = sonewconn(so, 0); 241157094Srwatson if (so == NULL) 24211819Sjulian goto drop; 243157094Srwatson 24411819Sjulian /* 24511819Sjulian * This is ugly, but .... 24611819Sjulian * 247157094Srwatson * Mark socket as temporary until we're committed to keeping 248157094Srwatson * it. The code at ``drop'' and ``dropwithreset'' check the 249157094Srwatson * flag dropsocket to see if the temporary socket created 250157094Srwatson * here should be discarded. We mark the socket as 251157094Srwatson * discardable until we're committed to it below in 252157094Srwatson * TCPS_LISTEN. 253157128Srwatson * 254157128Srwatson * XXXRW: In the new world order of real kernel parallelism, 255157128Srwatson * temporarily allocating the socket when we're "not sure" 256157128Srwatson * seems like a bad idea, as we might race to remove it if 257157128Srwatson * the listen socket is closed...? 258157128Srwatson * 259157128Srwatson * We drop the lock of the listen socket ipxp, and acquire 260157128Srwatson * the lock of the new socket ippx. 26111819Sjulian */ 26211819Sjulian dropsocket++; 263139932Srwatson IPX_UNLOCK(ipxp); 26411819Sjulian ipxp = (struct ipxpcb *)so->so_pcb; 265139932Srwatson IPX_LOCK(ipxp); 26611819Sjulian ipxp->ipxp_laddr = si->si_dna; 26711819Sjulian cb = ipxtospxpcb(ipxp); 26811819Sjulian cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ 26911819Sjulian cb->s_flags = ocb->s_flags; /* preserve sockopts */ 27011819Sjulian cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ 27111819Sjulian cb->s_state = TCPS_LISTEN; 27297658Stanimura } 273157094Srwatson IPX_LOCK_ASSERT(ipxp); 27411819Sjulian 27511819Sjulian /* 276157094Srwatson * Packet received on connection. Reset idle time and keep-alive 277157094Srwatson * timer. 27811819Sjulian */ 27911819Sjulian cb->s_idle = 0; 28011819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 28111819Sjulian 28211819Sjulian switch (cb->s_state) { 28311819Sjulian case TCPS_LISTEN:{ 28428270Swollman struct sockaddr_ipx *sipx, ssipx; 28511819Sjulian struct ipx_addr laddr; 28611819Sjulian 28711819Sjulian /* 288157094Srwatson * If somebody here was carying on a conversation and went 289157094Srwatson * away, and his pen pal thinks he can still talk, we get the 290157094Srwatson * misdirected packet. 29111819Sjulian */ 29211819Sjulian if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 29311819Sjulian spx_istat.gonawy++; 29411819Sjulian goto dropwithreset; 29511819Sjulian } 29628270Swollman sipx = &ssipx; 29728270Swollman bzero(sipx, sizeof *sipx); 29811819Sjulian sipx->sipx_len = sizeof(*sipx); 29911819Sjulian sipx->sipx_family = AF_IPX; 30011819Sjulian sipx->sipx_addr = si->si_sna; 30111819Sjulian laddr = ipxp->ipxp_laddr; 30211819Sjulian if (ipx_nullhost(laddr)) 30311819Sjulian ipxp->ipxp_laddr = si->si_dna; 30490361Sjulian if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &thread0)) { 30511819Sjulian ipxp->ipxp_laddr = laddr; 30611819Sjulian spx_istat.noconn++; 30711819Sjulian goto drop; 30811819Sjulian } 30911819Sjulian spx_template(cb); 31011819Sjulian dropsocket = 0; /* committed to socket */ 31111819Sjulian cb->s_did = si->si_sid; 31211819Sjulian cb->s_rack = si->si_ack; 31311819Sjulian cb->s_ralo = si->si_alo; 31411819Sjulian#define THREEWAYSHAKE 31511819Sjulian#ifdef THREEWAYSHAKE 31611819Sjulian cb->s_state = TCPS_SYN_RECEIVED; 31711819Sjulian cb->s_force = 1 + SPXT_KEEP; 31811819Sjulian spxstat.spxs_accepts++; 31911819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 32011819Sjulian } 32111819Sjulian break; 322157094Srwatson 32311819Sjulian case TCPS_SYN_RECEIVED: { 324157094Srwatson /* 325157094Srwatson * This state means that we have heard a response to our 326157094Srwatson * acceptance of their connection. It is probably logically 327157094Srwatson * unnecessary in this implementation. 328157094Srwatson */ 32925652Sjhay if (si->si_did != cb->s_sid) { 33011819Sjulian spx_istat.wrncon++; 33111819Sjulian goto drop; 33211819Sjulian } 33311819Sjulian#endif 33411819Sjulian ipxp->ipxp_fport = si->si_sport; 33511819Sjulian cb->s_timer[SPXT_REXMT] = 0; 33611819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 33711819Sjulian soisconnected(so); 33811819Sjulian cb->s_state = TCPS_ESTABLISHED; 33911819Sjulian spxstat.spxs_accepts++; 34011819Sjulian } 34111819Sjulian break; 34211819Sjulian 34311819Sjulian case TCPS_SYN_SENT: 344157094Srwatson /* 345157094Srwatson * This state means that we have gotten a response to our 346157094Srwatson * attempt to establish a connection. We fill in the data 347157094Srwatson * from the other side, telling us which port to respond to, 348157094Srwatson * instead of the well-known one we might have sent to in the 349157094Srwatson * first place. We also require that this is a response to 350157094Srwatson * our connection id. 351157094Srwatson */ 35225652Sjhay if (si->si_did != cb->s_sid) { 35311819Sjulian spx_istat.notme++; 35411819Sjulian goto drop; 35511819Sjulian } 35611819Sjulian spxstat.spxs_connects++; 35711819Sjulian cb->s_did = si->si_sid; 35811819Sjulian cb->s_rack = si->si_ack; 35911819Sjulian cb->s_ralo = si->si_alo; 36011819Sjulian cb->s_dport = ipxp->ipxp_fport = si->si_sport; 36111819Sjulian cb->s_timer[SPXT_REXMT] = 0; 36211819Sjulian cb->s_flags |= SF_ACKNOW; 36311819Sjulian soisconnected(so); 36411819Sjulian cb->s_state = TCPS_ESTABLISHED; 365179408Srwatson 366157094Srwatson /* 367157094Srwatson * Use roundtrip time of connection request for initial rtt. 368157094Srwatson */ 36911819Sjulian if (cb->s_rtt) { 37011819Sjulian cb->s_srtt = cb->s_rtt << 3; 37111819Sjulian cb->s_rttvar = cb->s_rtt << 1; 37211819Sjulian SPXT_RANGESET(cb->s_rxtcur, 37311819Sjulian ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 37411819Sjulian SPXTV_MIN, SPXTV_REXMTMAX); 37511819Sjulian cb->s_rtt = 0; 37611819Sjulian } 37711819Sjulian } 378157094Srwatson 37997658Stanimura if (so->so_options & SO_DEBUG || traceallspxs) 38011819Sjulian spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0); 38111819Sjulian 38225652Sjhay m->m_len -= sizeof(struct ipx); 38325652Sjhay m->m_pkthdr.len -= sizeof(struct ipx); 38425652Sjhay m->m_data += sizeof(struct ipx); 38511819Sjulian 386194547Srwatson if (spx_reass(cb, m, si)) 38725652Sjhay m_freem(m); 38811819Sjulian if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) 389139579Srwatson spx_output(cb, NULL); 39011819Sjulian cb->s_flags &= ~(SF_WIN|SF_RXT); 391139932Srwatson IPX_UNLOCK(ipxp); 392139932Srwatson IPX_LIST_UNLOCK(); 39311819Sjulian return; 39411819Sjulian 39511819Sjuliandropwithreset: 396157094Srwatson IPX_LOCK_ASSERT(ipxp); 397157164Srwatson if (cb == NULL || (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || 398157128Srwatson traceallspxs)) 399157128Srwatson spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 400139932Srwatson IPX_UNLOCK(ipxp); 401130822Srwatson if (dropsocket) { 402130822Srwatson struct socket *head; 403130822Srwatson ACCEPT_LOCK(); 404130822Srwatson KASSERT((so->so_qstate & SQ_INCOMP) != 0, 405130822Srwatson ("spx_input: nascent socket not SQ_INCOMP on soabort()")); 406130822Srwatson head = so->so_head; 407130822Srwatson TAILQ_REMOVE(&head->so_incomp, so, so_list); 408130822Srwatson head->so_incqlen--; 409130822Srwatson so->so_qstate &= ~SQ_INCOMP; 410130822Srwatson so->so_head = NULL; 411130822Srwatson ACCEPT_UNLOCK(); 41225652Sjhay soabort(so); 413130822Srwatson } 414139932Srwatson IPX_LIST_UNLOCK(); 415179332Srwatson m_freem(m); 41611819Sjulian return; 41711819Sjulian 41811819Sjuliandrop: 419157094Srwatson IPX_LOCK_ASSERT(ipxp); 420157128Srwatson if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs) 42111819Sjulian spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 422139932Srwatson IPX_UNLOCK(ipxp); 423139932Srwatson IPX_LIST_UNLOCK(); 42411819Sjulian m_freem(m); 42511819Sjulian} 42611819Sjulian 427192754Srwatsonvoid 428192754Srwatsonspx_ctlinput(int cmd, struct sockaddr *arg_as_sa, void *dummy) 429192754Srwatson{ 430192754Srwatson 431192754Srwatson /* Currently, nothing. */ 432192754Srwatson} 433192754Srwatson 434192746Srwatsonint 435157067Srwatsonspx_output(struct spxpcb *cb, struct mbuf *m0) 43611819Sjulian{ 43711819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 438192756Srwatson struct mbuf *m = NULL; 439157067Srwatson struct spx *si = NULL; 440157067Srwatson struct sockbuf *sb = &so->so_snd; 44111819Sjulian int len = 0, win, rcv_win; 44211819Sjulian short span, off, recordp = 0; 44311819Sjulian u_short alo; 44411819Sjulian int error = 0, sendalot; 44511819Sjulian#ifdef notdef 44611819Sjulian int idle; 44711819Sjulian#endif 44811819Sjulian struct mbuf *mprev; 44911819Sjulian 450139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 451139932Srwatson 45225652Sjhay if (m0 != NULL) { 45311819Sjulian int mtu = cb->s_mtu; 45411819Sjulian int datalen; 455157094Srwatson 45611819Sjulian /* 45711819Sjulian * Make sure that packet isn't too big. 45811819Sjulian */ 45925652Sjhay for (m = m0; m != NULL; m = m->m_next) { 46011819Sjulian mprev = m; 46111819Sjulian len += m->m_len; 46211819Sjulian if (m->m_flags & M_EOR) 46311819Sjulian recordp = 1; 46411819Sjulian } 46511819Sjulian datalen = (cb->s_flags & SF_HO) ? 46625652Sjhay len - sizeof(struct spxhdr) : len; 46711819Sjulian if (datalen > mtu) { 46811819Sjulian if (cb->s_flags & SF_PI) { 46911819Sjulian m_freem(m0); 47011819Sjulian return (EMSGSIZE); 47111819Sjulian } else { 47211819Sjulian int oldEM = cb->s_cc & SPX_EM; 47311819Sjulian 47411819Sjulian cb->s_cc &= ~SPX_EM; 47511819Sjulian while (len > mtu) { 476243882Sglebius m = m_copym(m0, 0, mtu, M_NOWAIT); 477157167Srwatson if (m == NULL) { 478157167Srwatson cb->s_cc |= oldEM; 479157167Srwatson m_freem(m0); 480157167Srwatson return (ENOBUFS); 481157167Srwatson } 48211819Sjulian if (cb->s_flags & SF_NEWCALL) { 48311819Sjulian struct mbuf *mm = m; 48411819Sjulian spx_newchecks[7]++; 48525652Sjhay while (mm != NULL) { 48611819Sjulian mm->m_flags &= ~M_EOR; 48711819Sjulian mm = mm->m_next; 48811819Sjulian } 48911819Sjulian } 49011819Sjulian error = spx_output(cb, m); 49111819Sjulian if (error) { 49211819Sjulian cb->s_cc |= oldEM; 49311819Sjulian m_freem(m0); 49425652Sjhay return (error); 49511819Sjulian } 49611819Sjulian m_adj(m0, mtu); 49711819Sjulian len -= mtu; 49811819Sjulian } 49911819Sjulian cb->s_cc |= oldEM; 50011819Sjulian } 50111819Sjulian } 502157094Srwatson 50311819Sjulian /* 50411819Sjulian * Force length even, by adding a "garbage byte" if 50511819Sjulian * necessary. 50611819Sjulian */ 50711819Sjulian if (len & 1) { 50811819Sjulian m = mprev; 50911819Sjulian if (M_TRAILINGSPACE(m) >= 1) 51011819Sjulian m->m_len++; 51111819Sjulian else { 512243882Sglebius struct mbuf *m1 = m_get(M_NOWAIT, MT_DATA); 51311819Sjulian 51425652Sjhay if (m1 == NULL) { 51511819Sjulian m_freem(m0); 51611819Sjulian return (ENOBUFS); 51711819Sjulian } 51811819Sjulian m1->m_len = 1; 51911819Sjulian *(mtod(m1, u_char *)) = 0; 52011819Sjulian m->m_next = m1; 52111819Sjulian } 52211819Sjulian } 523243882Sglebius m = m_gethdr(M_NOWAIT, MT_DATA); 52425652Sjhay if (m == NULL) { 52511819Sjulian m_freem(m0); 52611819Sjulian return (ENOBUFS); 52711819Sjulian } 528157094Srwatson 52911819Sjulian /* 530157094Srwatson * Fill in mbuf with extended SP header and addresses and 531157094Srwatson * length put into network format. 53211819Sjulian */ 53325652Sjhay MH_ALIGN(m, sizeof(struct spx)); 53425652Sjhay m->m_len = sizeof(struct spx); 53511819Sjulian m->m_next = m0; 53611819Sjulian si = mtod(m, struct spx *); 537192754Srwatson si->si_i = cb->s_ipx; 53811819Sjulian si->si_s = cb->s_shdr; 53911819Sjulian if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 540157067Srwatson struct spxhdr *sh; 54125652Sjhay if (m0->m_len < sizeof(*sh)) { 54211819Sjulian if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 54325652Sjhay m_free(m); 54411819Sjulian m_freem(m0); 54511819Sjulian return (EINVAL); 54611819Sjulian } 54711819Sjulian m->m_next = m0; 54811819Sjulian } 54911819Sjulian sh = mtod(m0, struct spxhdr *); 55011819Sjulian si->si_dt = sh->spx_dt; 55111819Sjulian si->si_cc |= sh->spx_cc & SPX_EM; 55225652Sjhay m0->m_len -= sizeof(*sh); 55325652Sjhay m0->m_data += sizeof(*sh); 55425652Sjhay len -= sizeof(*sh); 55511819Sjulian } 55611819Sjulian len += sizeof(*si); 55711819Sjulian if ((cb->s_flags2 & SF_NEWCALL) && recordp) { 55825652Sjhay si->si_cc |= SPX_EM; 55911819Sjulian spx_newchecks[8]++; 56011819Sjulian } 56111819Sjulian if (cb->s_oobflags & SF_SOOB) { 56211819Sjulian /* 563157094Srwatson * Per jqj@cornell: Make sure OB packets convey 564157094Srwatson * exactly 1 byte. If the packet is 1 byte or 565157094Srwatson * larger, we have already guaranted there to be at 566157094Srwatson * least one garbage byte for the checksum, and extra 567157094Srwatson * bytes shouldn't hurt! 56811819Sjulian */ 56911819Sjulian if (len > sizeof(*si)) { 57011819Sjulian si->si_cc |= SPX_OB; 57111819Sjulian len = (1 + sizeof(*si)); 57211819Sjulian } 57311819Sjulian } 57411819Sjulian si->si_len = htons((u_short)len); 57511819Sjulian m->m_pkthdr.len = ((len - 1) | 1) + 1; 576157094Srwatson 57711819Sjulian /* 578157094Srwatson * Queue stuff up for output. 57911819Sjulian */ 58011819Sjulian sbappendrecord(sb, m); 58111819Sjulian cb->s_seq++; 58211819Sjulian } 58311819Sjulian#ifdef notdef 58411819Sjulian idle = (cb->s_smax == (cb->s_rack - 1)); 58511819Sjulian#endif 58611819Sjulianagain: 58711819Sjulian sendalot = 0; 58811819Sjulian off = cb->s_snxt - cb->s_rack; 58925652Sjhay win = min(cb->s_swnd, (cb->s_cwnd / CUNIT)); 59011819Sjulian 59111819Sjulian /* 592157094Srwatson * If in persist timeout with window of 0, send a probe. Otherwise, 593179408Srwatson * if window is small but non-zero and timer expired, send what we 594179408Srwatson * can and go into transmit state. 59511819Sjulian */ 59611819Sjulian if (cb->s_force == 1 + SPXT_PERSIST) { 59711819Sjulian if (win != 0) { 59811819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 59911819Sjulian cb->s_rxtshift = 0; 60011819Sjulian } 60111819Sjulian } 60211819Sjulian span = cb->s_seq - cb->s_rack; 60311819Sjulian len = min(span, win) - off; 60411819Sjulian 60511819Sjulian if (len < 0) { 60611819Sjulian /* 607157094Srwatson * Window shrank after we went into it. If window shrank to 608157094Srwatson * 0, cancel pending restransmission and pull s_snxt back to 609157094Srwatson * (closed) window. We will enter persist state below. If 610157094Srwatson * the widndow didn't close completely, just wait for an ACK. 61111819Sjulian */ 61211819Sjulian len = 0; 61311819Sjulian if (win == 0) { 61411819Sjulian cb->s_timer[SPXT_REXMT] = 0; 61511819Sjulian cb->s_snxt = cb->s_rack; 61611819Sjulian } 61711819Sjulian } 61811819Sjulian if (len > 1) 61911819Sjulian sendalot = 1; 62011819Sjulian rcv_win = sbspace(&so->so_rcv); 62111819Sjulian 62211819Sjulian /* 62311819Sjulian * Send if we owe peer an ACK. 62411819Sjulian */ 62511819Sjulian if (cb->s_oobflags & SF_SOOB) { 62611819Sjulian /* 627157094Srwatson * Must transmit this out of band packet. 62811819Sjulian */ 62911819Sjulian cb->s_oobflags &= ~ SF_SOOB; 63011819Sjulian sendalot = 1; 63111819Sjulian spxstat.spxs_sndurg++; 63211819Sjulian goto found; 63311819Sjulian } 63411819Sjulian if (cb->s_flags & SF_ACKNOW) 63511819Sjulian goto send; 63611819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 63711819Sjulian goto send; 638157094Srwatson 63911819Sjulian /* 640157094Srwatson * Silly window can't happen in spx. Code from TCP deleted. 64111819Sjulian */ 64211819Sjulian if (len) 64311819Sjulian goto send; 644157094Srwatson 64511819Sjulian /* 646157094Srwatson * Compare available window to amount of window known to peer (as 647157094Srwatson * advertised window less next expected input.) If the difference is 648157094Srwatson * at least two packets or at least 35% of the mximum possible 649157094Srwatson * window, then want to send a window update to peer. 65011819Sjulian */ 65111819Sjulian if (rcv_win > 0) { 65211819Sjulian u_short delta = 1 + cb->s_alo - cb->s_ack; 65311819Sjulian int adv = rcv_win - (delta * cb->s_mtu); 654139584Srwatson 65511819Sjulian if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || 65611819Sjulian (100 * adv / so->so_rcv.sb_hiwat >= 35)) { 65711819Sjulian spxstat.spxs_sndwinup++; 65811819Sjulian cb->s_flags |= SF_ACKNOW; 65911819Sjulian goto send; 66011819Sjulian } 66111819Sjulian 66211819Sjulian } 663157094Srwatson 66411819Sjulian /* 665157094Srwatson * Many comments from tcp_output.c are appropriate here including ... 66611819Sjulian * If send window is too small, there is data to transmit, and no 667157094Srwatson * retransmit or persist is pending, then go to persist state. If 668157094Srwatson * nothing happens soon, send when timer expires: if window is 669179408Srwatson * non-zero, transmit what we can, otherwise send a probe. 67011819Sjulian */ 67111819Sjulian if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 && 672157128Srwatson cb->s_timer[SPXT_PERSIST] == 0) { 673157128Srwatson cb->s_rxtshift = 0; 674157128Srwatson spx_setpersist(cb); 67511819Sjulian } 676157094Srwatson 67711819Sjulian /* 67811819Sjulian * No reason to send a packet, just return. 67911819Sjulian */ 68011819Sjulian cb->s_outx = 1; 68111819Sjulian return (0); 68211819Sjulian 68311819Sjuliansend: 68411819Sjulian /* 68511819Sjulian * Find requested packet. 68611819Sjulian */ 687192755Srwatson si = NULL; 688192756Srwatson m = NULL; 68911819Sjulian if (len > 0) { 69011819Sjulian cb->s_want = cb->s_snxt; 691192748Srwatson for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt) { 69211819Sjulian si = mtod(m, struct spx *); 69311819Sjulian if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) 69411819Sjulian break; 69511819Sjulian } 69611819Sjulian found: 69725652Sjhay if (si != NULL) { 698192756Srwatson if (si->si_seq != cb->s_snxt) { 699192756Srwatson spxstat.spxs_sndvoid++; 700192756Srwatson si = NULL; 701192756Srwatson m = NULL; 702192756Srwatson } else 703192756Srwatson cb->s_snxt++; 70411819Sjulian } 70511819Sjulian } 706157094Srwatson 70711819Sjulian /* 708157094Srwatson * Update window. 70911819Sjulian */ 71011819Sjulian if (rcv_win < 0) 71111819Sjulian rcv_win = 0; 71211819Sjulian alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); 713139584Srwatson if (SSEQ_LT(alo, cb->s_alo)) 71411819Sjulian alo = cb->s_alo; 71511819Sjulian 716192756Srwatson if (m != NULL) { 71711819Sjulian /* 718157094Srwatson * Must make a copy of this packet for ipx_output to monkey 719157094Srwatson * with. 72011819Sjulian */ 721192756Srwatson m = m_copy(m, 0, M_COPYALL); 722157094Srwatson if (m == NULL) 72311819Sjulian return (ENOBUFS); 72411819Sjulian si = mtod(m, struct spx *); 72511819Sjulian if (SSEQ_LT(si->si_seq, cb->s_smax)) 72611819Sjulian spxstat.spxs_sndrexmitpack++; 72711819Sjulian else 72811819Sjulian spxstat.spxs_sndpack++; 72911819Sjulian } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { 73011819Sjulian /* 731157094Srwatson * Must send an acknowledgement or a probe. 73211819Sjulian */ 73311819Sjulian if (cb->s_force) 73411819Sjulian spxstat.spxs_sndprobe++; 73511819Sjulian if (cb->s_flags & SF_ACKNOW) 73611819Sjulian spxstat.spxs_sndacks++; 737243882Sglebius m = m_gethdr(M_NOWAIT, MT_DATA); 73825652Sjhay if (m == NULL) 73911819Sjulian return (ENOBUFS); 740157094Srwatson 74111819Sjulian /* 742157094Srwatson * Fill in mbuf with extended SP header and addresses and 743157094Srwatson * length put into network format. 74411819Sjulian */ 74525652Sjhay MH_ALIGN(m, sizeof(struct spx)); 74625652Sjhay m->m_len = sizeof(*si); 74725652Sjhay m->m_pkthdr.len = sizeof(*si); 74811819Sjulian si = mtod(m, struct spx *); 749192754Srwatson si->si_i = cb->s_ipx; 75011819Sjulian si->si_s = cb->s_shdr; 75111819Sjulian si->si_seq = cb->s_smax + 1; 75225652Sjhay si->si_len = htons(sizeof(*si)); 75311819Sjulian si->si_cc |= SPX_SP; 75411819Sjulian } else { 75511819Sjulian cb->s_outx = 3; 75697658Stanimura if (so->so_options & SO_DEBUG || traceallspxs) 75711819Sjulian spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 75811819Sjulian return (0); 75911819Sjulian } 760179408Srwatson 76111819Sjulian /* 76211819Sjulian * Stuff checksum and output datagram. 76311819Sjulian */ 76411819Sjulian if ((si->si_cc & SPX_SP) == 0) { 76511819Sjulian if (cb->s_force != (1 + SPXT_PERSIST) || 76611819Sjulian cb->s_timer[SPXT_PERSIST] == 0) { 76711819Sjulian /* 768139584Srwatson * If this is a new packet and we are not currently 76911819Sjulian * timing anything, time this one. 77011819Sjulian */ 77111819Sjulian if (SSEQ_LT(cb->s_smax, si->si_seq)) { 77211819Sjulian cb->s_smax = si->si_seq; 77311819Sjulian if (cb->s_rtt == 0) { 77411819Sjulian spxstat.spxs_segstimed++; 77511819Sjulian cb->s_rtseq = si->si_seq; 77611819Sjulian cb->s_rtt = 1; 77711819Sjulian } 77811819Sjulian } 779157094Srwatson 78011819Sjulian /* 781157094Srwatson * Set rexmt timer if not currently set, initial 782157094Srwatson * value for retransmit timer is smoothed round-trip 783157094Srwatson * time + 2 * round-trip time variance. Initialize 784157094Srwatson * shift counter which is used for backoff of 785157094Srwatson * retransmit time. 78611819Sjulian */ 78711819Sjulian if (cb->s_timer[SPXT_REXMT] == 0 && 78811819Sjulian cb->s_snxt != cb->s_rack) { 78911819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 79011819Sjulian if (cb->s_timer[SPXT_PERSIST]) { 79111819Sjulian cb->s_timer[SPXT_PERSIST] = 0; 79211819Sjulian cb->s_rxtshift = 0; 79311819Sjulian } 79411819Sjulian } 795157094Srwatson } else if (SSEQ_LT(cb->s_smax, si->si_seq)) 79611819Sjulian cb->s_smax = si->si_seq; 79711819Sjulian } else if (cb->s_state < TCPS_ESTABLISHED) { 79811819Sjulian if (cb->s_rtt == 0) 79911819Sjulian cb->s_rtt = 1; /* Time initial handshake */ 80011819Sjulian if (cb->s_timer[SPXT_REXMT] == 0) 80111819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 80211819Sjulian } 80311819Sjulian 804157094Srwatson /* 805157094Srwatson * Do not request acks when we ack their data packets or when we do a 806157094Srwatson * gratuitous window update. 807157094Srwatson */ 808157094Srwatson if (((si->si_cc & SPX_SP) == 0) || cb->s_force) 809157094Srwatson si->si_cc |= SPX_SA; 810157094Srwatson si->si_seq = htons(si->si_seq); 811157094Srwatson si->si_alo = htons(alo); 812157094Srwatson si->si_ack = htons(cb->s_ack); 81311819Sjulian 814157094Srwatson if (ipxcksum) 815157094Srwatson si->si_sum = ipx_cksum(m, ntohs(si->si_len)); 816157094Srwatson else 817157094Srwatson si->si_sum = 0xffff; 81811819Sjulian 819157094Srwatson cb->s_outx = 4; 820157094Srwatson if (so->so_options & SO_DEBUG || traceallspxs) 821157094Srwatson spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 822157094Srwatson 823194545Srwatson#ifdef MAC 824194545Srwatson mac_socket_create_mbuf(so, m); 825194545Srwatson#endif 826194545Srwatson 827157094Srwatson if (so->so_options & SO_DONTROUTE) 828157094Srwatson error = ipx_outputfl(m, NULL, IPX_ROUTETOIF); 829157094Srwatson else 830157094Srwatson error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0); 831157094Srwatson if (error) 83211819Sjulian return (error); 83311819Sjulian spxstat.spxs_sndtotal++; 834157094Srwatson 83511819Sjulian /* 836157094Srwatson * Data sent (as far as we can tell). If this advertises a larger 837157094Srwatson * window than any other segment, then remember the size of the 838157094Srwatson * advertized window. Any pending ACK has now been sent. 83911819Sjulian */ 84011819Sjulian cb->s_force = 0; 84111819Sjulian cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); 84211819Sjulian if (SSEQ_GT(alo, cb->s_alo)) 84311819Sjulian cb->s_alo = alo; 84411819Sjulian if (sendalot) 84511819Sjulian goto again; 84611819Sjulian cb->s_outx = 5; 84711819Sjulian return (0); 84811819Sjulian} 84911819Sjulian 85033181Seivindstatic int spx_do_persist_panics = 0; 85111819Sjulian 85225652Sjhaystatic void 853157067Srwatsonspx_setpersist(struct spxpcb *cb) 85411819Sjulian{ 855157067Srwatson int t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 85611819Sjulian 857139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 858139932Srwatson 85911819Sjulian if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics) 86011819Sjulian panic("spx_output REXMT"); 861157094Srwatson 86211819Sjulian /* 86311819Sjulian * Start/restart persistance timer. 86411819Sjulian */ 86511819Sjulian SPXT_RANGESET(cb->s_timer[SPXT_PERSIST], 86611819Sjulian t*spx_backoff[cb->s_rxtshift], 86711819Sjulian SPXTV_PERSMIN, SPXTV_PERSMAX); 86811819Sjulian if (cb->s_rxtshift < SPX_MAXRXTSHIFT) 86911819Sjulian cb->s_rxtshift++; 87011819Sjulian} 87125652Sjhay 87211819Sjulianint 873157067Srwatsonspx_ctloutput(struct socket *so, struct sockopt *sopt) 87411819Sjulian{ 875157125Srwatson struct spxhdr spxhdr; 876157125Srwatson struct ipxpcb *ipxp; 877157067Srwatson struct spxpcb *cb; 87838482Swollman int mask, error; 87938482Swollman short soptval; 88038482Swollman u_short usoptval; 88138482Swollman int optval; 88211819Sjulian 883157128Srwatson ipxp = sotoipxpcb(so); 884157128Srwatson KASSERT(ipxp != NULL, ("spx_ctloutput: ipxp == NULL")); 885157128Srwatson 886157094Srwatson /* 887157094Srwatson * This will have to be changed when we do more general stacking of 888157094Srwatson * protocols. 889157094Srwatson */ 890157094Srwatson if (sopt->sopt_level != IPXPROTO_SPX) 89138482Swollman return (ipx_ctloutput(so, sopt)); 892157125Srwatson 893157128Srwatson IPX_LOCK(ipxp); 894157128Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 895157128Srwatson IPX_UNLOCK(ipxp); 896157128Srwatson return (ECONNRESET); 897157128Srwatson } 898157125Srwatson 899157125Srwatson IPX_LOCK(ipxp); 900157125Srwatson cb = ipxtospxpcb(ipxp); 901157094Srwatson KASSERT(cb != NULL, ("spx_ctloutput: cb == NULL")); 90211819Sjulian 903157125Srwatson error = 0; 90438482Swollman switch (sopt->sopt_dir) { 90538482Swollman case SOPT_GET: 90638482Swollman switch (sopt->sopt_name) { 90711819Sjulian case SO_HEADERS_ON_INPUT: 90811819Sjulian mask = SF_HI; 90911819Sjulian goto get_flags; 91011819Sjulian 91111819Sjulian case SO_HEADERS_ON_OUTPUT: 91211819Sjulian mask = SF_HO; 91311819Sjulian get_flags: 91438482Swollman soptval = cb->s_flags & mask; 915157125Srwatson IPX_UNLOCK(ipxp); 916157125Srwatson error = sooptcopyout(sopt, &soptval, 917157125Srwatson sizeof(soptval)); 91811819Sjulian break; 91911819Sjulian 92011819Sjulian case SO_MTU: 92138482Swollman usoptval = cb->s_mtu; 922157125Srwatson IPX_UNLOCK(ipxp); 923157125Srwatson error = sooptcopyout(sopt, &usoptval, 924157125Srwatson sizeof(usoptval)); 92511819Sjulian break; 92611819Sjulian 92711819Sjulian case SO_LAST_HEADER: 928157125Srwatson spxhdr = cb->s_rhdr; 929157125Srwatson IPX_UNLOCK(ipxp); 930157125Srwatson error = sooptcopyout(sopt, &spxhdr, sizeof(spxhdr)); 93111819Sjulian break; 93211819Sjulian 93311819Sjulian case SO_DEFAULT_HEADERS: 934157125Srwatson spxhdr = cb->s_shdr; 935157125Srwatson IPX_UNLOCK(ipxp); 936157125Srwatson error = sooptcopyout(sopt, &spxhdr, sizeof(spxhdr)); 93711819Sjulian break; 93811819Sjulian 93911819Sjulian default: 940157125Srwatson IPX_UNLOCK(ipxp); 94138482Swollman error = ENOPROTOOPT; 94211819Sjulian } 94311819Sjulian break; 94411819Sjulian 94538482Swollman case SOPT_SET: 946157094Srwatson /* 947157094Srwatson * XXX Why are these shorts on get and ints on set? That 948157094Srwatson * doesn't make any sense... 949157128Srwatson * 950157128Srwatson * XXXRW: Note, when we re-acquire the ipxp lock, we should 951157128Srwatson * re-check that it's not dropped. 952157094Srwatson */ 953157125Srwatson IPX_UNLOCK(ipxp); 95438482Swollman switch (sopt->sopt_name) { 95511819Sjulian case SO_HEADERS_ON_INPUT: 95611819Sjulian mask = SF_HI; 95711819Sjulian goto set_head; 95811819Sjulian 95911819Sjulian case SO_HEADERS_ON_OUTPUT: 96011819Sjulian mask = SF_HO; 96111819Sjulian set_head: 96238482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 96338482Swollman sizeof optval); 96438482Swollman if (error) 96538482Swollman break; 96638482Swollman 967139932Srwatson IPX_LOCK(ipxp); 96811819Sjulian if (cb->s_flags & SF_PI) { 96938482Swollman if (optval) 97011819Sjulian cb->s_flags |= mask; 97111819Sjulian else 97211819Sjulian cb->s_flags &= ~mask; 97311819Sjulian } else error = EINVAL; 974139932Srwatson IPX_UNLOCK(ipxp); 97511819Sjulian break; 97611819Sjulian 97711819Sjulian case SO_MTU: 97838482Swollman error = sooptcopyin(sopt, &usoptval, sizeof usoptval, 97938482Swollman sizeof usoptval); 98038482Swollman if (error) 98138482Swollman break; 982139932Srwatson /* Unlocked write. */ 98338482Swollman cb->s_mtu = usoptval; 98411819Sjulian break; 98511819Sjulian 98611819Sjulian#ifdef SF_NEWCALL 98711819Sjulian case SO_NEWCALL: 98838482Swollman error = sooptcopyin(sopt, &optval, sizeof optval, 98938482Swollman sizeof optval); 99038482Swollman if (error) 99138482Swollman break; 992139932Srwatson IPX_LOCK(ipxp); 99338482Swollman if (optval) { 99411819Sjulian cb->s_flags2 |= SF_NEWCALL; 99511819Sjulian spx_newchecks[5]++; 99611819Sjulian } else { 99711819Sjulian cb->s_flags2 &= ~SF_NEWCALL; 99811819Sjulian spx_newchecks[6]++; 99911819Sjulian } 1000139932Srwatson IPX_UNLOCK(ipxp); 100111819Sjulian break; 100211819Sjulian#endif 100311819Sjulian 100411819Sjulian case SO_DEFAULT_HEADERS: 100511819Sjulian { 100638482Swollman struct spxhdr sp; 100738482Swollman 100838482Swollman error = sooptcopyin(sopt, &sp, sizeof sp, 100938482Swollman sizeof sp); 101038482Swollman if (error) 101138482Swollman break; 1012139932Srwatson IPX_LOCK(ipxp); 101338482Swollman cb->s_dt = sp.spx_dt; 101438482Swollman cb->s_cc = sp.spx_cc & SPX_EM; 1015139932Srwatson IPX_UNLOCK(ipxp); 101611819Sjulian } 101711819Sjulian break; 101811819Sjulian 101911819Sjulian default: 102038482Swollman error = ENOPROTOOPT; 102111819Sjulian } 102211819Sjulian break; 1023157125Srwatson 1024157125Srwatson default: 1025157125Srwatson panic("spx_ctloutput: bad socket option direction"); 102611819Sjulian } 102738482Swollman return (error); 102811819Sjulian} 102911819Sjulian 1030157366Srwatsonstatic void 1031157067Srwatsonspx_usr_abort(struct socket *so) 103211819Sjulian{ 103324659Sjhay struct ipxpcb *ipxp; 103424659Sjhay struct spxpcb *cb; 103511819Sjulian 103624659Sjhay ipxp = sotoipxpcb(so); 1037157094Srwatson KASSERT(ipxp != NULL, ("spx_usr_abort: ipxp == NULL")); 1038157094Srwatson 103924659Sjhay cb = ipxtospxpcb(ipxp); 1040157094Srwatson KASSERT(cb != NULL, ("spx_usr_abort: cb == NULL")); 104111819Sjulian 1042139932Srwatson IPX_LIST_LOCK(); 1043139932Srwatson IPX_LOCK(ipxp); 104424659Sjhay spx_drop(cb, ECONNABORTED); 1045160549Srwatson IPX_UNLOCK(ipxp); 1046139932Srwatson IPX_LIST_UNLOCK(); 104724659Sjhay} 104811819Sjulian 104924659Sjhay/* 1050157094Srwatson * Accept a connection. Essentially all the work is done at higher levels; 1051157094Srwatson * just return the address of the peer, storing through addr. 105224659Sjhay */ 105324659Sjhaystatic int 1054157067Srwatsonspx_accept(struct socket *so, struct sockaddr **nam) 105524659Sjhay{ 105624659Sjhay struct ipxpcb *ipxp; 105728270Swollman struct sockaddr_ipx *sipx, ssipx; 105811819Sjulian 105924659Sjhay ipxp = sotoipxpcb(so); 1060157154Srwatson KASSERT(ipxp != NULL, ("spx_accept: ipxp == NULL")); 1061157094Srwatson 106228270Swollman sipx = &ssipx; 106328270Swollman bzero(sipx, sizeof *sipx); 106428270Swollman sipx->sipx_len = sizeof *sipx; 106524659Sjhay sipx->sipx_family = AF_IPX; 1066139932Srwatson IPX_LOCK(ipxp); 106724659Sjhay sipx->sipx_addr = ipxp->ipxp_faddr; 1068139932Srwatson IPX_UNLOCK(ipxp); 1069139932Srwatson *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK); 107024659Sjhay return (0); 107124659Sjhay} 107224659Sjhay 107324659Sjhaystatic int 1074157067Srwatsonspx_attach(struct socket *so, int proto, struct thread *td) 107524659Sjhay{ 107624659Sjhay struct ipxpcb *ipxp; 107724659Sjhay struct spxpcb *cb; 107824659Sjhay struct mbuf *mm; 107924659Sjhay struct sockbuf *sb; 1080139932Srwatson int error; 108124659Sjhay 108224659Sjhay ipxp = sotoipxpcb(so); 1083157094Srwatson KASSERT(ipxp == NULL, ("spx_attach: ipxp != NULL")); 108424659Sjhay 108524659Sjhay if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 108624659Sjhay error = soreserve(so, (u_long) 3072, (u_long) 3072); 108711819Sjulian if (error) 1088157127Srwatson return (error); 108924659Sjhay } 109011819Sjulian 1091184205Sdes cb = malloc(sizeof *cb, M_PCB, M_NOWAIT | M_ZERO); 1092157127Srwatson if (cb == NULL) 1093157127Srwatson return (ENOBUFS); 1094243882Sglebius mm = m_getclr(M_NOWAIT, MT_DATA); 109524659Sjhay if (mm == NULL) { 1096184205Sdes free(cb, M_PCB); 1097157127Srwatson return (ENOBUFS); 109824659Sjhay } 1099157127Srwatson 1100157127Srwatson IPX_LIST_LOCK(); 1101157127Srwatson error = ipx_pcballoc(so, &ipxpcb_list, td); 1102157127Srwatson if (error) { 1103157127Srwatson IPX_LIST_UNLOCK(); 1104157127Srwatson m_free(mm); 1105184205Sdes free(cb, M_PCB); 1106157127Srwatson return (error); 1107157127Srwatson } 1108157127Srwatson ipxp = sotoipxpcb(so); 1109157145Srwatson ipxp->ipxp_flags |= IPXP_SPX; 1110157127Srwatson 111124659Sjhay cb->s_state = TCPS_LISTEN; 111224659Sjhay cb->s_smax = -1; 111324659Sjhay cb->s_swl1 = -1; 1114192753Srwatson spx_reass_init(cb); 111524659Sjhay cb->s_ipxpcb = ipxp; 111625652Sjhay cb->s_mtu = 576 - sizeof(struct spx); 1117157094Srwatson sb = &so->so_snd; 111824659Sjhay cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; 111924659Sjhay cb->s_ssthresh = cb->s_cwnd; 112025652Sjhay cb->s_cwmx = sbspace(sb) * CUNIT / (2 * sizeof(struct spx)); 1121179408Srwatson 1122157094Srwatson /* 1123157094Srwatson * Above is recomputed when connecting to account for changed 1124157094Srwatson * buffering or mtu's. 1125157094Srwatson */ 112624659Sjhay cb->s_rtt = SPXTV_SRTTBASE; 112724659Sjhay cb->s_rttvar = SPXTV_SRTTDFLT << 2; 112824659Sjhay SPXT_RANGESET(cb->s_rxtcur, 112924659Sjhay ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1, 113024659Sjhay SPXTV_MIN, SPXTV_REXMTMAX); 1131139584Srwatson ipxp->ipxp_pcb = (caddr_t)cb; 1132139932Srwatson IPX_LIST_UNLOCK(); 1133157128Srwatson return (0); 113424659Sjhay} 113511819Sjulian 1136157128Srwatsonstatic void 1137157128Srwatsonspx_pcbdetach(struct ipxpcb *ipxp) 1138157128Srwatson{ 1139157128Srwatson struct spxpcb *cb; 1140157128Srwatson 1141157128Srwatson IPX_LOCK_ASSERT(ipxp); 1142157128Srwatson 1143157128Srwatson cb = ipxtospxpcb(ipxp); 1144157128Srwatson KASSERT(cb != NULL, ("spx_pcbdetach: cb == NULL")); 1145157128Srwatson 1146192753Srwatson spx_reass_flush(cb); 1147184205Sdes free(cb, M_PCB); 1148157128Srwatson ipxp->ipxp_pcb = NULL; 1149157128Srwatson} 1150157128Srwatson 115124659Sjhaystatic int 1152157067Srwatsonspx_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 1153139584Srwatson{ 115424659Sjhay struct ipxpcb *ipxp; 1155139932Srwatson int error; 115611819Sjulian 115724659Sjhay ipxp = sotoipxpcb(so); 1158157094Srwatson KASSERT(ipxp != NULL, ("spx_bind: ipxp == NULL")); 115911819Sjulian 1160139932Srwatson IPX_LIST_LOCK(); 1161139932Srwatson IPX_LOCK(ipxp); 1162157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1163157153Srwatson error = EINVAL; 1164157153Srwatson goto out; 1165157153Srwatson } 1166139932Srwatson error = ipx_pcbbind(ipxp, nam, td); 1167157153Srwatsonout: 1168139932Srwatson IPX_UNLOCK(ipxp); 1169139932Srwatson IPX_LIST_UNLOCK(); 1170139932Srwatson return (error); 1171139584Srwatson} 1172139584Srwatson 1173160549Srwatsonstatic void 1174160549Srwatsonspx_usr_close(struct socket *so) 1175160549Srwatson{ 1176160549Srwatson struct ipxpcb *ipxp; 1177160549Srwatson struct spxpcb *cb; 1178160549Srwatson 1179160549Srwatson ipxp = sotoipxpcb(so); 1180160549Srwatson KASSERT(ipxp != NULL, ("spx_usr_close: ipxp == NULL")); 1181160549Srwatson 1182160549Srwatson cb = ipxtospxpcb(ipxp); 1183160549Srwatson KASSERT(cb != NULL, ("spx_usr_close: cb == NULL")); 1184160549Srwatson 1185160549Srwatson IPX_LIST_LOCK(); 1186160549Srwatson IPX_LOCK(ipxp); 1187160549Srwatson if (cb->s_state > TCPS_LISTEN) 1188160549Srwatson spx_disconnect(cb); 1189160549Srwatson else 1190160549Srwatson spx_close(cb); 1191160549Srwatson IPX_UNLOCK(ipxp); 1192160549Srwatson IPX_LIST_UNLOCK(); 1193160549Srwatson} 1194160549Srwatson 119524659Sjhay/* 1196157094Srwatson * Initiate connection to peer. Enter SYN_SENT state, and mark socket as 1197157094Srwatson * connecting. Start keep-alive timer, setup prototype header, send initial 1198157094Srwatson * system packet requesting connection. 119924659Sjhay */ 120024659Sjhaystatic int 1201157067Srwatsonspx_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 120224659Sjhay{ 120324659Sjhay struct ipxpcb *ipxp; 120424659Sjhay struct spxpcb *cb; 1205139932Srwatson int error; 120611819Sjulian 120724659Sjhay ipxp = sotoipxpcb(so); 1208157094Srwatson KASSERT(ipxp != NULL, ("spx_connect: ipxp == NULL")); 1209157094Srwatson 121024659Sjhay cb = ipxtospxpcb(ipxp); 1211157094Srwatson KASSERT(cb != NULL, ("spx_connect: cb == NULL")); 121224659Sjhay 1213139932Srwatson IPX_LIST_LOCK(); 1214139932Srwatson IPX_LOCK(ipxp); 1215157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1216157153Srwatson error = EINVAL; 1217157153Srwatson goto spx_connect_end; 1218157153Srwatson } 121924659Sjhay if (ipxp->ipxp_lport == 0) { 1220139579Srwatson error = ipx_pcbbind(ipxp, NULL, td); 122124659Sjhay if (error) 122224659Sjhay goto spx_connect_end; 122324659Sjhay } 122483366Sjulian error = ipx_pcbconnect(ipxp, nam, td); 122524659Sjhay if (error) 122624659Sjhay goto spx_connect_end; 122724659Sjhay soisconnecting(so); 122824659Sjhay spxstat.spxs_connattempt++; 122924659Sjhay cb->s_state = TCPS_SYN_SENT; 123024659Sjhay cb->s_did = 0; 123124659Sjhay spx_template(cb); 123224659Sjhay cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 123324659Sjhay cb->s_force = 1 + SPXTV_KEEP; 1234179408Srwatson 123511819Sjulian /* 1236157094Srwatson * Other party is required to respond to the port I send from, but he 1237157094Srwatson * is not required to answer from where I am sending to, so allow 1238157094Srwatson * wildcarding. Original port I am sending to is still saved in 123924659Sjhay * cb->s_dport. 124011819Sjulian */ 124124659Sjhay ipxp->ipxp_fport = 0; 1242139579Srwatson error = spx_output(cb, NULL); 124324659Sjhayspx_connect_end: 1244139932Srwatson IPX_UNLOCK(ipxp); 1245139932Srwatson IPX_LIST_UNLOCK(); 124624659Sjhay return (error); 124724659Sjhay} 124811819Sjulian 1249157370Srwatsonstatic void 1250157067Srwatsonspx_detach(struct socket *so) 125124659Sjhay{ 125224659Sjhay struct ipxpcb *ipxp; 125324659Sjhay struct spxpcb *cb; 125411819Sjulian 1255160549Srwatson /* 1256160549Srwatson * XXXRW: Should assert appropriately detached. 1257160549Srwatson */ 125824659Sjhay ipxp = sotoipxpcb(so); 1259157094Srwatson KASSERT(ipxp != NULL, ("spx_detach: ipxp == NULL")); 1260157094Srwatson 126124659Sjhay cb = ipxtospxpcb(ipxp); 1262157094Srwatson KASSERT(cb != NULL, ("spx_detach: cb == NULL")); 126311819Sjulian 1264139932Srwatson IPX_LIST_LOCK(); 1265139932Srwatson IPX_LOCK(ipxp); 1266157128Srwatson spx_pcbdetach(ipxp); 1267192757Srwatson ipx_pcbdetach(ipxp); 1268157128Srwatson ipx_pcbfree(ipxp); 1269139932Srwatson IPX_LIST_UNLOCK(); 127024659Sjhay} 127111819Sjulian 127224659Sjhay/* 1273157094Srwatson * We may decide later to implement connection closing handshaking at the spx 1274157094Srwatson * level optionally. Here is the hook to do it: 127524659Sjhay */ 127624659Sjhaystatic int 1277157067Srwatsonspx_usr_disconnect(struct socket *so) 127824659Sjhay{ 127924659Sjhay struct ipxpcb *ipxp; 128024659Sjhay struct spxpcb *cb; 1281157153Srwatson int error; 128211819Sjulian 128324659Sjhay ipxp = sotoipxpcb(so); 1284157094Srwatson KASSERT(ipxp != NULL, ("spx_usr_disconnect: ipxp == NULL")); 1285157094Srwatson 128624659Sjhay cb = ipxtospxpcb(ipxp); 1287157094Srwatson KASSERT(cb != NULL, ("spx_usr_disconnect: cb == NULL")); 128811819Sjulian 1289139932Srwatson IPX_LIST_LOCK(); 1290139932Srwatson IPX_LOCK(ipxp); 1291157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1292157153Srwatson error = EINVAL; 1293157153Srwatson goto out; 1294157153Srwatson } 129524659Sjhay spx_disconnect(cb); 1296157153Srwatson error = 0; 1297157153Srwatsonout: 1298157128Srwatson IPX_UNLOCK(ipxp); 1299139932Srwatson IPX_LIST_UNLOCK(); 1300157153Srwatson return (error); 130124659Sjhay} 130211819Sjulian 130324659Sjhaystatic int 1304157067Srwatsonspx_listen(struct socket *so, int backlog, struct thread *td) 130524659Sjhay{ 130624659Sjhay int error; 130724659Sjhay struct ipxpcb *ipxp; 130824659Sjhay struct spxpcb *cb; 130911819Sjulian 131024659Sjhay error = 0; 131124659Sjhay ipxp = sotoipxpcb(so); 1312157094Srwatson KASSERT(ipxp != NULL, ("spx_listen: ipxp == NULL")); 1313157094Srwatson 131424659Sjhay cb = ipxtospxpcb(ipxp); 1315157094Srwatson KASSERT(cb != NULL, ("spx_listen: cb == NULL")); 131611819Sjulian 1317139932Srwatson IPX_LIST_LOCK(); 1318139932Srwatson IPX_LOCK(ipxp); 1319157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1320157153Srwatson error = EINVAL; 1321157153Srwatson goto out; 1322157153Srwatson } 1323142190Srwatson SOCK_LOCK(so); 1324142190Srwatson error = solisten_proto_check(so); 1325142190Srwatson if (error == 0 && ipxp->ipxp_lport == 0) 1326139579Srwatson error = ipx_pcbbind(ipxp, NULL, td); 1327142190Srwatson if (error == 0) { 132824659Sjhay cb->s_state = TCPS_LISTEN; 1329151888Srwatson solisten_proto(so, backlog); 1330142190Srwatson } 1331142190Srwatson SOCK_UNLOCK(so); 1332157153Srwatsonout: 1333139932Srwatson IPX_UNLOCK(ipxp); 1334139932Srwatson IPX_LIST_UNLOCK(); 133524659Sjhay return (error); 133624659Sjhay} 133711819Sjulian 133824659Sjhay/* 1339157094Srwatson * After a receive, possibly send acknowledgment updating allocation. 134024659Sjhay */ 134124659Sjhaystatic int 1342157067Srwatsonspx_rcvd(struct socket *so, int flags) 134324659Sjhay{ 134424659Sjhay struct ipxpcb *ipxp; 134524659Sjhay struct spxpcb *cb; 1346157153Srwatson int error; 134711819Sjulian 134824659Sjhay ipxp = sotoipxpcb(so); 1349157094Srwatson KASSERT(ipxp != NULL, ("spx_rcvd: ipxp == NULL")); 1350157094Srwatson 135124659Sjhay cb = ipxtospxpcb(ipxp); 1352157094Srwatson KASSERT(cb != NULL, ("spx_rcvd: cb == NULL")); 135311819Sjulian 1354139932Srwatson IPX_LOCK(ipxp); 1355157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1356157153Srwatson error = EINVAL; 1357157153Srwatson goto out; 1358157153Srwatson } 135924659Sjhay cb->s_flags |= SF_RVD; 1360139579Srwatson spx_output(cb, NULL); 136124659Sjhay cb->s_flags &= ~SF_RVD; 1362157153Srwatson error = 0; 1363157153Srwatsonout: 1364139932Srwatson IPX_UNLOCK(ipxp); 1365157153Srwatson return (error); 136624659Sjhay} 136711819Sjulian 136824659Sjhaystatic int 1369157067Srwatsonspx_rcvoob(struct socket *so, struct mbuf *m, int flags) 137024659Sjhay{ 137124659Sjhay struct ipxpcb *ipxp; 137224659Sjhay struct spxpcb *cb; 1373157153Srwatson int error; 137411819Sjulian 137524659Sjhay ipxp = sotoipxpcb(so); 1376157094Srwatson KASSERT(ipxp != NULL, ("spx_rcvoob: ipxp == NULL")); 1377157094Srwatson 137824659Sjhay cb = ipxtospxpcb(ipxp); 1379157094Srwatson KASSERT(cb != NULL, ("spx_rcvoob: cb == NULL")); 138011819Sjulian 1381157128Srwatson IPX_LOCK(ipxp); 1382157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1383157153Srwatson error = EINVAL; 1384157153Srwatson goto out; 1385157153Srwatson } 1386139591Srwatson SOCKBUF_LOCK(&so->so_rcv); 138724659Sjhay if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 1388130480Srwatson (so->so_rcv.sb_state & SBS_RCVATMARK)) { 1389139591Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 139024659Sjhay m->m_len = 1; 139124659Sjhay *mtod(m, caddr_t) = cb->s_iobc; 1392157153Srwatson error = 0; 1393157153Srwatson goto out; 139411819Sjulian } 1395139591Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 1396157153Srwatson error = EINVAL; 1397157153Srwatsonout: 1398157128Srwatson IPX_UNLOCK(ipxp); 1399157153Srwatson return (error); 140024659Sjhay} 140124659Sjhay 140224659Sjhaystatic int 1403157067Srwatsonspx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 1404157067Srwatson struct mbuf *controlp, struct thread *td) 140524659Sjhay{ 140624659Sjhay struct ipxpcb *ipxp; 140724659Sjhay struct spxpcb *cb; 1408157153Srwatson int error; 140924659Sjhay 141024659Sjhay ipxp = sotoipxpcb(so); 1411157094Srwatson KASSERT(ipxp != NULL, ("spx_send: ipxp == NULL")); 1412157094Srwatson 141324659Sjhay cb = ipxtospxpcb(ipxp); 1414157094Srwatson KASSERT(cb != NULL, ("spx_send: cb == NULL")); 141524659Sjhay 1416157094Srwatson error = 0; 1417139932Srwatson IPX_LOCK(ipxp); 1418157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1419157153Srwatson error = ECONNRESET; 1420157153Srwatson goto spx_send_end; 1421157153Srwatson } 142224659Sjhay if (flags & PRUS_OOB) { 142324659Sjhay if (sbspace(&so->so_snd) < -512) { 142424659Sjhay error = ENOBUFS; 142524659Sjhay goto spx_send_end; 142624659Sjhay } 142724659Sjhay cb->s_oobflags |= SF_SOOB; 142824659Sjhay } 142925652Sjhay if (controlp != NULL) { 143024659Sjhay u_short *p = mtod(controlp, u_short *); 143124659Sjhay spx_newchecks[2]++; 143225652Sjhay if ((p[0] == 5) && (p[1] == 1)) { /* XXXX, for testing */ 143324659Sjhay cb->s_shdr.spx_dt = *(u_char *)(&p[2]); 143424659Sjhay spx_newchecks[3]++; 143524659Sjhay } 143624659Sjhay m_freem(controlp); 143724659Sjhay } 143824659Sjhay controlp = NULL; 143924659Sjhay error = spx_output(cb, m); 144024659Sjhay m = NULL; 144124659Sjhayspx_send_end: 1442139932Srwatson IPX_UNLOCK(ipxp); 144311819Sjulian if (controlp != NULL) 144411819Sjulian m_freem(controlp); 144511819Sjulian if (m != NULL) 144611819Sjulian m_freem(m); 144711819Sjulian return (error); 144811819Sjulian} 144911819Sjulian 145024659Sjhaystatic int 1451157067Srwatsonspx_shutdown(struct socket *so) 145224659Sjhay{ 145324659Sjhay struct ipxpcb *ipxp; 145424659Sjhay struct spxpcb *cb; 1455157153Srwatson int error; 145624659Sjhay 145724659Sjhay ipxp = sotoipxpcb(so); 1458157094Srwatson KASSERT(ipxp != NULL, ("spx_shutdown: ipxp == NULL")); 1459157094Srwatson 146024659Sjhay cb = ipxtospxpcb(ipxp); 1461157094Srwatson KASSERT(cb != NULL, ("spx_shutdown: cb == NULL")); 146224659Sjhay 146324659Sjhay socantsendmore(so); 1464139932Srwatson IPX_LIST_LOCK(); 1465139932Srwatson IPX_LOCK(ipxp); 1466157153Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) { 1467157153Srwatson error = EINVAL; 1468157153Srwatson goto out; 1469157153Srwatson } 1470139931Srwatson spx_usrclosed(cb); 1471157153Srwatson error = 0; 1472157153Srwatsonout: 1473157128Srwatson IPX_UNLOCK(ipxp); 1474139932Srwatson IPX_LIST_UNLOCK(); 1475157153Srwatson return (error); 147624659Sjhay} 147724659Sjhay 147824659Sjhaystatic int 1479157067Srwatsonspx_sp_attach(struct socket *so, int proto, struct thread *td) 148011819Sjulian{ 1481157127Srwatson struct ipxpcb *ipxp; 1482157127Srwatson struct spxpcb *cb; 148324659Sjhay int error; 148411819Sjulian 1485157127Srwatson KASSERT(so->so_pcb == NULL, ("spx_sp_attach: so_pcb != NULL")); 1486157127Srwatson 148783366Sjulian error = spx_attach(so, proto, td); 1488157127Srwatson if (error) 1489157127Srwatson return (error); 1490157127Srwatson 1491157127Srwatson ipxp = sotoipxpcb(so); 1492157127Srwatson KASSERT(ipxp != NULL, ("spx_sp_attach: ipxp == NULL")); 1493157127Srwatson 1494157127Srwatson cb = ipxtospxpcb(ipxp); 1495157127Srwatson KASSERT(cb != NULL, ("spx_sp_attach: cb == NULL")); 1496157127Srwatson 1497157127Srwatson IPX_LOCK(ipxp); 1498157127Srwatson cb->s_flags |= (SF_HI | SF_HO | SF_PI); 1499157127Srwatson IPX_UNLOCK(ipxp); 1500157127Srwatson return (0); 150111819Sjulian} 150211819Sjulian 150311819Sjulian/* 1504157094Srwatson * Create template to be used to send spx packets on a connection. Called 1505157094Srwatson * after host entry created, fills in a skeletal spx header (choosing 1506157094Srwatson * connection id), minimizing the amount of work necessary when the 1507157094Srwatson * connection is used. 150811819Sjulian */ 150925652Sjhaystatic void 1510157067Srwatsonspx_template(struct spxpcb *cb) 151111819Sjulian{ 1512157067Srwatson struct ipxpcb *ipxp = cb->s_ipxpcb; 1513157067Srwatson struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd); 151411819Sjulian 1515139932Srwatson IPX_LOCK_ASSERT(ipxp); 1516139932Srwatson 1517192754Srwatson cb->s_ipx.ipx_pt = IPXPROTO_SPX; 1518192754Srwatson cb->s_ipx.ipx_sna = ipxp->ipxp_laddr; 1519192754Srwatson cb->s_ipx.ipx_dna = ipxp->ipxp_faddr; 1520157069Srwatson SPX_LOCK(); 152111819Sjulian cb->s_sid = htons(spx_iss); 152211819Sjulian spx_iss += SPX_ISSINCR/2; 1523157069Srwatson SPX_UNLOCK(); 152411819Sjulian cb->s_alo = 1; 152511819Sjulian cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; 1526179408Srwatson 1527179408Srwatson /* 1528179408Srwatson * Try to expand fast to full complement of large packets. 1529179408Srwatson */ 1530157094Srwatson cb->s_ssthresh = cb->s_cwnd; 153111819Sjulian cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx)); 1532179408Srwatson 1533179408Srwatson /* 1534179408Srwatson * But allow for lots of little packets as well. 1535179408Srwatson */ 153611819Sjulian cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); 153711819Sjulian} 153811819Sjulian 153911819Sjulian/* 1540157128Srwatson * Close a SPIP control block. Wake up any sleepers. We used to free any 1541192754Srwatson * queued packets, but now we defer that until the pcb is discarded. 154211819Sjulian */ 1543139931Srwatsonvoid 1544157067Srwatsonspx_close(struct spxpcb *cb) 154511819Sjulian{ 154611819Sjulian struct ipxpcb *ipxp = cb->s_ipxpcb; 154711819Sjulian struct socket *so = ipxp->ipxp_socket; 154811819Sjulian 1549157094Srwatson KASSERT(ipxp != NULL, ("spx_close: ipxp == NULL")); 1550139932Srwatson IPX_LIST_LOCK_ASSERT(); 1551139932Srwatson IPX_LOCK_ASSERT(ipxp); 1552139932Srwatson 1553157128Srwatson ipxp->ipxp_flags |= IPXP_DROPPED; 155411819Sjulian soisdisconnected(so); 155511819Sjulian spxstat.spxs_closed++; 155611819Sjulian} 155725652Sjhay 155811819Sjulian/* 1559157094Srwatson * Someday we may do level 3 handshaking to close a connection or send a 1560157094Srwatson * xerox style error. For now, just close. cb will always be invalid after 1561157094Srwatson * this call. 156211819Sjulian */ 1563139931Srwatsonstatic void 1564157067Srwatsonspx_usrclosed(struct spxpcb *cb) 156511819Sjulian{ 1566139931Srwatson 1567139932Srwatson IPX_LIST_LOCK_ASSERT(); 1568139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 1569139932Srwatson 1570139931Srwatson spx_close(cb); 157111819Sjulian} 157225652Sjhay 1573139931Srwatson/* 1574139931Srwatson * cb will always be invalid after this call. 1575139931Srwatson */ 1576139931Srwatsonstatic void 1577157067Srwatsonspx_disconnect(struct spxpcb *cb) 157811819Sjulian{ 1579139931Srwatson 1580139932Srwatson IPX_LIST_LOCK_ASSERT(); 1581139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 1582139932Srwatson 1583139931Srwatson spx_close(cb); 158411819Sjulian} 158525652Sjhay 158611819Sjulian/* 1587157094Srwatson * Drop connection, reporting the specified error. cb will always be invalid 1588157094Srwatson * after this call. 158911819Sjulian */ 1590139931Srwatsonstatic void 1591157067Srwatsonspx_drop(struct spxpcb *cb, int errno) 159211819Sjulian{ 159311819Sjulian struct socket *so = cb->s_ipxpcb->ipxp_socket; 159411819Sjulian 1595139932Srwatson IPX_LIST_LOCK_ASSERT(); 1596139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 1597139932Srwatson 159811819Sjulian /* 1599157094Srwatson * Someday, in the xerox world we will generate error protocol 1600157094Srwatson * packets announcing that the socket has gone away. 160111819Sjulian */ 160211819Sjulian if (TCPS_HAVERCVDSYN(cb->s_state)) { 160311819Sjulian spxstat.spxs_drops++; 160411819Sjulian cb->s_state = TCPS_CLOSED; 160525652Sjhay /*tcp_output(cb);*/ 160611819Sjulian } else 160711819Sjulian spxstat.spxs_conndrops++; 160811819Sjulian so->so_error = errno; 1609139931Srwatson spx_close(cb); 161011819Sjulian} 161111819Sjulian 161211819Sjulian/* 1613157094Srwatson * Fast timeout routine for processing delayed acks. 161411819Sjulian */ 161511819Sjulianvoid 1616157067Srwatsonspx_fasttimo(void) 161711819Sjulian{ 1618139932Srwatson struct ipxpcb *ipxp; 1619139932Srwatson struct spxpcb *cb; 162011819Sjulian 1621139932Srwatson IPX_LIST_LOCK(); 1622139444Srwatson LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 1623139932Srwatson IPX_LOCK(ipxp); 1624157145Srwatson if (!(ipxp->ipxp_flags & IPXP_SPX) || 1625157145Srwatson (ipxp->ipxp_flags & IPXP_DROPPED)) { 1626157145Srwatson IPX_UNLOCK(ipxp); 1627157145Srwatson continue; 162811819Sjulian } 1629157145Srwatson cb = ipxtospxpcb(ipxp); 1630157145Srwatson if (cb->s_flags & SF_DELACK) { 1631157145Srwatson cb->s_flags &= ~SF_DELACK; 1632157145Srwatson cb->s_flags |= SF_ACKNOW; 1633157145Srwatson spxstat.spxs_delack++; 1634157145Srwatson spx_output(cb, NULL); 1635157145Srwatson } 1636139932Srwatson IPX_UNLOCK(ipxp); 1637139444Srwatson } 1638139932Srwatson IPX_LIST_UNLOCK(); 163911819Sjulian} 164011819Sjulian 164111819Sjulian/* 1642157094Srwatson * spx protocol timeout routine called every 500 ms. Updates the timers in 1643157094Srwatson * all active pcb's and causes finite state machine actions if timers expire. 164411819Sjulian */ 164511819Sjulianvoid 1646157067Srwatsonspx_slowtimo(void) 164711819Sjulian{ 1648157128Srwatson struct ipxpcb *ipxp; 1649139932Srwatson struct spxpcb *cb; 1650139932Srwatson int i; 165111819Sjulian 165211819Sjulian /* 1653157128Srwatson * Search through tcb's and update active timers. Once, timers could 1654157128Srwatson * free ipxp's, but now we do that only when detaching a socket. 165511819Sjulian */ 1656139932Srwatson IPX_LIST_LOCK(); 1657157128Srwatson LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 1658157128Srwatson IPX_LOCK(ipxp); 1659157145Srwatson if (!(ipxp->ipxp_flags & IPXP_SPX) || 1660157145Srwatson (ipxp->ipxp_flags & IPXP_DROPPED)) { 1661157128Srwatson IPX_UNLOCK(ipxp); 1662139444Srwatson continue; 1663157128Srwatson } 1664157128Srwatson 1665157128Srwatson cb = (struct spxpcb *)ipxp->ipxp_pcb; 1666157128Srwatson KASSERT(cb != NULL, ("spx_slowtimo: cb == NULL")); 166711819Sjulian for (i = 0; i < SPXT_NTIMERS; i++) { 166811819Sjulian if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 1669157128Srwatson spx_timers(cb, i); 1670157128Srwatson if (ipxp->ipxp_flags & IPXP_DROPPED) 1671139581Srwatson break; 167211819Sjulian } 167311819Sjulian } 1674157128Srwatson if (!(ipxp->ipxp_flags & IPXP_DROPPED)) { 1675139581Srwatson cb->s_idle++; 1676139581Srwatson if (cb->s_rtt) 1677139581Srwatson cb->s_rtt++; 1678139581Srwatson } 1679157128Srwatson IPX_UNLOCK(ipxp); 168011819Sjulian } 1681157069Srwatson IPX_LIST_UNLOCK(); 1682157069Srwatson SPX_LOCK(); 168311819Sjulian spx_iss += SPX_ISSINCR/PR_SLOWHZ; /* increment iss */ 1684157069Srwatson SPX_UNLOCK(); 168511819Sjulian} 168625652Sjhay 168711819Sjulian/* 168811819Sjulian * SPX timer processing. 168911819Sjulian */ 1690157128Srwatsonstatic void 1691157067Srwatsonspx_timers(struct spxpcb *cb, int timer) 169211819Sjulian{ 169311819Sjulian long rexmt; 169411819Sjulian int win; 169511819Sjulian 1696139932Srwatson IPX_LIST_LOCK_ASSERT(); 1697139932Srwatson IPX_LOCK_ASSERT(cb->s_ipxpcb); 1698139932Srwatson 169911819Sjulian cb->s_force = 1 + timer; 170011819Sjulian switch (timer) { 170111819Sjulian case SPXT_2MSL: 1702157124Srwatson /* 1703157124Srwatson * 2 MSL timeout in shutdown went off. TCP deletes 1704157124Srwatson * connection control block. 1705157124Srwatson */ 170611819Sjulian printf("spx: SPXT_2MSL went off for no reason\n"); 170711819Sjulian cb->s_timer[timer] = 0; 170811819Sjulian break; 170911819Sjulian 171011819Sjulian case SPXT_REXMT: 1711157124Srwatson /* 1712157124Srwatson * Retransmission timer went off. Message has not been acked 1713157124Srwatson * within retransmit interval. Back off to a longer 1714157124Srwatson * retransmit interval and retransmit one packet. 1715157124Srwatson */ 171611819Sjulian if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) { 171711819Sjulian cb->s_rxtshift = SPX_MAXRXTSHIFT; 171811819Sjulian spxstat.spxs_timeoutdrop++; 1719139931Srwatson spx_drop(cb, ETIMEDOUT); 172011819Sjulian break; 172111819Sjulian } 172211819Sjulian spxstat.spxs_rexmttimeo++; 172311819Sjulian rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 172411819Sjulian rexmt *= spx_backoff[cb->s_rxtshift]; 172511819Sjulian SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX); 172611819Sjulian cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 1727157094Srwatson 172811819Sjulian /* 1729157094Srwatson * If we have backed off fairly far, our srtt estimate is 1730157094Srwatson * probably bogus. Clobber it so we'll take the next rtt 1731157094Srwatson * measurement as our srtt; move the current srtt into rttvar 1732157094Srwatson * to keep the current retransmit times until then. 173311819Sjulian */ 173411819Sjulian if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) { 173511819Sjulian cb->s_rttvar += (cb->s_srtt >> 2); 173611819Sjulian cb->s_srtt = 0; 173711819Sjulian } 173811819Sjulian cb->s_snxt = cb->s_rack; 1739157094Srwatson 174011819Sjulian /* 174111819Sjulian * If timing a packet, stop the timer. 174211819Sjulian */ 174311819Sjulian cb->s_rtt = 0; 1744157094Srwatson 174511819Sjulian /* 174611819Sjulian * See very long discussion in tcp_timer.c about congestion 1747157094Srwatson * window and sstrhesh. 174811819Sjulian */ 174911819Sjulian win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; 175011819Sjulian if (win < 2) 175111819Sjulian win = 2; 175211819Sjulian cb->s_cwnd = CUNIT; 175311819Sjulian cb->s_ssthresh = win * CUNIT; 1754139579Srwatson spx_output(cb, NULL); 175511819Sjulian break; 175611819Sjulian 175711819Sjulian case SPXT_PERSIST: 1758157094Srwatson /* 1759157094Srwatson * Persistance timer into zero window. Force a probe to be 1760157094Srwatson * sent. 1761157094Srwatson */ 176211819Sjulian spxstat.spxs_persisttimeo++; 176311819Sjulian spx_setpersist(cb); 1764139579Srwatson spx_output(cb, NULL); 176511819Sjulian break; 176611819Sjulian 176711819Sjulian case SPXT_KEEP: 1768157094Srwatson /* 1769157094Srwatson * Keep-alive timer went off; send something or drop 1770157094Srwatson * connection if idle for too long. 1771157094Srwatson */ 177211819Sjulian spxstat.spxs_keeptimeo++; 177311819Sjulian if (cb->s_state < TCPS_ESTABLISHED) 177411819Sjulian goto dropit; 177511819Sjulian if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) { 177611819Sjulian if (cb->s_idle >= SPXTV_MAXIDLE) 177711819Sjulian goto dropit; 177811819Sjulian spxstat.spxs_keepprobe++; 1779139579Srwatson spx_output(cb, NULL); 178097658Stanimura } else 178111819Sjulian cb->s_idle = 0; 178211819Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 178311819Sjulian break; 1784157094Srwatson 178511819Sjulian dropit: 178611819Sjulian spxstat.spxs_keepdrops++; 1787139931Srwatson spx_drop(cb, ETIMEDOUT); 178811819Sjulian break; 1789157124Srwatson 1790157124Srwatson default: 1791157124Srwatson panic("spx_timers: unknown timer %d", timer); 179211819Sjulian } 179311819Sjulian} 1794