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;