206 lines
5.5 KiB
Diff
206 lines
5.5 KiB
Diff
|
From 99759e033ea960b86828657682f8382538c4ccb7 Mon Sep 17 00:00:00 2001
|
||
|
From: Ulrich Hecht <uli@suse.de>
|
||
|
Date: Tue, 14 Apr 2009 16:52:51 +0200
|
||
|
Subject: [PATCH 15/33] pcap network emulation
|
||
|
|
||
|
Implements network emulation using libpcap; useful for direct Ethernet access.
|
||
|
|
||
|
Signed-off-by: Ulrich Hecht <uli@suse.de>
|
||
|
---
|
||
|
Makefile.target | 3 ++
|
||
|
configure | 7 ++++
|
||
|
net.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
qemu-options.hx | 4 ++
|
||
|
4 files changed, 122 insertions(+), 0 deletions(-)
|
||
|
|
||
|
diff --git a/Makefile.target b/Makefile.target
|
||
|
index f9cd42a..9c9304c 100644
|
||
|
--- a/Makefile.target
|
||
|
+++ b/Makefile.target
|
||
|
@@ -618,6 +618,9 @@ endif
|
||
|
ifdef CONFIG_SLIRP
|
||
|
CPPFLAGS+=-I$(SRC_PATH)/slirp
|
||
|
endif
|
||
|
+ifdef CONFIG_PCAP
|
||
|
+LIBS+=-lpcap
|
||
|
+endif
|
||
|
|
||
|
# specific flags are needed for non soft mmu emulator
|
||
|
ifdef CONFIG_STATIC
|
||
|
diff --git a/configure b/configure
|
||
|
index cac4198..4ce7bc1 100755
|
||
|
--- a/configure
|
||
|
+++ b/configure
|
||
|
@@ -169,6 +169,7 @@ mingw32="no"
|
||
|
EXESUF=""
|
||
|
slirp="yes"
|
||
|
vde="yes"
|
||
|
+pcap="yes"
|
||
|
fmod_lib=""
|
||
|
fmod_inc=""
|
||
|
oss_lib=""
|
||
|
@@ -432,6 +433,8 @@ for opt do
|
||
|
;;
|
||
|
--disable-vde) vde="no"
|
||
|
;;
|
||
|
+ --disable-pcap) pcap="no"
|
||
|
+ ;;
|
||
|
--disable-kqemu) kqemu="no"
|
||
|
;;
|
||
|
--disable-xen) xen="no"
|
||
|
@@ -1598,6 +1601,10 @@ if test "$vde" = "yes" ; then
|
||
|
echo "#define CONFIG_VDE 1" >> $config_host_h
|
||
|
echo "VDE_LIBS=-lvdeplug" >> $config_host_mak
|
||
|
fi
|
||
|
+if test "$pcap" = "yes" ; then
|
||
|
+ echo "CONFIG_PCAP=yes" >> $config_host_mak
|
||
|
+ echo "#define CONFIG_PCAP 1" >> $config_host_h
|
||
|
+fi
|
||
|
for card in $audio_card_list; do
|
||
|
def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'`
|
||
|
echo "$def=y" >> $config_host_mak
|
||
|
diff --git a/net.c b/net.c
|
||
|
index 3d3829d..595f7bc 100644
|
||
|
--- a/net.c
|
||
|
+++ b/net.c
|
||
|
@@ -1264,6 +1264,105 @@ void do_info_usernet(Monitor *mon)
|
||
|
|
||
|
#endif /* CONFIG_SLIRP */
|
||
|
|
||
|
+#if defined(CONFIG_PCAP)
|
||
|
+#include <pcap.h>
|
||
|
+typedef struct PCAPState {
|
||
|
+ VLANClientState *vc;
|
||
|
+ pcap_t *handle;
|
||
|
+} PCAPState;
|
||
|
+
|
||
|
+static ssize_t pcap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
|
||
|
+{
|
||
|
+ PCAPState *s = (PCAPState *)(vc->opaque);
|
||
|
+
|
||
|
+ pcap_sendpacket(s->handle, (u_char*)buf, size);
|
||
|
+ return size;
|
||
|
+}
|
||
|
+
|
||
|
+static void pcap_callback(u_char *user, struct pcap_pkthdr *phdr, u_char *pdata)
|
||
|
+{
|
||
|
+ VLANClientState *vc = (VLANClientState *)user;
|
||
|
+
|
||
|
+ qemu_send_packet(vc, pdata, phdr->len);
|
||
|
+}
|
||
|
+
|
||
|
+static void pcap_send(void *opaque)
|
||
|
+{
|
||
|
+ PCAPState *s = (PCAPState *)opaque;
|
||
|
+
|
||
|
+ pcap_dispatch(s->handle, 1, (pcap_handler)&pcap_callback, (u_char *)s->vc);
|
||
|
+}
|
||
|
+
|
||
|
+static int net_pcap_init(VLANState *vlan, const char *model, const char *name, char *ifname)
|
||
|
+{
|
||
|
+ PCAPState *s;
|
||
|
+ char errbuf[PCAP_ERRBUF_SIZE];
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ s = qemu_mallocz(sizeof(PCAPState));
|
||
|
+ if (!s)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ if (ifname == NULL && (ifname = pcap_lookupdev(errbuf)) == NULL) {
|
||
|
+ fprintf(stderr, "qemu: pcap_lookupdev: %s\n", errbuf);
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Attempt to connect device. */
|
||
|
+ s->handle = (void*)pcap_open_live(ifname, 65535, 1, 0, errbuf);
|
||
|
+ if (!s->handle) {
|
||
|
+ fprintf(stderr, "qemu: pcap_open_live: %s\n", errbuf);
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Check non-blocking mode. */
|
||
|
+ if (pcap_setnonblock(s->handle, 1, errbuf) < 0) {
|
||
|
+ fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf);
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+#if defined(BIOCSHDRCMPLT)
|
||
|
+ /*
|
||
|
+ * Tell the kernel that the header is fully-formed when it gets it.
|
||
|
+ * This is required in order to fake the src address.
|
||
|
+ */
|
||
|
+ {
|
||
|
+ unsigned int one = 1;
|
||
|
+ ioctl(pcap_fileno(s->handle), BIOCSHDRCMPLT, &one);
|
||
|
+ }
|
||
|
+#endif /* BIOCSHDRCMPLT */
|
||
|
+
|
||
|
+#if defined(BIOCIMMEDIATE)
|
||
|
+ /*
|
||
|
+ * Tell the kernel that the packet has to be processed immediately.
|
||
|
+ */
|
||
|
+ {
|
||
|
+ unsigned int one = 1;
|
||
|
+ ioctl(pcap_fileno(s->handle), BIOCIMMEDIATE, &one);
|
||
|
+ }
|
||
|
+#endif /* BIOCIMMEDIATE */
|
||
|
+
|
||
|
+ s->vc = qemu_new_vlan_client(vlan, model, name, NULL, pcap_receive, NULL, NULL, s);
|
||
|
+ snprintf(s->vc->info_str, sizeof(s->vc->info_str), "pcap redirector");
|
||
|
+ if ((fd = pcap_get_selectable_fd(s->handle)) < 0) {
|
||
|
+ fprintf(stderr, "qemu: pcap_get_selectable_fd failed\n");
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+ qemu_set_fd_handler(fd, pcap_send, NULL, s);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+
|
||
|
+fail:
|
||
|
+ if (s) {
|
||
|
+ if (s->handle)
|
||
|
+ pcap_close(s->handle);
|
||
|
+ qemu_free(s);
|
||
|
+ }
|
||
|
+
|
||
|
+ return -1;
|
||
|
+}
|
||
|
+#endif /* CONFIG_PCAP */
|
||
|
+
|
||
|
#if !defined(_WIN32)
|
||
|
|
||
|
typedef struct TAPState {
|
||
|
@@ -2631,6 +2730,15 @@ int net_client_init(Monitor *mon, const char *device, const char *p)
|
||
|
ret = 0;
|
||
|
} else
|
||
|
#endif
|
||
|
+#ifdef CONFIG_PCAP
|
||
|
+ if (!strcmp(device, "pcap")) {
|
||
|
+ char ifname[64];
|
||
|
+ if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0)
|
||
|
+ ret = net_pcap_init(vlan, device, name, NULL);
|
||
|
+ else
|
||
|
+ ret = net_pcap_init(vlan, device, name, ifname);
|
||
|
+ } else
|
||
|
+#endif
|
||
|
#ifdef _WIN32
|
||
|
if (!strcmp(device, "tap")) {
|
||
|
static const char * const tap_params[] = {
|
||
|
diff --git a/qemu-options.hx b/qemu-options.hx
|
||
|
index a58287c..4d46d6c 100644
|
||
|
--- a/qemu-options.hx
|
||
|
+++ b/qemu-options.hx
|
||
|
@@ -801,6 +801,10 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
|
||
|
" default of 'sndbuf=1048576' can be disabled using 'sndbuf=0'\n"
|
||
|
#endif
|
||
|
#endif
|
||
|
+#ifdef CONFIG_PCAP
|
||
|
+ "-net pcap[,vlan=n][,ifname=name]\n"
|
||
|
+ " connect the host network interface using PCAP to VLAN 'n'\n"
|
||
|
+#endif
|
||
|
"-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
|
||
|
" connect the vlan 'n' to another VLAN using a socket connection\n"
|
||
|
"-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port]\n"
|
||
|
--
|
||
|
1.6.2.1
|
||
|
|