-- v5: 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 2b0e0eaccff..515cde31071 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 515cde31071..db067510bbd 100644 --- a/configure.ac +++ b/configure.ac @@ -3197,6 +3197,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(); +}
Looks like the build failure on Mac is a problem with the way the build bot handles configure. The first patch in this series changes the configure check for libpcap. The build bot runs the check after applying this patch and it fails as it should. On subsequent patches (that don't touch configure.ac) configure is run with cached values from before the first patch, where the check still succeeded, and this causes the build fail.
Looks like Alexandre fixed the build bot (thanks!). Restarting the pipeline for this MR results in the same failure however, presumably because it reuses a snapshot of the build bot code. I'll submit the first patch in a separate MR.
Looks like Alexandre fixed the build bot (thanks!). Restarting the pipeline for this MR results in the same failure however, presumably because it reuses a snapshot of the build bot code. I'll submit the first patch in a separate MR.
The gitlab scripts are in the source tree, so you'd need to rebase the MR to get the fixed scripts.