ETHER: Gracefully handle dynamic pcap library initialization errors

- Test BPF using all available Ethernet capable interfaces
This commit is contained in:
Mark Pizzolato 2019-04-15 16:49:08 -07:00
parent 2f0db74483
commit 456aa3ed5d

View file

@ -1202,7 +1202,7 @@ int load_pcap(void) {
/* define functions with dynamic revectoring */ /* define functions with dynamic revectoring */
void pcap_close(pcap_t* a) { void pcap_close(pcap_t* a) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
p_pcap_close(a); p_pcap_close(a);
} }
} }
@ -1213,7 +1213,7 @@ int pcap_compile(pcap_t* a, struct bpf_program* b, char* c, int d, bpf_u_int32 e
#else #else
int pcap_compile(pcap_t* a, struct bpf_program* b, const char* c, int d, bpf_u_int32 e) { int pcap_compile(pcap_t* a, struct bpf_program* b, const char* c, int d, bpf_u_int32 e) {
#endif #endif
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_compile(a, b, c, d, e); return p_pcap_compile(a, b, c, d, e);
} else { } else {
return 0; return 0;
@ -1221,7 +1221,7 @@ int pcap_compile(pcap_t* a, struct bpf_program* b, const char* c, int d, bpf_u_i
} }
int pcap_datalink(pcap_t* a) { int pcap_datalink(pcap_t* a) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_datalink(a); return p_pcap_datalink(a);
} else { } else {
return 0; return 0;
@ -1229,7 +1229,7 @@ int pcap_datalink(pcap_t* a) {
} }
int pcap_dispatch(pcap_t* a, int b, pcap_handler c, u_char* d) { int pcap_dispatch(pcap_t* a, int b, pcap_handler c, u_char* d) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_dispatch(a, b, c, d); return p_pcap_dispatch(a, b, c, d);
} else { } else {
return 0; return 0;
@ -1237,7 +1237,7 @@ int pcap_dispatch(pcap_t* a, int b, pcap_handler c, u_char* d) {
} }
int pcap_findalldevs(pcap_if_t** a, char* b) { int pcap_findalldevs(pcap_if_t** a, char* b) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_findalldevs(a, b); return p_pcap_findalldevs(a, b);
} else { } else {
*a = 0; *a = 0;
@ -1247,22 +1247,22 @@ int pcap_findalldevs(pcap_if_t** a, char* b) {
} }
void pcap_freealldevs(pcap_if_t* a) { void pcap_freealldevs(pcap_if_t* a) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
p_pcap_freealldevs(a); p_pcap_freealldevs(a);
} }
} }
void pcap_freecode(struct bpf_program* a) { void pcap_freecode(struct bpf_program* a) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
p_pcap_freecode(a); p_pcap_freecode(a);
} }
} }
char* pcap_geterr(pcap_t* a) { char* pcap_geterr(pcap_t* a) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_geterr(a); return p_pcap_geterr(a);
} else { } else {
return (char*) 0; return (char*) "";
} }
} }
@ -1284,15 +1284,15 @@ pcap_t* pcap_open_live(const char* a, int b, int c, int d, char* e) {
#ifdef _WIN32 #ifdef _WIN32
int pcap_setmintocopy(pcap_t* a, int b) { int pcap_setmintocopy(pcap_t* a, int b) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_setmintocopy(a, b); return p_pcap_setmintocopy(a, b);
} else { } else {
return 0; return -1;
} }
} }
HANDLE pcap_getevent(pcap_t* a) { HANDLE pcap_getevent(pcap_t* a) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_getevent(a); return p_pcap_getevent(a);
} else { } else {
return (HANDLE) 0; return (HANDLE) 0;
@ -1302,7 +1302,7 @@ HANDLE pcap_getevent(pcap_t* a) {
#else #else
#ifdef MUST_DO_SELECT #ifdef MUST_DO_SELECT
int pcap_get_selectable_fd(pcap_t* a) { int pcap_get_selectable_fd(pcap_t* a) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_get_selectable_fd(a); return p_pcap_get_selectable_fd(a);
} else { } else {
return 0; return 0;
@ -1311,7 +1311,7 @@ int pcap_get_selectable_fd(pcap_t* a) {
#endif #endif
int pcap_fileno(pcap_t * a) { int pcap_fileno(pcap_t * a) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_fileno(a); return p_pcap_fileno(a);
} else { } else {
return 0; return 0;
@ -1320,7 +1320,7 @@ int pcap_fileno(pcap_t * a) {
#endif #endif
int pcap_sendpacket(pcap_t* a, const u_char* b, int c) { int pcap_sendpacket(pcap_t* a, const u_char* b, int c) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_sendpacket(a, b, c); return p_pcap_sendpacket(a, b, c);
} else { } else {
return 0; return 0;
@ -1328,7 +1328,7 @@ int pcap_sendpacket(pcap_t* a, const u_char* b, int c) {
} }
int pcap_setfilter(pcap_t* a, struct bpf_program* b) { int pcap_setfilter(pcap_t* a, struct bpf_program* b) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_setfilter(a, b); return p_pcap_setfilter(a, b);
} else { } else {
return 0; return 0;
@ -1336,7 +1336,7 @@ int pcap_setfilter(pcap_t* a, struct bpf_program* b) {
} }
int pcap_setnonblock(pcap_t* a, int nonblock, char *errbuf) { int pcap_setnonblock(pcap_t* a, int nonblock, char *errbuf) {
if (load_pcap() != 0) { if (a && (load_pcap() != 0)) {
return p_pcap_setnonblock(a, nonblock, errbuf); return p_pcap_setnonblock(a, nonblock, errbuf);
} else { } else {
return 0; return 0;
@ -2182,7 +2182,13 @@ else { /* !tap: */
} }
#endif /* xBSD */ #endif /* xBSD */
#if defined(_WIN32) #if defined(_WIN32)
pcap_setmintocopy ((pcap_t*)(*handle), 0); if ((pcap_setmintocopy ((pcap_t*)(*handle), 0) == -1) ||
(pcap_getevent ((pcap_t*)(*handle)) == NULL)) {
pcap_close ((pcap_t*)(*handle));
errbuf[PCAP_ERRBUF_SIZE-1] = '\0';
snprintf (errbuf, PCAP_ERRBUF_SIZE-1, "pcap can't initialize API for interface: %s", savname);
return SCPE_OPENERR;
}
#endif #endif
#if !defined (USE_READER_THREAD) #if !defined (USE_READER_THREAD)
#ifdef USE_SETNONBLOCK #ifdef USE_SETNONBLOCK
@ -4170,6 +4176,10 @@ int errors = 0;
t_stat r; t_stat r;
DEVICE eth_tst; DEVICE eth_tst;
ETH_DEV dev; ETH_DEV dev;
int eth_num;
int eth_opened;
ETH_LIST eth_list[ETH_MAX_DEVICE];
int eth_device_count;
int reflections, all_multicast, promiscuous; int reflections, all_multicast, promiscuous;
char buf[116+66*ETH_FILTER_MAX]; char buf[116+66*ETH_FILTER_MAX];
char mac[20]; char mac[20];
@ -4215,59 +4225,83 @@ int bpf_compile_skip_count = 0;
memset (&eth_tst, 0, sizeof(eth_tst)); memset (&eth_tst, 0, sizeof(eth_tst));
eth_open(&dev, "eth0", &eth_tst, 1); eth_device_count = eth_devices(ETH_MAX_DEVICE, eth_list);
for (reflections=0; reflections<=1; reflections++) { eth_opened = 0;
for (all_multicast=0; all_multicast<=1; all_multicast++) { for (eth_num=0; eth_num<eth_device_count; eth_num++) {
for (promiscuous=0; promiscuous<=1; promiscuous++) { char eth_name[10];
for (addr_count=1; addr_count<=2; addr_count++) {
for (hash_listindex=0; hash_listindex<=1; hash_listindex++) {
for (host_phy_addr_listindex=0; host_phy_addr_listindex<=1; host_phy_addr_listindex++) {
int i;
char errbuf[PCAP_ERRBUF_SIZE];
++bpf_count; if ((0 == memcmp (eth_list[eth_num].name, "nat:", 4)) ||
r = eth_bpf_filter (&dev, addr_count, &filter_address[0], (0 == memcmp (eth_list[eth_num].name, "tap:", 4)) ||
all_multicast, promiscuous, reflections, (0 == memcmp (eth_list[eth_num].name, "vde:", 4)) ||
&filter_address[0], (0 == memcmp (eth_list[eth_num].name, "udp:", 4)))
host_phy_addr_list[host_phy_addr_listindex], continue;
hash_list[hash_listindex], eth_name[sizeof (eth_name)-1] = '\0';
buf); snprintf (eth_name, sizeof (eth_name)-1, "eth%d", eth_num);
if (r != SCPE_OK) { r = eth_open(&dev, eth_name, &eth_tst, 1);
++bpf_construct_error_count; if (r != SCPE_OK) {
sim_printf ("Eth: Error producing a BPF filter for:\n"); sim_printf ("%s: Eth: Error opening eth%d: %s\n", dptr->name, eth_num, sim_error_text (r));
SIM_PRINT_BPF_ARGUMENTS; continue;
} }
else { ++eth_opened;
if (sim_switches & SWMASK('D')) { for (reflections=0; reflections<=1; reflections++) {
for (all_multicast=0; all_multicast<=1; all_multicast++) {
for (promiscuous=0; promiscuous<=1; promiscuous++) {
for (addr_count=1; addr_count<=2; addr_count++) {
for (hash_listindex=0; hash_listindex<=1; hash_listindex++) {
for (host_phy_addr_listindex=0; host_phy_addr_listindex<=1; host_phy_addr_listindex++) {
int i;
char errbuf[PCAP_ERRBUF_SIZE];
++bpf_count;
r = eth_bpf_filter (&dev, addr_count, &filter_address[0],
all_multicast, promiscuous, reflections,
&filter_address[0],
host_phy_addr_list[host_phy_addr_listindex],
hash_list[hash_listindex],
buf);
if (r != SCPE_OK) {
++bpf_construct_error_count;
sim_printf ("Eth: Error producing a BPF filter for:\n");
SIM_PRINT_BPF_ARGUMENTS; SIM_PRINT_BPF_ARGUMENTS;
sim_printf ("Eth: BPF string is: |%s|\n", buf);
} }
if (dev.eth_api == ETH_API_PCAP) { else {
struct bpf_program bpf; if (sim_switches & SWMASK('D')) {
SIM_PRINT_BPF_ARGUMENTS;
if (pcap_compile ((pcap_t*)dev.handle, &bpf, buf, 1, (bpf_u_int32)0) < 0) { sim_printf ("Eth: BPF string is: |%s|\n", buf);
++bpf_compile_error_count;
sprintf(errbuf, "%s", pcap_geterr((pcap_t*)dev.handle));
sim_printf("Eth: pcap_compile error: %s\n", errbuf);
if (!(sim_switches & SWMASK('D'))) {
/* show erroneous BPF string */
SIM_PRINT_BPF_ARGUMENTS;
sim_printf ("Eth: BPF string is: |%s|\n", buf);
}
} }
pcap_freecode(&bpf); if (dev.eth_api == ETH_API_PCAP) {
struct bpf_program bpf;
if (pcap_compile ((pcap_t*)dev.handle, &bpf, buf, 1, (bpf_u_int32)0) < 0) {
++bpf_compile_error_count;
sprintf(errbuf, "%s", pcap_geterr((pcap_t*)dev.handle));
sim_printf("Eth: pcap_compile error: %s\n", errbuf);
if (!(sim_switches & SWMASK('D'))) {
/* show erroneous BPF string */
SIM_PRINT_BPF_ARGUMENTS;
sim_printf ("Eth: BPF string is: |%s|\n", buf);
}
}
pcap_freecode(&bpf);
}
else
++bpf_compile_skip_count;
} }
else
++bpf_compile_skip_count;
} }
} }
} }
} }
} }
} }
eth_close(&dev);
} }
eth_close(&dev);
sim_printf ("BPF Filter Count: %d\n", bpf_count); if (eth_opened == 0) {
errors = 1;
sim_printf ("%s: No testable LAN interfaces found\n", dptr->name);
}
if (bpf_count)
sim_printf ("BPF Filter Count: %d\n", bpf_count);
if (bpf_construct_error_count) if (bpf_construct_error_count)
sim_printf ("BPF Construct Errors: %d\n", bpf_construct_error_count); sim_printf ("BPF Construct Errors: %d\n", bpf_construct_error_count);
if (bpf_compile_error_count) if (bpf_compile_error_count)