summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYonit <yhalperi@redhat.com>2009-05-27 12:20:10 +0300
committerYonit <yhalperi@redhat.com>2009-05-27 12:20:10 +0300
commit0cc49020edd88d4a914c67407bc6ae0bda30bf48 (patch)
tree304e0f5c59de0c37dec9d08e6509945a40a6ffd0
parent47de9909ff0eb29285e62e5494dcc7ca4abb9da9 (diff)
slirp that uses user defined interface for sockets instead of operating system
sockets. Currently supports only TCP. some addtional changes: 1) DHCP NACK support 2) moving prototypes from slirp.h to specific header files 3) not supporting emulated sockets slirp
-rw-r--r--Makefile90
-rw-r--r--TODO5
-rw-r--r--bootp.c129
-rw-r--r--bootp.h13
-rw-r--r--cksum.c4
-rw-r--r--cksum.h7
-rw-r--r--ctl.h2
-rw-r--r--debug.c175
-rw-r--r--debug.h4
-rw-r--r--if.c212
-rw-r--r--if.h12
-rw-r--r--ip.h12
-rw-r--r--ip_icmp.c9
-rw-r--r--ip_icmp.h9
-rw-r--r--ip_input.c32
-rw-r--r--ip_output.c5
-rw-r--r--libslirp.h38
-rw-r--r--main.h56
-rw-r--r--mbuf.c37
-rw-r--r--mbuf.h3
-rw-r--r--misc.c825
-rw-r--r--misc.h57
-rw-r--r--net_slirp.c304
-rw-r--r--net_slirp.h59
-rw-r--r--sbuf.c72
-rw-r--r--sbuf.h5
-rw-r--r--slirp.c1039
-rw-r--r--slirp.pc11
-rw-r--r--slirp_common.h (renamed from slirp.h)160
-rw-r--r--socket.c252
-rw-r--r--socket.h27
-rw-r--r--tcp.h28
-rw-r--r--tcp_input.c112
-rw-r--r--tcp_output.c10
-rw-r--r--tcp_subr.c898
-rw-r--r--tcp_timer.c4
-rw-r--r--tcp_timer.h2
-rw-r--r--tcpip.h1
-rw-r--r--udp.c52
-rw-r--r--udp.h11
40 files changed, 1269 insertions, 3514 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..f7a778d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,90 @@
+CC = gcc
+
+CFLAGS = -fvisibility=hidden -fPIC -DPIC -Wall -Wno-sign-compare -Werror
+LDFLAGS = -fPIC
+TARGET = RELEASE
+
+ifeq ($(TARGET),DEBUG)
+ CFLAGS += -g -O0
+ TARGETNAME = debug
+else ifeq ($(TARGET),RELEASE)
+ CFLAGS += -g -O3
+ TARGETNAME = release
+else
+ TARGETNAME = $(error Invalid TARGET. Use DEBUG or RELEASE)
+endif
+
+HEADERNAME = net_slirp.h
+LIBNAME = libslirp.so
+PCNAME = slirp.pc
+
+BIN = $(addprefix $(TARGETNAME)/, libslirp.so)
+
+INCLUDEDIR = /usr/include/libslirp
+LIBDIR = /usr/lib64
+PKGCONFIGDIR = /usr/lib64/pkgconfig
+
+SRCS =\
+ bootp.c\
+ cksum.c\
+ debug.c\
+ if.c\
+ ip_icmp.c\
+ ip_input.c\
+ ip_output.c\
+ mbuf.c\
+ misc.c\
+ sbuf.c\
+ net_slirp.c\
+ tcp_input.c\
+ tcp_output.c\
+ tcp_subr.c\
+ tcp_timer.c\
+ udp.c\
+ socket.c\
+ $(NULL)
+
+TMP = $(SRCS:.c=.o)
+OBJ = $(addprefix $(TARGETNAME)/, $(TMP))
+
+STATIC_LIBS =
+DYNAMIC_LIBS =
+
+LIBS = -Wl,-Bstatic $(addprefix -l, $(STATIC_LIBS)) -Wl,-Bdynamic $(addprefix -l, $(DYNAMIC_LIBS))
+
+all : $(BIN) link
+
+$(BIN) : $(TARGETNAME) $(OBJ)
+ $(CC) -shared $(LDFLAGS) -o $(BIN) $(OBJ) $(LIBS)
+
+link : $(BIN)
+ rm -f $(LIBNAME)
+ ln -s $(BIN)
+
+MAKEDEPEND = $(CC) -M $(CFLAGS) -o $(addprefix $(TARGETNAME)/,.$*.dep.tmp) $<
+
+$(addprefix $(TARGETNAME)/, %.o) : %.c Makefile
+ @$(MAKEDEPEND) && \
+ cp $(addprefix $(TARGETNAME)/, .$*.dep.tmp) $(addprefix $(TARGETNAME)/, .$*.dep) && \
+ sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+ -e '/^$$/ d' -e 's/$$/ :/' < $(addprefix $(TARGETNAME)/,.$*.dep.tmp) >> $(addprefix $(TARGETNAME)/,.$*.dep) && \
+ sed -i '1 s/^\(.\)/$(TARGETNAME)\/\1/' $(addprefix $(TARGETNAME)/, .$*.dep) && \
+ rm -f $(addprefix $(TARGETNAME)/,.$*.dep.tmp)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+ @rm -f $(TARGETNAME)/*.o $(TARGETNAME)/.*.dep $(TARGETNAME)/.*.dep.tmp $(BIN)
+
+$(TARGETNAME):
+ @mkdir -p $(TARGETNAME)
+
+-include $(patsubst %.c, $(TARGETNAME)/.%.dep, $(SRCS))
+
+install:
+ cp $(LIBNAME) $(LIBDIR)
+ cp $(HEADERNAME) $(INCLUDEDIR)
+ cp $(PCNAME) $(PKGCONFIGDIR)
+uninstall:
+ rm -f $(LIBDIR)/$(LIBNAME)
+ rm -f $(INCLUDEDIR)/$(HEADERNAME)
+ rm -f $(PKGCONFIGDIR)/$(PCNAME)
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..54f3cb4
--- /dev/null
+++ b/TODO
@@ -0,0 +1,5 @@
+- debug and stats support
+- udp support
+- make DHCP gateway support optional
+- redir
+- return windows compatibility
diff --git a/bootp.c b/bootp.c
index bf704ab..bc08ae7 100644
--- a/bootp.c
+++ b/bootp.c
@@ -21,13 +21,17 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include <slirp.h>
+#include "bootp.h"
+#include "slirp_common.h"
+#include "udp.h"
+#include "if.h"
/* XXX: only DHCP is supported */
-#define NB_ADDR 16
+#define NB_ADDR 16 // TODO: we don't need more than 1
#define START_ADDR 15
+#define START_VIRTAUL_ADDR (NB_ADDR + START_ADDR)
#define LEASE_TIME (24 * 3600)
@@ -38,6 +42,8 @@ typedef struct {
static BOOTPClient bootp_clients[NB_ADDR];
+static int virtual_ips_count = 0;
+
const char *bootp_filename;
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
@@ -66,6 +72,31 @@ static BOOTPClient *get_new_addr(struct in_addr *paddr)
return bc;
}
+int alloc_virtual_ip(struct in_addr *out_addr)
+{
+ if ((virtual_ips_count + START_VIRTAUL_ADDR) > 0xff)
+ return FALSE;
+ out_addr->s_addr = htonl(ntohl(special_addr.s_addr) | (virtual_ips_count + START_VIRTAUL_ADDR));
+ virtual_ips_count++;
+ return TRUE;
+}
+
+void clear_virtual_ips()
+{
+ virtual_ips_count = 0;
+}
+
+int is_virtual_ip_allocated(struct in_addr *addr)
+{
+ if ((addr->s_addr&htonl(0xffffff00)) == special_addr.s_addr) {
+ int lastbyte=(ntohl(addr->s_addr)) & 0xff;
+ return (((lastbyte >= START_VIRTAUL_ADDR) &&
+ (lastbyte < virtual_ips_count + START_VIRTAUL_ADDR)) ||(lastbyte == CTL_ALIAS) );
+ }
+ return FALSE;
+}
+
+
static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
{
BOOTPClient *bc;
@@ -130,7 +161,10 @@ static void bootp_reply(struct bootp_t *bp)
struct mbuf *m;
struct bootp_t *rbp;
struct sockaddr_in saddr, daddr;
+#if 0
struct in_addr dns_addr;
+#endif
+ int reply_nack = 0;
int dhcp_msg_type, val;
uint8_t *q;
@@ -155,22 +189,30 @@ static void bootp_reply(struct bootp_t *bp)
memset(rbp, 0, sizeof(struct bootp_t));
if (dhcp_msg_type == DHCPDISCOVER) {
- new_addr:
- bc = get_new_addr(&daddr.sin_addr);
+ bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);
+ if (!bc) {
+ bc = get_new_addr(&daddr.sin_addr);
+ }
+
if (!bc) {
dprintf("no address left\n");
return;
}
+
memcpy(bc->macaddr, client_ethaddr, 6);
} else {
bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);
if (!bc) {
- /* if never assigned, behaves as if it was already
- assigned (windows fix because it remembers its address) */
- goto new_addr;
+ // The requested address might no be in our network. We return nack.
+ // TODO: make this nicer by checking if the requested address is valid and
+ // accordingly allocating it or return nack.
+ reply_nack = 1;
+ inet_aton("255.255.255.255", &daddr.sin_addr);
}
}
+
+
if (bootp_filename)
snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
bootp_filename);
@@ -188,9 +230,11 @@ static void bootp_reply(struct bootp_t *bp)
rbp->bp_hlen = 6;
memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
- rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
- rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
-
+ if (!reply_nack) {
+ rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
+ rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
+ }
+
q = rbp->bp_vend;
memcpy(q, rfc1533_cookie, 4);
q += 4;
@@ -202,7 +246,12 @@ static void bootp_reply(struct bootp_t *bp)
} else if (dhcp_msg_type == DHCPREQUEST) {
*q++ = RFC2132_MSG_TYPE;
*q++ = 1;
- *q++ = DHCPACK;
+
+ if (!reply_nack) {
+ *q++ = DHCPACK;
+ } else {
+ *q++ = DHCPNACK;
+ }
}
if (dhcp_msg_type == DHCPDISCOVER ||
@@ -212,38 +261,44 @@ static void bootp_reply(struct bootp_t *bp)
memcpy(q, &saddr.sin_addr, 4);
q += 4;
- *q++ = RFC1533_NETMASK;
- *q++ = 4;
- *q++ = 0xff;
- *q++ = 0xff;
- *q++ = 0xff;
- *q++ = 0x00;
-
- if (!slirp_restrict) {
- *q++ = RFC1533_GATEWAY;
+ if (!reply_nack) {
+ *q++ = RFC1533_NETMASK;
*q++ = 4;
- memcpy(q, &saddr.sin_addr, 4);
- q += 4;
+ *q++ = 0xff;
+ *q++ = 0xff;
+ *q++ = 0xff;
+ *q++ = 0x00;
+
+ // TODO: removed gateway. Return it to be optional
+#if 0
+ if (!slirp_restrict) {
+ *q++ = RFC1533_GATEWAY;
+ *q++ = 4;
+ memcpy(q, &saddr.sin_addr, 4);
+ q += 4;
+
+ *q++ = RFC1533_DNS;
+ *q++ = 4;
+ dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
+ memcpy(q, &dns_addr, 4);
+ q += 4;
+ }
+#endif
- *q++ = RFC1533_DNS;
+ *q++ = RFC2132_LEASE_TIME;
*q++ = 4;
- dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
- memcpy(q, &dns_addr, 4);
+ val = htonl(LEASE_TIME);
+ memcpy(q, &val, 4);
q += 4;
- }
- *q++ = RFC2132_LEASE_TIME;
- *q++ = 4;
- val = htonl(LEASE_TIME);
- memcpy(q, &val, 4);
- q += 4;
+ if (*slirp_hostname) {
+ val = strlen(slirp_hostname);
+ *q++ = RFC1533_HOSTNAME;
+ *q++ = val;
+ memcpy(q, slirp_hostname, val);
+ q += val;
+ }
- if (*slirp_hostname) {
- val = strlen(slirp_hostname);
- *q++ = RFC1533_HOSTNAME;
- *q++ = val;
- memcpy(q, slirp_hostname, val);
- q += val;
}
}
*q++ = RFC1533_END;
diff --git a/bootp.h b/bootp.h
index e48f53f..f3b1b8e 100644
--- a/bootp.h
+++ b/bootp.h
@@ -1,3 +1,9 @@
+#ifndef _BOOTP_H
+#define _BOOTP_H
+
+#include "ip.h"
+#include "udp.h"
+
/* bootp/dhcp defines */
#define BOOTP_SERVER 67
@@ -71,6 +77,7 @@
#define DHCPOFFER 2
#define DHCPREQUEST 3
#define DHCPACK 5
+#define DHCPNACK 6
#define RFC1533_VENDOR_MAJOR 0
#define RFC1533_VENDOR_MINOR 0
@@ -111,3 +118,9 @@ struct bootp_t {
};
void bootp_input(struct mbuf *m);
+
+int alloc_virtual_ip(struct in_addr *out_addr);
+int is_virtual_ip_allocated(struct in_addr *addr);
+void clear_virtual_ips();
+
+#endif
diff --git a/cksum.c b/cksum.c
index b98373b..3538f8a 100644
--- a/cksum.c
+++ b/cksum.c
@@ -34,8 +34,8 @@
* in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp
*/
-#include <slirp.h>
-
+#include "slirp_common.h"
+#include "cksum.h"
/*
* Checksum routine for Internet Protocol family headers (Portable Version).
*
diff --git a/cksum.h b/cksum.h
new file mode 100644
index 0000000..aa887a0
--- /dev/null
+++ b/cksum.h
@@ -0,0 +1,7 @@
+#ifndef _H_CHKSUM
+#define _H_CHKSUM
+
+#include "mbuf.h"
+int cksum(struct mbuf *m, int len);
+
+#endif
diff --git a/ctl.h b/ctl.h
index 4a8576d..2398a34 100644
--- a/ctl.h
+++ b/ctl.h
@@ -4,4 +4,4 @@
#define CTL_DNS 3
#define CTL_SPECIAL "10.0.2.0"
-#define CTL_LOCAL "10.0.2.15"
+
diff --git a/debug.c b/debug.c
index bfef580..809f4ba 100644
--- a/debug.c
+++ b/debug.c
@@ -6,7 +6,7 @@
* terms and conditions of the copyright.
*/
-#include <slirp.h>
+#include <stdio.h>
FILE *dfd = NULL;
#ifdef DEBUG
@@ -16,119 +16,9 @@ int dostats = 0;
#endif
int slirp_debug = 0;
-/* Carry over one item from main.c so that the tty's restored.
- * Only done when the tty being used is /dev/tty --RedWolf */
-#ifndef CONFIG_QEMU
-extern struct termios slirp_tty_settings;
-extern int slirp_tty_restore;
-void
-debug_init(file, dbg)
- char *file;
- int dbg;
-{
- /* Close the old debugging file */
- if (dfd)
- fclose(dfd);
-
- dfd = fopen(file,"w");
- if (dfd != NULL) {
-#if 0
- fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION);
-#endif
- fprintf(dfd,"Debugging Started level %i.\r\n",dbg);
- fflush(dfd);
- slirp_debug = dbg;
- } else {
- lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n",
- file, strerror(errno));
- }
-}
-
-/*
- * Dump a packet in the same format as tcpdump -x
- */
-#ifdef DEBUG
-void
-dump_packet(dat, n)
- void *dat;
- int n;
-{
- u_char *pptr = (u_char *)dat;
- int j,k;
-
- n /= 16;
- n++;
- DEBUG_MISC((dfd, "PACKET DUMPED: \n"));
- for(j = 0; j < n; j++) {
- for(k = 0; k < 6; k++)
- DEBUG_MISC((dfd, "%02x ", *pptr++));
- DEBUG_MISC((dfd, "\n"));
- fflush(dfd);
- }
-}
-#endif
-#endif
-
#ifdef LOG_ENABLED
-#if 0
-/*
- * Statistic routines
- *
- * These will print statistics to the screen, the debug file (dfd), or
- * a buffer, depending on "type", so that the stats can be sent over
- * the link as well.
- */
-
-static void
-ttystats(ttyp)
- struct ttys *ttyp;
-{
- struct slirp_ifstats *is = &ttyp->ifstats;
- char buff[512];
-
- lprint(" \r\n");
-
- if (IF_COMP & IF_COMPRESS)
- strcpy(buff, "on");
- else if (IF_COMP & IF_NOCOMPRESS)
- strcpy(buff, "off");
- else
- strcpy(buff, "off (for now)");
- lprint("Unit %d:\r\n", ttyp->unit);
- lprint(" using %s encapsulation (VJ compression is %s)\r\n", (
-#ifdef USE_PPP
- ttyp->proto==PROTO_PPP?"PPP":
-#endif
- "SLIP"), buff);
- lprint(" %d baudrate\r\n", ttyp->baud);
- lprint(" interface is %s\r\n", ttyp->up?"up":"down");
- lprint(" using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid);
-#ifndef FULL_BOLT
- lprint(" towrite is %d bytes\r\n", ttyp->towrite);
-#endif
- if (ttyp->zeros)
- lprint(" %d zeros have been typed\r\n", ttyp->zeros);
- else if (ttyp->ones)
- lprint(" %d ones have been typed\r\n", ttyp->ones);
- lprint("Interface stats:\r\n");
- lprint(" %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes);
- lprint(" %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes);
- lprint(" %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes);
- lprint(" %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes);
- lprint(" %6d bad input packets\r\n", is->in_mbad);
-}
-
-static void
-allttystats(void)
-{
- struct ttys *ttyp;
-
- for (ttyp = ttys; ttyp; ttyp = ttyp->next)
- ttystats(ttyp);
-}
-#endif
static void
ipstats(void)
@@ -154,24 +44,6 @@ ipstats(void)
lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered);
}
-#ifndef CONFIG_QEMU
-static void
-vjstats(void)
-{
- lprint(" \r\n");
-
- lprint("VJ compression stats:\r\n");
-
- lprint(" %6d outbound packets (%d compressed)\r\n",
- comp_s.sls_packets, comp_s.sls_compressed);
- lprint(" %6d searches for connection stats (%d misses)\r\n",
- comp_s.sls_searches, comp_s.sls_misses);
- lprint(" %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin);
- lprint(" %6d inbound compressed packets\r\n", comp_s.sls_compressedin);
- lprint(" %6d inbound unknown type packets\r\n", comp_s.sls_errorin);
- lprint(" %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed);
-}
-#endif
static void
tcpstats(void)
@@ -334,49 +206,7 @@ sockstats(void)
}
#endif
-#ifndef CONFIG_QEMU
-void
-slirp_exit(exit_status)
- int exit_status;
-{
- struct ttys *ttyp;
-
- DEBUG_CALL("slirp_exit");
- DEBUG_ARG("exit_status = %d", exit_status);
-
- if (dostats) {
- lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf;
- if (!dfd)
- debug_init("slirp_stats", 0xf);
- lprint_arg = (char **)&dfd;
-
- ipstats();
- tcpstats();
- udpstats();
- icmpstats();
- mbufstats();
- sockstats();
- allttystats();
- vjstats();
- }
-
- for (ttyp = ttys; ttyp; ttyp = ttyp->next)
- tty_detached(ttyp, 1);
-
- if (slirp_forked) {
- /* Menendez time */
- if (kill(getppid(), SIGQUIT) < 0)
- lprint("Couldn't kill parent process %ld!\n",
- (long) getppid());
- }
-
- /* Restore the terminal if we gotta */
- if(slirp_tty_restore)
- tcsetattr(0,TCSANOW, &slirp_tty_settings); /* NOW DAMMIT! */
- exit(exit_status);
-}
-#endif
-
+#if 0 // TODO: tmp
void
slirp_stats(void)
{
@@ -391,3 +221,4 @@ slirp_stats(void)
lprint("SLIRP statistics code not compiled.\n");
#endif
}
+#endif
diff --git a/debug.h b/debug.h
index c43eff7..36d671c 100644
--- a/debug.h
+++ b/debug.h
@@ -1,3 +1,5 @@
+#ifndef __SLIRP_DEBUG_H__
+#define __SLIRP_DEBUG_H__
/*
* Copyright (c) 1995 Danny Gasparovski.
*
@@ -36,4 +38,4 @@ extern int slirp_debug;
#endif
-void debug_init _P((char *, int));
+#endif
diff --git a/if.c b/if.c
index 0e10f3e..e0dd169 100644
--- a/if.c
+++ b/if.c
@@ -5,7 +5,9 @@
* terms and conditions of the copyright.
*/
-#include <slirp.h>
+#include "slirp_common.h"
+#include "if.h"
+#include "bootp.h"
int if_queued = 0; /* Number of packets queued so far */
@@ -40,84 +42,146 @@ if_init()
next_m = &if_batchq;
}
-#if 0
-/*
- * This shouldn't be needed since the modem is blocking and
- * we don't expect any signals, but what the hell..
- */
-inline int
-writen(fd, bptr, n)
- int fd;
- char *bptr;
- int n;
-{
- int ret;
- int total;
-
- /* This should succeed most of the time */
- ret = send(fd, bptr, n,0);
- if (ret == n || ret <= 0)
- return ret;
-
- /* Didn't write everything, go into the loop */
- total = ret;
- while (n > total) {
- ret = send(fd, bptr+total, n-total,0);
- if (ret <= 0)
- return ret;
- total += ret;
- }
- return total;
-}
-/*
- * if_input - read() the tty, do "top level" processing (ie: check for any escapes),
- * and pass onto (*ttyp->if_input)
- *
- * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet.
- */
-#define INBUFF_SIZE 2048 /* XXX */
-void
-if_input(ttyp)
- struct ttys *ttyp;
-{
- u_char if_inbuff[INBUFF_SIZE];
- int if_n;
-
- DEBUG_CALL("if_input");
- DEBUG_ARG("ttyp = %lx", (long)ttyp);
+#define ARPOP_REQUEST 1 /* ARP request */
+#define ARPOP_REPLY 2 /* ARP reply */
- if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0);
+struct ethhdr
+{
+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
+ unsigned char h_source[ETH_ALEN]; /* source ether addr */
+ unsigned short h_proto; /* packet type ID field */
+};
- DEBUG_MISC((dfd, " read %d bytes\n", if_n));
+struct arphdr
+{
+ unsigned short ar_hrd; /* format of hardware address */
+ unsigned short ar_pro; /* format of protocol address */
+ unsigned char ar_hln; /* length of hardware address */
+ unsigned char ar_pln; /* length of protocol address */
+ unsigned short ar_op; /* ARP opcode (command) */
+
+ /*
+ * Ethernet looks like this : This bit is variable sized however...
+ */
+ unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
+ unsigned char ar_sip[4]; /* sender IP address */
+ unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
+ unsigned char ar_tip[4]; /* target IP address */
+};
+
+void arp_input(const uint8_t *pkt, int pkt_len)
+{
+ struct ethhdr *eh = (struct ethhdr *)pkt;
+ struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
+ uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
+ struct ethhdr *reh = (struct ethhdr *)arp_reply;
+ struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
+ int ar_op;
+ //struct ex_list *ex_ptr;
+
+ ar_op = ntohs(ah->ar_op);
+ switch(ar_op) {
+ case ARPOP_REQUEST:
+ if (is_virtual_ip_allocated((struct in_addr *)ah->ar_tip)) {
+ goto arp_ok;
+ } else {
+ return;
+ }
- if (if_n <= 0) {
- if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) {
- if (ttyp->up)
- link_up--;
- tty_detached(ttyp, 0);
- }
- return;
- }
- if (if_n == 1) {
- if (*if_inbuff == '0') {
- ttyp->ones = 0;
- if (++ttyp->zeros >= 5)
- slirp_exit(0);
- return;
- }
- if (*if_inbuff == '1') {
- ttyp->zeros = 0;
- if (++ttyp->ones >= 5)
- tty_detached(ttyp, 0);
- return;
- }
- }
- ttyp->ones = ttyp->zeros = 0;
+#if 0
+ if (!memcmp(ah->ar_tip, &special_addr, 3)) {
+ if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
+ goto arp_ok;
+ for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+ if (ex_ptr->ex_addr == ah->ar_tip[3])
+ goto arp_ok;
+ }
+#endif
+ arp_ok:
+ /* XXX: make an ARP request to have the client address */
+ memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
+
+ /* ARP request for alias/dns mac address */
+ memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
+ memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
+ reh->h_source[5] = ah->ar_tip[3];
+ reh->h_proto = htons(ETH_P_ARP);
+
+ rah->ar_hrd = htons(1);
+ rah->ar_pro = htons(ETH_P_IP);
+ rah->ar_hln = ETH_ALEN;
+ rah->ar_pln = 4;
+ rah->ar_op = htons(ARPOP_REPLY);
+ memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
+ memcpy(rah->ar_sip, ah->ar_tip, 4);
+ memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
+ memcpy(rah->ar_tip, ah->ar_sip, 4);
+ slirp_net_interface->slirp_output(slirp_net_interface, arp_reply, sizeof(arp_reply));
+ break;
+ case ARPOP_REPLY:
+ /* reply to request of client mac address ? */
+ if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
+ !memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) {
+ memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
+ }
+ break;
+ default:
+ break;
+ }
+}
- (*ttyp->if_input)(ttyp, if_inbuff, if_n);
+/* output the IP packet to the ethernet device */
+static void if_encap(const uint8_t *ip_data, int ip_data_len)
+{
+ uint8_t buf[1600];
+ struct ethhdr *eh = (struct ethhdr *)buf;
+
+ if (ip_data_len + ETH_HLEN > sizeof(buf))
+ return;
+
+ if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
+ uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
+ struct ethhdr *reh = (struct ethhdr *)arp_req;
+ struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
+ const struct ip *iph = (const struct ip *)ip_data;
+
+ /* If the client addr is not known, there is no point in
+ sending the packet to it. Normally the sender should have
+ done an ARP request to get its MAC address. Here we do it
+ in place of sending the packet and we hope that the sender
+ will retry sending its packet. */
+ memset(reh->h_dest, 0xff, ETH_ALEN);
+ memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
+ reh->h_source[5] = CTL_ALIAS;
+ reh->h_proto = htons(ETH_P_ARP);
+ rah->ar_hrd = htons(1);
+ rah->ar_pro = htons(ETH_P_IP);
+ rah->ar_hln = ETH_ALEN;
+ rah->ar_pln = 4;
+ rah->ar_op = htons(ARPOP_REQUEST);
+ /* source hw addr */
+ memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
+ rah->ar_sha[5] = CTL_ALIAS;
+ /* source IP */
+ memcpy(rah->ar_sip, &alias_addr, 4);
+ /* target hw addr (none) */
+ memset(rah->ar_tha, 0, ETH_ALEN);
+ /* target IP */
+ memcpy(rah->ar_tip, &iph->ip_dst, 4);
+ client_ipaddr = iph->ip_dst;
+ slirp_net_interface->slirp_output(slirp_net_interface, arp_req, sizeof(arp_req));
+ } else {
+ memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
+ memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
+ /* XXX: not correct */
+ eh->h_source[5] = CTL_ALIAS;
+ eh->h_proto = htons(ETH_P_IP);
+ memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
+ slirp_net_interface->slirp_output(slirp_net_interface, buf, ip_data_len + ETH_HLEN);
+ }
}
-#endif
+
/*
* if_output: Queue packet into an output queue.
@@ -251,7 +315,7 @@ if_start(void)
again:
/* check if we can really output */
- if (!slirp_can_output())
+ if (!slirp_net_interface->slirp_can_output(slirp_net_interface))
return;
/*
diff --git a/if.h b/if.h
index bed7152..d83ac56 100644
--- a/if.h
+++ b/if.h
@@ -8,6 +8,15 @@
#ifndef _IF_H_
#define _IF_H_
+#include "mbuf.h"
+#include "socket.h"
+
+#define ETH_ALEN 6
+#define ETH_HLEN 14
+
+#define ETH_P_IP 0x0800 /* Internet Protocol packet */
+#define ETH_P_ARP 0x0806 /* Address Resolution packet */
+
#define IF_COMPRESS 0x01 /* We want compression */
#define IF_NOCOMPRESS 0x02 /* Do not do compression */
#define IF_AUTOCOMP 0x04 /* Autodetect (default) */
@@ -60,4 +69,7 @@ struct slirp_ifstats {
};
#endif
+void if_init();
+void arp_input(const uint8_t *pkt, int pkt_len);
+void if_output(struct socket *so, struct mbuf *ifm);
#endif
diff --git a/ip.h b/ip.h
index 3079f90..cf9bf65 100644
--- a/ip.h
+++ b/ip.h
@@ -37,6 +37,8 @@
#ifndef _IP_H_
#define _IP_H_
+#include "socket.h"
+
#ifdef WORDS_BIGENDIAN
# ifndef NTOHL
# define NTOHL(d)
@@ -294,4 +296,14 @@ extern struct ipstat ipstat;
extern struct ipq ipq; /* ip reass. queue */
extern u_int16_t ip_id; /* ip packet ctr, for ids */
+/* ip_input.c */
+void ip_init();
+void ip_input(struct mbuf *);
+void ip_slowtimo ();
+void ip_stripoptions (register struct mbuf *, struct mbuf *);
+
+/* ip_output.c */
+int ip_output(struct socket *, struct mbuf *);
+
+
#endif
diff --git a/ip_icmp.c b/ip_icmp.c
index b3d4348..250c2f5 100644
--- a/ip_icmp.c
+++ b/ip_icmp.c
@@ -34,8 +34,9 @@
* ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp
*/
-#include "slirp.h"
+#include "slirp_common.h"
#include "ip_icmp.h"
+#include "cksum.h"
#ifdef LOG_ENABLED
struct icmpstat icmpstat;
@@ -71,6 +72,8 @@ static const int icmp_flush[19] = {
/*
* Process a received ICMP message.
*/
+
+#if 0 // TODO: temp till udp is supported
void
icmp_input(m, hlen)
struct mbuf *m;
@@ -185,7 +188,7 @@ end_error:
/* m is m_free()'d xor put in a socket xor or given to ip_send */
return;
}
-
+#endif
/*
* Send an ICMP message in response to a situation
@@ -319,6 +322,7 @@ end_error:
}
#undef ICMP_MAXDATALEN
+#if 0 // TODO: temp till udp is supported
/*
* Reflect the ip packet back to the source
*/
@@ -371,3 +375,4 @@ icmp_reflect(m)
STAT(icmpstat.icps_reflect++);
}
+#endif
diff --git a/ip_icmp.h b/ip_icmp.h
index 5cd9f7f..e30ccfc 100644
--- a/ip_icmp.h
+++ b/ip_icmp.h
@@ -36,7 +36,7 @@
#ifndef _NETINET_IP_ICMP_H_
#define _NETINET_IP_ICMP_H_
-
+#include "ip.h"
/*
* Interface Control Message Protocol Definitions.
* Per RFC 792, September 1981.
@@ -156,10 +156,13 @@ struct icmp {
(type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
-
+
+#if 0 // TODO: temp till udp is supported
void icmp_input _P((struct mbuf *, int));
+void icmp_reflect _P((struct mbuf *));
+#endif
+
void icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
const char *message);
-void icmp_reflect _P((struct mbuf *));
#endif
diff --git a/ip_input.c b/ip_input.c
index 116ee45..a428101 100644
--- a/ip_input.c
+++ b/ip_input.c
@@ -42,9 +42,13 @@
* terms and conditions of the copyright.
*/
-#include <slirp.h>
-#include <osdep.h>
+
+#include "slirp_common.h"
+#include "ip.h"
#include "ip_icmp.h"
+#include "udp.h"
+#include "tcp.h"
+#include "cksum.h"
#ifdef LOG_ENABLED
struct ipstat ipstat;
@@ -138,25 +142,6 @@ ip_input(m)
goto bad;
}
- if (slirp_restrict) {
- if (memcmp(&ip->ip_dst.s_addr, &special_addr, 3)) {
- if (ip->ip_dst.s_addr == 0xffffffff && ip->ip_p != IPPROTO_UDP)
- goto bad;
- } else {
- int host = ntohl(ip->ip_dst.s_addr) & 0xff;
- struct ex_list *ex_ptr;
-
- if (host == 0xff)
- goto bad;
-
- for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
- if (ex_ptr->ex_addr == host)
- break;
-
- if (!ex_ptr)
- goto bad;
- }
- }
/* Should drop packet if mbuf too long? hmmm... */
if (m->m_len > ip->ip_len)
@@ -249,9 +234,12 @@ ip_input(m)
udp_input(m, hlen);
break;
case IPPROTO_ICMP:
- icmp_input(m, hlen);
+ //icmp_input(m, hlen);
+ printf("ip_input : ICMP not supported yet\n"); // TODO: temp
+ return;
break;
default:
+ printf("ip_input : IPPROTO %d not supported", ip->ip_p); // TODO: temp
STAT(ipstat.ips_noproto++);
m_free(m);
}
diff --git a/ip_output.c b/ip_output.c
index a8a6067..3d2f6c5 100644
--- a/ip_output.c
+++ b/ip_output.c
@@ -42,7 +42,10 @@
* terms and conditions of the copyright.
*/
-#include <slirp.h>
+#include "slirp_common.h"
+#include "ip.h"
+#include "if.h"
+#include "cksum.h"
u_int16_t ip_id;
diff --git a/libslirp.h b/libslirp.h
deleted file mode 100644
index 6c5db54..0000000
--- a/libslirp.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef _LIBSLIRP_H
-#define _LIBSLIRP_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void slirp_init(int restrict, char *special_ip);
-
-void slirp_select_fill(int *pnfds,
- fd_set *readfds, fd_set *writefds, fd_set *xfds);
-
-void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds);
-
-void slirp_input(const uint8_t *pkt, int pkt_len);
-
-/* you must provide the following functions: */
-int slirp_can_output(void);
-void slirp_output(const uint8_t *pkt, int pkt_len);
-
-int slirp_redir(int is_udp, int host_port,
- struct in_addr guest_addr, int guest_port);
-int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
- int guest_port);
-
-extern const char *tftp_prefix;
-extern char slirp_hostname[33];
-
-void slirp_stats(void);
-void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
- int size);
-size_t slirp_socket_can_recv(int addr_low_byte, int guest_port);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/main.h b/main.h
deleted file mode 100644
index ed51385..0000000
--- a/main.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#define TOWRITEMAX 512
-
-extern struct timeval tt;
-extern int link_up;
-extern int slirp_socket;
-extern int slirp_socket_unit;
-extern int slirp_socket_port;
-extern u_int32_t slirp_socket_addr;
-extern char *slirp_socket_passwd;
-extern int ctty_closed;
-
-/*
- * Get the difference in 2 times from updtim()
- * Allow for wraparound times, "just in case"
- * x is the greater of the 2 (current time) and y is
- * what it's being compared against.
- */
-#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y)
-
-extern char *slirp_tty;
-extern char *exec_shell;
-extern u_int curtime;
-extern fd_set *global_readfds, *global_writefds, *global_xfds;
-extern struct in_addr ctl_addr;
-extern struct in_addr special_addr;
-extern struct in_addr alias_addr;
-extern struct in_addr our_addr;
-extern struct in_addr loopback_addr;
-extern struct in_addr dns_addr;
-extern char *username;
-extern char *socket_path;
-extern int towrite_max;
-extern int ppp_exit;
-extern int tcp_keepintvl;
-extern uint8_t client_ethaddr[6];
-extern const char *slirp_special_ip;
-extern int slirp_restrict;
-
-#define PROTO_SLIP 0x1
-#ifdef USE_PPP
-#define PROTO_PPP 0x2
-#endif
-
-void if_encap(const uint8_t *ip_data, int ip_data_len);
-ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
diff --git a/mbuf.c b/mbuf.c
index 655de41..3744cfa 100644
--- a/mbuf.c
+++ b/mbuf.c
@@ -15,8 +15,9 @@
* the flags
*/
-#include <slirp.h>
-
+#include "mbuf.h"
+#include "slirp_common.h"
+#include "if.h"
int mbuf_alloced = 0;
struct mbuf m_freelist, m_usedlist;
#define MBUF_THRESH 30
@@ -74,6 +75,7 @@ m_get()
m->m_len = 0;
m->m_nextpkt = 0;
m->m_prevpkt = 0;
+
end_error:
DEBUG_ARG("m = %lx", (long )m);
return m;
@@ -107,6 +109,7 @@ m_free(m)
m->m_flags = M_FREELIST; /* Clobber other flags */
}
} /* if(m) */
+
}
/*
@@ -140,30 +143,30 @@ m_inc(m, size)
int datasize;
/* some compiles throw up on gotos. This one we can fake. */
- if(m->m_size>size) return;
+ if(m->m_size>size) return;
- if (m->m_flags & M_EXT) {
- datasize = m->m_data - m->m_ext;
- m->m_ext = (char *)realloc(m->m_ext,size);
+ if (m->m_flags & M_EXT) {
+ datasize = m->m_data - m->m_ext;
+ m->m_ext = (char *)realloc(m->m_ext,size);
/* if (m->m_ext == NULL)
* return (struct mbuf *)NULL;
*/
- m->m_data = m->m_ext + datasize;
- } else {
- char *dat;
- datasize = m->m_data - m->m_dat;
- dat = (char *)malloc(size);
+ m->m_data = m->m_ext + datasize;
+ } else {
+ char *dat;
+ datasize = m->m_data - m->m_dat;
+ dat = (char *)malloc(size);
/* if (dat == NULL)
* return (struct mbuf *)NULL;
*/
- memcpy(dat, m->m_dat, m->m_size);
+ memcpy(dat, m->m_dat, m->m_size);
- m->m_ext = dat;
- m->m_data = m->m_ext + datasize;
- m->m_flags |= M_EXT;
- }
+ m->m_ext = dat;
+ m->m_data = m->m_ext + datasize;
+ m->m_flags |= M_EXT;
+ }
- m->m_size = size;
+ m->m_size = size;
}
diff --git a/mbuf.h b/mbuf.h
index f9f2132..80a96aa 100644
--- a/mbuf.h
+++ b/mbuf.h
@@ -37,6 +37,8 @@
#ifndef _MBUF_H_
#define _MBUF_H_
+#include "slirp_common.h"
+
#define m_freem m_free
@@ -131,7 +133,6 @@ struct mbstat {
extern struct mbstat mbstat;
extern int mbuf_alloced;
-extern struct mbuf m_freelist, m_usedlist;
extern int mbuf_max;
void m_init _P((void));
diff --git a/misc.c b/misc.c
index f558b3c..90f76d3 100644
--- a/misc.c
+++ b/misc.c
@@ -6,82 +6,8 @@
*/
#define WANT_SYS_IOCTL_H
-#include <slirp.h>
+#include "slirp_common.h"
-u_int curtime, time_fasttimo, last_slowtimo;
-
-#if 0
-int x_port = -1;
-int x_display = 0;
-int x_screen = 0;
-
-int
-show_x(buff, inso)
- char *buff;
- struct socket *inso;
-{
- if (x_port < 0) {
- lprint("X Redir: X not being redirected.\r\n");
- } else {
- lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n",
- inet_ntoa(our_addr), x_port, x_screen);
- lprint("X Redir: In csh/tcsh/etc. type: setenv DISPLAY %s:%d.%d\r\n",
- inet_ntoa(our_addr), x_port, x_screen);
- if (x_display)
- lprint("X Redir: Redirecting to display %d\r\n", x_display);
- }
-
- return CFG_OK;
-}
-
-
-/*
- * XXX Allow more than one X redirection?
- */
-void
-redir_x(inaddr, start_port, display, screen)
- u_int32_t inaddr;
- int start_port;
- int display;
- int screen;
-{
- int i;
-
- if (x_port >= 0) {
- lprint("X Redir: X already being redirected.\r\n");
- show_x(0, 0);
- } else {
- for (i = 6001 + (start_port-1); i <= 6100; i++) {
- if (solisten(htons(i), inaddr, htons(6000 + display), 0)) {
- /* Success */
- x_port = i - 6000;
- x_display = display;
- x_screen = screen;
- show_x(0, 0);
- return;
- }
- }
- lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n");
- }
-}
-#endif
-
-/*
- * Get our IP address and put it in our_addr
- */
-void
-getouraddr()
-{
- char buff[256];
- struct hostent *he = NULL;
-
- if (gethostname(buff,256) == 0)
- he = gethostbyname(buff);
- if (he)
- our_addr = *(struct in_addr *)he->h_addr;
- if (our_addr.s_addr == 0)
- our_addr.s_addr = loopback_addr.s_addr;
-}
struct quehead {
struct quehead *qh_link;
@@ -89,7 +15,7 @@ struct quehead {
};
inline void
-insque(a, b)
+slirp_insque(a, b)
void *a, *b;
{
register struct quehead *element = (struct quehead *) a;
@@ -102,7 +28,7 @@ insque(a, b)
}
inline void
-remque(a)
+slirp_remque(a)
void *a;
{
register struct quehead *element = (struct quehead *) a;
@@ -115,32 +41,6 @@ remque(a)
/* #endif */
-int
-add_exec(ex_ptr, do_pty, exec, addr, port)
- struct ex_list **ex_ptr;
- int do_pty;
- char *exec;
- int addr;
- int port;
-{
- struct ex_list *tmp_ptr;
-
- /* First, check if the port is "bound" */
- for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
- if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr)
- return -1;
- }
-
- tmp_ptr = *ex_ptr;
- *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list));
- (*ex_ptr)->ex_fport = port;
- (*ex_ptr)->ex_addr = addr;
- (*ex_ptr)->ex_pty = do_pty;
- (*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec);
- (*ex_ptr)->ex_next = tmp_ptr;
- return 0;
-}
-
#ifndef HAVE_STRERROR
/*
@@ -163,254 +63,6 @@ strerror(error)
#endif
-#ifdef _WIN32
-
-int
-fork_exec(struct socket *so, const char *ex, int do_pty)
-{
- /* not implemented */
- return 0;
-}
-
-#else
-
-#ifndef CONFIG_QEMU
-int
-slirp_openpty(amaster, aslave)
- int *amaster, *aslave;
-{
- register int master, slave;
-
-#ifdef HAVE_GRANTPT
- char *ptr;
-
- if ((master = open("/dev/ptmx", O_RDWR)) < 0 ||
- grantpt(master) < 0 ||
- unlockpt(master) < 0 ||
- (ptr = ptsname(master)) == NULL) {
- close(master);
- return -1;
- }
-
- if ((slave = open(ptr, O_RDWR)) < 0 ||
- ioctl(slave, I_PUSH, "ptem") < 0 ||
- ioctl(slave, I_PUSH, "ldterm") < 0 ||
- ioctl(slave, I_PUSH, "ttcompat") < 0) {
- close(master);
- close(slave);
- return -1;
- }
-
- *amaster = master;
- *aslave = slave;
- return 0;
-
-#else
-
- static char line[] = "/dev/ptyXX";
- register const char *cp1, *cp2;
-
- for (cp1 = "pqrsPQRS"; *cp1; cp1++) {
- line[8] = *cp1;
- for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
- line[9] = *cp2;
- if ((master = open(line, O_RDWR, 0)) == -1) {
- if (errno == ENOENT)
- return (-1); /* out of ptys */
- } else {
- line[5] = 't';
- /* These will fail */
- (void) chown(line, getuid(), 0);
- (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
-#ifdef HAVE_REVOKE
- (void) revoke(line);
-#endif
- if ((slave = open(line, O_RDWR, 0)) != -1) {
- *amaster = master;
- *aslave = slave;
- return 0;
- }
- (void) close(master);
- line[5] = 'p';
- }
- }
- }
- errno = ENOENT; /* out of ptys */
- return (-1);
-#endif
-}
-#endif
-
-/*
- * XXX This is ugly
- * We create and bind a socket, then fork off to another
- * process, which connects to this socket, after which we
- * exec the wanted program. If something (strange) happens,
- * the accept() call could block us forever.
- *
- * do_pty = 0 Fork/exec inetd style
- * do_pty = 1 Fork/exec using slirp.telnetd
- * do_ptr = 2 Fork/exec using pty
- */
-int
-fork_exec(struct socket *so, const char *ex, int do_pty)
-{
- int s;
- struct sockaddr_in addr;
- socklen_t addrlen = sizeof(addr);
- int opt;
- int master = -1;
- const char *argv[256];
-#if 0
- char buff[256];
-#endif
- /* don't want to clobber the original */
- char *bptr;
- const char *curarg;
- int c, i, ret;
-
- DEBUG_CALL("fork_exec");
- DEBUG_ARG("so = %lx", (long)so);
- DEBUG_ARG("ex = %lx", (long)ex);
- DEBUG_ARG("do_pty = %lx", (long)do_pty);
-
- if (do_pty == 2) {
-#if 0
- if (slirp_openpty(&master, &s) == -1) {
- lprint("Error: openpty failed: %s\n", strerror(errno));
- return 0;
- }
-#else
- return 0;
-#endif
- } else {
- addr.sin_family = AF_INET;
- addr.sin_port = 0;
- addr.sin_addr.s_addr = INADDR_ANY;
-
- if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
- bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
- listen(s, 1) < 0) {
- lprint("Error: inet socket: %s\n", strerror(errno));
- closesocket(s);
-
- return 0;
- }
- }
-
- switch(fork()) {
- case -1:
- lprint("Error: fork failed: %s\n", strerror(errno));
- close(s);
- if (do_pty == 2)
- close(master);
- return 0;
-
- case 0:
- /* Set the DISPLAY */
- if (do_pty == 2) {
- (void) close(master);
-#ifdef TIOCSCTTY /* XXXXX */
- (void) setsid();
- ioctl(s, TIOCSCTTY, (char *)NULL);
-#endif
- } else {
- getsockname(s, (struct sockaddr *)&addr, &addrlen);
- close(s);
- /*
- * Connect to the socket
- * XXX If any of these fail, we're in trouble!
- */
- s = socket(AF_INET, SOCK_STREAM, 0);
- addr.sin_addr = loopback_addr;
- do {
- ret = connect(s, (struct sockaddr *)&addr, addrlen);
- } while (ret < 0 && errno == EINTR);
- }
-
-#if 0
- if (x_port >= 0) {
-#ifdef HAVE_SETENV
- sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
- setenv("DISPLAY", buff, 1);
-#else
- sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
- putenv(buff);
-#endif
- }
-#endif
- dup2(s, 0);
- dup2(s, 1);
- dup2(s, 2);
- for (s = getdtablesize() - 1; s >= 3; s--)
- close(s);
-
- i = 0;
- bptr = strdup(ex); /* No need to free() this */
- if (do_pty == 1) {
- /* Setup "slirp.telnetd -x" */
- argv[i++] = "slirp.telnetd";
- argv[i++] = "-x";
- argv[i++] = bptr;
- } else
- do {
- /* Change the string into argv[] */
- curarg = bptr;
- while (*bptr != ' ' && *bptr != (char)0)
- bptr++;
- c = *bptr;
- *bptr++ = (char)0;
- argv[i++] = strdup(curarg);
- } while (c);
-
- argv[i] = 0;
- execvp(argv[0], (char **)argv);
-
- /* Ooops, failed, let's tell the user why */
- {
- char buff[256];
-
- snprintf(buff, sizeof(buff),
- "Error: execvp of %s failed: %s\n",
- argv[0], strerror(errno));
- write(2, buff, strlen(buff)+1);
- }
- close(0); close(1); close(2); /* XXX */
- exit(1);
-
- default:
- if (do_pty == 2) {
- close(s);
- so->s = master;
- } else {
- /*
- * XXX this could block us...
- * XXX Should set a timer here, and if accept() doesn't
- * return after X seconds, declare it a failure
- * The only reason this will block forever is if socket()
- * of connect() fail in the child process
- */
- do {
- so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
- } while (so->s < 0 && errno == EINTR);
- closesocket(s);
- opt = 1;
- setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
- opt = 1;
- setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
- }
- fd_nonblock(so->s);
-
- /* Append the telnet options now */
- if (so->so_m != 0 && do_pty == 1) {
- sbappend(so, so->so_m);
- so->so_m = 0;
- }
-
- return 1;
- }
-}
-#endif
#ifndef HAVE_STRDUP
char *
@@ -426,137 +78,7 @@ strdup(str)
}
#endif
-#if 0
-void
-snooze_hup(num)
- int num;
-{
- int s, ret;
-#ifndef NO_UNIX_SOCKETS
- struct sockaddr_un sock_un;
-#endif
- struct sockaddr_in sock_in;
- char buff[256];
-
- ret = -1;
- if (slirp_socket_passwd) {
- s = socket(AF_INET, SOCK_STREAM, 0);
- if (s < 0)
- slirp_exit(1);
- sock_in.sin_family = AF_INET;
- sock_in.sin_addr.s_addr = slirp_socket_addr;
- sock_in.sin_port = htons(slirp_socket_port);
- if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0)
- slirp_exit(1); /* just exit...*/
- sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit);
- write(s, buff, strlen(buff)+1);
- }
-#ifndef NO_UNIX_SOCKETS
- else {
- s = socket(AF_UNIX, SOCK_STREAM, 0);
- if (s < 0)
- slirp_exit(1);
- sock_un.sun_family = AF_UNIX;
- strcpy(sock_un.sun_path, socket_path);
- if (connect(s, (struct sockaddr *)&sock_un,
- sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0)
- slirp_exit(1);
- sprintf(buff, "kill none:%d", slirp_socket_unit);
- write(s, buff, strlen(buff)+1);
- }
-#endif
- slirp_exit(0);
-}
-
-
-void
-snooze()
-{
- sigset_t s;
- int i;
-
- /* Don't need our data anymore */
- /* XXX This makes SunOS barf */
-/* brk(0); */
-
- /* Close all fd's */
- for (i = 255; i >= 0; i--)
- close(i);
-
- signal(SIGQUIT, slirp_exit);
- signal(SIGHUP, snooze_hup);
- sigemptyset(&s);
-
- /* Wait for any signal */
- sigsuspend(&s);
-
- /* Just in case ... */
- exit(255);
-}
-
-void
-relay(s)
- int s;
-{
- char buf[8192];
- int n;
- fd_set readfds;
- struct ttys *ttyp;
-
- /* Don't need our data anymore */
- /* XXX This makes SunOS barf */
-/* brk(0); */
-
- signal(SIGQUIT, slirp_exit);
- signal(SIGHUP, slirp_exit);
- signal(SIGINT, slirp_exit);
- signal(SIGTERM, slirp_exit);
-
- /* Fudge to get term_raw and term_restore to work */
- if (NULL == (ttyp = tty_attach (0, slirp_tty))) {
- lprint ("Error: tty_attach failed in misc.c:relay()\r\n");
- slirp_exit (1);
- }
- ttyp->fd = 0;
- ttyp->flags |= TTY_CTTY;
- term_raw(ttyp);
-
- while (1) {
- FD_ZERO(&readfds);
-
- FD_SET(0, &readfds);
- FD_SET(s, &readfds);
-
- n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0);
-
- if (n <= 0)
- slirp_exit(0);
-
- if (FD_ISSET(0, &readfds)) {
- n = read(0, buf, 8192);
- if (n <= 0)
- slirp_exit(0);
- n = writen(s, buf, n);
- if (n <= 0)
- slirp_exit(0);
- }
-
- if (FD_ISSET(s, &readfds)) {
- n = read(s, buf, 8192);
- if (n <= 0)
- slirp_exit(0);
- n = writen(0, buf, n);
- if (n <= 0)
- slirp_exit(0);
- }
- }
-
- /* Just in case.... */
- exit(1);
-}
-#endif
-
-#ifdef CONFIG_QEMU
+#if 0 // TODO: tmp term_vprintf is defined in qemu.
extern void term_vprintf(const char *fmt, va_list ap);
void lprint(const char *format, ...)
@@ -567,344 +89,5 @@ void lprint(const char *format, ...)
term_vprintf(format, args);
va_end(args);
}
-#else
-int (*lprint_print) _P((void *, const char *, va_list));
-char *lprint_ptr, *lprint_ptr2, **lprint_arg;
-
-void
-#ifdef __STDC__
-lprint(const char *format, ...)
-#else
-lprint(va_alist) va_dcl
-#endif
-{
- va_list args;
-
-#ifdef __STDC__
- va_start(args, format);
-#else
- char *format;
- va_start(args);
- format = va_arg(args, char *);
-#endif
-#if 0
- /* If we're printing to an sbuf, make sure there's enough room */
- /* XXX +100? */
- if (lprint_sb) {
- if ((lprint_ptr - lprint_sb->sb_wptr) >=
- (lprint_sb->sb_datalen - (strlen(format) + 100))) {
- int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data;
- int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data;
- int deltap = lprint_ptr - lprint_sb->sb_data;
-
- lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data,
- lprint_sb->sb_datalen + TCP_SNDSPACE);
-
- /* Adjust all values */
- lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw;
- lprint_sb->sb_rptr = lprint_sb->sb_data + deltar;
- lprint_ptr = lprint_sb->sb_data + deltap;
-
- lprint_sb->sb_datalen += TCP_SNDSPACE;
- }
- }
-#endif
- if (lprint_print)
- lprint_ptr += (*lprint_print)(*lprint_arg, format, args);
-
- /* Check if they want output to be logged to file as well */
- if (lfd) {
- /*
- * Remove \r's
- * otherwise you'll get ^M all over the file
- */
- int len = strlen(format);
- char *bptr1, *bptr2;
-
- bptr1 = bptr2 = strdup(format);
-
- while (len--) {
- if (*bptr1 == '\r')
- memcpy(bptr1, bptr1+1, len+1);
- else
- bptr1++;
- }
- vfprintf(lfd, bptr2, args);
- free(bptr2);
- }
- va_end(args);
-}
-
-void
-add_emu(buff)
- char *buff;
-{
- u_int lport, fport;
- u_int8_t tos = 0, emu = 0;
- char buff1[256], buff2[256], buff4[128];
- char *buff3 = buff4;
- struct emu_t *emup;
- struct socket *so;
-
- if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) {
- lprint("Error: Bad arguments\r\n");
- return;
- }
-
- if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) {
- lport = 0;
- if (sscanf(buff1, "%d", &fport) != 1) {
- lprint("Error: Bad first argument\r\n");
- return;
- }
- }
-
- if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) {
- buff3 = 0;
- if (sscanf(buff2, "%256s", buff1) != 1) {
- lprint("Error: Bad second argument\r\n");
- return;
- }
- }
-
- if (buff3) {
- if (strcmp(buff3, "lowdelay") == 0)
- tos = IPTOS_LOWDELAY;
- else if (strcmp(buff3, "throughput") == 0)
- tos = IPTOS_THROUGHPUT;
- else {
- lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n");
- return;
- }
- }
-
- if (strcmp(buff1, "ftp") == 0)
- emu = EMU_FTP;
- else if (strcmp(buff1, "irc") == 0)
- emu = EMU_IRC;
- else if (strcmp(buff1, "none") == 0)
- emu = EMU_NONE; /* ie: no emulation */
- else {
- lprint("Error: Unknown service\r\n");
- return;
- }
-
- /* First, check that it isn't already emulated */
- for (emup = tcpemu; emup; emup = emup->next) {
- if (emup->lport == lport && emup->fport == fport) {
- lprint("Error: port already emulated\r\n");
- return;
- }
- }
-
- /* link it */
- emup = (struct emu_t *)malloc(sizeof (struct emu_t));
- emup->lport = (u_int16_t)lport;
- emup->fport = (u_int16_t)fport;
- emup->tos = tos;
- emup->emu = emu;
- emup->next = tcpemu;
- tcpemu = emup;
-
- /* And finally, mark all current sessions, if any, as being emulated */
- for (so = tcb.so_next; so != &tcb; so = so->so_next) {
- if ((lport && lport == ntohs(so->so_lport)) ||
- (fport && fport == ntohs(so->so_fport))) {
- if (emu)
- so->so_emu = emu;
- if (tos)
- so->so_iptos = tos;
- }
- }
-
- lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport);
-}
-#endif
-
-#ifdef BAD_SPRINTF
-
-#undef vsprintf
-#undef sprintf
-
-/*
- * Some BSD-derived systems have a sprintf which returns char *
- */
-
-int
-vsprintf_len(string, format, args)
- char *string;
- const char *format;
- va_list args;
-{
- vsprintf(string, format, args);
- return strlen(string);
-}
-
-int
-#ifdef __STDC__
-sprintf_len(char *string, const char *format, ...)
-#else
-sprintf_len(va_alist) va_dcl
-#endif
-{
- va_list args;
-#ifdef __STDC__
- va_start(args, format);
-#else
- char *string;
- char *format;
- va_start(args);
- string = va_arg(args, char *);
- format = va_arg(args, char *);
-#endif
- vsprintf(string, format, args);
- return strlen(string);
-}
-
-#endif
-
-void
-u_sleep(usec)
- int usec;
-{
- struct timeval t;
- fd_set fdset;
-
- FD_ZERO(&fdset);
-
- t.tv_sec = 0;
- t.tv_usec = usec * 1000;
-
- select(0, &fdset, &fdset, &fdset, &t);
-}
-
-/*
- * Set fd blocking and non-blocking
- */
-
-void
-fd_nonblock(fd)
- int fd;
-{
-#ifdef FIONBIO
- int opt = 1;
-
- ioctlsocket(fd, FIONBIO, &opt);
-#else
- int opt;
-
- opt = fcntl(fd, F_GETFL, 0);
- opt |= O_NONBLOCK;
- fcntl(fd, F_SETFL, opt);
-#endif
-}
-
-void
-fd_block(fd)
- int fd;
-{
-#ifdef FIONBIO
- int opt = 0;
-
- ioctlsocket(fd, FIONBIO, &opt);
-#else
- int opt;
-
- opt = fcntl(fd, F_GETFL, 0);
- opt &= ~O_NONBLOCK;
- fcntl(fd, F_SETFL, opt);
-#endif
-}
-
-
-#if 0
-/*
- * invoke RSH
- */
-int
-rsh_exec(so,ns, user, host, args)
- struct socket *so;
- struct socket *ns;
- char *user;
- char *host;
- char *args;
-{
- int fd[2];
- int fd0[2];
- int s;
- char buff[256];
-
- DEBUG_CALL("rsh_exec");
- DEBUG_ARG("so = %lx", (long)so);
-
- if (pipe(fd)<0) {
- lprint("Error: pipe failed: %s\n", strerror(errno));
- return 0;
- }
-/* #ifdef HAVE_SOCKETPAIR */
-#if 1
- if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) {
- close(fd[0]);
- close(fd[1]);
- lprint("Error: openpty failed: %s\n", strerror(errno));
- return 0;
- }
-#else
- if (slirp_openpty(&fd0[0], &fd0[1]) == -1) {
- close(fd[0]);
- close(fd[1]);
- lprint("Error: openpty failed: %s\n", strerror(errno));
- return 0;
- }
-#endif
-
- switch(fork()) {
- case -1:
- lprint("Error: fork failed: %s\n", strerror(errno));
- close(fd[0]);
- close(fd[1]);
- close(fd0[0]);
- close(fd0[1]);
- return 0;
-
- case 0:
- close(fd[0]);
- close(fd0[0]);
-
- /* Set the DISPLAY */
- if (x_port >= 0) {
-#ifdef HAVE_SETENV
- sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
- setenv("DISPLAY", buff, 1);
-#else
- sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
- putenv(buff);
-#endif
- }
-
- dup2(fd0[1], 0);
- dup2(fd0[1], 1);
- dup2(fd[1], 2);
- for (s = 3; s <= 255; s++)
- close(s);
- execlp("rsh","rsh","-l", user, host, args, NULL);
-
- /* Ooops, failed, let's tell the user why */
-
- sprintf(buff, "Error: execlp of %s failed: %s\n",
- "rsh", strerror(errno));
- write(2, buff, strlen(buff)+1);
- close(0); close(1); close(2); /* XXX */
- exit(1);
-
- default:
- close(fd[1]);
- close(fd0[1]);
- ns->s=fd[0];
- so->s=fd0[0];
-
- return 1;
- }
-}
#endif
diff --git a/misc.h b/misc.h
index ab8e3a7..03ec4ae 100644
--- a/misc.h
+++ b/misc.h
@@ -8,29 +8,6 @@
#ifndef _MISC_H_
#define _MISC_H_
-struct ex_list {
- int ex_pty; /* Do we want a pty? */
- int ex_addr; /* The last byte of the address */
- int ex_fport; /* Port to telnet to */
- const char *ex_exec; /* Command line of what to exec */
- struct ex_list *ex_next;
-};
-
-extern struct ex_list *exec_list;
-extern u_int time_fasttimo, last_slowtimo;
-
-extern int (*lprint_print) _P((void *, const char *, va_list));
-extern char *lprint_ptr, *lprint_ptr2, **lprint_arg;
-extern struct sbuf *lprint_sb;
-
-#ifndef HAVE_STRDUP
-char *strdup _P((const char *));
-#endif
-
-void do_wait _P((int));
-
-#define EMU_NONE 0x0
-
/* TCP emulations */
#define EMU_CTL 0x1
#define EMU_FTP 0x2
@@ -41,12 +18,7 @@ void do_wait _P((int));
#define EMU_IDENT 0x7
#define EMU_RSH 0x8
-#define EMU_NOCONNECT 0x10 /* Don't connect */
-
-/* UDP emulations */
-#define EMU_TALK 0x1
-#define EMU_NTALK 0x2
-#define EMU_CUSEEME 0x3
+#define EMU_NOCONNECT 0x10 /* Don't connect */
struct tos_t {
u_int16_t lport;
@@ -55,35 +27,12 @@ struct tos_t {
u_int8_t emu;
};
-struct emu_t {
- u_int16_t lport;
- u_int16_t fport;
- u_int8_t tos;
- u_int8_t emu;
- struct emu_t *next;
-};
-
-#ifndef CONFIG_QEMU
-extern struct emu_t *tcpemu;
+#ifndef HAVE_STRDUP
+char *strdup _P((const char *));
#endif
-extern int x_port, x_server, x_display;
-int show_x _P((char *, struct socket *));
-void redir_x _P((u_int32_t, int, int, int));
-void getouraddr _P((void));
void slirp_insque _P((void *, void *));
void slirp_remque _P((void *));
-int add_exec _P((struct ex_list **, int, char *, int, int));
-int slirp_openpty _P((int *, int *));
-int fork_exec(struct socket *so, const char *ex, int do_pty);
-void snooze_hup _P((int));
-void snooze _P((void));
-void relay _P((int));
-void add_emu _P((char *));
-void u_sleep _P((int));
-void fd_nonblock _P((int));
-void fd_block _P((int));
-int rsh_exec _P((struct socket *, struct socket *, char *, char *, char *));
#endif
diff --git a/net_slirp.c b/net_slirp.c
new file mode 100644
index 0000000..f313b33
--- /dev/null
+++ b/net_slirp.c
@@ -0,0 +1,304 @@
+/*
+ * libslirp glue
+ *
+ * Copyright (c) 2004-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "slirp_common.h"
+#include "net_slirp.h"
+#include "if.h"
+#include "ip.h"
+#include "mbuf.h"
+#include "ctl.h"
+#include "socket.h"
+#include "tcp.h"
+#include "socket.h"
+#include "bootp.h"
+
+#define DLL_PUBLIC __attribute__ ((visibility ("default")))
+/* host address */
+struct in_addr our_addr;
+/* host dns address */
+struct in_addr dns_addr;
+/* host loopback address */
+struct in_addr loopback_addr;
+
+/* address for slirp virtual addresses */
+struct in_addr special_addr;
+/* virtual address alias for host */
+struct in_addr alias_addr;
+const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
+const uint8_t special_ethaddr[6] = {
+ 0x52, 0x54, 0x00, 0x12, 0x35, 0x00
+};
+
+/* ARP cache for the guest IP addresses (XXX: allow many entries) */
+uint8_t client_ethaddr[6]; // bootp_reply sets it or arp...
+struct in_addr client_ipaddr;
+
+
+int link_up;
+struct timeval tt;
+FILE *lfd;
+
+char slirp_hostname[33];
+
+SlirpUsrNetworkInterface *slirp_net_interface;
+
+UserTimer *fast_timer, *slow_timer;
+int fast_timer_armed, slow_timer_armed;
+/*
+u_int curtime, last_fasttimo, last_slowtimo;
+static void updtime(void)
+{
+ gettimeofday(&tt, 0);
+
+ curtime = (u_int)tt.tv_sec * (u_int)1000;
+ curtime += (u_int)tt.tv_usec / (u_int)1000;
+
+ if ((tt.tv_usec % 1000) >= 500)
+ curtime++;
+}*/
+
+static int get_dns_addr(struct in_addr *pdns_addr)
+{
+ char buff[512];
+ char buff2[257];
+ FILE *f;
+ int found = 0;
+ struct in_addr tmp_addr;
+
+ f = fopen("/etc/resolv.conf", "r");
+ if (!f)
+ return -1;
+
+#ifdef DEBUG
+ lprint("IP address of your DNS(s): ");
+#endif
+ while (fgets(buff, 512, f) != NULL) {
+ if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
+ if (!inet_aton(buff2, &tmp_addr))
+ continue;
+ if (tmp_addr.s_addr == loopback_addr.s_addr)
+ tmp_addr = our_addr;
+ /* If it's the first one, set it to dns_addr */
+ if (!found)
+ *pdns_addr = tmp_addr;
+#ifdef DEBUG
+ else
+ lprint(", ");
+#endif
+ if (++found > 3) {
+#ifdef DEBUG
+ lprint("(more)");
+#endif
+ break;
+ }
+#ifdef DEBUG
+ else
+ lprint("%s", inet_ntoa(tmp_addr));
+#endif
+ }
+ }
+ fclose(f);
+ if (!found)
+ return -1;
+ return 0;
+}
+
+
+/*
+ * Get our IP address and put it in our_addr
+ */
+static void getouraddr()
+{
+ char buff[256];
+ struct hostent *he = NULL;
+
+ if (gethostname(buff,256) == 0)
+ he = gethostbyname(buff);
+ if (he)
+ our_addr = *(struct in_addr *)he->h_addr;
+ if (our_addr.s_addr == 0)
+ our_addr.s_addr = loopback_addr.s_addr;
+}
+
+static int need_fast_timer()
+{
+ // the timer will check if realy needed (if there is pending delayed ack)
+ return (if_queued || (tcb.so_next != &tcb));
+}
+
+static int need_slow_timer()
+{
+ return ((tcb.so_next != &tcb) || (&ipq.ip_link != ipq.ip_link.next));
+}
+
+static void fast_timeout(void *opaque)
+{
+ tcp_fasttimo();
+
+ if (if_queued)
+ if_start();
+ if (need_fast_timer()) {
+ slirp_net_interface->arm_timer(slirp_net_interface, fast_timer, FAST_TIMEOUT_MS);
+ } else {
+ fast_timer_armed = 0;
+ }
+}
+
+static void slow_timeout(void *opaque)
+{
+ ip_slowtimo();
+ tcp_slowtimo();
+ if (need_slow_timer()) {
+ slirp_net_interface->arm_timer(slirp_net_interface, slow_timer, SLOW_TIMEOUT_MS);
+ } else {
+ slow_timer_armed = 0;
+ }
+}
+
+
+void DLL_PUBLIC net_slirp_init(struct in_addr special_ip, SlirpUsrNetworkInterface *net_interface)
+{
+ // debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
+ link_up = 1;
+
+ if_init();
+ ip_init();
+
+ /* Initialise mbufs *after* setting the MTU */
+ m_init();
+
+ /* set default addresses */
+ inet_aton("127.0.0.1", &loopback_addr);
+
+ if (get_dns_addr(&dns_addr) < 0) {
+ dns_addr = loopback_addr;
+ fprintf (stderr, "Warning: No DNS servers found\n");
+ }
+
+ special_addr.s_addr = special_ip.s_addr;
+ alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
+
+ slirp_net_interface = net_interface;
+
+ getouraddr();
+
+ fast_timer = net_interface->create_timer(net_interface, fast_timeout, NULL);
+ slow_timer = net_interface->create_timer(net_interface, slow_timeout, NULL);
+ fast_timer_armed = 0;
+ slow_timer_armed = 0;
+
+}
+
+void DLL_PUBLIC net_slirp_input(const uint8_t *pkt, int pkt_len)
+{
+ struct mbuf *m;
+ int proto;
+
+ if (pkt_len < ETH_HLEN)
+ return;
+
+ proto = ntohs(*(uint16_t *)(pkt + 12));
+ switch(proto) {
+ case ETH_P_ARP:
+ arp_input(pkt, pkt_len);
+ break;
+ case ETH_P_IP:
+ m = m_get();
+ if (!m)
+ return;
+ /* Note: we add to align the IP header */
+ if (M_FREEROOM(m) < pkt_len + 2) {
+ m_inc(m, pkt_len + 2);
+ }
+ m->m_len = pkt_len + 2;
+ memcpy(m->m_data + 2, pkt, pkt_len);
+
+ m->m_data += 2 + ETH_HLEN;
+ m->m_len -= 2 + ETH_HLEN;
+
+ ip_input(m);
+ break;
+ default:
+ printf("SLIRP INPUT : UNKNOWN\n");
+ break;
+ }
+
+ if (!slow_timer_armed && need_slow_timer()) {
+ slirp_net_interface->arm_timer(slirp_net_interface, slow_timer, SLOW_TIMEOUT_MS);
+ }
+
+ if (!fast_timer_armed && need_fast_timer()) {
+ slirp_net_interface->arm_timer(slirp_net_interface, fast_timer, FAST_TIMEOUT_MS);
+ }
+}
+
+
+
+void DLL_PUBLIC net_slirp_socket_connected_notify(SlirpSocket *sckt)
+{
+ struct socket *so = (struct socket *)sckt;
+ so->so_state &= ~SS_ISFCONNECTING;
+
+ // when tcp_input is called with null, the connection continues
+ tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+}
+
+void DLL_PUBLIC net_slirp_socket_connect_failed_notify(SlirpSocket *sckt)
+{
+ struct socket *so = (struct socket *)sckt;
+ so->so_state = SS_NOFDREF;
+ tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+}
+
+void DLL_PUBLIC net_slirp_socket_can_send_notify(SlirpSocket *sckt)
+{
+ struct socket *so = (struct socket *)sckt;
+ sotrysend(so);
+}
+
+void DLL_PUBLIC net_slirp_socket_can_receive_notify(SlirpSocket *sckt)
+{
+ struct socket *so = (struct socket *)sckt;
+
+ // if it can't read cause a buffer is full, it will try again in sodropacked
+ if (sotryrecv(so) > 0) {
+ /* Output it if we read something */
+ tcp_output(sototcpcb(so));
+ }
+}
+
+void DLL_PUBLIC net_slirp_socket_abort(SlirpSocket *sckt)
+{
+ struct socket *so = (struct socket *)sckt;
+ tcp_drop(sototcpcb(so), 0);
+}
+
+int DLL_PUBLIC net_slirp_allocate_virtual_ip(struct in_addr *addr)
+{
+ return alloc_virtual_ip(addr); // bootp
+}
+
+void DLL_PUBLIC net_slirp_clear_virtual_ips()
+{
+ clear_virtual_ips();
+}
diff --git a/net_slirp.h b/net_slirp.h
new file mode 100644
index 0000000..71bdc97
--- /dev/null
+++ b/net_slirp.h
@@ -0,0 +1,59 @@
+#ifndef _H_NET_SLIRP
+#define _H_NET_SLIRP
+
+#include <stdint.h>
+typedef void UserSocket;
+typedef void SlirpSocket;
+typedef void UserTimer;
+typedef void (*timer_proc_t)(void *opaque);
+
+// TODO: only tcp/ip supported
+typedef struct SlirpUsrNetworkInterface SlirpUsrNetworkInterface;
+struct SlirpUsrNetworkInterface {
+ int (*slirp_can_output)(SlirpUsrNetworkInterface *usr_interface);
+ void (*slirp_output)(SlirpUsrNetworkInterface *usr_interface, const uint8_t *pkt, int pkt_len);
+ int (*connect)(SlirpUsrNetworkInterface *usr_interface,
+ struct in_addr src_addr, uint16_t src_port,
+ struct in_addr dst_addr, uint16_t dst_port,
+ SlirpSocket *slirp_s, UserSocket **o_usr_s);
+ int (*send)(SlirpUsrNetworkInterface *usr_interface, UserSocket *opaque,
+ uint8_t *buf, size_t len, uint8_t urgent);
+ int (*recv)(SlirpUsrNetworkInterface *usr_interface, UserSocket *opaque,
+ uint8_t *buf, size_t len);
+ void (*shutdown_send)(SlirpUsrNetworkInterface *usr_interface, UserSocket *opaque);
+ void (*shutdown_recv)(SlirpUsrNetworkInterface *usr_interface, UserSocket *opaque);
+ void (*close)(SlirpUsrNetworkInterface *usr_interface, UserSocket *opaque);
+
+ UserTimer *(*create_timer)(SlirpUsrNetworkInterface *usr_interface, timer_proc_t proc,
+ void *opaque);
+ void (*arm_timer)(SlirpUsrNetworkInterface *usr_interface, UserTimer *timer, uint32_t ms);
+};
+
+void net_slirp_init(struct in_addr special_ip, SlirpUsrNetworkInterface *net_interface);
+void net_slirp_input(const uint8_t *pkt, int pkt_len);
+
+// TODO: maybe we will need to change the allocation/deallocation to be for specific
+// ips (because of problems when client/server restart or client changes network, and
+// services were already installed). Maybe the netwrok mask should be extended too.
+int net_slirp_allocate_virtual_ip(struct in_addr *addr);
+void net_slirp_clear_virtual_ips();
+
+void net_slirp_socket_connected_notify(SlirpSocket *sckt);
+void net_slirp_socket_connect_failed_notify(SlirpSocket *sckt);
+void net_slirp_socket_can_send_notify(SlirpSocket *sckt);
+void net_slirp_socket_can_receive_notify(SlirpSocket *sckt);
+void net_slirp_socket_abort(SlirpSocket *sckt);
+
+#if 0
+
+int slirp_redir(int is_udp, int host_port,
+ struct in_addr guest_addr, int guest_port);
+int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
+ int guest_port);
+
+void slirp_stats(void);
+
+#endif
+
+
+#endif
diff --git a/sbuf.c b/sbuf.c
index 2e6e2b2..b1ffdf3 100644
--- a/sbuf.c
+++ b/sbuf.c
@@ -4,10 +4,9 @@
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
-
-#include <slirp.h>
-
-static void sbappendsb(struct sbuf *sb, struct mbuf *m);
+#include "sbuf.h"
+#include "mbuf.h"
+#include "slirp_common.h"
/* Done as a macro in socket.h */
/* int
@@ -67,75 +66,12 @@ sbreserve(sb, size)
}
}
-/*
- * Try and write() to the socket, whatever doesn't get written
- * append to the buffer... for a host with a fast net connection,
- * this prevents an unnecessary copy of the data
- * (the socket is non-blocking, so we won't hang)
- */
-void
-sbappend(so, m)
- struct socket *so;
- struct mbuf *m;
-{
- int ret = 0;
-
- DEBUG_CALL("sbappend");
- DEBUG_ARG("so = %lx", (long)so);
- DEBUG_ARG("m = %lx", (long)m);
- DEBUG_ARG("m->m_len = %d", m->m_len);
-
- /* Shouldn't happen, but... e.g. foreign host closes connection */
- if (m->m_len <= 0) {
- m_free(m);
- return;
- }
-
- /*
- * If there is urgent data, call sosendoob
- * if not all was sent, sowrite will take care of the rest
- * (The rest of this function is just an optimisation)
- */
- if (so->so_urgc) {
- sbappendsb(&so->so_rcv, m);
- m_free(m);
- sosendoob(so);
- return;
- }
-
- /*
- * We only write if there's nothing in the buffer,
- * ottherwise it'll arrive out of order, and hence corrupt
- */
- if (!so->so_rcv.sb_cc)
- ret = slirp_send(so, m->m_data, m->m_len, 0);
-
- if (ret <= 0) {
- /*
- * Nothing was written
- * It's possible that the socket has closed, but
- * we don't need to check because if it has closed,
- * it will be detected in the normal way by soread()
- */
- sbappendsb(&so->so_rcv, m);
- } else if (ret != m->m_len) {
- /*
- * Something was written, but not everything..
- * sbappendsb the rest
- */
- m->m_len -= ret;
- m->m_data += ret;
- sbappendsb(&so->so_rcv, m);
- } /* else */
- /* Whatever happened, we free the mbuf */
- m_free(m);
-}
/*
* Copy the data from m into sb
* The caller is responsible to make sure there's enough room
*/
-static void
+void
sbappendsb(struct sbuf *sb, struct mbuf *m)
{
int len, n, nn;
diff --git a/sbuf.h b/sbuf.h
index a4f1036..dfe2d2e 100644
--- a/sbuf.h
+++ b/sbuf.h
@@ -8,7 +8,8 @@
#ifndef _SBUF_H_
#define _SBUF_H_
-#define sbflush(sb) sbdrop((sb),(sb)->sb_cc)
+#include "mbuf.h"
+
#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
struct sbuf {
@@ -24,7 +25,7 @@ struct sbuf {
void sbfree _P((struct sbuf *));
void sbdrop _P((struct sbuf *, int));
void sbreserve _P((struct sbuf *, int));
-void sbappend _P((struct socket *, struct mbuf *));
void sbcopy _P((struct sbuf *, int, int, char *));
+void sbappendsb _P((struct sbuf *sb, struct mbuf *m));
#endif
diff --git a/slirp.c b/slirp.c
deleted file mode 100644
index 0394496..0000000
--- a/slirp.c
+++ /dev/null
@@ -1,1039 +0,0 @@
-/*
- * libslirp glue
- *
- * Copyright (c) 2004-2008 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu-common.h"
-#include "qemu-char.h"
-#include "slirp.h"
-#include "hw/hw.h"
-
-/* host address */
-struct in_addr our_addr;
-/* host dns address */
-struct in_addr dns_addr;
-/* host loopback address */
-struct in_addr loopback_addr;
-
-/* address for slirp virtual addresses */
-struct in_addr special_addr;
-/* virtual address alias for host */
-struct in_addr alias_addr;
-
-static const uint8_t special_ethaddr[6] = {
- 0x52, 0x54, 0x00, 0x12, 0x35, 0x00
-};
-
-/* ARP cache for the guest IP addresses (XXX: allow many entries) */
-uint8_t client_ethaddr[6];
-static struct in_addr client_ipaddr;
-
-static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
-
-const char *slirp_special_ip = CTL_SPECIAL;
-int slirp_restrict;
-int do_slowtimo;
-int link_up;
-struct timeval tt;
-FILE *lfd;
-struct ex_list *exec_list;
-
-/* XXX: suppress those select globals */
-fd_set *global_readfds, *global_writefds, *global_xfds;
-
-char slirp_hostname[33];
-
-#ifdef _WIN32
-
-static int get_dns_addr(struct in_addr *pdns_addr)
-{
- FIXED_INFO *FixedInfo=NULL;
- ULONG BufLen;
- DWORD ret;
- IP_ADDR_STRING *pIPAddr;
- struct in_addr tmp_addr;
-
- FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
- BufLen = sizeof(FIXED_INFO);
-
- if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
- if (FixedInfo) {
- GlobalFree(FixedInfo);
- FixedInfo = NULL;
- }
- FixedInfo = GlobalAlloc(GPTR, BufLen);
- }
-
- if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
- printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
- if (FixedInfo) {
- GlobalFree(FixedInfo);
- FixedInfo = NULL;
- }
- return -1;
- }
-
- pIPAddr = &(FixedInfo->DnsServerList);
- inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
- *pdns_addr = tmp_addr;
-#if 0
- printf( "DNS Servers:\n" );
- printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
-
- pIPAddr = FixedInfo -> DnsServerList.Next;
- while ( pIPAddr ) {
- printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
- pIPAddr = pIPAddr ->Next;
- }
-#endif
- if (FixedInfo) {
- GlobalFree(FixedInfo);
- FixedInfo = NULL;
- }
- return 0;
-}
-
-#else
-
-static int get_dns_addr(struct in_addr *pdns_addr)
-{
- char buff[512];
- char buff2[257];
- FILE *f;
- int found = 0;
- struct in_addr tmp_addr;
-
- f = fopen("/etc/resolv.conf", "r");
- if (!f)
- return -1;
-
-#ifdef DEBUG
- lprint("IP address of your DNS(s): ");
-#endif
- while (fgets(buff, 512, f) != NULL) {
- if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
- if (!inet_aton(buff2, &tmp_addr))
- continue;
- if (tmp_addr.s_addr == loopback_addr.s_addr)
- tmp_addr = our_addr;
- /* If it's the first one, set it to dns_addr */
- if (!found)
- *pdns_addr = tmp_addr;
-#ifdef DEBUG
- else
- lprint(", ");
-#endif
- if (++found > 3) {
-#ifdef DEBUG
- lprint("(more)");
-#endif
- break;
- }
-#ifdef DEBUG
- else
- lprint("%s", inet_ntoa(tmp_addr));
-#endif
- }
- }
- fclose(f);
- if (!found)
- return -1;
- return 0;
-}
-
-#endif
-
-#ifdef _WIN32
-static void slirp_cleanup(void)
-{
- WSACleanup();
-}
-#endif
-
-static void slirp_state_save(QEMUFile *f, void *opaque);
-static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
-
-void slirp_init(int restrict, char *special_ip)
-{
- // debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
-
-#ifdef _WIN32
- {
- WSADATA Data;
- WSAStartup(MAKEWORD(2,0), &Data);
- atexit(slirp_cleanup);
- }
-#endif
-
- link_up = 1;
- slirp_restrict = restrict;
-
- if_init();
- ip_init();
-
- /* Initialise mbufs *after* setting the MTU */
- m_init();
-
- /* set default addresses */
- inet_aton("127.0.0.1", &loopback_addr);
-
- if (get_dns_addr(&dns_addr) < 0) {
- dns_addr = loopback_addr;
- fprintf (stderr, "Warning: No DNS servers found\n");
- }
-
- if (special_ip)
- slirp_special_ip = special_ip;
-
- inet_aton(slirp_special_ip, &special_addr);
- alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
- getouraddr();
- register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
-}
-
-#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
-#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
-#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
-
-/*
- * curtime kept to an accuracy of 1ms
- */
-#ifdef _WIN32
-static void updtime(void)
-{
- struct _timeb tb;
-
- _ftime(&tb);
- curtime = (u_int)tb.time * (u_int)1000;
- curtime += (u_int)tb.millitm;
-}
-#else
-static void updtime(void)
-{
- gettimeofday(&tt, 0);
-
- curtime = (u_int)tt.tv_sec * (u_int)1000;
- curtime += (u_int)tt.tv_usec / (u_int)1000;
-
- if ((tt.tv_usec % 1000) >= 500)
- curtime++;
-}
-#endif
-
-void slirp_select_fill(int *pnfds,
- fd_set *readfds, fd_set *writefds, fd_set *xfds)
-{
- struct socket *so, *so_next;
- struct timeval timeout;
- int nfds;
- int tmp_time;
-
- /* fail safe */
- global_readfds = NULL;
- global_writefds = NULL;
- global_xfds = NULL;
-
- nfds = *pnfds;
- /*
- * First, TCP sockets
- */
- do_slowtimo = 0;
- if (link_up) {
- /*
- * *_slowtimo needs calling if there are IP fragments
- * in the fragment queue, or there are TCP connections active
- */
- do_slowtimo = ((tcb.so_next != &tcb) ||
- (&ipq.ip_link != ipq.ip_link.next));
-
- for (so = tcb.so_next; so != &tcb; so = so_next) {
- so_next = so->so_next;
-
- /*
- * See if we need a tcp_fasttimo
- */
- if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
- time_fasttimo = curtime; /* Flag when we want a fasttimo */
-
- /*
- * NOFDREF can include still connecting to local-host,
- * newly socreated() sockets etc. Don't want to select these.
- */
- if (so->so_state & SS_NOFDREF || so->s == -1)
- continue;
-
- /*
- * Set for reading sockets which are accepting
- */
- if (so->so_state & SS_FACCEPTCONN) {
- FD_SET(so->s, readfds);
- UPD_NFDS(so->s);
- continue;
- }
-
- /*
- * Set for writing sockets which are connecting
- */
- if (so->so_state & SS_ISFCONNECTING) {
- FD_SET(so->s, writefds);
- UPD_NFDS(so->s);
- continue;
- }
-
- /*
- * Set for writing if we are connected, can send more, and
- * we have something to send
- */
- if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
- FD_SET(so->s, writefds);
- UPD_NFDS(so->s);
- }
-
- /*
- * Set for reading (and urgent data) if we are connected, can
- * receive more, and we have room for it XXX /2 ?
- */
- if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
- FD_SET(so->s, readfds);
- FD_SET(so->s, xfds);
- UPD_NFDS(so->s);
- }
- }
-
- /*
- * UDP sockets
- */
- for (so = udb.so_next; so != &udb; so = so_next) {
- so_next = so->so_next;
-
- /*
- * See if it's timed out
- */
- if (so->so_expire) {
- if (so->so_expire <= curtime) {
- udp_detach(so);
- continue;
- } else
- do_slowtimo = 1; /* Let socket expire */
- }
-
- /*
- * When UDP packets are received from over the
- * link, they're sendto()'d straight away, so
- * no need for setting for writing
- * Limit the number of packets queued by this session
- * to 4. Note that even though we try and limit this
- * to 4 packets, the session could have more queued
- * if the packets needed to be fragmented
- * (XXX <= 4 ?)
- */
- if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
- FD_SET(so->s, readfds);
- UPD_NFDS(so->s);
- }
- }
- }
-
- /*
- * Setup timeout to use minimum CPU usage, especially when idle
- */
-
- /*
- * First, see the timeout needed by *timo
- */
- timeout.tv_sec = 0;
- timeout.tv_usec = -1;
- /*
- * If a slowtimo is needed, set timeout to 500ms from the last
- * slow timeout. If a fast timeout is needed, set timeout within
- * 200ms of when it was requested.
- */
- if (do_slowtimo) {
- /* XXX + 10000 because some select()'s aren't that accurate */
- timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
- if (timeout.tv_usec < 0)
- timeout.tv_usec = 0;
- else if (timeout.tv_usec > 510000)
- timeout.tv_usec = 510000;
-
- /* Can only fasttimo if we also slowtimo */
- if (time_fasttimo) {
- tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
- if (tmp_time < 0)
- tmp_time = 0;
-
- /* Choose the smallest of the 2 */
- if (tmp_time < timeout.tv_usec)
- timeout.tv_usec = (u_int)tmp_time;
- }
- }
- *pnfds = nfds;
-}
-
-void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
-{
- struct socket *so, *so_next;
- int ret;
-
- global_readfds = readfds;
- global_writefds = writefds;
- global_xfds = xfds;
-
- /* Update time */
- updtime();
-
- /*
- * See if anything has timed out
- */
- if (link_up) {
- if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
- tcp_fasttimo();
- time_fasttimo = 0;
- }
- if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
- ip_slowtimo();
- tcp_slowtimo();
- last_slowtimo = curtime;
- }
- }
-
- /*
- * Check sockets
- */
- if (link_up) {
- /*
- * Check TCP sockets
- */
- for (so = tcb.so_next; so != &tcb; so = so_next) {
- so_next = so->so_next;
-
- /*
- * FD_ISSET is meaningless on these sockets
- * (and they can crash the program)
- */
- if (so->so_state & SS_NOFDREF || so->s == -1)
- continue;
-
- /*
- * Check for URG data
- * This will soread as well, so no need to
- * test for readfds below if this succeeds
- */
- if (FD_ISSET(so->s, xfds))
- sorecvoob(so);
- /*
- * Check sockets for reading
- */
- else if (FD_ISSET(so->s, readfds)) {
- /*
- * Check for incoming connections
- */
- if (so->so_state & SS_FACCEPTCONN) {
- tcp_connect(so);
- continue;
- } /* else */
- ret = soread(so);
-
- /* Output it if we read something */
- if (ret > 0)
- tcp_output(sototcpcb(so));
- }
-
- /*
- * Check sockets for writing
- */
- if (FD_ISSET(so->s, writefds)) {
- /*
- * Check for non-blocking, still-connecting sockets
- */
- if (so->so_state & SS_ISFCONNECTING) {
- /* Connected */
- so->so_state &= ~SS_ISFCONNECTING;
-
- ret = send(so->s, &ret, 0, 0);
- if (ret < 0) {
- /* XXXXX Must fix, zero bytes is a NOP */
- if (errno == EAGAIN || errno == EWOULDBLOCK ||
- errno == EINPROGRESS || errno == ENOTCONN)
- continue;
-
- /* else failed */
- so->so_state = SS_NOFDREF;
- }
- /* else so->so_state &= ~SS_ISFCONNECTING; */
-
- /*
- * Continue tcp_input
- */
- tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
- /* continue; */
- } else
- ret = sowrite(so);
- /*
- * XXXXX If we wrote something (a lot), there
- * could be a need for a window update.
- * In the worst case, the remote will send
- * a window probe to get things going again
- */
- }
-
- /*
- * Probe a still-connecting, non-blocking socket
- * to check if it's still alive
- */
-#ifdef PROBE_CONN
- if (so->so_state & SS_ISFCONNECTING) {
- ret = recv(so->s, (char *)&ret, 0,0);
-
- if (ret < 0) {
- /* XXX */
- if (errno == EAGAIN || errno == EWOULDBLOCK ||
- errno == EINPROGRESS || errno == ENOTCONN)
- continue; /* Still connecting, continue */
-
- /* else failed */
- so->so_state = SS_NOFDREF;
-
- /* tcp_input will take care of it */
- } else {
- ret = send(so->s, &ret, 0,0);
- if (ret < 0) {
- /* XXX */
- if (errno == EAGAIN || errno == EWOULDBLOCK ||
- errno == EINPROGRESS || errno == ENOTCONN)
- continue;
- /* else failed */
- so->so_state = SS_NOFDREF;
- } else
- so->so_state &= ~SS_ISFCONNECTING;
-
- }
- tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
- } /* SS_ISFCONNECTING */
-#endif
- }
-
- /*
- * Now UDP sockets.
- * Incoming packets are sent straight away, they're not buffered.
- * Incoming UDP data isn't buffered either.
- */
- for (so = udb.so_next; so != &udb; so = so_next) {
- so_next = so->so_next;
-
- if (so->s != -1 && FD_ISSET(so->s, readfds)) {
- sorecvfrom(so);
- }
- }
- }
-
- /*
- * See if we can start outputting
- */
- if (if_queued && link_up)
- if_start();
-
- /* clear global file descriptor sets.
- * these reside on the stack in vl.c
- * so they're unusable if we're not in
- * slirp_select_fill or slirp_select_poll.
- */
- global_readfds = NULL;
- global_writefds = NULL;
- global_xfds = NULL;
-}
-
-#define ETH_ALEN 6
-#define ETH_HLEN 14
-
-#define ETH_P_IP 0x0800 /* Internet Protocol packet */
-#define ETH_P_ARP 0x0806 /* Address Resolution packet */
-
-#define ARPOP_REQUEST 1 /* ARP request */
-#define ARPOP_REPLY 2 /* ARP reply */
-
-struct ethhdr
-{
- unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
- unsigned char h_source[ETH_ALEN]; /* source ether addr */
- unsigned short h_proto; /* packet type ID field */
-};
-
-struct arphdr
-{
- unsigned short ar_hrd; /* format of hardware address */
- unsigned short ar_pro; /* format of protocol address */
- unsigned char ar_hln; /* length of hardware address */
- unsigned char ar_pln; /* length of protocol address */
- unsigned short ar_op; /* ARP opcode (command) */
-
- /*
- * Ethernet looks like this : This bit is variable sized however...
- */
- unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
- unsigned char ar_sip[4]; /* sender IP address */
- unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
- unsigned char ar_tip[4]; /* target IP address */
-};
-
-static void arp_input(const uint8_t *pkt, int pkt_len)
-{
- struct ethhdr *eh = (struct ethhdr *)pkt;
- struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
- uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
- struct ethhdr *reh = (struct ethhdr *)arp_reply;
- struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
- int ar_op;
- struct ex_list *ex_ptr;
-
- ar_op = ntohs(ah->ar_op);
- switch(ar_op) {
- case ARPOP_REQUEST:
- if (!memcmp(ah->ar_tip, &special_addr, 3)) {
- if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
- goto arp_ok;
- for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
- if (ex_ptr->ex_addr == ah->ar_tip[3])
- goto arp_ok;
- }
- return;
- arp_ok:
- /* XXX: make an ARP request to have the client address */
- memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
-
- /* ARP request for alias/dns mac address */
- memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
- memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
- reh->h_source[5] = ah->ar_tip[3];
- reh->h_proto = htons(ETH_P_ARP);
-
- rah->ar_hrd = htons(1);
- rah->ar_pro = htons(ETH_P_IP);
- rah->ar_hln = ETH_ALEN;
- rah->ar_pln = 4;
- rah->ar_op = htons(ARPOP_REPLY);
- memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
- memcpy(rah->ar_sip, ah->ar_tip, 4);
- memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
- memcpy(rah->ar_tip, ah->ar_sip, 4);
- slirp_output(arp_reply, sizeof(arp_reply));
- }
- break;
- case ARPOP_REPLY:
- /* reply to request of client mac address ? */
- if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
- !memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) {
- memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
- }
- break;
- default:
- break;
- }
-}
-
-void slirp_input(const uint8_t *pkt, int pkt_len)
-{
- struct mbuf *m;
- int proto;
-
- if (pkt_len < ETH_HLEN)
- return;
-
- proto = ntohs(*(uint16_t *)(pkt + 12));
- switch(proto) {
- case ETH_P_ARP:
- arp_input(pkt, pkt_len);
- break;
- case ETH_P_IP:
- m = m_get();
- if (!m)
- return;
- /* Note: we add to align the IP header */
- if (M_FREEROOM(m) < pkt_len + 2) {
- m_inc(m, pkt_len + 2);
- }
- m->m_len = pkt_len + 2;
- memcpy(m->m_data + 2, pkt, pkt_len);
-
- m->m_data += 2 + ETH_HLEN;
- m->m_len -= 2 + ETH_HLEN;
-
- ip_input(m);
- break;
- default:
- break;
- }
-}
-
-/* output the IP packet to the ethernet device */
-void if_encap(const uint8_t *ip_data, int ip_data_len)
-{
- uint8_t buf[1600];
- struct ethhdr *eh = (struct ethhdr *)buf;
-
- if (ip_data_len + ETH_HLEN > sizeof(buf))
- return;
-
- if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
- uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
- struct ethhdr *reh = (struct ethhdr *)arp_req;
- struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
- const struct ip *iph = (const struct ip *)ip_data;
-
- /* If the client addr is not known, there is no point in
- sending the packet to it. Normally the sender should have
- done an ARP request to get its MAC address. Here we do it
- in place of sending the packet and we hope that the sender
- will retry sending its packet. */
- memset(reh->h_dest, 0xff, ETH_ALEN);
- memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
- reh->h_source[5] = CTL_ALIAS;
- reh->h_proto = htons(ETH_P_ARP);
- rah->ar_hrd = htons(1);
- rah->ar_pro = htons(ETH_P_IP);
- rah->ar_hln = ETH_ALEN;
- rah->ar_pln = 4;
- rah->ar_op = htons(ARPOP_REQUEST);
- /* source hw addr */
- memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
- rah->ar_sha[5] = CTL_ALIAS;
- /* source IP */
- memcpy(rah->ar_sip, &alias_addr, 4);
- /* target hw addr (none) */
- memset(rah->ar_tha, 0, ETH_ALEN);
- /* target IP */
- memcpy(rah->ar_tip, &iph->ip_dst, 4);
- client_ipaddr = iph->ip_dst;
- slirp_output(arp_req, sizeof(arp_req));
- } else {
- memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
- memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
- /* XXX: not correct */
- eh->h_source[5] = CTL_ALIAS;
- eh->h_proto = htons(ETH_P_IP);
- memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
- slirp_output(buf, ip_data_len + ETH_HLEN);
- }
-}
-
-int slirp_redir(int is_udp, int host_port,
- struct in_addr guest_addr, int guest_port)
-{
- if (is_udp) {
- if (!udp_listen(htons(host_port), guest_addr.s_addr,
- htons(guest_port), 0))
- return -1;
- } else {
- if (!solisten(htons(host_port), guest_addr.s_addr,
- htons(guest_port), 0))
- return -1;
- }
- return 0;
-}
-
-int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
- int guest_port)
-{
- return add_exec(&exec_list, do_pty, (char *)args,
- addr_low_byte, htons(guest_port));
-}
-
-ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
-{
- if (so->s == -1 && so->extra) {
- qemu_chr_write(so->extra, buf, len);
- return len;
- }
-
- return send(so->s, buf, len, flags);
-}
-
-static struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port)
-{
- struct socket *so;
-
- for (so = tcb.so_next; so != &tcb; so = so->so_next) {
- if ((so->so_faddr.s_addr & htonl(0xffffff00)) ==
- special_addr.s_addr
- && (ntohl(so->so_faddr.s_addr) & 0xff) ==
- addr_low_byte
- && htons(so->so_fport) == guest_port)
- return so;
- }
-
- return NULL;
-}
-
-size_t slirp_socket_can_recv(int addr_low_byte, int guest_port)
-{
- struct iovec iov[2];
- struct socket *so;
-
- if (!link_up)
- return 0;
-
- so = slirp_find_ctl_socket(addr_low_byte, guest_port);
-
- if (!so || so->so_state & SS_NOFDREF)
- return 0;
-
- if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
- return 0;
-
- return sopreprbuf(so, iov, NULL);
-}
-
-void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
- int size)
-{
- int ret;
- struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port);
-
- if (!so)
- return;
-
- ret = soreadbuf(so, (const char *)buf, size);
-
- if (ret > 0)
- tcp_output(sototcpcb(so));
-}
-
-static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp)
-{
- int i;
-
- qemu_put_sbe16(f, tp->t_state);
- for (i = 0; i < TCPT_NTIMERS; i++)
- qemu_put_sbe16(f, tp->t_timer[i]);
- qemu_put_sbe16(f, tp->t_rxtshift);
- qemu_put_sbe16(f, tp->t_rxtcur);
- qemu_put_sbe16(f, tp->t_dupacks);
- qemu_put_be16(f, tp->t_maxseg);
- qemu_put_sbyte(f, tp->t_force);
- qemu_put_be16(f, tp->t_flags);
- qemu_put_be32(f, tp->snd_una);
- qemu_put_be32(f, tp->snd_nxt);
- qemu_put_be32(f, tp->snd_up);
- qemu_put_be32(f, tp->snd_wl1);
- qemu_put_be32(f, tp->snd_wl2);
- qemu_put_be32(f, tp->iss);
- qemu_put_be32(f, tp->snd_wnd);
- qemu_put_be32(f, tp->rcv_wnd);
- qemu_put_be32(f, tp->rcv_nxt);
- qemu_put_be32(f, tp->rcv_up);
- qemu_put_be32(f, tp->irs);
- qemu_put_be32(f, tp->rcv_adv);
- qemu_put_be32(f, tp->snd_max);
- qemu_put_be32(f, tp->snd_cwnd);
- qemu_put_be32(f, tp->snd_ssthresh);
- qemu_put_sbe16(f, tp->t_idle);
- qemu_put_sbe16(f, tp->t_rtt);
- qemu_put_be32(f, tp->t_rtseq);
- qemu_put_sbe16(f, tp->t_srtt);
- qemu_put_sbe16(f, tp->t_rttvar);
- qemu_put_be16(f, tp->t_rttmin);
- qemu_put_be32(f, tp->max_sndwnd);
- qemu_put_byte(f, tp->t_oobflags);
- qemu_put_byte(f, tp->t_iobc);
- qemu_put_sbe16(f, tp->t_softerror);
- qemu_put_byte(f, tp->snd_scale);
- qemu_put_byte(f, tp->rcv_scale);
- qemu_put_byte(f, tp->request_r_scale);
- qemu_put_byte(f, tp->requested_s_scale);
- qemu_put_be32(f, tp->ts_recent);
- qemu_put_be32(f, tp->ts_recent_age);
- qemu_put_be32(f, tp->last_ack_sent);
-}
-
-static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
-{
- uint32_t off;
-
- qemu_put_be32(f, sbuf->sb_cc);
- qemu_put_be32(f, sbuf->sb_datalen);
- off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data);
- qemu_put_sbe32(f, off);
- off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data);
- qemu_put_sbe32(f, off);
- qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
-}
-
-static void slirp_socket_save(QEMUFile *f, struct socket *so)
-{
- qemu_put_be32(f, so->so_urgc);
- qemu_put_be32(f, so->so_faddr.s_addr);
- qemu_put_be32(f, so->so_laddr.s_addr);
- qemu_put_be16(f, so->so_fport);
- qemu_put_be16(f, so->so_lport);
- qemu_put_byte(f, so->so_iptos);
- qemu_put_byte(f, so->so_emu);
- qemu_put_byte(f, so->so_type);
- qemu_put_be32(f, so->so_state);
- slirp_sbuf_save(f, &so->so_rcv);
- slirp_sbuf_save(f, &so->so_snd);
- slirp_tcp_save(f, so->so_tcpcb);
-}
-
-static void slirp_state_save(QEMUFile *f, void *opaque)
-{
- struct ex_list *ex_ptr;
-
- for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
- if (ex_ptr->ex_pty == 3) {
- struct socket *so;
- so = slirp_find_ctl_socket(ex_ptr->ex_addr, ntohs(ex_ptr->ex_fport));
- if (!so)
- continue;
-
- qemu_put_byte(f, 42);
- slirp_socket_save(f, so);
- }
- qemu_put_byte(f, 0);
-}
-
-static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp)
-{
- int i;
-
- tp->t_state = qemu_get_sbe16(f);
- for (i = 0; i < TCPT_NTIMERS; i++)
- tp->t_timer[i] = qemu_get_sbe16(f);
- tp->t_rxtshift = qemu_get_sbe16(f);
- tp->t_rxtcur = qemu_get_sbe16(f);
- tp->t_dupacks = qemu_get_sbe16(f);
- tp->t_maxseg = qemu_get_be16(f);
- tp->t_force = qemu_get_sbyte(f);
- tp->t_flags = qemu_get_be16(f);
- tp->snd_una = qemu_get_be32(f);
- tp->snd_nxt = qemu_get_be32(f);
- tp->snd_up = qemu_get_be32(f);
- tp->snd_wl1 = qemu_get_be32(f);
- tp->snd_wl2 = qemu_get_be32(f);
- tp->iss = qemu_get_be32(f);
- tp->snd_wnd = qemu_get_be32(f);
- tp->rcv_wnd = qemu_get_be32(f);
- tp->rcv_nxt = qemu_get_be32(f);
- tp->rcv_up = qemu_get_be32(f);
- tp->irs = qemu_get_be32(f);
- tp->rcv_adv = qemu_get_be32(f);
- tp->snd_max = qemu_get_be32(f);
- tp->snd_cwnd = qemu_get_be32(f);
- tp->snd_ssthresh = qemu_get_be32(f);
- tp->t_idle = qemu_get_sbe16(f);
- tp->t_rtt = qemu_get_sbe16(f);
- tp->t_rtseq = qemu_get_be32(f);
- tp->t_srtt = qemu_get_sbe16(f);
- tp->t_rttvar = qemu_get_sbe16(f);
- tp->t_rttmin = qemu_get_be16(f);
- tp->max_sndwnd = qemu_get_be32(f);
- tp->t_oobflags = qemu_get_byte(f);
- tp->t_iobc = qemu_get_byte(f);
- tp->t_softerror = qemu_get_sbe16(f);
- tp->snd_scale = qemu_get_byte(f);
- tp->rcv_scale = qemu_get_byte(f);
- tp->request_r_scale = qemu_get_byte(f);
- tp->requested_s_scale = qemu_get_byte(f);
- tp->ts_recent = qemu_get_be32(f);
- tp->ts_recent_age = qemu_get_be32(f);
- tp->last_ack_sent = qemu_get_be32(f);
- tcp_template(tp);
-}
-
-static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf)
-{
- uint32_t off, sb_cc, sb_datalen;
-
- sb_cc = qemu_get_be32(f);
- sb_datalen = qemu_get_be32(f);
-
- sbreserve(sbuf, sb_datalen);
-
- if (sbuf->sb_datalen != sb_datalen)
- return -ENOMEM;
-
- sbuf->sb_cc = sb_cc;
-
- off = qemu_get_sbe32(f);
- sbuf->sb_wptr = sbuf->sb_data + off;
- off = qemu_get_sbe32(f);
- sbuf->sb_rptr = sbuf->sb_data + off;
- qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
-
- return 0;
-}
-
-static int slirp_socket_load(QEMUFile *f, struct socket *so)
-{
- if (tcp_attach(so) < 0)
- return -ENOMEM;
-
- so->so_urgc = qemu_get_be32(f);
- so->so_faddr.s_addr = qemu_get_be32(f);
- so->so_laddr.s_addr = qemu_get_be32(f);
- so->so_fport = qemu_get_be16(f);
- so->so_lport = qemu_get_be16(f);
- so->so_iptos = qemu_get_byte(f);
- so->so_emu = qemu_get_byte(f);
- so->so_type = qemu_get_byte(f);
- so->so_state = qemu_get_be32(f);
- if (slirp_sbuf_load(f, &so->so_rcv) < 0)
- return -ENOMEM;
- if (slirp_sbuf_load(f, &so->so_snd) < 0)
- return -ENOMEM;
- slirp_tcp_load(f, so->so_tcpcb);
-
- return 0;
-}
-
-static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
-{
- struct ex_list *ex_ptr;
- int r;
-
- while ((r = qemu_get_byte(f))) {
- int ret;
- struct socket *so = socreate();
-
- if (!so)
- return -ENOMEM;
-
- ret = slirp_socket_load(f, so);
-
- if (ret < 0)
- return ret;
-
- if ((so->so_faddr.s_addr & htonl(0xffffff00)) != special_addr.s_addr)
- return -EINVAL;
-
- for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
- if (ex_ptr->ex_pty == 3 &&
- (ntohl(so->so_faddr.s_addr) & 0xff) == ex_ptr->ex_addr &&
- so->so_fport == ex_ptr->ex_fport)
- break;
-
- if (!ex_ptr)
- return -EINVAL;
-
- so->extra = (void *)ex_ptr->ex_exec;
- }
-
- return 0;
-}
diff --git a/slirp.pc b/slirp.pc
new file mode 100644
index 0000000..d463103
--- /dev/null
+++ b/slirp.pc
@@ -0,0 +1,11 @@
+prefix=/usr/local
+exec_prefix=${prefix}
+libdir=/usr/lib64
+includedir=/usr/include
+
+Name: slirp
+Description: user network stack
+Version: 0.1.0
+Requires:
+Libs: -L${libdir} -lslirp
+Cflags: -I${includedir}/libslirp
diff --git a/slirp.h b/slirp_common.h
index d57fb12..41b206c 100644
--- a/slirp.h
+++ b/slirp_common.h
@@ -1,7 +1,6 @@
-#ifndef __COMMON_H__
-#define __COMMON_H__
+#ifndef __SLIRP_COMMON_H__
+#define __SLIRP_COMMON_H__
-#define CONFIG_QEMU
//#define DEBUG 1
@@ -14,14 +13,10 @@
#define STAT(expr) do { } while(0)
#endif
-#ifndef CONFIG_QEMU
-#include "version.h"
-#endif
-#include "config-host.h"
#include "slirp_config.h"
#ifdef _WIN32
-# include <inttypes.h>
+#include <inttypes.h>
typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t;
@@ -201,36 +196,6 @@ int inet_aton _P((const char *cp, struct in_addr *ia));
#include <sys/stropts.h>
#endif
-#include "debug.h"
-
-#include "ip.h"
-#include "tcp.h"
-#include "tcp_timer.h"
-#include "tcp_var.h"
-#include "tcpip.h"
-#include "udp.h"
-#include "icmp_var.h"
-#include "mbuf.h"
-#include "sbuf.h"
-#include "socket.h"
-#include "if.h"
-#include "main.h"
-#include "misc.h"
-#include "ctl.h"
-#ifdef USE_PPP
-#include "ppp/pppd.h"
-#include "ppp/ppp.h"
-#endif
-
-#include "bootp.h"
-#include "tftp.h"
-#include "libslirp.h"
-
-extern struct ttys *ttys_unit[MAX_INTERFACES];
-
-#ifndef NULL
-#define NULL (void *)0
-#endif
#ifndef FULL_BOLT
void if_start _P((void));
@@ -275,44 +240,7 @@ void lprint _P((const char *, ...));
#define SO_OPTIONS DO_KEEPALIVE
#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL)
-/* cksum.c */
-int cksum(struct mbuf *m, int len);
-
-/* if.c */
-void if_init _P((void));
-void if_output _P((struct socket *, struct mbuf *));
-
-/* ip_input.c */
-void ip_init _P((void));
-void ip_input _P((struct mbuf *));
-void ip_slowtimo _P((void));
-void ip_stripoptions _P((register struct mbuf *, struct mbuf *));
-
-/* ip_output.c */
-int ip_output _P((struct socket *, struct mbuf *));
-
-/* tcp_input.c */
-void tcp_input _P((register struct mbuf *, int, struct socket *));
-int tcp_mss _P((register struct tcpcb *, u_int));
-
-/* tcp_output.c */
-int tcp_output _P((register struct tcpcb *));
-void tcp_setpersist _P((register struct tcpcb *));
-
-/* tcp_subr.c */
-void tcp_init _P((void));
-void tcp_template _P((struct tcpcb *));
-void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int));
-struct tcpcb * tcp_newtcpcb _P((struct socket *));
-struct tcpcb * tcp_close _P((register struct tcpcb *));
-void tcp_sockclosed _P((struct tcpcb *));
-int tcp_fconnect _P((struct socket *));
-void tcp_connect _P((struct socket *));
-int tcp_attach _P((struct socket *));
-u_int8_t tcp_tos _P((struct socket *));
-int tcp_emu _P((struct socket *, struct mbuf *));
-int tcp_ctl _P((struct socket *));
-struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
+
#ifdef USE_PPP
#define MIN_MRU MINMRU
@@ -332,4 +260,84 @@ struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
#define errno (WSAGetLastError())
#endif
+#include "net_slirp.h"
+#include "debug.h"
+#include "misc.h"
+#include "ctl.h"
+
+
+extern struct ttys *ttys_unit[MAX_INTERFACES];
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+#define FALSE 0
+#define TRUE 1
+
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#define TOWRITEMAX 512
+
+extern struct timeval tt;
+extern int link_up;
+extern int slirp_socket;
+extern int slirp_socket_unit;
+extern int slirp_socket_port;
+extern u_int32_t slirp_socket_addr;
+extern char *slirp_socket_passwd;
+extern int ctty_closed;
+
+/*
+ * Get the difference in 2 times from updtim()
+ * Allow for wraparound times, "just in case"
+ * x is the greater of the 2 (current time) and y is
+ * what it's being compared against.
+ */
+#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y)
+
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER)
+#endif
+#ifndef container_of
+#define container_of(ptr, type, member) ({ \
+ const typeof(((type *) 0)->member) *__mptr = (ptr); \
+ (type *) ((char *) __mptr - offsetof(type, member));})
+#endif
+
+
+extern char *slirp_tty;
+extern char *exec_shell;
+extern u_int curtime;
+extern fd_set *global_readfds, *global_writefds, *global_xfds;
+extern struct in_addr ctl_addr;
+extern struct in_addr special_addr;
+extern struct in_addr alias_addr;
+extern struct in_addr our_addr;
+extern struct in_addr loopback_addr;
+extern struct in_addr dns_addr;
+extern char *username;
+extern char *socket_path;
+extern int towrite_max;
+extern int ppp_exit;
+extern int tcp_keepintvl;
+extern uint8_t client_ethaddr[6];
+extern char slirp_hostname[33];
+extern const char *slirp_special_ip;
+
+#define PROTO_SLIP 0x1
+#ifdef USE_PPP
+#define PROTO_PPP 0x2
#endif
+
+extern const uint8_t zero_ethaddr[6];
+extern const uint8_t special_ethaddr[6];
+extern struct in_addr client_ipaddr;
+
+extern SlirpUsrNetworkInterface *slirp_net_interface;
+#endif
+
diff --git a/socket.c b/socket.c
index 9def541..cc027e6 100644
--- a/socket.c
+++ b/socket.c
@@ -5,14 +5,20 @@
* terms and conditions of the copyright.
*/
-#include "qemu-common.h"
#define WANT_SYS_IOCTL_H
-#include <slirp.h>
+#include "slirp_common.h"
#include "ip_icmp.h"
+#include "socket.h"
+#include "tcp.h"
+#include "udp.h"
+
#ifdef __sun__
#include <sys/filio.h>
#endif
+#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
+#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
+
static void sofcantrcvmore(struct socket *so);
static void sofcantsendmore(struct socket *so);
@@ -62,7 +68,7 @@ socreate()
if(so) {
memset(so, 0, sizeof(struct socket));
so->so_state = SS_NOFDREF;
- so->s = -1;
+ so->usr_so = NULL;
}
return(so);
}
@@ -174,12 +180,8 @@ soread(so)
*/
sopreprbuf(so, iov, &n);
-#ifdef HAVE_READV
- nn = readv(so->s, (struct iovec *)iov, n);
- DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
-#else
- nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
-#endif
+ nn = slirp_net_interface->recv(slirp_net_interface, so->usr_so, iov[0].iov_base, iov[0].iov_len);
+
if (nn <= 0) {
if (nn < 0 && (errno == EINTR || errno == EAGAIN))
return 0;
@@ -191,7 +193,6 @@ soread(so)
}
}
-#ifndef HAVE_READV
/*
* If there was no error, try and read the second time round
* We read again if n = 2 (ie, there's another part of the buffer)
@@ -203,13 +204,15 @@ soread(so)
*/
if (n == 2 && nn == iov[0].iov_len) {
int ret;
- ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
+
+ ret = slirp_net_interface->recv(slirp_net_interface, so->usr_so,
+ iov[1].iov_base, iov[1].iov_len);
if (ret > 0)
nn += ret;
}
DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
-#endif
+
/* Update fields */
sb->sb_cc += nn;
@@ -219,47 +222,6 @@ soread(so)
return nn;
}
-int soreadbuf(struct socket *so, const char *buf, int size)
-{
- int n, nn, copy = size;
- struct sbuf *sb = &so->so_snd;
- struct iovec iov[2];
-
- DEBUG_CALL("soreadbuf");
- DEBUG_ARG("so = %lx", (long )so);
-
- /*
- * No need to check if there's enough room to read.
- * soread wouldn't have been called if there weren't
- */
- if (sopreprbuf(so, iov, &n) < size)
- goto err;
-
- nn = MIN(iov[0].iov_len, copy);
- memcpy(iov[0].iov_base, buf, nn);
-
- copy -= nn;
- buf += nn;
-
- if (copy == 0)
- goto done;
-
- memcpy(iov[1].iov_base, buf, copy);
-
-done:
- /* Update fields */
- sb->sb_cc += size;
- sb->sb_wptr += size;
- if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
- sb->sb_wptr -= sb->sb_datalen;
- return size;
-err:
-
- sofcantrcvmore(so);
- tcp_sockclosed(sototcpcb(so));
- fprintf(stderr, "soreadbuf buffer to small");
- return -1;
-}
/*
* Get urgent data
@@ -313,8 +275,9 @@ sosendoob(so)
so->so_urgc = 2048; /* XXXX */
if (sb->sb_rptr < sb->sb_wptr) {
- /* We can send it directly */
- n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
+ n = slirp_net_interface->send(slirp_net_interface, so->usr_so, (uint8_t *)sb->sb_rptr,
+ so->so_urgc, 1);
+
so->so_urgc -= n;
DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
@@ -335,7 +298,9 @@ sosendoob(so)
so->so_urgc -= n;
len += n;
}
- n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
+ n = slirp_net_interface->send(slirp_net_interface, so->usr_so,
+ (uint8_t *)buff, len, 1);
+
#ifdef DEBUG
if (n != len)
DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
@@ -402,13 +367,8 @@ sowrite(so)
}
/* Check if there's urgent data to send, and if so, send it */
-#ifdef HAVE_READV
- nn = writev(so->s, (const struct iovec *)iov, n);
+ nn = slirp_net_interface->send(slirp_net_interface, so->usr_so, iov[0].iov_base, iov[0].iov_len, 0);
- DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn));
-#else
- nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0);
-#endif
/* This should never happen, but people tell me it does *shrug* */
if (nn < 0 && (errno == EAGAIN || errno == EINTR))
return 0;
@@ -421,15 +381,15 @@ sowrite(so)
return -1;
}
-#ifndef HAVE_READV
if (n == 2 && nn == iov[0].iov_len) {
- int ret;
- ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0);
+ int ret;
+ ret = slirp_net_interface->send(slirp_net_interface, so->usr_so,
+ iov[1].iov_base, iov[1].iov_len, 0);
+
if (ret > 0)
nn += ret;
}
DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn));
-#endif
/* Update sbuf */
sb->sb_cc -= nn;
@@ -447,6 +407,76 @@ sowrite(so)
return nn;
}
+void sotrysend (struct socket *so)
+{
+ if (so->so_state & SS_NOFDREF)
+ return;
+
+ if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
+ sowrite(so);
+ }
+}
+int sotryrecv(struct socket *so)
+{
+ int ret = 0;
+ if (so->so_state & SS_NOFDREF)
+ return 0;
+ if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
+ ret = soread(so);
+ }
+ return ret;
+}
+
+void sodropacked (struct socket *so, int acked)
+{
+ sbdrop(&so->so_snd, acked);
+}
+
+
+#if 0 // UDP and socket listen
+int soreadbuf(struct socket *so, const char *buf, int size)
+{
+ int n, nn, copy = size;
+ struct sbuf *sb = &so->so_snd;
+ struct iovec iov[2];
+
+ DEBUG_CALL("soreadbuf");
+ DEBUG_ARG("so = %lx", (long )so);
+
+ /*
+ * No need to check if there's enough room to read.
+ * soread wouldn't have been called if there weren't
+ */
+ if (sopreprbuf(so, iov, &n) < size)
+ goto err;
+
+ nn = min(iov[0].iov_len, copy);
+ memcpy(iov[0].iov_base, buf, nn);
+
+ copy -= nn;
+ buf += nn;
+
+ if (copy == 0)
+ goto done;
+
+ memcpy(iov[1].iov_base, buf, copy);
+
+done:
+ /* Update fields */
+ sb->sb_cc += size;
+ sb->sb_wptr += size;
+ if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
+ sb->sb_wptr -= sb->sb_datalen;
+ return size;
+err:
+
+ sofcantrcvmore(so);
+ tcp_sockclosed(sototcpcb(so));
+ fprintf(stderr, "soreadbuf buffer to small");
+ return -1;
+}
+
+
/*
* recvfrom() a UDP socket
*/
@@ -672,6 +702,8 @@ solisten(port, laddr, lport, flags)
return so;
}
+#endif
+
#if 0
/*
* Data is available in so_rcv
@@ -725,12 +757,10 @@ soisfconnected(so)
static void
sofcantrcvmore(struct socket *so)
{
- if ((so->so_state & SS_NOFDREF) == 0) {
- shutdown(so->s,0);
- if(global_writefds) {
- FD_CLR(so->s,global_writefds);
- }
- }
+ if ((so->so_state & SS_NOFDREF) == 0) {
+ slirp_net_interface->shutdown_recv(slirp_net_interface, so->usr_so);
+ }
+
so->so_state &= ~(SS_ISFCONNECTING);
if (so->so_state & SS_FCANTSENDMORE)
so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */
@@ -741,15 +771,10 @@ sofcantrcvmore(struct socket *so)
static void
sofcantsendmore(struct socket *so)
{
- if ((so->so_state & SS_NOFDREF) == 0) {
- shutdown(so->s,1); /* send FIN to fhost */
- if (global_readfds) {
- FD_CLR(so->s,global_readfds);
- }
- if (global_xfds) {
- FD_CLR(so->s,global_xfds);
- }
- }
+ if ((so->so_state & SS_NOFDREF) == 0) {
+ slirp_net_interface->shutdown_send(slirp_net_interface, so->usr_so);
+ }
+
so->so_state &= ~(SS_ISFCONNECTING);
if (so->so_state & SS_FCANTRCVMORE)
so->so_state = SS_NOFDREF; /* as above */
@@ -782,3 +807,68 @@ sofwdrain(so)
else
sofcantsendmore(so);
}
+
+/*
+ * Try and write() to the socket, whatever doesn't get written
+ * append to the buffer... for a host with a fast net connection,
+ * this prevents an unnecessary copy of the data
+ * (the socket is non-blocking, so we won't hang)
+ */
+void
+sosbappend(so, m)
+ struct socket *so;
+ struct mbuf *m;
+{
+ int ret = 0;
+
+ DEBUG_CALL("sbappend");
+ DEBUG_ARG("so = %lx", (long)so);
+ DEBUG_ARG("m = %lx", (long)m);
+ DEBUG_ARG("m->m_len = %d", m->m_len);
+
+ /* Shouldn't happen, but... e.g. foreign host closes connection */
+ if (m->m_len <= 0) {
+ m_free(m);
+ return;
+ }
+
+ /*
+ * If there is urgent data, call sosendoob
+ * if not all was sent, sowrite will take care of the rest
+ * (The rest of this function is just an optimisation)
+ */
+ if (so->so_urgc) {
+ sbappendsb(&so->so_rcv, m);
+ m_free(m);
+ sosendoob(so);
+ return;
+ }
+
+ /*
+ * We only write if there's nothing in the buffer,
+ * ottherwise it'll arrive out of order, and hence corrupt
+ */
+ if (!so->so_rcv.sb_cc){
+ ret = slirp_net_interface->send(slirp_net_interface, so->usr_so, (uint8_t*)m->m_data, m->m_len, 0);
+ }
+
+ if (ret <= 0) {
+ /*
+ * Nothing was written
+ * It's possible that the socket has closed, but
+ * we don't need to check because if it has closed,
+ * it will be detected in the normal way by soread()
+ */
+ sbappendsb(&so->so_rcv, m);
+ } else if (ret != m->m_len) {
+ /*
+ * Something was written, but not everything..
+ * sbappendsb the rest
+ */
+ m->m_len -= ret;
+ m->m_data += ret;
+ sbappendsb(&so->so_rcv, m);
+ } /* else */
+ /* Whatever happened, we free the mbuf */
+ m_free(m);
+}
diff --git a/socket.h b/socket.h
index 72b473d..fc392e2 100644
--- a/socket.h
+++ b/socket.h
@@ -10,6 +10,9 @@
#ifndef _SLIRP_SOCKET_H_
#define _SLIRP_SOCKET_H_
+#include "sbuf.h"
+#include "mbuf.h"
+
#define SO_EXPIRE 240000
#define SO_EXPIREFAST 10000
@@ -19,9 +22,8 @@
struct socket {
struct socket *so_next,*so_prev; /* For a linked list of sockets */
-
- int s; /* The actual socket */
-
+ void *usr_so;
+
/* XXX union these with not-yet-used sbuf params */
struct mbuf *so_m; /* Pointer to the original SYN packet,
* for non-blocking connect()'s, and
@@ -73,6 +75,7 @@ struct socket {
extern struct socket tcb;
+
struct socket * solookup _P((struct socket *, struct in_addr, u_int, struct in_addr, u_int));
struct socket * socreate _P((void));
void sofree _P((struct socket *));
@@ -80,14 +83,24 @@ int soread _P((struct socket *));
void sorecvoob _P((struct socket *));
int sosendoob _P((struct socket *));
int sowrite _P((struct socket *));
-void sorecvfrom _P((struct socket *));
-int sosendto _P((struct socket *, struct mbuf *));
-struct socket * solisten _P((u_int, u_int32_t, u_int, int));
+
+
+void sotrysend _P((struct socket *));
+int sotryrecv _P((struct socket *));
+void sodropacked _P((struct socket *, int));
+
void soisfconnecting _P((register struct socket *));
void soisfconnected _P((register struct socket *));
void soisfdisconnected _P((struct socket *));
void sofwdrain _P((struct socket *));
size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
-int soreadbuf(struct socket *so, const char *buf, int size);
+void sosbappend _P((struct socket *, struct mbuf *));
+
+#if 0 // UDP and socket listen
+int soreadbuf(struct socket *so, const char *buf, int size);
+void sorecvfrom _P((struct socket *));
+int sosendto _P((struct socket *, struct mbuf *));
+struct socket * solisten _P((u_int, u_int32_t, u_int, int));
+#endif
#endif /* _SOCKET_H_ */
diff --git a/tcp.h b/tcp.h
index 1115076..af4ca14 100644
--- a/tcp.h
+++ b/tcp.h
@@ -37,6 +37,10 @@
#ifndef _TCP_H_
#define _TCP_H_
+#include "slirp_common.h"
+#include "mbuf.h"
+#include "socket.h"
+
typedef u_int32_t tcp_seq;
#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */
@@ -169,7 +173,29 @@ struct tcphdr {
#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */
extern tcp_seq tcp_iss; /* tcp initial send seq # */
-
+extern struct socket tcb;
extern const char * const tcpstates[];
+/* tcp_input */
+void tcp_input(register struct mbuf *m, int iphlen, struct socket *inso);
+int tcp_mss _P((register struct tcpcb *, u_int));
+
+/* tcp_output */
+int tcp_output _P((register struct tcpcb *));
+void tcp_setpersist _P((register struct tcpcb *));
+
+/* tcp_subr */
+void tcp_init _P((void));
+void tcp_template _P((struct tcpcb *));
+void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int));
+struct tcpcb * tcp_newtcpcb _P((struct socket *));
+struct tcpcb * tcp_close _P((register struct tcpcb *));
+int tcp_fconnect _P((struct socket *));
+struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
+int tcp_attach _P((struct socket *));
+u_int8_t tcp_tos _P((struct socket *));
+int tcp_emu _P((struct socket *, struct mbuf *));
+int tcp_ctl _P((struct socket *));
+void tcp_sockclosed _P((struct tcpcb *));
+
#endif
diff --git a/tcp_input.c b/tcp_input.c
index f324adb..f8ac7cd 100644
--- a/tcp_input.c
+++ b/tcp_input.c
@@ -42,8 +42,18 @@
* terms and conditions of the copyright.
*/
-#include <slirp.h>
+#include "tcp.h"
+#include "tcpip.h"
+#include "ip.h"
+#include "if.h"
+#include "slirp_common.h"
#include "ip_icmp.h"
+#include "sbuf.h"
+#include "cksum.h"
+#include "tcp_timer.h"
+#include "misc.h"
+#include "mbuf.h"
+#include "socket.h"
struct socket tcb;
@@ -82,9 +92,9 @@ tcp_seq tcp_iss; /* tcp initial send seq # */
STAT(tcpstat.tcps_rcvpack++); \
STAT(tcpstat.tcps_rcvbyte += (ti)->ti_len); \
if (so->so_emu) { \
- if (tcp_emu((so),(m))) sbappend((so), (m)); \
+ if (tcp_emu((so),(m))) sosbappend((so), (m)); \
} else \
- sbappend((so), (m)); \
+ sosbappend((so), (m)); \
/* sorwakeup(so); */ \
} else {\
(flags) = tcp_reass((tp), (ti), (m)); \
@@ -102,9 +112,9 @@ tcp_seq tcp_iss; /* tcp initial send seq # */
STAT(tcpstat.tcps_rcvpack++); \
STAT(tcpstat.tcps_rcvbyte += (ti)->ti_len); \
if (so->so_emu) { \
- if (tcp_emu((so),(m))) sbappend(so, (m)); \
+ if (tcp_emu((so),(m))) sosbappend(so, (m)); \
} else \
- sbappend((so), (m)); \
+ sosbappend((so), (m)); \
/* sorwakeup(so); */ \
} else { \
(flags) = tcp_reass((tp), (ti), (m)); \
@@ -112,6 +122,7 @@ tcp_seq tcp_iss; /* tcp initial send seq # */
} \
}
#endif
+
static void tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt,
struct tcpiphdr *ti);
static void tcp_xmit_timer(register struct tcpcb *tp, int rtt);
@@ -220,24 +231,43 @@ present:
m_freem(m);
else {
if (so->so_emu) {
- if (tcp_emu(so,m)) sbappend(so, m);
+ if (tcp_emu(so,m)) sosbappend(so, m);
} else
- sbappend(so, m);
+ sosbappend(so, m);
}
} while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
/* sorwakeup(so); */
return (flags);
}
+static void
+tcp_input1(register struct mbuf *m, int iphlen, struct socket *inso,
+ int *drop_acked, struct socket **outso);
+
+void tcp_input(m, iphlen, inso)
+ register struct mbuf *m;
+ int iphlen;
+ struct socket *inso;
+{
+ int drop_acked = 0;
+ struct socket *so = NULL;
+ tcp_input1(m, iphlen, inso, &drop_acked, &so);
+ if (drop_acked && so) {
+ sotryrecv(so);
+ }
+}
/*
* TCP input routine, follows pages 65-76 of the
* protocol specification dated September, 1981 very closely.
+ * outso is valid only when drop_acked is true
*/
-void
-tcp_input(m, iphlen, inso)
+static void
+tcp_input1(m, iphlen, inso, drop_acked, outso)
register struct mbuf *m;
int iphlen;
struct socket *inso;
+ int *drop_acked;
+ struct socket **outso;
{
struct ip save_ip, *ip;
register struct tcpiphdr *ti;
@@ -253,7 +283,7 @@ tcp_input(m, iphlen, inso)
u_long tiwin;
int ret;
/* int ts_present = 0; */
- struct ex_list *ex_ptr;
+ *drop_acked = 0;
DEBUG_CALL("tcp_input");
DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n",
@@ -365,15 +395,7 @@ tcp_input(m, iphlen, inso)
m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
- if (slirp_restrict) {
- for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
- if (ex_ptr->ex_fport == ti->ti_dport &&
- (ntohl(ti->ti_dst.s_addr) & 0xff) == ex_ptr->ex_addr)
- break;
- if (!ex_ptr)
- goto drop;
- }
/*
* Locate pcb for segment.
*/
@@ -525,7 +547,11 @@ findso:
acked = ti->ti_ack - tp->snd_una;
STAT(tcpstat.tcps_rcvackpack++);
STAT(tcpstat.tcps_rcvackbyte += acked);
- sbdrop(&so->so_snd, acked);
+
+ sodropacked(so, acked);
+ *drop_acked = 1;
+ *outso = so;
+
tp->snd_una = ti->ti_ack;
m_freem(m);
@@ -576,9 +602,9 @@ findso:
* Add data to socket buffer.
*/
if (so->so_emu) {
- if (tcp_emu(so,m)) sbappend(so, m);
+ if (tcp_emu(so,m)) sosbappend(so, m);
} else
- sbappend(so, m);
+ sosbappend(so, m);
/*
* XXX This is called when data arrives. Later, check
@@ -646,35 +672,13 @@ findso:
* If this is destined for the control address, then flag to
* tcp_ctl once connected, otherwise connect
*/
- if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) {
- int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff;
- if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) {
-#if 0
- if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) {
- /* Command or exec adress */
- so->so_state |= SS_CTL;
- } else
-#endif
- {
- /* May be an add exec */
- for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
- if(ex_ptr->ex_fport == so->so_fport &&
- lastbyte == ex_ptr->ex_addr) {
- so->so_state |= SS_CTL;
- break;
- }
- }
- }
- if(so->so_state & SS_CTL) goto cont_input;
- }
- /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
- }
if (so->so_emu & EMU_NOCONNECT) {
so->so_emu &= ~EMU_NOCONNECT;
goto cont_input;
}
+
if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
u_char code=ICMP_UNREACH_NET;
DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",
@@ -683,6 +687,7 @@ findso:
/* ACK the SYN, send RST to refuse the connection */
tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0,
TH_RST|TH_ACK);
+ tp = tcp_close(tp);
} else {
if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
HTONL(ti->ti_seq); /* restore tcp header */
@@ -693,9 +698,11 @@ findso:
m->m_len += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
*ip=save_ip;
icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno));
+ tp = tcp_close(tp);
+ m_free(m);
}
- tp = tcp_close(tp);
- m_free(m);
+
+ // if errno == ECONNREFUSED. tcp_respond will free m. icmp_error not. it copies it
} else {
/*
* Haven't connected yet, save the current mbuf
@@ -1202,10 +1209,16 @@ trimthenstep6:
}
if (acked > so->so_snd.sb_cc) {
tp->snd_wnd -= so->so_snd.sb_cc;
- sbdrop(&so->so_snd, (int )so->so_snd.sb_cc);
+ sodropacked(so, (int)so->so_snd.sb_cc);
+ *drop_acked = 1;
+ *outso = so;
+
ourfinisacked = 1;
} else {
- sbdrop(&so->so_snd, acked);
+ sodropacked(so, acked);
+ *drop_acked = 1;
+ *outso = so;
+
tp->snd_wnd -= acked;
ourfinisacked = 0;
}
@@ -1382,7 +1395,7 @@ dodata:
/*
* If we receive a FIN we can't send more data,
* set it SS_FDRAIN
- * Shutdown the socket if there is no rx data in the
+ * Shutdown the socket if there is no rx data in the
* buffer.
* soread() is called on completion of shutdown() and
* will got to TCPS_LAST_ACK, and use tcp_output()
@@ -1732,3 +1745,4 @@ tcp_mss(tp, offer)
return mss;
}
+
diff --git a/tcp_output.c b/tcp_output.c
index dba4ed7..4f252c0 100644
--- a/tcp_output.c
+++ b/tcp_output.c
@@ -42,7 +42,15 @@
* terms and conditions of the copyright.
*/
-#include <slirp.h>
+#include "tcp.h"
+#include "tcpip.h"
+#include "ip.h"
+#include "if.h"
+#include "slirp_common.h"
+#include "ip_icmp.h"
+#include "sbuf.h"
+#include "cksum.h"
+#include "tcp_timer.h"
/*
* Since this is only used in "stats socket", we give meaning
diff --git a/tcp_subr.c b/tcp_subr.c
index 497b988..15cc2df 100644
--- a/tcp_subr.c
+++ b/tcp_subr.c
@@ -43,7 +43,11 @@
*/
#define WANT_SYS_IOCTL_H
-#include <slirp.h>
+#include "tcp.h"
+#include "if.h"
+#include "slirp_common.h"
+#include "cksum.h"
+#include "misc.h"
/* patchable/settable parameters for tcp */
/* Don't do rfc1323 performance enhancements */
@@ -59,6 +63,7 @@ tcp_init()
tcb.so_next = tcb.so_prev = &tcb;
}
+
/*
* Create template to be used to send tcp packets on a connection.
* Call after host entry created, fills
@@ -290,7 +295,10 @@ tcp_close(tp)
/* clobber input socket cache if we're closing the cached connection */
if (so == tcp_last_so)
tcp_last_so = &tcb;
- closesocket(so->s);
+
+ if (so->usr_so) {
+ slirp_net_interface->close(slirp_net_interface, so->usr_so);
+ }
sbfree(&so->so_rcv);
sbfree(&so->so_snd);
sofree(so);
@@ -383,149 +391,50 @@ int tcp_fconnect(so)
struct socket *so;
{
int ret=0;
+ struct sockaddr_in addr;
DEBUG_CALL("tcp_fconnect");
DEBUG_ARG("so = %lx", (long )so);
- if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) {
- int opt, s=so->s;
- struct sockaddr_in addr;
-
- fd_nonblock(s);
- opt = 1;
- setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
- opt = 1;
- setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
-
addr.sin_family = AF_INET;
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
/* It's an alias */
switch(ntohl(so->so_faddr.s_addr) & 0xff) {
- case CTL_DNS:
- addr.sin_addr = dns_addr;
- break;
- case CTL_ALIAS:
- default:
- addr.sin_addr = loopback_addr;
- break;
+ case CTL_DNS:
+ addr.sin_addr = dns_addr;
+ printf("tcp_fconnect DNS not supported");
+ exit(-1);
+ break;
+ case CTL_ALIAS:
+ addr.sin_addr = loopback_addr;
+ printf("tcp_fconnect LOOPBACK not supported");
+ exit(-1);
+ break;
+ default:
+ addr.sin_addr = so->so_faddr; // should be part of the virtual netowk
+ break;
}
- } else
- addr.sin_addr = so->so_faddr;
+ } else {
+ addr.sin_addr = so->so_faddr;
+ }
addr.sin_port = so->so_fport;
DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
"addr.sin_addr.s_addr=%.16s\n",
ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
/* We don't care what port we get */
- ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
-
+ ret = slirp_net_interface->connect(slirp_net_interface, so->so_laddr, so->so_lport,
+ addr.sin_addr, addr.sin_port, so, &so->usr_so);
/*
* If it's not in progress, it failed, so we just return 0,
* without clearing SS_NOFDREF
*/
soisfconnecting(so);
- }
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
-tcp_connect(inso)
- struct socket *inso;
-{
- struct socket *so;
- struct sockaddr_in addr;
- socklen_t addrlen = sizeof(struct sockaddr_in);
- struct tcpcb *tp;
- int s, opt;
-
- DEBUG_CALL("tcp_connect");
- DEBUG_ARG("inso = %lx", (long)inso);
-
- /*
- * If it's an SS_ACCEPTONCE socket, no need to socreate()
- * another socket, just use the accept() socket.
- */
- if (inso->so_state & SS_FACCEPTONCE) {
- /* FACCEPTONCE already have a tcpcb */
- so = inso;
- } else {
- if ((so = socreate()) == NULL) {
- /* If it failed, get rid of the pending connection */
- closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen));
- return;
- }
- if (tcp_attach(so) < 0) {
- free(so); /* NOT sofree */
- return;
- }
- so->so_laddr = inso->so_laddr;
- so->so_lport = inso->so_lport;
- }
-
- (void) tcp_mss(sototcpcb(so), 0);
-
- if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) {
- tcp_close(sototcpcb(so)); /* This will sofree() as well */
- return;
- }
- fd_nonblock(s);
- opt = 1;
- setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
- opt = 1;
- setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
- opt = 1;
- setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int));
-
- so->so_fport = addr.sin_port;
- so->so_faddr = addr.sin_addr;
- /* Translate connections from localhost to the real hostname */
- if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
- so->so_faddr = alias_addr;
-
- /* Close the accept() socket, set right state */
- if (inso->so_state & SS_FACCEPTONCE) {
- closesocket(so->s); /* If we only accept once, close the accept() socket */
- so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */
- /* if it's not FACCEPTONCE, it's already NOFDREF */
- }
- so->s = s;
-
- so->so_iptos = tcp_tos(so);
- tp = sototcpcb(so);
-
- tcp_template(tp);
-
- /* 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 */
- STAT(tcpstat.tcps_connattempt++);
-
- tp->t_state = TCPS_SYN_SENT;
- tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
- tp->iss = tcp_iss;
- tcp_iss += TCP_ISSINCR/2;
- tcp_sendseqinit(tp);
- tcp_output(tp);
-}
-
-/*
* Attach a TCPCB to a socket.
*/
int
@@ -540,6 +449,7 @@ tcp_attach(so)
return 0;
}
+
/*
* Set the socket's type of service field
*/
@@ -559,773 +469,39 @@ static const struct tos_t tcptos[] = {
{0, 0, 0, 0}
};
-#ifdef CONFIG_QEMU
-static
-#endif
-struct emu_t *tcpemu = 0;
-
-/*
- * Return TOS according to the above table
- */
u_int8_t
tcp_tos(so)
struct socket *so;
{
+ return 0;
+#if 0
int i = 0;
- struct emu_t *emup;
while(tcptos[i].tos) {
if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
(tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
- so->so_emu = tcptos[i].emu;
return tcptos[i].tos;
}
i++;
}
- /* Nope, lets see if there's a user-added one */
- for (emup = tcpemu; emup; emup = emup->next) {
- if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
- (emup->lport && (ntohs(so->so_lport) == emup->lport))) {
- so->so_emu = emup->emu;
- return emup->tos;
- }
- }
-
return 0;
+#endif
}
-#if 0
-int do_echo = -1;
-#endif
-
-/*
- * 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 came 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
tcp_emu(so, m)
struct socket *so;
struct mbuf *m;
{
- u_int n1, n2, n3, n4, n5, n6;
- char buff[257];
- u_int32_t laddr;
- u_int lport;
- char *bptr;
-
- DEBUG_CALL("tcp_emu");
- DEBUG_ARG("so = %lx", (long)so);
- DEBUG_ARG("m = %lx", (long)m);
-
- switch(so->so_emu) {
- int x, i;
-
- case EMU_IDENT:
- /*
- * Identification protocol as per rfc-1413
- */
-
- {
- struct socket *tmpso;
- struct sockaddr_in addr;
- socklen_t addrlen = sizeof(struct sockaddr_in);
- struct sbuf *so_rcv = &so->so_rcv;
-
- memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
- so_rcv->sb_wptr += m->m_len;
- so_rcv->sb_rptr += m->m_len;
- m->m_data[m->m_len] = 0; /* NULL terminate */
- if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
- if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
- HTONS(n1);
- HTONS(n2);
- /* n2 is the one on our host */
- for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
- if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
- tmpso->so_lport == n2 &&
- tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
- tmpso->so_fport == n1) {
- if (getsockname(tmpso->s,
- (struct sockaddr *)&addr, &addrlen) == 0)
- n2 = ntohs(addr.sin_port);
- break;
- }
- }
- }
- so_rcv->sb_cc = snprintf(so_rcv->sb_data,
- so_rcv->sb_datalen,
- "%d,%d\r\n", n1, n2);
- so_rcv->sb_rptr = so_rcv->sb_data;
- so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
- }
- m_free(m);
- return 0;
- }
-
-#if 0
- case EMU_RLOGIN:
- /*
- * Rlogin emulation
- * First we accumulate all the initial option negotiation,
- * then fork_exec() rlogin according to the options
- */
- {
- int i, i2, n;
- char *ptr;
- char args[100];
- char term[100];
- struct sbuf *so_snd = &so->so_snd;
- struct sbuf *so_rcv = &so->so_rcv;
-
- /* First check if they have a priveladged port, or too much data has arrived */
- if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
- (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
- memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
- so_snd->sb_wptr += 18;
- so_snd->sb_cc += 18;
- tcp_sockclosed(sototcpcb(so));
- m_free(m);
- return 0;
- }
-
- /* Append the current data */
- memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
- so_rcv->sb_wptr += m->m_len;
- so_rcv->sb_rptr += m->m_len;
- m_free(m);
-
- /*
- * Check if we have all the initial options,
- * and build argument list to rlogin while we're here
- */
- n = 0;
- ptr = so_rcv->sb_data;
- args[0] = 0;
- term[0] = 0;
- while (ptr < so_rcv->sb_wptr) {
- if (*ptr++ == 0) {
- n++;
- if (n == 2) {
- sprintf(args, "rlogin -l %s %s",
- ptr, inet_ntoa(so->so_faddr));
- } else if (n == 3) {
- i2 = so_rcv->sb_wptr - ptr;
- for (i = 0; i < i2; i++) {
- if (ptr[i] == '/') {
- ptr[i] = 0;
-#ifdef HAVE_SETENV
- sprintf(term, "%s", ptr);
-#else
- sprintf(term, "TERM=%s", ptr);
-#endif
- ptr[i] = '/';
- break;
- }
- }
- }
- }
- }
-
- if (n != 4)
- return 0;
-
- /* We have it, set our term variable and fork_exec() */
-#ifdef HAVE_SETENV
- setenv("TERM", term, 1);
-#else
- putenv(term);
-#endif
- fork_exec(so, args, 2);
- term[0] = 0;
- so->so_emu = 0;
-
- /* And finally, send the client a 0 character */
- so_snd->sb_wptr[0] = 0;
- so_snd->sb_wptr++;
- so_snd->sb_cc++;
-
- return 0;
- }
-
- case EMU_RSH:
- /*
- * rsh emulation
- * First we accumulate all the initial option negotiation,
- * then rsh_exec() rsh according to the options
- */
- {
- int n;
- char *ptr;
- char *user;
- char *args;
- struct sbuf *so_snd = &so->so_snd;
- struct sbuf *so_rcv = &so->so_rcv;
-
- /* First check if they have a priveladged port, or too much data has arrived */
- if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
- (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
- memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
- so_snd->sb_wptr += 18;
- so_snd->sb_cc += 18;
- tcp_sockclosed(sototcpcb(so));
- m_free(m);
- return 0;
- }
-
- /* Append the current data */
- memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
- so_rcv->sb_wptr += m->m_len;
- so_rcv->sb_rptr += m->m_len;
- m_free(m);
-
- /*
- * Check if we have all the initial options,
- * and build argument list to rlogin while we're here
- */
- n = 0;
- ptr = so_rcv->sb_data;
- user="";
- args="";
- if (so->extra==NULL) {
- struct socket *ns;
- struct tcpcb* tp;
- int port=atoi(ptr);
- if (port <= 0) return 0;
- if (port > 1023 || port < 512) {
- memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
- so_snd->sb_wptr += 18;
- so_snd->sb_cc += 18;
- tcp_sockclosed(sototcpcb(so));
- return 0;
- }
- if ((ns=socreate()) == NULL)
- return 0;
- if (tcp_attach(ns)<0) {
- free(ns);
- return 0;
- }
-
- ns->so_laddr=so->so_laddr;
- ns->so_lport=htons(port);
-
- (void) tcp_mss(sototcpcb(ns), 0);
-
- ns->so_faddr=so->so_faddr;
- ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */
-
- if (ns->so_faddr.s_addr == 0 ||
- ns->so_faddr.s_addr == loopback_addr.s_addr)
- ns->so_faddr = alias_addr;
-
- ns->so_iptos = tcp_tos(ns);
- tp = sototcpcb(ns);
-
- tcp_template(tp);
-
- /* 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++;
- */
-
- /*soisfconnecting(ns);*/
-
- STAT(tcpstat.tcps_connattempt++);
-
- tp->t_state = TCPS_SYN_SENT;
- tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
- tp->iss = tcp_iss;
- tcp_iss += TCP_ISSINCR/2;
- tcp_sendseqinit(tp);
- tcp_output(tp);
- so->extra=ns;
- }
- while (ptr < so_rcv->sb_wptr) {
- if (*ptr++ == 0) {
- n++;
- if (n == 2) {
- user=ptr;
- } else if (n == 3) {
- args=ptr;
- }
- }
- }
-
- if (n != 4)
- return 0;
-
- rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args);
- so->so_emu = 0;
- so->extra=NULL;
-
- /* And finally, send the client a 0 character */
- so_snd->sb_wptr[0] = 0;
- so_snd->sb_wptr++;
- so_snd->sb_cc++;
-
- return 0;
- }
-
- case EMU_CTL:
- {
- int num;
- struct sbuf *so_snd = &so->so_snd;
- struct sbuf *so_rcv = &so->so_rcv;
-
- /*
- * If there is binary data here, we save it in so->so_m
- */
- if (!so->so_m) {
- int rxlen;
- char *rxdata;
- rxdata=mtod(m, char *);
- for (rxlen=m->m_len; rxlen; rxlen--) {
- if (*rxdata++ & 0x80) {
- so->so_m = m;
- return 0;
- }
- }
- } /* if(so->so_m==NULL) */
-
- /*
- * Append the line
- */
- sbappendsb(so_rcv, m);
-
- /* To avoid going over the edge of the buffer, we reset it */
- if (so_snd->sb_cc == 0)
- so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data;
-
- /*
- * A bit of a hack:
- * If the first packet we get here is 1 byte long, then it
- * was done in telnet character mode, therefore we must echo
- * the characters as they come. Otherwise, we echo nothing,
- * because in linemode, the line is already echoed
- * XXX two or more control connections won't work
- */
- if (do_echo == -1) {
- if (m->m_len == 1) do_echo = 1;
- else do_echo = 0;
- }
- if (do_echo) {
- sbappendsb(so_snd, m);
- m_free(m);
- tcp_output(sototcpcb(so)); /* XXX */
- } else
- m_free(m);
-
- num = 0;
- while (num < so->so_rcv.sb_cc) {
- if (*(so->so_rcv.sb_rptr + num) == '\n' ||
- *(so->so_rcv.sb_rptr + num) == '\r') {
- int n;
-
- *(so_rcv->sb_rptr + num) = 0;
- if (ctl_password && !ctl_password_ok) {
- /* Need a password */
- if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) {
- if (strcmp(buff, ctl_password) == 0) {
- ctl_password_ok = 1;
- n = sprintf(so_snd->sb_wptr,
- "Password OK.\r\n");
- goto do_prompt;
- }
- }
- n = sprintf(so_snd->sb_wptr,
- "Error: Password required, log on with \"pass PASSWORD\"\r\n");
- goto do_prompt;
- }
- cfg_quitting = 0;
- n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF);
- if (!cfg_quitting) {
- /* Register the printed data */
-do_prompt:
- so_snd->sb_cc += n;
- so_snd->sb_wptr += n;
- /* Add prompt */
- n = sprintf(so_snd->sb_wptr, "Slirp> ");
- so_snd->sb_cc += n;
- so_snd->sb_wptr += n;
- }
- /* Drop so_rcv data */
- so_rcv->sb_cc = 0;
- so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data;
- tcp_output(sototcpcb(so)); /* Send the reply */
- }
- num++;
- }
- return 0;
- }
-#endif
- case EMU_FTP: /* ftp */
- *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */
- if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
- /*
- * Need to emulate the PORT command
- */
- x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
- &n1, &n2, &n3, &n4, &n5, &n6, buff);
- if (x < 6)
- return 1;
-
- laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
- lport = htons((n5 << 8) | (n6));
-
- if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
- return 1;
-
- n6 = ntohs(so->so_fport);
-
- n5 = (n6 >> 8) & 0xff;
- n6 &= 0xff;
-
- laddr = ntohl(so->so_faddr.s_addr);
-
- n1 = ((laddr >> 24) & 0xff);
- n2 = ((laddr >> 16) & 0xff);
- n3 = ((laddr >> 8) & 0xff);
- n4 = (laddr & 0xff);
-
- m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
- "ORT %d,%d,%d,%d,%d,%d\r\n%s",
- n1, n2, n3, n4, n5, n6, x==7?buff:"");
- return 1;
- } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
- /*
- * Need to emulate the PASV response
- */
- x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
- &n1, &n2, &n3, &n4, &n5, &n6, buff);
- if (x < 6)
- return 1;
-
- laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
- lport = htons((n5 << 8) | (n6));
-
- if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
- return 1;
-
- n6 = ntohs(so->so_fport);
-
- n5 = (n6 >> 8) & 0xff;
- n6 &= 0xff;
-
- laddr = ntohl(so->so_faddr.s_addr);
-
- n1 = ((laddr >> 24) & 0xff);
- n2 = ((laddr >> 16) & 0xff);
- n3 = ((laddr >> 8) & 0xff);
- n4 = (laddr & 0xff);
-
- m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
- "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
- n1, n2, n3, n4, n5, n6, x==7?buff:"");
-
- 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.
- */
- so->so_emu = 0;
- for (lport = 0, i = 0; i < m->m_len-1; ++i) {
- if (m->m_data[i] < '0' || m->m_data[i] > '9')
- return 1; /* invalid number */
- lport *= 10;
- lport += m->m_data[i] - '0';
- }
- if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
- (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL)
- m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d",
- ntohs(so->so_fport)) + 1;
- return 1;
-
- case EMU_IRC:
- /*
- * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
- */
- *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
- if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
- return 1;
-
- /* The %256s is for the broken mIRC */
- if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
- if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
- return 1;
-
- m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += snprintf(bptr, m->m_hdr.mh_size,
- "DCC CHAT chat %lu %u%c\n",
- (unsigned long)ntohl(so->so_faddr.s_addr),
- ntohs(so->so_fport), 1);
- } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
- if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
- return 1;
-
- m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += snprintf(bptr, m->m_hdr.mh_size,
- "DCC SEND %s %lu %u %u%c\n", buff,
- (unsigned long)ntohl(so->so_faddr.s_addr),
- ntohs(so->so_fport), n1, 1);
- } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
- if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
- return 1;
-
- m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += snprintf(bptr, m->m_hdr.mh_size,
- "DCC MOVE %s %lu %u %u%c\n", buff,
- (unsigned long)ntohl(so->so_faddr.s_addr),
- ntohs(so->so_fport), n1, 1);
- }
- return 1;
-
- 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.
- */
-
- bptr = m->m_data;
- while (bptr < m->m_data + m->m_len) {
- u_short p;
- static int ra = 0;
- char ra_tbl[4];
-
- ra_tbl[0] = 0x50;
- ra_tbl[1] = 0x4e;
- ra_tbl[2] = 0x41;
- ra_tbl[3] = 0;
-
- switch (ra) {
- case 0:
- case 2:
- case 3:
- if (*bptr++ != ra_tbl[ra]) {
- ra = 0;
- continue;
- }
- break;
-
- case 1:
- /*
- * We may get 0x50 several times, ignore them
- */
- if (*bptr == 0x50) {
- ra = 1;
- bptr++;
- continue;
- } else if (*bptr++ != ra_tbl[ra]) {
- 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.
- */
- if (*(bptr + 1) == 0x02)
- bptr += 8;
- else
- bptr += 4;
- break;
-
- case 6:
- /* This is the field containing the port
- * number that RA-player is listening to.
- */
- lport = (((u_char*)bptr)[0] << 8)
- + ((u_char *)bptr)[1];
- if (lport < 6970)
- lport += 256; /* don't know why */
- if (lport < 6970 || lport > 7170)
- return 1; /* failed */
-
- /* try to get udp port between 6970 - 7170 */
- for (p = 6970; p < 7071; p++) {
- if (udp_listen( htons(p),
- so->so_laddr.s_addr,
- htons(lport),
- SS_FACCEPTONCE)) {
- break;
- }
- }
- if (p == 7071)
- p = 0;
- *(u_char *)bptr++ = (p >> 8) & 0xff;
- *(u_char *)bptr++ = p & 0xff;
- ra = 0;
- return 1; /* port redirected, we're done */
- break;
-
- default:
- ra = 0;
- }
- ra++;
- }
- return 1;
-
- default:
- /* Ooops, not emulated, won't call tcp_emu again */
- so->so_emu = 0;
- return 1;
- }
+ printf("Error tcp_emu not supported");
+ exit(-1);
}
-/*
- * Do misc. config of SLiRP while its running.
- * Return 0 if this connections is to be closed, 1 otherwise,
- * return 2 if this is a command-line connection
- */
int
tcp_ctl(so)
struct socket *so;
{
- struct sbuf *sb = &so->so_snd;
- int command;
- struct ex_list *ex_ptr;
- int do_pty;
- // struct socket *tmpso;
-
- DEBUG_CALL("tcp_ctl");
- DEBUG_ARG("so = %lx", (long )so);
-
-#if 0
- /*
- * Check if they're authorised
- */
- if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) {
- sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n");
- sb->sb_wptr += sb->sb_cc;
- return 0;
- }
-#endif
- command = (ntohl(so->so_faddr.s_addr) & 0xff);
-
- switch(command) {
- default: /* Check for exec's */
-
- /*
- * Check if it's pty_exec
- */
- for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
- if (ex_ptr->ex_fport == so->so_fport &&
- command == ex_ptr->ex_addr) {
- if (ex_ptr->ex_pty == 3) {
- so->s = -1;
- so->extra = (void *)ex_ptr->ex_exec;
- return 1;
- }
- do_pty = ex_ptr->ex_pty;
- goto do_exec;
- }
- }
-
- /*
- * Nothing bound..
- */
- /* tcp_fconnect(so); */
-
- /* FALLTHROUGH */
- case CTL_ALIAS:
- sb->sb_cc = snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
- "Error: No application configured.\r\n");
- sb->sb_wptr += sb->sb_cc;
- return(0);
-
- do_exec:
- DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
- return(fork_exec(so, ex_ptr->ex_exec, do_pty));
-
-#if 0
- case CTL_CMD:
- for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
- if (tmpso->so_emu == EMU_CTL &&
- !(tmpso->so_tcpcb?
- (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK))
- :0)) {
- /* Ooops, control connection already active */
- sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n");
- sb->sb_wptr += sb->sb_cc;
- return 0;
- }
- }
- so->so_emu = EMU_CTL;
- ctl_password_ok = 0;
- sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> ");
- sb->sb_wptr += sb->sb_cc;
- do_echo=-1;
- return(2);
-#endif
- }
+ printf("Error tcp_ctl not supported");
+ exit(-1);
}
diff --git a/tcp_timer.c b/tcp_timer.c
index 244bad6..cb7d37f 100644
--- a/tcp_timer.c
+++ b/tcp_timer.c
@@ -34,7 +34,9 @@
* tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp
*/
-#include <slirp.h>
+#include "slirp_common.h"
+#include "tcp_timer.h"
+#include "tcp.h"
#ifdef LOG_ENABLED
struct tcpstat tcpstat; /* tcp statistics */
diff --git a/tcp_timer.h b/tcp_timer.h
index f251846..55fd4f0 100644
--- a/tcp_timer.h
+++ b/tcp_timer.h
@@ -84,6 +84,8 @@
* amount of time probing, then we drop the connection.
*/
+#define SLOW_TIMEOUT_MS 1000/PR_SLOWHZ
+#define FAST_TIMEOUT_MS 1000/PR_FASTHZ
/*
* Time constants.
*/
diff --git a/tcpip.h b/tcpip.h
index b98cdb3..e3a31d9 100644
--- a/tcpip.h
+++ b/tcpip.h
@@ -37,6 +37,7 @@
#ifndef _TCPIP_H_
#define _TCPIP_H_
+#include "ip.h"
/*
* Tcp+ip header, after ip options removed.
*/
diff --git a/udp.c b/udp.c
index c992618..959529e 100644
--- a/udp.c
+++ b/udp.c
@@ -42,17 +42,22 @@
* terms and conditions of the copyright.
*/
-#include <slirp.h>
+#include "slirp_common.h"
+#include "udp.h"
+#include "ip.h"
#include "ip_icmp.h"
+#include "bootp.h"
+#include "cksum.h"
#ifdef LOG_ENABLED
struct udpstat udpstat;
#endif
struct socket udb;
-
+#if 0
static u_int8_t udp_tos(struct socket *so);
static void udp_emu(struct socket *so, struct mbuf *m);
+#endif
/*
* UDP protocol implementation.
@@ -85,7 +90,7 @@ udp_input(m, iphlen)
/* struct mbuf *opts = 0;*/
int len;
struct ip save_ip;
- struct socket *so;
+// struct socket *so;
DEBUG_CALL("udp_input");
DEBUG_ARG("m = %lx", (long)m);
@@ -147,26 +152,25 @@ udp_input(m, iphlen)
STAT(udpstat.udps_badsum++);
goto bad;
}
- }
+ }
- /*
- * handle DHCP/BOOTP
- */
- if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
- bootp_input(m);
- goto bad;
- }
-
- if (slirp_restrict)
- goto bad;
-
- /*
- * handle TFTP
- */
- if (ntohs(uh->uh_dport) == TFTP_SERVER) {
- tftp_input(m);
- goto bad;
- }
+ /*
+ * handle DHCP/BOOTP
+ */
+ if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
+ bootp_input(m);
+ goto bad;
+ } else { // TODO: temp.
+ return;
+ }
+#if 0 //TODO: tmp
+ /*
+ * handle TFTP
+ */
+ if (ntohs(uh->uh_dport) == TFTP_SERVER) {
+ tftp_input(m);
+ goto bad;
+ }
/*
* Locate pcb for datagram.
@@ -250,7 +254,7 @@ udp_input(m, iphlen)
m->m_data -= iphlen;
*ip=save_ip;
so->so_m=m; /* ICMP backup */
-
+#endif
return;
bad:
m_freem(m);
@@ -313,6 +317,7 @@ int udp_output2(struct socket *so, struct mbuf *m,
return (error);
}
+#if 0 // TODO: temp till udp is supported
int udp_output(struct socket *so, struct mbuf *m,
struct sockaddr_in *addr)
@@ -680,3 +685,4 @@ udp_listen(port, laddr, lport, flags)
return so;
}
+#endif
diff --git a/udp.h b/udp.h
index e2ca546..ba43b86 100644
--- a/udp.h
+++ b/udp.h
@@ -37,6 +37,8 @@
#ifndef _UDP_H_
#define _UDP_H_
+#include "ip.h"
+
#define UDP_TTL 0x60
#define UDP_UDPDATALEN 16192
@@ -102,11 +104,14 @@ struct mbuf;
void udp_init _P((void));
void udp_input _P((register struct mbuf *, int));
+int udp_output2(struct socket *so, struct mbuf *m,
+ struct sockaddr_in *saddr, struct sockaddr_in *daddr,
+ int iptos); // for bootp reply
+#if 0 // TODO: temp till udp is supported.
int udp_output _P((struct socket *, struct mbuf *, struct sockaddr_in *));
int udp_attach _P((struct socket *));
void udp_detach _P((struct socket *));
struct socket * udp_listen _P((u_int, u_int32_t, u_int, int));
-int udp_output2(struct socket *so, struct mbuf *m,
- struct sockaddr_in *saddr, struct sockaddr_in *daddr,
- int iptos);
+
+#endif
#endif