tcp_subr.c revision 3d061451ecc0fa7baa94211f5038ee56a60ebc0f
/*
* 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.
*/
#define WANT_SYS_IOCTL_H
#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;
int win = 0;
DEBUG_CALL("tcp_respond");
DEBUG_ARG("m = %lx", (long)m);
if (tp)
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;
{
*/
DEBUG_CALL("tcp_drop");
{
}
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 *
{
register struct tcpiphdr *t;
register struct mbuf *m;
DEBUG_CALL("tcp_close");
/*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;
closesocket(so->s);
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
{
DEBUG_CALL("tcp_sockclosed");
{
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
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;
DEBUG_CALL("tcp_fconnect");
{
struct sockaddr_in addr;
fd_nonblock(s);
opt = 1;
opt = 1;
{
/* It's an alias */
{
case CTL_DNS:
else
break;
case CTL_ALIAS:
default:
break;
}
}
else
"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
{
struct sockaddr_in addr;
int s, opt;
DEBUG_CALL("tcp_connect");
/*
* 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;
}
}
{
return;
}
fd_nonblock(s);
opt = 1;
opt = 1;
opt = 1;
/* 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
{
return -1;
return 0;
}
/*
* Set the socket's type of service field
*/
{
{0, 0, 0, 0}
};
/*
* Return TOS according to the above table
*/
{
int i = 0;
{
{
}
i++;
}
return 0;
}
/*
* Emulate programs that try and connect to us. This includes ftp (the data
* connection is initiated by the server) and IRC (DCC CHAT and DCC SEND)
* for now
*
* NOTE: It's possible to crash SLiRP by sending it unstandard strings to
* emulate... if this is a problem, more checks are needed here.
*
* XXX Assumes the whole command cames in one packet
*
* XXX Some ftp clients will have their TOS set to LOWDELAY and so Nagel will
* kick in. Because of this, we'll get the first letter, followed by the
* rest, so we simply scan for ORT instead of PORT... DCC doesn't have this
* problem because there's other stuff in the packet before the DCC command.
*
* Return 1 if the mbuf m is still valid and should be sbappend()ed
*
* NOTE: if you return 0 you MUST m_free() the mbuf!
*/
int
{
char buff[256];
char *bptr;
DEBUG_CALL("tcp_emu");
DEBUG_ARG("m = %lx", (long)m);
{
int x, i;
case EMU_IDENT:
/*
* Identification protocol as per rfc-1413
*/
{
struct sockaddr_in addr;
{
{
/* n2 is the one on our host */
{
{
if (getsockname(tmpso->s,
break;
}
}
}
}
return 0;
}
case EMU_FTP:
{
/*
* Need to emulate the PORT command
*/
if (x < 6)
return 1;
return 1;
n6 &= 0xff;
return 1;
}
{
/*
* Need to emulate the PASV response
*/
if (x < 6)
return 1;
return 1;
n6 &= 0xff;
return 1;
}
return 1;
case EMU_KSH:
/*
* The kshell (Kerberos rsh) and shell services both pass
* a local port port number to carry signals to the server
* and stderr to the client. It is passed at the beginning
* of the connection as a NUL-terminated decimal ASCII string.
*/
{
return 1; /* invalid number */
lport *= 10;
}
&& lport != 0
return 1;
case EMU_IRC:
/*
* Need to emulate DCC CHAT, DCC SEND and DCC MOVE
*/
return 1;
/* The %256s is for the broken mIRC */
{
return 1;
}
{
return 1;
}
{
return 1;
}
return 1;
#ifdef VBOX
/** @todo Disabled EMU_REALAUDIO, because it uses a static variable.
* This is not legal when more than one slirp instance is active. */
#else /* !VBOX */
case EMU_REALAUDIO:
/*
* RealAudio emulation - JP. We must try to parse the incoming
* data and try to find the two characters that contain the
* port number. Then we redirect an udp port and replace the
* number with the real port we got.
*
* The 1.0 beta versions of the player are not supported
* any more.
*
* A typical packet for player version 1.0 (release version):
*
* 0000:50 4E 41 00 05
* 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....�..g�l�c..P
* 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
* 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
* 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
*
* Now the port number 0x1BD7 is found at offset 0x04 of the
* Now the port number 0x1BD7 is found at offset 0x04 of the
* second packet. This time we received five bytes first and
* then the rest. You never know how many bytes you get.
*
* A typical packet for player version 2.0 (beta):
*
* 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........�.
* 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux�c..Win2.0.0
* 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
* 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
* 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B
*
* Port number 0x1BC1 is found at offset 0x0d.
*
* This is just a horrible switch statement. Variable ra tells
* us where we're going.
*/
{
u_short p;
static int ra = 0;
char ra_tbl[4];
ra_tbl[0] = 0x50;
ra_tbl[3] = 0;
switch (ra)
{
case 0:
case 2:
case 3:
{
ra = 0;
continue;
}
break;
case 1:
/*
* We may get 0x50 several times, ignore them
*/
if (*bptr == 0x50)
{
ra = 1;
bptr++;
continue;
}
{
ra = 0;
continue;
}
break;
case 4:
/*
* skip version number
*/
bptr++;
break;
case 5:
/*
* The difference between versions 1.0 and
* 2.0 is here. For future versions of
* the player this may need to be modified.
*/
bptr += 8;
else
bptr += 4;
break;
case 6:
/* This is the field containing the port
* number that RA-player is listening to.
*/
if (lport < 6970)
return 1; /* failed */
/* try to get udp port between 6970 - 7170 */
for (p = 6970; p < 7071; p++)
{
if (udp_listen(htons(p),
{
break;
}
}
if (p == 7071)
p = 0;
ra = 0;
return 1; /* port redirected, we're done */
break;
default:
ra = 0;
}
ra++;
}
return 1;
#endif /* !VBOX */
default:
/* Ooops, not emulated, won't call tcp_emu again */
return 1;
}
}