--- Makefile.target.orig Thu Jul 17 18:35:15 2008 +++ Makefile.target Thu Jul 17 18:36:24 2008 @@ -622,6 +622,13 @@ ifdef CONFIG_SLIRP CPPFLAGS+=-I$(SRC_PATH)/slirp endif +ifdef CONFIG_PCAP +ifdef CONFIG_WIN32 +LIBS+=-lwpcap +else +LIBS+=-lpcap +endif +endif LIBS+=$(AIOLIBS) # specific flags are needed for non soft mmu emulator --- configure.orig Thu Jul 17 18:35:47 2008 +++ configure Thu Jul 17 18:36:24 2008 @@ -89,6 +89,7 @@ EXESUF="" gdbstub="yes" slirp="yes" +pcap="no" fmod_lib="" fmod_inc="" vnc_tls="yes" @@ -280,6 +281,8 @@ ;; --disable-slirp) slirp="no" ;; + --enable-pcap) pcap="yes" + ;; --disable-kqemu) kqemu="no" ;; --disable-brlapi) brlapi="no" @@ -712,6 +715,24 @@ fi # -z $sdl ########################################## +# pcap probe + +if test "$pcap" = "yes" ; then + cat > $TMPC << EOF +#include +int main(void) { return (pcap_lib_version() == (char *)0 ? 1 : 0); } +EOF + if test "$mingw32" = "no" ; then + libpcap=-lpcap + else + libpcap=-lwpcap + fi + if ! $cc $ARCH_CFLAGS -o $TMPE $TMPC $libpcap 2> /dev/null ; then + pcap=no + fi +fi # test "$pcap" + +########################################## # VNC TLS detection if test "$vnc_tls" = "yes" ; then `pkg-config gnutls` || vnc_tls="no" @@ -865,6 +886,7 @@ echo " TLS CFLAGS $vnc_tls_cflags" echo " TLS LIBS $vnc_tls_libs" fi +echo "pcap support $pcap" if test -n "$sparc_cpu"; then echo "Target Sparc Arch $sparc_cpu" fi @@ -1037,6 +1059,15 @@ if test "$slirp" = "yes" ; then echo "CONFIG_SLIRP=yes" >> $config_mak echo "#define CONFIG_SLIRP 1" >> $config_h +fi +if test "$pcap" = "yes" ; then + echo "CONFIG_PCAP=yes" >> $config_mak + echo "#define CONFIG_PCAP 1" >> $config_h + if test "$mingw32" = "no" ; then + if test -c /dev/bpf0 ; then + echo "#define HAVE_BPF 1" >> $config_h + fi + fi fi for card in $audio_card_list; do def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'` --- vl.c.orig Thu Jul 17 18:34:45 2008 +++ vl.c Thu Jul 17 18:37:01 2008 @@ -102,6 +102,10 @@ int inet_aton(const char *cp, struct in_addr *ia); #endif +#if defined(CONFIG_PCAP) +#include +#endif + #if defined(CONFIG_SLIRP) #include "libslirp.h" #endif @@ -4107,6 +4111,170 @@ #endif /* CONFIG_SLIRP */ +#if defined(CONFIG_PCAP) + +typedef struct PCAPState { + VLANClientState *vc; + pcap_t *handle; +} PCAPState; + +static void pcap_receive(void *opaque, const uint8_t *buf, int size) +{ + PCAPState *s = (PCAPState *)opaque; + + pcap_sendpacket(s->handle, (u_char*)buf, 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, char *ifname) +{ + PCAPState *s = NULL; +#ifdef PCAP_SET_FILTER + struct bpf_program fcode = { 0, NULL }; + char pcap_program[128]; +#endif + char macstr[] = "xx:xx:xx:xx:xx:xx"; + char errbuf[PCAP_ERRBUF_SIZE]; +#ifdef _WIN32 + HANDLE h; +#endif + int i; + + /* Find guest's MAC address. */ + for (i = 0; i < nb_nics; i++) + if (nd_table[i].vlan == vlan) { + u_char *mac = nd_table[i].macaddr; + snprintf(macstr, sizeof(macstr), "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + break; + } + if (macstr[0] == 'x') { + fprintf(stderr, "qemu: net_pcap_init: no matching NIC found\n"); + return -1; + } + + 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; + } + +#ifdef PCAP_SET_FILTER + /* Set filter program. */ + snprintf(pcap_program, 128, "ether dst %s or " + "((broadcast or multicast) and not ether src %s)", + macstr, macstr); + if (pcap_compile(s->handle, &fcode, pcap_program, 1, 0) < 0) { + fprintf(stderr, "qemu: pcap_compile failed\n"); + goto fail; + } + if (pcap_setfilter(s->handle, &fcode) < 0) { + fprintf(stderr, "qemu: pcap_setfilter failed\n"); + goto fail; + } +#endif + + /* Set non-blocking mode. */ + if (pcap_setnonblock(s->handle, 1, errbuf) < 0) { + fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf); + goto fail; + } + +#if defined(_WIN32) + /* + * Tell the kernel that the packet has to be seen immediately. + */ + if (pcap_setmintocopy(s->handle, 0) < 0) { + fprintf(stderr, "qemu: pcap failed to set immediate mode\n"); + goto fail; + } +#elif defined(HAVE_BPF) +#if defined(BIOCIMMEDIATE) + /* + * Tell the kernel that the packet has to be seen immediately. + */ + { + unsigned int one = 1; + if (ioctl(pcap_fileno(s->handle), BIOCIMMEDIATE, &one) < 0) { + fprintf(stderr, "qemu: pcap failed to set immediate mode\n"); + goto fail; + } + } +#endif /* BIOCIMMEDIATE */ + +#if defined(BIOCFEEDBACK) + /* + * Tell the kernel that the sent packet has to be fed back. + * This is necessary to connect host and guest. + */ + { + unsigned int one = 1; + if (ioctl(pcap_fileno(s->handle), BIOCFEEDBACK, &one) < 0) { + fprintf(stderr, "qemu: pcap failed to set feedback mode\n"); + goto fail; + } + } +#endif /* BIOCFEEDBACK */ +#endif + + s->vc = qemu_new_vlan_client(vlan, pcap_receive, NULL, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "pcap redirector"); + +#ifdef _WIN32 + if ((h = pcap_getevent(s->handle)) == NULL) { + fprintf(stderr, "qemu: pcap_getevent failed\n"); + goto fail; + } + qemu_add_wait_object(h, pcap_send, s); +#else + if ((i = pcap_get_selectable_fd(s->handle)) < 0) { + fprintf(stderr, "qemu: pcap_get_selectable_fd failed\n"); + goto fail; + } + qemu_set_fd_handler(i, pcap_send, NULL, s); +#endif + + return 0; + +fail: + if (s) { + if (s->handle) { +#ifdef PCAP_SET_FILTER + if (fcode.bf_len) + pcap_freecode(&fcode); +#endif + pcap_close(s->handle); + } + qemu_free(s); + } + + return -1; +} +#endif /* CONFIG_PCAP */ + #if !defined(_WIN32) typedef struct TAPState { @@ -4991,6 +5159,16 @@ ret = net_slirp_init(vlan); } else #endif +#ifdef CONFIG_PCAP + if (!strcmp(device, "pcap")) { + char ifname[64]; + vlan->nb_host_devs++; + if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) + ret = net_pcap_init(vlan, NULL); + else + ret = net_pcap_init(vlan, ifname); + } else +#endif #ifdef _WIN32 if (!strcmp(device, "tap")) { char ifname[64]; @@ -7399,6 +7577,10 @@ "-net user[,vlan=n][,hostname=host]\n" " connect the user mode network stack to VLAN 'n' and send\n" " hostname 'host' to DHCP clients\n" +#endif +#ifdef CONFIG_PCAP + "-net pcap[,vlan=n][,ifname=name]\n" + " connect the host network interface using PCAP to VLAN 'n'\n" #endif #ifdef _WIN32 "-net tap[,vlan=n],ifname=name\n"