spx_usrreq.c revision 194545
1139804Simp/*- 21541Srgrimes * Copyright (c) 1984, 1985, 1986, 1987, 1993 31541Srgrimes * The Regents of the University of California. 41541Srgrimes * Copyright (c) 2004-2009 Robert N. M. Watson 51541Srgrimes * All rights reserved. 61541Srgrimes * 71541Srgrimes * Redistribution and use in source and binary forms, with or without 81541Srgrimes * modification, are permitted provided that the following conditions 91541Srgrimes * are met: 101541Srgrimes * 1. Redistributions of source code must retain the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer. 121541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 131541Srgrimes * notice, this list of conditions and the following disclaimer in the 141541Srgrimes * documentation and/or other materials provided with the distribution. 151541Srgrimes * 4. Neither the name of the University nor the names of its contributors 161541Srgrimes * may be used to endorse or promote products derived from this software 171541Srgrimes * without specific prior written permission. 181541Srgrimes * 191541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 201541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 211541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 221541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 231541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 241541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 251541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 261541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 271541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 281541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 291541Srgrimes * SUCH DAMAGE. 301541Srgrimes * 311541Srgrimes * Copyright (c) 1995, Mike Mitchell 321541Srgrimes * All rights reserved. 331541Srgrimes * 341541Srgrimes * Redistribution and use in source and binary forms, with or without 351541Srgrimes * modification, are permitted provided that the following conditions 361541Srgrimes * are met: 37116182Sobrien * 1. Redistributions of source code must retain the above copyright 38116182Sobrien * notice, this list of conditions and the following disclaimer. 391541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 401541Srgrimes * notice, this list of conditions and the following disclaimer in the 412112Swollman * documentation and/or other materials provided with the distribution. 422946Swollman * 3. All advertising materials mentioning features or use of this software 43138350Sphk * must display the following acknowledgement: 441541Srgrimes * This product includes software developed by the University of 45138350Sphk * California, Berkeley and its contributors. 46159590Sjhb * 4. Neither the name of the University nor the names of its contributors 4738869Sbde * may be used to endorse or promote products derived from this software 481541Srgrimes * without specific prior written permission. 491541Srgrimes * 501541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51141634Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52141634Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5312577Sbde * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5430354Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5530354Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5610358Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5769664Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5829653Sdyson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5969664Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6091690Seivind * SUCH DAMAGE. 6191690Seivind * 6291690Seivind * @(#)spx_usrreq.h 6391690Seivind */ 6491690Seivind 65132710Sphk#include <sys/cdefs.h> 6652780Smsmith__FBSDID("$FreeBSD: head/sys/netipx/spx_usrreq.c 194545 2009-06-20 17:44:04Z rwatson $"); 6752780Smsmith 68135279Sphk#include <sys/param.h> 69135279Sphk#include <sys/lock.h> 70135279Sphk#include <sys/malloc.h> 71135279Sphk#include <sys/mbuf.h> 72135279Sphk#include <sys/mutex.h> 73135279Sphk#include <sys/proc.h> 74135279Sphk#include <sys/protosw.h> 751541Srgrimes#include <sys/signalvar.h> 761541Srgrimes#include <sys/socket.h> 771541Srgrimes#include <sys/socketvar.h> 781541Srgrimes#include <sys/sx.h> 791541Srgrimes#include <sys/systm.h> 801541Srgrimes 811541Srgrimes#include <net/route.h> 821541Srgrimes#include <netinet/tcp_fsm.h> 831541Srgrimes 841541Srgrimes#include <netipx/ipx.h> 851541Srgrimes#include <netipx/ipx_pcb.h> 861541Srgrimes#include <netipx/ipx_var.h> 871541Srgrimes#include <netipx/spx.h> 881541Srgrimes#include <netipx/spx_debug.h> 891541Srgrimes#include <netipx/spx_timer.h> 9041056Speter#include <netipx/spx_var.h> 91138290Sphk 92138290Sphk#include <security/mac/mac_framework.h> 93138290Sphk 9441056Speter/* 95132710Sphk * SPX protocol implementation. 96132710Sphk */ 97132710Sphkstatic struct mtx spx_mtx; /* Protects only spx_iss. */ 98132710Sphkstatic u_short spx_iss; 99132710Sphku_short spx_newchecks[50]; 100138497Sphkstatic int spx_hardnosed; 101138497Sphkstatic int traceallspxs = 0; 102132710Sphkstruct spx_istat spx_istat; 103132710Sphk 104132710Sphk#define SPX_LOCK_INIT() mtx_init(&spx_mtx, "spx_mtx", NULL, MTX_DEF) 105132710Sphk#define SPX_LOCK() mtx_lock(&spx_mtx) 106132710Sphk#define SPX_UNLOCK() mtx_unlock(&spx_mtx) 107132710Sphk 108138350Sphkstatic const int spx_backoff[SPX_MAXRXTSHIFT+1] = 109138350Sphk { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 110138350Sphk 111138350Sphkstatic void spx_close(struct spxpcb *cb); 112159590Sjhbstatic void spx_disconnect(struct spxpcb *cb); 113138350Sphkstatic void spx_drop(struct spxpcb *cb, int errno); 114138350Sphkstatic void spx_setpersist(struct spxpcb *cb); 115138350Sphkstatic void spx_template(struct spxpcb *cb); 116138350Sphkstatic void spx_timers(struct spxpcb *cb, int timer); 117138350Sphkstatic void spx_usrclosed(struct spxpcb *cb); 118138350Sphk 119138350Sphkstatic void spx_usr_abort(struct socket *so); 120138350Sphkstatic int spx_accept(struct socket *so, struct sockaddr **nam); 121138350Sphkstatic int spx_attach(struct socket *so, int proto, struct thread *td); 122138350Sphkstatic int spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); 123138350Sphkstatic void spx_usr_close(struct socket *so); 124138350Sphkstatic int spx_connect(struct socket *so, struct sockaddr *nam, 125159590Sjhb struct thread *td); 126138350Sphkstatic void spx_detach(struct socket *so); 127138350Sphkstatic void spx_pcbdetach(struct ipxpcb *ipxp); 128159590Sjhbstatic int spx_usr_disconnect(struct socket *so); 129138350Sphkstatic int spx_listen(struct socket *so, int backlog, struct thread *td); 130138350Sphkstatic int spx_rcvd(struct socket *so, int flags); 131138350Sphkstatic int spx_rcvoob(struct socket *so, struct mbuf *m, int flags); 132159590Sjhbstatic int spx_send(struct socket *so, int flags, struct mbuf *m, 133138350Sphk struct sockaddr *addr, struct mbuf *control, 134138350Sphk struct thread *td); 135138350Sphkstatic int spx_shutdown(struct socket *so); 136138350Sphkstatic int spx_sp_attach(struct socket *so, int proto, struct thread *td); 137138350Sphk 138138350Sphkstruct pr_usrreqs spx_usrreqs = { 139138350Sphk .pru_abort = spx_usr_abort, 14096755Strhodes .pru_accept = spx_accept, 141141634Sphk .pru_attach = spx_attach, 14241056Speter .pru_bind = spx_bind, 14340435Speter .pru_connect = spx_connect, 14444549Sdfr .pru_control = ipx_control, 145116271Sphk .pru_detach = spx_detach, 146135279Sphk .pru_disconnect = spx_usr_disconnect, 147135279Sphk .pru_listen = spx_listen, 148135279Sphk .pru_peeraddr = ipx_peeraddr, 149135279Sphk .pru_rcvd = spx_rcvd, 150135279Sphk .pru_rcvoob = spx_rcvoob, 151135279Sphk .pru_send = spx_send, 152116271Sphk .pru_shutdown = spx_shutdown, 153132902Sphk .pru_sockaddr = ipx_sockaddr, 154132902Sphk .pru_close = spx_usr_close, 155132902Sphk}; 156132902Sphk 157132902Sphkstruct pr_usrreqs spx_usrreq_sps = { 158132710Sphk .pru_abort = spx_usr_abort, 159132710Sphk .pru_accept = spx_accept, 16040435Speter .pru_attach = spx_sp_attach, 16140435Speter .pru_bind = spx_bind, 162132710Sphk .pru_connect = spx_connect, 16340435Speter .pru_control = ipx_control, 16440435Speter .pru_detach = spx_detach, 16544549Sdfr .pru_disconnect = spx_usr_disconnect, 16644549Sdfr .pru_listen = spx_listen, 16744549Sdfr .pru_peeraddr = ipx_peeraddr, 16844549Sdfr .pru_rcvd = spx_rcvd, 16944549Sdfr .pru_rcvoob = spx_rcvoob, 17044549Sdfr .pru_send = spx_send, 17144549Sdfr .pru_shutdown = spx_shutdown, 17244549Sdfr .pru_sockaddr = ipx_sockaddr, 17344549Sdfr .pru_close = spx_usr_close, 17472012Sphk}; 17544549Sdfr 17644549Sdfrvoid 17744549Sdfrspx_init(void) 17844549Sdfr{ 17944549Sdfr 18044549Sdfr SPX_LOCK_INIT(); 18144549Sdfr spx_iss = 1; /* WRONG !! should fish it out of TODR */ 182116271Sphk} 183116271Sphk 184116271Sphkvoid 185116271Sphkspx_input(struct mbuf *m, struct ipxpcb *ipxp) 186116271Sphk{ 187116271Sphk struct spxpcb *cb; 188116271Sphk struct spx *si = mtod(m, struct spx *); 189116271Sphk struct socket *so; 190116271Sphk struct spx spx_savesi; 191116271Sphk int dropsocket = 0; 192116271Sphk short ostate = 0; 193138509Sphk 194138509Sphk spxstat.spxs_rcvtotal++; 195116271Sphk KASSERT(ipxp != NULL, ("spx_input: ipxpcb == NULL")); 196116271Sphk 197116271Sphk /* 198116271Sphk * spx_input() assumes that the caller will hold both the pcb list 199116271Sphk * lock and also the ipxp lock. spx_input() will release both before 200116271Sphk * returning, and may in fact trade in the ipxp lock for another pcb 201116271Sphk * lock following sonewconn(). 202116271Sphk */ 203116271Sphk IPX_LIST_LOCK_ASSERT(); 204116271Sphk IPX_LOCK_ASSERT(ipxp); 205116271Sphk 206116271Sphk cb = ipxtospxpcb(ipxp); 207116271Sphk KASSERT(cb != NULL, ("spx_input: cb == NULL")); 208116271Sphk 209116271Sphk if (ipxp->ipxp_flags & IPXP_DROPPED) 210116271Sphk goto drop; 211116271Sphk 212116271Sphk if (m->m_len < sizeof(*si)) { 213116271Sphk if ((m = m_pullup(m, sizeof(*si))) == NULL) { 214116271Sphk IPX_UNLOCK(ipxp); 215116271Sphk IPX_LIST_UNLOCK(); 216116271Sphk spxstat.spxs_rcvshort++; 217116271Sphk return; 218116271Sphk } 219116271Sphk si = mtod(m, struct spx *); 220116271Sphk } 221116271Sphk si->si_seq = ntohs(si->si_seq); 222116271Sphk si->si_ack = ntohs(si->si_ack); 223116271Sphk si->si_alo = ntohs(si->si_alo); 224116271Sphk 225116271Sphk so = ipxp->ipxp_socket; 226116271Sphk KASSERT(so != NULL, ("spx_input: so == NULL")); 227116271Sphk 228116271Sphk if (so->so_options & SO_DEBUG || traceallspxs) { 229116271Sphk ostate = cb->s_state; 230116271Sphk spx_savesi = *si; 231116271Sphk } 232116271Sphk if (so->so_options & SO_ACCEPTCONN) { 233116271Sphk struct spxpcb *ocb = cb; 234116271Sphk 235116271Sphk so = sonewconn(so, 0); 236131733Salfred if (so == NULL) 237131733Salfred goto drop; 238116271Sphk 239116271Sphk /* 24040435Speter * This is ugly, but .... 24140435Speter * 24240435Speter * Mark socket as temporary until we're committed to keeping 24340435Speter * it. The code at ``drop'' and ``dropwithreset'' check the 24440435Speter * flag dropsocket to see if the temporary socket created 2451541Srgrimes * here should be discarded. We mark the socket as 2462946Swollman * discardable until we're committed to it below in 24740435Speter * TCPS_LISTEN. 24896755Strhodes * 249141634Sphk * XXXRW: In the new world order of real kernel parallelism, 25041056Speter * temporarily allocating the socket when we're "not sure" 25140435Speter * seems like a bad idea, as we might race to remove it if 252132710Sphk * the listen socket is closed...? 25340435Speter * 25440435Speter * We drop the lock of the listen socket ipxp, and acquire 25540435Speter * the lock of the new socket ippx. 25640435Speter */ 257132710Sphk dropsocket++; 25840435Speter IPX_UNLOCK(ipxp); 25940435Speter ipxp = (struct ipxpcb *)so->so_pcb; 26040435Speter IPX_LOCK(ipxp); 26140435Speter ipxp->ipxp_laddr = si->si_dna; 26240435Speter cb = ipxtospxpcb(ipxp); 26340435Speter cb->s_mtu = ocb->s_mtu; /* preserve sockopts */ 26440435Speter cb->s_flags = ocb->s_flags; /* preserve sockopts */ 26540435Speter cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ 26640435Speter cb->s_state = TCPS_LISTEN; 267132710Sphk } 26840435Speter IPX_LOCK_ASSERT(ipxp); 269132710Sphk 27040435Speter /* 27140435Speter * Packet received on connection. Reset idle time and keep-alive 27240435Speter * timer. 27340435Speter */ 27440435Speter cb->s_idle = 0; 27541056Speter cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 27691690Seivind 27796755Strhodes switch (cb->s_state) { 27891690Seivind case TCPS_LISTEN:{ 27991690Seivind struct sockaddr_ipx *sipx, ssipx; 28041056Speter struct ipx_addr laddr; 28141170Sbde 28241056Speter /* 28341056Speter * If somebody here was carying on a conversation and went 28441056Speter * away, and his pen pal thinks he can still talk, we get the 28541056Speter * misdirected packet. 28641056Speter */ 28741056Speter if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 28841056Speter spx_istat.gonawy++; 28941056Speter goto dropwithreset; 29041056Speter } 29141056Speter sipx = &ssipx; 29241056Speter bzero(sipx, sizeof *sipx); 29341056Speter sipx->sipx_len = sizeof(*sipx); 29441056Speter sipx->sipx_family = AF_IPX; 29541056Speter sipx->sipx_addr = si->si_sna; 29641056Speter laddr = ipxp->ipxp_laddr; 29741056Speter if (ipx_nullhost(laddr)) 298132199Sphk ipxp->ipxp_laddr = si->si_dna; 299132199Sphk if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &thread0)) { 30041056Speter ipxp->ipxp_laddr = laddr; 30141056Speter spx_istat.noconn++; 30241056Speter goto drop; 30341056Speter } 304 spx_template(cb); 305 dropsocket = 0; /* committed to socket */ 306 cb->s_did = si->si_sid; 307 cb->s_rack = si->si_ack; 308 cb->s_ralo = si->si_alo; 309#define THREEWAYSHAKE 310#ifdef THREEWAYSHAKE 311 cb->s_state = TCPS_SYN_RECEIVED; 312 cb->s_force = 1 + SPXT_KEEP; 313 spxstat.spxs_accepts++; 314 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 315 } 316 break; 317 318 case TCPS_SYN_RECEIVED: { 319 /* 320 * This state means that we have heard a response to our 321 * acceptance of their connection. It is probably logically 322 * unnecessary in this implementation. 323 */ 324 if (si->si_did != cb->s_sid) { 325 spx_istat.wrncon++; 326 goto drop; 327 } 328#endif 329 ipxp->ipxp_fport = si->si_sport; 330 cb->s_timer[SPXT_REXMT] = 0; 331 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 332 soisconnected(so); 333 cb->s_state = TCPS_ESTABLISHED; 334 spxstat.spxs_accepts++; 335 } 336 break; 337 338 case TCPS_SYN_SENT: 339 /* 340 * This state means that we have gotten a response to our 341 * attempt to establish a connection. We fill in the data 342 * from the other side, telling us which port to respond to, 343 * instead of the well-known one we might have sent to in the 344 * first place. We also require that this is a response to 345 * our connection id. 346 */ 347 if (si->si_did != cb->s_sid) { 348 spx_istat.notme++; 349 goto drop; 350 } 351 spxstat.spxs_connects++; 352 cb->s_did = si->si_sid; 353 cb->s_rack = si->si_ack; 354 cb->s_ralo = si->si_alo; 355 cb->s_dport = ipxp->ipxp_fport = si->si_sport; 356 cb->s_timer[SPXT_REXMT] = 0; 357 cb->s_flags |= SF_ACKNOW; 358 soisconnected(so); 359 cb->s_state = TCPS_ESTABLISHED; 360 361 /* 362 * Use roundtrip time of connection request for initial rtt. 363 */ 364 if (cb->s_rtt) { 365 cb->s_srtt = cb->s_rtt << 3; 366 cb->s_rttvar = cb->s_rtt << 1; 367 SPXT_RANGESET(cb->s_rxtcur, 368 ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1, 369 SPXTV_MIN, SPXTV_REXMTMAX); 370 cb->s_rtt = 0; 371 } 372 } 373 374 if (so->so_options & SO_DEBUG || traceallspxs) 375 spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0); 376 377 m->m_len -= sizeof(struct ipx); 378 m->m_pkthdr.len -= sizeof(struct ipx); 379 m->m_data += sizeof(struct ipx); 380 381 if (spx_reass(cb, si)) 382 m_freem(m); 383 if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT))) 384 spx_output(cb, NULL); 385 cb->s_flags &= ~(SF_WIN|SF_RXT); 386 IPX_UNLOCK(ipxp); 387 IPX_LIST_UNLOCK(); 388 return; 389 390dropwithreset: 391 IPX_LOCK_ASSERT(ipxp); 392 if (cb == NULL || (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || 393 traceallspxs)) 394 spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 395 IPX_UNLOCK(ipxp); 396 if (dropsocket) { 397 struct socket *head; 398 ACCEPT_LOCK(); 399 KASSERT((so->so_qstate & SQ_INCOMP) != 0, 400 ("spx_input: nascent socket not SQ_INCOMP on soabort()")); 401 head = so->so_head; 402 TAILQ_REMOVE(&head->so_incomp, so, so_list); 403 head->so_incqlen--; 404 so->so_qstate &= ~SQ_INCOMP; 405 so->so_head = NULL; 406 ACCEPT_UNLOCK(); 407 soabort(so); 408 } 409 IPX_LIST_UNLOCK(); 410 m_freem(m); 411 return; 412 413drop: 414 IPX_LOCK_ASSERT(ipxp); 415 if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs) 416 spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); 417 IPX_UNLOCK(ipxp); 418 IPX_LIST_UNLOCK(); 419 m_freem(m); 420} 421 422void 423spx_ctlinput(int cmd, struct sockaddr *arg_as_sa, void *dummy) 424{ 425 426 /* Currently, nothing. */ 427} 428 429int 430spx_output(struct spxpcb *cb, struct mbuf *m0) 431{ 432 struct socket *so = cb->s_ipxpcb->ipxp_socket; 433 struct mbuf *m = NULL; 434 struct spx *si = NULL; 435 struct sockbuf *sb = &so->so_snd; 436 int len = 0, win, rcv_win; 437 short span, off, recordp = 0; 438 u_short alo; 439 int error = 0, sendalot; 440#ifdef notdef 441 int idle; 442#endif 443 struct mbuf *mprev; 444 445 IPX_LOCK_ASSERT(cb->s_ipxpcb); 446 447 if (m0 != NULL) { 448 int mtu = cb->s_mtu; 449 int datalen; 450 451 /* 452 * Make sure that packet isn't too big. 453 */ 454 for (m = m0; m != NULL; m = m->m_next) { 455 mprev = m; 456 len += m->m_len; 457 if (m->m_flags & M_EOR) 458 recordp = 1; 459 } 460 datalen = (cb->s_flags & SF_HO) ? 461 len - sizeof(struct spxhdr) : len; 462 if (datalen > mtu) { 463 if (cb->s_flags & SF_PI) { 464 m_freem(m0); 465 return (EMSGSIZE); 466 } else { 467 int oldEM = cb->s_cc & SPX_EM; 468 469 cb->s_cc &= ~SPX_EM; 470 while (len > mtu) { 471 m = m_copym(m0, 0, mtu, M_DONTWAIT); 472 if (m == NULL) { 473 cb->s_cc |= oldEM; 474 m_freem(m0); 475 return (ENOBUFS); 476 } 477 if (cb->s_flags & SF_NEWCALL) { 478 struct mbuf *mm = m; 479 spx_newchecks[7]++; 480 while (mm != NULL) { 481 mm->m_flags &= ~M_EOR; 482 mm = mm->m_next; 483 } 484 } 485 error = spx_output(cb, m); 486 if (error) { 487 cb->s_cc |= oldEM; 488 m_freem(m0); 489 return (error); 490 } 491 m_adj(m0, mtu); 492 len -= mtu; 493 } 494 cb->s_cc |= oldEM; 495 } 496 } 497 498 /* 499 * Force length even, by adding a "garbage byte" if 500 * necessary. 501 */ 502 if (len & 1) { 503 m = mprev; 504 if (M_TRAILINGSPACE(m) >= 1) 505 m->m_len++; 506 else { 507 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 508 509 if (m1 == NULL) { 510 m_freem(m0); 511 return (ENOBUFS); 512 } 513 m1->m_len = 1; 514 *(mtod(m1, u_char *)) = 0; 515 m->m_next = m1; 516 } 517 } 518 m = m_gethdr(M_DONTWAIT, MT_DATA); 519 if (m == NULL) { 520 m_freem(m0); 521 return (ENOBUFS); 522 } 523 524 /* 525 * Fill in mbuf with extended SP header and addresses and 526 * length put into network format. 527 */ 528 MH_ALIGN(m, sizeof(struct spx)); 529 m->m_len = sizeof(struct spx); 530 m->m_next = m0; 531 si = mtod(m, struct spx *); 532 si->si_i = cb->s_ipx; 533 si->si_s = cb->s_shdr; 534 if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 535 struct spxhdr *sh; 536 if (m0->m_len < sizeof(*sh)) { 537 if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 538 m_free(m); 539 m_freem(m0); 540 return (EINVAL); 541 } 542 m->m_next = m0; 543 } 544 sh = mtod(m0, struct spxhdr *); 545 si->si_dt = sh->spx_dt; 546 si->si_cc |= sh->spx_cc & SPX_EM; 547 m0->m_len -= sizeof(*sh); 548 m0->m_data += sizeof(*sh); 549 len -= sizeof(*sh); 550 } 551 len += sizeof(*si); 552 if ((cb->s_flags2 & SF_NEWCALL) && recordp) { 553 si->si_cc |= SPX_EM; 554 spx_newchecks[8]++; 555 } 556 if (cb->s_oobflags & SF_SOOB) { 557 /* 558 * Per jqj@cornell: Make sure OB packets convey 559 * exactly 1 byte. If the packet is 1 byte or 560 * larger, we have already guaranted there to be at 561 * least one garbage byte for the checksum, and extra 562 * bytes shouldn't hurt! 563 */ 564 if (len > sizeof(*si)) { 565 si->si_cc |= SPX_OB; 566 len = (1 + sizeof(*si)); 567 } 568 } 569 si->si_len = htons((u_short)len); 570 m->m_pkthdr.len = ((len - 1) | 1) + 1; 571 572 /* 573 * Queue stuff up for output. 574 */ 575 sbappendrecord(sb, m); 576 cb->s_seq++; 577 } 578#ifdef notdef 579 idle = (cb->s_smax == (cb->s_rack - 1)); 580#endif 581again: 582 sendalot = 0; 583 off = cb->s_snxt - cb->s_rack; 584 win = min(cb->s_swnd, (cb->s_cwnd / CUNIT)); 585 586 /* 587 * If in persist timeout with window of 0, send a probe. Otherwise, 588 * if window is small but non-zero and timer expired, send what we 589 * can and go into transmit state. 590 */ 591 if (cb->s_force == 1 + SPXT_PERSIST) { 592 if (win != 0) { 593 cb->s_timer[SPXT_PERSIST] = 0; 594 cb->s_rxtshift = 0; 595 } 596 } 597 span = cb->s_seq - cb->s_rack; 598 len = min(span, win) - off; 599 600 if (len < 0) { 601 /* 602 * Window shrank after we went into it. If window shrank to 603 * 0, cancel pending restransmission and pull s_snxt back to 604 * (closed) window. We will enter persist state below. If 605 * the widndow didn't close completely, just wait for an ACK. 606 */ 607 len = 0; 608 if (win == 0) { 609 cb->s_timer[SPXT_REXMT] = 0; 610 cb->s_snxt = cb->s_rack; 611 } 612 } 613 if (len > 1) 614 sendalot = 1; 615 rcv_win = sbspace(&so->so_rcv); 616 617 /* 618 * Send if we owe peer an ACK. 619 */ 620 if (cb->s_oobflags & SF_SOOB) { 621 /* 622 * Must transmit this out of band packet. 623 */ 624 cb->s_oobflags &= ~ SF_SOOB; 625 sendalot = 1; 626 spxstat.spxs_sndurg++; 627 goto found; 628 } 629 if (cb->s_flags & SF_ACKNOW) 630 goto send; 631 if (cb->s_state < TCPS_ESTABLISHED) 632 goto send; 633 634 /* 635 * Silly window can't happen in spx. Code from TCP deleted. 636 */ 637 if (len) 638 goto send; 639 640 /* 641 * Compare available window to amount of window known to peer (as 642 * advertised window less next expected input.) If the difference is 643 * at least two packets or at least 35% of the mximum possible 644 * window, then want to send a window update to peer. 645 */ 646 if (rcv_win > 0) { 647 u_short delta = 1 + cb->s_alo - cb->s_ack; 648 int adv = rcv_win - (delta * cb->s_mtu); 649 650 if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) || 651 (100 * adv / so->so_rcv.sb_hiwat >= 35)) { 652 spxstat.spxs_sndwinup++; 653 cb->s_flags |= SF_ACKNOW; 654 goto send; 655 } 656 657 } 658 659 /* 660 * Many comments from tcp_output.c are appropriate here including ... 661 * If send window is too small, there is data to transmit, and no 662 * retransmit or persist is pending, then go to persist state. If 663 * nothing happens soon, send when timer expires: if window is 664 * non-zero, transmit what we can, otherwise send a probe. 665 */ 666 if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 && 667 cb->s_timer[SPXT_PERSIST] == 0) { 668 cb->s_rxtshift = 0; 669 spx_setpersist(cb); 670 } 671 672 /* 673 * No reason to send a packet, just return. 674 */ 675 cb->s_outx = 1; 676 return (0); 677 678send: 679 /* 680 * Find requested packet. 681 */ 682 si = NULL; 683 m = NULL; 684 if (len > 0) { 685 cb->s_want = cb->s_snxt; 686 for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt) { 687 si = mtod(m, struct spx *); 688 if (SSEQ_LEQ(cb->s_snxt, si->si_seq)) 689 break; 690 } 691 found: 692 if (si != NULL) { 693 if (si->si_seq != cb->s_snxt) { 694 spxstat.spxs_sndvoid++; 695 si = NULL; 696 m = NULL; 697 } else 698 cb->s_snxt++; 699 } 700 } 701 702 /* 703 * Update window. 704 */ 705 if (rcv_win < 0) 706 rcv_win = 0; 707 alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu)); 708 if (SSEQ_LT(alo, cb->s_alo)) 709 alo = cb->s_alo; 710 711 if (m != NULL) { 712 /* 713 * Must make a copy of this packet for ipx_output to monkey 714 * with. 715 */ 716 m = m_copy(m, 0, M_COPYALL); 717 if (m == NULL) 718 return (ENOBUFS); 719 si = mtod(m, struct spx *); 720 if (SSEQ_LT(si->si_seq, cb->s_smax)) 721 spxstat.spxs_sndrexmitpack++; 722 else 723 spxstat.spxs_sndpack++; 724 } else if (cb->s_force || cb->s_flags & SF_ACKNOW) { 725 /* 726 * Must send an acknowledgement or a probe. 727 */ 728 if (cb->s_force) 729 spxstat.spxs_sndprobe++; 730 if (cb->s_flags & SF_ACKNOW) 731 spxstat.spxs_sndacks++; 732 m = m_gethdr(M_DONTWAIT, MT_DATA); 733 if (m == NULL) 734 return (ENOBUFS); 735 736 /* 737 * Fill in mbuf with extended SP header and addresses and 738 * length put into network format. 739 */ 740 MH_ALIGN(m, sizeof(struct spx)); 741 m->m_len = sizeof(*si); 742 m->m_pkthdr.len = sizeof(*si); 743 si = mtod(m, struct spx *); 744 si->si_i = cb->s_ipx; 745 si->si_s = cb->s_shdr; 746 si->si_seq = cb->s_smax + 1; 747 si->si_len = htons(sizeof(*si)); 748 si->si_cc |= SPX_SP; 749 } else { 750 cb->s_outx = 3; 751 if (so->so_options & SO_DEBUG || traceallspxs) 752 spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 753 return (0); 754 } 755 756 /* 757 * Stuff checksum and output datagram. 758 */ 759 if ((si->si_cc & SPX_SP) == 0) { 760 if (cb->s_force != (1 + SPXT_PERSIST) || 761 cb->s_timer[SPXT_PERSIST] == 0) { 762 /* 763 * If this is a new packet and we are not currently 764 * timing anything, time this one. 765 */ 766 if (SSEQ_LT(cb->s_smax, si->si_seq)) { 767 cb->s_smax = si->si_seq; 768 if (cb->s_rtt == 0) { 769 spxstat.spxs_segstimed++; 770 cb->s_rtseq = si->si_seq; 771 cb->s_rtt = 1; 772 } 773 } 774 775 /* 776 * Set rexmt timer if not currently set, initial 777 * value for retransmit timer is smoothed round-trip 778 * time + 2 * round-trip time variance. Initialize 779 * shift counter which is used for backoff of 780 * retransmit time. 781 */ 782 if (cb->s_timer[SPXT_REXMT] == 0 && 783 cb->s_snxt != cb->s_rack) { 784 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 785 if (cb->s_timer[SPXT_PERSIST]) { 786 cb->s_timer[SPXT_PERSIST] = 0; 787 cb->s_rxtshift = 0; 788 } 789 } 790 } else if (SSEQ_LT(cb->s_smax, si->si_seq)) 791 cb->s_smax = si->si_seq; 792 } else if (cb->s_state < TCPS_ESTABLISHED) { 793 if (cb->s_rtt == 0) 794 cb->s_rtt = 1; /* Time initial handshake */ 795 if (cb->s_timer[SPXT_REXMT] == 0) 796 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 797 } 798 799 /* 800 * Do not request acks when we ack their data packets or when we do a 801 * gratuitous window update. 802 */ 803 if (((si->si_cc & SPX_SP) == 0) || cb->s_force) 804 si->si_cc |= SPX_SA; 805 si->si_seq = htons(si->si_seq); 806 si->si_alo = htons(alo); 807 si->si_ack = htons(cb->s_ack); 808 809 if (ipxcksum) 810 si->si_sum = ipx_cksum(m, ntohs(si->si_len)); 811 else 812 si->si_sum = 0xffff; 813 814 cb->s_outx = 4; 815 if (so->so_options & SO_DEBUG || traceallspxs) 816 spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 817 818#ifdef MAC 819 mac_socket_create_mbuf(so, m); 820#endif 821 822 if (so->so_options & SO_DONTROUTE) 823 error = ipx_outputfl(m, NULL, IPX_ROUTETOIF); 824 else 825 error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0); 826 if (error) 827 return (error); 828 spxstat.spxs_sndtotal++; 829 830 /* 831 * Data sent (as far as we can tell). If this advertises a larger 832 * window than any other segment, then remember the size of the 833 * advertized window. Any pending ACK has now been sent. 834 */ 835 cb->s_force = 0; 836 cb->s_flags &= ~(SF_ACKNOW|SF_DELACK); 837 if (SSEQ_GT(alo, cb->s_alo)) 838 cb->s_alo = alo; 839 if (sendalot) 840 goto again; 841 cb->s_outx = 5; 842 return (0); 843} 844 845static int spx_do_persist_panics = 0; 846 847static void 848spx_setpersist(struct spxpcb *cb) 849{ 850 int t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 851 852 IPX_LOCK_ASSERT(cb->s_ipxpcb); 853 854 if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics) 855 panic("spx_output REXMT"); 856 857 /* 858 * Start/restart persistance timer. 859 */ 860 SPXT_RANGESET(cb->s_timer[SPXT_PERSIST], 861 t*spx_backoff[cb->s_rxtshift], 862 SPXTV_PERSMIN, SPXTV_PERSMAX); 863 if (cb->s_rxtshift < SPX_MAXRXTSHIFT) 864 cb->s_rxtshift++; 865} 866 867int 868spx_ctloutput(struct socket *so, struct sockopt *sopt) 869{ 870 struct spxhdr spxhdr; 871 struct ipxpcb *ipxp; 872 struct spxpcb *cb; 873 int mask, error; 874 short soptval; 875 u_short usoptval; 876 int optval; 877 878 ipxp = sotoipxpcb(so); 879 KASSERT(ipxp != NULL, ("spx_ctloutput: ipxp == NULL")); 880 881 /* 882 * This will have to be changed when we do more general stacking of 883 * protocols. 884 */ 885 if (sopt->sopt_level != IPXPROTO_SPX) 886 return (ipx_ctloutput(so, sopt)); 887 888 IPX_LOCK(ipxp); 889 if (ipxp->ipxp_flags & IPXP_DROPPED) { 890 IPX_UNLOCK(ipxp); 891 return (ECONNRESET); 892 } 893 894 IPX_LOCK(ipxp); 895 cb = ipxtospxpcb(ipxp); 896 KASSERT(cb != NULL, ("spx_ctloutput: cb == NULL")); 897 898 error = 0; 899 switch (sopt->sopt_dir) { 900 case SOPT_GET: 901 switch (sopt->sopt_name) { 902 case SO_HEADERS_ON_INPUT: 903 mask = SF_HI; 904 goto get_flags; 905 906 case SO_HEADERS_ON_OUTPUT: 907 mask = SF_HO; 908 get_flags: 909 soptval = cb->s_flags & mask; 910 IPX_UNLOCK(ipxp); 911 error = sooptcopyout(sopt, &soptval, 912 sizeof(soptval)); 913 break; 914 915 case SO_MTU: 916 usoptval = cb->s_mtu; 917 IPX_UNLOCK(ipxp); 918 error = sooptcopyout(sopt, &usoptval, 919 sizeof(usoptval)); 920 break; 921 922 case SO_LAST_HEADER: 923 spxhdr = cb->s_rhdr; 924 IPX_UNLOCK(ipxp); 925 error = sooptcopyout(sopt, &spxhdr, sizeof(spxhdr)); 926 break; 927 928 case SO_DEFAULT_HEADERS: 929 spxhdr = cb->s_shdr; 930 IPX_UNLOCK(ipxp); 931 error = sooptcopyout(sopt, &spxhdr, sizeof(spxhdr)); 932 break; 933 934 default: 935 IPX_UNLOCK(ipxp); 936 error = ENOPROTOOPT; 937 } 938 break; 939 940 case SOPT_SET: 941 /* 942 * XXX Why are these shorts on get and ints on set? That 943 * doesn't make any sense... 944 * 945 * XXXRW: Note, when we re-acquire the ipxp lock, we should 946 * re-check that it's not dropped. 947 */ 948 IPX_UNLOCK(ipxp); 949 switch (sopt->sopt_name) { 950 case SO_HEADERS_ON_INPUT: 951 mask = SF_HI; 952 goto set_head; 953 954 case SO_HEADERS_ON_OUTPUT: 955 mask = SF_HO; 956 set_head: 957 error = sooptcopyin(sopt, &optval, sizeof optval, 958 sizeof optval); 959 if (error) 960 break; 961 962 IPX_LOCK(ipxp); 963 if (cb->s_flags & SF_PI) { 964 if (optval) 965 cb->s_flags |= mask; 966 else 967 cb->s_flags &= ~mask; 968 } else error = EINVAL; 969 IPX_UNLOCK(ipxp); 970 break; 971 972 case SO_MTU: 973 error = sooptcopyin(sopt, &usoptval, sizeof usoptval, 974 sizeof usoptval); 975 if (error) 976 break; 977 /* Unlocked write. */ 978 cb->s_mtu = usoptval; 979 break; 980 981#ifdef SF_NEWCALL 982 case SO_NEWCALL: 983 error = sooptcopyin(sopt, &optval, sizeof optval, 984 sizeof optval); 985 if (error) 986 break; 987 IPX_LOCK(ipxp); 988 if (optval) { 989 cb->s_flags2 |= SF_NEWCALL; 990 spx_newchecks[5]++; 991 } else { 992 cb->s_flags2 &= ~SF_NEWCALL; 993 spx_newchecks[6]++; 994 } 995 IPX_UNLOCK(ipxp); 996 break; 997#endif 998 999 case SO_DEFAULT_HEADERS: 1000 { 1001 struct spxhdr sp; 1002 1003 error = sooptcopyin(sopt, &sp, sizeof sp, 1004 sizeof sp); 1005 if (error) 1006 break; 1007 IPX_LOCK(ipxp); 1008 cb->s_dt = sp.spx_dt; 1009 cb->s_cc = sp.spx_cc & SPX_EM; 1010 IPX_UNLOCK(ipxp); 1011 } 1012 break; 1013 1014 default: 1015 error = ENOPROTOOPT; 1016 } 1017 break; 1018 1019 default: 1020 panic("spx_ctloutput: bad socket option direction"); 1021 } 1022 return (error); 1023} 1024 1025static void 1026spx_usr_abort(struct socket *so) 1027{ 1028 struct ipxpcb *ipxp; 1029 struct spxpcb *cb; 1030 1031 ipxp = sotoipxpcb(so); 1032 KASSERT(ipxp != NULL, ("spx_usr_abort: ipxp == NULL")); 1033 1034 cb = ipxtospxpcb(ipxp); 1035 KASSERT(cb != NULL, ("spx_usr_abort: cb == NULL")); 1036 1037 IPX_LIST_LOCK(); 1038 IPX_LOCK(ipxp); 1039 spx_drop(cb, ECONNABORTED); 1040 IPX_UNLOCK(ipxp); 1041 IPX_LIST_UNLOCK(); 1042} 1043 1044/* 1045 * Accept a connection. Essentially all the work is done at higher levels; 1046 * just return the address of the peer, storing through addr. 1047 */ 1048static int 1049spx_accept(struct socket *so, struct sockaddr **nam) 1050{ 1051 struct ipxpcb *ipxp; 1052 struct sockaddr_ipx *sipx, ssipx; 1053 1054 ipxp = sotoipxpcb(so); 1055 KASSERT(ipxp != NULL, ("spx_accept: ipxp == NULL")); 1056 1057 sipx = &ssipx; 1058 bzero(sipx, sizeof *sipx); 1059 sipx->sipx_len = sizeof *sipx; 1060 sipx->sipx_family = AF_IPX; 1061 IPX_LOCK(ipxp); 1062 sipx->sipx_addr = ipxp->ipxp_faddr; 1063 IPX_UNLOCK(ipxp); 1064 *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK); 1065 return (0); 1066} 1067 1068static int 1069spx_attach(struct socket *so, int proto, struct thread *td) 1070{ 1071 struct ipxpcb *ipxp; 1072 struct spxpcb *cb; 1073 struct mbuf *mm; 1074 struct sockbuf *sb; 1075 int error; 1076 1077 ipxp = sotoipxpcb(so); 1078 KASSERT(ipxp == NULL, ("spx_attach: ipxp != NULL")); 1079 1080 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 1081 error = soreserve(so, (u_long) 3072, (u_long) 3072); 1082 if (error) 1083 return (error); 1084 } 1085 1086 cb = malloc(sizeof *cb, M_PCB, M_NOWAIT | M_ZERO); 1087 if (cb == NULL) 1088 return (ENOBUFS); 1089 mm = m_getclr(M_DONTWAIT, MT_DATA); 1090 if (mm == NULL) { 1091 free(cb, M_PCB); 1092 return (ENOBUFS); 1093 } 1094 1095 IPX_LIST_LOCK(); 1096 error = ipx_pcballoc(so, &ipxpcb_list, td); 1097 if (error) { 1098 IPX_LIST_UNLOCK(); 1099 m_free(mm); 1100 free(cb, M_PCB); 1101 return (error); 1102 } 1103 ipxp = sotoipxpcb(so); 1104 ipxp->ipxp_flags |= IPXP_SPX; 1105 1106 cb->s_state = TCPS_LISTEN; 1107 cb->s_smax = -1; 1108 cb->s_swl1 = -1; 1109 spx_reass_init(cb); 1110 cb->s_ipxpcb = ipxp; 1111 cb->s_mtu = 576 - sizeof(struct spx); 1112 sb = &so->so_snd; 1113 cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; 1114 cb->s_ssthresh = cb->s_cwnd; 1115 cb->s_cwmx = sbspace(sb) * CUNIT / (2 * sizeof(struct spx)); 1116 1117 /* 1118 * Above is recomputed when connecting to account for changed 1119 * buffering or mtu's. 1120 */ 1121 cb->s_rtt = SPXTV_SRTTBASE; 1122 cb->s_rttvar = SPXTV_SRTTDFLT << 2; 1123 SPXT_RANGESET(cb->s_rxtcur, 1124 ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1, 1125 SPXTV_MIN, SPXTV_REXMTMAX); 1126 ipxp->ipxp_pcb = (caddr_t)cb; 1127 IPX_LIST_UNLOCK(); 1128 return (0); 1129} 1130 1131static void 1132spx_pcbdetach(struct ipxpcb *ipxp) 1133{ 1134 struct spxpcb *cb; 1135 1136 IPX_LOCK_ASSERT(ipxp); 1137 1138 cb = ipxtospxpcb(ipxp); 1139 KASSERT(cb != NULL, ("spx_pcbdetach: cb == NULL")); 1140 1141 spx_reass_flush(cb); 1142 free(cb, M_PCB); 1143 ipxp->ipxp_pcb = NULL; 1144} 1145 1146static int 1147spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 1148{ 1149 struct ipxpcb *ipxp; 1150 int error; 1151 1152 ipxp = sotoipxpcb(so); 1153 KASSERT(ipxp != NULL, ("spx_bind: ipxp == NULL")); 1154 1155 IPX_LIST_LOCK(); 1156 IPX_LOCK(ipxp); 1157 if (ipxp->ipxp_flags & IPXP_DROPPED) { 1158 error = EINVAL; 1159 goto out; 1160 } 1161 error = ipx_pcbbind(ipxp, nam, td); 1162out: 1163 IPX_UNLOCK(ipxp); 1164 IPX_LIST_UNLOCK(); 1165 return (error); 1166} 1167 1168static void 1169spx_usr_close(struct socket *so) 1170{ 1171 struct ipxpcb *ipxp; 1172 struct spxpcb *cb; 1173 1174 ipxp = sotoipxpcb(so); 1175 KASSERT(ipxp != NULL, ("spx_usr_close: ipxp == NULL")); 1176 1177 cb = ipxtospxpcb(ipxp); 1178 KASSERT(cb != NULL, ("spx_usr_close: cb == NULL")); 1179 1180 IPX_LIST_LOCK(); 1181 IPX_LOCK(ipxp); 1182 if (cb->s_state > TCPS_LISTEN) 1183 spx_disconnect(cb); 1184 else 1185 spx_close(cb); 1186 IPX_UNLOCK(ipxp); 1187 IPX_LIST_UNLOCK(); 1188} 1189 1190/* 1191 * Initiate connection to peer. Enter SYN_SENT state, and mark socket as 1192 * connecting. Start keep-alive timer, setup prototype header, send initial 1193 * system packet requesting connection. 1194 */ 1195static int 1196spx_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 1197{ 1198 struct ipxpcb *ipxp; 1199 struct spxpcb *cb; 1200 int error; 1201 1202 ipxp = sotoipxpcb(so); 1203 KASSERT(ipxp != NULL, ("spx_connect: ipxp == NULL")); 1204 1205 cb = ipxtospxpcb(ipxp); 1206 KASSERT(cb != NULL, ("spx_connect: cb == NULL")); 1207 1208 IPX_LIST_LOCK(); 1209 IPX_LOCK(ipxp); 1210 if (ipxp->ipxp_flags & IPXP_DROPPED) { 1211 error = EINVAL; 1212 goto spx_connect_end; 1213 } 1214 if (ipxp->ipxp_lport == 0) { 1215 error = ipx_pcbbind(ipxp, NULL, td); 1216 if (error) 1217 goto spx_connect_end; 1218 } 1219 error = ipx_pcbconnect(ipxp, nam, td); 1220 if (error) 1221 goto spx_connect_end; 1222 soisconnecting(so); 1223 spxstat.spxs_connattempt++; 1224 cb->s_state = TCPS_SYN_SENT; 1225 cb->s_did = 0; 1226 spx_template(cb); 1227 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 1228 cb->s_force = 1 + SPXTV_KEEP; 1229 1230 /* 1231 * Other party is required to respond to the port I send from, but he 1232 * is not required to answer from where I am sending to, so allow 1233 * wildcarding. Original port I am sending to is still saved in 1234 * cb->s_dport. 1235 */ 1236 ipxp->ipxp_fport = 0; 1237 error = spx_output(cb, NULL); 1238spx_connect_end: 1239 IPX_UNLOCK(ipxp); 1240 IPX_LIST_UNLOCK(); 1241 return (error); 1242} 1243 1244static void 1245spx_detach(struct socket *so) 1246{ 1247 struct ipxpcb *ipxp; 1248 struct spxpcb *cb; 1249 1250 /* 1251 * XXXRW: Should assert appropriately detached. 1252 */ 1253 ipxp = sotoipxpcb(so); 1254 KASSERT(ipxp != NULL, ("spx_detach: ipxp == NULL")); 1255 1256 cb = ipxtospxpcb(ipxp); 1257 KASSERT(cb != NULL, ("spx_detach: cb == NULL")); 1258 1259 IPX_LIST_LOCK(); 1260 IPX_LOCK(ipxp); 1261 spx_pcbdetach(ipxp); 1262 ipx_pcbdetach(ipxp); 1263 ipx_pcbfree(ipxp); 1264 IPX_LIST_UNLOCK(); 1265} 1266 1267/* 1268 * We may decide later to implement connection closing handshaking at the spx 1269 * level optionally. Here is the hook to do it: 1270 */ 1271static int 1272spx_usr_disconnect(struct socket *so) 1273{ 1274 struct ipxpcb *ipxp; 1275 struct spxpcb *cb; 1276 int error; 1277 1278 ipxp = sotoipxpcb(so); 1279 KASSERT(ipxp != NULL, ("spx_usr_disconnect: ipxp == NULL")); 1280 1281 cb = ipxtospxpcb(ipxp); 1282 KASSERT(cb != NULL, ("spx_usr_disconnect: cb == NULL")); 1283 1284 IPX_LIST_LOCK(); 1285 IPX_LOCK(ipxp); 1286 if (ipxp->ipxp_flags & IPXP_DROPPED) { 1287 error = EINVAL; 1288 goto out; 1289 } 1290 spx_disconnect(cb); 1291 error = 0; 1292out: 1293 IPX_UNLOCK(ipxp); 1294 IPX_LIST_UNLOCK(); 1295 return (error); 1296} 1297 1298static int 1299spx_listen(struct socket *so, int backlog, struct thread *td) 1300{ 1301 int error; 1302 struct ipxpcb *ipxp; 1303 struct spxpcb *cb; 1304 1305 error = 0; 1306 ipxp = sotoipxpcb(so); 1307 KASSERT(ipxp != NULL, ("spx_listen: ipxp == NULL")); 1308 1309 cb = ipxtospxpcb(ipxp); 1310 KASSERT(cb != NULL, ("spx_listen: cb == NULL")); 1311 1312 IPX_LIST_LOCK(); 1313 IPX_LOCK(ipxp); 1314 if (ipxp->ipxp_flags & IPXP_DROPPED) { 1315 error = EINVAL; 1316 goto out; 1317 } 1318 SOCK_LOCK(so); 1319 error = solisten_proto_check(so); 1320 if (error == 0 && ipxp->ipxp_lport == 0) 1321 error = ipx_pcbbind(ipxp, NULL, td); 1322 if (error == 0) { 1323 cb->s_state = TCPS_LISTEN; 1324 solisten_proto(so, backlog); 1325 } 1326 SOCK_UNLOCK(so); 1327out: 1328 IPX_UNLOCK(ipxp); 1329 IPX_LIST_UNLOCK(); 1330 return (error); 1331} 1332 1333/* 1334 * After a receive, possibly send acknowledgment updating allocation. 1335 */ 1336static int 1337spx_rcvd(struct socket *so, int flags) 1338{ 1339 struct ipxpcb *ipxp; 1340 struct spxpcb *cb; 1341 int error; 1342 1343 ipxp = sotoipxpcb(so); 1344 KASSERT(ipxp != NULL, ("spx_rcvd: ipxp == NULL")); 1345 1346 cb = ipxtospxpcb(ipxp); 1347 KASSERT(cb != NULL, ("spx_rcvd: cb == NULL")); 1348 1349 IPX_LOCK(ipxp); 1350 if (ipxp->ipxp_flags & IPXP_DROPPED) { 1351 error = EINVAL; 1352 goto out; 1353 } 1354 cb->s_flags |= SF_RVD; 1355 spx_output(cb, NULL); 1356 cb->s_flags &= ~SF_RVD; 1357 error = 0; 1358out: 1359 IPX_UNLOCK(ipxp); 1360 return (error); 1361} 1362 1363static int 1364spx_rcvoob(struct socket *so, struct mbuf *m, int flags) 1365{ 1366 struct ipxpcb *ipxp; 1367 struct spxpcb *cb; 1368 int error; 1369 1370 ipxp = sotoipxpcb(so); 1371 KASSERT(ipxp != NULL, ("spx_rcvoob: ipxp == NULL")); 1372 1373 cb = ipxtospxpcb(ipxp); 1374 KASSERT(cb != NULL, ("spx_rcvoob: cb == NULL")); 1375 1376 IPX_LOCK(ipxp); 1377 if (ipxp->ipxp_flags & IPXP_DROPPED) { 1378 error = EINVAL; 1379 goto out; 1380 } 1381 SOCKBUF_LOCK(&so->so_rcv); 1382 if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 1383 (so->so_rcv.sb_state & SBS_RCVATMARK)) { 1384 SOCKBUF_UNLOCK(&so->so_rcv); 1385 m->m_len = 1; 1386 *mtod(m, caddr_t) = cb->s_iobc; 1387 error = 0; 1388 goto out; 1389 } 1390 SOCKBUF_UNLOCK(&so->so_rcv); 1391 error = EINVAL; 1392out: 1393 IPX_UNLOCK(ipxp); 1394 return (error); 1395} 1396 1397static int 1398spx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 1399 struct mbuf *controlp, struct thread *td) 1400{ 1401 struct ipxpcb *ipxp; 1402 struct spxpcb *cb; 1403 int error; 1404 1405 ipxp = sotoipxpcb(so); 1406 KASSERT(ipxp != NULL, ("spx_send: ipxp == NULL")); 1407 1408 cb = ipxtospxpcb(ipxp); 1409 KASSERT(cb != NULL, ("spx_send: cb == NULL")); 1410 1411 error = 0; 1412 IPX_LOCK(ipxp); 1413 if (ipxp->ipxp_flags & IPXP_DROPPED) { 1414 error = ECONNRESET; 1415 goto spx_send_end; 1416 } 1417 if (flags & PRUS_OOB) { 1418 if (sbspace(&so->so_snd) < -512) { 1419 error = ENOBUFS; 1420 goto spx_send_end; 1421 } 1422 cb->s_oobflags |= SF_SOOB; 1423 } 1424 if (controlp != NULL) { 1425 u_short *p = mtod(controlp, u_short *); 1426 spx_newchecks[2]++; 1427 if ((p[0] == 5) && (p[1] == 1)) { /* XXXX, for testing */ 1428 cb->s_shdr.spx_dt = *(u_char *)(&p[2]); 1429 spx_newchecks[3]++; 1430 } 1431 m_freem(controlp); 1432 } 1433 controlp = NULL; 1434 error = spx_output(cb, m); 1435 m = NULL; 1436spx_send_end: 1437 IPX_UNLOCK(ipxp); 1438 if (controlp != NULL) 1439 m_freem(controlp); 1440 if (m != NULL) 1441 m_freem(m); 1442 return (error); 1443} 1444 1445static int 1446spx_shutdown(struct socket *so) 1447{ 1448 struct ipxpcb *ipxp; 1449 struct spxpcb *cb; 1450 int error; 1451 1452 ipxp = sotoipxpcb(so); 1453 KASSERT(ipxp != NULL, ("spx_shutdown: ipxp == NULL")); 1454 1455 cb = ipxtospxpcb(ipxp); 1456 KASSERT(cb != NULL, ("spx_shutdown: cb == NULL")); 1457 1458 socantsendmore(so); 1459 IPX_LIST_LOCK(); 1460 IPX_LOCK(ipxp); 1461 if (ipxp->ipxp_flags & IPXP_DROPPED) { 1462 error = EINVAL; 1463 goto out; 1464 } 1465 spx_usrclosed(cb); 1466 error = 0; 1467out: 1468 IPX_UNLOCK(ipxp); 1469 IPX_LIST_UNLOCK(); 1470 return (error); 1471} 1472 1473static int 1474spx_sp_attach(struct socket *so, int proto, struct thread *td) 1475{ 1476 struct ipxpcb *ipxp; 1477 struct spxpcb *cb; 1478 int error; 1479 1480 KASSERT(so->so_pcb == NULL, ("spx_sp_attach: so_pcb != NULL")); 1481 1482 error = spx_attach(so, proto, td); 1483 if (error) 1484 return (error); 1485 1486 ipxp = sotoipxpcb(so); 1487 KASSERT(ipxp != NULL, ("spx_sp_attach: ipxp == NULL")); 1488 1489 cb = ipxtospxpcb(ipxp); 1490 KASSERT(cb != NULL, ("spx_sp_attach: cb == NULL")); 1491 1492 IPX_LOCK(ipxp); 1493 cb->s_flags |= (SF_HI | SF_HO | SF_PI); 1494 IPX_UNLOCK(ipxp); 1495 return (0); 1496} 1497 1498/* 1499 * Create template to be used to send spx packets on a connection. Called 1500 * after host entry created, fills in a skeletal spx header (choosing 1501 * connection id), minimizing the amount of work necessary when the 1502 * connection is used. 1503 */ 1504static void 1505spx_template(struct spxpcb *cb) 1506{ 1507 struct ipxpcb *ipxp = cb->s_ipxpcb; 1508 struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd); 1509 1510 IPX_LOCK_ASSERT(ipxp); 1511 1512 cb->s_ipx.ipx_pt = IPXPROTO_SPX; 1513 cb->s_ipx.ipx_sna = ipxp->ipxp_laddr; 1514 cb->s_ipx.ipx_dna = ipxp->ipxp_faddr; 1515 SPX_LOCK(); 1516 cb->s_sid = htons(spx_iss); 1517 spx_iss += SPX_ISSINCR/2; 1518 SPX_UNLOCK(); 1519 cb->s_alo = 1; 1520 cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; 1521 1522 /* 1523 * Try to expand fast to full complement of large packets. 1524 */ 1525 cb->s_ssthresh = cb->s_cwnd; 1526 cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx)); 1527 1528 /* 1529 * But allow for lots of little packets as well. 1530 */ 1531 cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); 1532} 1533 1534/* 1535 * Close a SPIP control block. Wake up any sleepers. We used to free any 1536 * queued packets, but now we defer that until the pcb is discarded. 1537 */ 1538void 1539spx_close(struct spxpcb *cb) 1540{ 1541 struct ipxpcb *ipxp = cb->s_ipxpcb; 1542 struct socket *so = ipxp->ipxp_socket; 1543 1544 KASSERT(ipxp != NULL, ("spx_close: ipxp == NULL")); 1545 IPX_LIST_LOCK_ASSERT(); 1546 IPX_LOCK_ASSERT(ipxp); 1547 1548 ipxp->ipxp_flags |= IPXP_DROPPED; 1549 soisdisconnected(so); 1550 spxstat.spxs_closed++; 1551} 1552 1553/* 1554 * Someday we may do level 3 handshaking to close a connection or send a 1555 * xerox style error. For now, just close. cb will always be invalid after 1556 * this call. 1557 */ 1558static void 1559spx_usrclosed(struct spxpcb *cb) 1560{ 1561 1562 IPX_LIST_LOCK_ASSERT(); 1563 IPX_LOCK_ASSERT(cb->s_ipxpcb); 1564 1565 spx_close(cb); 1566} 1567 1568/* 1569 * cb will always be invalid after this call. 1570 */ 1571static void 1572spx_disconnect(struct spxpcb *cb) 1573{ 1574 1575 IPX_LIST_LOCK_ASSERT(); 1576 IPX_LOCK_ASSERT(cb->s_ipxpcb); 1577 1578 spx_close(cb); 1579} 1580 1581/* 1582 * Drop connection, reporting the specified error. cb will always be invalid 1583 * after this call. 1584 */ 1585static void 1586spx_drop(struct spxpcb *cb, int errno) 1587{ 1588 struct socket *so = cb->s_ipxpcb->ipxp_socket; 1589 1590 IPX_LIST_LOCK_ASSERT(); 1591 IPX_LOCK_ASSERT(cb->s_ipxpcb); 1592 1593 /* 1594 * Someday, in the xerox world we will generate error protocol 1595 * packets announcing that the socket has gone away. 1596 */ 1597 if (TCPS_HAVERCVDSYN(cb->s_state)) { 1598 spxstat.spxs_drops++; 1599 cb->s_state = TCPS_CLOSED; 1600 /*tcp_output(cb);*/ 1601 } else 1602 spxstat.spxs_conndrops++; 1603 so->so_error = errno; 1604 spx_close(cb); 1605} 1606 1607/* 1608 * Fast timeout routine for processing delayed acks. 1609 */ 1610void 1611spx_fasttimo(void) 1612{ 1613 struct ipxpcb *ipxp; 1614 struct spxpcb *cb; 1615 1616 IPX_LIST_LOCK(); 1617 LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 1618 IPX_LOCK(ipxp); 1619 if (!(ipxp->ipxp_flags & IPXP_SPX) || 1620 (ipxp->ipxp_flags & IPXP_DROPPED)) { 1621 IPX_UNLOCK(ipxp); 1622 continue; 1623 } 1624 cb = ipxtospxpcb(ipxp); 1625 if (cb->s_flags & SF_DELACK) { 1626 cb->s_flags &= ~SF_DELACK; 1627 cb->s_flags |= SF_ACKNOW; 1628 spxstat.spxs_delack++; 1629 spx_output(cb, NULL); 1630 } 1631 IPX_UNLOCK(ipxp); 1632 } 1633 IPX_LIST_UNLOCK(); 1634} 1635 1636/* 1637 * spx protocol timeout routine called every 500 ms. Updates the timers in 1638 * all active pcb's and causes finite state machine actions if timers expire. 1639 */ 1640void 1641spx_slowtimo(void) 1642{ 1643 struct ipxpcb *ipxp; 1644 struct spxpcb *cb; 1645 int i; 1646 1647 /* 1648 * Search through tcb's and update active timers. Once, timers could 1649 * free ipxp's, but now we do that only when detaching a socket. 1650 */ 1651 IPX_LIST_LOCK(); 1652 LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { 1653 IPX_LOCK(ipxp); 1654 if (!(ipxp->ipxp_flags & IPXP_SPX) || 1655 (ipxp->ipxp_flags & IPXP_DROPPED)) { 1656 IPX_UNLOCK(ipxp); 1657 continue; 1658 } 1659 1660 cb = (struct spxpcb *)ipxp->ipxp_pcb; 1661 KASSERT(cb != NULL, ("spx_slowtimo: cb == NULL")); 1662 for (i = 0; i < SPXT_NTIMERS; i++) { 1663 if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 1664 spx_timers(cb, i); 1665 if (ipxp->ipxp_flags & IPXP_DROPPED) 1666 break; 1667 } 1668 } 1669 if (!(ipxp->ipxp_flags & IPXP_DROPPED)) { 1670 cb->s_idle++; 1671 if (cb->s_rtt) 1672 cb->s_rtt++; 1673 } 1674 IPX_UNLOCK(ipxp); 1675 } 1676 IPX_LIST_UNLOCK(); 1677 SPX_LOCK(); 1678 spx_iss += SPX_ISSINCR/PR_SLOWHZ; /* increment iss */ 1679 SPX_UNLOCK(); 1680} 1681 1682/* 1683 * SPX timer processing. 1684 */ 1685static void 1686spx_timers(struct spxpcb *cb, int timer) 1687{ 1688 long rexmt; 1689 int win; 1690 1691 IPX_LIST_LOCK_ASSERT(); 1692 IPX_LOCK_ASSERT(cb->s_ipxpcb); 1693 1694 cb->s_force = 1 + timer; 1695 switch (timer) { 1696 case SPXT_2MSL: 1697 /* 1698 * 2 MSL timeout in shutdown went off. TCP deletes 1699 * connection control block. 1700 */ 1701 printf("spx: SPXT_2MSL went off for no reason\n"); 1702 cb->s_timer[timer] = 0; 1703 break; 1704 1705 case SPXT_REXMT: 1706 /* 1707 * Retransmission timer went off. Message has not been acked 1708 * within retransmit interval. Back off to a longer 1709 * retransmit interval and retransmit one packet. 1710 */ 1711 if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) { 1712 cb->s_rxtshift = SPX_MAXRXTSHIFT; 1713 spxstat.spxs_timeoutdrop++; 1714 spx_drop(cb, ETIMEDOUT); 1715 break; 1716 } 1717 spxstat.spxs_rexmttimeo++; 1718 rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; 1719 rexmt *= spx_backoff[cb->s_rxtshift]; 1720 SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX); 1721 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur; 1722 1723 /* 1724 * If we have backed off fairly far, our srtt estimate is 1725 * probably bogus. Clobber it so we'll take the next rtt 1726 * measurement as our srtt; move the current srtt into rttvar 1727 * to keep the current retransmit times until then. 1728 */ 1729 if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) { 1730 cb->s_rttvar += (cb->s_srtt >> 2); 1731 cb->s_srtt = 0; 1732 } 1733 cb->s_snxt = cb->s_rack; 1734 1735 /* 1736 * If timing a packet, stop the timer. 1737 */ 1738 cb->s_rtt = 0; 1739 1740 /* 1741 * See very long discussion in tcp_timer.c about congestion 1742 * window and sstrhesh. 1743 */ 1744 win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; 1745 if (win < 2) 1746 win = 2; 1747 cb->s_cwnd = CUNIT; 1748 cb->s_ssthresh = win * CUNIT; 1749 spx_output(cb, NULL); 1750 break; 1751 1752 case SPXT_PERSIST: 1753 /* 1754 * Persistance timer into zero window. Force a probe to be 1755 * sent. 1756 */ 1757 spxstat.spxs_persisttimeo++; 1758 spx_setpersist(cb); 1759 spx_output(cb, NULL); 1760 break; 1761 1762 case SPXT_KEEP: 1763 /* 1764 * Keep-alive timer went off; send something or drop 1765 * connection if idle for too long. 1766 */ 1767 spxstat.spxs_keeptimeo++; 1768 if (cb->s_state < TCPS_ESTABLISHED) 1769 goto dropit; 1770 if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) { 1771 if (cb->s_idle >= SPXTV_MAXIDLE) 1772 goto dropit; 1773 spxstat.spxs_keepprobe++; 1774 spx_output(cb, NULL); 1775 } else 1776 cb->s_idle = 0; 1777 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; 1778 break; 1779 1780 dropit: 1781 spxstat.spxs_keepdrops++; 1782 spx_drop(cb, ETIMEDOUT); 1783 break; 1784 1785 default: 1786 panic("spx_timers: unknown timer %d", timer); 1787 } 1788} 1789