Next set of updates from libslirp.
- Started implementing guest forwarding feature. - Updated most of socket.h. - Added if_mtu / if_mru handling. - Cleaned up MIN / MAX defines.
This commit is contained in:
parent
b84ebf5dfc
commit
a684734975
@ -35,5 +35,8 @@
|
|||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -224,11 +224,15 @@ void slirp_pollfds_poll(Slirp *slirp, int select_error,
|
|||||||
* guest network, to be interpreted by slirp. */
|
* guest network, to be interpreted by slirp. */
|
||||||
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
|
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
|
||||||
|
|
||||||
|
/* This is called by the application when a timer expires, if it provides
|
||||||
|
* the timer_new_opaque callback. It is not needed if the application only
|
||||||
|
* uses timer_new. */
|
||||||
|
void slirp_handle_timer(Slirp *slirp, SlirpTimerId id, void *cb_opaque);
|
||||||
|
|
||||||
/* These set up / remove port forwarding between a host port in the real world
|
/* These set up / remove port forwarding between a host port in the real world
|
||||||
* and the guest network. */
|
* and the guest network. */
|
||||||
int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
|
int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
|
||||||
int host_port, struct in_addr guest_addr, int guest_port);
|
int host_port, struct in_addr guest_addr, int guest_port);
|
||||||
|
|
||||||
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
|
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
|
||||||
int host_port);
|
int host_port);
|
||||||
|
|
||||||
@ -237,6 +241,14 @@ int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
|
|||||||
int slirp_add_exec(Slirp *slirp, const char *cmdline,
|
int slirp_add_exec(Slirp *slirp, const char *cmdline,
|
||||||
struct in_addr *guest_addr, int guest_port);
|
struct in_addr *guest_addr, int guest_port);
|
||||||
|
|
||||||
|
/* Set up port forwarding between a port in the guest network and a
|
||||||
|
* callback that will receive the data coming from the port */
|
||||||
|
int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
|
||||||
|
struct in_addr *guest_addr, int guest_port);
|
||||||
|
|
||||||
|
/* TODO: rather identify a guestfwd through an opaque pointer instead of through
|
||||||
|
* the guest_addr */
|
||||||
|
|
||||||
/* This is called by the application for a guestfwd, to determine how much data
|
/* This is called by the application for a guestfwd, to determine how much data
|
||||||
* can be received by the forwarded port through a call to slirp_socket_recv. */
|
* can be received by the forwarded port through a call to slirp_socket_recv. */
|
||||||
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
|
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
|
||||||
@ -246,10 +258,14 @@ size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
|
|||||||
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
|
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
|
||||||
const uint8_t *buf, int size);
|
const uint8_t *buf, int size);
|
||||||
|
|
||||||
|
/* Remove entries added by slirp_add_exec, slirp_add_unix or slirp_add_guestfwd */
|
||||||
|
int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr,
|
||||||
|
int guest_port);
|
||||||
|
|
||||||
/* Return the version of the slirp implementation */
|
/* Return the version of the slirp implementation */
|
||||||
const char *slirp_version_string(void);
|
const char *slirp_version_string(void);
|
||||||
|
|
||||||
/* you must provide the following functions: */
|
/* you must provide the following functions: */
|
||||||
void slirp_warning(const char *, void *);
|
void slirp_warning(const char *, void *);
|
||||||
|
|
||||||
#endif
|
#endif /* LIBSLIRP_H */
|
||||||
|
@ -91,7 +91,7 @@ m_get(Slirp *slirp)
|
|||||||
m->m_len = 0;
|
m->m_len = 0;
|
||||||
m->m_nextpkt = NULL;
|
m->m_nextpkt = NULL;
|
||||||
m->m_prevpkt = NULL;
|
m->m_prevpkt = NULL;
|
||||||
m->arp_requested = false;
|
m->resolution_requested = false;
|
||||||
m->expiration_date = (uint64_t)-1;
|
m->expiration_date = (uint64_t)-1;
|
||||||
end_error:
|
end_error:
|
||||||
DEBUG_ARG("m = %lx", (long )m);
|
DEBUG_ARG("m = %lx", (long )m);
|
||||||
|
@ -79,14 +79,14 @@ struct mbuf {
|
|||||||
char *m_data; /* Location of data */
|
char *m_data; /* Location of data */
|
||||||
int m_len; /* Amount of data in this mbuf */
|
int m_len; /* Amount of data in this mbuf */
|
||||||
|
|
||||||
Slirp *slirp;
|
Slirp *slirp;
|
||||||
bool arp_requested;
|
bool resolution_requested;
|
||||||
uint64_t expiration_date;
|
uint64_t expiration_date;
|
||||||
/* start of dynamic buffer area, must be last element */
|
/* start of dynamic buffer area, must be last element */
|
||||||
union {
|
union {
|
||||||
char m_dat[1]; /* ANSI don't like 0 sized arrays */
|
char m_dat[1]; /* ANSI don't like 0 sized arrays */
|
||||||
char *m_ext;
|
char *m_ext;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ifq_prev m_prev
|
#define ifq_prev m_prev
|
||||||
|
@ -4,16 +4,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "slirp.h"
|
#include "slirp.h"
|
||||||
#include "libslirp.h"
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <dirent.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if BX_NETWORKING && BX_NETMOD_SLIRP
|
#if BX_NETWORKING && BX_NETMOD_SLIRP
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifndef _WIN32
|
||||||
int slirp_debug = DBG_CALL|DBG_MISC|DBG_ERROR;
|
#include <sys/un.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void slirp_insque(void *a, void *b)
|
void slirp_insque(void *a, void *b)
|
||||||
@ -35,187 +29,66 @@ void slirp_remque(void *a)
|
|||||||
element->qh_rlink = NULL;
|
element->qh_rlink = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_exec(struct gfwd_list **ex_ptr, const char *exec, struct in_addr addr, int port)
|
/* TODO: IPv6 */
|
||||||
|
struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb,
|
||||||
|
void *opaque, struct in_addr addr, int port)
|
||||||
{
|
{
|
||||||
struct gfwd_list *tmp_ptr;
|
struct gfwd_list *f = (struct gfwd_list *)malloc(sizeof(struct gfwd_list));
|
||||||
|
|
||||||
/* First, check if the port is "bound" */
|
f->write_cb = write_cb;
|
||||||
for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
|
f->opaque = opaque;
|
||||||
if (port == tmp_ptr->ex_fport &&
|
f->ex_fport = port;
|
||||||
addr.s_addr == tmp_ptr->ex_addr.s_addr)
|
f->ex_addr = addr;
|
||||||
return -1;
|
f->ex_next = *ex_ptr;
|
||||||
}
|
*ex_ptr = f;
|
||||||
|
|
||||||
tmp_ptr = *ex_ptr;
|
return f;
|
||||||
*ex_ptr = (struct gfwd_list *)malloc(sizeof(struct gfwd_list));
|
|
||||||
(*ex_ptr)->ex_fport = port;
|
|
||||||
(*ex_ptr)->ex_addr = addr;
|
|
||||||
(*ex_ptr)->ex_exec = strdup(exec);
|
|
||||||
(*ex_ptr)->ex_next = tmp_ptr;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
|
||||||
|
struct in_addr addr, int port)
|
||||||
|
{
|
||||||
|
struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
|
||||||
|
|
||||||
int
|
f->ex_exec = strdup(cmdline);
|
||||||
fork_exec(struct socket *so, const char *ex, int do_pty)
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock,
|
||||||
|
struct in_addr addr, int port)
|
||||||
|
{
|
||||||
|
struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
|
||||||
|
|
||||||
|
f->ex_unix = strdup(unixsock);
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port)
|
||||||
|
{
|
||||||
|
for (; *ex_ptr != NULL; ex_ptr = &((*ex_ptr)->ex_next)) {
|
||||||
|
struct gfwd_list *f = *ex_ptr;
|
||||||
|
if (f->ex_addr.s_addr == addr.s_addr && f->ex_fport == port) {
|
||||||
|
*ex_ptr = f->ex_next;
|
||||||
|
free(f->ex_exec);
|
||||||
|
free(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fork_exec(struct socket *so, const char *ex)
|
||||||
{
|
{
|
||||||
/* not implemented */
|
/* not implemented */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
int open_unix(struct socket *so, const char *unixpath)
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
/* not implemented */
|
||||||
struct sockaddr_in addr;
|
return 0;
|
||||||
socklen_t addrlen = sizeof(addr);
|
|
||||||
int opt;
|
|
||||||
const char *argv[256];
|
|
||||||
/* don't want to clobber the original */
|
|
||||||
char *bptr;
|
|
||||||
const char *curarg;
|
|
||||||
int c, i, ret;
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = 0;
|
|
||||||
addr.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
|
|
||||||
if ((s = slirp_socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
|
|
||||||
bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
|
|
||||||
listen(s, 1) < 0) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("Error: inet socket: %s\n", strerror(errno));
|
|
||||||
#endif
|
|
||||||
closesocket(s);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = fork();
|
|
||||||
switch(pid) {
|
|
||||||
case -1:
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("Error: fork failed: %s\n", strerror(errno));
|
|
||||||
#endif
|
|
||||||
close(s);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
setsid();
|
|
||||||
|
|
||||||
/* Set the DISPLAY */
|
|
||||||
getsockname(s, (struct sockaddr *)&addr, &addrlen);
|
|
||||||
close(s);
|
|
||||||
/*
|
|
||||||
* Connect to the socket
|
|
||||||
* XXX If any of these fail, we're in trouble!
|
|
||||||
*/
|
|
||||||
s = slirp_socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
addr.sin_addr = loopback_addr;
|
|
||||||
do {
|
|
||||||
ret = connect(s, (struct sockaddr *)&addr, addrlen);
|
|
||||||
} while (ret < 0 && errno == EINTR);
|
|
||||||
|
|
||||||
dup2(s, 0);
|
|
||||||
dup2(s, 1);
|
|
||||||
dup2(s, 2);
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
{
|
|
||||||
/* No getdtablesize() on Android, we will use /proc/XXX/fd/ Linux virtual FS instead */
|
|
||||||
char proc_fd_path[256];
|
|
||||||
sprintf(proc_fd_path, "/proc/%u/fd", (unsigned)getpid());
|
|
||||||
DIR *proc_dir = opendir(proc_fd_path);
|
|
||||||
if (proc_dir) {
|
|
||||||
for (struct dirent *fd = readdir(proc_dir); fd != NULL; fd = readdir(proc_dir)) {
|
|
||||||
if (atoi(fd->d_name) >= 3 && fd->d_name[0] != '.') /* ".." and "." will return 0 anyway */
|
|
||||||
close(atoi(fd->d_name));
|
|
||||||
}
|
|
||||||
closedir(proc_dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for (s = getdtablesize() - 1; s >= 3; s--)
|
|
||||||
close(s);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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] = NULL;
|
|
||||||
execvp(argv[0], (char **)argv);
|
|
||||||
|
|
||||||
/* Ooops, failed, let's tell the user why */
|
|
||||||
fprintf(stderr, "Error: execvp of %s failed: %s\n",
|
|
||||||
argv[0], strerror(errno));
|
|
||||||
close(0); close(1); close(2); /* XXX */
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
default:
|
|
||||||
slirp_warning("qemu_add_child_watch(pid) not implemented", so->slirp->opaque);
|
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
slirp_socket_set_fast_reuse(so->s);
|
|
||||||
opt = 1;
|
|
||||||
setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
|
|
||||||
slirp_set_nonblock(so->s);
|
|
||||||
|
|
||||||
/* Append the telnet options now */
|
|
||||||
if (so->so_m != NULL && do_pty == 1) {
|
|
||||||
sbappend(so, so->so_m);
|
|
||||||
so->so_m = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -6,10 +6,15 @@
|
|||||||
#ifndef MISC_H
|
#ifndef MISC_H
|
||||||
#define MISC_H
|
#define MISC_H
|
||||||
|
|
||||||
|
#include "libslirp.h"
|
||||||
|
|
||||||
struct gfwd_list {
|
struct gfwd_list {
|
||||||
struct in_addr ex_addr; /* Server address */
|
SlirpWriteCb write_cb;
|
||||||
int ex_fport; /* Port to telnet to */
|
void *opaque;
|
||||||
const char *ex_exec; /* Command line of what to exec */
|
struct in_addr ex_addr; /* Server address */
|
||||||
|
int ex_fport; /* Port to telnet to */
|
||||||
|
char *ex_exec; /* Command line of what to exec */
|
||||||
|
char *ex_unix; /* unix socket */
|
||||||
struct gfwd_list *ex_next;
|
struct gfwd_list *ex_next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,7 +58,28 @@ void slirp_insque(void *a, void *b);
|
|||||||
/* Remove element a from its queue */
|
/* Remove element a from its queue */
|
||||||
void slirp_remque(void *a);
|
void slirp_remque(void *a);
|
||||||
|
|
||||||
int add_exec(struct gfwd_list **, const char *, struct in_addr, int);
|
/* Run the given command in the background, and expose its output as a socket */
|
||||||
int fork_exec(struct socket *so, const char *ex, int do_pty);
|
int fork_exec(struct socket *so, const char *ex);
|
||||||
|
|
||||||
|
/* Create a Unix socket, and expose it as a socket */
|
||||||
|
int open_unix(struct socket *so, const char *unixsock);
|
||||||
|
|
||||||
|
/* Add a guest forward on the given address and port, with guest data being
|
||||||
|
* forwarded by calling write_cb */
|
||||||
|
struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb,
|
||||||
|
void *opaque, struct in_addr addr, int port);
|
||||||
|
|
||||||
|
/* Run the given command in the backaground, and send its output to the guest on
|
||||||
|
* the given address and port */
|
||||||
|
struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
|
||||||
|
struct in_addr addr, int port);
|
||||||
|
|
||||||
|
/* Create a Unix socket, and expose it to the guest on the given address and
|
||||||
|
* port */
|
||||||
|
struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock,
|
||||||
|
struct in_addr addr, int port);
|
||||||
|
|
||||||
|
/* Remove the guest forward bound to the given address and port */
|
||||||
|
int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,6 +28,15 @@
|
|||||||
|
|
||||||
#if BX_NETWORKING && BX_NETMOD_SLIRP
|
#if BX_NETWORKING && BX_NETMOD_SLIRP
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <net/if.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* https://gitlab.freedesktop.org/slirp/libslirp/issues/18 */
|
||||||
|
#if defined(__NetBSD__) && defined(if_mtu)
|
||||||
|
#undef if_mtu
|
||||||
|
#endif
|
||||||
|
|
||||||
int slirp_debug;
|
int slirp_debug;
|
||||||
|
|
||||||
/* host loopback address */
|
/* host loopback address */
|
||||||
@ -250,7 +259,8 @@ Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque)
|
|||||||
if (cfg->vdnssearch) {
|
if (cfg->vdnssearch) {
|
||||||
translate_dnssearch(slirp, cfg->vdnssearch);
|
translate_dnssearch(slirp, cfg->vdnssearch);
|
||||||
}
|
}
|
||||||
|
slirp->if_mtu = cfg->if_mtu == 0 ? IF_MTU_DEFAULT : cfg->if_mtu;
|
||||||
|
slirp->if_mru = cfg->if_mru == 0 ? IF_MRU_DEFAULT : cfg->if_mru;
|
||||||
slirp->disable_host_loopback = cfg->disable_host_loopback;
|
slirp->disable_host_loopback = cfg->disable_host_loopback;
|
||||||
slirp->enable_emu = cfg->enable_emu;
|
slirp->enable_emu = cfg->enable_emu;
|
||||||
|
|
||||||
@ -679,7 +689,7 @@ void slirp_pollfds_poll(Slirp *slirp, int select_error,
|
|||||||
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
|
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
|
||||||
{
|
{
|
||||||
struct slirp_arphdr *ah = (struct slirp_arphdr *)(pkt + ETH_HLEN);
|
struct slirp_arphdr *ah = (struct slirp_arphdr *)(pkt + ETH_HLEN);
|
||||||
uint8_t arp_reply[max(ETH_HLEN + sizeof(struct slirp_arphdr), 64)];
|
uint8_t arp_reply[MAX(ETH_HLEN + sizeof(struct slirp_arphdr), 64)];
|
||||||
struct ethhdr *reh = (struct ethhdr *)arp_reply;
|
struct ethhdr *reh = (struct ethhdr *)arp_reply;
|
||||||
struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN);
|
struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN);
|
||||||
int ar_op;
|
int ar_op;
|
||||||
@ -774,26 +784,21 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
|
/* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no
|
||||||
* re-queued.
|
* packet should be sent, 0 if the packet must be re-queued, 2 if the packet
|
||||||
|
* is ready to go.
|
||||||
*/
|
*/
|
||||||
int if_encap(Slirp *slirp, struct mbuf *ifm)
|
static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
|
||||||
|
uint8_t ethaddr[ETH_ALEN])
|
||||||
{
|
{
|
||||||
uint8_t buf[1600];
|
|
||||||
struct ethhdr *eh = (struct ethhdr *)buf;
|
|
||||||
uint8_t ethaddr[ETH_ALEN];
|
|
||||||
const struct ip *iph = (const struct ip *)ifm->m_data;
|
const struct ip *iph = (const struct ip *)ifm->m_data;
|
||||||
|
|
||||||
if (ifm->m_len + ETH_HLEN > (int)sizeof(buf)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
|
if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
|
||||||
uint8_t arp_req[ETH_HLEN + sizeof(struct slirp_arphdr)];
|
uint8_t arp_req[2 + ETH_HLEN + sizeof(struct slirp_arphdr)];
|
||||||
struct ethhdr *reh = (struct ethhdr *)arp_req;
|
struct ethhdr *reh = (struct ethhdr *)(arp_req + 2);
|
||||||
struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + ETH_HLEN);
|
struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + 2 + ETH_HLEN);
|
||||||
|
|
||||||
if (!ifm->arp_requested) {
|
if (!ifm->resolution_requested) {
|
||||||
/* If the client addr is not known, send an ARP request */
|
/* If the client addr is not known, send an ARP request */
|
||||||
memset(reh->h_dest, 0xff, ETH_ALEN);
|
memset(reh->h_dest, 0xff, ETH_ALEN);
|
||||||
memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
|
memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
|
||||||
@ -818,23 +823,79 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
|
|||||||
/* target IP */
|
/* target IP */
|
||||||
rah->ar_tip = iph->ip_dst.s_addr;
|
rah->ar_tip = iph->ip_dst.s_addr;
|
||||||
slirp->client_ipaddr = iph->ip_dst;
|
slirp->client_ipaddr = iph->ip_dst;
|
||||||
slirp_send_packet_all(slirp, arp_req, sizeof(arp_req));
|
slirp_send_packet_all(slirp, arp_req + 2, sizeof(arp_req) - 2);
|
||||||
ifm->arp_requested = true;
|
ifm->resolution_requested = true;
|
||||||
|
|
||||||
/* Expire request and drop outgoing packet after 1 second */
|
/* Expire request and drop outgoing packet after 1 second */
|
||||||
ifm->expiration_date = slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
|
ifm->expiration_date =
|
||||||
|
slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
memcpy(eh->h_dest, ethaddr, ETH_ALEN);
|
|
||||||
memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
|
memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
|
||||||
/* XXX: not correct */
|
/* XXX: not correct */
|
||||||
memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
|
memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
|
||||||
eh->h_proto = htons(ETH_P_IP);
|
eh->h_proto = htons(ETH_P_IP);
|
||||||
memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
|
|
||||||
slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN);
|
/* Send this */
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no
|
||||||
|
* packet should be sent, 0 if the packet must be re-queued, 2 if the packet
|
||||||
|
* is ready to go.
|
||||||
|
*/
|
||||||
|
static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
|
||||||
|
uint8_t ethaddr[ETH_ALEN])
|
||||||
|
{
|
||||||
|
slirp_warning("IPv6 packet not supported yet", slirp->opaque);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
|
||||||
|
* re-queued.
|
||||||
|
*/
|
||||||
|
int if_encap(Slirp *slirp, struct mbuf *ifm)
|
||||||
|
{
|
||||||
|
uint8_t buf[IF_MTU_MAX + 100];
|
||||||
|
struct ethhdr *eh = (struct ethhdr *)(buf + 2);
|
||||||
|
uint8_t ethaddr[ETH_ALEN];
|
||||||
|
const struct ip *iph = (const struct ip *)ifm->m_data;
|
||||||
|
int ret;
|
||||||
|
// char ethaddr_str[ETH_ADDRSTRLEN];
|
||||||
|
|
||||||
|
if (ifm->m_len + ETH_HLEN > (int)sizeof(buf) - 2) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (iph->ip_v) {
|
||||||
|
case IPVERSION:
|
||||||
|
ret = if_encap4(slirp, ifm, eh, ethaddr);
|
||||||
|
if (ret < 2) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IP6VERSION:
|
||||||
|
ret = if_encap6(slirp, ifm, eh, ethaddr);
|
||||||
|
if (ret < 2) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
slirp_warning("unknown protocol", slirp->opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(eh->h_dest, ethaddr, ETH_ALEN);
|
||||||
|
DEBUG_ARG("src = %s", slirp_ether_ntoa(eh->h_source, ethaddr_str,
|
||||||
|
sizeof(ethaddr_str)));
|
||||||
|
DEBUG_ARG("dst = %s", slirp_ether_ntoa(eh->h_dest, ethaddr_str,
|
||||||
|
sizeof(ethaddr_str)));
|
||||||
|
memcpy(buf + 2 + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
|
||||||
|
slirp_send_packet_all(slirp, buf + 2, ifm->m_len + ETH_HLEN);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop host forwarding rule, return 0 if found. */
|
/* Drop host forwarding rule, return 0 if found. */
|
||||||
@ -880,32 +941,99 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: IPv6 */
|
||||||
|
static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr,
|
||||||
|
int guest_port)
|
||||||
|
{
|
||||||
|
struct gfwd_list *tmp_ptr;
|
||||||
|
|
||||||
|
if (!guest_addr->s_addr) {
|
||||||
|
guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
|
||||||
|
(htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
|
||||||
|
}
|
||||||
|
if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
|
||||||
|
slirp->vnetwork_addr.s_addr ||
|
||||||
|
guest_addr->s_addr == slirp->vhost_addr.s_addr ||
|
||||||
|
guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if the port is "bound" */
|
||||||
|
for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
|
||||||
|
if (guest_port == tmp_ptr->ex_fport &&
|
||||||
|
guest_addr->s_addr == tmp_ptr->ex_addr.s_addr)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int slirp_add_exec(Slirp *slirp, const char *cmdline,
|
int slirp_add_exec(Slirp *slirp, const char *cmdline,
|
||||||
struct in_addr *guest_addr, int guest_port)
|
struct in_addr *guest_addr, int guest_port)
|
||||||
{
|
{
|
||||||
if (!guest_addr->s_addr) {
|
if (!check_guestfwd(slirp, guest_addr, guest_port)) {
|
||||||
guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
|
|
||||||
(htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
|
|
||||||
}
|
|
||||||
if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
|
|
||||||
slirp->vnetwork_addr.s_addr ||
|
|
||||||
guest_addr->s_addr == slirp->vhost_addr.s_addr ||
|
|
||||||
guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return add_exec(&slirp->guestfwd_list, cmdline, *guest_addr,
|
|
||||||
htons(guest_port));
|
add_exec(&slirp->guestfwd_list, cmdline, *guest_addr, htons(guest_port));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int slirp_add_unix(Slirp *slirp, const char *unixsock,
|
||||||
|
struct in_addr *guest_addr, int guest_port)
|
||||||
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (!check_guestfwd(slirp, guest_addr, guest_port)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_unix(&slirp->guestfwd_list, unixsock, *guest_addr, htons(guest_port));
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
|
||||||
|
struct in_addr *guest_addr, int guest_port)
|
||||||
|
{
|
||||||
|
if (!check_guestfwd(slirp, guest_addr, guest_port)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_guestfwd(&slirp->guestfwd_list, write_cb, opaque, *guest_addr,
|
||||||
|
htons(guest_port));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr,
|
||||||
|
int guest_port)
|
||||||
|
{
|
||||||
|
return remove_guestfwd(&slirp->guestfwd_list, guest_addr,
|
||||||
|
htons(guest_port));
|
||||||
}
|
}
|
||||||
|
|
||||||
slirp_ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
|
slirp_ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
|
||||||
{
|
{
|
||||||
if (so->s == -1 && so->extra) {
|
if (so->s == -1 && so->guestfwd) {
|
||||||
Slirp *slirp = so->slirp;
|
/* XXX this blocks entire thread. Rewrite to use
|
||||||
slirp_warning("slirp_send(): so->extra not supported", slirp->opaque);
|
* qemu_chr_fe_write and background I/O callbacks */
|
||||||
|
so->guestfwd->write_cb(buf, len, so->guestfwd->opaque);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return send(so->s, (const char*)buf, len, flags);
|
if (so->s == -1) {
|
||||||
|
/*
|
||||||
|
* This should in theory not happen but it is hard to be
|
||||||
|
* sure because some code paths will end up with so->s == -1
|
||||||
|
* on a failure but don't dispose of the struct socket.
|
||||||
|
* Check specifically, so we don't pass -1 to send().
|
||||||
|
*/
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return send(so->s, buf, len, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr,
|
struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr,
|
||||||
|
@ -110,6 +110,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr,
|
|||||||
bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
|
bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
|
||||||
uint8_t out_ethaddr[ETH_ALEN]);
|
uint8_t out_ethaddr[ETH_ALEN]);
|
||||||
|
|
||||||
|
/* Slirp configuration, specified by the application */
|
||||||
struct Slirp {
|
struct Slirp {
|
||||||
int cfg_version;
|
int cfg_version;
|
||||||
|
|
||||||
@ -137,6 +138,9 @@ struct Slirp {
|
|||||||
int restricted;
|
int restricted;
|
||||||
struct gfwd_list *guestfwd_list;
|
struct gfwd_list *guestfwd_list;
|
||||||
|
|
||||||
|
int if_mtu;
|
||||||
|
int if_mru;
|
||||||
|
|
||||||
bool disable_host_loopback;
|
bool disable_host_loopback;
|
||||||
|
|
||||||
/* mbuf states */
|
/* mbuf states */
|
||||||
@ -244,16 +248,4 @@ struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
|
|||||||
/* Send a frame to the virtual Ethernet board, i.e. call the application send_packet callback */
|
/* Send a frame to the virtual Ethernet board, i.e. call the application send_packet callback */
|
||||||
void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len);
|
void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len);
|
||||||
|
|
||||||
#ifndef min
|
|
||||||
#define min(x,y) ((x) < (y) ? (x) : (y))
|
|
||||||
#endif
|
|
||||||
#ifndef max
|
|
||||||
#define max(x,y) ((x) > (y) ? (x) : (y))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#undef errno
|
|
||||||
#define errno (WSAGetLastError())
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,12 +29,6 @@
|
|||||||
#define HAVE_SYS_SELECT_H
|
#define HAVE_SYS_SELECT_H
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Define to whatever your compiler thinks inline should be */
|
|
||||||
//#define inline inline
|
|
||||||
|
|
||||||
/* Define to whatever your compiler thinks const should be */
|
|
||||||
//#define const const
|
|
||||||
|
|
||||||
/* Define to sizeof(char) */
|
/* Define to sizeof(char) */
|
||||||
#define SIZEOF_CHAR 1
|
#define SIZEOF_CHAR 1
|
||||||
|
|
||||||
|
@ -62,12 +62,13 @@ socreate(Slirp *slirp)
|
|||||||
void
|
void
|
||||||
sofree(struct socket *so)
|
sofree(struct socket *so)
|
||||||
{
|
{
|
||||||
Slirp *slirp = so->slirp;
|
Slirp *slirp = so->slirp;
|
||||||
|
/*
|
||||||
if (so->so_emu==EMU_RSH && so->extra) {
|
if (so->so_emu==EMU_RSH && so->extra) {
|
||||||
sofree((struct socket*)so->extra);
|
sofree((struct socket*)so->extra);
|
||||||
so->extra=NULL;
|
so->extra=NULL;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if (so == slirp->tcp_last_so) {
|
if (so == slirp->tcp_last_so) {
|
||||||
slirp->tcp_last_so = &slirp->tcb;
|
slirp->tcp_last_so = &slirp->tcb;
|
||||||
} else if (so == slirp->udp_last_so) {
|
} else if (so == slirp->udp_last_so) {
|
||||||
@ -316,12 +317,12 @@ sosendoob(struct socket *so)
|
|||||||
* send it all
|
* send it all
|
||||||
*/
|
*/
|
||||||
len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
|
len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
|
||||||
if (len > so->so_urgc) len = so->so_urgc;
|
if (len > (int)so->so_urgc) len = so->so_urgc;
|
||||||
memcpy(buff, sb->sb_rptr, len);
|
memcpy(buff, sb->sb_rptr, len);
|
||||||
so->so_urgc -= len;
|
so->so_urgc -= len;
|
||||||
if (so->so_urgc) {
|
if (so->so_urgc) {
|
||||||
n = sb->sb_wptr - sb->sb_data;
|
n = sb->sb_wptr - sb->sb_data;
|
||||||
if (n > so->so_urgc) n = so->so_urgc;
|
if (n > (int)so->so_urgc) n = so->so_urgc;
|
||||||
memcpy((buff + len), sb->sb_data, n);
|
memcpy((buff + len), sb->sb_data, n);
|
||||||
so->so_urgc -= n;
|
so->so_urgc -= n;
|
||||||
len += n;
|
len += n;
|
||||||
|
@ -3,58 +3,89 @@
|
|||||||
* Copyright (c) 1995 Danny Gasparovski.
|
* Copyright (c) 1995 Danny Gasparovski.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef SLIRP_SOCKET_H
|
||||||
|
#define SLIRP_SOCKET_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SLIRP_SOCKET_H
|
#include "misc.h"
|
||||||
#define SLIRP_SOCKET_H
|
#include "sbuf.h"
|
||||||
|
|
||||||
#define SO_EXPIRE 240000
|
#define SO_EXPIRE 240000
|
||||||
#define SO_EXPIREFAST 10000
|
#define SO_EXPIREFAST 10000
|
||||||
|
|
||||||
|
/* Helps unify some in/in6 routines. */
|
||||||
|
union in4or6_addr {
|
||||||
|
struct in_addr addr4;
|
||||||
|
struct in6_addr addr6;
|
||||||
|
};
|
||||||
|
typedef union in4or6_addr in4or6_addr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Our socket structure
|
* Our socket structure
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
union slirp_sockaddr {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct sockaddr_storage ss;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
};
|
||||||
|
|
||||||
struct socket {
|
struct socket {
|
||||||
struct socket *so_next,*so_prev; /* For a linked list of sockets */
|
struct socket *so_next, *so_prev; /* For a linked list of sockets */
|
||||||
|
|
||||||
int s; /* The actual socket */
|
int s; /* The actual socket */
|
||||||
|
int s_aux; /* An auxiliary socket for miscellaneous use. Currently used to
|
||||||
|
* reserve OS ports in UNIX-to-inet translation. */
|
||||||
|
struct gfwd_list *guestfwd;
|
||||||
|
|
||||||
int pollfds_idx;
|
int pollfds_idx;
|
||||||
|
|
||||||
Slirp *slirp; /* managing slirp instance */
|
Slirp *slirp; /* managing slirp instance */
|
||||||
|
|
||||||
/* XXX union these with not-yet-used sbuf params */
|
/* XXX union these with not-yet-used sbuf params */
|
||||||
struct mbuf *so_m; /* Pointer to the original SYN packet,
|
struct mbuf *so_m; /* Pointer to the original SYN packet,
|
||||||
* for non-blocking connect()'s, and
|
* for non-blocking connect()'s, and
|
||||||
* PING reply's */
|
* PING reply's */
|
||||||
struct tcpiphdr *so_ti; /* Pointer to the original ti within
|
struct tcpiphdr *so_ti; /* Pointer to the original ti within
|
||||||
* so_mconn, for non-blocking connections */
|
* so_mconn, for non-blocking connections */
|
||||||
int so_urgc;
|
uint32_t so_urgc;
|
||||||
struct in_addr so_faddr; /* foreign host table entry */
|
union slirp_sockaddr fhost; /* Foreign host */
|
||||||
struct in_addr so_laddr; /* local host table entry */
|
#define so_faddr fhost.sin.sin_addr
|
||||||
uint16_t so_fport; /* foreign port */
|
#define so_fport fhost.sin.sin_port
|
||||||
uint16_t so_lport; /* local port */
|
#define so_faddr6 fhost.sin6.sin6_addr
|
||||||
|
#define so_fport6 fhost.sin6.sin6_port
|
||||||
|
#define so_ffamily fhost.ss.ss_family
|
||||||
|
|
||||||
uint8_t so_iptos; /* Type of service */
|
union slirp_sockaddr lhost; /* Local host */
|
||||||
uint8_t so_emu; /* Is the socket emulated? */
|
#define so_laddr lhost.sin.sin_addr
|
||||||
|
#define so_lport lhost.sin.sin_port
|
||||||
|
#define so_laddr6 lhost.sin6.sin6_addr
|
||||||
|
#define so_lport6 lhost.sin6.sin6_port
|
||||||
|
#define so_lfamily lhost.ss.ss_family
|
||||||
|
|
||||||
u_char so_type; /* Type of socket, UDP or TCP */
|
uint8_t so_iptos; /* Type of service */
|
||||||
int so_state; /* internal state flags SS_*, below */
|
uint8_t so_emu; /* Is the socket emulated? */
|
||||||
|
|
||||||
struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */
|
uint8_t so_type; /* Protocol of the socket. May be 0 if loading old
|
||||||
u_int so_expire; /* When the socket will expire */
|
* states. */
|
||||||
|
int32_t so_state; /* internal state flags SS_*, below */
|
||||||
|
|
||||||
int so_queued; /* Number of packets queued from this socket */
|
struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */
|
||||||
int so_nqueued; /* Number of packets queued in a row
|
unsigned so_expire; /* When the socket will expire */
|
||||||
* Used to determine when to "downgrade" a session
|
|
||||||
* from fastq to batchq */
|
|
||||||
|
|
||||||
struct sbuf so_rcv; /* Receive buffer */
|
int so_queued; /* Number of packets queued from this socket */
|
||||||
struct sbuf so_snd; /* Send buffer */
|
int so_nqueued; /* Number of packets queued in a row
|
||||||
void * extra; /* Extra pointer */
|
* Used to determine when to "downgrade" a session
|
||||||
|
* from fastq to batchq */
|
||||||
|
|
||||||
|
struct sbuf so_rcv; /* Receive buffer */
|
||||||
|
struct sbuf so_snd; /* Send buffer */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -62,21 +93,29 @@ struct socket {
|
|||||||
* Socket state bits. (peer means the host on the Internet,
|
* Socket state bits. (peer means the host on the Internet,
|
||||||
* local host means the host on the other end of the modem)
|
* local host means the host on the other end of the modem)
|
||||||
*/
|
*/
|
||||||
#define SS_NOFDREF 0x001 /* No fd reference */
|
#define SS_NOFDREF 0x001 /* No fd reference */
|
||||||
|
|
||||||
#define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */
|
#define SS_ISFCONNECTING \
|
||||||
#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */
|
0x002 /* Socket is connecting to peer (non-blocking connect()'s) */
|
||||||
#define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */
|
#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */
|
||||||
#define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */
|
#define SS_FCANTRCVMORE \
|
||||||
#define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */
|
0x008 /* Socket can't receive more from peer (for half-closes) */
|
||||||
|
#define SS_FCANTSENDMORE \
|
||||||
|
0x010 /* Socket can't send more to peer (for half-closes) */
|
||||||
|
#define SS_FWDRAIN \
|
||||||
|
0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */
|
||||||
|
|
||||||
#define SS_CTL 0x080
|
#define SS_CTL 0x080
|
||||||
#define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */
|
#define SS_FACCEPTCONN \
|
||||||
#define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */
|
0x100 /* Socket is accepting connections from a host on the internet */
|
||||||
|
#define SS_FACCEPTONCE \
|
||||||
|
0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */
|
||||||
|
|
||||||
#define SS_PERSISTENT_MASK 0xf000 /* Unremovable state bits */
|
#define SS_PERSISTENT_MASK 0xf000 /* Unremovable state bits */
|
||||||
#define SS_HOSTFWD 0x1000 /* Socket describes host->guest forwarding */
|
#define SS_HOSTFWD 0x1000 /* Socket describes host->guest forwarding */
|
||||||
#define SS_INCOMING 0x2000 /* Connection was initiated by a host on the internet */
|
#define SS_INCOMING \
|
||||||
|
0x2000 /* Connection was initiated by a host on the internet */
|
||||||
|
#define SS_HOSTFWD_V6ONLY 0x4000 /* Only bind on v6 addresses */
|
||||||
|
|
||||||
/* Check that two addresses are equal */
|
/* Check that two addresses are equal */
|
||||||
static inline int sockaddr_equal(const struct sockaddr_storage *a,
|
static inline int sockaddr_equal(const struct sockaddr_storage *a,
|
||||||
@ -132,22 +171,56 @@ static inline socklen_t sockaddr_size(const struct sockaddr_storage *a)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct socket * solookup(struct socket *, struct in_addr, u_int, struct in_addr, u_int);
|
/* Copy an address */
|
||||||
struct socket * socreate(Slirp *);
|
static inline void sockaddr_copy(struct sockaddr *dst, socklen_t dstlen, const struct sockaddr *src, socklen_t srclen)
|
||||||
|
{
|
||||||
|
socklen_t len = sockaddr_size((const struct sockaddr_storage *) src);
|
||||||
|
assert(len <= srclen);
|
||||||
|
assert(len <= dstlen);
|
||||||
|
memcpy(dst, src, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the socket corresponding to lhost & fhost, trying last as a guess */
|
||||||
|
struct socket *solookup(struct socket *, struct in_addr, u_int, struct in_addr, u_int);
|
||||||
|
/* Create a new socket */
|
||||||
|
struct socket *socreate(Slirp *);
|
||||||
|
/* Release a socket */
|
||||||
void sofree(struct socket *);
|
void sofree(struct socket *);
|
||||||
|
/* Receive the available data from the Internet socket and queue it on the sb */
|
||||||
int soread(struct socket *);
|
int soread(struct socket *);
|
||||||
|
/* Receive the available OOB data from the Internet socket and try to send it immediately */
|
||||||
int sorecvoob(struct socket *);
|
int sorecvoob(struct socket *);
|
||||||
|
/* Send OOB data to the Internet socket */
|
||||||
int sosendoob(struct socket *);
|
int sosendoob(struct socket *);
|
||||||
|
/* Send data to the Internet socket */
|
||||||
int sowrite(struct socket *);
|
int sowrite(struct socket *);
|
||||||
|
/* Receive the available data from the Internet UDP socket, and send it to the guest */
|
||||||
void sorecvfrom(struct socket *);
|
void sorecvfrom(struct socket *);
|
||||||
|
/* Send data to the Internet UDP socket */
|
||||||
int sosendto(struct socket *, struct mbuf *);
|
int sosendto(struct socket *, struct mbuf *);
|
||||||
struct socket * tcp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
|
/* Listen for incoming TCPv4 connections on this haddr+hport */
|
||||||
int);
|
struct socket * tcp_listen(Slirp *, uint32_t haddr, unsigned hport, uint32_t laddr, unsigned lport, int flags);
|
||||||
|
/*
|
||||||
|
* Listen for incoming TCP connections on this haddr
|
||||||
|
* On failure errno contains the reason.
|
||||||
|
*/
|
||||||
|
struct socket * tcpx_listen(Slirp *slirp,
|
||||||
|
const struct sockaddr *haddr, socklen_t haddrlen,
|
||||||
|
const struct sockaddr *laddr, socklen_t laddrlen,
|
||||||
|
int flags);
|
||||||
|
/* Note that the socket is connecting */
|
||||||
void soisfconnecting(struct socket *);
|
void soisfconnecting(struct socket *);
|
||||||
|
/* Note that the socket is connected */
|
||||||
void soisfconnected(struct socket *);
|
void soisfconnected(struct socket *);
|
||||||
|
/*
|
||||||
|
* Set write drain mode
|
||||||
|
* Set CANTSENDMORE once all data has been write()n
|
||||||
|
*/
|
||||||
void sofwdrain(struct socket *);
|
void sofwdrain(struct socket *);
|
||||||
struct iovec; /* For win32 */
|
struct iovec; /* For win32 */
|
||||||
|
/* Prepare iov for storing into the sb */
|
||||||
size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
|
size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
|
||||||
|
/* Get data from the buffer and queue it on the sb */
|
||||||
int soreadbuf(struct socket *so, const char *buf, int size);
|
int soreadbuf(struct socket *so, const char *buf, int size);
|
||||||
|
|
||||||
#endif /* SLIRP_SOCKET_H */
|
#endif /* SLIRP_SOCKET_H */
|
||||||
|
@ -36,11 +36,12 @@
|
|||||||
|
|
||||||
typedef uint32_t tcp_seq;
|
typedef uint32_t tcp_seq;
|
||||||
|
|
||||||
#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */
|
#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */
|
||||||
#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */
|
#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */
|
||||||
|
|
||||||
#define TCP_SNDSPACE 8192
|
#define TCP_SNDSPACE 1024 * 128
|
||||||
#define TCP_RCVSPACE 8192
|
#define TCP_RCVSPACE 1024 * 128
|
||||||
|
#define TCP_MAXSEG_MAX 32768
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TCP header.
|
* TCP header.
|
||||||
|
@ -526,7 +526,7 @@ findso:
|
|||||||
win = sbspace(&so->so_rcv);
|
win = sbspace(&so->so_rcv);
|
||||||
if (win < 0)
|
if (win < 0)
|
||||||
win = 0;
|
win = 0;
|
||||||
tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));
|
tp->rcv_wnd = MAX(win, (int)(tp->rcv_adv - tp->rcv_nxt));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (tp->t_state) {
|
switch (tp->t_state) {
|
||||||
@ -952,7 +952,7 @@ trimthenstep6:
|
|||||||
else if (++tp->t_dupacks == TCPREXMTTHRESH) {
|
else if (++tp->t_dupacks == TCPREXMTTHRESH) {
|
||||||
tcp_seq onxt = tp->snd_nxt;
|
tcp_seq onxt = tp->snd_nxt;
|
||||||
u_int win =
|
u_int win =
|
||||||
min(tp->snd_wnd, tp->snd_cwnd) / 2 /
|
MIN(tp->snd_wnd, tp->snd_cwnd) / 2 /
|
||||||
tp->t_maxseg;
|
tp->t_maxseg;
|
||||||
|
|
||||||
if (win < 2)
|
if (win < 2)
|
||||||
@ -1025,7 +1025,7 @@ trimthenstep6:
|
|||||||
|
|
||||||
if (cw > tp->snd_ssthresh)
|
if (cw > tp->snd_ssthresh)
|
||||||
incr = incr * incr / cw;
|
incr = incr * incr / cw;
|
||||||
tp->snd_cwnd = min((int)(cw + incr), TCP_MAXWIN<<tp->snd_scale);
|
tp->snd_cwnd = MIN((int)(cw + incr), TCP_MAXWIN<<tp->snd_scale);
|
||||||
}
|
}
|
||||||
if (acked > (int)so->so_snd.sb_cc) {
|
if (acked > (int)so->so_snd.sb_cc) {
|
||||||
tp->snd_wnd -= so->so_snd.sb_cc;
|
tp->snd_wnd -= so->so_snd.sb_cc;
|
||||||
@ -1471,10 +1471,11 @@ tcp_mss(struct tcpcb *tp, u_int offer)
|
|||||||
DEBUG_ARG("tp = %lx", (long)tp);
|
DEBUG_ARG("tp = %lx", (long)tp);
|
||||||
DEBUG_ARG("offer = %d", offer);
|
DEBUG_ARG("offer = %d", offer);
|
||||||
|
|
||||||
mss = min(IF_MTU_DEFAULT, IF_MRU_DEFAULT) - sizeof(struct tcpiphdr);
|
mss = MIN(so->slirp->if_mtu, so->slirp->if_mru) -
|
||||||
|
sizeof(struct tcphdr) - sizeof(struct ip);
|
||||||
if (offer)
|
if (offer)
|
||||||
mss = min(mss, (int)offer);
|
mss = MIN(mss, (int)offer);
|
||||||
mss = max(mss, 32);
|
mss = MAX(mss, 32);
|
||||||
if (mss < tp->t_maxseg || offer != 0)
|
if (mss < tp->t_maxseg || offer != 0)
|
||||||
tp->t_maxseg = mss;
|
tp->t_maxseg = mss;
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ tcp_output(struct tcpcb *tp)
|
|||||||
again:
|
again:
|
||||||
sendalot = 0;
|
sendalot = 0;
|
||||||
off = tp->snd_nxt - tp->snd_una;
|
off = tp->snd_nxt - tp->snd_una;
|
||||||
win = min(tp->snd_wnd, tp->snd_cwnd);
|
win = MIN(tp->snd_wnd, tp->snd_cwnd);
|
||||||
|
|
||||||
flags = tcp_outflags[tp->t_state];
|
flags = tcp_outflags[tp->t_state];
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ again:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
len = min((long)so->so_snd.sb_cc, win) - off;
|
len = MIN((long)so->so_snd.sb_cc, win) - off;
|
||||||
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
/*
|
/*
|
||||||
@ -193,7 +193,7 @@ again:
|
|||||||
* taking into account that we are limited by
|
* taking into account that we are limited by
|
||||||
* TCP_MAXWIN << tp->rcv_scale.
|
* TCP_MAXWIN << tp->rcv_scale.
|
||||||
*/
|
*/
|
||||||
long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) -
|
long adv = MIN(win, (long)TCP_MAXWIN << tp->rcv_scale) -
|
||||||
(tp->rcv_adv - tp->rcv_nxt);
|
(tp->rcv_adv - tp->rcv_nxt);
|
||||||
|
|
||||||
if (adv >= (long) (2 * tp->t_maxseg))
|
if (adv >= (long) (2 * tp->t_maxseg))
|
||||||
|
@ -181,21 +181,26 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
|
|||||||
* empty reassembly queue and hooking it to the argument
|
* empty reassembly queue and hooking it to the argument
|
||||||
* protocol control block.
|
* protocol control block.
|
||||||
*/
|
*/
|
||||||
struct tcpcb *
|
struct tcpcb *tcp_newtcpcb(struct socket *so)
|
||||||
tcp_newtcpcb(struct socket *so)
|
|
||||||
{
|
{
|
||||||
struct tcpcb *tp;
|
struct tcpcb *tp;
|
||||||
|
|
||||||
tp = (struct tcpcb *)malloc(sizeof(*tp));
|
tp = (struct tcpcb *)malloc(sizeof(*tp));
|
||||||
if (tp == NULL)
|
if (tp == NULL)
|
||||||
return ((struct tcpcb *)0);
|
return ((struct tcpcb *)0);
|
||||||
|
|
||||||
memset((char *) tp, 0, sizeof(struct tcpcb));
|
memset((char *) tp, 0, sizeof(struct tcpcb));
|
||||||
tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
|
tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
|
||||||
tp->t_maxseg = TCP_MSS;
|
/*
|
||||||
|
* 40: length of IPv4 header (20) + TCP header (20)
|
||||||
|
* 60: length of IPv6 header (40) + TCP header (20)
|
||||||
|
*/
|
||||||
|
tp->t_maxseg =
|
||||||
|
MIN(so->slirp->if_mtu - 40,
|
||||||
|
TCP_MAXSEG_MAX);
|
||||||
|
|
||||||
tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
|
tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
|
||||||
tp->t_socket = so;
|
tp->t_socket = so;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
|
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
|
||||||
@ -900,7 +905,6 @@ int tcp_ctl(struct socket *so)
|
|||||||
Slirp *slirp = so->slirp;
|
Slirp *slirp = so->slirp;
|
||||||
struct sbuf *sb = &so->so_snd;
|
struct sbuf *sb = &so->so_snd;
|
||||||
struct gfwd_list *ex_ptr;
|
struct gfwd_list *ex_ptr;
|
||||||
int do_pty;
|
|
||||||
|
|
||||||
DEBUG_CALL("tcp_ctl");
|
DEBUG_CALL("tcp_ctl");
|
||||||
DEBUG_ARG("so = %lx", (long )so);
|
DEBUG_ARG("so = %lx", (long )so);
|
||||||
@ -910,16 +914,16 @@ int tcp_ctl(struct socket *so)
|
|||||||
for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
|
for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
|
||||||
if (ex_ptr->ex_fport == so->so_fport &&
|
if (ex_ptr->ex_fport == so->so_fport &&
|
||||||
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
|
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
|
||||||
/*
|
if (ex_ptr->write_cb) {
|
||||||
if (ex_ptr->ex_pty == 3) {
|
|
||||||
so->s = -1;
|
so->s = -1;
|
||||||
so->extra = (void *)ex_ptr->ex_exec;
|
so->guestfwd = ex_ptr;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
do_pty = ex_ptr->ex_pty;
|
DEBUG_MISC((dfd, " executing %s", ex_ptr->ex_exec));
|
||||||
*/
|
if (ex_ptr->ex_unix)
|
||||||
DEBUG_MISC((dfd, " executing %s\n", ex_ptr->ex_exec));
|
return open_unix(so, ex_ptr->ex_unix);
|
||||||
return fork_exec(so, ex_ptr->ex_exec, do_pty);
|
else
|
||||||
|
return fork_exec(so, ex_ptr->ex_exec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ tcp_timers(struct tcpcb *tp, int timer)
|
|||||||
* to go below this.)
|
* to go below this.)
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
|
u_int win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
|
||||||
if (win < 2)
|
if (win < 2)
|
||||||
win = 2;
|
win = 2;
|
||||||
tp->snd_cwnd = tp->t_maxseg;
|
tp->snd_cwnd = tp->t_maxseg;
|
||||||
|
Loading…
Reference in New Issue
Block a user