mirror of https://github.com/xqemu/xqemu.git
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJWswswAAoJEO8Ells5jWIRmuAIAKfexolRpauVFoMt2w69Yrk4 0XhaAuSaazsfU06azXKjrchBUgXbw4Y6lw3tkTos4lnd8m1ovfAzSTS4q28rZ+Tf u5M06Fi13oyhEViGS4gt6gTwmYPTx2FTBDMCL1OZvka7GPbVsweQn0IS18j1Q2xL ps2kruNTad7mUa2EypuBugm3woL8kGupLUX63aWKmnvqobwFDNTKJLWiFn5eXlbg Zq7LxmC4R3A5K9rD8wN16ScaK3RH2x83DXaRoddtSIRwdldxG9ZCv2oFKPZrr6WA HsJIjurMTXhaRxNL3PsGMd/MbT7gmNF5muq8kZnkORmGxfMvi3RUuBdyhrq1I0w= =2Uz/ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging # gpg: Signature made Thu 04 Feb 2016 08:26:24 GMT using RSA key ID 398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211 * remotes/jasowang/tags/net-pull-request: net/filter: Fix the output information for command 'info network' net: always walk through filters in reverse if traffic is egress net: netmap: use nm_open() to open netmap ports e1000: eliminate infinite loops on out-of-bounds transfer start slirp: Adding family argument to tcp_fconnect() slirp: Make udp_attach IPv6 compatible slirp: Add sockaddr_equal, make solookup family-agnostic slirp: Factorizing and cleaning solookup() slirp: Factorizing address translation slirp: Make Socket structure IPv6 compatible slirp: Adding address family switch for produced frames slirp: Generalizing and neutralizing ARP code slirp: goto bad in udp_input if sosendto fails cadence_gem: fix buffer overflow net: cadence_gem: check packet size in gem_recieve qemu-doc: Do not promote deprecated -smb and -redir options net/slirp: Tell the users when they are using deprecated options Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
bac8e20367
|
@ -678,6 +678,10 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||
} else {
|
||||
unsigned crc_val;
|
||||
|
||||
if (size > sizeof(rxbuf) - sizeof(crc_val)) {
|
||||
size = sizeof(rxbuf) - sizeof(crc_val);
|
||||
}
|
||||
bytes_to_copy = size;
|
||||
/* The application wants the FCS field, which QEMU does not provide.
|
||||
* We must try and calculate one.
|
||||
*/
|
||||
|
@ -863,6 +867,14 @@ static void gem_transmit(CadenceGEMState *s)
|
|||
break;
|
||||
}
|
||||
|
||||
if (tx_desc_get_length(desc) > sizeof(tx_packet) - (p - tx_packet)) {
|
||||
DB_PRINT("TX descriptor @ 0x%x too large: size 0x%x space 0x%x\n",
|
||||
(unsigned)packet_desc_addr,
|
||||
(unsigned)tx_desc_get_length(desc),
|
||||
sizeof(tx_packet) - (p - tx_packet));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Gather this fragment of the packet from "dma memory" to our contig.
|
||||
* buffer.
|
||||
*/
|
||||
|
|
|
@ -909,7 +909,8 @@ start_xmit(E1000State *s)
|
|||
* bogus values to TDT/TDLEN.
|
||||
* there's nothing too intelligent we could do about this.
|
||||
*/
|
||||
if (s->mac_reg[TDH] == tdh_start) {
|
||||
if (s->mac_reg[TDH] == tdh_start ||
|
||||
tdh_start >= s->mac_reg[TDLEN] / sizeof(desc)) {
|
||||
DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
|
||||
tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
|
||||
break;
|
||||
|
@ -1166,7 +1167,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
|
|||
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
|
||||
s->mac_reg[RDH] = 0;
|
||||
/* see comment in start_xmit; same here */
|
||||
if (s->mac_reg[RDH] == rdh_start) {
|
||||
if (s->mac_reg[RDH] == rdh_start ||
|
||||
rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) {
|
||||
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
|
||||
rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
|
||||
set_ics(s, 0, E1000_ICS_RXO);
|
||||
|
|
|
@ -55,7 +55,6 @@ struct NetFilterState {
|
|||
char *netdev_id;
|
||||
NetClientState *netdev;
|
||||
NetFilterDirection direction;
|
||||
char info_str[256];
|
||||
QTAILQ_ENTRY(NetFilterState) next;
|
||||
};
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ struct NetClientState {
|
|||
NetClientDestructor *destructor;
|
||||
unsigned int queue_index;
|
||||
unsigned rxfilter_notify_enabled:1;
|
||||
QTAILQ_HEAD(, NetFilterState) filters;
|
||||
QTAILQ_HEAD(NetFilterHead, NetFilterState) filters;
|
||||
};
|
||||
|
||||
typedef struct NICState {
|
||||
|
|
43
net/filter.c
43
net/filter.c
|
@ -15,7 +15,6 @@
|
|||
#include "net/vhost_net.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qapi/string-output-visitor.h"
|
||||
|
||||
ssize_t qemu_netfilter_receive(NetFilterState *nf,
|
||||
NetFilterDirection direction,
|
||||
|
@ -34,6 +33,22 @@ ssize_t qemu_netfilter_receive(NetFilterState *nf,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static NetFilterState *netfilter_next(NetFilterState *nf,
|
||||
NetFilterDirection dir)
|
||||
{
|
||||
NetFilterState *next;
|
||||
|
||||
if (dir == NET_FILTER_DIRECTION_TX) {
|
||||
/* forward walk through filters */
|
||||
next = QTAILQ_NEXT(nf, next);
|
||||
} else {
|
||||
/* reverse order */
|
||||
next = QTAILQ_PREV(nf, NetFilterHead, next);
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
ssize_t qemu_netfilter_pass_to_next(NetClientState *sender,
|
||||
unsigned flags,
|
||||
const struct iovec *iov,
|
||||
|
@ -43,7 +58,7 @@ ssize_t qemu_netfilter_pass_to_next(NetClientState *sender,
|
|||
int ret = 0;
|
||||
int direction;
|
||||
NetFilterState *nf = opaque;
|
||||
NetFilterState *next = QTAILQ_NEXT(nf, next);
|
||||
NetFilterState *next = NULL;
|
||||
|
||||
if (!sender || !sender->peer) {
|
||||
/* no receiver, or sender been deleted, no need to pass it further */
|
||||
|
@ -61,6 +76,7 @@ ssize_t qemu_netfilter_pass_to_next(NetClientState *sender,
|
|||
direction = nf->direction;
|
||||
}
|
||||
|
||||
next = netfilter_next(nf, direction);
|
||||
while (next) {
|
||||
/*
|
||||
* if qemu_netfilter_pass_to_next been called, means that
|
||||
|
@ -73,7 +89,7 @@ ssize_t qemu_netfilter_pass_to_next(NetClientState *sender,
|
|||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
next = QTAILQ_NEXT(next, next);
|
||||
next = netfilter_next(next, direction);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -135,10 +151,6 @@ static void netfilter_complete(UserCreatable *uc, Error **errp)
|
|||
NetFilterClass *nfc = NETFILTER_GET_CLASS(uc);
|
||||
int queues;
|
||||
Error *local_err = NULL;
|
||||
char *str, *info;
|
||||
ObjectProperty *prop;
|
||||
ObjectPropertyIterator iter;
|
||||
StringOutputVisitor *ov;
|
||||
|
||||
if (!nf->netdev_id) {
|
||||
error_setg(errp, "Parameter 'netdev' is required");
|
||||
|
@ -172,23 +184,6 @@ static void netfilter_complete(UserCreatable *uc, Error **errp)
|
|||
}
|
||||
}
|
||||
QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next);
|
||||
|
||||
/* generate info str */
|
||||
object_property_iter_init(&iter, OBJECT(nf));
|
||||
while ((prop = object_property_iter_next(&iter))) {
|
||||
if (!strcmp(prop->name, "type")) {
|
||||
continue;
|
||||
}
|
||||
ov = string_output_visitor_new(false);
|
||||
object_property_get(OBJECT(nf), string_output_get_visitor(ov),
|
||||
prop->name, errp);
|
||||
str = string_output_get_string(ov);
|
||||
string_output_visitor_cleanup(ov);
|
||||
info = g_strdup_printf(",%s=%s", prop->name, str);
|
||||
g_strlcat(nf->info_str, info, sizeof(nf->info_str));
|
||||
g_free(str);
|
||||
g_free(info);
|
||||
}
|
||||
}
|
||||
|
||||
static void netfilter_finalize(Object *obj)
|
||||
|
|
52
net/net.c
52
net/net.c
|
@ -45,6 +45,7 @@
|
|||
#include "qapi/dealloc-visitor.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "net/filter.h"
|
||||
#include "qapi/string-output-visitor.h"
|
||||
|
||||
/* Net bridge is currently not supported for W32. */
|
||||
#if !defined(_WIN32)
|
||||
|
@ -580,11 +581,21 @@ static ssize_t filter_receive_iov(NetClientState *nc,
|
|||
ssize_t ret = 0;
|
||||
NetFilterState *nf = NULL;
|
||||
|
||||
QTAILQ_FOREACH(nf, &nc->filters, next) {
|
||||
ret = qemu_netfilter_receive(nf, direction, sender, flags, iov,
|
||||
iovcnt, sent_cb);
|
||||
if (ret) {
|
||||
return ret;
|
||||
if (direction == NET_FILTER_DIRECTION_TX) {
|
||||
QTAILQ_FOREACH(nf, &nc->filters, next) {
|
||||
ret = qemu_netfilter_receive(nf, direction, sender, flags, iov,
|
||||
iovcnt, sent_cb);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QTAILQ_FOREACH_REVERSE(nf, &nc->filters, NetFilterHead, next) {
|
||||
ret = qemu_netfilter_receive(nf, direction, sender, flags, iov,
|
||||
iovcnt, sent_cb);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1185,6 +1196,30 @@ void qmp_netdev_del(const char *id, Error **errp)
|
|||
qemu_opts_del(opts);
|
||||
}
|
||||
|
||||
static void netfilter_print_info(Monitor *mon, NetFilterState *nf)
|
||||
{
|
||||
char *str;
|
||||
ObjectProperty *prop;
|
||||
ObjectPropertyIterator iter;
|
||||
StringOutputVisitor *ov;
|
||||
|
||||
/* generate info str */
|
||||
object_property_iter_init(&iter, OBJECT(nf));
|
||||
while ((prop = object_property_iter_next(&iter))) {
|
||||
if (!strcmp(prop->name, "type")) {
|
||||
continue;
|
||||
}
|
||||
ov = string_output_visitor_new(false);
|
||||
object_property_get(OBJECT(nf), string_output_get_visitor(ov),
|
||||
prop->name, NULL);
|
||||
str = string_output_get_string(ov);
|
||||
string_output_visitor_cleanup(ov);
|
||||
monitor_printf(mon, ",%s=%s", prop->name, str);
|
||||
g_free(str);
|
||||
}
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
void print_net_client(Monitor *mon, NetClientState *nc)
|
||||
{
|
||||
NetFilterState *nf;
|
||||
|
@ -1198,9 +1233,10 @@ void print_net_client(Monitor *mon, NetClientState *nc)
|
|||
}
|
||||
QTAILQ_FOREACH(nf, &nc->filters, next) {
|
||||
char *path = object_get_canonical_path_component(OBJECT(nf));
|
||||
monitor_printf(mon, " - %s: type=%s%s\n", path,
|
||||
object_get_typename(OBJECT(nf)),
|
||||
nf->info_str);
|
||||
|
||||
monitor_printf(mon, " - %s: type=%s", path,
|
||||
object_get_typename(OBJECT(nf)));
|
||||
netfilter_print_info(mon, nf);
|
||||
g_free(path);
|
||||
}
|
||||
}
|
||||
|
|
97
net/netmap.c
97
net/netmap.c
|
@ -39,21 +39,12 @@
|
|||
#include "qemu/error-report.h"
|
||||
#include "qemu/iov.h"
|
||||
|
||||
/* Private netmap device info. */
|
||||
typedef struct NetmapPriv {
|
||||
int fd;
|
||||
size_t memsize;
|
||||
void *mem;
|
||||
struct netmap_if *nifp;
|
||||
struct netmap_ring *rx;
|
||||
struct netmap_ring *tx;
|
||||
char fdname[PATH_MAX]; /* Normally "/dev/netmap". */
|
||||
char ifname[IFNAMSIZ];
|
||||
} NetmapPriv;
|
||||
|
||||
typedef struct NetmapState {
|
||||
NetClientState nc;
|
||||
NetmapPriv me;
|
||||
struct nm_desc *nmd;
|
||||
char ifname[IFNAMSIZ];
|
||||
struct netmap_ring *tx;
|
||||
struct netmap_ring *rx;
|
||||
bool read_poll;
|
||||
bool write_poll;
|
||||
struct iovec iov[IOV_MAX];
|
||||
|
@ -90,44 +81,23 @@ pkt_copy(const void *_src, void *_dst, int l)
|
|||
* Open a netmap device. We assume there is only one queue
|
||||
* (which is the case for the VALE bridge).
|
||||
*/
|
||||
static void netmap_open(NetmapPriv *me, Error **errp)
|
||||
static struct nm_desc *netmap_open(const NetdevNetmapOptions *nm_opts,
|
||||
Error **errp)
|
||||
{
|
||||
int fd;
|
||||
int err;
|
||||
size_t l;
|
||||
struct nm_desc *nmd;
|
||||
struct nmreq req;
|
||||
|
||||
me->fd = fd = open(me->fdname, O_RDWR);
|
||||
if (fd < 0) {
|
||||
error_setg_file_open(errp, errno, me->fdname);
|
||||
return;
|
||||
}
|
||||
memset(&req, 0, sizeof(req));
|
||||
pstrcpy(req.nr_name, sizeof(req.nr_name), me->ifname);
|
||||
req.nr_ringid = NETMAP_NO_TX_POLL;
|
||||
req.nr_version = NETMAP_API;
|
||||
err = ioctl(fd, NIOCREGIF, &req);
|
||||
if (err) {
|
||||
error_setg_errno(errp, errno, "Unable to register %s", me->ifname);
|
||||
goto error;
|
||||
}
|
||||
l = me->memsize = req.nr_memsize;
|
||||
|
||||
me->mem = mmap(0, l, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (me->mem == MAP_FAILED) {
|
||||
error_setg_errno(errp, errno, "Unable to mmap netmap shared memory");
|
||||
me->mem = NULL;
|
||||
goto error;
|
||||
nmd = nm_open(nm_opts->ifname, &req, NETMAP_NO_TX_POLL,
|
||||
NULL);
|
||||
if (nmd == NULL) {
|
||||
error_setg_errno(errp, errno, "Failed to nm_open() %s",
|
||||
nm_opts->ifname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
me->nifp = NETMAP_IF(me->mem, req.nr_offset);
|
||||
me->tx = NETMAP_TXRING(me->nifp, 0);
|
||||
me->rx = NETMAP_RXRING(me->nifp, 0);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
close(me->fd);
|
||||
return nmd;
|
||||
}
|
||||
|
||||
static void netmap_send(void *opaque);
|
||||
|
@ -136,7 +106,7 @@ static void netmap_writable(void *opaque);
|
|||
/* Set the event-loop handlers for the netmap backend. */
|
||||
static void netmap_update_fd_handler(NetmapState *s)
|
||||
{
|
||||
qemu_set_fd_handler(s->me.fd,
|
||||
qemu_set_fd_handler(s->nmd->fd,
|
||||
s->read_poll ? netmap_send : NULL,
|
||||
s->write_poll ? netmap_writable : NULL,
|
||||
s);
|
||||
|
@ -188,7 +158,7 @@ static ssize_t netmap_receive(NetClientState *nc,
|
|||
const uint8_t *buf, size_t size)
|
||||
{
|
||||
NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
|
||||
struct netmap_ring *ring = s->me.tx;
|
||||
struct netmap_ring *ring = s->tx;
|
||||
uint32_t i;
|
||||
uint32_t idx;
|
||||
uint8_t *dst;
|
||||
|
@ -218,7 +188,7 @@ static ssize_t netmap_receive(NetClientState *nc,
|
|||
ring->slot[i].flags = 0;
|
||||
pkt_copy(buf, dst, size);
|
||||
ring->cur = ring->head = nm_ring_next(ring, i);
|
||||
ioctl(s->me.fd, NIOCTXSYNC, NULL);
|
||||
ioctl(s->nmd->fd, NIOCTXSYNC, NULL);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
@ -227,7 +197,7 @@ static ssize_t netmap_receive_iov(NetClientState *nc,
|
|||
const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
|
||||
struct netmap_ring *ring = s->me.tx;
|
||||
struct netmap_ring *ring = s->tx;
|
||||
uint32_t last;
|
||||
uint32_t idx;
|
||||
uint8_t *dst;
|
||||
|
@ -284,7 +254,7 @@ static ssize_t netmap_receive_iov(NetClientState *nc,
|
|||
/* Now update ring->cur and ring->head. */
|
||||
ring->cur = ring->head = i;
|
||||
|
||||
ioctl(s->me.fd, NIOCTXSYNC, NULL);
|
||||
ioctl(s->nmd->fd, NIOCTXSYNC, NULL);
|
||||
|
||||
return iov_size(iov, iovcnt);
|
||||
}
|
||||
|
@ -301,7 +271,7 @@ static void netmap_send_completed(NetClientState *nc, ssize_t len)
|
|||
static void netmap_send(void *opaque)
|
||||
{
|
||||
NetmapState *s = opaque;
|
||||
struct netmap_ring *ring = s->me.rx;
|
||||
struct netmap_ring *ring = s->rx;
|
||||
|
||||
/* Keep sending while there are available packets into the netmap
|
||||
RX ring and the forwarding path towards the peer is open. */
|
||||
|
@ -349,10 +319,8 @@ static void netmap_cleanup(NetClientState *nc)
|
|||
qemu_purge_queued_packets(nc);
|
||||
|
||||
netmap_poll(nc, false);
|
||||
munmap(s->me.mem, s->me.memsize);
|
||||
close(s->me.fd);
|
||||
|
||||
s->me.fd = -1;
|
||||
nm_close(s->nmd);
|
||||
s->nmd = NULL;
|
||||
}
|
||||
|
||||
/* Offloading manipulation support callbacks. */
|
||||
|
@ -383,17 +351,17 @@ static void netmap_set_vnet_hdr_len(NetClientState *nc, int len)
|
|||
struct nmreq req;
|
||||
|
||||
/* Issue a NETMAP_BDG_VNET_HDR command to change the virtio-net header
|
||||
* length for the netmap adapter associated to 'me->ifname'.
|
||||
* length for the netmap adapter associated to 's->ifname'.
|
||||
*/
|
||||
memset(&req, 0, sizeof(req));
|
||||
pstrcpy(req.nr_name, sizeof(req.nr_name), s->me.ifname);
|
||||
pstrcpy(req.nr_name, sizeof(req.nr_name), s->ifname);
|
||||
req.nr_version = NETMAP_API;
|
||||
req.nr_cmd = NETMAP_BDG_VNET_HDR;
|
||||
req.nr_arg1 = len;
|
||||
err = ioctl(s->me.fd, NIOCREGIF, &req);
|
||||
err = ioctl(s->nmd->fd, NIOCREGIF, &req);
|
||||
if (err) {
|
||||
error_report("Unable to execute NETMAP_BDG_VNET_HDR on %s: %s",
|
||||
s->me.ifname, strerror(errno));
|
||||
s->ifname, strerror(errno));
|
||||
} else {
|
||||
/* Keep track of the current length. */
|
||||
s->vnet_hdr_len = len;
|
||||
|
@ -437,16 +405,12 @@ int net_init_netmap(const NetClientOptions *opts,
|
|||
const char *name, NetClientState *peer, Error **errp)
|
||||
{
|
||||
const NetdevNetmapOptions *netmap_opts = opts->u.netmap;
|
||||
struct nm_desc *nmd;
|
||||
NetClientState *nc;
|
||||
Error *err = NULL;
|
||||
NetmapPriv me;
|
||||
NetmapState *s;
|
||||
|
||||
pstrcpy(me.fdname, sizeof(me.fdname),
|
||||
netmap_opts->has_devname ? netmap_opts->devname : "/dev/netmap");
|
||||
/* Set default name for the port if not supplied. */
|
||||
pstrcpy(me.ifname, sizeof(me.ifname), netmap_opts->ifname);
|
||||
netmap_open(&me, &err);
|
||||
nmd = netmap_open(netmap_opts, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return -1;
|
||||
|
@ -454,8 +418,11 @@ int net_init_netmap(const NetClientOptions *opts,
|
|||
/* Create the object. */
|
||||
nc = qemu_new_net_client(&net_netmap_info, peer, "netmap", name);
|
||||
s = DO_UPCAST(NetmapState, nc, nc);
|
||||
s->me = me;
|
||||
s->nmd = nmd;
|
||||
s->tx = NETMAP_TXRING(nmd->nifp, 0);
|
||||
s->rx = NETMAP_RXRING(nmd->nifp, 0);
|
||||
s->vnet_hdr_len = 0;
|
||||
pstrcpy(s->ifname, sizeof(s->ifname), netmap_opts->ifname);
|
||||
netmap_read_poll(s, true); /* Initially only poll for reads. */
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -784,6 +784,9 @@ int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret
|
|||
return 0;
|
||||
}
|
||||
|
||||
error_report("The '-net channel' option is deprecated. "
|
||||
"Please use '-netdev user,guestfwd=...' instead.");
|
||||
|
||||
/* handle legacy -net channel,port:chr */
|
||||
optarg += strlen("channel,");
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "net/slirp.h"
|
||||
#include "qemu-options.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
#include <sys/prctl.h>
|
||||
|
@ -139,6 +140,8 @@ void os_parse_cmd_args(int index, const char *optarg)
|
|||
switch (index) {
|
||||
#ifdef CONFIG_SLIRP
|
||||
case QEMU_OPTION_smb:
|
||||
error_report("The -smb option is deprecated. "
|
||||
"Please use '-netdev user,smb=...' instead.");
|
||||
if (net_slirp_smb(optarg) < 0)
|
||||
exit(1);
|
||||
break;
|
||||
|
|
|
@ -1237,9 +1237,9 @@ echo 100 100 > /proc/sys/net/ipv4/ping_group_range
|
|||
When using the built-in TFTP server, the router is also the TFTP
|
||||
server.
|
||||
|
||||
When using the @option{-redir} option, TCP or UDP connections can be
|
||||
redirected from the host to the guest. It allows for example to
|
||||
redirect X11, telnet or SSH connections.
|
||||
When using the @option{'-netdev user,hostfwd=...'} option, TCP or UDP
|
||||
connections can be redirected from the host to the guest. It allows for
|
||||
example to redirect X11, telnet or SSH connections.
|
||||
|
||||
@subsection Connecting VLANs between QEMU instances
|
||||
|
||||
|
@ -1889,7 +1889,8 @@ correctly instructs QEMU to shutdown at the appropriate moment.
|
|||
|
||||
@subsubsection Share a directory between Unix and Windows
|
||||
|
||||
See @ref{sec_invocation} about the help of the option @option{-smb}.
|
||||
See @ref{sec_invocation} about the help of the option
|
||||
@option{'-netdev user,smb=...'}.
|
||||
|
||||
@subsubsection Windows XP security problem
|
||||
|
||||
|
|
|
@ -325,7 +325,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
|
|||
|
||||
m->m_len = sizeof(struct bootp_t) -
|
||||
sizeof(struct ip) - sizeof(struct udphdr);
|
||||
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
|
||||
udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
|
||||
}
|
||||
|
||||
void bootp_input(struct mbuf *m)
|
||||
|
|
|
@ -157,12 +157,12 @@ icmp_input(struct mbuf *m, int hlen)
|
|||
goto freeit;
|
||||
} else {
|
||||
struct socket *so;
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_storage addr;
|
||||
if ((so = socreate(slirp)) == NULL) goto freeit;
|
||||
if (icmp_send(so, m, hlen) == 0) {
|
||||
return;
|
||||
}
|
||||
if(udp_attach(so) == -1) {
|
||||
if (udp_attach(so, AF_INET) == -1) {
|
||||
DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
|
||||
errno,strerror(errno)));
|
||||
sofree(so);
|
||||
|
@ -170,8 +170,10 @@ icmp_input(struct mbuf *m, int hlen)
|
|||
goto end_error;
|
||||
}
|
||||
so->so_m = m;
|
||||
so->so_ffamily = AF_INET;
|
||||
so->so_faddr = ip->ip_dst;
|
||||
so->so_fport = htons(7);
|
||||
so->so_lfamily = AF_INET;
|
||||
so->so_laddr = ip->ip_src;
|
||||
so->so_lport = htons(9);
|
||||
so->so_iptos = ip->ip_tos;
|
||||
|
@ -179,20 +181,9 @@ icmp_input(struct mbuf *m, int hlen)
|
|||
so->so_state = SS_ISFCONNECTED;
|
||||
|
||||
/* Send the packet */
|
||||
addr.sin_family = AF_INET;
|
||||
if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
|
||||
slirp->vnetwork_addr.s_addr) {
|
||||
/* It's an alias */
|
||||
if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
|
||||
if (get_dns_addr(&addr.sin_addr) < 0)
|
||||
addr.sin_addr = loopback_addr;
|
||||
} else {
|
||||
addr.sin_addr = loopback_addr;
|
||||
}
|
||||
} else {
|
||||
addr.sin_addr = so->so_faddr;
|
||||
}
|
||||
addr.sin_port = so->so_fport;
|
||||
addr = so->fhost.ss;
|
||||
sotranslate_out(so, &addr);
|
||||
|
||||
if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
|
||||
|
|
|
@ -91,7 +91,7 @@ m_get(Slirp *slirp)
|
|||
m->m_len = 0;
|
||||
m->m_nextpkt = NULL;
|
||||
m->m_prevpkt = NULL;
|
||||
m->arp_requested = false;
|
||||
m->resolution_requested = false;
|
||||
m->expiration_date = (uint64_t)-1;
|
||||
end_error:
|
||||
DEBUG_ARG("m = %p", m);
|
||||
|
|
|
@ -79,7 +79,7 @@ struct mbuf {
|
|||
int m_len; /* Amount of data in this mbuf */
|
||||
|
||||
Slirp *slirp;
|
||||
bool arp_requested;
|
||||
bool resolution_requested;
|
||||
uint64_t expiration_date;
|
||||
/* start of dynamic buffer area, must be last element */
|
||||
union {
|
||||
|
|
116
slirp/slirp.c
116
slirp/slirp.c
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "slirp.h"
|
||||
#include "hw/hw.h"
|
||||
|
@ -234,7 +235,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
|
|||
|
||||
slirp->opaque = opaque;
|
||||
|
||||
register_savevm(NULL, "slirp", 0, 3,
|
||||
register_savevm(NULL, "slirp", 0, 4,
|
||||
slirp_state_save, slirp_state_load, slirp);
|
||||
|
||||
QTAILQ_INSERT_TAIL(&slirp_instances, slirp, entry);
|
||||
|
@ -762,20 +763,15 @@ 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
|
||||
* re-queued.
|
||||
/* Prepare the IPv4 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.
|
||||
*/
|
||||
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;
|
||||
|
||||
if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (iph->ip_dst.s_addr == 0) {
|
||||
/* 0.0.0.0 can not be a destination address, something went wrong,
|
||||
* avoid making it worse */
|
||||
|
@ -786,7 +782,7 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
|
|||
struct ethhdr *reh = (struct ethhdr *)arp_req;
|
||||
struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
|
||||
|
||||
if (!ifm->arp_requested) {
|
||||
if (!ifm->resolution_requested) {
|
||||
/* If the client addr is not known, send an ARP request */
|
||||
memset(reh->h_dest, 0xff, ETH_ALEN);
|
||||
memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
|
||||
|
@ -812,22 +808,62 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
|
|||
rah->ar_tip = iph->ip_dst.s_addr;
|
||||
slirp->client_ipaddr = iph->ip_dst;
|
||||
slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
|
||||
ifm->arp_requested = true;
|
||||
ifm->resolution_requested = true;
|
||||
|
||||
/* Expire request and drop outgoing packet after 1 second */
|
||||
ifm->expiration_date = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
memcpy(eh->h_dest, ethaddr, ETH_ALEN);
|
||||
memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
|
||||
/* XXX: not correct */
|
||||
memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
|
||||
eh->h_proto = htons(ETH_P_IP);
|
||||
memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
|
||||
slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
|
||||
|
||||
/* Send this */
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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[1600];
|
||||
struct ethhdr *eh = (struct ethhdr *)buf;
|
||||
uint8_t ethaddr[ETH_ALEN];
|
||||
const struct ip *iph = (const struct ip *)ifm->m_data;
|
||||
int ret;
|
||||
|
||||
if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (iph->ip_v) {
|
||||
case IPVERSION:
|
||||
ret = if_encap4(slirp, ifm, eh, ethaddr);
|
||||
if (ret < 2) {
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Do not assert while we don't manage IP6VERSION */
|
||||
/* assert(0); */
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(eh->h_dest, ethaddr, ETH_ALEN);
|
||||
DEBUG_ARGS((dfd, " src = %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
eh->h_source[0], eh->h_source[1], eh->h_source[2],
|
||||
eh->h_source[3], eh->h_source[4], eh->h_source[5]));
|
||||
DEBUG_ARGS((dfd, " dst = %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
|
||||
eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]));
|
||||
memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
|
||||
slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Drop host forwarding rule, return 0 if found. */
|
||||
|
@ -1011,10 +1047,26 @@ static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
|
|||
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_be16(f, so->so_ffamily);
|
||||
switch (so->so_ffamily) {
|
||||
case AF_INET:
|
||||
qemu_put_be32(f, so->so_faddr.s_addr);
|
||||
qemu_put_be16(f, so->so_fport);
|
||||
break;
|
||||
default:
|
||||
error_report(
|
||||
"so_ffamily unknown, unable to save so_faddr and so_fport\n");
|
||||
}
|
||||
qemu_put_be16(f, so->so_lfamily);
|
||||
switch (so->so_lfamily) {
|
||||
case AF_INET:
|
||||
qemu_put_be32(f, so->so_laddr.s_addr);
|
||||
qemu_put_be16(f, so->so_lport);
|
||||
break;
|
||||
default:
|
||||
error_report(
|
||||
"so_ffamily unknown, unable to save so_laddr and so_lport\n");
|
||||
}
|
||||
qemu_put_byte(f, so->so_iptos);
|
||||
qemu_put_byte(f, so->so_emu);
|
||||
qemu_put_byte(f, so->so_type);
|
||||
|
@ -1134,10 +1186,26 @@ static int slirp_socket_load(QEMUFile *f, struct socket *so)
|
|||
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_ffamily = qemu_get_be16(f);
|
||||
switch (so->so_ffamily) {
|
||||
case AF_INET:
|
||||
so->so_faddr.s_addr = qemu_get_be32(f);
|
||||
so->so_fport = qemu_get_be16(f);
|
||||
break;
|
||||
default:
|
||||
error_report(
|
||||
"so_ffamily unknown, unable to restore so_faddr and so_lport\n");
|
||||
}
|
||||
so->so_lfamily = qemu_get_be16(f);
|
||||
switch (so->so_lfamily) {
|
||||
case AF_INET:
|
||||
so->so_laddr.s_addr = qemu_get_be32(f);
|
||||
so->so_lport = qemu_get_be16(f);
|
||||
break;
|
||||
default:
|
||||
error_report(
|
||||
"so_ffamily unknown, unable to restore so_laddr and so_lport\n");
|
||||
}
|
||||
so->so_iptos = qemu_get_byte(f);
|
||||
so->so_emu = qemu_get_byte(f);
|
||||
so->so_type = qemu_get_byte(f);
|
||||
|
|
|
@ -327,7 +327,7 @@ void tcp_respond(struct tcpcb *, register struct tcpiphdr *, register struct mbu
|
|||
struct tcpcb * tcp_newtcpcb(struct socket *);
|
||||
struct tcpcb * tcp_close(register struct tcpcb *);
|
||||
void tcp_sockclosed(struct tcpcb *);
|
||||
int tcp_fconnect(struct socket *);
|
||||
int tcp_fconnect(struct socket *, unsigned short af);
|
||||
void tcp_connect(struct socket *);
|
||||
int tcp_attach(struct socket *);
|
||||
uint8_t tcp_tos(struct socket *);
|
||||
|
|
154
slirp/socket.c
154
slirp/socket.c
|
@ -15,24 +15,26 @@
|
|||
static void sofcantrcvmore(struct socket *so);
|
||||
static void sofcantsendmore(struct socket *so);
|
||||
|
||||
struct socket *
|
||||
solookup(struct socket *head, struct in_addr laddr, u_int lport,
|
||||
struct in_addr faddr, u_int fport)
|
||||
struct socket *solookup(struct socket **last, struct socket *head,
|
||||
struct sockaddr_storage *lhost, struct sockaddr_storage *fhost)
|
||||
{
|
||||
struct socket *so;
|
||||
struct socket *so = *last;
|
||||
|
||||
for (so = head->so_next; so != head; so = so->so_next) {
|
||||
if (so->so_lport == lport &&
|
||||
so->so_laddr.s_addr == laddr.s_addr &&
|
||||
so->so_faddr.s_addr == faddr.s_addr &&
|
||||
so->so_fport == fport)
|
||||
break;
|
||||
}
|
||||
/* Optimisation */
|
||||
if (so != head && sockaddr_equal(&(so->lhost.ss), lhost)
|
||||
&& (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) {
|
||||
return so;
|
||||
}
|
||||
|
||||
if (so == head)
|
||||
return (struct socket *)NULL;
|
||||
return so;
|
||||
for (so = head->so_next; so != head; so = so->so_next) {
|
||||
if (sockaddr_equal(&(so->lhost.ss), lhost)
|
||||
&& (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) {
|
||||
*last = so;
|
||||
return so;
|
||||
}
|
||||
}
|
||||
|
||||
return (struct socket *)NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -437,8 +439,9 @@ sowrite(struct socket *so)
|
|||
void
|
||||
sorecvfrom(struct socket *so)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrlen = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_storage addr;
|
||||
struct sockaddr_storage saddr, daddr;
|
||||
socklen_t addrlen = sizeof(struct sockaddr_storage);
|
||||
|
||||
DEBUG_CALL("sorecvfrom");
|
||||
DEBUG_ARG("so = %p", so);
|
||||
|
@ -525,9 +528,21 @@ sorecvfrom(struct socket *so)
|
|||
|
||||
/*
|
||||
* If this packet was destined for CTL_ADDR,
|
||||
* make it look like that's where it came from, done by udp_output
|
||||
* make it look like that's where it came from
|
||||
*/
|
||||
udp_output(so, m, &addr);
|
||||
saddr = addr;
|
||||
sotranslate_in(so, &saddr);
|
||||
daddr = so->lhost.ss;
|
||||
|
||||
switch (so->so_ffamily) {
|
||||
case AF_INET:
|
||||
udp_output(so, m, (struct sockaddr_in *) &saddr,
|
||||
(struct sockaddr_in *) &daddr,
|
||||
so->so_iptos);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} /* rx error */
|
||||
} /* if ping packet */
|
||||
}
|
||||
|
@ -538,33 +553,20 @@ sorecvfrom(struct socket *so)
|
|||
int
|
||||
sosendto(struct socket *so, struct mbuf *m)
|
||||
{
|
||||
Slirp *slirp = so->slirp;
|
||||
int ret;
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
DEBUG_CALL("sosendto");
|
||||
DEBUG_ARG("so = %p", so);
|
||||
DEBUG_ARG("m = %p", m);
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
|
||||
slirp->vnetwork_addr.s_addr) {
|
||||
/* It's an alias */
|
||||
if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
|
||||
if (get_dns_addr(&addr.sin_addr) < 0)
|
||||
addr.sin_addr = loopback_addr;
|
||||
} else {
|
||||
addr.sin_addr = loopback_addr;
|
||||
}
|
||||
} else
|
||||
addr.sin_addr = so->so_faddr;
|
||||
addr.sin_port = so->so_fport;
|
||||
|
||||
DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
|
||||
addr = so->fhost.ss;
|
||||
DEBUG_CALL(" sendto()ing)");
|
||||
sotranslate_out(so, &addr);
|
||||
|
||||
/* Don't care what port we get */
|
||||
ret = sendto(so->s, m->m_data, m->m_len, 0,
|
||||
(struct sockaddr *)&addr, sizeof (struct sockaddr));
|
||||
(struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
|
@ -619,6 +621,7 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
|
|||
|
||||
so->so_state &= SS_PERSISTENT_MASK;
|
||||
so->so_state |= (SS_FACCEPTCONN | flags);
|
||||
so->so_lfamily = AF_INET;
|
||||
so->so_lport = lport; /* Kept in network format */
|
||||
so->so_laddr.s_addr = laddr; /* Ditto */
|
||||
|
||||
|
@ -645,6 +648,7 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
|
|||
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
|
||||
|
||||
getsockname(s,(struct sockaddr *)&addr,&addrlen);
|
||||
so->so_ffamily = AF_INET;
|
||||
so->so_fport = addr.sin_port;
|
||||
if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
|
||||
so->so_faddr = slirp->vhost_addr;
|
||||
|
@ -718,3 +722,81 @@ sofwdrain(struct socket *so)
|
|||
else
|
||||
sofcantsendmore(so);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate addr in host addr when it is a virtual address
|
||||
*/
|
||||
void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
|
||||
{
|
||||
Slirp *slirp = so->slirp;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
|
||||
|
||||
switch (addr->ss_family) {
|
||||
case AF_INET:
|
||||
if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
|
||||
slirp->vnetwork_addr.s_addr) {
|
||||
/* It's an alias */
|
||||
if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
|
||||
if (get_dns_addr(&sin->sin_addr) < 0) {
|
||||
sin->sin_addr = loopback_addr;
|
||||
}
|
||||
} else {
|
||||
sin->sin_addr = loopback_addr;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MISC((dfd, " addr.sin_port=%d, "
|
||||
"addr.sin_addr.s_addr=%.16s\n",
|
||||
ntohs(sin->sin_port), inet_ntoa(sin->sin_addr)));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
|
||||
{
|
||||
Slirp *slirp = so->slirp;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
|
||||
|
||||
switch (addr->ss_family) {
|
||||
case AF_INET:
|
||||
if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
|
||||
slirp->vnetwork_addr.s_addr) {
|
||||
uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
|
||||
|
||||
if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
|
||||
sin->sin_addr = slirp->vhost_addr;
|
||||
} else if (sin->sin_addr.s_addr == loopback_addr.s_addr ||
|
||||
so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
|
||||
sin->sin_addr = so->so_faddr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate connections from localhost to the real hostname
|
||||
*/
|
||||
void sotranslate_accept(struct socket *so)
|
||||
{
|
||||
Slirp *slirp = so->slirp;
|
||||
|
||||
switch (so->so_ffamily) {
|
||||
case AF_INET:
|
||||
if (so->so_faddr.s_addr == INADDR_ANY ||
|
||||
(so->so_faddr.s_addr & loopback_mask) ==
|
||||
(loopback_addr.s_addr & loopback_mask)) {
|
||||
so->so_faddr = slirp->vhost_addr;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,10 +31,21 @@ struct socket {
|
|||
struct tcpiphdr *so_ti; /* Pointer to the original ti within
|
||||
* so_mconn, for non-blocking connections */
|
||||
int so_urgc;
|
||||
struct in_addr so_faddr; /* foreign host table entry */
|
||||
struct in_addr so_laddr; /* local host table entry */
|
||||
uint16_t so_fport; /* foreign port */
|
||||
uint16_t so_lport; /* local port */
|
||||
union { /* foreign host */
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr_in sin;
|
||||
} fhost;
|
||||
#define so_faddr fhost.sin.sin_addr
|
||||
#define so_fport fhost.sin.sin_port
|
||||
#define so_ffamily fhost.ss.ss_family
|
||||
|
||||
union { /* local host */
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr_in sin;
|
||||
} lhost;
|
||||
#define so_laddr lhost.sin.sin_addr
|
||||
#define so_lport lhost.sin.sin_port
|
||||
#define so_lfamily lhost.ss.ss_family
|
||||
|
||||
uint8_t so_iptos; /* Type of service */
|
||||
uint8_t so_emu; /* Is the socket emulated? */
|
||||
|
@ -76,8 +87,31 @@ struct socket {
|
|||
#define SS_HOSTFWD 0x1000 /* Socket describes host->guest forwarding */
|
||||
#define SS_INCOMING 0x2000 /* Connection was initiated by a host on the internet */
|
||||
|
||||
struct socket * solookup(struct socket *, struct in_addr, u_int, struct in_addr, u_int);
|
||||
struct socket * socreate(Slirp *);
|
||||
static inline int sockaddr_equal(struct sockaddr_storage *a,
|
||||
struct sockaddr_storage *b)
|
||||
{
|
||||
if (a->ss_family != b->ss_family) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (a->ss_family) {
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in *a4 = (struct sockaddr_in *) a;
|
||||
struct sockaddr_in *b4 = (struct sockaddr_in *) b;
|
||||
return a4->sin_addr.s_addr == b4->sin_addr.s_addr
|
||||
&& a4->sin_port == b4->sin_port;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct socket *solookup(struct socket **, struct socket *,
|
||||
struct sockaddr_storage *, struct sockaddr_storage *);
|
||||
struct socket *socreate(Slirp *);
|
||||
void sofree(struct socket *);
|
||||
int soread(struct socket *);
|
||||
void sorecvoob(struct socket *);
|
||||
|
@ -94,4 +128,9 @@ struct iovec; /* For win32 */
|
|||
size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
|
||||
int soreadbuf(struct socket *so, const char *buf, int size);
|
||||
|
||||
void sotranslate_out(struct socket *, struct sockaddr_storage *);
|
||||
void sotranslate_in(struct socket *, struct sockaddr_storage *);
|
||||
void sotranslate_accept(struct socket *);
|
||||
|
||||
|
||||
#endif /* _SOCKET_H_ */
|
||||
|
|
|
@ -227,6 +227,8 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
|
|||
int iss = 0;
|
||||
u_long tiwin;
|
||||
int ret;
|
||||
struct sockaddr_storage lhost, fhost;
|
||||
struct sockaddr_in *lhost4, *fhost4;
|
||||
struct ex_list *ex_ptr;
|
||||
Slirp *slirp;
|
||||
|
||||
|
@ -320,16 +322,16 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
|
|||
* Locate pcb for segment.
|
||||
*/
|
||||
findso:
|
||||
so = slirp->tcp_last_so;
|
||||
if (so->so_fport != ti->ti_dport ||
|
||||
so->so_lport != ti->ti_sport ||
|
||||
so->so_laddr.s_addr != ti->ti_src.s_addr ||
|
||||
so->so_faddr.s_addr != ti->ti_dst.s_addr) {
|
||||
so = solookup(&slirp->tcb, ti->ti_src, ti->ti_sport,
|
||||
ti->ti_dst, ti->ti_dport);
|
||||
if (so)
|
||||
slirp->tcp_last_so = so;
|
||||
}
|
||||
lhost.ss_family = AF_INET;
|
||||
lhost4 = (struct sockaddr_in *) &lhost;
|
||||
lhost4->sin_addr = ti->ti_src;
|
||||
lhost4->sin_port = ti->ti_sport;
|
||||
fhost.ss_family = AF_INET;
|
||||
fhost4 = (struct sockaddr_in *) &fhost;
|
||||
fhost4->sin_addr = ti->ti_dst;
|
||||
fhost4->sin_port = ti->ti_dport;
|
||||
|
||||
so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost);
|
||||
|
||||
/*
|
||||
* If the state is CLOSED (i.e., TCB does not exist) then
|
||||
|
@ -374,10 +376,8 @@ findso:
|
|||
sbreserve(&so->so_snd, TCP_SNDSPACE);
|
||||
sbreserve(&so->so_rcv, TCP_RCVSPACE);
|
||||
|
||||
so->so_laddr = ti->ti_src;
|
||||
so->so_lport = ti->ti_sport;
|
||||
so->so_faddr = ti->ti_dst;
|
||||
so->so_fport = ti->ti_dport;
|
||||
so->lhost.ss = lhost;
|
||||
so->fhost.ss = fhost;
|
||||
|
||||
if ((so->so_iptos = tcp_tos(so)) == 0)
|
||||
so->so_iptos = ((struct ip *)ti)->ip_tos;
|
||||
|
@ -584,7 +584,7 @@ findso:
|
|||
goto cont_input;
|
||||
}
|
||||
|
||||
if ((tcp_fconnect(so) == -1) &&
|
||||
if ((tcp_fconnect(so, so->so_ffamily) == -1) &&
|
||||
#if defined(_WIN32)
|
||||
socket_error() != WSAEWOULDBLOCK
|
||||
#else
|
||||
|
|
|
@ -324,40 +324,27 @@ tcp_sockclosed(struct tcpcb *tp)
|
|||
* nonblocking. Connect returns after the SYN is sent, and does
|
||||
* not wait for ACK+SYN.
|
||||
*/
|
||||
int tcp_fconnect(struct socket *so)
|
||||
int tcp_fconnect(struct socket *so, unsigned short af)
|
||||
{
|
||||
Slirp *slirp = so->slirp;
|
||||
int ret=0;
|
||||
|
||||
DEBUG_CALL("tcp_fconnect");
|
||||
DEBUG_ARG("so = %p", so);
|
||||
|
||||
if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) {
|
||||
ret = so->s = qemu_socket(af, SOCK_STREAM, 0);
|
||||
if (ret >= 0) {
|
||||
int opt, s=so->s;
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
qemu_set_nonblock(s);
|
||||
socket_set_fast_reuse(s);
|
||||
opt = 1;
|
||||
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
|
||||
slirp->vnetwork_addr.s_addr) {
|
||||
/* It's an alias */
|
||||
if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
|
||||
if (get_dns_addr(&addr.sin_addr) < 0)
|
||||
addr.sin_addr = loopback_addr;
|
||||
} else {
|
||||
addr.sin_addr = loopback_addr;
|
||||
}
|
||||
} else
|
||||
addr.sin_addr = so->so_faddr;
|
||||
addr.sin_port = so->so_fport;
|
||||
addr = so->fhost.ss;
|
||||
DEBUG_CALL(" connect()ing")
|
||||
sotranslate_out(so, &addr);
|
||||
|
||||
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));
|
||||
|
||||
|
@ -413,6 +400,7 @@ void tcp_connect(struct socket *inso)
|
|||
free(so); /* NOT sofree */
|
||||
return;
|
||||
}
|
||||
so->so_lfamily = AF_INET;
|
||||
so->so_laddr = inso->so_laddr;
|
||||
so->so_lport = inso->so_lport;
|
||||
}
|
||||
|
@ -430,14 +418,8 @@ void tcp_connect(struct socket *inso)
|
|||
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
|
||||
socket_set_nodelay(s);
|
||||
|
||||
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_mask) ==
|
||||
(loopback_addr.s_addr & loopback_mask)) {
|
||||
so->so_faddr = slirp->vhost_addr;
|
||||
}
|
||||
so->fhost.sin = addr;
|
||||
sotranslate_accept(so);
|
||||
|
||||
/* Close the accept() socket, set right state */
|
||||
if (inso->so_state & SS_FACCEPTONCE) {
|
||||
|
|
|
@ -155,7 +155,7 @@ static int tftp_send_oack(struct tftp_session *spt,
|
|||
|
||||
m->m_len = sizeof(struct tftp_t) - 514 + n -
|
||||
sizeof(struct ip) - sizeof(struct udphdr);
|
||||
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
|
||||
udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ static void tftp_send_error(struct tftp_session *spt,
|
|||
m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
|
||||
sizeof(struct ip) - sizeof(struct udphdr);
|
||||
|
||||
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
|
||||
udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
|
||||
|
||||
out:
|
||||
tftp_session_terminate(spt);
|
||||
|
@ -243,7 +243,7 @@ static void tftp_send_next_block(struct tftp_session *spt,
|
|||
m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
|
||||
sizeof(struct ip) - sizeof(struct udphdr);
|
||||
|
||||
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
|
||||
udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
|
||||
|
||||
if (nobytes == 512) {
|
||||
tftp_session_update(spt);
|
||||
|
|
72
slirp/udp.c
72
slirp/udp.c
|
@ -70,6 +70,8 @@ udp_input(register struct mbuf *m, int iphlen)
|
|||
int len;
|
||||
struct ip save_ip;
|
||||
struct socket *so;
|
||||
struct sockaddr_storage lhost;
|
||||
struct sockaddr_in *lhost4;
|
||||
|
||||
DEBUG_CALL("udp_input");
|
||||
DEBUG_ARG("m = %p", m);
|
||||
|
@ -151,25 +153,12 @@ udp_input(register struct mbuf *m, int iphlen)
|
|||
/*
|
||||
* Locate pcb for datagram.
|
||||
*/
|
||||
so = slirp->udp_last_so;
|
||||
if (so == &slirp->udb || so->so_lport != uh->uh_sport ||
|
||||
so->so_laddr.s_addr != ip->ip_src.s_addr) {
|
||||
struct socket *tmp;
|
||||
lhost.ss_family = AF_INET;
|
||||
lhost4 = (struct sockaddr_in *) &lhost;
|
||||
lhost4->sin_addr = ip->ip_src;
|
||||
lhost4->sin_port = uh->uh_sport;
|
||||
|
||||
for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
|
||||
tmp = tmp->so_next) {
|
||||
if (tmp->so_lport == uh->uh_sport &&
|
||||
tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
|
||||
so = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tmp == &slirp->udb) {
|
||||
so = NULL;
|
||||
} else {
|
||||
slirp->udp_last_so = so;
|
||||
}
|
||||
}
|
||||
so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
|
||||
|
||||
if (so == NULL) {
|
||||
/*
|
||||
|
@ -180,7 +169,7 @@ udp_input(register struct mbuf *m, int iphlen)
|
|||
if (!so) {
|
||||
goto bad;
|
||||
}
|
||||
if(udp_attach(so) == -1) {
|
||||
if (udp_attach(so, AF_INET) == -1) {
|
||||
DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
|
||||
errno,strerror(errno)));
|
||||
sofree(so);
|
||||
|
@ -190,6 +179,7 @@ udp_input(register struct mbuf *m, int iphlen)
|
|||
/*
|
||||
* Setup fields
|
||||
*/
|
||||
so->so_lfamily = AF_INET;
|
||||
so->so_laddr = ip->ip_src;
|
||||
so->so_lport = uh->uh_sport;
|
||||
|
||||
|
@ -202,6 +192,7 @@ udp_input(register struct mbuf *m, int iphlen)
|
|||
*/
|
||||
}
|
||||
|
||||
so->so_ffamily = AF_INET;
|
||||
so->so_faddr = ip->ip_dst; /* XXX */
|
||||
so->so_fport = uh->uh_dport; /* XXX */
|
||||
|
||||
|
@ -218,6 +209,7 @@ udp_input(register struct mbuf *m, int iphlen)
|
|||
*ip=save_ip;
|
||||
DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
|
||||
icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
|
||||
|
@ -233,7 +225,7 @@ bad:
|
|||
m_free(m);
|
||||
}
|
||||
|
||||
int udp_output2(struct socket *so, struct mbuf *m,
|
||||
int udp_output(struct socket *so, struct mbuf *m,
|
||||
struct sockaddr_in *saddr, struct sockaddr_in *daddr,
|
||||
int iptos)
|
||||
{
|
||||
|
@ -284,35 +276,11 @@ int udp_output2(struct socket *so, struct mbuf *m,
|
|||
return (error);
|
||||
}
|
||||
|
||||
int udp_output(struct socket *so, struct mbuf *m,
|
||||
struct sockaddr_in *addr)
|
||||
|
||||
{
|
||||
Slirp *slirp = so->slirp;
|
||||
struct sockaddr_in saddr, daddr;
|
||||
|
||||
saddr = *addr;
|
||||
if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
|
||||
slirp->vnetwork_addr.s_addr) {
|
||||
uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
|
||||
|
||||
if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
|
||||
saddr.sin_addr = slirp->vhost_addr;
|
||||
} else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
|
||||
so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
|
||||
saddr.sin_addr = so->so_faddr;
|
||||
}
|
||||
}
|
||||
daddr.sin_addr = so->so_laddr;
|
||||
daddr.sin_port = so->so_lport;
|
||||
|
||||
return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
|
||||
}
|
||||
|
||||
int
|
||||
udp_attach(struct socket *so)
|
||||
udp_attach(struct socket *so, unsigned short af)
|
||||
{
|
||||
if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) {
|
||||
so->s = qemu_socket(af, SOCK_DGRAM, 0);
|
||||
if (so->s != -1) {
|
||||
so->so_expire = curtime + SO_EXPIRE;
|
||||
insque(so, &so->slirp->udb);
|
||||
}
|
||||
|
@ -375,13 +343,9 @@ udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
|
|||
socket_set_fast_reuse(so->s);
|
||||
|
||||
getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
|
||||
so->so_fport = addr.sin_port;
|
||||
if (addr.sin_addr.s_addr == 0 ||
|
||||
addr.sin_addr.s_addr == loopback_addr.s_addr) {
|
||||
so->so_faddr = slirp->vhost_addr;
|
||||
} else {
|
||||
so->so_faddr = addr.sin_addr;
|
||||
}
|
||||
so->fhost.sin = addr;
|
||||
sotranslate_accept(so);
|
||||
so->so_lfamily = AF_INET;
|
||||
so->so_lport = lport;
|
||||
so->so_laddr.s_addr = laddr;
|
||||
if (flags != SS_FACCEPTONCE)
|
||||
|
|
|
@ -76,12 +76,11 @@ struct mbuf;
|
|||
void udp_init(Slirp *);
|
||||
void udp_cleanup(Slirp *);
|
||||
void udp_input(register struct mbuf *, int);
|
||||
int udp_output(struct socket *, struct mbuf *, struct sockaddr_in *);
|
||||
int udp_attach(struct socket *);
|
||||
int udp_attach(struct socket *, unsigned short af);
|
||||
void udp_detach(struct socket *);
|
||||
struct socket * udp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
|
||||
int);
|
||||
int udp_output2(struct socket *so, struct mbuf *m,
|
||||
int udp_output(struct socket *so, struct mbuf *m,
|
||||
struct sockaddr_in *saddr, struct sockaddr_in *daddr,
|
||||
int iptos);
|
||||
#endif
|
||||
|
|
6
vl.c
6
vl.c
|
@ -3311,12 +3311,18 @@ int main(int argc, char **argv, char **envp)
|
|||
#endif
|
||||
#ifdef CONFIG_SLIRP
|
||||
case QEMU_OPTION_tftp:
|
||||
error_report("The -tftp option is deprecated. "
|
||||
"Please use '-netdev user,tftp=...' instead.");
|
||||
legacy_tftp_prefix = optarg;
|
||||
break;
|
||||
case QEMU_OPTION_bootp:
|
||||
error_report("The -bootp option is deprecated. "
|
||||
"Please use '-netdev user,bootfile=...' instead.");
|
||||
legacy_bootp_filename = optarg;
|
||||
break;
|
||||
case QEMU_OPTION_redir:
|
||||
error_report("The -redir option is deprecated. "
|
||||
"Please use '-netdev user,hostfwd=...' instead.");
|
||||
if (net_slirp_redir(optarg) < 0)
|
||||
exit(1);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue