spx_reass.c revision 139823
19313Ssos/*- 2230132Suqs * Copyright (c) 2004 Robert N. M. Watson 39313Ssos * Copyright (c) 1995, Mike Mitchell 49313Ssos * Copyright (c) 1984, 1985, 1986, 1987, 1993 59313Ssos * The Regents of the University of California. All rights reserved. 69313Ssos * 79313Ssos * Redistribution and use in source and binary forms, with or without 89313Ssos * modification, are permitted provided that the following conditions 9111798Sdes * are met: 109313Ssos * 1. Redistributions of source code must retain the above copyright 119313Ssos * notice, this list of conditions and the following disclaimer. 129313Ssos * 2. Redistributions in binary form must reproduce the above copyright 139313Ssos * notice, this list of conditions and the following disclaimer in the 149313Ssos * documentation and/or other materials provided with the distribution. 1597748Sschweikh * 3. All advertising materials mentioning features or use of this software 169313Ssos * must display the following acknowledgement: 179313Ssos * This product includes software developed by the University of 189313Ssos * California, Berkeley and its contributors. 199313Ssos * 4. Neither the name of the University nor the names of its contributors 209313Ssos * may be used to endorse or promote products derived from this software 219313Ssos * without specific prior written permission. 229313Ssos * 239313Ssos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 249313Ssos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 259313Ssos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 269313Ssos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 279313Ssos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 289313Ssos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29116173Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30116173Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31116173Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32156874Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3331784Seivind * SUCH DAMAGE. 349313Ssos * 359313Ssos * @(#)spx_usrreq.h 36224778Srwatson */ 3776166Smarkm 3876166Smarkm#include <sys/cdefs.h> 399313Ssos__FBSDID("$FreeBSD: head/sys/netipx/spx_usrreq.c 139823 2005-01-07 01:45:51Z imp $"); 409313Ssos 419313Ssos#include <sys/param.h> 4231561Sbde#include <sys/lock.h> 439313Ssos#include <sys/malloc.h> 4472538Sjlemon#include <sys/mbuf.h> 4576166Smarkm#include <sys/mutex.h> 46168014Sjulian#include <sys/proc.h> 4776166Smarkm#include <sys/protosw.h> 48162201Snetchild#include <sys/signalvar.h> 49166085Skib#include <sys/socket.h> 50102814Siedowse#include <sys/socketvar.h> 5176166Smarkm#include <sys/sx.h> 5214331Speter#include <sys/systm.h> 53162585Snetchild 5476166Smarkm#include <net/route.h> 5512458Sbde#include <netinet/tcp_fsm.h> 56163606Srwatson 57163606Srwatson#include <netipx/ipx.h> 5872538Sjlemon#include <netipx/ipx_pcb.h> 5972538Sjlemon#include <netipx/ipx_var.h> 6072538Sjlemon#include <netipx/spx.h> 6172538Sjlemon#include <netipx/spx_debug.h> 62140214Sobrien#include <netipx/spx_timer.h> 63140214Sobrien#include <netipx/spx_var.h> 64140214Sobrien 65140214Sobrien/* 6664905Smarcel * SPX protocol implementation. 6768583Smarcel */ 68133816Stjrstatic u_short spx_iss; 69246085Sjhbstatic u_short spx_newchecks[50]; 7064905Smarcelstatic int spx_hardnosed; 71177997Skibstatic int spx_use_delack = 0; 729313Ssosstatic int traceallspxs = 0; 739313Ssosstatic struct spx spx_savesi; 7483366Sjulianstatic struct spx_istat spx_istat; 759313Ssos 76102814Siedowse/* Following was struct spxstat spxstat; */ 77102814Siedowse#ifndef spxstat 789313Ssos#define spxstat spx_istat.newstats 79102814Siedowse#endif 8014331Speter 819313Ssosstatic const int spx_backoff[SPX_MAXRXTSHIFT+1] = 8272543Sjlemon { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 83102814Siedowse 849313Ssosstatic struct spxpcb *spx_close(struct spxpcb *cb); 85102814Siedowsestatic struct spxpcb *spx_disconnect(struct spxpcb *cb); 86102814Siedowsestatic struct spxpcb *spx_drop(struct spxpcb *cb, int errno); 87102814Siedowsestatic int spx_output(struct spxpcb *cb, struct mbuf *m0); 88102814Siedowsestatic int spx_reass(struct spxpcb *cb, struct spx *si); 899313Ssosstatic void spx_setpersist(struct spxpcb *cb); 909313Ssosstatic void spx_template(struct spxpcb *cb); 91168014Sjulianstatic struct spxpcb *spx_timers(struct spxpcb *cb, int timer); 92168014Sjulianstatic struct spxpcb *spx_usrclosed(struct spxpcb *cb); 93177997Skib 949313Ssosstatic int spx_usr_abort(struct socket *so); 95255219Spjdstatic int spx_accept(struct socket *so, struct sockaddr **nam); 9683382Sjhbstatic int spx_attach(struct socket *so, int proto, struct thread *td); 97166085Skibstatic int spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 98166085Skibstatic int spx_connect(struct socket *so, struct sockaddr *nam, 99102814Siedowse struct thread *td); 10014331Speterstatic int spx_detach(struct socket *so); 101102814Siedowsestatic int spx_usr_disconnect(struct socket *so); 102168014Sjulianstatic int spx_listen(struct socket *so, struct thread *td); 103168014Sjulianstatic int spx_rcvd(struct socket *so, int flags); 104102814Siedowsestatic int spx_rcvoob(struct socket *so, struct mbuf *m, int flags); 105168014Sjulianstatic int spx_send(struct socket *so, int flags, struct mbuf *m, 106168014Sjulian struct sockaddr *addr, struct mbuf *control, 107102814Siedowse struct thread *td); 108168014Sjulianstatic int spx_shutdown(struct socket *so); 109168014Sjulianstatic int spx_sp_attach(struct socket *so, int proto, struct thread *td); 110168014Sjulian 111168014Sjulianstruct pr_usrreqs spx_usrreqs = { 112168014Sjulian .pru_abort = spx_usr_abort, 113102814Siedowse .pru_accept = spx_accept, 114168014Sjulian .pru_attach = spx_attach, 115102814Siedowse .pru_bind = spx_bind, 116168014Sjulian .pru_connect = spx_connect, 117102814Siedowse .pru_control = ipx_control, 118168014Sjulian .pru_detach = spx_detach, 119102814Siedowse .pru_disconnect = spx_usr_disconnect, 120168014Sjulian .pru_listen = spx_listen, 121102814Siedowse .pru_peeraddr = ipx_peeraddr, 122168014Sjulian .pru_rcvd = spx_rcvd, 123102814Siedowse .pru_rcvoob = spx_rcvoob, 124168014Sjulian .pru_send = spx_send, 125102814Siedowse .pru_shutdown = spx_shutdown, 126168014Sjulian .pru_sockaddr = ipx_sockaddr, 127102814Siedowse}; 128168014Sjulian 129102814Siedowsestruct pr_usrreqs spx_usrreq_sps = { 130168014Sjulian .pru_abort = spx_usr_abort, 131166085Skib .pru_accept = spx_accept, 132168014Sjulian .pru_attach = spx_sp_attach, 133166085Skib .pru_bind = spx_bind, 134205423Sed .pru_connect = spx_connect, 135205423Sed .pru_control = ipx_control, 136166085Skib .pru_detach = spx_detach, 1379313Ssos .pru_disconnect = spx_usr_disconnect, 138178036Srdivacky .pru_listen = spx_listen, 139178036Srdivacky .pru_peeraddr = ipx_peeraddr, 140166085Skib .pru_rcvd = spx_rcvd, 141166085Skib .pru_rcvoob = spx_rcvoob, 142166085Skib .pru_send = spx_send, 143166085Skib .pru_shutdown = spx_shutdown, 144166085Skib .pru_sockaddr = ipx_sockaddr, 145166085Skib}; 146166085Skib 147255219Spjdvoid 148166085Skibspx_init() 149166085Skib{ 150166085Skib 151166085Skib spx_iss = 1; /* WRONG !! should fish it out of TODR */ 152166085Skib} 153166085Skib 154166085Skibvoid 155247602Spjdspx_input(m, ipxp) 156166085Skib register struct mbuf *m; 157166085Skib register struct ipxpcb *ipxp; 158166085Skib{ 159166085Skib register struct spxpcb *cb; 160166085Skib register struct spx *si = mtod(m, struct spx *); 161166085Skib register struct socket *so; 162166085Skib int dropsocket = 0; 163166085Skib short ostate = 0; 164166085Skib 165166085Skib spxstat.spxs_rcvtotal++; 166166085Skib KASSERT(ipxp != NULL, ("spx_input: NULL ipxpcb")); 167166085Skib 168166085Skib cb = ipxtospxpcb(ipxp); 169166085Skib if (cb == NULL) 170166085Skib goto bad; 1719313Ssos 17214331Speter if (m->m_len < sizeof(*si)) { 173166085Skib if ((m = m_pullup(m, sizeof(*si))) == NULL) { 174166085Skib spxstat.spxs_rcvshort++; 17514331Speter return; 176177997Skib } 177177997Skib si = mtod(m, struct spx *); 1789313Ssos } 1799313Ssos si->si_seq = ntohs(si->si_seq); 1809313Ssos si->si_ack = ntohs(si->si_ack); 181168014Sjulian si->si_alo = ntohs(si->si_alo); 182168014Sjulian 183177997Skib so = ipxp->ipxp_socket; 184177997Skib 185168014Sjulian if (so->so_options & SO_DEBUG || traceallspxs) { 186177997Skib ostate = cb->s_state; 187177997Skib spx_savesi = *si; 188177997Skib } 189177997Skib if (so->so_options & SO_ACCEPTCONN) { 190177997Skib struct spxpcb *ocb = cb; 191168014Sjulian 192168014Sjulian so = sonewconn(so, 0); 193168014Sjulian if (so == NULL) { 194177997Skib goto drop; 195168014Sjulian } 196177997Skib /* 197168014Sjulian * This is ugly, but .... 198168014Sjulian * 199168014Sjulian * Mark socket as temporary until we're 200168014Sjulian * committed to keeping it. The code at 201168014Sjulian * ``drop'' and ``dropwithreset'' check the 202168014Sjulian * flag dropsocket to see if the temporary 203168014Sjulian * socket created here should be discarded. 204168014Sjulian * We mark the socket as discardable until 205168014Sjulian * we're committed to it below in TCPS_LISTEN. 206168014Sjulian */ 207168014Sjulian dropsocket++; 208168014Sjulian ipxp = (struct ipxpcb *)so->so_pcb; 209168014Sjulian ipxp->ipxp_laddr = si->si_dna; 210168014Sjulian cb = ipxtospxpcb(ipxp); 211168014Sjulian cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ 212168014Sjulian cb->s_flags = ocb->s_flags; /* preserve sockopts */ 213168014Sjulian cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ 214168014Sjulian cb->s_state = TCPS_LISTEN; 215178036Srdivacky } 216168014Sjulian 217168014Sjulian /* 218168014Sjulian * Packet received on connection. 21983366Sjulian * reset idle time and keep-alive timer; 2209313Ssos */ 2219313Ssos cb->s_idle = 0; 22212858Speter cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 22312858Speter 2249313Ssos switch (cb->s_state) { 22512858Speter 2269313Ssos case TCPS_LISTEN:{ 22712858Speter struct sockaddr_ipx *sipx, ssipx; 2289313Ssos struct ipx_addr laddr; 2299313Ssos 2309313Ssos /* 23172543Sjlemon * If somebody here was carying on a conversation 23272543Sjlemon * and went away, and his pen pal thinks he can 23383221Smarcel * still talk, we get the misdirected packet. 2349313Ssos */ 23512858Speter if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 23612858Speter spx_istat.gonawy++; 2379313Ssos goto dropwithreset; 238225617Skmacy } 2399313Ssos sipx = &ssipx; 2409313Ssos bzero(sipx, sizeof *sipx); 2419313Ssos sipx->sipx_len = sizeof(*sipx); 24214331Speter sipx->sipx_family = AF_IPX; 24383366Sjulian sipx->sipx_addr = si->si_sna; 24414331Speter laddr = ipxp->ipxp_laddr; 24514331Speter if (ipx_nullhost(laddr)) 24614331Speter ipxp->ipxp_laddr = si->si_dna; 24714331Speter if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &thread0)) { 24814331Speter ipxp->ipxp_laddr = laddr; 24914331Speter spx_istat.noconn++; 25072543Sjlemon goto drop; 25172543Sjlemon } 25272543Sjlemon spx_template(cb); 25314331Speter dropsocket = 0; /* committed to socket */ 25414331Speter cb->s_did = si->si_sid; 25514331Speter cb->s_rack = si->si_ack; 25614331Speter cb->s_ralo = si->si_alo; 25714331Speter#define THREEWAYSHAKE 25814331Speter#ifdef THREEWAYSHAKE 25914331Speter cb->s_state = TCPS_SYN_RECEIVED; 260225617Skmacy cb->s_force = 1 + SPXT_KEEP; 26114331Speter spxstat.spxs_accepts++; 26214331Speter cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 263111797Sdes } 26414331Speter break; 26514331Speter /* 26683366Sjulian * This state means that we have heard a response 26714331Speter * to our acceptance of their connection 26814331Speter * It is probably logically unnecessary in this 26914331Speter * implementation. 2709313Ssos */ 27183366Sjulian case TCPS_SYN_RECEIVED: { 2729313Ssos if (si->si_did != cb->s_sid) { 27314331Speter spx_istat.wrncon++; 27414331Speter goto drop; 27514331Speter } 27614331Speter#endif 27714331Speter ipxp->ipxp_fport = si->si_sport; 27883366Sjulian cb->s_timer[SPXT_REXMT] = 0; 27914331Speter cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 28014331Speter soisconnected(so); 28183221Smarcel cb->s_state = TCPS_ESTABLISHED; 28283221Smarcel spxstat.spxs_accepts++; 28383221Smarcel } 28483221Smarcel break; 28583221Smarcel 28683221Smarcel /* 28783221Smarcel * This state means that we have gotten a response 28883221Smarcel * to our attempt to establish a connection. 28983221Smarcel * We fill in the data from the other side, 29083221Smarcel * telling us which port to respond to, instead of the well- 291179651Srdivacky * known one we might have sent to in the first place. 29283221Smarcel * We also require that this is a response to our 29383221Smarcel * connection id. 29483221Smarcel */ 29583221Smarcel case TCPS_SYN_SENT: 29683221Smarcel if (si->si_did != cb->s_sid) { 29783221Smarcel spx_istat.notme++; 29883221Smarcel goto drop; 29983221Smarcel } 30083221Smarcel spxstat.spxs_connects++; 30183221Smarcel cb->s_did = si->si_sid; 30283221Smarcel cb->s_rack = si->si_ack; 30383221Smarcel cb->s_ralo = si->si_alo; 30483221Smarcel cb->s_dport = ipxp->ipxp_fport = si->si_sport; 305182892Srdivacky cb->s_timer[SPXT_REXMT] = 0; 306182892Srdivacky cb->s_flags |= SF_ACKNOW; 307182892Srdivacky soisconnected(so); 308182892Srdivacky cb->s_state = TCPS_ESTABLISHED; 309182892Srdivacky /* Use roundtrip time of connection request for initial rtt */ 310182892Srdivacky if (cb->s_rtt) { 311182892Srdivacky cb->s_srtt = cb->s_rtt << 3; 31283221Smarcel cb->s_rttvar = cb->s_rtt << 1; 313182892Srdivacky SPXT_RANGESET(cb->s_rxtcur, 314182892Srdivacky ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 315182892Srdivacky SPXTV_MIN, SPXTV_REXMTMAX); 316182892Srdivacky cb->s_rtt = 0; 317182892Srdivacky } 318182892Srdivacky } 31983221Smarcel if (so->so_options & SO_DEBUG || traceallspxs) 32083221Smarcel spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0); 32183221Smarcel 32283366Sjulian m->m_len -= sizeof(struct ipx); 32383221Smarcel m->m_pkthdr.len -= sizeof(struct ipx); 32414331Speter m->m_data += sizeof(struct ipx); 325111798Sdes 32683221Smarcel if (spx_reass(cb, si)) { 32783221Smarcel m_freem(m); 32883221Smarcel } 32983221Smarcel if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) 33083221Smarcel spx_output(cb, NULL); 331182892Srdivacky cb->s_flags &= ~(SF_WIN|SF_RXT); 332255219Spjd return; 33383221Smarcel 33483221Smarceldropwithreset: 33583221Smarcel if (dropsocket) { 33683221Smarcel struct socket *head; 337182892Srdivacky ACCEPT_LOCK(); 338182892Srdivacky KASSERT((so->so_qstate & SQ_INCOMP) != 0, 33983221Smarcel ("spx_input: nascent socket not SQ_INCOMP on soabort()")); 34083221Smarcel head = so->so_head; 341241896Skib TAILQ_REMOVE(&head->so_incomp, so, so_list); 3429313Ssos head->so_incqlen--; 343160276Sjhb so->so_qstate &= ~SQ_INCOMP; 344160276Sjhb so->so_head = NULL; 345160276Sjhb ACCEPT_UNLOCK(); 346160276Sjhb soabort(so); 347160276Sjhb } 348188572Snetchild si->si_seq = ntohs(si->si_seq); 349160276Sjhb si->si_ack = ntohs(si->si_ack); 350160276Sjhb si->si_alo = ntohs(si->si_alo); 351160276Sjhb m_freem(dtom(si)); 352160276Sjhb if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs) 353255219Spjd spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 354255219Spjd return; 355255219Spjd 35683221Smarceldrop: 3579313Ssosbad: 35889306Salfred if (cb == NULL || cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || 35989306Salfred traceallspxs) 36083221Smarcel spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 36189306Salfred m_freem(m); 3629313Ssos} 363238029Skib 364116678Sphkstatic int spxrexmtthresh = 3; 36589306Salfred 366238029Skib/* 36789306Salfred * This is structurally similar to the tcp reassembly routine 36883221Smarcel * but its function is somewhat different: It merely queues 36989306Salfred * packets up, and suppresses duplicates. 3709313Ssos */ 3719313Ssosstatic int 37283221Smarcelspx_reass(cb, si) 37383221Smarcelregister struct spxpcb *cb; 374111119Simpregister struct spx *si; 375182892Srdivacky{ 376188588Sjhb register struct spx_q *q; 37783221Smarcel register struct mbuf *m; 37883221Smarcel register struct socket *so = cb->s_ipxpcb->ipxp_socket; 37983221Smarcel char packetp = cb->s_flags & SF_HI; 38083221Smarcel int incr; 38183221Smarcel char wakeup = 0; 38283221Smarcel 38383221Smarcel if (si == SI(0)) 38483366Sjulian goto present; 38583221Smarcel /* 38683221Smarcel * Update our news from them. 3879313Ssos */ 388101189Srwatson if (si->si_cc & SPX_SA) 389101189Srwatson cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW); 390101189Srwatson if (SSEQ_GT(si->si_alo, cb->s_ralo)) 391101189Srwatson cb->s_flags |= SF_WIN; 392172930Srwatson if (SSEQ_LEQ(si->si_ack, cb->s_rack)) { 393101189Srwatson if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) { 394101189Srwatson spxstat.spxs_rcvdupack++; 39583221Smarcel /* 39683221Smarcel * If this is a completely duplicate ack 39783221Smarcel * and other conditions hold, we assume 3989313Ssos * a packet has been dropped and retransmit 39983221Smarcel * it exactly as in tcp_input(). 40083221Smarcel */ 40183221Smarcel if (si->si_ack != cb->s_rack || 40283221Smarcel si->si_alo != cb->s_ralo) 40383221Smarcel cb->s_dupacks = 0; 4049313Ssos else if (++cb->s_dupacks == spxrexmtthresh) { 40583221Smarcel u_short onxt = cb->s_snxt; 40624654Sdfr int cwnd = cb->s_cwnd; 40783221Smarcel 40883221Smarcel cb->s_snxt = si->si_ack; 40983221Smarcel cb->s_cwnd = CUNIT; 41083221Smarcel cb->s_force = 1 + SPXT_REXMT; 41183221Smarcel spx_output(cb, NULL); 41283221Smarcel cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 41383221Smarcel cb->s_rtt = 0; 41483221Smarcel if (cwnd >= 4 * CUNIT) 41583221Smarcel cb->s_cwnd = cwnd / 2; 41683221Smarcel if (SSEQ_GT(onxt, cb->s_snxt)) 41783221Smarcel cb->s_snxt = onxt; 41883221Smarcel return (1); 41983221Smarcel } 42083221Smarcel } else 42183221Smarcel cb->s_dupacks = 0; 42224654Sdfr goto update_window; 42324654Sdfr } 42483221Smarcel cb->s_dupacks = 0; 42583221Smarcel /* 42683221Smarcel * If our correspondent acknowledges data we haven't sent 42783221Smarcel * TCP would drop the packet after acking. We'll be a little 42883221Smarcel * more permissive 42983221Smarcel */ 43083221Smarcel if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) { 43183221Smarcel spxstat.spxs_rcvacktoomuch++; 43283221Smarcel si->si_ack = cb->s_smax + 1; 43383221Smarcel } 43483221Smarcel spxstat.spxs_rcvackpack++; 43583221Smarcel /* 43683221Smarcel * If transmit timer is running and timed sequence 43783221Smarcel * number was acked, update smoothed round trip time. 43883221Smarcel * See discussion of algorithm in tcp_input.c 43983221Smarcel */ 44083221Smarcel if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 44183221Smarcel spxstat.spxs_rttupdated++; 44283221Smarcel if (cb->s_srtt != 0) { 44383221Smarcel register short delta; 44483221Smarcel delta = cb->s_rtt - (cb->s_srtt >> 3); 44583221Smarcel if ((cb->s_srtt += delta) <= 0) 44683221Smarcel cb->s_srtt = 1; 447182892Srdivacky if (delta < 0) 448182892Srdivacky delta = -delta; 44983221Smarcel delta -= (cb->s_rttvar >> 2); 45083221Smarcel if ((cb->s_rttvar += delta) <= 0) 45183221Smarcel cb->s_rttvar = 1; 45283221Smarcel } else { 45383221Smarcel /* 45483221Smarcel * No rtt measurement yet 45583221Smarcel */ 45683221Smarcel cb->s_srtt = cb->s_rtt << 3; 457182892Srdivacky cb->s_rttvar = cb->s_rtt << 1; 458182892Srdivacky } 459182892Srdivacky cb->s_rtt = 0; 460182892Srdivacky cb->s_rxtshift = 0; 461182892Srdivacky SPXT_RANGESET(cb->s_rxtcur, 462182892Srdivacky ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 463182892Srdivacky SPXTV_MIN, SPXTV_REXMTMAX); 46483221Smarcel } 465182892Srdivacky /* 466182892Srdivacky * If all outstanding data is acked, stop retransmit 467182892Srdivacky * timer and remember to restart (more output or persist). 468182892Srdivacky * If there is more data to be acked, restart retransmit 469182892Srdivacky * timer, using current (possibly backed-off) value; 470182892Srdivacky */ 471182892Srdivacky if (si->si_ack == cb->s_smax + 1) { 472182892Srdivacky cb->s_timer[SPXT_REXMT] = 0; 473182892Srdivacky cb->s_flags |= SF_RXT; 474182892Srdivacky } else if (cb->s_timer[SPXT_PERSIST] == 0) 475182892Srdivacky cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 476182892Srdivacky /* 477182892Srdivacky * When new data is acked, open the congestion window. 478182892Srdivacky * If the window gives us less than ssthresh packets 479182892Srdivacky * in flight, open exponentially (maxseg at a time). 480182892Srdivacky * Otherwise open linearly (maxseg^2 / cwnd at a time). 481182892Srdivacky */ 482182892Srdivacky incr = CUNIT; 483182892Srdivacky if (cb->s_cwnd > cb->s_ssthresh) 484182892Srdivacky incr = max(incr * incr / cb->s_cwnd, 1); 485182892Srdivacky cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx); 486182892Srdivacky /* 487182892Srdivacky * Trim Acked data from output queue. 488182892Srdivacky */ 489182892Srdivacky SOCKBUF_LOCK(&so->so_snd); 490182892Srdivacky while ((m = so->so_snd.sb_mb) != NULL) { 491182892Srdivacky if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack)) 49283221Smarcel sbdroprecord_locked(&so->so_snd); 49383221Smarcel else 49483221Smarcel break; 49583221Smarcel } 49683221Smarcel sowwakeup_locked(so); 49783221Smarcel cb->s_rack = si->si_ack; 49883221Smarcelupdate_window: 49983221Smarcel if (SSEQ_LT(cb->s_snxt, cb->s_rack)) 50083221Smarcel cb->s_snxt = cb->s_rack; 50183221Smarcel if (SSEQ_LT(cb->s_swl1, si->si_seq) || ((cb->s_swl1 == si->si_seq && 50283221Smarcel (SSEQ_LT(cb->s_swl2, si->si_ack))) || 50383221Smarcel (cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo)))) { 50483221Smarcel /* keep track of pure window updates */ 50583221Smarcel if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack 50683221Smarcel && SSEQ_LT(cb->s_ralo, si->si_alo)) { 50710355Sswallace spxstat.spxs_rcvwinupd++; 5089313Ssos spxstat.spxs_rcvdupack--; 509217578Skib } 510217578Skib cb->s_ralo = si->si_alo; 511217578Skib cb->s_swl1 = si->si_seq; 512217578Skib cb->s_swl2 = si->si_ack; 5139313Ssos cb->s_swnd = (1 + si->si_alo - si->si_ack); 51483221Smarcel if (cb->s_swnd > cb->s_smxw) 51583221Smarcel cb->s_smxw = cb->s_swnd; 51610355Sswallace cb->s_flags |= SF_WIN; 5179313Ssos } 51883366Sjulian /* 51983221Smarcel * If this packet number is higher than that which 5209313Ssos * we have allocated refuse it, unless urgent 521247764Seadler */ 52283221Smarcel if (SSEQ_GT(si->si_seq, cb->s_alo)) { 523175294Sattilio if (si->si_cc & SPX_SP) { 524238029Skib spxstat.spxs_rcvwinprobe++; 52589306Salfred return (1); 52683221Smarcel } else 527182892Srdivacky spxstat.spxs_rcvpackafterwin++; 52883221Smarcel if (si->si_cc & SPX_OB) { 5299313Ssos if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { 53014331Speter m_freem(dtom(si)); 53183221Smarcel return (0); 53283366Sjulian } /* else queue this packet; */ 53383221Smarcel } else { 53483221Smarcel#ifdef BROKEN 53583221Smarcel /* 53683221Smarcel * XXXRW: This is broken on at least one count: 53783221Smarcel * spx_close() will free the ipxp and related parts, 53883221Smarcel * which are then touched by spx_input() after the 53983221Smarcel * return from spx_reass(). 54083366Sjulian */ 54183221Smarcel /*register struct socket *so = cb->s_ipxpcb->ipxp_socket; 54283221Smarcel if (so->so_state && SS_NOFDREF) { 54383221Smarcel spx_close(cb); 54483366Sjulian } else 54583221Smarcel would crash system*/ 54683221Smarcel#endif 54783221Smarcel spx_istat.notyet++; 54883221Smarcel m_freem(dtom(si)); 54983221Smarcel return (0); 55083221Smarcel } 55183221Smarcel } 55283366Sjulian /* 55383221Smarcel * If this is a system packet, we don't need to 55483221Smarcel * queue it up, and won't update acknowledge # 55514331Speter */ 55614331Speter if (si->si_cc & SPX_SP) { 55714331Speter return (1); 55814331Speter } 55914331Speter /* 56083366Sjulian * We have already seen this packet, so drop. 56114331Speter */ 562102814Siedowse if (SSEQ_LT(si->si_seq, cb->s_ack)) { 563102814Siedowse spx_istat.bdreas++; 56414331Speter spxstat.spxs_rcvduppack++; 565162585Snetchild if (si->si_seq == cb->s_ack - 1) 566227691Sed spx_istat.lstdup++; 567162585Snetchild return (1); 568162585Snetchild } 569102814Siedowse /* 57014331Speter * Loop through all packets queued up to insert in 57114331Speter * appropriate sequence. 57272543Sjlemon */ 573227691Sed for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { 57414331Speter if (si->si_seq == SI(q)->si_seq) { 575227691Sed spxstat.spxs_rcvduppack++; 576102814Siedowse return (1); 577162585Snetchild } 578102814Siedowse if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) { 57914331Speter spxstat.spxs_rcvoopack++; 58014331Speter break; 58114331Speter } 582177997Skib } 583177997Skib insque(si, q->si_prev); 584177997Skib /* 585227693Sed * If this packet is urgent, inform process 586177997Skib */ 587227693Sed if (si->si_cc & SPX_OB) { 588227693Sed cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 589177997Skib sohasoutofband(so); 590227691Sed cb->s_oobflags |= SF_IOOB; 591177997Skib } 592177997Skibpresent: 593177997Skib#define SPINC sizeof(struct spxhdr) 594177997Skib SOCKBUF_LOCK(&so->so_rcv); 595177997Skib /* 596177997Skib * Loop through all packets queued up to update acknowledge 597177997Skib * number, and present all acknowledged data to user; 598227691Sed * If in packet interface mode, show packet headers. 599177997Skib */ 600177997Skib for (q = cb->s_q.si_next; q != &cb->s_q; q = q->si_next) { 601227693Sed if (SI(q)->si_seq == cb->s_ack) { 602227693Sed cb->s_ack++; 603177997Skib m = dtom(q); 604177997Skib if (SI(q)->si_cc & SPX_OB) { 605177997Skib cb->s_oobflags &= ~SF_IOOB; 606177997Skib if (so->so_rcv.sb_cc) 607177997Skib so->so_oobmark = so->so_rcv.sb_cc; 608177997Skib else 60983366Sjulian so->so_rcv.sb_state |= SBS_RCVATMARK; 61014331Speter } 611102814Siedowse q = q->si_prev; 612102814Siedowse remque(q->si_next); 613162201Snetchild wakeup = 1; 61414331Speter spxstat.spxs_rcvpack++; 615102814Siedowse#ifdef SF_NEWCALL 61614331Speter if (cb->s_flags2 & SF_NEWCALL) { 61714331Speter struct spxhdr *sp = mtod(m, struct spxhdr *); 61872543Sjlemon u_char dt = sp->spx_dt; 619102814Siedowse spx_newchecks[4]++; 62014331Speter if (dt != cb->s_rhdr.spx_dt) { 62114331Speter struct mbuf *mm = 622102814Siedowse m_getclr(M_DONTWAIT, MT_CONTROL); 623162201Snetchild spx_newchecks[0]++; 624162201Snetchild if (mm != NULL) { 625162201Snetchild u_short *s = 626162201Snetchild mtod(mm, u_short *); 627162201Snetchild cb->s_rhdr.spx_dt = dt; 628102814Siedowse mm->m_len = 5; /*XXX*/ 629102814Siedowse s[0] = 5; 63014331Speter s[1] = 1; 63114331Speter *(u_char *)(&s[2]) = dt; 63214331Speter sbappend_locked(&so->so_rcv, mm); 633177997Skib } 634177997Skib } 635177997Skib if (sp->spx_cc & SPX_OB) { 636177997Skib MCHTYPE(m, MT_OOBDATA); 637177997Skib spx_newchecks[1]++; 638177997Skib so->so_oobmark = 0; 639177997Skib so->so_rcv.sb_state &= ~SBS_RCVATMARK; 640177997Skib } 641177997Skib if (packetp == 0) { 642177997Skib m->m_data += SPINC; 643177997Skib m->m_len -= SPINC; 644177997Skib m->m_pkthdr.len -= SPINC; 645177997Skib } 646177997Skib if ((sp->spx_cc & SPX_EM) || packetp) { 647177997Skib sbappendrecord_locked(&so->so_rcv, m); 648177997Skib spx_newchecks[9]++; 649177997Skib } else 650177997Skib sbappend_locked(&so->so_rcv, m); 651177997Skib } else 652177997Skib#endif 653202113Smckusick if (packetp) { 654177997Skib sbappendrecord_locked(&so->so_rcv, m); 655177997Skib } else { 656177997Skib cb->s_rhdr = *mtod(m, struct spxhdr *); 657177997Skib m->m_data += SPINC; 658177997Skib m->m_len -= SPINC; 659177997Skib m->m_pkthdr.len -= SPINC; 660177997Skib sbappend_locked(&so->so_rcv, m); 661177997Skib } 662177997Skib } else 663177997Skib break; 66483366Sjulian } 66514331Speter if (wakeup) 666102814Siedowse sorwakeup_locked(so); 667102814Siedowse else 66814331Speter SOCKBUF_UNLOCK(&so->so_rcv); 669102814Siedowse return (0); 67014331Speter} 67114331Speter 67272543Sjlemonvoid 673102814Siedowsespx_ctlinput(cmd, arg_as_sa, dummy) 67414331Speter int cmd; 675102814Siedowse struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */ 676102814Siedowse void *dummy; 677102814Siedowse{ 67814331Speter caddr_t arg = (/* XXX */ caddr_t)arg_as_sa; 67914331Speter struct ipx_addr *na; 68014331Speter struct sockaddr_ipx *sipx; 68183366Sjulian 68214331Speter if (cmd < 0 || cmd >= PRC_NCMDS) 683102814Siedowse return; 684102814Siedowse 68514331Speter switch (cmd) { 686102814Siedowse 68714331Speter case PRC_ROUTEDEAD: 68814331Speter return; 68972543Sjlemon 690102814Siedowse case PRC_IFDOWN: 69114331Speter case PRC_HOSTDEAD: 692102814Siedowse case PRC_HOSTUNREACH: 693102814Siedowse sipx = (struct sockaddr_ipx *)arg; 694102814Siedowse if (sipx->sipx_family != AF_IPX) 69514331Speter return; 69614331Speter na = &sipx->sipx_addr; 69714331Speter break; 698177997Skib 699177997Skib default: 700177997Skib break; 701177997Skib } 702177997Skib} 703177997Skib 704177997Skibstatic int 705177997Skibspx_output(cb, m0) 706177997Skib register struct spxpcb *cb; 707177997Skib struct mbuf *m0; 708177997Skib{ 709177997Skib struct socket *so = cb->s_ipxpcb->ipxp_socket; 710177997Skib register struct mbuf *m; 711177997Skib register struct spx *si = NULL; 712177997Skib register struct sockbuf *sb = &so->so_snd; 713177997Skib int len = 0, win, rcv_win; 714177997Skib short span, off, recordp = 0; 715177997Skib u_short alo; 716177997Skib int error = 0, sendalot; 71783366Sjulian#ifdef notdef 71814331Speter int idle; 719102814Siedowse#endif 720102814Siedowse struct mbuf *mprev; 72114331Speter 722102814Siedowse if (m0 != NULL) { 72314331Speter int mtu = cb->s_mtu; 72414331Speter int datalen; 72572543Sjlemon /* 726102814Siedowse * Make sure that packet isn't too big. 72714331Speter */ 728102814Siedowse for (m = m0; m != NULL; m = m->m_next) { 729102814Siedowse mprev = m; 730102814Siedowse len += m->m_len; 73114331Speter if (m->m_flags & M_EOR) 73214331Speter recordp = 1; 73314331Speter } 734177997Skib datalen = (cb->s_flags & SF_HO) ? 735177997Skib len - sizeof(struct spxhdr) : len; 736177997Skib if (datalen > mtu) { 737177997Skib if (cb->s_flags & SF_PI) { 738177997Skib m_freem(m0); 739177997Skib return (EMSGSIZE); 740177997Skib } else { 741177997Skib int oldEM = cb->s_cc & SPX_EM; 742177997Skib 743177997Skib cb->s_cc &= ~SPX_EM; 744177997Skib while (len > mtu) { 745177997Skib /* 746177997Skib * Here we are only being called 747177997Skib * from usrreq(), so it is OK to 748177997Skib * block. 749177997Skib */ 750177997Skib m = m_copym(m0, 0, mtu, M_TRYWAIT); 751177997Skib if (cb->s_flags & SF_NEWCALL) { 75283366Sjulian struct mbuf *mm = m; 75314331Speter spx_newchecks[7]++; 754102814Siedowse while (mm != NULL) { 755102814Siedowse mm->m_flags &= ~M_EOR; 75614331Speter mm = mm->m_next; 757102814Siedowse } 75814331Speter } 75914331Speter error = spx_output(cb, m); 76072543Sjlemon if (error) { 761102814Siedowse cb->s_cc |= oldEM; 76214331Speter m_freem(m0); 763102814Siedowse return (error); 764102814Siedowse } 765102814Siedowse m_adj(m0, mtu); 76614331Speter len -= mtu; 76714331Speter } 76814331Speter cb->s_cc |= oldEM; 76983366Sjulian } 77014331Speter } 771102814Siedowse /* 772102814Siedowse * Force length even, by adding a "garbage byte" if 77314331Speter * necessary. 774102814Siedowse */ 775102814Siedowse if (len & 1) { 776177997Skib m = mprev; 777102814Siedowse if (M_TRAILINGSPACE(m) >= 1) 778102814Siedowse m->m_len++; 779102814Siedowse else { 780102814Siedowse struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 78114331Speter 78214331Speter if (m1 == NULL) { 78372543Sjlemon m_freem(m0); 784102814Siedowse return (ENOBUFS); 78514331Speter } 786102814Siedowse m1->m_len = 1; 787102814Siedowse *(mtod(m1, u_char *)) = 0; 788102814Siedowse m->m_next = m1; 789102814Siedowse } 79014331Speter } 79114331Speter m = m_gethdr(M_DONTWAIT, MT_HEADER); 79214331Speter if (m == NULL) { 793177997Skib m_freem(m0); 794177997Skib return (ENOBUFS); 795177997Skib } 796177997Skib /* 797177997Skib * Fill in mbuf with extended SP header 798177997Skib * and addresses and length put into network format. 799177997Skib */ 800177997Skib MH_ALIGN(m, sizeof(struct spx)); 801177997Skib m->m_len = sizeof(struct spx); 802177997Skib m->m_next = m0; 803177997Skib si = mtod(m, struct spx *); 804177997Skib si->si_i = *cb->s_ipx; 805177997Skib si->si_s = cb->s_shdr; 806177997Skib if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 807177997Skib register struct spxhdr *sh; 808177997Skib if (m0->m_len < sizeof(*sh)) { 809177997Skib if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 810177997Skib m_free(m); 811177997Skib m_freem(m0); 812177997Skib return (EINVAL); 813177997Skib } 814177997Skib m->m_next = m0; 815177997Skib } 816177997Skib sh = mtod(m0, struct spxhdr *); 817177997Skib si->si_dt = sh->spx_dt; 818177997Skib si->si_cc |= sh->spx_cc & SPX_EM; 81983366Sjulian m0->m_len -= sizeof(*sh); 82014331Speter m0->m_data += sizeof(*sh); 821102814Siedowse len -= sizeof(*sh); 822102814Siedowse } 82314331Speter len += sizeof(*si); 824102814Siedowse if ((cb->s_flags2 & SF_NEWCALL) && recordp) { 825102814Siedowse si->si_cc |= SPX_EM; 826177997Skib spx_newchecks[8]++; 827102814Siedowse } 828102814Siedowse if (cb->s_oobflags & SF_SOOB) { 829102814Siedowse /* 830102814Siedowse * Per jqj@cornell: 83114331Speter * make sure OB packets convey exactly 1 byte. 83214331Speter * If the packet is 1 byte or larger, we 83372543Sjlemon * have already guaranted there to be at least 834102814Siedowse * one garbage byte for the checksum, and 83514331Speter * extra bytes shouldn't hurt! 836102814Siedowse */ 837102814Siedowse if (len > sizeof(*si)) { 838102814Siedowse si->si_cc |= SPX_OB; 839102814Siedowse len = (1 + sizeof(*si)); 84014331Speter } 84114331Speter } 84214331Speter si->si_len = htons((u_short)len); 843177997Skib m->m_pkthdr.len = ((len - 1) | 1) + 1; 844177997Skib /* 845177997Skib * queue stuff up for output 846177997Skib */ 847177997Skib sbappendrecord(sb, m); 848177997Skib cb->s_seq++; 849177997Skib } 850177997Skib#ifdef notdef 851177997Skib idle = (cb->s_smax == (cb->s_rack - 1)); 852177997Skib#endif 853177997Skibagain: 854177997Skib sendalot = 0; 855177997Skib off = cb->s_snxt - cb->s_rack; 856177997Skib win = min(cb->s_swnd, (cb->s_cwnd / CUNIT)); 857177997Skib 858177997Skib /* 859177997Skib * If in persist timeout with window of 0, send a probe. 860177997Skib * Otherwise, if window is small but nonzero 861177997Skib * and timer expired, send what we can and go into 862177997Skib * transmit state. 863177997Skib */ 864177997Skib if (cb->s_force == 1 + SPXT_PERSIST) { 865177997Skib if (win != 0) { 866177997Skib cb->s_timer[SPXT_PERSIST] = 0; 867177997Skib cb->s_rxtshift = 0; 868177997Skib } 86983366Sjulian } 87014331Speter span = cb->s_seq - cb->s_rack; 871102814Siedowse len = min(span, win) - off; 872102814Siedowse 87314331Speter if (len < 0) { 874102814Siedowse /* 87514331Speter * Window shrank after we went into it. 87614331Speter * If window shrank to 0, cancel pending 87772543Sjlemon * restransmission and pull s_snxt back 878102814Siedowse * to (closed) window. We will enter persist 879102814Siedowse * state below. If the widndow didn't close completely, 88014331Speter * just wait for an ACK. 881102814Siedowse */ 882102814Siedowse len = 0; 883102814Siedowse if (win == 0) { 884102814Siedowse cb->s_timer[SPXT_REXMT] = 0; 88514331Speter cb->s_snxt = cb->s_rack; 88614331Speter } 88714331Speter } 888177997Skib if (len > 1) 889177997Skib sendalot = 1; 890177997Skib rcv_win = sbspace(&so->so_rcv); 891177997Skib 892177997Skib /* 893177997Skib * Send if we owe peer an ACK. 894177997Skib */ 895177997Skib if (cb->s_oobflags & SF_SOOB) { 896177997Skib /* 897177997Skib * must transmit this out of band packet 898177997Skib */ 899177997Skib cb->s_oobflags &= ~ SF_SOOB; 900177997Skib sendalot = 1; 901177997Skib spxstat.spxs_sndurg++; 902177997Skib goto found; 903177997Skib } 904177997Skib if (cb->s_flags & SF_ACKNOW) 905177997Skib goto send; 906177997Skib if (cb->s_state < TCPS_ESTABLISHED) 907178439Srdivacky goto send; 908177997Skib /* 90983366Sjulian * Silly window can't happen in spx. 91014331Speter * Code from tcp deleted. 911102814Siedowse */ 912102814Siedowse if (len) 91314331Speter goto send; 914102814Siedowse /* 91514331Speter * Compare available window to amount of window 91614331Speter * known to peer (as advertised window less 91772543Sjlemon * next expected input.) If the difference is at least two 918102814Siedowse * packets or at least 35% of the mximum possible window, 91914331Speter * then want to send a window update to peer. 92014331Speter */ 921102814Siedowse if (rcv_win > 0) { 922102814Siedowse u_short delta = 1 + cb->s_alo - cb->s_ack; 923102814Siedowse int adv = rcv_win - (delta * cb->s_mtu); 92414331Speter 92514331Speter if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || 92649662Smarcel (100 * adv / so->so_rcv.sb_hiwat >= 35)) { 927178439Srdivacky spxstat.spxs_sndwinup++; 928178439Srdivacky cb->s_flags |= SF_ACKNOW; 929178439Srdivacky goto send; 930178439Srdivacky } 931178439Srdivacky 932178439Srdivacky } 933178439Srdivacky /* 934178439Srdivacky * Many comments from tcp_output.c are appropriate here 935178439Srdivacky * including . . . 936178439Srdivacky * If send window is too small, there is data to transmit, and no 937178439Srdivacky * retransmit or persist is pending, then go to persist state. 938178439Srdivacky * If nothing happens soon, send when timer expires: 939178439Srdivacky * if window is nonzero, transmit what we can, 940178439Srdivacky * otherwise send a probe. 941178439Srdivacky */ 942178439Srdivacky if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 && 943178439Srdivacky cb->s_timer[SPXT_PERSIST] == 0) { 944156842Snetchild cb->s_rxtshift = 0; 945156842Snetchild spx_setpersist(cb); 946156842Snetchild } 947156842Snetchild /* 948156842Snetchild * No reason to send a packet, just return. 949156842Snetchild */ 950156842Snetchild cb->s_outx = 1; 951156842Snetchild return (0); 952156842Snetchild 953156842Snetchildsend: 954225617Skmacy /* 955156842Snetchild * Find requested packet. 956156842Snetchild */ 957156842Snetchild si = 0; 95883366Sjulian if (len > 0) { 95949662Smarcel cb->s_want = cb->s_snxt; 960102814Siedowse for (m = sb->sb_mb; m != NULL; m = m->m_act) { 961102814Siedowse si = mtod(m, struct spx *); 96249662Smarcel if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) 963102814Siedowse break; 964102814Siedowse } 965177997Skib found: 966102814Siedowse if (si != NULL) { 967102814Siedowse if (si->si_seq == cb->s_snxt) 968102814Siedowse cb->s_snxt++; 969102814Siedowse else 97049662Smarcel spxstat.spxs_sndvoid++, si = 0; 97149662Smarcel } 97272543Sjlemon } 973102814Siedowse /* 97449662Smarcel * update window 975102814Siedowse */ 976102814Siedowse if (rcv_win < 0) 977102814Siedowse rcv_win = 0; 978102814Siedowse alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); 97949662Smarcel if (SSEQ_LT(alo, cb->s_alo)) 98049788Smarcel alo = cb->s_alo; 98153713Smarcel 982177997Skib if (si != NULL) { 983177997Skib /* 984177997Skib * must make a copy of this packet for 985227693Sed * ipx_output to monkey with 986177997Skib */ 987227693Sed m = m_copy(dtom(si), 0, (int)M_COPYALL); 988177997Skib if (m == NULL) { 989177997Skib return (ENOBUFS); 990177997Skib } 991177997Skib si = mtod(m, struct spx *); 992177997Skib if (SSEQ_LT(si->si_seq, cb->s_smax)) 993177997Skib spxstat.spxs_sndrexmitpack++; 994177997Skib else 995177997Skib spxstat.spxs_sndpack++; 996177997Skib } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { 997177997Skib /* 998177997Skib * Must send an acknowledgement or a probe 999177997Skib */ 1000177997Skib if (cb->s_force) 1001177997Skib spxstat.spxs_sndprobe++; 1002177997Skib if (cb->s_flags & SF_ACKNOW) 1003227693Sed spxstat.spxs_sndacks++; 1004177997Skib m = m_gethdr(M_DONTWAIT, MT_HEADER); 1005177997Skib if (m == NULL) 1006227693Sed return (ENOBUFS); 1007227693Sed /* 1008227693Sed * Fill in mbuf with extended SP header 1009177997Skib * and addresses and length put into network format. 1010177997Skib */ 1011177997Skib MH_ALIGN(m, sizeof(struct spx)); 1012177997Skib m->m_len = sizeof(*si); 1013177997Skib m->m_pkthdr.len = sizeof(*si); 1014177997Skib si = mtod(m, struct spx *); 101583366Sjulian si->si_i = *cb->s_ipx; 101683366Sjulian si->si_s = cb->s_shdr; 101753713Smarcel si->si_seq = cb->s_smax + 1; 101853713Smarcel si->si_len = htons(sizeof(*si)); 101953713Smarcel si->si_cc |= SPX_SP; 102053713Smarcel } else { 102153713Smarcel cb->s_outx = 3; 1022225617Skmacy if (so->so_options & SO_DEBUG || traceallspxs) 102353713Smarcel spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 102463285Smarcel return (0); 102563285Smarcel } 102683366Sjulian /* 102783366Sjulian * Stuff checksum and output datagram. 102863285Smarcel */ 102963285Smarcel if ((si->si_cc & SPX_SP) == 0) { 103063285Smarcel if (cb->s_force != (1 + SPXT_PERSIST) || 1031255219Spjd cb->s_timer[SPXT_PERSIST] == 0) { 1032162585Snetchild /* 1033162585Snetchild * If this is a new packet and we are not currently 103463285Smarcel * timing anything, time this one. 103563285Smarcel */ 103663285Smarcel if (SSEQ_LT(cb->s_smax, si->si_seq)) { 103763285Smarcel cb->s_smax = si->si_seq; 103863285Smarcel if (cb->s_rtt == 0) { 1039162585Snetchild spxstat.spxs_segstimed++; 1040225617Skmacy cb->s_rtseq = si->si_seq; 1041162585Snetchild cb->s_rtt = 1; 1042162585Snetchild } 1043247602Spjd } 1044255219Spjd /* 1045255219Spjd * Set rexmt timer if not currently set, 1046255219Spjd * Initial value for retransmit timer is smoothed 1047247602Spjd * round-trip time + 2 * round-trip time variance. 1048162585Snetchild * Initialize shift counter which is used for backoff 1049247602Spjd * of retransmit time. 1050162585Snetchild */ 1051162585Snetchild if (cb->s_timer[SPXT_REXMT] == 0 && 1052162585Snetchild cb->s_snxt != cb->s_rack) { 1053162585Snetchild cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 1054162585Snetchild if (cb->s_timer[SPXT_PERSIST]) { 1055162585Snetchild cb->s_timer[SPXT_PERSIST] = 0; 105663285Smarcel cb->s_rxtshift = 0; 105763285Smarcel } 105863285Smarcel } 105983366Sjulian } else if (SSEQ_LT(cb->s_smax, si->si_seq)) { 106083366Sjulian cb->s_smax = si->si_seq; 106163285Smarcel } 106263285Smarcel } else if (cb->s_state < TCPS_ESTABLISHED) { 106363285Smarcel if (cb->s_rtt == 0) 106463285Smarcel cb->s_rtt = 1; /* Time initial handshake */ 106563285Smarcel if (cb->s_timer[SPXT_REXMT] == 0) 106663285Smarcel cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 106763285Smarcel } 106863285Smarcel { 1069225617Skmacy /* 107063285Smarcel * Do not request acks when we ack their data packets or 107172538Sjlemon * when we do a gratuitous window update. 107272538Sjlemon */ 107383366Sjulian if (((si->si_cc & SPX_SP) == 0) || cb->s_force) 107472538Sjlemon si->si_cc |= SPX_SA; 107572538Sjlemon si->si_seq = htons(si->si_seq); 1076111798Sdes si->si_alo = htons(alo); 1077111798Sdes si->si_ack = htons(cb->s_ack); 107873286Sadrian 107973286Sadrian if (ipxcksum) { 108073286Sadrian si->si_sum = ipx_cksum(m, ntohs(si->si_len)); 108172538Sjlemon } else 1082111798Sdes si->si_sum = 0xffff; 108373286Sadrian 108472538Sjlemon cb->s_outx = 4; 1085111798Sdes if (so->so_options & SO_DEBUG || traceallspxs) 1086127057Stjr spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 108772538Sjlemon 1088111798Sdes if (so->so_options & SO_DONTROUTE) 1089127057Stjr error = ipx_outputfl(m, NULL, IPX_ROUTETOIF); 109072538Sjlemon else 1091111798Sdes error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0); 109272538Sjlemon } 109372538Sjlemon if (error) { 109472538Sjlemon return (error); 109572538Sjlemon } 109672538Sjlemon spxstat.spxs_sndtotal++; 109772538Sjlemon /* 109872538Sjlemon * Data sent (as far as we can tell). 109972538Sjlemon * If this advertises a larger window than any other segment, 1100127059Stjr * then remember the size of the advertized window. 110173286Sadrian * Any pending ACK has now been sent. 110272538Sjlemon */ 110372538Sjlemon cb->s_force = 0; 110472538Sjlemon cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); 110572538Sjlemon if (SSEQ_GT(alo, cb->s_alo)) 110672538Sjlemon cb->s_alo = alo; 110772538Sjlemon if (sendalot) 1108127059Stjr goto again; 110973286Sadrian cb->s_outx = 5; 1110190445Sambrisko return (0); 1111190445Sambrisko} 1112190445Sambrisko 111372538Sjlemonstatic int spx_do_persist_panics = 0; 111472538Sjlemon 111572538Sjlemonstatic void 111672538Sjlemonspx_setpersist(cb) 111773286Sadrian register struct spxpcb *cb; 111872538Sjlemon{ 111972538Sjlemon register int t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 112072538Sjlemon 112172538Sjlemon if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics) 112272538Sjlemon panic("spx_output REXMT"); 112372538Sjlemon /* 112472538Sjlemon * Start/restart persistance timer. 1125111798Sdes */ 112672538Sjlemon SPXT_RANGESET(cb->s_timer[SPXT_PERSIST], 1127111798Sdes t*spx_backoff[cb->s_rxtshift], 112872538Sjlemon SPXTV_PERSMIN, SPXTV_PERSMAX); 1129111798Sdes if (cb->s_rxtshift < SPX_MAXRXTSHIFT) 113072538Sjlemon cb->s_rxtshift++; 1131111798Sdes} 113272538Sjlemon 113372538Sjlemonint 1134127059Stjrspx_ctloutput(so, sopt) 1135132708Sphk struct socket *so; 1136132708Sphk struct sockopt *sopt; 1137132708Sphk{ 1138132708Sphk struct ipxpcb *ipxp = sotoipxpcb(so); 1139190445Sambrisko register struct spxpcb *cb; 1140190445Sambrisko int mask, error; 1141190445Sambrisko short soptval; 1142190445Sambrisko u_short usoptval; 1143190445Sambrisko int optval; 1144190445Sambrisko 1145127059Stjr error = 0; 1146138353Sphk 1147127059Stjr if (sopt->sopt_level != IPXPROTO_SPX) { 114872538Sjlemon /* This will have to be changed when we do more general 114972538Sjlemon stacking of protocols */ 115072538Sjlemon return (ipx_ctloutput(so, sopt)); 115183366Sjulian } 115272538Sjlemon if (ipxp == NULL) 115383221Smarcel return (EINVAL); 115472538Sjlemon else 115572538Sjlemon cb = ipxtospxpcb(ipxp); 115672538Sjlemon 115783366Sjulian switch (sopt->sopt_dir) { 115872538Sjlemon case SOPT_GET: 115972538Sjlemon switch (sopt->sopt_name) { 116072538Sjlemon case SO_HEADERS_ON_INPUT: 116183366Sjulian mask = SF_HI; 116272538Sjlemon goto get_flags; 116372538Sjlemon 116472538Sjlemon case SO_HEADERS_ON_OUTPUT: 116572538Sjlemon mask = SF_HO; 116672538Sjlemon get_flags: 1167225617Skmacy soptval = cb->s_flags & mask; 116872538Sjlemon error = sooptcopyout(sopt, &soptval, sizeof soptval); 116983221Smarcel break; 117083221Smarcel 117183221Smarcel case SO_MTU: 117283221Smarcel usoptval = cb->s_mtu; 117383221Smarcel error = sooptcopyout(sopt, &usoptval, sizeof usoptval); 117483221Smarcel break; 117583221Smarcel 117683221Smarcel case SO_LAST_HEADER: 117783221Smarcel error = sooptcopyout(sopt, &cb->s_rhdr, 117883221Smarcel sizeof cb->s_rhdr); 117983221Smarcel break; 1180133816Stjr 1181140214Sobrien case SO_DEFAULT_HEADERS: 1182133816Stjr error = sooptcopyout(sopt, &cb->s_shdr, 1183133816Stjr sizeof cb->s_shdr); 1184133816Stjr break; 118583221Smarcel 118683221Smarcel default: 118783221Smarcel error = ENOPROTOOPT; 118883221Smarcel } 118983221Smarcel break; 119083221Smarcel 119183221Smarcel case SOPT_SET: 119283221Smarcel switch (sopt->sopt_name) { 119383221Smarcel /* XXX why are these shorts on get and ints on set? 119483221Smarcel that doesn't make any sense... */ 119583221Smarcel case SO_HEADERS_ON_INPUT: 119683221Smarcel mask = SF_HI; 119783221Smarcel goto set_head; 119883221Smarcel 119983221Smarcel case SO_HEADERS_ON_OUTPUT: 120083221Smarcel mask = SF_HO; 120183221Smarcel set_head: 120283221Smarcel error = sooptcopyin(sopt, &optval, sizeof optval, 120383221Smarcel sizeof optval); 120483221Smarcel if (error) 120583221Smarcel break; 120683221Smarcel 1207177633Sdfr if (cb->s_flags & SF_PI) { 120883221Smarcel if (optval) 120983221Smarcel cb->s_flags |= mask; 121083221Smarcel else 121183221Smarcel cb->s_flags &= ~mask; 121283221Smarcel } else error = EINVAL; 121383221Smarcel break; 121483221Smarcel 121583221Smarcel case SO_MTU: 121683221Smarcel error = sooptcopyin(sopt, &usoptval, sizeof usoptval, 121783221Smarcel sizeof usoptval); 121883221Smarcel if (error) 121983221Smarcel break; 122083221Smarcel cb->s_mtu = usoptval; 122183221Smarcel break; 122283221Smarcel 122383221Smarcel#ifdef SF_NEWCALL 122483221Smarcel case SO_NEWCALL: 122583221Smarcel error = sooptcopyin(sopt, &optval, sizeof optval, 122683221Smarcel sizeof optval); 122783221Smarcel if (error) 122883221Smarcel break; 122983221Smarcel if (optval) { 1230140214Sobrien cb->s_flags2 |= SF_NEWCALL; 123183221Smarcel spx_newchecks[5]++; 123283221Smarcel } else { 123383221Smarcel cb->s_flags2 &= ~SF_NEWCALL; 123483221Smarcel spx_newchecks[6]++; 123583221Smarcel } 123683221Smarcel break; 1237133816Stjr#endif 1238140214Sobrien 1239133816Stjr case SO_DEFAULT_HEADERS: 1240133816Stjr { 1241133816Stjr struct spxhdr sp; 124283221Smarcel 124383221Smarcel error = sooptcopyin(sopt, &sp, sizeof sp, 124483221Smarcel sizeof sp); 124583221Smarcel if (error) 124683221Smarcel break; 124783221Smarcel cb->s_dt = sp.spx_dt; 124883221Smarcel cb->s_cc = sp.spx_cc & SPX_EM; 124983221Smarcel } 125083221Smarcel break; 125183221Smarcel 125283221Smarcel default: 125383221Smarcel error = ENOPROTOOPT; 125483221Smarcel } 125583221Smarcel break; 125683221Smarcel } 125783221Smarcel return (error); 125883221Smarcel} 125983221Smarcel 126083221Smarcelstatic int 126183221Smarcelspx_usr_abort(so) 126283221Smarcel struct socket *so; 126383221Smarcel{ 1264177633Sdfr int s; 126583221Smarcel struct ipxpcb *ipxp; 126683221Smarcel struct spxpcb *cb; 126783221Smarcel 126883221Smarcel ipxp = sotoipxpcb(so); 126983221Smarcel cb = ipxtospxpcb(ipxp); 127083221Smarcel 127183221Smarcel s = splnet(); 127283221Smarcel spx_drop(cb, ECONNABORTED); 127383221Smarcel splx(s); 127483221Smarcel return (0); 127583221Smarcel} 127683221Smarcel 127783221Smarcel/* 127883221Smarcel * Accept a connection. Essentially all the work is 127983221Smarcel * done at higher levels; just return the address 128083221Smarcel * of the peer, storing through addr. 128183221Smarcel */ 128283221Smarcelstatic int 128383221Smarcelspx_accept(so, nam) 128483221Smarcel struct socket *so; 128583221Smarcel struct sockaddr **nam; 1286133816Stjr{ 128783221Smarcel struct ipxpcb *ipxp; 128883221Smarcel struct sockaddr_ipx *sipx, ssipx; 128983366Sjulian 129083221Smarcel ipxp = sotoipxpcb(so); 1291107680Siedowse sipx = &ssipx; 1292107680Siedowse bzero(sipx, sizeof *sipx); 1293255219Spjd sipx->sipx_len = sizeof *sipx; 129483221Smarcel sipx->sipx_family = AF_IPX; 1295102872Siedowse sipx->sipx_addr = ipxp->ipxp_faddr; 129683221Smarcel *nam = sodupsockaddr((struct sockaddr *)sipx, M_NOWAIT); 129783221Smarcel return (0); 129883221Smarcel} 129983221Smarcel 1300102872Siedowsestatic int 130183221Smarcelspx_attach(so, proto, td) 130283221Smarcel struct socket *so; 1303102872Siedowse int proto; 130483221Smarcel struct thread *td; 130583221Smarcel{ 1306102872Siedowse int error; 130783221Smarcel int s; 130883221Smarcel struct ipxpcb *ipxp; 1309102872Siedowse struct spxpcb *cb; 131083366Sjulian struct mbuf *mm; 131183366Sjulian struct sockbuf *sb; 131283221Smarcel 131383366Sjulian ipxp = sotoipxpcb(so); 131483221Smarcel cb = ipxtospxpcb(ipxp); 131583366Sjulian 131683221Smarcel if (ipxp != NULL) 131783366Sjulian return (EISCONN); 131883221Smarcel s = splnet(); 131983366Sjulian error = ipx_pcballoc(so, &ipxpcb_list, td); 132083221Smarcel if (error) 132183366Sjulian goto spx_attach_end; 132283221Smarcel if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 132383366Sjulian error = soreserve(so, (u_long) 3072, (u_long) 3072); 132483221Smarcel if (error) 132583366Sjulian goto spx_attach_end; 1326144987Smdodd } 1327144987Smdodd ipxp = sotoipxpcb(so); 1328144987Smdodd 1329144987Smdodd MALLOC(cb, struct spxpcb *, sizeof *cb, M_PCB, M_NOWAIT | M_ZERO); 1330144987Smdodd 1331144987Smdodd if (cb == NULL) { 1332144987Smdodd error = ENOBUFS; 1333144987Smdodd goto spx_attach_end; 133483221Smarcel } 133583221Smarcel sb = &so->so_snd; 133683221Smarcel 1337102872Siedowse mm = m_getclr(M_DONTWAIT, MT_HEADER); 133883221Smarcel if (mm == NULL) { 1339102872Siedowse FREE(cb, M_PCB); 134083221Smarcel error = ENOBUFS; 1341102872Siedowse goto spx_attach_end; 134283221Smarcel } 1343102872Siedowse cb->s_ipx = mtod(mm, struct ipx *); 134483221Smarcel cb->s_state = TCPS_LISTEN; 1345102872Siedowse cb->s_smax = -1; 1346144987Smdodd cb->s_swl1 = -1; 1347144987Smdodd cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 1348144987Smdodd cb->s_ipxpcb = ipxp; 1349144987Smdodd cb->s_mtu = 576 - sizeof(struct spx); 1350144987Smdodd cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; 1351144987Smdodd cb->s_ssthresh = cb->s_cwnd; 1352144987Smdodd cb->s_cwmx = sbspace(sb) * CUNIT / (2 * sizeof(struct spx)); 1353144987Smdodd /* Above is recomputed when connecting to account 1354102872Siedowse for changed buffering or mtu's */ 135583221Smarcel cb->s_rtt = SPXTV_SRTTBASE; 1356107680Siedowse cb->s_rttvar = SPXTV_SRTTDFLT << 2; 1357111797Sdes SPXT_RANGESET(cb->s_rxtcur, 1358107680Siedowse ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1, 1359107680Siedowse SPXTV_MIN, SPXTV_REXMTMAX); 1360107680Siedowse ipxp->ipxp_pcb = (caddr_t)cb; 1361107680Siedowsespx_attach_end: 1362107680Siedowse splx(s); 1363107680Siedowse return (error); 1364107680Siedowse} 1365107680Siedowse 1366111797Sdesstatic int 1367107680Siedowsespx_bind(so, nam, td) 1368107680Siedowse struct socket *so; 1369107680Siedowse struct sockaddr *nam; 1370111797Sdes struct thread *td; 1371107680Siedowse{ 1372107680Siedowse struct ipxpcb *ipxp; 1373107680Siedowse 1374107680Siedowse ipxp = sotoipxpcb(so); 1375107680Siedowse 1376107680Siedowse return (ipx_pcbbind(ipxp, nam, td)); 1377107680Siedowse} 1378107680Siedowse 1379111797Sdes/* 1380107680Siedowse * Initiate connection to peer. 1381107680Siedowse * Enter SYN_SENT state, and mark socket as connecting. 1382107680Siedowse * Start keep-alive timer, setup prototype header, 1383107680Siedowse * Send initial system packet requesting connection. 1384107680Siedowse */ 1385107680Siedowsestatic int 1386107680Siedowsespx_connect(so, nam, td) 138783221Smarcel struct socket *so; 1388102872Siedowse struct sockaddr *nam; 138983221Smarcel struct thread *td; 139083221Smarcel{ 139183221Smarcel int error; 139283221Smarcel int s; 139383221Smarcel struct ipxpcb *ipxp; 139483221Smarcel struct spxpcb *cb; 139583221Smarcel 1396255219Spjd ipxp = sotoipxpcb(so); 1397255219Spjd cb = ipxtospxpcb(ipxp); 139889319Salfred 139989319Salfred s = splnet(); 140089306Salfred if (ipxp->ipxp_lport == 0) { 140189306Salfred error = ipx_pcbbind(ipxp, NULL, td); 140283221Smarcel if (error) 140389306Salfred goto spx_connect_end; 140489306Salfred } 140583221Smarcel error = ipx_pcbconnect(ipxp, nam, td); 1406102872Siedowse if (error) 140783221Smarcel goto spx_connect_end; 140883221Smarcel soisconnecting(so); 140983221Smarcel spxstat.spxs_connattempt++; 141083221Smarcel cb->s_state = TCPS_SYN_SENT; 141183221Smarcel cb->s_did = 0; 141283221Smarcel spx_template(cb); 141383366Sjulian cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 141483221Smarcel cb->s_force = 1 + SPXTV_KEEP; 141583221Smarcel /* 141683221Smarcel * Other party is required to respond to 141783221Smarcel * the port I send from, but he is not 141883221Smarcel * required to answer from where I am sending to, 141983221Smarcel * so allow wildcarding. 142083221Smarcel * original port I am sending to is still saved in 142183221Smarcel * cb->s_dport. 142283221Smarcel */ 142383221Smarcel ipxp->ipxp_fport = 0; 142483221Smarcel error = spx_output(cb, NULL); 142583366Sjulianspx_connect_end: 142683221Smarcel splx(s); 142783221Smarcel return (error); 1428140214Sobrien} 142983221Smarcel 143083366Sjulianstatic int 143183221Smarcelspx_detach(so) 143283221Smarcel struct socket *so; 1433102872Siedowse{ 143483221Smarcel int s; 143583221Smarcel struct ipxpcb *ipxp; 143683221Smarcel struct spxpcb *cb; 143783221Smarcel 143883221Smarcel ipxp = sotoipxpcb(so); 143983221Smarcel cb = ipxtospxpcb(ipxp); 144083221Smarcel 144183221Smarcel if (ipxp == NULL) 144299687Srobert return (ENOTCONN); 1443111797Sdes s = splnet(); 144483221Smarcel if (cb->s_state > TCPS_LISTEN) 144583221Smarcel spx_disconnect(cb); 144683221Smarcel else 1447102872Siedowse spx_close(cb); 1448102872Siedowse splx(s); 144983221Smarcel return (0); 145083221Smarcel} 1451102872Siedowse 1452111797Sdes/* 1453111797Sdes * We may decide later to implement connection closing 145483221Smarcel * handshaking at the spx level optionally. 145599687Srobert * here is the hook to do it: 1456111797Sdes */ 145783221Smarcelstatic int 145883221Smarcelspx_usr_disconnect(so) 145983221Smarcel struct socket *so; 1460102872Siedowse{ 1461102872Siedowse int s; 1462102872Siedowse struct ipxpcb *ipxp; 146383221Smarcel struct spxpcb *cb; 146499687Srobert 1465111797Sdes ipxp = sotoipxpcb(so); 146683221Smarcel cb = ipxtospxpcb(ipxp); 146783221Smarcel 146883221Smarcel s = splnet(); 1469102872Siedowse spx_disconnect(cb); 1470102872Siedowse splx(s); 1471102872Siedowse return (0); 147283221Smarcel} 147383221Smarcel 147483366Sjulianstatic int 147583221Smarcelspx_listen(so, td) 1476133816Stjr struct socket *so; 147785022Smarcel struct thread *td; 147885022Smarcel{ 147985022Smarcel int error; 148085022Smarcel struct ipxpcb *ipxp; 1481102814Siedowse struct spxpcb *cb; 1482102814Siedowse 148385022Smarcel error = 0; 1484102814Siedowse ipxp = sotoipxpcb(so); 148585022Smarcel cb = ipxtospxpcb(ipxp); 148685022Smarcel 148785022Smarcel if (ipxp->ipxp_lport == 0) 1488102814Siedowse error = ipx_pcbbind(ipxp, NULL, td); 148985022Smarcel if (error == 0) 1490102814Siedowse cb->s_state = TCPS_LISTEN; 1491102814Siedowse return (error); 1492102814Siedowse} 149385022Smarcel 149485022Smarcel/* 149585022Smarcel * After a receive, possibly send acknowledgment 1496177997Skib * updating allocation. 1497177997Skib */ 1498177997Skibstatic int 1499227693Sedspx_rcvd(so, flags) 1500177997Skib struct socket *so; 1501177997Skib int flags; 1502177997Skib{ 1503177997Skib int s; 1504177997Skib struct ipxpcb *ipxp; 1505177997Skib struct spxpcb *cb; 1506177997Skib 1507177997Skib ipxp = sotoipxpcb(so); 1508177997Skib cb = ipxtospxpcb(ipxp); 1509177997Skib 1510177997Skib s = splnet(); 1511177997Skib cb->s_flags |= SF_RVD; 1512227693Sed spx_output(cb, NULL); 1513177997Skib cb->s_flags &= ~SF_RVD; 1514177997Skib splx(s); 1515227693Sed return (0); 1516177997Skib} 1517177997Skib 1518177997Skibstatic int 1519177997Skibspx_rcvoob(so, m, flags) 1520177997Skib struct socket *so; 152185022Smarcel struct mbuf *m; 152285022Smarcel int flags; 1523102814Siedowse{ 1524102814Siedowse struct ipxpcb *ipxp; 152585022Smarcel struct spxpcb *cb; 1526102814Siedowse 152785022Smarcel ipxp = sotoipxpcb(so); 152885022Smarcel cb = ipxtospxpcb(ipxp); 152985022Smarcel 1530102814Siedowse SOCKBUF_LOCK(&so->so_rcv); 153185022Smarcel if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 1532102814Siedowse (so->so_rcv.sb_state & SBS_RCVATMARK)) { 1533102814Siedowse SOCKBUF_UNLOCK(&so->so_rcv); 1534102814Siedowse m->m_len = 1; 153585022Smarcel *mtod(m, caddr_t) = cb->s_iobc; 1536228957Sjhb return (0); 1537228957Sjhb } 1538228957Sjhb SOCKBUF_UNLOCK(&so->so_rcv); 1539228957Sjhb return (EINVAL); 1540228957Sjhb} 1541228957Sjhb 1542228957Sjhbstatic int 1543228957Sjhbspx_send(so, flags, m, addr, controlp, td) 1544228957Sjhb struct socket *so; 1545228957Sjhb int flags; 1546228957Sjhb struct mbuf *m; 1547228957Sjhb struct sockaddr *addr; 1548228957Sjhb struct mbuf *controlp; 1549228957Sjhb struct thread *td; 1550228957Sjhb{ 1551228957Sjhb int error; 1552228957Sjhb int s; 1553228957Sjhb struct ipxpcb *ipxp; 1554228957Sjhb struct spxpcb *cb; 1555228957Sjhb 1556228957Sjhb error = 0; 1557228957Sjhb ipxp = sotoipxpcb(so); 1558228957Sjhb cb = ipxtospxpcb(ipxp); 1559228957Sjhb 1560228957Sjhb s = splnet(); 1561228957Sjhb if (flags & PRUS_OOB) { 1562228957Sjhb if (sbspace(&so->so_snd) < -512) { 1563228957Sjhb error = ENOBUFS; 1564228957Sjhb goto spx_send_end; 1565228957Sjhb } 1566228957Sjhb cb->s_oobflags |= SF_SOOB; 1567228957Sjhb } 1568228957Sjhb if (controlp != NULL) { 1569228957Sjhb u_short *p = mtod(controlp, u_short *); 1570228957Sjhb spx_newchecks[2]++; 1571228957Sjhb if ((p[0] == 5) && (p[1] == 1)) { /* XXXX, for testing */ 1572228957Sjhb cb->s_shdr.spx_dt = *(u_char *)(&p[2]); 1573228957Sjhb spx_newchecks[3]++; 1574228957Sjhb } 1575228957Sjhb m_freem(controlp); 1576228957Sjhb } 1577228957Sjhb controlp = NULL; 1578228957Sjhb error = spx_output(cb, m); 1579228957Sjhb m = NULL; 1580228957Sjhbspx_send_end: 1581234352Sjkim if (controlp != NULL) 1582234352Sjkim m_freem(controlp); 1583234352Sjkim if (m != NULL) 1584234352Sjkim m_freem(m); 1585234352Sjkim splx(s); 1586234352Sjkim return (error); 1587234352Sjkim} 1588234352Sjkim 1589234352Sjkimstatic int 1590234352Sjkimspx_shutdown(so) 1591234352Sjkim struct socket *so; 1592234352Sjkim{ 1593248951Sjilles int error; 1594234352Sjkim int s; 1595234352Sjkim struct ipxpcb *ipxp; 1596234352Sjkim struct spxpcb *cb; 1597234352Sjkim 1598234352Sjkim error = 0; 1599234352Sjkim ipxp = sotoipxpcb(so); 1600234352Sjkim cb = ipxtospxpcb(ipxp); 1601234352Sjkim 1602234352Sjkim s = splnet(); 1603234352Sjkim socantsendmore(so); 1604234352Sjkim cb = spx_usrclosed(cb); 1605234352Sjkim if (cb != NULL) 1606234352Sjkim error = spx_output(cb, NULL); 1607234352Sjkim splx(s); 1608234352Sjkim return (error); 1609234352Sjkim} 1610234352Sjkim 1611234352Sjkimstatic int 1612234352Sjkimspx_sp_attach(so, proto, td) 1613234352Sjkim struct socket *so; 1614234352Sjkim int proto; 1615234352Sjkim struct thread *td; 1616234352Sjkim{ 1617234352Sjkim int error; 1618234352Sjkim struct ipxpcb *ipxp; 1619234352Sjkim 1620248951Sjilles error = spx_attach(so, proto, td); 1621234352Sjkim if (error == 0) { 1622234352Sjkim ipxp = sotoipxpcb(so); 1623234352Sjkim ((struct spxpcb *)ipxp->ipxp_pcb)->s_flags |= 1624234352Sjkim (SF_HI | SF_HO | SF_PI); 1625234352Sjkim } 1626234352Sjkim return (error); 1627} 1628 1629/* 1630 * Create template to be used to send spx packets on a connection. 1631 * Called after host entry created, fills 1632 * in a skeletal spx header (choosing connection id), 1633 * minimizing the amount of work necessary when the connection is used. 1634 */ 1635static void 1636spx_template(cb) 1637 register struct spxpcb *cb; 1638{ 1639 register struct ipxpcb *ipxp = cb->s_ipxpcb; 1640 register struct ipx *ipx = cb->s_ipx; 1641 register struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd); 1642 1643 ipx->ipx_pt = IPXPROTO_SPX; 1644 ipx->ipx_sna = ipxp->ipxp_laddr; 1645 ipx->ipx_dna = ipxp->ipxp_faddr; 1646 cb->s_sid = htons(spx_iss); 1647 spx_iss += SPX_ISSINCR/2; 1648 cb->s_alo = 1; 1649 cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; 1650 cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement 1651 of large packets */ 1652 cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx)); 1653 cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); 1654 /* But allow for lots of little packets as well */ 1655} 1656 1657/* 1658 * Close a SPIP control block: 1659 * discard spx control block itself 1660 * discard ipx protocol control block 1661 * wake up any sleepers 1662 */ 1663static struct spxpcb * 1664spx_close(cb) 1665 register struct spxpcb *cb; 1666{ 1667 register struct spx_q *s; 1668 struct ipxpcb *ipxp = cb->s_ipxpcb; 1669 struct socket *so = ipxp->ipxp_socket; 1670 register struct mbuf *m; 1671 1672 s = cb->s_q.si_next; 1673 while (s != &(cb->s_q)) { 1674 s = s->si_next; 1675 m = dtom(s->si_prev); 1676 remque(s->si_prev); 1677 m_freem(m); 1678 } 1679 m_free(dtom(cb->s_ipx)); 1680 FREE(cb, M_PCB); 1681 ipxp->ipxp_pcb = NULL; 1682 soisdisconnected(so); 1683 ipx_pcbdetach(ipxp); 1684 spxstat.spxs_closed++; 1685 return (NULL); 1686} 1687 1688/* 1689 * Someday we may do level 3 handshaking 1690 * to close a connection or send a xerox style error. 1691 * For now, just close. 1692 */ 1693static struct spxpcb * 1694spx_usrclosed(cb) 1695 register struct spxpcb *cb; 1696{ 1697 return (spx_close(cb)); 1698} 1699 1700static struct spxpcb * 1701spx_disconnect(cb) 1702 register struct spxpcb *cb; 1703{ 1704 return (spx_close(cb)); 1705} 1706 1707/* 1708 * Drop connection, reporting 1709 * the specified error. 1710 */ 1711static struct spxpcb * 1712spx_drop(cb, errno) 1713 register struct spxpcb *cb; 1714 int errno; 1715{ 1716 struct socket *so = cb->s_ipxpcb->ipxp_socket; 1717 1718 /* 1719 * someday, in the xerox world 1720 * we will generate error protocol packets 1721 * announcing that the socket has gone away. 1722 */ 1723 if (TCPS_HAVERCVDSYN(cb->s_state)) { 1724 spxstat.spxs_drops++; 1725 cb->s_state = TCPS_CLOSED; 1726 /*tcp_output(cb);*/ 1727 } else 1728 spxstat.spxs_conndrops++; 1729 so->so_error = errno; 1730 return (spx_close(cb)); 1731} 1732 1733/* 1734 * Fast timeout routine for processing delayed acks 1735 */ 1736void 1737spx_fasttimo() 1738{ 1739 register struct ipxpcb *ipxp; 1740 register struct spxpcb *cb; 1741 int s = splnet(); 1742 1743 LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 1744 if ((cb = (struct spxpcb *)ipxp->ipxp_pcb) != NULL && 1745 (cb->s_flags & SF_DELACK)) { 1746 cb->s_flags &= ~SF_DELACK; 1747 cb->s_flags |= SF_ACKNOW; 1748 spxstat.spxs_delack++; 1749 spx_output(cb, NULL); 1750 } 1751 } 1752 1753 splx(s); 1754} 1755 1756/* 1757 * spx protocol timeout routine called every 500 ms. 1758 * Updates the timers in all active pcb's and 1759 * causes finite state machine actions if timers expire. 1760 */ 1761void 1762spx_slowtimo() 1763{ 1764 register struct ipxpcb *ip, *ip_temp; 1765 register struct spxpcb *cb; 1766 int s = splnet(); 1767 register int i; 1768 1769 /* 1770 * Search through tcb's and update active timers. Note that timers 1771 * may free the ipxpcb, so be sure to handle that case. 1772 */ 1773 LIST_FOREACH_SAFE(ip, &ipxpcb_list, ipxp_list, ip_temp) { 1774 cb = ipxtospxpcb(ip); 1775 if (cb == NULL) 1776 continue; 1777 for (i = 0; i < SPXT_NTIMERS; i++) { 1778 if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 1779 /* 1780 * spx_timers() returns (NULL) if it free'd 1781 * the pcb. 1782 */ 1783 cb = spx_timers(cb, i); 1784 if (cb == NULL) 1785 break; 1786 } 1787 } 1788 if (cb != NULL) { 1789 cb->s_idle++; 1790 if (cb->s_rtt) 1791 cb->s_rtt++; 1792 } 1793 } 1794 spx_iss += SPX_ISSINCR/PR_SLOWHZ; /* increment iss */ 1795 splx(s); 1796} 1797 1798/* 1799 * SPX timer processing. 1800 */ 1801static struct spxpcb * 1802spx_timers(cb, timer) 1803 register struct spxpcb *cb; 1804 int timer; 1805{ 1806 long rexmt; 1807 int win; 1808 1809 cb->s_force = 1 + timer; 1810 switch (timer) { 1811 1812 /* 1813 * 2 MSL timeout in shutdown went off. TCP deletes connection 1814 * control block. 1815 */ 1816 case SPXT_2MSL: 1817 printf("spx: SPXT_2MSL went off for no reason\n"); 1818 cb->s_timer[timer] = 0; 1819 break; 1820 1821 /* 1822 * Retransmission timer went off. Message has not 1823 * been acked within retransmit interval. Back off 1824 * to a longer retransmit interval and retransmit one packet. 1825 */ 1826 case SPXT_REXMT: 1827 if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) { 1828 cb->s_rxtshift = SPX_MAXRXTSHIFT; 1829 spxstat.spxs_timeoutdrop++; 1830 cb = spx_drop(cb, ETIMEDOUT); 1831 break; 1832 } 1833 spxstat.spxs_rexmttimeo++; 1834 rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 1835 rexmt *= spx_backoff[cb->s_rxtshift]; 1836 SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX); 1837 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 1838 /* 1839 * If we have backed off fairly far, our srtt 1840 * estimate is probably bogus. Clobber it 1841 * so we'll take the next rtt measurement as our srtt; 1842 * move the current srtt into rttvar to keep the current 1843 * retransmit times until then. 1844 */ 1845 if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) { 1846 cb->s_rttvar += (cb->s_srtt >> 2); 1847 cb->s_srtt = 0; 1848 } 1849 cb->s_snxt = cb->s_rack; 1850 /* 1851 * If timing a packet, stop the timer. 1852 */ 1853 cb->s_rtt = 0; 1854 /* 1855 * See very long discussion in tcp_timer.c about congestion 1856 * window and sstrhesh 1857 */ 1858 win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; 1859 if (win < 2) 1860 win = 2; 1861 cb->s_cwnd = CUNIT; 1862 cb->s_ssthresh = win * CUNIT; 1863 spx_output(cb, NULL); 1864 break; 1865 1866 /* 1867 * Persistance timer into zero window. 1868 * Force a probe to be sent. 1869 */ 1870 case SPXT_PERSIST: 1871 spxstat.spxs_persisttimeo++; 1872 spx_setpersist(cb); 1873 spx_output(cb, NULL); 1874 break; 1875 1876 /* 1877 * Keep-alive timer went off; send something 1878 * or drop connection if idle for too long. 1879 */ 1880 case SPXT_KEEP: 1881 spxstat.spxs_keeptimeo++; 1882 if (cb->s_state < TCPS_ESTABLISHED) 1883 goto dropit; 1884 if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) { 1885 if (cb->s_idle >= SPXTV_MAXIDLE) 1886 goto dropit; 1887 spxstat.spxs_keepprobe++; 1888 spx_output(cb, NULL); 1889 } else 1890 cb->s_idle = 0; 1891 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 1892 break; 1893 dropit: 1894 spxstat.spxs_keepdrops++; 1895 cb = spx_drop(cb, ETIMEDOUT); 1896 break; 1897 } 1898 return (cb); 1899} 1900