/* $Id$ */
/** @file
* NAT - TCP support.
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*
* This code is based on:
*
* Copyright (c) 1982, 1986, 1988, 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93
* tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
*/
/*
* Changes and additions relating to SLiRP
* Copyright (c) 1995 Danny Gasparovski.
*
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
#include <slirp.h>
/*
* Tcp initialization
*/
void
{
tcp_last_so = &tcb;
tcp_reass_maxqlen = 48;
tcp_reass_maxseg = 256;
}
/*
* Create template to be used to send tcp packets on a connection.
* Call after host entry created, fills
* necessary when the connection is used.
*/
/* struct tcpiphdr * */
void
{
n->ti_pr = IPPROTO_TCP;
n->ti_seq = 0;
n->ti_ack = 0;
n->ti_x2 = 0;
n->ti_off = 5;
n->ti_flags = 0;
n->ti_win = 0;
n->ti_sum = 0;
n->ti_urp = 0;
}
/*
* Send a single message to the TCP at address specified by
* of the tcpiphdr at ti and send directly to the addressed host.
* This is used to force keep alive messages out using the TCP
* template for a connection tp->t_template. If flags are given
* then we send a message back to the TCP which originated the
* segment ti, and discard the mbuf containing it and any other
* attached mbufs.
*
* In any case the ack and sequence number of the transmitted
* segment are as specified by the parameters.
*/
void
tcp_respond(PNATState pData, struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, tcp_seq ack, tcp_seq seq, int flags)
{
register int tlen;
LogFlowFunc(("ENTER: tp = %R[tcpcb793], ti = %lx, m = %lx, ack = %u, seq = %u, flags = %x\n",
if (m == 0)
{
return;
#ifdef TCP_COMPAT_42
tlen = 1;
#else
tlen = 0;
#endif
m->m_data += if_maxlinkhdr;
}
else
{
/*
* ti points into m so the next line is just making
* the mbuf point to ti
*/
tlen = 0;
}
if (tp)
{
}
else
else
}
/*
* Create a new TCP control block, making an
* empty reassembly queue and hooking it to the argument
* protocol control block.
*/
struct tcpcb *
{
return ((struct tcpcb *)0);
/*
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
* rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
* reasonable initial retransmit time.
*/
return (tp);
}
/*
* Drop a TCP connection, reporting
* the specified error. If connection is synchronized,
* then send a RST to peer.
*/
{
/* tcp_drop(tp, errno)
register struct tcpcb *tp;
int errno;
{
*/
int fUninitiolizedTemplate = 0;
#ifndef LOG_ENABLED
#endif
{
}
else
#if 0
#endif
}
/*
* Close a TCP control block:
* discard all space held by the tcp
* discard internet protocol block
* wake up any sleepers
*/
struct tcpcb *
{
/*XXX: freeing the reassembly queue */
{
}
/* clobber input socket cache if we're closing the cached connection */
if (so == tcp_last_so)
tcp_last_so = &tcb;
if (so->s != -1)
closesocket(so->s);
/* Avoid double free if the socket is listening and therefore doesn't have
* any sbufs reserved. */
{
}
return ((struct tcpcb *)0);
}
void
{
/* XXX */
}
/*
* When a source quench is received, close congestion window
* to one segment. We will gradually open it again as we proceed.
*/
#if 0
void
tcp_quench(i, int errno)
{
if (tp)
}
#endif
/*
* TCP protocol interface to socket abstraction.
*/
/*
* User issued close, and wish to trail through shutdown states:
* if never received SYN, just forget it. If got a SYN from peer,
* but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
* If already got a FIN from peer, then almost done; go to LAST_ACK
* state. In all other cases, have already sent FIN to peer (e.g.
* after PRU_SHUTDOWN), and just have to play tedious game waiting
* for peer to send FIN or not respond to keep-alives, etc.
* We can let the user exit from the close as soon as the FIN is acked.
*/
void
{
{
case TCPS_CLOSED:
case TCPS_LISTEN:
case TCPS_SYN_SENT:
break;
case TCPS_SYN_RECEIVED:
case TCPS_ESTABLISHED:
break;
case TCPS_CLOSE_WAIT:
break;
}
/* soisfdisconnecting(tp->t_socket); */
if ( tp
/*
* (vasily) there're situations when the FIN or FIN,ACK are lost (Windows host)
* and retransmitting keeps VBox busy on sending closing sequences *very* frequent,
* easting a lot of CPU. To avoid this we don't sent on sockets marked as closed
* (see slirp.c for details about setting so_close member).
*/
if ( tp
}
/*
* Connect to a host on the Internet
* Called by tcp_input
* Only do a connect, the tcp fields will be set in tcp_input
* return 0 if there's a result of the connect,
* else return -1 means we're still connecting
* The return value is almost always -1 since the socket is
* nonblocking. Connect returns after the SYN is sent, and does
* not wait for ACK+SYN.
*/
{
int ret = 0;
{
fd_nonblock(s);
opt = 1;
opt = 1;
{
/* It's an alias */
{
case CTL_DNS:
case CTL_ALIAS:
default:
break;
}
}
else
Log2((" connect()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n",
/* We don't care what port we get */
/*
* If it's not in progress, it failed, so we just return 0,
* without clearing SS_NOFDREF
*/
}
return(ret);
}
/*
* Accept the socket and connect to the local-host
*
* We have a problem. The correct thing to do would be
* to first connect to the local-host, and only if the
* connection is accepted, then do an accept() here.
* But, a) we need to know who's trying to connect
* to the socket to be able to SYN the local-host, and
* b) we are already connected to the foreign host by
* the time it gets to accept(), so... We simply accept
* here and SYN the local-host.
*/
void
{
int s, opt;
int status;
/*
* If it's an SS_ACCEPTONCE socket, no need to socreate()
* another socket, just use the accept() socket.
*/
{
/* FACCEPTONCE already have a tcpcb */
}
else
{
{
/* If it failed, get rid of the pending connection */
return;
}
{
return;
}
}
fd_nonblock(inso->s);
{
return;
}
fd_nonblock(s);
opt = 1;
opt = 1;
#if 0
opt = 1;
#endif
optlen = sizeof(int);
if (status < 0)
{
goto no_sockopt;
}
if (cVerbose > 0)
/* @todo (r-vvl) make it configurable (via extra data) */
if (status < 0)
{
goto no_sockopt;
}
optlen = sizeof(int);
if (status < 0)
{
goto no_sockopt;
}
if (cVerbose > 0)
if (status < 0)
{
goto no_sockopt;
}
if (cVerbose > 0)
cVerbose--;
/* Translate connections from localhost to the real hostname */
/* Close the accept() socket, set right state */
{
/* if it's not FACCEPTONCE, it's already NOFDREF */
}
so->s = s;
/* Compute window scaling to request. */
/* while (tp->request_r_scale < TCP_MAX_WINSHIFT
* && (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
* tp->request_r_scale++;
*/
/* soisconnecting(so); */ /* NOFDREF used instead */
}
/*
* Attach a TCPCB to a socket.
*/
int
{
/* We're attaching already attached socket??? */
return -1;
NSOCK_INC();
return 0;
}