From 99759e033ea960b86828657682f8382538c4ccb7 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht 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 --- 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 +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