diff options
author | Yonit <yhalperi@redhat.com> | 2009-05-27 12:20:10 +0300 |
---|---|---|
committer | Yonit <yhalperi@redhat.com> | 2009-05-27 12:20:10 +0300 |
commit | 0cc49020edd88d4a914c67407bc6ae0bda30bf48 (patch) | |
tree | 304e0f5c59de0c37dec9d08e6509945a40a6ffd0 | |
parent | 47de9909ff0eb29285e62e5494dcc7ca4abb9da9 (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-- | Makefile | 90 | ||||
-rw-r--r-- | TODO | 5 | ||||
-rw-r--r-- | bootp.c | 129 | ||||
-rw-r--r-- | bootp.h | 13 | ||||
-rw-r--r-- | cksum.c | 4 | ||||
-rw-r--r-- | cksum.h | 7 | ||||
-rw-r--r-- | ctl.h | 2 | ||||
-rw-r--r-- | debug.c | 175 | ||||
-rw-r--r-- | debug.h | 4 | ||||
-rw-r--r-- | if.c | 212 | ||||
-rw-r--r-- | if.h | 12 | ||||
-rw-r--r-- | ip.h | 12 | ||||
-rw-r--r-- | ip_icmp.c | 9 | ||||
-rw-r--r-- | ip_icmp.h | 9 | ||||
-rw-r--r-- | ip_input.c | 32 | ||||
-rw-r--r-- | ip_output.c | 5 | ||||
-rw-r--r-- | libslirp.h | 38 | ||||
-rw-r--r-- | main.h | 56 | ||||
-rw-r--r-- | mbuf.c | 37 | ||||
-rw-r--r-- | mbuf.h | 3 | ||||
-rw-r--r-- | misc.c | 825 | ||||
-rw-r--r-- | misc.h | 57 | ||||
-rw-r--r-- | net_slirp.c | 304 | ||||
-rw-r--r-- | net_slirp.h | 59 | ||||
-rw-r--r-- | sbuf.c | 72 | ||||
-rw-r--r-- | sbuf.h | 5 | ||||
-rw-r--r-- | slirp.c | 1039 | ||||
-rw-r--r-- | slirp.pc | 11 | ||||
-rw-r--r-- | slirp_common.h (renamed from slirp.h) | 160 | ||||
-rw-r--r-- | socket.c | 252 | ||||
-rw-r--r-- | socket.h | 27 | ||||
-rw-r--r-- | tcp.h | 28 | ||||
-rw-r--r-- | tcp_input.c | 112 | ||||
-rw-r--r-- | tcp_output.c | 10 | ||||
-rw-r--r-- | tcp_subr.c | 898 | ||||
-rw-r--r-- | tcp_timer.c | 4 | ||||
-rw-r--r-- | tcp_timer.h | 2 | ||||
-rw-r--r-- | tcpip.h | 1 | ||||
-rw-r--r-- | udp.c | 52 | ||||
-rw-r--r-- | udp.h | 11 |
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) @@ -0,0 +1,5 @@ +- debug and stats support +- udp support +- make DHCP gateway support optional +- redir +- return windows compatibility @@ -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; @@ -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 @@ -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). * @@ -0,0 +1,7 @@ +#ifndef _H_CHKSUM +#define _H_CHKSUM + +#include "mbuf.h" +int cksum(struct mbuf *m, int len); + +#endif @@ -4,4 +4,4 @@ #define CTL_DNS 3 #define CTL_SPECIAL "10.0.2.0" -#define CTL_LOCAL "10.0.2.15" + @@ -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 @@ -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 @@ -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; /* @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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); @@ -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; } @@ -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)); @@ -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 @@ -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 @@ -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; @@ -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 @@ -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 + @@ -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); +} @@ -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_ */ @@ -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 @@ -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. */ @@ -37,6 +37,7 @@ #ifndef _TCPIP_H_ #define _TCPIP_H_ +#include "ip.h" /* * Tcp+ip header, after ip options removed. */ @@ -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 @@ -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 |