-- v7: wpcap/tests: Initial tests. wpcap: Try to enable 32-bit mmap() support in libpcap. wpcap: Add wow64 thunks. wpcap: Enable UTF-8 encoding in libpcap. wpcap: Reimplement pcap_loop() on top of pcap_next_ex(). wpcap: Implement pcap_init(). wpcap: Implement pcap_dump_close(). wpcap: Implement pcap_bufsize(). wpcap: Fix an off-by-one error in convert_length_to_ipv6_mask(). wpcap: Make Unix call parameters wow64 compatible. wpcap: Sync spec file with latest version of libpcap. configure: Check for pcap_init() instead of pcap_create().
From: Hans Leidekker hans@codeweavers.com
pcap_init() will be required by later patches and it was introduced after pcap_create(). --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac index 6410f8a0e42..3d996c34fae 100644 --- a/configure.ac +++ b/configure.ac @@ -1371,9 +1371,9 @@ WINE_NOTICE_WITH(opencl,[test "x$ac_cv_lib_OpenCL_clGetPlatformInfo" != xyes], dnl **** Check for libpcap **** if test "$ac_cv_header_pcap_pcap_h" = "yes" then - AC_CHECK_LIB(pcap,pcap_create,[AC_SUBST(PCAP_LIBS,["-lpcap"])]) + AC_CHECK_LIB(pcap,pcap_init,[AC_SUBST(PCAP_LIBS,["-lpcap"])]) fi -WINE_NOTICE_WITH(pcap,[test "x$ac_cv_lib_pcap_pcap_create" != xyes], +WINE_NOTICE_WITH(pcap,[test "x$ac_cv_lib_pcap_pcap_init" != xyes], [pcap ${notice_platform}development files not found, wpcap won't be supported.], [enable_wpcap])
From: Hans Leidekker hans@codeweavers.com
--- dlls/wpcap/wpcap.c | 2 +- dlls/wpcap/wpcap.spec | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/dlls/wpcap/wpcap.c b/dlls/wpcap/wpcap.c index 4d8a115b0ea..0964715f92c 100644 --- a/dlls/wpcap/wpcap.c +++ b/dlls/wpcap/wpcap.c @@ -865,7 +865,7 @@ const char * CDECL pcap_tstamp_type_val_to_name( int val ) return ret; }
-int CDECL wsockinit( void ) +int CDECL pcap_wsockinit( void ) { WSADATA wsadata; TRACE( "\n" ); diff --git a/dlls/wpcap/wpcap.spec b/dlls/wpcap/wpcap.spec index 8cbb44148e8..5c26ad0c24e 100644 --- a/dlls/wpcap/wpcap.spec +++ b/dlls/wpcap/wpcap.spec @@ -2,11 +2,9 @@ @ stub bpf_filter @ stub bpf_image @ stub bpf_validate -@ stub endservent @ stub eproto_db -@ stub getservent -@ stub install_bpf_program @ cdecl pcap_activate(ptr) +@ stub pcap_bufsize @ cdecl pcap_breakloop(ptr) @ cdecl pcap_can_set_rfmon(ptr) @ cdecl pcap_close(ptr) @@ -14,9 +12,11 @@ @ stub pcap_compile_nopcap @ cdecl pcap_create(str ptr) @ stub pcap_createsrcstr +@ stub pcap_datalink_ext @ cdecl pcap_datalink(ptr) @ cdecl pcap_datalink_name_to_val(str) @ cdecl pcap_datalink_val_to_description(long) +@ stub pcap_datalink_val_to_description_or_dlt @ cdecl pcap_datalink_val_to_name(long) @ cdecl pcap_dispatch(ptr long ptr ptr) @ cdecl pcap_dump(ptr ptr str) @@ -24,7 +24,12 @@ @ stub pcap_dump_file @ stub pcap_dump_flush @ stub pcap_dump_ftell +@ stub pcap_dump_ftell64 +@ stub pcap_dump_hopen @ cdecl pcap_dump_open(ptr str) +@ stub pcap_dump_open_append +@ stub pcap_ether_aton +@ stub pcap_ether_hostton @ stub pcap_file @ stub pcap_fileno @ cdecl pcap_findalldevs(ptr ptr) @@ -38,6 +43,10 @@ @ cdecl pcap_geterr(ptr) @ stub pcap_getevent @ cdecl pcap_getnonblock(ptr ptr) +@ stub pcap_hopen_offline +@ stub pcap_hopen_offline_with_tstamp_precision +@ stub pcap_init +@ stub pcap_inject @ stub pcap_is_swapped @ cdecl pcap_lib_version() @ cdecl pcap_list_datalinks(ptr ptr) @@ -53,15 +62,18 @@ @ stub pcap_next_etherent @ cdecl pcap_next_ex(ptr ptr ptr) @ stub pcap_offline_filter -@ stub pcap_offline_read +@ stub pcap_oid_get_request +@ stub pcap_oid_set_request @ cdecl pcap_open(str long long long ptr ptr) @ stub pcap_open_dead +@ stub pcap_open_dead_with_tstamp_precision @ cdecl pcap_open_live(str long long long ptr) @ stub pcap_open_offline +@ stub pcap_open_offline_with_tstamp_precision @ cdecl pcap_parsesrcstr(str ptr ptr ptr ptr ptr) @ stub pcap_perror -@ stub pcap_read @ stub pcap_remoteact_accept +@ stub pcap_remoteact_accept_ex @ stub pcap_remoteact_cleanup @ stub pcap_remoteact_close @ stub pcap_remoteact_list @@ -72,6 +84,7 @@ @ stub pcap_sendqueue_transmit @ cdecl pcap_set_buffer_size(ptr long) @ cdecl pcap_set_datalink(ptr long) +@ stub pcap_set_immediate_mode @ cdecl pcap_set_promisc(ptr long) @ cdecl pcap_set_rfmon(ptr long) @ cdecl pcap_set_snaplen(ptr long) @@ -79,6 +92,7 @@ @ cdecl pcap_set_tstamp_precision(ptr long) @ cdecl pcap_set_tstamp_type(ptr long) @ cdecl pcap_setbuff(ptr long) +@ stub pcap_setdirection @ cdecl pcap_setfilter(ptr ptr) @ stub pcap_setmintocopy @ stub pcap_setmode @@ -93,4 +107,5 @@ @ cdecl pcap_tstamp_type_name_to_val(str) @ cdecl pcap_tstamp_type_val_to_description(long) @ cdecl pcap_tstamp_type_val_to_name(long) -@ cdecl wsockinit() +@ stub pcap_version +@ cdecl pcap_wsockinit()
From: Hans Leidekker hans@codeweavers.com
--- dlls/wpcap/unixlib.c | 281 ++++++++------ dlls/wpcap/unixlib.h | 166 ++++++--- dlls/wpcap/wpcap.c | 870 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 966 insertions(+), 351 deletions(-)
diff --git a/dlls/wpcap/unixlib.c b/dlls/wpcap/unixlib.c index a44627a7754..c65a13a1c15 100644 --- a/dlls/wpcap/unixlib.c +++ b/dlls/wpcap/unixlib.c @@ -26,6 +26,7 @@ #ifdef HAVE_PCAP_PCAP_H #include <pcap/pcap.h>
+#include <assert.h> #include <stdarg.h> #include <stdlib.h> #include <limits.h> @@ -40,78 +41,98 @@ #include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(wpcap); -WINE_DECLARE_DEBUG_CHANNEL(winediag);
static NTSTATUS wrap_activate( void *args ) { - struct pcap *pcap = args; - return pcap_activate( pcap->handle ); + const struct activate_params *params = args; + return pcap_activate( (pcap_t *)(ULONG_PTR)params->handle ); }
static NTSTATUS wrap_breakloop( void *args ) { - struct pcap *pcap = args; - pcap_breakloop( pcap->handle ); + const struct breakloop_params *params = args; + pcap_breakloop( (pcap_t *)(ULONG_PTR)params->handle ); return STATUS_SUCCESS; }
static NTSTATUS wrap_can_set_rfmon( void *args ) { - struct pcap *pcap = args; - return pcap_can_set_rfmon( pcap->handle ); + const struct can_set_rfmon_params *params = args; + return pcap_can_set_rfmon( (pcap_t *)(ULONG_PTR)params->handle ); }
static NTSTATUS wrap_close( void *args ) { - struct pcap *pcap = args; - pcap_close( pcap->handle ); - free( pcap ); + const struct close_params *params = args; + pcap_close( (pcap_t *)(ULONG_PTR)params->handle ); return STATUS_SUCCESS; }
static NTSTATUS wrap_compile( void *args ) { - const struct compile_params *params = args; - return pcap_compile( params->pcap->handle, params->program, params->buf, params->optimize, params->mask ); + struct compile_params *params = args; + struct bpf_program program; + int ret; + + if (!(ret = pcap_compile( (pcap_t *)(ULONG_PTR)params->handle, &program, params->str, params->optimize, + params->mask ))) + { + if (*params->program_len < program.bf_len) ret = STATUS_BUFFER_TOO_SMALL; + else memcpy( params->program_insns, program.bf_insns, program.bf_len * sizeof(*program.bf_insns) ); + *params->program_len = program.bf_len; + pcap_freecode( &program ); + } + return ret; }
static NTSTATUS wrap_create( void *args ) { - const struct create_params *params = args; - struct pcap *ret = malloc( sizeof(*ret) ); - - if (ret && !(ret->handle = pcap_create( params->src, params->errbuf ))) - { - free( ret ); - ret = NULL; - } - *params->ret = ret; + struct create_params *params = args; + if (!(*params->handle = (ULONG_PTR)pcap_create( params->source, params->errbuf ))) return STATUS_NO_MEMORY; return STATUS_SUCCESS; }
static NTSTATUS wrap_datalink( void *args ) { - struct pcap *pcap = args; - return pcap_datalink( pcap->handle ); + struct datalink_params *params = args; + return pcap_datalink( (pcap_t *)(ULONG_PTR)params->handle ); }
static NTSTATUS wrap_datalink_name_to_val( void *args ) { - const struct datalink_name_to_val_params *params = args; + struct datalink_name_to_val_params *params = args; return pcap_datalink_name_to_val( params->name ); }
static NTSTATUS wrap_datalink_val_to_description( void *args ) { const struct datalink_val_to_description_params *params = args; - *params->ret = pcap_datalink_val_to_description( params->link ); + const char *str = pcap_datalink_val_to_description( params->link ); + int len; + + if (!str || !params->buf) return STATUS_INVALID_PARAMETER; + if ((len = strlen( str )) >= *params->buflen) + { + *params->buflen = len + 1; + return STATUS_BUFFER_TOO_SMALL; + } + strcpy( params->buf, str ); return STATUS_SUCCESS; }
static NTSTATUS wrap_datalink_val_to_name( void *args ) { const struct datalink_val_to_name_params *params = args; - *params->ret = pcap_datalink_val_to_name( params->link ); + const char *str = pcap_datalink_val_to_name( params->link ); + int len; + + if (!str || !params->buf) return STATUS_INVALID_PARAMETER; + if ((len = strlen( str )) >= *params->buflen) + { + *params->buflen = len + 1; + return STATUS_BUFFER_TOO_SMALL; + } + strcpy( params->buf, str ); return STATUS_SUCCESS; }
@@ -131,65 +152,69 @@ static NTSTATUS wrap_dump( void *args ) static NTSTATUS wrap_dump_open( void *args ) { const struct dump_open_params *params = args; - *params->ret = pcap_dump_open( params->pcap->handle, params->name ); + *params->ret_handle = (ULONG_PTR)pcap_dump_open( (pcap_t *)(ULONG_PTR)params->handle, params->name ); return STATUS_SUCCESS; }
static NTSTATUS wrap_findalldevs( void *args ) { const struct findalldevs_params *params = args; - int ret; - ret = pcap_findalldevs( (pcap_if_t **)params->devs, params->errbuf ); - if (params->devs && !*params->devs) - ERR_(winediag)( "Failed to access raw network (pcap), this requires special permissions.\n" ); - return ret; -} - -static NTSTATUS wrap_free_datalinks( void *args ) -{ - int *links = args; - pcap_free_datalinks( links ); - return STATUS_SUCCESS; -} + pcap_if_t *devs = NULL, *src; + struct pcap_interface_offsets *dst = (struct pcap_interface_offsets *)params->buf; + int ret, len_total = 0;
-static NTSTATUS wrap_free_tstamp_types( void *args ) -{ - int *types = args; - pcap_free_tstamp_types( types ); - return STATUS_SUCCESS; -} + if ((ret = pcap_findalldevs( &devs, params->errbuf ))) return ret;
-static NTSTATUS wrap_freealldevs( void *args ) -{ - struct pcap_interface *devs = args; - pcap_freealldevs( (pcap_if_t *)devs ); - return STATUS_SUCCESS; -} + src = devs; + while (src) + { + int len_name = strlen( src->name ) + 1, len_description = src->description ? strlen( src->description ) + 1 : 0; + int len = sizeof(*dst) + len_name + len_description; + + if (*params->buflen >= len_total + len) + { + dst->name_offset = sizeof(*dst); + dst->name_len = len_name; + strcpy( (char *)dst + dst->name_offset, src->name ); + if (!len_description) dst->description_offset = dst->description_len = 0; + else + { + dst->description_offset = dst->name_offset + len_name; + dst->description_len = len_description; + strcpy( (char *)dst + dst->description_offset, src->description ); + } + dst->flags = src->flags; + dst = (struct pcap_interface_offsets *)((char *)dst + len); + } + len_total += len; + src = src->next; + }
-static NTSTATUS wrap_freecode( void *args ) -{ - void *program = args; - pcap_freecode( program ); - return STATUS_SUCCESS; + if (*params->buflen < len_total) ret = STATUS_BUFFER_TOO_SMALL; + *params->buflen = len_total; + pcap_freealldevs( devs ); + return ret; }
static NTSTATUS wrap_get_tstamp_precision( void *args ) { - struct pcap *pcap = args; - return pcap_get_tstamp_precision( pcap->handle ); + const struct get_tstamp_precision_params *params = args; + return pcap_get_tstamp_precision( (pcap_t *)(ULONG_PTR)params->handle ); }
static NTSTATUS wrap_geterr( void *args ) { const struct geterr_params *params = args; - *params->ret = pcap_geterr( params->pcap->handle ); + char *errbuf = pcap_geterr( (pcap_t *)(ULONG_PTR)params->handle ); + assert( strlen(errbuf) < PCAP_ERRBUF_SIZE ); + strcpy( params->errbuf, errbuf ); return STATUS_SUCCESS; }
static NTSTATUS wrap_getnonblock( void *args ) { const struct getnonblock_params *params = args; - return pcap_getnonblock( params->pcap->handle, params->errbuf ); + return pcap_getnonblock( (pcap_t *)(ULONG_PTR)params->handle, params->errbuf ); }
static NTSTATUS wrap_lib_version( void *args ) @@ -197,6 +222,7 @@ static NTSTATUS wrap_lib_version( void *args ) const struct lib_version_params *params = args; const char *str = pcap_lib_version(); unsigned int len = min( strlen(str) + 1, params->size ); + memcpy( params->version, str, len ); params->version[len - 1] = 0; return STATUS_SUCCESS; @@ -205,13 +231,33 @@ static NTSTATUS wrap_lib_version( void *args ) static NTSTATUS wrap_list_datalinks( void *args ) { const struct list_datalinks_params *params = args; - return pcap_list_datalinks( params->pcap->handle, params->buf ); + NTSTATUS status = STATUS_SUCCESS; + int *links = NULL, count; + + if ((count = pcap_list_datalinks( (pcap_t *)(ULONG_PTR)params->handle, &links )) > 0) + { + if (*params->count < count) status = STATUS_BUFFER_TOO_SMALL; + else memcpy( params->links, links, count * sizeof(*links) ); + } + pcap_free_datalinks( links ); + *params->count = count; + return status; }
static NTSTATUS wrap_list_tstamp_types( void *args ) { const struct list_tstamp_types_params *params = args; - return pcap_list_tstamp_types( params->pcap->handle, params->types ); + NTSTATUS status = STATUS_SUCCESS; + int *types = NULL, count; + + if ((count = pcap_list_tstamp_types( (pcap_t *)(ULONG_PTR)params->handle, &types )) > 0) + { + if (*params->count < count) status = STATUS_BUFFER_TOO_SMALL; + else memcpy( params->types, types, count * sizeof(*types) ); + } + pcap_free_tstamp_types( types ); + *params->count = count; + return status; }
static NTSTATUS wrap_lookupnet( void *args ) @@ -222,31 +268,29 @@ static NTSTATUS wrap_lookupnet( void *args )
static NTSTATUS wrap_major_version( void *args ) { - struct pcap *pcap = args; - return pcap_major_version( pcap->handle ); + const struct major_version_params *params = args; + return pcap_major_version( (pcap_t *)(ULONG_PTR)params->handle ); }
static NTSTATUS wrap_minor_version( void *args ) { - struct pcap *pcap = args; - return pcap_minor_version( pcap->handle ); + const struct minor_version_params *params = args; + return pcap_minor_version( (pcap_t *)(ULONG_PTR)params->handle ); }
static NTSTATUS wrap_next_ex( void *args ) { - const struct next_ex_params *params = args; - struct pcap *pcap = params->pcap; + struct next_ex_params *params = args; struct pcap_pkthdr *hdr_unix; int ret;
- if ((ret = pcap_next_ex( pcap->handle, &hdr_unix, params->data )) == 1) + if ((ret = pcap_next_ex( (pcap_t *)(ULONG_PTR)params->handle, &hdr_unix, params->data )) == 1) { if (hdr_unix->ts.tv_sec > INT_MAX || hdr_unix->ts.tv_usec > INT_MAX) WARN( "truncating timeval values(s)\n" ); - pcap->hdr.ts.tv_sec = hdr_unix->ts.tv_sec; - pcap->hdr.ts.tv_usec = hdr_unix->ts.tv_usec; - pcap->hdr.caplen = hdr_unix->caplen; - pcap->hdr.len = hdr_unix->len; - *params->hdr = &pcap->hdr; + params->hdr->ts.tv_sec = hdr_unix->ts.tv_sec; + params->hdr->ts.tv_usec = hdr_unix->ts.tv_usec; + params->hdr->caplen = hdr_unix->caplen; + params->hdr->len = hdr_unix->len; } return ret; } @@ -254,100 +298,100 @@ static NTSTATUS wrap_next_ex( void *args ) static NTSTATUS wrap_open_live( void *args ) { const struct open_live_params *params = args; - struct pcap *ret = malloc( sizeof(*ret) ); - if (ret && !(ret->handle = pcap_open_live( params->source, params->snaplen, params->promisc, - params->to_ms, params->errbuf ))) - { - free( ret ); - ret = NULL; - } - *params->ret = ret; + if (!(*params->handle = (ULONG_PTR)pcap_open_live( params->source, params->snaplen, params->promisc, + params->timeout, params->errbuf ))) return STATUS_NO_MEMORY; return STATUS_SUCCESS; }
static NTSTATUS wrap_sendpacket( void *args ) { const struct sendpacket_params *params = args; - return pcap_sendpacket( params->pcap->handle, params->buf, params->size ); + return pcap_sendpacket( (pcap_t *)(ULONG_PTR)params->handle, params->buf, params->size ); }
static NTSTATUS wrap_set_buffer_size( void *args ) { const struct set_buffer_size_params *params = args; - return pcap_set_buffer_size( params->pcap->handle, params->size ); + return pcap_set_buffer_size( (pcap_t *)(ULONG_PTR)params->handle, params->size ); }
static NTSTATUS wrap_set_datalink( void *args ) { const struct set_datalink_params *params = args; - return pcap_set_datalink( params->pcap->handle, params->link ); + return pcap_set_datalink( (pcap_t *)(ULONG_PTR)params->handle, params->link ); }
static NTSTATUS wrap_set_promisc( void *args ) { const struct set_promisc_params *params = args; - return pcap_set_promisc( params->pcap->handle, params->enable ); + return pcap_set_promisc( (pcap_t *)(ULONG_PTR)params->handle, params->enable ); }
static NTSTATUS wrap_set_rfmon( void *args ) { const struct set_rfmon_params *params = args; - return pcap_set_rfmon( params->pcap->handle, params->enable ); + return pcap_set_rfmon( (pcap_t *)(ULONG_PTR)params->handle, params->enable ); }
static NTSTATUS wrap_set_snaplen( void *args ) { const struct set_snaplen_params *params = args; - return pcap_set_snaplen( params->pcap->handle, params->len ); + return pcap_set_snaplen( (pcap_t *)(ULONG_PTR)params->handle, params->len ); }
static NTSTATUS wrap_set_timeout( void *args ) { const struct set_timeout_params *params = args; - return pcap_set_timeout( params->pcap->handle, params->timeout ); + return pcap_set_timeout( (pcap_t *)(ULONG_PTR)params->handle, params->timeout ); }
static NTSTATUS wrap_set_tstamp_precision( void *args ) { const struct set_tstamp_precision_params *params = args; - return pcap_set_tstamp_precision( params->pcap->handle, params->precision ); + return pcap_set_tstamp_precision( (pcap_t *)(ULONG_PTR)params->handle, params->precision ); }
static NTSTATUS wrap_set_tstamp_type( void *args ) { const struct set_tstamp_type_params *params = args; - return pcap_set_tstamp_type( params->pcap->handle, params->type ); + return pcap_set_tstamp_type( (pcap_t *)(ULONG_PTR)params->handle, params->type ); }
static NTSTATUS wrap_setfilter( void *args ) { const struct setfilter_params *params = args; - return pcap_setfilter( params->pcap->handle, params->program ); + struct bpf_program program = { params->program_len, params->program_insns }; + return pcap_setfilter( (pcap_t *)(ULONG_PTR)params->handle, &program ); }
static NTSTATUS wrap_setnonblock( void *args ) { const struct setnonblock_params *params = args; - return pcap_setnonblock( params->pcap->handle, params->nonblock, params->errbuf ); + return pcap_setnonblock( (pcap_t *)(ULONG_PTR)params->handle, params->nonblock, params->errbuf ); }
static NTSTATUS wrap_snapshot( void *args ) { - struct pcap *pcap = args; - return pcap_snapshot( pcap->handle ); + const struct snapshot_params *params = args; + return pcap_snapshot( (pcap_t *)(ULONG_PTR)params->handle ); }
static NTSTATUS wrap_stats( void *args ) { - const struct stats_params *params = args; - return pcap_stats( params->pcap->handle, params->stats ); -} + struct stats_params *params = args; + struct pcap_stat stat; + int ret;
-static NTSTATUS wrap_statustostr( void *args ) -{ - const struct statustostr_params *params = args; - *params->ret = pcap_statustostr( params->status ); - return STATUS_SUCCESS; + if (!(ret = pcap_stats( (pcap_t *)(ULONG_PTR)params->handle, &stat ))) + { + params->stat.ps_recv = stat.ps_recv; + params->stat.ps_drop = stat.ps_drop; + params->stat.ps_ifdrop = stat.ps_ifdrop; + params->stat.ps_capt = 0; + params->stat.ps_sent = 0; + params->stat.ps_netdrop = 0; + } + return ret; }
static NTSTATUS wrap_tstamp_type_name_to_val( void *args ) @@ -359,14 +403,32 @@ static NTSTATUS wrap_tstamp_type_name_to_val( void *args ) static NTSTATUS wrap_tstamp_type_val_to_description( void *args ) { const struct tstamp_type_val_to_description_params *params = args; - *params->ret = pcap_tstamp_type_val_to_description( params->val ); + const char *str = pcap_tstamp_type_val_to_description( params->type ); + int len; + + if (!str || !params->buf) return STATUS_INVALID_PARAMETER; + if ((len = strlen( str )) >= *params->buflen) + { + *params->buflen = len + 1; + return STATUS_BUFFER_TOO_SMALL; + } + strcpy( params->buf, str ); return STATUS_SUCCESS; }
static NTSTATUS wrap_tstamp_type_val_to_name( void *args ) { const struct tstamp_type_val_to_name_params *params = args; - *params->ret = pcap_tstamp_type_val_to_name( params->val ); + const char *str = pcap_tstamp_type_val_to_name( params->type ); + int len; + + if (!str || !params->buf) return STATUS_INVALID_PARAMETER; + if ((len = strlen( str )) >= *params->buflen) + { + *params->buflen = len + 1; + return STATUS_BUFFER_TOO_SMALL; + } + strcpy( params->buf, str ); return STATUS_SUCCESS; }
@@ -382,14 +444,9 @@ const unixlib_entry_t __wine_unix_call_funcs[] = wrap_datalink_name_to_val, wrap_datalink_val_to_description, wrap_datalink_val_to_name, - /* wrap_dispatch, */ wrap_dump, wrap_dump_open, wrap_findalldevs, - wrap_free_datalinks, - wrap_free_tstamp_types, - wrap_freealldevs, - wrap_freecode, wrap_get_tstamp_precision, wrap_geterr, wrap_getnonblock, @@ -397,7 +454,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = wrap_list_datalinks, wrap_list_tstamp_types, wrap_lookupnet, - /* wrap_loop, */ wrap_major_version, wrap_minor_version, wrap_next_ex, @@ -415,7 +471,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = wrap_setnonblock, wrap_snapshot, wrap_stats, - wrap_statustostr, wrap_tstamp_type_name_to_val, wrap_tstamp_type_val_to_description, wrap_tstamp_type_val_to_name, diff --git a/dlls/wpcap/unixlib.h b/dlls/wpcap/unixlib.h index 18854e0b86b..403158af978 100644 --- a/dlls/wpcap/unixlib.h +++ b/dlls/wpcap/unixlib.h @@ -35,6 +35,15 @@ struct pcap_interface unsigned int flags; };
+struct pcap_interface_offsets +{ + unsigned int name_offset; + unsigned int name_len; + unsigned int description_offset; + unsigned int description_len; + unsigned int flags; +}; + struct pcap_pkthdr_win32 { struct @@ -46,26 +55,56 @@ struct pcap_pkthdr_win32 unsigned int len; };
-struct pcap +struct pcap_stat_win32 +{ + unsigned int ps_recv; + unsigned int ps_drop; + unsigned int ps_ifdrop; + unsigned int ps_capt; + unsigned int ps_sent; + unsigned int ps_netdrop; +}; + +struct activate_params +{ + UINT64 handle; +}; + +struct breakloop_params { - void *handle; - struct pcap_pkthdr_win32 hdr; + UINT64 handle; +}; + +struct can_set_rfmon_params +{ + UINT64 handle; +}; + +struct close_params +{ + UINT64 handle; };
struct compile_params { - struct pcap *pcap; - void *program; - const char *buf; + UINT64 handle; + unsigned int *program_len; + struct bpf_insn *program_insns; + const char *str; int optimize; unsigned int mask; };
struct create_params { - const char *src; + char *source; char *errbuf; - struct pcap **ret; + UINT64 *handle; +}; + +struct datalink_params +{ + UINT64 handle; };
struct datalink_name_to_val_params @@ -76,13 +115,15 @@ struct datalink_name_to_val_params struct datalink_val_to_description_params { int link; - const char **ret; + char *buf; + unsigned int *buflen; };
struct datalink_val_to_name_params { int link; - const char **ret; + char *buf; + unsigned int *buflen; };
struct dump_params @@ -94,29 +135,35 @@ struct dump_params
struct dump_open_params { - struct pcap *pcap; - const char *name; - void **ret; + UINT64 handle; + char *name; + UINT64 *ret_handle; };
struct findalldevs_params { - struct pcap_interface **devs; + char *buf; + unsigned int *buflen; char *errbuf; };
struct geterr_params { - struct pcap *pcap; - char **ret; + UINT64 handle; + char *errbuf; };
struct getnonblock_params { - struct pcap *pcap; + UINT64 handle; char *errbuf; };
+struct get_tstamp_precision_params +{ + UINT64 handle; +}; + struct lib_version_params { char *version; @@ -125,119 +172,131 @@ struct lib_version_params
struct list_datalinks_params { - struct pcap *pcap; - int **buf; + UINT64 handle; + int *links; + int *count; };
struct list_tstamp_types_params { - struct pcap *pcap; - int **types; + UINT64 handle; + int *types; + int *count; };
struct lookupnet_params { - const char *device; + char *device; unsigned int *net; unsigned int *mask; char *errbuf; };
+struct major_version_params +{ + UINT64 handle; +}; + +struct minor_version_params +{ + UINT64 handle; +}; + struct next_ex_params { - struct pcap *pcap; - struct pcap_pkthdr_win32 **hdr; + UINT64 handle; + struct pcap_pkthdr_win32 *hdr; const unsigned char **data; };
struct open_live_params { - const char *source; + char *source; int snaplen; int promisc; - int to_ms; + int timeout; char *errbuf; - struct pcap **ret; + UINT64 *handle; };
struct sendpacket_params { - struct pcap *pcap; + UINT64 handle; const unsigned char *buf; int size; };
struct set_buffer_size_params { - struct pcap *pcap; + UINT64 handle; int size; };
struct set_datalink_params { - struct pcap *pcap; + UINT64 handle; int link; };
struct set_promisc_params { - struct pcap *pcap; + UINT64 handle; int enable; };
struct set_rfmon_params { - struct pcap *pcap; + UINT64 handle; int enable; };
struct set_snaplen_params { - struct pcap *pcap; + UINT64 handle; int len; };
struct set_timeout_params { - struct pcap *pcap; + UINT64 handle; int timeout; };
struct set_tstamp_precision_params { - struct pcap *pcap; + UINT64 handle; int precision; };
struct set_tstamp_type_params { - struct pcap *pcap; + UINT64 handle; int type; };
struct setfilter_params { - struct pcap *pcap; - void *program; + UINT64 handle; + unsigned int program_len; + struct bpf_insn *program_insns; };
struct setnonblock_params { - struct pcap *pcap; + UINT64 handle; int nonblock; char *errbuf; };
-struct stats_params +struct snapshot_params { - struct pcap *pcap; - void *stats; + UINT64 handle; };
-struct statustostr_params +struct stats_params { - int status; - const char **ret; + UINT64 handle; + struct pcap_stat_win32 stat; };
struct tstamp_type_name_to_val_params @@ -247,14 +306,16 @@ struct tstamp_type_name_to_val_params
struct tstamp_type_val_to_description_params { - int val; - const char **ret; + int type; + char *buf; + unsigned int *buflen; };
struct tstamp_type_val_to_name_params { - int val; - const char **ret; + int type; + char *buf; + unsigned int *buflen; };
enum pcap_funcs @@ -269,14 +330,9 @@ enum pcap_funcs unix_datalink_name_to_val, unix_datalink_val_to_description, unix_datalink_val_to_name, - /* unix_dispatch, */ unix_dump, unix_dump_open, unix_findalldevs, - unix_free_datalinks, - unix_free_tstamp_types, - unix_freealldevs, - unix_freecode, unix_get_tstamp_precision, unix_geterr, unix_getnonblock, @@ -284,7 +340,6 @@ enum pcap_funcs unix_list_datalinks, unix_list_tstamp_types, unix_lookupnet, - /* unix_loop, */ unix_major_version, unix_minor_version, unix_next_ex, @@ -302,7 +357,6 @@ enum pcap_funcs unix_setnonblock, unix_snapshot, unix_stats, - unix_statustostr, unix_tstamp_type_name_to_val, unix_tstamp_type_val_to_description, unix_tstamp_type_val_to_name, diff --git a/dlls/wpcap/wpcap.c b/dlls/wpcap/wpcap.c index 0964715f92c..5494ed292e1 100644 --- a/dlls/wpcap/wpcap.c +++ b/dlls/wpcap/wpcap.c @@ -2,6 +2,7 @@ * WPcap.dll Proxy. * * Copyright 2011, 2014 André Hentschel + * Copyright 2022 Hans Leidekker for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,6 +20,10 @@ */
#include <stdarg.h> +#include <malloc.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winternl.h" @@ -33,44 +38,147 @@ #include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(wpcap); +WINE_DECLARE_DEBUG_CHANNEL(winediag);
#define PCAP_CALL( func, params ) WINE_UNIX_CALL( unix_ ## func, params )
+#define PCAP_ERROR -1 +#define PCAP_ERROR_BREAK -2 +#define PCAP_ERROR_NOT_ACTIVATED -3 +#define PCAP_ERROR_ACTIVATED -4 +#define PCAP_ERROR_NO_SUCH_DEVICE -5 +#define PCAP_ERROR_RFMON_NOTSUP -6 +#define PCAP_ERROR_NOT_RFMON -7 +#define PCAP_ERROR_PERM_DENIED -8 +#define PCAP_ERROR_IFACE_NOT_UP -9 +#define PCAP_ERROR_CANTSET_TSTAMP_TYPE -10 +#define PCAP_ERROR_PROMISC_PERM_DENIED -11 +#define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12 + +#define PCAP_WARNING 1 +#define PCAP_WARNING_PROMISC_NOTSUP 2 +#define PCAP_WARNING_TSTAMP_TYPE_NOTSUP 3 + +#define PCAP_ERRBUF_SIZE 256 +struct pcap +{ + UINT64 handle; + struct pcap_pkthdr_win32 hdr; + char errbuf[PCAP_ERRBUF_SIZE]; +}; + +struct bpf_insn +{ + unsigned short code; + unsigned char jt; + unsigned char jf; + unsigned int k; +}; + +struct bpf_program +{ + unsigned int bf_len; + struct bpf_insn *bf_insns; +}; + int CDECL pcap_activate( struct pcap *pcap ) { + struct activate_params params; + int ret; + TRACE( "%p\n", pcap ); - return PCAP_CALL( activate, pcap ); + + if (!pcap) return PCAP_ERROR; + + params.handle = pcap->handle; + ret = PCAP_CALL( activate, ¶ms ); + if (ret == PCAP_ERROR_PERM_DENIED) + ERR_(winediag)( "Failed to access raw network (pcap), this requires special permissions.\n" ); + return ret; }
void CDECL pcap_breakloop( struct pcap *pcap ) { + struct breakloop_params params; + TRACE( "%p\n", pcap ); - PCAP_CALL( breakloop, pcap ); + + if (!pcap) return; + params.handle = pcap->handle; + PCAP_CALL( breakloop, ¶ms ); }
int CDECL pcap_can_set_rfmon( struct pcap *pcap ) { + struct can_set_rfmon_params params; + TRACE( "%p\n", pcap ); - return PCAP_CALL( can_set_rfmon, pcap ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + return PCAP_CALL( can_set_rfmon, ¶ms ); }
void CDECL pcap_close( struct pcap *pcap ) { + struct close_params params; + TRACE( "%p\n", pcap ); - PCAP_CALL( close, pcap ); + + if (!pcap) return; + params.handle = pcap->handle; + PCAP_CALL( close, ¶ms ); + free( pcap ); }
-int CDECL pcap_compile( struct pcap *pcap, void *program, const char *buf, int optimize, unsigned int mask ) +int CDECL pcap_compile( struct pcap *pcap, struct bpf_program *program, const char *str, int optimize, unsigned int mask ) { - struct compile_params params = { pcap, program, buf, optimize, mask }; - TRACE( "%p, %p, %s, %d, %u\n", pcap, program, debugstr_a(buf), optimize, mask ); - return PCAP_CALL( compile, ¶ms ); + struct compile_params params; + unsigned int len = 64; + struct bpf_insn *tmp; + NTSTATUS status; + + TRACE( "%p, %p, %s, %d, %#x\n", pcap, program, debugstr_a(str), optimize, mask ); + + if (!pcap || !program) return PCAP_ERROR; + + if (!(params.program_insns = malloc( len * sizeof(*params.program_insns) ))) return PCAP_ERROR; + params.handle = pcap->handle; + params.program_len = &len; + params.str = str; + params.optimize = optimize; + params.mask = mask; + if ((status = PCAP_CALL( compile, ¶ms )) == STATUS_SUCCESS) + { + program->bf_len = *params.program_len; + program->bf_insns = params.program_insns; + return 0; + } + if (status != STATUS_BUFFER_TOO_SMALL || !(tmp = realloc( params.program_insns, len * sizeof(*tmp) ))) + { + free( params.program_insns ); + return PCAP_ERROR; + } + params.program_insns = tmp; + if (PCAP_CALL( compile, ¶ms )) + { + free( params.program_insns ); + return PCAP_ERROR; + } + program->bf_len = *params.program_len; + program->bf_insns = params.program_insns; + return 0; }
int CDECL pcap_datalink( struct pcap *pcap ) { + struct datalink_params params; + TRACE( "%p\n", pcap ); - return PCAP_CALL( datalink, pcap ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + return PCAP_CALL( datalink, ¶ms ); }
int CDECL pcap_datalink_name_to_val( const char *name ) @@ -80,22 +188,94 @@ int CDECL pcap_datalink_name_to_val( const char *name ) return PCAP_CALL( datalink_name_to_val, ¶ms ); }
+static struct +{ + char *name; + char *description; +} datalinks[192]; + +static void free_datalinks( void ) +{ + unsigned int i; + for (i = 0; i < ARRAY_SIZE(datalinks); i++) + { + free( datalinks[i].name ); + datalinks[i].name = NULL; + free( datalinks[i].description ); + datalinks[i].description = NULL; + } +} + const char * CDECL pcap_datalink_val_to_description( int link ) { - const char *ret; - struct datalink_val_to_description_params params = { link, &ret }; + struct datalink_val_to_description_params params; + unsigned int len = 192; + char *tmp; + NTSTATUS status; + TRACE( "%d\n", link ); - PCAP_CALL( datalink_val_to_description, ¶ms ); - return ret; + + if (link < 0 || link >= ARRAY_SIZE(datalinks)) + { + WARN( "unhandled link type %d\n", link ); + return NULL; + } + if (datalinks[link].description) return datalinks[link].description; + + if (!(params.buf = malloc( len ))) return NULL; + params.link = link; + params.buflen = &len; + status = PCAP_CALL( datalink_val_to_description, ¶ms ); + if (status == STATUS_SUCCESS) return (datalinks[link].description = params.buf); + if (status != STATUS_BUFFER_TOO_SMALL || !(tmp = realloc( params.buf, len ))) + { + free( params.buf ); + return NULL; + } + params.buf = tmp; + if (PCAP_CALL( datalink_val_to_description, ¶ms )) + { + free( params.buf ); + return NULL; + } + + return (datalinks[link].description = params.buf); }
const char * CDECL pcap_datalink_val_to_name( int link ) { - const char *ret; - struct datalink_val_to_name_params params = { link, &ret }; + struct datalink_val_to_name_params params; + unsigned int len = 64; + char *tmp; + NTSTATUS status; + TRACE( "%d\n", link ); - PCAP_CALL( datalink_val_to_name, ¶ms ); - return ret; + + if (link < 0 || link >= ARRAY_SIZE(datalinks)) + { + WARN( "unhandled link type %d\n", link ); + return NULL; + } + if (datalinks[link].name) return datalinks[link].name; + + if (!(params.buf = malloc( len ))) return NULL; + params.link = link; + params.buflen = &len; + status = PCAP_CALL( datalink_val_to_name, ¶ms ); + if (status == STATUS_SUCCESS) return (datalinks[link].name = params.buf); + if (status != STATUS_BUFFER_TOO_SMALL || !(tmp = realloc( params.buf, len ))) + { + free( params.buf ); + return NULL; + } + params.buf = tmp; + if (PCAP_CALL( datalink_val_to_name, ¶ms )) + { + free( params.buf ); + return NULL; + } + + return (datalinks[link].name = params.buf); }
void CDECL pcap_dump( unsigned char *user, const struct pcap_pkthdr_win32 *hdr, const unsigned char *packet ) @@ -105,38 +285,53 @@ void CDECL pcap_dump( unsigned char *user, const struct pcap_pkthdr_win32 *hdr, PCAP_CALL( dump, ¶ms ); }
-static inline WCHAR *strdupAW( const char *str ) +struct dumper +{ + UINT64 handle; +}; + +static inline WCHAR *strdup_from_utf8( const char *str ) { WCHAR *ret = NULL; if (str) { - int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); - if ((ret = malloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); + int len = MultiByteToWideChar( CP_UTF8, 0, str, -1, NULL, 0 ); + if ((ret = malloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_UTF8, 0, str, -1, ret, len ); } return ret; }
-void * CDECL pcap_dump_open( struct pcap *pcap, const char *filename ) +struct dumper * CDECL pcap_dump_open( struct pcap *pcap, const char *filename ) { - void *dumper; + struct dumper *dumper; WCHAR *filenameW; - char *unix_path; struct dump_open_params params;
TRACE( "%p, %s\n", pcap, debugstr_a(filename) );
- if (!(filenameW = strdupAW( filename ))) return NULL; - unix_path = wine_get_unix_file_name( filenameW ); + if (!pcap) return NULL; + + if (!(filenameW = strdup_from_utf8( filename ))) return NULL; + params.name = wine_get_unix_file_name( filenameW ); free( filenameW ); - if (!unix_path) return NULL; + if (!params.name) return NULL; + + if (!(dumper = calloc( 1, sizeof(*dumper) ))) + { + HeapFree( GetProcessHeap(), 0, params.name ); + return NULL; + }
- TRACE( "unix_path %s\n", debugstr_a(unix_path) ); + TRACE( "unix_path %s\n", debugstr_a(params.name) );
- params.pcap = pcap; - params.name = unix_path; - params.ret = &dumper; - PCAP_CALL( dump_open, ¶ms ); - HeapFree( GetProcessHeap(), 0, unix_path ); + params.handle = pcap->handle; + params.ret_handle = &dumper->handle; + if (PCAP_CALL( dump_open, ¶ms )) + { + free( dumper ); + dumper = NULL; + } + HeapFree( GetProcessHeap(), 0, params.name ); return dumper; }
@@ -192,7 +387,7 @@ static IP_ADAPTER_ADDRESSES *find_adapter( IP_ADAPTER_ADDRESSES *list, const cha IP_ADAPTER_ADDRESSES *ret; WCHAR *nameW;
- if (!(nameW = strdupAW( name ))) return NULL; + if (!(nameW = strdup_from_utf8( name ))) return NULL; for (ret = list; ret; ret = ret->Next) { if (!wcscmp( nameW, ret->FriendlyName )) break; @@ -218,21 +413,22 @@ static char *build_win32_name( const char *source, const char *adapter_name ) return ret; }
-static char *build_win32_description( const struct pcap_interface *unix_dev ) +static char *build_win32_description( const struct pcap_interface_offsets *unix_dev ) { - int len = strlen(unix_dev->name) + 1; + const char *name = (const char *)unix_dev + unix_dev->name_offset; + const char *description = (const char *)unix_dev + unix_dev->description_offset; + int len = unix_dev->name_len + unix_dev->description_len + 1; char *ret;
- if (unix_dev->description && unix_dev->description[0]) len += strlen(unix_dev->description) + 1; if ((ret = malloc( len ))) { - if (unix_dev->description) + if (unix_dev->description_len) { - strcpy( ret, unix_dev->description ); + strcpy( ret, description ); strcat( ret, " " ); - strcat( ret, unix_dev->name ); + strcat( ret, name ); } - else strcpy( ret, unix_dev->name ); + else strcpy( ret, name ); } return ret; } @@ -366,7 +562,7 @@ static struct pcap_address *build_win32_addresses( const IP_ADAPTER_ADDRESSES *a return ret; }
-static struct pcap_interface *build_win32_device( const struct pcap_interface *unix_dev, const char *source, +static struct pcap_interface *build_win32_device( const struct pcap_interface_offsets *unix_dev, const char *source, const IP_ADAPTER_ADDRESSES *adapter ) { struct pcap_interface *ret; @@ -399,33 +595,58 @@ static void add_win32_device( struct pcap_interface **list, struct pcap_interfac
static int find_all_devices( const char *source, struct pcap_interface **devs, char *errbuf ) { - struct pcap_interface *unix_devs, *win32_devs = NULL, *cur, *dev; - IP_ADAPTER_ADDRESSES *ptr, *adapters = get_adapters(); - struct findalldevs_params params = { &unix_devs, errbuf }; + struct pcap_interface *win32_devs = NULL, *dst; + const struct pcap_interface_offsets *src; + IP_ADAPTER_ADDRESSES *ptr, *adapters; + struct findalldevs_params params; + unsigned int len_total = 0, len = 512; int ret;
- if (!adapters) + if (!(params.buf = malloc( len ))) return PCAP_ERROR; + params.buflen = &len; + params.errbuf = errbuf; + for (;;) { - if (errbuf) sprintf( errbuf, "Out of memory." ); - return -1; + char *tmp; + if ((ret = PCAP_CALL( findalldevs, ¶ms )) != STATUS_BUFFER_TOO_SMALL) break; + if (!(tmp = realloc( params.buf, *params.buflen ))) + { + free( params.buf ); + return PCAP_ERROR; + } + params.buf = tmp; + } + if (ret) + { + free( params.buf ); + return ret; }
- if (!(ret = PCAP_CALL( findalldevs, ¶ms ))) + if (!(adapters = get_adapters())) { - cur = unix_devs; - while (cur) + free( params.buf ); + return PCAP_ERROR; + } + + src = (const struct pcap_interface_offsets *)params.buf; + for (;;) + { + const char *name = (const char *)src + src->name_offset; + unsigned int len_src = sizeof(*src) + src->name_len + src->description_len; + + if ((ptr = find_adapter( adapters, name )) && (dst = build_win32_device( src, source, ptr ))) { - if ((ptr = find_adapter( adapters, cur->name )) && (dev = build_win32_device( cur, source, ptr ))) - { - add_win32_device( &win32_devs, dev ); - } - cur = cur->next; + add_win32_device( &win32_devs, dst ); } - *devs = win32_devs; - PCAP_CALL( freealldevs, unix_devs ); + + len_total += len_src; + if (len_total >= *params.buflen) break; + src = (const struct pcap_interface_offsets *)((const char *)src + len_src); } + *devs = win32_devs;
free( adapters ); + free( params.buf ); return ret; }
@@ -444,13 +665,13 @@ int CDECL pcap_findalldevs_ex( char *source, void *auth, struct pcap_interface * void CDECL pcap_free_datalinks( int *links ) { TRACE( "%p\n", links ); - PCAP_CALL( free_datalinks, links ); + free( links ); }
void CDECL pcap_free_tstamp_types( int *types ) { TRACE( "%p\n", types ); - PCAP_CALL( free_tstamp_types, types ); + free( types ); }
void CDECL pcap_freealldevs( struct pcap_interface *devs ) @@ -459,10 +680,12 @@ void CDECL pcap_freealldevs( struct pcap_interface *devs ) free_devices( devs ); }
-void CDECL pcap_freecode( void *program ) +void CDECL pcap_freecode( struct bpf_program *program ) { TRACE( "%p\n", program ); - PCAP_CALL( freecode, program ); + + if (!program) return; + free( program->bf_insns ); }
void * CDECL pcap_get_airpcap_handle( struct pcap *pcap ) @@ -473,23 +696,37 @@ void * CDECL pcap_get_airpcap_handle( struct pcap *pcap )
int CDECL pcap_get_tstamp_precision( struct pcap *pcap ) { + struct get_tstamp_precision_params params; + TRACE( "%p\n", pcap ); - return PCAP_CALL( get_tstamp_precision, pcap ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + return PCAP_CALL( get_tstamp_precision, ¶ms ); }
char * CDECL pcap_geterr( struct pcap *pcap ) { - char *ret; - struct geterr_params params = { pcap, &ret }; + struct geterr_params params; + TRACE( "%p\n", pcap ); + + if (!pcap) return NULL; + params.handle = pcap->handle; + params.errbuf = pcap->errbuf; PCAP_CALL( geterr, ¶ms ); - return ret; + return pcap->errbuf; /* FIXME: keep up-to-date */ }
int CDECL pcap_getnonblock( struct pcap *pcap, char *errbuf ) { - struct getnonblock_params params = { pcap, errbuf }; + struct getnonblock_params params; + TRACE( "%p, %p\n", pcap, errbuf ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.errbuf = errbuf; return PCAP_CALL( getnonblock, ¶ms ); }
@@ -509,18 +746,82 @@ const char * CDECL pcap_lib_version( void ) return lib_version; }
-int CDECL pcap_list_datalinks( struct pcap *pcap, int **buf ) +int CDECL pcap_list_datalinks( struct pcap *pcap, int **links ) { - struct list_datalinks_params params = { pcap, buf }; - TRACE( "%p, %p\n", pcap, buf ); - return PCAP_CALL( list_datalinks, ¶ms ); + struct list_datalinks_params params; + int count = 8, *tmp; + NTSTATUS status; + + TRACE( "%p, %p\n", pcap, links ); + + if (!pcap || !links) return PCAP_ERROR; + + if (!(params.links = malloc( count * sizeof(*params.links) ))) return PCAP_ERROR; + params.handle = pcap->handle; + params.count = &count; + if ((status = PCAP_CALL( list_datalinks, ¶ms )) == STATUS_SUCCESS) + { + if (count > 0) *links = params.links; + else + { + free( params.links ); + *links = NULL; + } + return count; + } + if (status != STATUS_BUFFER_TOO_SMALL || !(tmp = realloc( params.links, count * sizeof(*tmp) ))) + { + free( params.links ); + return PCAP_ERROR; + } + params.links = tmp; + if (PCAP_CALL( list_datalinks, ¶ms )) + { + free( params.links ); + return PCAP_ERROR; + } + *links = params.links; + return count; }
int CDECL pcap_list_tstamp_types( struct pcap *pcap, int **types ) { - struct list_tstamp_types_params params = { pcap, types }; + struct list_tstamp_types_params params; + int count = 8, *tmp; + NTSTATUS status; + + TRACE( "%p, %p\n", pcap, types ); + TRACE( "%p, %p\n", pcap, types ); - return PCAP_CALL( list_tstamp_types, ¶ms ); + + if (!pcap || !types) return PCAP_ERROR; + + if (!(params.types = malloc( count * sizeof(*params.types) ))) return PCAP_ERROR; + params.handle = pcap->handle; + params.count = &count; + if ((status = PCAP_CALL( list_tstamp_types, ¶ms )) == STATUS_SUCCESS) + { + if (count > 0) *types = params.types; + else + { + free( params.types ); + *types = NULL; + } + return count; + } + if (status != STATUS_BUFFER_TOO_SMALL || !(tmp = realloc( params.types, count * sizeof(*tmp) ))) + { + free( params.types ); + return PCAP_ERROR; + } + params.types = tmp; + if (PCAP_CALL( list_tstamp_types, ¶ms )) + { + free( params.types ); + return PCAP_ERROR; + } + *types = params.types; + return count; }
char * CDECL pcap_lookupdev( char *errbuf ) @@ -531,18 +832,58 @@ char * CDECL pcap_lookupdev( char *errbuf ) TRACE( "%p\n", errbuf ); if (!ret) { - if (pcap_findalldevs( &devs, errbuf ) == -1 || !devs) return NULL; + if (pcap_findalldevs( &devs, errbuf ) == PCAP_ERROR || !devs) return NULL; if ((ret = malloc( strlen(devs->name) + 1 ))) strcpy( ret, devs->name ); pcap_freealldevs( devs ); } return ret; }
+static char *strdup_to_utf8( const WCHAR *src ) +{ + char *dst; + int len = WideCharToMultiByte( CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL ); + if ((dst = malloc( len ))) WideCharToMultiByte( CP_UTF8, 0, src, -1, dst, len, NULL, NULL ); + return dst; +} + +static char *map_win32_device_name( const char *dev ) +{ + IP_ADAPTER_ADDRESSES *ptr, *adapters = get_adapters(); + const char *name = strchr( dev, '{' ); + char *ret = NULL; + + if (!adapters || !name) return NULL; + for (ptr = adapters; ptr; ptr = ptr->Next) + { + if (!strcmp( name, ptr->AdapterName )) + { + ret = strdup_to_utf8( ptr->FriendlyName ); + break; + } + } + free( adapters ); + return ret; +} + int CDECL pcap_lookupnet( const char *device, unsigned int *net, unsigned int *mask, char *errbuf ) { - struct lookupnet_params params = { device, net, mask, errbuf }; + struct lookupnet_params params; + int ret; + TRACE( "%s, %p, %p, %p\n", debugstr_a(device), net, mask, errbuf ); - return PCAP_CALL( lookupnet, ¶ms ); + + if (!(params.device = map_win32_device_name( device ))) + { + if (errbuf) sprintf( errbuf, "Unable to open the adapter." ); + return PCAP_ERROR; + } + params.net = net; + params.mask = mask; + params.errbuf = errbuf; + ret = PCAP_CALL( lookupnet, ¶ms ); + free( params.device ); + return ret; }
int CDECL pcap_loop( struct pcap *pcap, int count, @@ -556,21 +897,39 @@ int CDECL pcap_loop( struct pcap *pcap, int count,
int CDECL pcap_major_version( struct pcap *pcap ) { + struct major_version_params params; + TRACE( "%p\n", pcap ); - return PCAP_CALL( major_version, pcap ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + return PCAP_CALL( major_version, ¶ms ); }
int CDECL pcap_minor_version( struct pcap *pcap ) { + struct minor_version_params params; + TRACE( "%p\n", pcap ); - return PCAP_CALL( minor_version, pcap ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + return PCAP_CALL( minor_version, ¶ms ); }
int CDECL pcap_next_ex( struct pcap *pcap, struct pcap_pkthdr_win32 **hdr, const unsigned char **data ) { - struct next_ex_params params = { pcap, hdr, data }; + struct next_ex_params params; + int ret; + TRACE( "%p, %p, %p\n", pcap, hdr, data ); - return PCAP_CALL( next_ex, ¶ms ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.hdr = &pcap->hdr; + params.data = data; + if ((ret = PCAP_CALL( next_ex, ¶ms )) == 1) *hdr = &pcap->hdr; + return ret; }
const unsigned char * CDECL pcap_next( struct pcap *pcap, struct pcap_pkthdr_win32 *hdr ) @@ -578,9 +937,12 @@ const unsigned char * CDECL pcap_next( struct pcap *pcap, struct pcap_pkthdr_win struct pcap_pkthdr_win32 *hdr_ptr; const unsigned char *data;
- pcap_next_ex( pcap, &hdr_ptr, &data ); - *hdr = *hdr_ptr; - return data; + if (pcap_next_ex( pcap, &hdr_ptr, &data ) == 1) + { + *hdr = *hdr_ptr; + return data; + } + return NULL; }
int CDECL pcap_dispatch( struct pcap *pcap, int count, @@ -588,6 +950,7 @@ int CDECL pcap_dispatch( struct pcap *pcap, int count, unsigned char *user ) { int processed = 0; + TRACE( "%p, %d, %p, %p\n", pcap, count, callback, user );
while (processed < count) @@ -601,9 +964,9 @@ int CDECL pcap_dispatch( struct pcap *pcap, int count, processed++; else if (ret == 0) break; - else if (ret == -2) + else if (ret == PCAP_ERROR_BREAK) { - if (processed == 0) return -2; + if (processed == 0) return PCAP_ERROR_BREAK; break; } else @@ -615,69 +978,56 @@ int CDECL pcap_dispatch( struct pcap *pcap, int count, return processed; }
-static char *strdupWA( const WCHAR *src ) -{ - char *dst; - int len = WideCharToMultiByte( CP_ACP, 0, src, -1, NULL, 0, NULL, NULL ); - if ((dst = malloc( len ))) WideCharToMultiByte( CP_ACP, 0, src, -1, dst, len, NULL, NULL ); - return dst; -} - -static char *map_win32_device_name( const char *dev ) -{ - IP_ADAPTER_ADDRESSES *ptr, *adapters = get_adapters(); - const char *name = strchr( dev, '{' ); - char *ret = NULL; - - if (!adapters || !name) return NULL; - for (ptr = adapters; ptr; ptr = ptr->Next) - { - if (!strcmp( name, ptr->AdapterName )) - { - ret = strdupWA( ptr->FriendlyName ); - break; - } - } - free( adapters ); - return ret; -} - struct pcap * CDECL pcap_create( const char *source, char *errbuf ) { - char *unix_dev; struct pcap *ret; + struct create_params params; + TRACE( "%s, %p\n", source, errbuf );
- if (!(unix_dev = map_win32_device_name( source ))) + if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL; + + if (!(params.source = map_win32_device_name( source ))) { if (errbuf) sprintf( errbuf, "Unable to open the adapter." ); + free( ret ); return NULL; } - else + params.errbuf = errbuf; + params.handle = &ret->handle; + if (PCAP_CALL( create, ¶ms )) { - struct create_params params = { unix_dev, errbuf, &ret }; - PCAP_CALL( create, ¶ms ); + free( ret ); + ret = NULL; } - free( unix_dev ); + free( params.source ); return ret; }
static struct pcap *open_live( const char *source, int snaplen, int promisc, int timeout, char *errbuf ) { - char *unix_dev; struct pcap *ret; + struct open_live_params params; + + if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL;
- if (!(unix_dev = map_win32_device_name( source ))) + if (!(params.source = map_win32_device_name( source ))) { if (errbuf) sprintf( errbuf, "Unable to open the adapter." ); + free( ret ); return NULL; } - else + params.snaplen = snaplen; + params.promisc = promisc; + params.timeout = timeout; + params.errbuf = errbuf; + params.handle = &ret->handle; + if (PCAP_CALL( open_live, ¶ms )) { - struct open_live_params params = { unix_dev, snaplen, promisc, timeout, errbuf, &ret }; - PCAP_CALL( open_live, ¶ms ); + free( ret ); + ret = NULL; } - free( unix_dev ); + free( params.source ); return ret; }
@@ -697,104 +1047,141 @@ struct pcap * CDECL pcap_open_live( const char *source, int snaplen, int promisc #define PCAP_SRC_FILE 2 #define PCAP_SRC_IFLOCAL 3
-int CDECL pcap_parsesrcstr( const char *source, int *type, char *host, char *port, char *name, char *errbuf ) +int CDECL pcap_parsesrcstr( const char *source, int *ret_type, char *host, char *port, char *name, char *errbuf ) { - int t = PCAP_SRC_IFLOCAL; - const char *p = source; + int type = PCAP_SRC_IFLOCAL; + const char *ptr = source;
- FIXME( "%s, %p, %p, %p, %p, %p: partial stub\n", debugstr_a(source), type, host, port, name, errbuf ); + FIXME( "%s, %p, %p, %p, %p, %p: partial stub\n", debugstr_a(source), ret_type, host, port, name, errbuf );
- if (host) - *host = '\0'; - if (port) - *port = '\0'; - if (name) - *name = '\0'; + if (host) *host = 0; + if (port) *port = 0; + if (name) *name = 0;
- if (!strncmp(p, "rpcap://", strlen("rpcap://"))) - p += strlen("rpcap://"); - else if (!strncmp(p, "file://", strlen("file://"))) + if (!strncmp( ptr, "rpcap://", strlen("rpcap://"))) ptr += strlen( "rpcap://" ); + else if (!strncmp( ptr, "file://", strlen("file://") )) { - p += strlen("file://"); - t = PCAP_SRC_FILE; + ptr += strlen( "file://" ); + type = PCAP_SRC_FILE; }
- if (type) - *type = t; - - if (!*p) + if (ret_type) *ret_type = type; + if (!*ptr) { - if (errbuf) - sprintf(errbuf, "The name has not been specified in the source string."); - return -1; + if (errbuf) sprintf( errbuf, "The name has not been specified in the source string." ); + return PCAP_ERROR; }
- if (name) - strcpy(name, p); - + if (name) strcpy( name, ptr ); return 0; }
int CDECL pcap_sendpacket( struct pcap *pcap, const unsigned char *buf, int size ) { - struct sendpacket_params params = { pcap, buf, size }; + struct sendpacket_params params; + TRACE( "%p, %p, %d\n", pcap, buf, size ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.buf = buf; + params.size = size; return PCAP_CALL( sendpacket, ¶ms ); }
int CDECL pcap_set_buffer_size( struct pcap *pcap, int size ) { - struct set_buffer_size_params params = { pcap, size }; + struct set_buffer_size_params params; + TRACE( "%p, %d\n", pcap, size ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.size = size; return PCAP_CALL( set_buffer_size, ¶ms ); }
int CDECL pcap_set_datalink( struct pcap *pcap, int link ) { - struct set_datalink_params params = { pcap, link }; + struct set_datalink_params params; + TRACE( "%p, %d\n", pcap, link ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.link = link; return PCAP_CALL( set_datalink, ¶ms ); }
int CDECL pcap_set_promisc( struct pcap *pcap, int enable ) { - struct set_promisc_params params = { pcap, enable }; + struct set_promisc_params params; + TRACE( "%p, %d\n", pcap, enable ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.enable = enable; return PCAP_CALL( set_promisc, ¶ms ); }
int CDECL pcap_set_rfmon( struct pcap *pcap, int enable ) { - struct set_rfmon_params params = { pcap, enable }; + struct set_rfmon_params params; + TRACE( "%p, %d\n", pcap, enable ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.enable = enable; return PCAP_CALL( set_rfmon, ¶ms ); }
int CDECL pcap_set_snaplen( struct pcap *pcap, int len ) { - struct set_snaplen_params params = { pcap, len }; + struct set_snaplen_params params; + TRACE( "%p, %d\n", pcap, len ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.len = len; return PCAP_CALL( set_snaplen, ¶ms ); }
int CDECL pcap_set_timeout( struct pcap *pcap, int timeout ) { - struct set_timeout_params params = { pcap, timeout }; + struct set_timeout_params params; + TRACE( "%p, %d\n", pcap, timeout ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.timeout = timeout; return PCAP_CALL( set_timeout, ¶ms ); }
int CDECL pcap_set_tstamp_precision( struct pcap *pcap, int precision ) { - struct set_tstamp_precision_params params = { pcap, precision }; + struct set_tstamp_precision_params params; + TRACE( "%p, %d\n", pcap, precision ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.precision = precision; return PCAP_CALL( set_tstamp_precision, ¶ms ); }
int CDECL pcap_set_tstamp_type( struct pcap *pcap, int type ) { - struct set_tstamp_type_params params = { pcap, type }; + struct set_tstamp_type_params params; + TRACE( "%p, %d\n", pcap, type ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.type = type; return PCAP_CALL( set_tstamp_type, ¶ms ); }
@@ -804,40 +1191,84 @@ int CDECL pcap_setbuff( struct pcap *pcap, int size ) return 0; }
-int CDECL pcap_setfilter( struct pcap *pcap, void *program ) +int CDECL pcap_setfilter( struct pcap *pcap, struct bpf_program *program ) { - struct setfilter_params params = { pcap, program }; + struct setfilter_params params; + TRACE( "%p, %p\n", pcap, program ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.program_len = program->bf_len; + params.program_insns = program->bf_insns; return PCAP_CALL( setfilter, ¶ms ); }
int CDECL pcap_setnonblock( struct pcap *pcap, int nonblock, char *errbuf ) { - struct setnonblock_params params = { pcap, nonblock, errbuf }; + struct setnonblock_params params; + TRACE( "%p, %d, %p\n", pcap, nonblock, errbuf ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + params.nonblock = nonblock; + params.errbuf = errbuf; return PCAP_CALL( setnonblock, ¶ms ); }
int CDECL pcap_snapshot( struct pcap *pcap ) { + struct snapshot_params params; + TRACE( "%p\n", pcap ); - return PCAP_CALL( snapshot, pcap ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + return PCAP_CALL( snapshot, ¶ms ); }
-int CDECL pcap_stats( struct pcap *pcap, void *stats ) +int CDECL pcap_stats( struct pcap *pcap, struct pcap_stat_win32 *stat ) { - struct stats_params params = { pcap, stats }; - TRACE( "%p, %p\n", pcap, stats ); - return PCAP_CALL( stats, ¶ms ); + struct stats_params params; + int ret; + + TRACE( "%p, %p\n", pcap, stat ); + + if (!pcap) return PCAP_ERROR; + params.handle = pcap->handle; + if (!(ret = PCAP_CALL( stats, ¶ms ))) *stat = params.stat; + return ret; }
const char * CDECL pcap_statustostr( int status ) { - const char *ret; - struct statustostr_params params = { status, &ret }; + static char errbuf[32]; + TRACE( "%d\n", status ); - PCAP_CALL( statustostr, ¶ms ); - return ret; + + switch (status) + { + case PCAP_WARNING: + return "Generic warning"; + case PCAP_WARNING_TSTAMP_TYPE_NOTSUP: + return "That type of time stamp is not supported by that device"; + case PCAP_WARNING_PROMISC_NOTSUP: + return "That device doesn't support promiscuous mode"; + case PCAP_ERROR: + return "Generic error"; + case PCAP_ERROR_BREAK: + return "Loop terminated by pcap_breakloop"; + case PCAP_ERROR_NOT_ACTIVATED: + return "The pcap_t has not been activated"; + case PCAP_ERROR_ACTIVATED: + return "The setting can't be changed after the pcap_t is activated"; + case PCAP_ERROR_NO_SUCH_DEVICE: + return "No such device exists"; + default: + sprintf( errbuf, "Unknown error: %d", status ); + return errbuf; + } }
int CDECL pcap_tstamp_type_name_to_val( const char *name ) @@ -847,29 +1278,101 @@ int CDECL pcap_tstamp_type_name_to_val( const char *name ) return PCAP_CALL( tstamp_type_name_to_val, ¶ms ); }
-const char * CDECL pcap_tstamp_type_val_to_description( int val ) +static struct { - const char *ret; - struct tstamp_type_val_to_description_params params = { val, &ret }; - TRACE( "%d\n", val ); - PCAP_CALL( tstamp_type_val_to_description, ¶ms ); - return ret; + char *name; + char *description; +} tstamp_types[16]; + +static void free_tstamp_types( void ) +{ + unsigned int i; + for (i = 0; i < ARRAY_SIZE(tstamp_types); i++) + { + free( tstamp_types[i].name ); + tstamp_types[i].name = NULL; + free( tstamp_types[i].description ); + tstamp_types[i].description = NULL; + } }
-const char * CDECL pcap_tstamp_type_val_to_name( int val ) +const char * CDECL pcap_tstamp_type_val_to_description( int type ) { - const char *ret; - struct tstamp_type_val_to_name_params params = { val, &ret }; - TRACE( "%d\n", val ); - PCAP_CALL( tstamp_type_val_to_name, ¶ms ); - return ret; + struct tstamp_type_val_to_description_params params; + unsigned int len = 64; + char *tmp; + NTSTATUS status; + + TRACE( "%d\n", type ); + + if (type < 0 || type >= ARRAY_SIZE(tstamp_types)) + { + WARN( "unhandled tstamp type %d\n", type ); + return NULL; + } + if (tstamp_types[type].description) return tstamp_types[type].description; + + if (!(params.buf = malloc( len ))) return NULL; + params.type = type; + params.buflen = &len; + status = PCAP_CALL( tstamp_type_val_to_description, ¶ms ); + if (status == STATUS_SUCCESS) return (tstamp_types[type].description = params.buf); + if (status != STATUS_BUFFER_TOO_SMALL || !(tmp = realloc( params.buf, len ))) + { + free( params.buf ); + return NULL; + } + params.buf = tmp; + if (PCAP_CALL( tstamp_type_val_to_description, ¶ms )) + { + free( params.buf ); + return NULL; + } + + return (tstamp_types[type].description = params.buf); +} + +const char * CDECL pcap_tstamp_type_val_to_name( int type ) +{ + struct tstamp_type_val_to_name_params params; + unsigned int len = 32; + char *tmp; + NTSTATUS status; + + TRACE( "%d\n", type ); + + if (type < 0 || type >= ARRAY_SIZE(tstamp_types)) + { + WARN( "unhandled tstamp type %d\n", type ); + return NULL; + } + if (tstamp_types[type].name) return tstamp_types[type].name; + + if (!(params.buf = malloc( len ))) return NULL; + params.type = type; + params.buflen = &len; + status = PCAP_CALL( tstamp_type_val_to_name, ¶ms ); + if (status == STATUS_SUCCESS) return (tstamp_types[type].name = params.buf); + if (status != STATUS_BUFFER_TOO_SMALL || !(tmp = realloc( params.buf, len ))) + { + free( params.buf ); + return NULL; + } + params.buf = tmp; + if (PCAP_CALL( tstamp_type_val_to_name, ¶ms )) + { + free( params.buf ); + return NULL; + } + + return (tstamp_types[type].name = params.buf); }
int CDECL pcap_wsockinit( void ) { WSADATA wsadata; TRACE( "\n" ); - if (WSAStartup( MAKEWORD(1, 1), &wsadata )) return -1; + if (WSAStartup( MAKEWORD(1, 1), &wsadata )) return PCAP_ERROR; return 0; }
@@ -883,6 +1386,9 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved ) ERR( "No pcap support, expect problems\n" ); break; case DLL_PROCESS_DETACH: + if (reserved) break; + free_datalinks(); + free_tstamp_types(); break; } return TRUE;
From: Hans Leidekker hans@codeweavers.com
--- dlls/wpcap/wpcap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/wpcap/wpcap.c b/dlls/wpcap/wpcap.c index 5494ed292e1..5c25e4a2708 100644 --- a/dlls/wpcap/wpcap.c +++ b/dlls/wpcap/wpcap.c @@ -444,7 +444,7 @@ static struct sockaddr *get_address( const IP_ADAPTER_UNICAST_ADDRESS *addr ) static void convert_length_to_ipv6_mask( ULONG length, IN6_ADDR *mask ) { unsigned int i; - for (i = 0; i < length / 8; i++) mask->u.Byte[i] = 0xff; + for (i = 0; i < length / 8 - 1; i++) mask->u.Byte[i] = 0xff; mask->u.Byte[i] = 0xff << (8 - length % 8); }
From: Hans Leidekker hans@codeweavers.com
--- dlls/wpcap/unixlib.c | 7 +++++++ dlls/wpcap/unixlib.h | 6 ++++++ dlls/wpcap/wpcap.c | 11 +++++++++++ dlls/wpcap/wpcap.spec | 2 +- 4 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/dlls/wpcap/unixlib.c b/dlls/wpcap/unixlib.c index c65a13a1c15..ed753c0d6fd 100644 --- a/dlls/wpcap/unixlib.c +++ b/dlls/wpcap/unixlib.c @@ -55,6 +55,12 @@ static NTSTATUS wrap_breakloop( void *args ) return STATUS_SUCCESS; }
+static NTSTATUS wrap_bufsize( void *args ) +{ + const struct bufsize_params *params = args; + return pcap_bufsize( (pcap_t *)(ULONG_PTR)params->handle ); +} + static NTSTATUS wrap_can_set_rfmon( void *args ) { const struct can_set_rfmon_params *params = args; @@ -436,6 +442,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { wrap_activate, wrap_breakloop, + wrap_bufsize, wrap_can_set_rfmon, wrap_close, wrap_compile, diff --git a/dlls/wpcap/unixlib.h b/dlls/wpcap/unixlib.h index 403158af978..740be3ad12e 100644 --- a/dlls/wpcap/unixlib.h +++ b/dlls/wpcap/unixlib.h @@ -75,6 +75,11 @@ struct breakloop_params UINT64 handle; };
+struct bufsize_params +{ + UINT64 handle; +}; + struct can_set_rfmon_params { UINT64 handle; @@ -322,6 +327,7 @@ enum pcap_funcs { unix_activate, unix_breakloop, + unix_bufsize, unix_can_set_rfmon, unix_close, unix_compile, diff --git a/dlls/wpcap/wpcap.c b/dlls/wpcap/wpcap.c index 5c25e4a2708..f3b203f983d 100644 --- a/dlls/wpcap/wpcap.c +++ b/dlls/wpcap/wpcap.c @@ -108,6 +108,17 @@ void CDECL pcap_breakloop( struct pcap *pcap ) PCAP_CALL( breakloop, ¶ms ); }
+int CDECL pcap_bufsize( struct pcap *pcap ) +{ + struct bufsize_params params; + + TRACE( "%p\n", pcap ); + + if (!pcap) return 0; + params.handle = pcap->handle; + return PCAP_CALL( bufsize, ¶ms ); +} + int CDECL pcap_can_set_rfmon( struct pcap *pcap ) { struct can_set_rfmon_params params; diff --git a/dlls/wpcap/wpcap.spec b/dlls/wpcap/wpcap.spec index 5c26ad0c24e..7a59dda3caf 100644 --- a/dlls/wpcap/wpcap.spec +++ b/dlls/wpcap/wpcap.spec @@ -4,7 +4,7 @@ @ stub bpf_validate @ stub eproto_db @ cdecl pcap_activate(ptr) -@ stub pcap_bufsize +@ cdecl pcap_bufsize(ptr) @ cdecl pcap_breakloop(ptr) @ cdecl pcap_can_set_rfmon(ptr) @ cdecl pcap_close(ptr)
From: Hans Leidekker hans@codeweavers.com
--- dlls/wpcap/unixlib.c | 8 ++++++++ dlls/wpcap/unixlib.h | 6 ++++++ dlls/wpcap/wpcap.c | 12 ++++++++++++ dlls/wpcap/wpcap.spec | 2 +- 4 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/dlls/wpcap/unixlib.c b/dlls/wpcap/unixlib.c index ed753c0d6fd..49232c4c444 100644 --- a/dlls/wpcap/unixlib.c +++ b/dlls/wpcap/unixlib.c @@ -155,6 +155,13 @@ static NTSTATUS wrap_dump( void *args ) return STATUS_SUCCESS; }
+static NTSTATUS wrap_dump_close( void *args ) +{ + const struct dump_close_params *params = args; + pcap_dump_close( (pcap_dumper_t *)(ULONG_PTR)params->handle ); + return STATUS_SUCCESS; +} + static NTSTATUS wrap_dump_open( void *args ) { const struct dump_open_params *params = args; @@ -452,6 +459,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = wrap_datalink_val_to_description, wrap_datalink_val_to_name, wrap_dump, + wrap_dump_close, wrap_dump_open, wrap_findalldevs, wrap_get_tstamp_precision, diff --git a/dlls/wpcap/unixlib.h b/dlls/wpcap/unixlib.h index 740be3ad12e..3adb8f1f61d 100644 --- a/dlls/wpcap/unixlib.h +++ b/dlls/wpcap/unixlib.h @@ -138,6 +138,11 @@ struct dump_params const unsigned char *packet; };
+struct dump_close_params +{ + UINT64 handle; +}; + struct dump_open_params { UINT64 handle; @@ -337,6 +342,7 @@ enum pcap_funcs unix_datalink_val_to_description, unix_datalink_val_to_name, unix_dump, + unix_dump_close, unix_dump_open, unix_findalldevs, unix_get_tstamp_precision, diff --git a/dlls/wpcap/wpcap.c b/dlls/wpcap/wpcap.c index f3b203f983d..afb47a58a90 100644 --- a/dlls/wpcap/wpcap.c +++ b/dlls/wpcap/wpcap.c @@ -301,6 +301,18 @@ struct dumper UINT64 handle; };
+void CDECL pcap_dump_close( struct dumper *dumper ) +{ + struct dump_close_params params; + + TRACE( "%p\n", dumper ); + + if (!dumper) return; + params.handle = dumper->handle; + PCAP_CALL( dump, ¶ms ); + free( dumper ); +} + static inline WCHAR *strdup_from_utf8( const char *str ) { WCHAR *ret = NULL; diff --git a/dlls/wpcap/wpcap.spec b/dlls/wpcap/wpcap.spec index 7a59dda3caf..b3685d098fe 100644 --- a/dlls/wpcap/wpcap.spec +++ b/dlls/wpcap/wpcap.spec @@ -20,7 +20,7 @@ @ cdecl pcap_datalink_val_to_name(long) @ cdecl pcap_dispatch(ptr long ptr ptr) @ cdecl pcap_dump(ptr ptr str) -@ stub pcap_dump_close +@ cdecl pcap_dump_close(ptr) @ stub pcap_dump_file @ stub pcap_dump_flush @ stub pcap_dump_ftell
From: Hans Leidekker hans@codeweavers.com
--- dlls/wpcap/unixlib.c | 7 +++++++ dlls/wpcap/unixlib.h | 7 +++++++ dlls/wpcap/wpcap.c | 14 ++++++++++++++ dlls/wpcap/wpcap.spec | 2 +- 4 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/dlls/wpcap/unixlib.c b/dlls/wpcap/unixlib.c index 49232c4c444..4ef301c8bbe 100644 --- a/dlls/wpcap/unixlib.c +++ b/dlls/wpcap/unixlib.c @@ -230,6 +230,12 @@ static NTSTATUS wrap_getnonblock( void *args ) return pcap_getnonblock( (pcap_t *)(ULONG_PTR)params->handle, params->errbuf ); }
+static NTSTATUS wrap_init( void *args ) +{ + const struct init_params *params = args; + return pcap_init( params->opt, params->errbuf ); +} + static NTSTATUS wrap_lib_version( void *args ) { const struct lib_version_params *params = args; @@ -465,6 +471,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = wrap_get_tstamp_precision, wrap_geterr, wrap_getnonblock, + wrap_init, wrap_lib_version, wrap_list_datalinks, wrap_list_tstamp_types, diff --git a/dlls/wpcap/unixlib.h b/dlls/wpcap/unixlib.h index 3adb8f1f61d..668658089f3 100644 --- a/dlls/wpcap/unixlib.h +++ b/dlls/wpcap/unixlib.h @@ -174,6 +174,12 @@ struct get_tstamp_precision_params UINT64 handle; };
+struct init_params +{ + int opt; + char *errbuf; +}; + struct lib_version_params { char *version; @@ -348,6 +354,7 @@ enum pcap_funcs unix_get_tstamp_precision, unix_geterr, unix_getnonblock, + unix_init, unix_lib_version, unix_list_datalinks, unix_list_tstamp_types, diff --git a/dlls/wpcap/wpcap.c b/dlls/wpcap/wpcap.c index afb47a58a90..d1c05ed0c01 100644 --- a/dlls/wpcap/wpcap.c +++ b/dlls/wpcap/wpcap.c @@ -1399,6 +1399,20 @@ int CDECL pcap_wsockinit( void ) return 0; }
+#define PCAP_CHAR_ENC_LOCAL 0 + +int CDECL pcap_init( unsigned int opt, char *errbuf ) +{ + struct init_params params; + + TRACE( "%u, %p\n", opt, errbuf ); + if (opt == PCAP_CHAR_ENC_LOCAL) FIXME( "need to convert to/from local encoding\n" ); + + params.opt = opt; + params.errbuf = errbuf; + return PCAP_CALL( init, ¶ms ); +} + BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved ) { switch (reason) diff --git a/dlls/wpcap/wpcap.spec b/dlls/wpcap/wpcap.spec index b3685d098fe..ec2e17dc16e 100644 --- a/dlls/wpcap/wpcap.spec +++ b/dlls/wpcap/wpcap.spec @@ -45,7 +45,7 @@ @ cdecl pcap_getnonblock(ptr ptr) @ stub pcap_hopen_offline @ stub pcap_hopen_offline_with_tstamp_precision -@ stub pcap_init +@ cdecl pcap_init(long ptr) @ stub pcap_inject @ stub pcap_is_swapped @ cdecl pcap_lib_version()
From: Hans Leidekker hans@codeweavers.com
--- dlls/wpcap/wpcap.c | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-)
diff --git a/dlls/wpcap/wpcap.c b/dlls/wpcap/wpcap.c index d1c05ed0c01..2a3be168fdf 100644 --- a/dlls/wpcap/wpcap.c +++ b/dlls/wpcap/wpcap.c @@ -909,15 +909,6 @@ int CDECL pcap_lookupnet( const char *device, unsigned int *net, unsigned int *m return ret; }
-int CDECL pcap_loop( struct pcap *pcap, int count, - void (CALLBACK *callback)(unsigned char *, const struct pcap_pkthdr_win32 *, const unsigned char *), - unsigned char *user) -{ - /* FIXME: reimplement on top of pcap_next_ex */ - FIXME( "%p, %d, %p, %p: not implemented\n", pcap, count, callback, user ); - return -1; -} - int CDECL pcap_major_version( struct pcap *pcap ) { struct major_version_params params; @@ -1001,6 +992,39 @@ int CDECL pcap_dispatch( struct pcap *pcap, int count, return processed; }
+int CDECL pcap_loop( struct pcap *pcap, int count, + void (CALLBACK *callback)(unsigned char *, const struct pcap_pkthdr_win32 *, const unsigned char *), + unsigned char *user) +{ + int processed = 0; + + TRACE( "%p, %d, %p, %p\n", pcap, count, callback, user ); + + while (processed < count) + { + struct pcap_pkthdr_win32 *hdr = NULL; + const unsigned char *data = NULL; + + int ret = pcap_next_ex( pcap, &hdr, &data ); + + if (ret == 1) + processed++; + else if (ret == 0) + continue; + else if (ret == PCAP_ERROR_BREAK) + { + if (processed == 0) return PCAP_ERROR_BREAK; + break; + } + else + return ret; + + callback( user, hdr, data ); + } + + return processed; +} + struct pcap * CDECL pcap_create( const char *source, char *errbuf ) { struct pcap *ret;
From: Hans Leidekker hans@codeweavers.com
--- dlls/wpcap/wpcap.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/dlls/wpcap/wpcap.c b/dlls/wpcap/wpcap.c index 2a3be168fdf..39a65885723 100644 --- a/dlls/wpcap/wpcap.c +++ b/dlls/wpcap/wpcap.c @@ -1424,6 +1424,7 @@ int CDECL pcap_wsockinit( void ) }
#define PCAP_CHAR_ENC_LOCAL 0 +#define PCAP_CHAR_ENC_UTF_8 1
int CDECL pcap_init( unsigned int opt, char *errbuf ) { @@ -1442,10 +1443,19 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved ) switch (reason) { case DLL_PROCESS_ATTACH: + { DisableThreadLibraryCalls( hinst ); - if (__wine_init_unix_call()) - ERR( "No pcap support, expect problems\n" ); + if (__wine_init_unix_call()) ERR( "No pcap support, expect problems\n" ); + else + { + char errbuf[PCAP_ERRBUF_SIZE]; + struct init_params params = { PCAP_CHAR_ENC_UTF_8, errbuf }; + + if (PCAP_CALL( init, ¶ms ) == PCAP_ERROR) + WARN( "failed to enable UTF-8 encoding %s\n", debugstr_a(errbuf) ); + } break; + } case DLL_PROCESS_DETACH: if (reserved) break; free_datalinks();
From: Hans Leidekker hans@codeweavers.com
--- dlls/wpcap/unixlib.c | 465 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+)
diff --git a/dlls/wpcap/unixlib.c b/dlls/wpcap/unixlib.c index 4ef301c8bbe..55069fac79e 100644 --- a/dlls/wpcap/unixlib.c +++ b/dlls/wpcap/unixlib.c @@ -498,4 +498,469 @@ const unixlib_entry_t __wine_unix_call_funcs[] = wrap_tstamp_type_val_to_name, };
+#ifdef _WIN64 + +typedef ULONG PTR32; + +static NTSTATUS wow64_compile( void *args ) +{ + struct + { + UINT64 handle; + PTR32 program_len; + PTR32 program_insns; + PTR32 str; + int optimize; + unsigned int mask; + } const *params32 = args; + + struct compile_params params = + { + params32->handle, + ULongToPtr(params32->program_len), + ULongToPtr(params32->program_insns), + ULongToPtr(params32->str), + params32->optimize, + params32->mask + }; + return wrap_compile( ¶ms ); +} + +static NTSTATUS wow64_create( void *args ) +{ + struct + { + PTR32 source; + PTR32 errbuf; + PTR32 handle; + } const *params32 = args; + + struct create_params params = + { + ULongToPtr(params32->source), + ULongToPtr(params32->errbuf), + ULongToPtr(params32->handle), + }; + return wrap_create( ¶ms ); +} + +static NTSTATUS wow64_datalink_name_to_val( void *args ) +{ + struct + { + PTR32 name; + } const *params32 = args; + + struct datalink_name_to_val_params params = + { + ULongToPtr(params32->name), + }; + return wrap_datalink_name_to_val( ¶ms ); +} + +static NTSTATUS wow64_datalink_val_to_description( void *args ) +{ + struct + { + int link; + PTR32 buf; + PTR32 buflen; + } const *params32 = args; + + struct datalink_val_to_description_params params = + { + params32->link, + ULongToPtr(params32->buf), + ULongToPtr(params32->buflen) + }; + return wrap_datalink_val_to_description( ¶ms ); +} + +static NTSTATUS wow64_datalink_val_to_name( void *args ) +{ + struct + { + int link; + PTR32 buf; + PTR32 buflen; + } const *params32 = args; + + struct datalink_val_to_name_params params = + { + params32->link, + ULongToPtr(params32->buf), + ULongToPtr(params32->buflen) + }; + return wrap_datalink_val_to_name( ¶ms ); +} + +static NTSTATUS wow64_dump( void *args ) +{ + struct + { + PTR32 user; + PTR32 hdr; + PTR32 packet; + } const *params32 = args; + + struct dump_params params = + { + ULongToPtr(params32->user), + ULongToPtr(params32->hdr), + ULongToPtr(params32->packet) + }; + return wrap_dump( ¶ms ); +} + +static NTSTATUS wow64_dump_open( void *args ) +{ + struct + { + UINT64 handle; + PTR32 name; + PTR32 ret_handle; + } const *params32 = args; + + struct datalink_val_to_name_params params = + { + params32->handle, + ULongToPtr(params32->name), + ULongToPtr(params32->ret_handle) + }; + return wrap_dump_open( ¶ms ); +} + +static NTSTATUS wow64_findalldevs( void *args ) +{ + struct + { + PTR32 buf; + PTR32 buflen; + PTR32 errbuf; + } const *params32 = args; + + struct findalldevs_params params = + { + ULongToPtr(params32->buf), + ULongToPtr(params32->buflen), + ULongToPtr(params32->errbuf) + }; + return wrap_findalldevs( ¶ms ); +} + +static NTSTATUS wow64_geterr( void *args ) +{ + struct + { + UINT64 handle; + PTR32 errbuf; + } const *params32 = args; + + struct geterr_params params = + { + params32->handle, + ULongToPtr(params32->errbuf) + }; + return wrap_geterr( ¶ms ); +} + +static NTSTATUS wow64_getnonblock( void *args ) +{ + struct + { + UINT64 handle; + PTR32 errbuf; + } const *params32 = args; + + struct getnonblock_params params = + { + params32->handle, + ULongToPtr(params32->errbuf) + }; + return wrap_getnonblock( ¶ms ); +} + +static NTSTATUS wow64_init( void *args ) +{ + struct + { + int opt; + PTR32 errbuf; + } const *params32 = args; + + struct init_params params = + { + params32->opt, + ULongToPtr(params32->errbuf) + }; + return wrap_init( ¶ms ); +} + +static NTSTATUS wow64_lib_version( void *args ) +{ + struct + { + PTR32 version; + unsigned int size; + } const *params32 = args; + + struct lib_version_params params = + { + ULongToPtr(params32->version), + params32->size + }; + return wrap_lib_version( ¶ms ); +} + +static NTSTATUS wow64_list_datalinks( void *args ) +{ + struct + { + UINT64 handle; + PTR32 links; + PTR32 count; + } const *params32 = args; + + struct list_datalinks_params params = + { + params32->handle, + ULongToPtr(params32->links), + ULongToPtr(params32->count) + }; + return wrap_list_datalinks( ¶ms ); +} + +static NTSTATUS wow64_list_tstamp_types( void *args ) +{ + struct + { + UINT64 handle; + PTR32 types; + PTR32 count; + } const *params32 = args; + + struct list_tstamp_types_params params = + { + params32->handle, + ULongToPtr(params32->types), + ULongToPtr(params32->count) + }; + return wrap_list_tstamp_types( ¶ms ); +} + +static NTSTATUS wow64_lookupnet( void *args ) +{ + struct + { + PTR32 device; + PTR32 net; + PTR32 mask; + PTR32 errbuf; + } const *params32 = args; + + struct lookupnet_params params = + { + ULongToPtr(params32->device), + ULongToPtr(params32->net), + ULongToPtr(params32->mask), + ULongToPtr(params32->errbuf) + }; + return wrap_lookupnet( ¶ms ); +} + +static NTSTATUS wow64_next_ex( void *args ) +{ + struct + { + UINT64 handle; + PTR32 hdr; + PTR32 data; + } const *params32 = args; + + struct next_ex_params params = + { + params32->handle, + ULongToPtr(params32->hdr), + ULongToPtr(params32->data) + }; + return wrap_next_ex( ¶ms ); +} + +static NTSTATUS wow64_open_live( void *args ) +{ + struct + { + PTR32 source; + int snaplen; + int promisc; + int timeout; + PTR32 errbuf; + PTR32 handle; + } const *params32 = args; + + struct open_live_params params = + { + ULongToPtr(params32->source), + params32->snaplen, + params32->promisc, + params32->timeout, + ULongToPtr(params32->errbuf), + ULongToPtr(params32->handle) + }; + return wrap_open_live( ¶ms ); +} + +static NTSTATUS wow64_sendpacket( void *args ) +{ + struct + { + UINT64 handle; + PTR32 buf; + int size; + } const *params32 = args; + + struct sendpacket_params params = + { + params32->handle, + ULongToPtr(params32->buf), + params32->size + }; + return wrap_sendpacket( ¶ms ); +} + +static NTSTATUS wow64_setfilter( void *args ) +{ + struct + { + UINT64 handle; + unsigned int program_len; + PTR32 program_insns; + } const *params32 = args; + + struct setfilter_params params = + { + params32->handle, + params32->program_len, + ULongToPtr(params32->program_insns) + }; + return wrap_setfilter( ¶ms ); +} + +static NTSTATUS wow64_setnonblock( void *args ) +{ + struct + { + UINT64 handle; + int nonblock; + PTR32 errbuf; + } const *params32 = args; + + struct setnonblock_params params = + { + params32->handle, + params32->nonblock, + ULongToPtr(params32->errbuf) + }; + return wrap_setnonblock( ¶ms ); +} + +static NTSTATUS wow64_tstamp_type_name_to_val( void *args ) +{ + struct + { + PTR32 name; + } const *params32 = args; + + struct tstamp_type_name_to_val_params params = + { + ULongToPtr(params32->name) + }; + return wrap_tstamp_type_name_to_val( ¶ms ); +} + +static NTSTATUS wow64_tstamp_type_val_to_description( void *args ) +{ + struct + { + int type; + PTR32 buf; + PTR32 buflen; + } const *params32 = args; + + struct tstamp_type_val_to_description_params params = + { + params32->type, + ULongToPtr(params32->buf), + ULongToPtr(params32->buflen) + }; + return wrap_tstamp_type_val_to_description( ¶ms ); +} + +static NTSTATUS wow64_tstamp_type_val_to_name( void *args ) +{ + struct + { + int type; + PTR32 buf; + PTR32 buflen; + } const *params32 = args; + + struct tstamp_type_val_to_name_params params = + { + params32->type, + ULongToPtr(params32->buf), + ULongToPtr(params32->buflen) + }; + return wrap_tstamp_type_val_to_name( ¶ms ); +} + +const unixlib_entry_t __wine_unix_call_wow64_funcs[] = +{ + wrap_activate, + wrap_breakloop, + wrap_bufsize, + wrap_can_set_rfmon, + wrap_close, + wow64_compile, + wow64_create, + wrap_datalink, + wow64_datalink_name_to_val, + wow64_datalink_val_to_description, + wow64_datalink_val_to_name, + wow64_dump, + wrap_dump_close, + wow64_dump_open, + wow64_findalldevs, + wrap_get_tstamp_precision, + wow64_geterr, + wow64_getnonblock, + wow64_init, + wow64_lib_version, + wow64_list_datalinks, + wow64_list_tstamp_types, + wow64_lookupnet, + wrap_major_version, + wrap_minor_version, + wow64_next_ex, + wow64_open_live, + wow64_sendpacket, + wrap_set_buffer_size, + wrap_set_datalink, + wrap_set_promisc, + wrap_set_rfmon, + wrap_set_snaplen, + wrap_set_timeout, + wrap_set_tstamp_precision, + wrap_set_tstamp_type, + wow64_setfilter, + wow64_setnonblock, + wrap_snapshot, + wrap_stats, + wow64_tstamp_type_name_to_val, + wow64_tstamp_type_val_to_description, + wow64_tstamp_type_val_to_name, +}; + +#endif /* _WIN64 */ + #endif /* HAVE_PCAP_PCAP_H */
From: Hans Leidekker hans@codeweavers.com
This feature will be available in version 1.11. --- dlls/wpcap/wpcap.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/dlls/wpcap/wpcap.c b/dlls/wpcap/wpcap.c index 39a65885723..8c304ce66a4 100644 --- a/dlls/wpcap/wpcap.c +++ b/dlls/wpcap/wpcap.c @@ -1425,6 +1425,7 @@ int CDECL pcap_wsockinit( void )
#define PCAP_CHAR_ENC_LOCAL 0 #define PCAP_CHAR_ENC_UTF_8 1 +#define PCAP_MMAP_32BIT 2
int CDECL pcap_init( unsigned int opt, char *errbuf ) { @@ -1450,9 +1451,16 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved ) { char errbuf[PCAP_ERRBUF_SIZE]; struct init_params params = { PCAP_CHAR_ENC_UTF_8, errbuf }; + BOOL is_wow64;
if (PCAP_CALL( init, ¶ms ) == PCAP_ERROR) WARN( "failed to enable UTF-8 encoding %s\n", debugstr_a(errbuf) ); + if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64) + { + params.opt = PCAP_MMAP_32BIT; + if (PCAP_CALL( init, ¶ms ) == PCAP_ERROR) + WARN( "failed to enable 32-bit mmap() %s\n", debugstr_a(errbuf) ); + } } break; }
From: Hans Leidekker hans@codeweavers.com
--- configure.ac | 1 + dlls/wpcap/tests/Makefile.in | 4 + dlls/wpcap/tests/wpcap.c | 374 +++++++++++++++++++++++++++++++++++ 3 files changed, 379 insertions(+) create mode 100644 dlls/wpcap/tests/Makefile.in create mode 100644 dlls/wpcap/tests/wpcap.c
diff --git a/configure.ac b/configure.ac index 3d996c34fae..84fadd08853 100644 --- a/configure.ac +++ b/configure.ac @@ -3201,6 +3201,7 @@ WINE_CONFIG_MAKEFILE(dlls/wow64win) WINE_CONFIG_MAKEFILE(dlls/wpc) WINE_CONFIG_MAKEFILE(dlls/wpc/tests) WINE_CONFIG_MAKEFILE(dlls/wpcap) +WINE_CONFIG_MAKEFILE(dlls/wpcap/tests) WINE_CONFIG_MAKEFILE(dlls/ws2_32) WINE_CONFIG_MAKEFILE(dlls/ws2_32/tests) WINE_CONFIG_MAKEFILE(dlls/wsdapi) diff --git a/dlls/wpcap/tests/Makefile.in b/dlls/wpcap/tests/Makefile.in new file mode 100644 index 00000000000..c2f8fce6da8 --- /dev/null +++ b/dlls/wpcap/tests/Makefile.in @@ -0,0 +1,4 @@ +TESTDLL = wpcap.dll + +C_SRCS = \ + wpcap.c diff --git a/dlls/wpcap/tests/wpcap.c b/dlls/wpcap/tests/wpcap.c new file mode 100644 index 00000000000..017d3b77a4e --- /dev/null +++ b/dlls/wpcap/tests/wpcap.c @@ -0,0 +1,374 @@ +/* + * Unit test for wpcap functions + * + * Copyright 2022 Hans Leidekker for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdio.h> +#include <ntstatus.h> +#define WIN32_NO_STATUS +#include <windows.h> + +#include "wine/test.h" + +#define PCAP_MMAP_32BIT 2 +#define PCAP_ERRBUF_SIZE 256 +#define PCAP_ERROR_PERM_DENIED -8 + +typedef struct pcap pcap_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_dumper pcap_dumper_t; + +struct pcap_if +{ + struct pcap_if *next; + char *name; +}; + +struct pcap_stat +{ + unsigned int ps_recv; + unsigned int ps_drop; + unsigned int ps_ifdrop; + unsigned int ps_capt; + unsigned int ps_sent; + unsigned int ps_netdrop; +}; + +struct bpf_insn +{ + unsigned short code; + unsigned char jt; + unsigned char jf; + unsigned int k; +}; + +struct bpf_program +{ + unsigned int bf_len; + struct bpf_insn *bf_insns; +}; + +struct pcap_pkthdr +{ + struct + { + int tv_sec; + int tv_usec; + } ts; + unsigned int caplen; + unsigned int len; +}; + +static int (CDECL *ppcap_activate)( pcap_t * ); +static void (CDECL *ppcap_breakloop)( pcap_t * ); +static int (CDECL *ppcap_bufsize)( pcap_t * ); +static int (CDECL *ppcap_can_set_rfmon)( pcap_t * ); +static void (CDECL *ppcap_close)( pcap_t * ); +static int (CDECL *ppcap_compile)( pcap_t *, struct bpf_program *, const char *, int, unsigned int ); +static pcap_t * (CDECL *ppcap_create)( const char *, char * ); +static int (CDECL *ppcap_datalink)( pcap_t * ); +static int (CDECL *ppcap_datalink_name_to_val)( const char * ); +static const char * (CDECL *ppcap_datalink_val_to_description)( int ); +static const char * (CDECL *ppcap_datalink_val_to_name)( int ); +static int (CDECL *ppcap_dispatch)( pcap_t *, int, + void (CALLBACK *)(unsigned char *, const struct pcap_pkthdr *, const unsigned char *), + unsigned char * ); +static pcap_dumper_t * (CDECL *ppcap_dump_open)( pcap_t *, const char * ); +static void (CDECL *ppcap_dump)( unsigned char *, const struct pcap_pkthdr *, const unsigned char * ); +static void (CDECL *ppcap_dump_close)( pcap_dumper_t * ); +static int (CDECL *ppcap_findalldevs)( pcap_if_t **, char * ); +static void (CDECL *ppcap_freealldevs)( pcap_if_t * ); +static void (CDECL *ppcap_free_datalinks)( int * ); +static void (CDECL *ppcap_free_tstamp_types)( int * ); +static void (CDECL *ppcap_freecode)( struct bpf_program * ); +static void * (CDECL *ppcap_get_airpcap_handle)( pcap_t * ); +static int (CDECL *ppcap_get_tstamp_precision)( pcap_t * ); +static char * (CDECL *ppcap_geterr)( pcap_t * ); +static int (CDECL *ppcap_getnonblock)( pcap_t *, char * ); +static int (CDECL *ppcap_init)( unsigned int, char * ); +static const char * (CDECL *ppcap_lib_version)( void ); +static int (CDECL *ppcap_list_datalinks)( pcap_t *, int ** ); +static int (CDECL *ppcap_list_tstamp_types)( pcap_t *, int ** ); +static char * (CDECL *ppcap_lookupdev)( char * ); +static int (CDECL *ppcap_lookupnet)( const char *, unsigned int *, unsigned int *, char * ); +static int (CDECL *ppcap_loop)( pcap_t *, int, + void (CALLBACK *)(unsigned char *, const struct pcap_pkthdr *, const unsigned char *), + unsigned char * ); +static int (CDECL *ppcap_set_buffer_size)( pcap_t *, int ); +static int (CDECL *ppcap_set_datalink)( pcap_t *, int ); +static int (CDECL *ppcap_set_promisc)( pcap_t *, int ); +static int (CDECL *ppcap_set_timeout)( pcap_t *, int ); +static int (CDECL *ppcap_set_tstamp_precision)( pcap_t *, int ); +static int (CDECL *ppcap_setfilter)( pcap_t *, struct bpf_program * ); +static int (CDECL *ppcap_snapshot)( pcap_t * ); +static int (CDECL *ppcap_stats)( pcap_t *, struct pcap_stat * ); +static int CDECL (*ppcap_tstamp_type_name_to_val)( const char * ); +static const char * (CDECL *ppcap_tstamp_type_val_to_description)( int ); +static const char * (CDECL *ppcap_tstamp_type_val_to_name)( int ); + +static void CALLBACK capture_callback( unsigned char *user, const struct pcap_pkthdr *hdr, const unsigned char *bytes ) +{ + trace( "user %p hdr %p byte %p\n", user, hdr, bytes ); +} + +static void test_capture( void ) +{ + char errbuf[PCAP_ERRBUF_SIZE], *dev, *err; + pcap_t *pcap; + void *aircap; + struct pcap_stat stats; + unsigned int net, mask; + struct bpf_program program; + int ret, *links, *types; + + dev = ppcap_lookupdev( errbuf ); + ok( dev != NULL, "got NULL (%s)\n", errbuf ); + + pcap = ppcap_create( dev, errbuf ); + ok( pcap != NULL, "got NULL (%s)\n", errbuf ); + + ret = ppcap_set_promisc( pcap, 1 ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_set_timeout( pcap, 100 ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_set_tstamp_precision( pcap, 0 ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_can_set_rfmon( pcap ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_getnonblock( pcap, errbuf ); + ok( ret == -3, "got %d\n", ret ); + + ret = ppcap_datalink( pcap ); + ok( ret == -3, "got %d\n", ret ); + + err = ppcap_geterr( pcap ); + ok( err != NULL, "got NULL\n" ); + + ret = ppcap_set_buffer_size( pcap, 2097152 ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_activate( pcap ); + if (ret == PCAP_ERROR_PERM_DENIED) + { + skip( "no permission\n" ); + ppcap_close( pcap ); + return; + } + ok( !ret, "got %d\n", ret ); + + ret = ppcap_set_buffer_size( pcap, 256000 ); + ok( ret == -4, "got %d\n", ret ); + + ret = ppcap_bufsize( pcap ); + ok( ret > 0, "got %d\n", ret ); + + ret = ppcap_getnonblock( pcap, errbuf ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_get_tstamp_precision( pcap ); + trace( "pcap_get_tstamp_precision %d\n", ret ); + + ret = ppcap_datalink( pcap ); + trace( "pcap_datalink %d\n", ret ); + + links = NULL; + ret = ppcap_list_datalinks( pcap, &links ); + ok( ret > 0, "got %d\n", ret ); + ok( links != NULL, "got NULL\n" ); + + ret = ppcap_set_datalink( pcap, links[0] ); + ok( !ret, "got %d\n", ret ); + ppcap_free_datalinks( links ); + + types = NULL; + ret = ppcap_list_tstamp_types( pcap, &types ); + ok( ret > 0, "got %d\n", ret ); + ok( types != NULL, "got NULL\n" ); + ppcap_free_tstamp_types( types ); + + net = mask = 0; + ret = ppcap_lookupnet( dev, &net, &mask, errbuf ); + ok( !ret, "got %d\n", ret ); + + memset( &program, 0, sizeof(program) ); + ret = ppcap_compile( pcap, &program, "", 1, 0xffffff ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_setfilter( pcap, &program ); + ok( !ret, "got %d\n", ret ); + ppcap_freecode( &program ); + + ret = ppcap_snapshot( pcap ); + ok( ret > 0, "got %d\n", ret ); + + ret = ppcap_dispatch( pcap, 1, capture_callback, NULL ); + ok( ret >= 0, "got %d\n", ret ); + + aircap = ppcap_get_airpcap_handle( pcap ); + ok( aircap == NULL, "got %p\n", aircap ); + + memset( &stats, 0, sizeof(stats) ); + ret = ppcap_stats( pcap, &stats ); + ok( !ret, "got %d\n", ret ); + ppcap_close( pcap ); +} + +static void test_datalink( void ) +{ + const char *str; + int ret; + + str = ppcap_datalink_val_to_name( 0 ); + ok( str != NULL, "got NULL\n" ); + ok( !strcmp(str, "NULL"), "got %s\n", wine_dbgstr_a(str) ); + + ret = ppcap_datalink_name_to_val( str ); + ok( !ret, "got %d\n", ret ); + + str = ppcap_datalink_val_to_description( 0 ); + ok( str != NULL, "got NULL\n" ); + ok( !strcmp(str, "BSD loopback"), "got %s\n", wine_dbgstr_a(str) ); + + str = ppcap_datalink_val_to_name( 1 ); + ok( str != NULL, "got NULL\n" ); + ok( !strcmp(str, "EN10MB"), "got %s\n", wine_dbgstr_a(str) ); + + ret = ppcap_datalink_name_to_val( str ); + ok( ret == 1, "got %d\n", ret ); + + str = ppcap_datalink_val_to_description( 1 ); + ok( str != NULL, "got NULL\n" ); + ok( !strcmp(str, "Ethernet"), "got %s\n", wine_dbgstr_a(str) ); +} + +static void CALLBACK dump_callback( unsigned char *user, const struct pcap_pkthdr *hdr, const unsigned char *bytes ) +{ + trace( "user %p hdr %p bytes %p\n", user, hdr, bytes ); + ppcap_dump( user, hdr, bytes ); +} + +static void test_dump( void ) +{ + char errbuf[PCAP_ERRBUF_SIZE], path[MAX_PATH], filename[MAX_PATH]; + pcap_t *pcap; + pcap_if_t *devs; + pcap_dumper_t *dumper; + int ret; + + devs = NULL; + ret = ppcap_findalldevs( &devs, errbuf ); + ok( !ret, "got %d (%s)\n", ret, errbuf ); + ok( devs != NULL, "got NULL\n" ); + + pcap = ppcap_create( devs->name, errbuf ); + ok( pcap != NULL, "got NULL (%s)\n", errbuf ); + + ret = ppcap_set_timeout( pcap, 100 ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_activate( pcap ); + if (ret == PCAP_ERROR_PERM_DENIED) + { + skip( "no permission\n" ); + ppcap_freealldevs( devs ); + ppcap_close( pcap ); + return; + } + ok( !ret, "got %d\n", ret ); + + ret = ppcap_bufsize( pcap ); + ok( ret > 0, "got %d\n", ret ); + + GetTempPathA( sizeof(path), path ); + GetTempFileNameA( path, "cap", 0, filename ); + + dumper = ppcap_dump_open( pcap, filename ); + ok( dumper != NULL, "got NULL\n" ); + + ret = ppcap_dispatch( pcap, 1, dump_callback, NULL ); + ok( ret >= 0, "got %d\n", ret ); + + ppcap_dump_close( dumper ); + ppcap_freealldevs( devs ); + ppcap_close( pcap ); + DeleteFileA( filename ); +} + +START_TEST( wpcap ) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + HMODULE module = LoadLibraryW( L"wpcap.dll" ); + if (!module) + { + win_skip( "wpcap.dll not found\n" ); + return; + } + ppcap_activate = (void *)GetProcAddress( module, "pcap_activate" ); + ppcap_breakloop = (void *)GetProcAddress( module, "pcap_breakloop" ); + ppcap_bufsize = (void *)GetProcAddress( module, "pcap_bufsize" ); + ppcap_can_set_rfmon = (void *)GetProcAddress( module, "pcap_can_set_rfmon" ); + ppcap_close = (void *)GetProcAddress( module, "pcap_close" ); + ppcap_compile = (void *)GetProcAddress( module, "pcap_compile" ); + ppcap_create = (void *)GetProcAddress( module, "pcap_create" ); + ppcap_datalink = (void *)GetProcAddress( module, "pcap_datalink" ); + ppcap_datalink_name_to_val = (void *)GetProcAddress( module, "pcap_datalink_name_to_val" ); + ppcap_datalink_val_to_description = (void *)GetProcAddress( module, "pcap_datalink_val_to_description" ); + ppcap_datalink_val_to_name = (void *)GetProcAddress( module, "pcap_datalink_val_to_name" ); + ppcap_dispatch = (void *)GetProcAddress( module, "pcap_dispatch" ); + ppcap_dump_open = (void *)GetProcAddress( module, "pcap_dump_open" ); + ppcap_dump = (void *)GetProcAddress( module, "pcap_dump" ); + ppcap_dump_close = (void *)GetProcAddress( module, "pcap_dump_close" ); + ppcap_get_airpcap_handle = (void *)GetProcAddress( module, "pcap_get_airpcap_handle" ); + ppcap_get_tstamp_precision = (void *)GetProcAddress( module, "pcap_get_tstamp_precision" ); + ppcap_geterr = (void *)GetProcAddress( module, "pcap_geterr" ); + ppcap_getnonblock = (void *)GetProcAddress( module, "pcap_getnonblock" ); + ppcap_findalldevs = (void *)GetProcAddress( module, "pcap_findalldevs" ); + ppcap_freealldevs = (void *)GetProcAddress( module, "pcap_freealldevs" ); + ppcap_free_datalinks = (void *)GetProcAddress( module, "pcap_free_datalinks" ); + ppcap_free_tstamp_types = (void *)GetProcAddress( module, "pcap_free_tstamp_types" ); + ppcap_freecode = (void *)GetProcAddress( module, "pcap_freecode" ); + ppcap_init = (void *)GetProcAddress( module, "pcap_init" ); + ppcap_lib_version = (void *)GetProcAddress( module, "pcap_lib_version" ); + ppcap_list_datalinks = (void *)GetProcAddress( module, "pcap_list_datalinks" ); + ppcap_list_tstamp_types = (void *)GetProcAddress( module, "pcap_list_tstamp_types" ); + ppcap_lookupdev = (void *)GetProcAddress( module, "pcap_lookupdev" ); + ppcap_lookupnet = (void *)GetProcAddress( module, "pcap_lookupnet" ); + ppcap_loop = (void *)GetProcAddress( module, "pcap_loop" ); + ppcap_set_buffer_size = (void *)GetProcAddress( module, "pcap_set_buffer_size" ); + ppcap_set_datalink = (void *)GetProcAddress( module, "pcap_set_datalink" ); + ppcap_set_promisc = (void *)GetProcAddress( module, "pcap_set_promisc" ); + ppcap_set_timeout = (void *)GetProcAddress( module, "pcap_set_timeout" ); + ppcap_set_tstamp_precision = (void *)GetProcAddress( module, "pcap_set_tstamp_precision" ); + ppcap_setfilter = (void *)GetProcAddress( module, "pcap_setfilter" ); + ppcap_snapshot = (void *)GetProcAddress( module, "pcap_snapshot" ); + ppcap_stats = (void *)GetProcAddress( module, "pcap_stats" ); + ppcap_tstamp_type_name_to_val = (void *)GetProcAddress( module, "pcap_tstamp_type_name_to_val" ); + ppcap_tstamp_type_val_to_description = (void *)GetProcAddress( module, "pcap_tstamp_type_val_to_description" ); + ppcap_tstamp_type_val_to_name = (void *)GetProcAddress( module, "pcap_tstamp_type_val_to_name" ); + + trace( "lib version %s\n", ppcap_lib_version() ); + trace( "supports PCAP_MMAP_32BIT: %s\n", (ppcap_init(PCAP_MMAP_32BIT, errbuf) < 0) ? "no" : "yes" ); + + test_capture(); + test_datalink(); + test_dump(); +}