-----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>
stable-2.6
Peter Maydell 2016-02-04 14:17:11 +00:00
commit bac8e20367
24 changed files with 443 additions and 294 deletions

View File

@ -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.
*/

View File

@ -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);

View File

@ -55,7 +55,6 @@ struct NetFilterState {
char *netdev_id;
NetClientState *netdev;
NetFilterDirection direction;
char info_str[256];
QTAILQ_ENTRY(NetFilterState) next;
};

View File

@ -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 {

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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,");

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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",

View File

@ -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);

View File

@ -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 {

View File

@ -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);

View File

@ -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 *);

View File

@ -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;
}
}

View File

@ -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_ */

View File

@ -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

View File

@ -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) {

View File

@ -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);

View File

@ -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)

View File

@ -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
View File

@ -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;