From edfda8412f82c3e31dab146706d6f32dead091b4 Mon Sep 17 00:00:00 2001 From: Bob Supnik Date: Sat, 14 Mar 2020 07:20:53 -0700 Subject: [PATCH] ETHER: Imported latest from master branch --- sim_ether.c | 740 +++++++++++++++++++++++++++++++++++++++------------- sim_ether.h | 9 +- 2 files changed, 563 insertions(+), 186 deletions(-) diff --git a/sim_ether.c b/sim_ether.c index c29e5dc3..64182cf5 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -379,6 +379,7 @@ /* Internal routines - forward declarations */ static int _eth_get_system_id (char *buf, size_t buf_size); +static int _eth_devices (int max, ETH_LIST* dev); /* get ethernet devices on host */ /*============================================================================*/ /* OS-independant ethernet routines */ @@ -416,17 +417,17 @@ t_stat eth_mac_scan_ex (ETH_MAC* mac, const char* strmac, UNIT *uptr) memset (&state, 0, sizeof(state)); _eth_get_system_id (state.system_id, sizeof(state.system_id)); - strncpy (state.sim, sim_name, sizeof(state.sim)); - getcwd (state.cwd, sizeof(state.cwd)); + strlcpy (state.sim, sim_name, sizeof(state.sim)); + if (getcwd (state.cwd, sizeof(state.cwd))) {}; if (uptr) - strncpy (state.uname, sim_uname (uptr), sizeof(state.uname)-1); + strlcpy (state.uname, sim_uname (uptr), sizeof(state.uname)); cptr = strchr (strmac, '>'); if (cptr) { state.file[sizeof(state.file)-1] = '\0'; - strncpy (state.file, cptr + 1, sizeof(state.file)-1); + strlcpy (state.file, cptr + 1, sizeof(state.file)); if ((f = fopen (state.file, "r"))) { filebuf[sizeof(filebuf)-1] = '\0'; - fgets (filebuf, sizeof(filebuf)-1, f); + if (fgets (filebuf, sizeof(filebuf)-1, f)) {}; strmac = filebuf; fclose (f); strcpy (state.file, ""); /* avoid saving */ @@ -657,10 +658,10 @@ void eth_packet_trace_detail(ETH_DEV* dev, const uint8 *msg, int len, const char eth_packet_trace_ex(dev, msg, len, txt, 1 , dev->dbit); } -const char* eth_getname(int number, char* name, char *desc) +static const char* _eth_getname(int number, char* name, char *desc) { ETH_LIST list[ETH_MAX_DEVICE]; - int count = eth_devices(ETH_MAX_DEVICE, list); + int count = _eth_devices(ETH_MAX_DEVICE, list); if ((number < 0) || (count <= number)) return NULL; @@ -677,7 +678,7 @@ const char* eth_getname(int number, char* name, char *desc) const char* eth_getname_bydesc(const char* desc, char* name, char *ndesc) { ETH_LIST list[ETH_MAX_DEVICE]; - int count = eth_devices(ETH_MAX_DEVICE, list); + int count = _eth_devices(ETH_MAX_DEVICE, list); int i; size_t j=strlen(desc); @@ -703,7 +704,7 @@ const char* eth_getname_bydesc(const char* desc, char* name, char *ndesc) char* eth_getname_byname(const char* name, char* temp, char *desc) { ETH_LIST list[ETH_MAX_DEVICE]; - int count = eth_devices(ETH_MAX_DEVICE, list); + int count = _eth_devices(ETH_MAX_DEVICE, list); size_t n; int i, found; @@ -723,7 +724,7 @@ char* eth_getname_byname(const char* name, char* temp, char *desc) char* eth_getdesc_byname(char* name, char* temp) { ETH_LIST list[ETH_MAX_DEVICE]; - int count = eth_devices(ETH_MAX_DEVICE, list); + int count = _eth_devices(ETH_MAX_DEVICE, list); size_t n; int i, found; @@ -750,7 +751,6 @@ static char* (*p_pcap_lib_version) (void); static ETH_DEV **eth_open_devices = NULL; static int eth_open_device_count = 0; -static t_bool eth_show_active = FALSE; #if defined (USE_NETWORK) || defined (USE_SHARED) static void _eth_add_to_open_list (ETH_DEV* dev) @@ -778,8 +778,7 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc) ETH_LIST list[ETH_MAX_DEVICE]; int number; - eth_show_active = TRUE; - number = eth_devices(ETH_MAX_DEVICE, list); + number = _eth_devices(ETH_MAX_DEVICE, list); fprintf(st, "ETH devices:\n"); if (number == -1) fprintf(st, " network support not available in simulator\n"); @@ -794,9 +793,6 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc) for (i=0; ihave_host_nic_phy_addr); ++i) { - snprintf(command, sizeof(command)-1, "ifconfig %s | %s >NIC.hwaddr", devname, patterns[i]); - (void)system(command); + snprintf(command, sizeof(command)-1, "ifconfig %.*s | %s >NIC.hwaddr", (int)(sizeof(command) - (26 + strlen(patterns[i]))), devname, patterns[i]); + if (system(command)) {}; if (NULL != (f = fopen("NIC.hwaddr", "r"))) { while (0 == dev->have_host_nic_phy_addr) { if (fgets(command, sizeof(command)-1, f)) { @@ -1609,7 +1616,7 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname) break; } fclose(f); - remove("NIC.hwaddr"); + (void)remove("NIC.hwaddr"); } } } @@ -1647,7 +1654,7 @@ static int _eth_get_system_id (char *buf, size_t buf_size) if ((status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Cryptography", 0, KEY_QUERY_VALUE|KEY_WOW64_64KEY, ®hnd)) != ERROR_SUCCESS) return -1; reglen = buf_size; - if ((status = RegQueryValueExA (reghnd, "MachineGuid", NULL, ®type, buf, ®len)) != ERROR_SUCCESS) { + if ((status = RegQueryValueExA (reghnd, "MachineGuid", NULL, ®type, (LPBYTE)buf, ®len)) != ERROR_SUCCESS) { RegCloseKey (reghnd); return -1; } @@ -1666,13 +1673,17 @@ FILE *f; memset (buf, 0, buf_size); if ((f = fopen ("/etc/machine-id", "r"))) { - fread (buf, 1, buf_size, f); - fclose (f); + if (fread (buf, 1, buf_size - 1, f)) + fclose (f); + else + fclose (f); } else { if ((f = popen ("hostname", "r"))) { - fread (buf, 1, buf_size, f); - pclose (f); + if (fread (buf, 1, buf_size - 1, f)) + pclose (f); + else + pclose (f); } } while ((strlen (buf) > 0) && sim_isspace(buf[strlen (buf) - 1])) @@ -1907,6 +1918,8 @@ pthread_mutex_lock (&dev->writer_lock); while (dev->handle) { pthread_cond_wait (&dev->writer_cond, &dev->writer_lock); while (NULL != (request = dev->write_requests)) { + if (dev->handle == NULL) /* Shutting down? */ + break; /* Pull buffer off request list */ dev->write_requests = request->next; pthread_mutex_unlock (&dev->writer_lock); @@ -1927,8 +1940,15 @@ while (dev->handle) { /* Put buffer on free buffer list */ request->next = dev->write_buffers; dev->write_buffers = request; + request = NULL; } } +/* If we exited these loops with a request allocated, */ +/* avoid buffer leaking by putting it on free buffer list */ +if (request) { + request->next = dev->write_buffers; + dev->write_buffers = request; + } pthread_mutex_unlock (&dev->writer_lock); sim_debug(dev->dbit, dev->dptr, "Writer Thread Exiting\n"); @@ -1940,8 +1960,7 @@ t_stat eth_set_async (ETH_DEV *dev, int latency) { #if !defined(USE_READER_THREAD) || !defined(SIM_ASYNCH_IO) char *msg = "Eth: can't operate asynchronously, must poll\n"; -sim_printf ("%s", msg); -return SCPE_NOFNC; +return sim_messagef (SCPE_NOFNC, "%s", msg); #else int wakeup_needed; @@ -2012,25 +2031,30 @@ if (0 == strncmp("tap:", savname, 4)) { memset(&ifr, 0, sizeof(ifr)); /* Set up interface flags */ - strcpy(ifr.ifr_name, devname); + strlcpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name)); ifr.ifr_flags = IFF_TAP|IFF_NO_PI; /* Send interface requests to TUN/TAP driver. */ if (ioctl(tun, TUNSETIFF, &ifr) >= 0) { if (ioctl(tun, FIONBIO, &on)) { - strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1); + strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); close(tun); + tun = -1; } else { - *fd_handle = tun; + *fd_handle = (SOCKET)tun; strcpy(savname, ifr.ifr_name); } } else - strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1); + strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); } else - strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1); + strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); + if ((tun >= 0) && (errbuf[0] != 0)) { + close(tun); + tun = -1; + } #elif defined(HAVE_BSDTUNTAP) && defined(HAVE_TAP_NETWORK) if (1) { char dev_name[64] = ""; @@ -2040,11 +2064,12 @@ if (0 == strncmp("tap:", savname, 4)) { if ((tun = open(dev_name, O_RDWR)) >= 0) { if (ioctl(tun, FIONBIO, &on)) { - strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1); + strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); close(tun); + tun = -1; } else { - *fd_handle = tun; + *fd_handle = (SOCKET)tun; strcpy(savname, devname); } #if defined (__APPLE__) @@ -2054,13 +2079,14 @@ if (0 == strncmp("tap:", savname, 4)) { memset (&ifr, 0, sizeof(ifr)); ifr.ifr_addr.sa_family = AF_INET; - strncpy(ifr.ifr_name, savname, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, savname, sizeof(ifr.ifr_name)); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0) { ifr.ifr_flags |= IFF_UP; if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr)) { - strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1); + strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); close(tun); + tun = -1; } } close(s); @@ -2069,10 +2095,14 @@ if (0 == strncmp("tap:", savname, 4)) { #endif } else - strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1); - } + strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); + if ((tun >= 0) && (errbuf[0] != 0)) { + close(tun); + tun = -1; + } + } #else - strncpy(errbuf, "No support for tap: devices", PCAP_ERRBUF_SIZE-1); + strlcpy(errbuf, "No support for tap: devices", PCAP_ERRBUF_SIZE); #endif /* !defined(__linux) && !defined(HAVE_BSDTUNTAP) */ if (0 == errbuf[0]) { *eth_api = ETH_API_TAP; @@ -2105,13 +2135,13 @@ else { /* !tap: */ } if (!(*handle = (void*) vde_open((char *)vdeswitch_s, (char *)"simh", &voa))) - strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1); + strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); else { *eth_api = ETH_API_VDE; - *fd_handle = vde_datafd((VDECONN*)(*handle)); + *fd_handle = (SOCKET)vde_datafd((VDECONN*)(*handle)); } #else - strncpy(errbuf, "No support for vde: network devices", PCAP_ERRBUF_SIZE-1); + strlcpy(errbuf, "No support for vde: network devices", PCAP_ERRBUF_SIZE); #endif /* defined(HAVE_VDE_NETWORK) */ } else { /* !vde: */ @@ -2121,14 +2151,14 @@ else { /* !tap: */ while (isspace(*devname)) ++devname; - if (!(*handle = (void*) sim_slirp_open(devname, opaque, &_slirp_callback, dptr, dbit))) - strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1); + if (!(*handle = (void*) sim_slirp_open(devname, opaque, &_slirp_callback, dptr, dbit, errbuf, PCAP_ERRBUF_SIZE))) + strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); else { *eth_api = ETH_API_NAT; *fd_handle = 0; } #else - strncpy(errbuf, "No support for nat: network devices", PCAP_ERRBUF_SIZE-1); + strlcpy(errbuf, "No support for nat: network devices", PCAP_ERRBUF_SIZE); #endif /* defined(HAVE_SLIRP_NETWORK) */ } else { /* not nat: */ @@ -2160,7 +2190,21 @@ else { /* !tap: */ else { /* not udp:, so attempt to open the parameter as if it were an explicit device name */ #if defined(HAVE_PCAP_NETWORK) *handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf); - if (!*handle) /* can't open device */ +#if !defined(__CYGWIN__) && !defined(__VMS) && !defined(_WIN32) + if (!*handle) { /* can't open device */ + if (strstr (errbuf, "That device is not up")) { + char command[1024]; + + /* try to force an otherwise unused interface to be turned on */ + memset(command, 0, sizeof(command)); + snprintf(command, sizeof(command)-1, "ifconfig %s up", savname); + if (system(command)) {}; + errbuf[0] = '\0'; + *handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf); + } + } +#endif + if (!*handle) /* can't open device */ return sim_messagef (SCPE_OPENERR, "Eth: pcap_open_live error - %s\n", errbuf); *eth_api = ETH_API_PCAP; #if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__) @@ -2172,7 +2216,13 @@ else { /* !tap: */ } #endif /* xBSD */ #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 #if !defined (USE_READER_THREAD) #ifdef USE_SETNONBLOCK @@ -2194,7 +2244,7 @@ else { /* !tap: */ #endif /* defined (__APPLE__) */ #endif /* !defined (USE_READER_THREAD) */ #else - strncpy (errbuf, "Unknown or unsupported network device", PCAP_ERRBUF_SIZE-1); + strlcpy (errbuf, "Unknown or unsupported network device", PCAP_ERRBUF_SIZE); #endif /* defined(HAVE_PCAP_NETWORK) */ } /* not udp:, so attempt to open the parameter as if it were an explicit device name */ } /* !nat: */ @@ -2261,7 +2311,7 @@ if ((strlen(name) == 4) && isdigit(name[3]) ) { num = atoi(&name[3]); - savname = eth_getname(num, temp, desc); + savname = _eth_getname(num, temp, desc); if (savname == NULL) /* didn't translate */ return SCPE_OPENERR; } @@ -2279,7 +2329,12 @@ else { } namebuf[sizeof(namebuf)-1] = '\0'; -strncpy (namebuf, savname, sizeof(namebuf)-1); +strlcpy (namebuf, savname, sizeof(namebuf)); +if (strchr (namebuf, ':')) { + for (num = 0; (namebuf[num] != ':') && (namebuf[num] != '\0'); num++) + if (isupper (namebuf[num])) + namebuf[num] = tolower (namebuf[num]); + } savname = namebuf; r = _eth_open_port(namebuf, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, NULL, (void *)dev, dptr, dbit); @@ -2290,7 +2345,7 @@ if (r != SCPE_OK) if (!strcmp (desc, "No description available")) strcpy (desc, ""); -sim_printf ("Eth: opened OS device %s%s%s\n", savname, desc[0] ? " - " : "", desc); +sim_messagef (SCPE_OK, "Eth: opened OS device %s%s%s\n", savname, desc[0] ? " - " : "", desc); /* get the NIC's hardware MAC address */ eth_get_nic_hw_addr(dev, savname); @@ -2330,7 +2385,12 @@ if (1) { } #endif /* defined (USE_READER_THREAD */ _eth_add_to_open_list (dev); -return SCPE_OK; +/* + * install a total filter on a newly opened interface and let the device + * simulator install an appropriate filter that reflects the device's + * configuration. + */ +return eth_filter_hash (dev, 0, NULL, FALSE, FALSE, NULL); } static t_stat _eth_close_port(int eth_api, pcap_t *pcap, SOCKET pcap_fd) @@ -2401,7 +2461,7 @@ ethq_destroy (&dev->read_queue); /* release FIFO queue */ #endif _eth_close_port (dev->eth_api, pcap, pcap_fd); -sim_printf ("Eth: closed %s\n", dev->name); +sim_messagef (SCPE_OK, "Eth: closed %s\n", dev->name); /* clean up the mess */ free(dev->name); @@ -2411,6 +2471,23 @@ _eth_remove_from_open_list (dev); return SCPE_OK; } +const char *eth_version (void) +{ +#if defined(HAVE_PCAP_NETWORK) +static char version[256]; + +if (!version[0]) { + if (memcmp(pcap_lib_version(), "Npcap", 5)) + strlcpy(version, pcap_lib_version(), sizeof(version)); + else + snprintf(version, sizeof(version), "Unsupported - %s", pcap_lib_version()); + } +return version; +#else +return NULL; +#endif +} + t_stat eth_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) { fprintf (st, "%s attach help\n\n", dptr->name); @@ -2446,8 +2523,10 @@ if (!rand_initialized) return (rand() & 0xFF); } -t_stat eth_check_address_conflict (ETH_DEV* dev, - ETH_MAC* const mac) +t_stat eth_check_address_conflict_ex (ETH_DEV* dev, + ETH_MAC* const mac, + int *reflections, + t_bool silent) { ETH_PACK send, recv; t_stat status; @@ -2456,9 +2535,18 @@ int responses = 0; uint32 offset, function; char mac_string[32]; +if (reflections) + *reflections = 0; eth_mac_fmt(mac, mac_string); sim_debug(dev->dbit, dev->dptr, "Determining Address Conflict for MAC address: %s\n", mac_string); +/* 00:00:00:00:00:00 or any address with a multi-cast address is invalid */ +if ((((*mac)[0] == 0) && ((*mac)[1] == 0) && ((*mac)[2] == 0) && + ((*mac)[3] == 0) && ((*mac)[4] == 0) && ((*mac)[5] == 0)) || + ((*mac)[0] & 1)) { + return sim_messagef (SCPE_ARG, "%s: Invalid NIC MAC Address: %s\n", sim_dname(dev->dptr), mac_string); + } + /* The process of checking address conflicts is used in two ways: 1) to determine the behavior of the currently running packet delivery facility regarding whether it may receive copies @@ -2543,13 +2631,12 @@ status = _eth_write (dev, &send, NULL); if (status != SCPE_OK) { const char *msg; msg = (dev->eth_api == ETH_API_PCAP) ? - "Eth: Error Transmitting packet: %s\n" + "%s: Eth: Error Transmitting packet: %s\n" "You may need to run as root, or install a libpcap version\n" "which is at least 0.9 from your OS vendor or www.tcpdump.org\n" : - "Eth: Error Transmitting packet: %s\n" + "%s: Eth: Error Transmitting packet: %s\n" "You may need to run as root.\n"; - sim_printf(msg, strerror(errno)); - return status; + return sim_messagef (SCPE_ARG, msg, sim_dname (dev->dptr), strerror(errno)); } sim_os_ms_sleep (300); /* time for a conflicting host to respond */ @@ -2573,11 +2660,28 @@ do { } while (recv.len > 0); sim_debug(dev->dbit, dev->dptr, "Address Conflict = %d\n", responses); -return responses; +if (responses && !silent) + return sim_messagef (SCPE_ARG, "%s: MAC Address Conflict on LAN for address %s, change the MAC address to a unique value\n", sim_dname (dev->dptr), mac_string); +if (reflections) + *reflections = responses; +return SCPE_OK; +} + +t_stat eth_check_address_conflict (ETH_DEV* dev, + ETH_MAC* const mac) +{ +char mac_string[32]; + +eth_mac_fmt(mac, mac_string); +if (0 == memcmp (mac, dev->host_nic_phy_hw_addr, sizeof *mac)) + return sim_messagef (SCPE_OK, "Sharing the host NIC MAC address %s may cause unexpected behavior\n", mac_string); +return eth_check_address_conflict_ex (dev, mac, NULL, FALSE); } t_stat eth_reflect(ETH_DEV* dev) { +t_stat r; + /* Test with an address no NIC should have. */ /* We do this to avoid reflections from the wire, */ /* in the event that a simulated NIC has a MAC address conflict. */ @@ -2585,11 +2689,12 @@ static ETH_MAC mac = {0xfe,0xff,0xff,0xff,0xff,0xfe}; sim_debug(dev->dbit, dev->dptr, "Determining Reflections...\n"); -dev->reflections = 0; -dev->reflections = eth_check_address_conflict (dev, &mac); +r = eth_check_address_conflict_ex (dev, &mac, &dev->reflections, TRUE); +if (r != SCPE_OK) + return sim_messagef (r, "eth: Error determining reflection count\n"); sim_debug(dev->dbit, dev->dptr, "Reflections = %d\n", dev->reflections); -return dev->reflections; +return SCPE_OK; } static void @@ -2991,15 +3096,22 @@ cksum += (cksum >> 16); return (uint16)(~cksum); } +/* + * src_addr and dest_addr are presented in network byte order + */ + static uint16 -pseudo_checksum(uint16 len, uint16 proto, uint16 *src_addr, uint16 *dest_addr, uint8 *buff) +pseudo_checksum(uint16 len, uint16 proto, void *nsrc_addr, void *ndest_addr, uint8 *buff) { uint32 sum; +uint16 *src_addr = (uint16 *)nsrc_addr; +uint16 *dest_addr = (uint16 *)ndest_addr; /* Sum the data first */ sum = 0xffff&(~ip_checksum((uint16 *)buff, len)); -/* add the pseudo header which contains the IP source and destinationn addresses */ +/* add the pseudo header which contains the IP source and + destination addresses already in network byte order */ sum += src_addr[0]; sum += src_addr[1]; sum += dest_addr[0]; @@ -3060,7 +3172,7 @@ switch (IP->proto) { break; /* UDP Checksums are disabled */ orig_checksum = UDP->checksum; UDP->checksum = 0; - UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP); + UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, &IP->source_ip, &IP->dest_ip, (uint8 *)UDP); if (orig_checksum != UDP->checksum) eth_packet_trace (dev, msg, len, "reading jumbo UDP header Checksum Fixed"); break; @@ -3169,7 +3281,7 @@ switch (IP->proto) { IP->checksum = 0; IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP)); TCP->checksum = 0; - TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP); + TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, &IP->source_ip, &IP->dest_ip, (uint8 *)TCP); header.caplen = header.len = 14 + ntohs(IP->total_len); eth_packet_trace_ex (dev, ((u_char *)IP)-14, header.len, "reading TCP segment", 1, dev->dbit); #if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET @@ -3241,7 +3353,7 @@ switch (IP->proto) { return; /* UDP Checksums are disabled */ orig_checksum = UDP->checksum; UDP->checksum = 0; - UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP); + UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, &IP->source_ip, &IP->dest_ip, (uint8 *)UDP); if (orig_checksum != UDP->checksum) eth_packet_trace (dev, msg, len, "reading UDP header Checksum Fixed"); break; @@ -3249,7 +3361,7 @@ switch (IP->proto) { TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP)); orig_checksum = TCP->checksum; TCP->checksum = 0; - TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP); + TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, &IP->source_ip, &IP->dest_ip, (uint8 *)TCP); if (orig_checksum != TCP->checksum) eth_packet_trace (dev, msg, len, "reading TCP header Checksum Fixed"); break; @@ -3603,6 +3715,98 @@ if (status < 0) { return status; } +t_stat eth_bpf_filter (ETH_DEV* dev, int addr_count, ETH_MAC* const filter_address, + ETH_BOOL all_multicast, ETH_BOOL promiscuous, + int reflections, + ETH_MAC* physical_addr, + ETH_MAC* host_nic_phy_hw_addr, + ETH_MULTIHASH* const hash, + char *buf) +{ +int i; +char mac[20]; +char *buf2; + +/* setup BPF filters and other fields to minimize packet delivery */ +strcpy(buf, ""); + +/* construct destination filters - since the real ethernet interface was set + into promiscuous mode by eth_open(), we need to filter out the packets that + our simulated interface doesn't want. */ +if (!promiscuous) { + for (i = 0; i < addr_count; i++) { + eth_mac_fmt(&filter_address[i], mac); + if (!strstr(buf, mac)) /* eliminate duplicates */ + sprintf(&buf[strlen(buf)], "%s(ether dst %s)", (*buf) ? " or " : "((", mac); + } + if (all_multicast || hash) + sprintf(&buf[strlen(buf)], "%s(ether multicast)", (*buf) ? " or " : "(("); + if (strlen(buf) > 0) + sprintf(&buf[strlen(buf)], ")"); + } + +/* construct source filters - this prevents packets from being reflected back + by systems where WinPcap and libpcap cause packet reflections. Note that + some systems do not reflect packets at all. This *assumes* that the + simulated NIC will not send out packets with multicast source fields. */ +if ((addr_count > 0) && (reflections > 0)) { + if (strlen(buf) > 0) + sprintf(&buf[strlen(buf)], " and "); + else + if (promiscuous) + sprintf(&buf[strlen(buf)], "("); + sprintf (&buf[strlen(buf)], "not ("); + buf2 = &buf[strlen(buf)]; + for (i = 0; i < addr_count; i++) { + if (filter_address[i][0] & 0x01) continue; /* skip multicast addresses */ + eth_mac_fmt(&filter_address[i], mac); + if (!strstr(buf2, mac)) /* only process each address once */ + sprintf(&buf2[strlen(buf2)], "%s(ether src %s)", (*buf2) ? " or " : "", mac); + } + sprintf (&buf[strlen(buf)], ")"); + if (1 == strlen(buf2)) { /* all addresses were multicast? */ + buf[strlen(buf)-6] = '\0'; /* Remove "not ()" */ + if (strlen(buf) > 0) + buf[strlen(buf)-5] = '\0'; /* remove " and " */ + } + } +if (strlen(buf) > 0) + sprintf(&buf[strlen(buf)], ")"); +/* When changing the Physical Address on a LAN interface, VMS sends out a + loopback packet with the source and destination addresses set to the same + value as the Physical Address which is being setup. This packet is + designed to find and help diagnose MAC address conflicts (which also + include DECnet address conflicts). Normally, this packet would not be + seen by the sender, only by the other machine that has the same Physical + Address (or possibly DECnet address). If the ethernet subsystem is + reflecting packets, the network startup will fail to start if it sees the + reflected packet, since it thinks another system is using this Physical + Address (or DECnet address). We have to let these packets through, so + that if another machine has the same Physical Address (or DECnet address) + that we can detect it. Both eth_write() and _eth_callback() help by + checking the reflection count - eth_write() adds the reflection count to + dev->loopback_self_sent, and _eth_callback() check the value - if the + dev->loopback_self_sent count is zero, then the packet has come from + another machine with the same address, and needs to be passed on to the + simulated machine. */ +/* check for physical address in filters */ +if ((!promiscuous) && (addr_count) && (reflections > 0)) { + eth_mac_fmt(&physical_addr[0], mac); + if (strcmp(mac, "00:00:00:00:00:00") != 0) { + /* let packets through where dst and src are the same as our physical address */ + sprintf (&buf[strlen(buf)], " or ((ether dst %s) and (ether src %s))", mac, mac); + if (host_nic_phy_hw_addr) { + eth_mac_fmt(&host_nic_phy_hw_addr[0], mac); + sprintf(&buf[strlen(buf)], " or ((ether dst %s) and (ether proto 0x9000))", mac); + } + } + } +if ((0 == strlen(buf)) && (!promiscuous)) /* Empty filter means match nothing */ + strcpy(buf, "ether host fe:ff:ff:ff:ff:ff"); /* this should be a good match nothing filter */ +sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf); +return SCPE_OK; +} + t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses, ETH_BOOL all_multicast, ETH_BOOL promiscuous) { @@ -3618,7 +3822,6 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses, int i; char buf[116+66*ETH_FILTER_MAX]; char mac[20]; -char* buf2; t_stat status; #ifdef USE_BPF struct bpf_program bpf; @@ -3631,7 +3834,8 @@ if (!dev) return SCPE_UNATT; if ((addr_count < 0) || (addr_count > ETH_FILTER_MAX)) return SCPE_ARG; else - if (!addresses) return SCPE_ARG; + if (!addresses && (addr_count != 0)) + return SCPE_ARG; /* test reflections. This is done early in this routine since eth_reflect */ /* calls eth_filter recursively and thus changes the state of the device. */ @@ -3671,89 +3875,26 @@ if (dev->dptr->dctrl & dev->dbit) { sim_debug(dev->dbit, dev->dptr, "Promiscuous\n"); } } - -/* setup BPF filters and other fields to minimize packet delivery */ -strcpy(buf, ""); - -/* construct destination filters - since the real ethernet interface was set - into promiscuous mode by eth_open(), we need to filter out the packets that - our simulated interface doesn't want. */ -if (!dev->promiscuous) { - for (i = 0; i < addr_count; i++) { - eth_mac_fmt(&dev->filter_address[i], mac); - if (!strstr(buf, mac)) /* eliminate duplicates */ - sprintf(&buf[strlen(buf)], "%s(ether dst %s)", (*buf) ? " or " : "((", mac); - } - if (dev->all_multicast || dev->hash_filter) - sprintf(&buf[strlen(buf)], "%s(ether multicast)", (*buf) ? " or " : "(("); - if (strlen(buf) > 0) - sprintf(&buf[strlen(buf)], ")"); - } - -/* construct source filters - this prevents packets from being reflected back - by systems where WinPcap and libpcap cause packet reflections. Note that - some systems do not reflect packets at all. This *assumes* that the - simulated NIC will not send out packets with multicast source fields. */ -if ((addr_count > 0) && (dev->reflections > 0)) { - if (strlen(buf) > 0) - sprintf(&buf[strlen(buf)], " and "); - sprintf (&buf[strlen(buf)], "not ("); - buf2 = &buf[strlen(buf)]; - for (i = 0; i < addr_count; i++) { - if (dev->filter_address[i][0] & 0x01) continue; /* skip multicast addresses */ - eth_mac_fmt(&dev->filter_address[i], mac); - if (!strstr(buf2, mac)) /* eliminate duplicates */ - sprintf(&buf2[strlen(buf2)], "%s(ether src %s)", (*buf2) ? " or " : "", mac); - } - sprintf (&buf[strlen(buf)], ")"); - if (1 == strlen(buf2)) { /* all addresses were multicast? */ - buf[strlen(buf)-6] = '\0'; /* Remove "not ()" */ - if (strlen(buf) > 0) - buf[strlen(buf)-5] = '\0'; /* remove " and " */ - } - } -if (strlen(buf) > 0) - sprintf(&buf[strlen(buf)], ")"); -/* When changing the Physical Address on a LAN interface, VMS sends out a - loopback packet with the source and destination addresses set to the same - value as the Physical Address which is being setup. This packet is - designed to find and help diagnose MAC address conflicts (which also - include DECnet address conflicts). Normally, this packet would not be - seen by the sender, only by the other machine that has the same Physical - Address (or possibly DECnet address). If the ethernet subsystem is - reflecting packets, the network startup will fail to start if it sees the - reflected packet, since it thinks another system is using this Physical - Address (or DECnet address). We have to let these packets through, so - that if another machine has the same Physical Address (or DECnet address) - that we can detect it. Both eth_write() and _eth_callback() help by - checking the reflection count - eth_write() adds the reflection count to - dev->loopback_self_sent, and _eth_callback() check the value - if the - dev->loopback_self_sent count is zero, then the packet has come from - another machine with the same address, and needs to be passed on to the - simulated machine. */ +/* Set the desired physical address */ memset(dev->physical_addr, 0, sizeof(ETH_MAC)); dev->loopback_self_sent = 0; -/* check for physical address in filters */ -if ((addr_count) && (dev->reflections > 0)) { - for (i = 0; i < addr_count; i++) { - if (dev->filter_address[i][0]&1) - continue; /* skip all multicast addresses */ - eth_mac_fmt(&dev->filter_address[i], mac); - if (strcmp(mac, "00:00:00:00:00:00") != 0) { - memcpy(dev->physical_addr, &dev->filter_address[i], sizeof(ETH_MAC)); - /* let packets through where dst and src are the same as our physical address */ - sprintf (&buf[strlen(buf)], " or ((ether dst %s) and (ether src %s))", mac, mac); - if (dev->have_host_nic_phy_addr) { - eth_mac_fmt(&dev->host_nic_phy_hw_addr, mac); - sprintf(&buf[strlen(buf)], " or ((ether dst %s) and (ether proto 0x9000))", mac); - } - break; - } +/* Find desired physical address in filters */ +for (i = 0; i < addr_count; i++) { + if (dev->filter_address[i][0]&1) + continue; /* skip all multicast addresses */ + eth_mac_fmt(&dev->filter_address[i], mac); + if (strcmp(mac, "00:00:00:00:00:00") != 0) { + memcpy(dev->physical_addr, &dev->filter_address[i], sizeof(ETH_MAC)); + break; } } -if ((0 == strlen(buf)) && (!dev->promiscuous)) /* Empty filter means match nothing */ - strcpy(buf, "ether host fe:ff:ff:ff:ff:ff"); /* this should be a good match nothing filter */ -sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf); + +/* setup BPF filters and other fields to minimize packet delivery */ +eth_bpf_filter (dev, dev->addr_count, dev->filter_address, + dev->all_multicast, dev->promiscuous, + dev->reflections, &dev->physical_addr, + dev->have_host_nic_phy_addr ? &dev->host_nic_phy_hw_addr: NULL, + (dev->hash_filter ? &dev->hash : NULL), buf); /* get netmask, which is a required argument for compiling. The value, in our case isn't actually interesting since the filters we generate @@ -3772,12 +3913,33 @@ if (dev->eth_api == ETH_API_PCAP) { sim_printf("Eth: pcap_compile error: %s\n", errbuf); /* show erroneous BPF string */ sim_printf ("Eth: BPF string is: |%s|\n", buf); + sim_printf ("Eth: Input to BPF string construction:\n"); + sim_printf ("Eth: Reflections: %d\n", dev->reflections); + sim_printf ("Eth: Filter Set:\n"); + for (i = 0; i < addr_count; i++) { + char mac[20]; + eth_mac_fmt(&dev->filter_address[i], mac); + sim_printf ("Eth: Addr[%d]: %s\n", i, mac); + } + if (dev->all_multicast) + sim_printf ("Eth: All Multicast\n"); + if (dev->promiscuous) + sim_printf ("Eth: Promiscuous\n"); + if (dev->hash_filter) + sim_printf ("Eth: Multicast Hash: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n", + dev->hash[0], dev->hash[1], dev->hash[2], dev->hash[3], + dev->hash[4], dev->hash[5], dev->hash[6], dev->hash[7]); + if (dev->have_host_nic_phy_addr) { + eth_mac_fmt(&dev->host_nic_phy_hw_addr, mac); + sim_printf ("Eth: host_nic_phy_hw_addr: %s\n", mac); + } } else { /* apply compiled filter string */ if ((status = pcap_setfilter((pcap_t*)dev->handle, &bpf)) < 0) { sprintf(errbuf, "%s", pcap_geterr((pcap_t*)dev->handle)); sim_printf("Eth: pcap_setfilter error: %s\n", errbuf); + sim_printf ("Eth: BPF string is: |%s|\n", buf); } else { /* Save BPF filter string */ @@ -3820,7 +3982,7 @@ return SCPE_OK; returned by pcap_findalldevs. */ -int eth_host_devices(int used, int max, ETH_LIST* list) +static int eth_host_devices(int used, int max, ETH_LIST* list) { pcap_t* conn = NULL; int i, j, datalink = 0; @@ -3923,7 +4085,7 @@ if (used < max) { return used; } -int eth_devices(int max, ETH_LIST* list) +static int _eth_devices(int max, ETH_LIST* list) { int i = 0; char errbuf[PCAP_ERRBUF_SIZE] = ""; @@ -3935,17 +4097,18 @@ memset(list, 0, max*sizeof(*list)); errbuf[0] = '\0'; /* retrieve the device list */ if (pcap_findalldevs(&alldevs, errbuf) == -1) { - sim_printf ("Eth: error in pcap_findalldevs: %s\n", errbuf); + if (errbuf[0]) + sim_printf ("Eth: %s\n", errbuf); } else { /* copy device list into the passed structure */ for (i=0, dev=alldevs; dev && (i < max); dev=dev->next, ++i) { if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue; - strncpy(list[i].name, dev->name, sizeof(list[i].name)-1); + strlcpy(list[i].name, dev->name, sizeof(list[i].name)); if (dev->description) - strncpy(list[i].desc, dev->description, sizeof(list[i].desc)-1); + strlcpy(list[i].desc, dev->description, sizeof(list[i].desc)); else - strncpy(list[i].desc, "No description available", sizeof(list[i].desc)-1); + strlcpy(list[i].desc, "No description available", sizeof(list[i].desc)); } /* free device list */ @@ -4018,4 +4181,213 @@ if (dev->eth_api == ETH_API_NAT) sim_slirp_show ((SLIRP *)dev->handle, st); #endif } + +static +t_stat eth_test_crc32 (DEVICE *dptr) +{ +int errors = 0; +int val; +uint8 data[12]; +static uint32 valcrc32[] = { + 0x7BD5C66F, 0x92C4D707, 0x7286E2FE, 0x9B97F396, 0x69738F4D, 0x80629E25, 0x6020ABDC, 0x8931BAB4, + 0x5E99542B, 0xB7884543, 0x57CA70BA, 0xBEDB61D2, 0x4C3F1D09, 0xA52E0C61, 0x456C3998, 0xAC7D28F0, + 0x314CE2E7, 0xD85DF38F, 0x381FC676, 0xD10ED71E, 0x23EAABC5, 0xCAFBBAAD, 0x2AB98F54, 0xC3A89E3C, + 0x140070A3, 0xFD1161CB, 0x1D535432, 0xF442455A, 0x06A63981, 0xEFB728E9, 0x0FF51D10, 0xE6E40C78, + 0xEEE78F7F, 0x07F69E17, 0xE7B4ABEE, 0x0EA5BA86, 0xFC41C65D, 0x1550D735, 0xF512E2CC, 0x1C03F3A4, + 0xCBAB1D3B, 0x22BA0C53, 0xC2F839AA, 0x2BE928C2, 0xD90D5419, 0x301C4571, 0xD05E7088, 0x394F61E0, + 0xA47EABF7, 0x4D6FBA9F, 0xAD2D8F66, 0x443C9E0E, 0xB6D8E2D5, 0x5FC9F3BD, 0xBF8BC644, 0x569AD72C, + 0x813239B3, 0x682328DB, 0x88611D22, 0x61700C4A, 0x93947091, 0x7A8561F9, 0x9AC75400, 0x73D64568, + 0x8AC0520E, 0x63D14366, 0x8393769F, 0x6A8267F7, 0x98661B2C, 0x71770A44, 0x91353FBD, 0x78242ED5, + 0xAF8CC04A, 0x469DD122, 0xA6DFE4DB, 0x4FCEF5B3, 0xBD2A8968, 0x543B9800, 0xB479ADF9, 0x5D68BC91, + 0xC0597686, 0x294867EE, 0xC90A5217, 0x201B437F, 0xD2FF3FA4, 0x3BEE2ECC, 0xDBAC1B35, 0x32BD0A5D, + 0xE515E4C2, 0x0C04F5AA, 0xEC46C053, 0x0557D13B, 0xF7B3ADE0, 0x1EA2BC88, 0xFEE08971, 0x17F19819, + 0x1FF21B1E, 0xF6E30A76, 0x16A13F8F, 0xFFB02EE7, 0x0D54523C, 0xE4454354, 0x040776AD, 0xED1667C5, + 0x3ABE895A, 0xD3AF9832, 0x33EDADCB, 0xDAFCBCA3, 0x2818C078, 0xC109D110, 0x214BE4E9, 0xC85AF581, + 0x556B3F96, 0xBC7A2EFE, 0x5C381B07, 0xB5290A6F, 0x47CD76B4, 0xAEDC67DC, 0x4E9E5225, 0xA78F434D, + 0x7027ADD2, 0x9936BCBA, 0x79748943, 0x9065982B, 0x6281E4F0, 0x8B90F598, 0x6BD2C061, 0x82C3D109, + 0x428FE8EC, 0xAB9EF984, 0x4BDCCC7D, 0xA2CDDD15, 0x5029A1CE, 0xB938B0A6, 0x597A855F, 0xB06B9437, + 0x67C37AA8, 0x8ED26BC0, 0x6E905E39, 0x87814F51, 0x7565338A, 0x9C7422E2, 0x7C36171B, 0x95270673, + 0x0816CC64, 0xE107DD0C, 0x0145E8F5, 0xE854F99D, 0x1AB08546, 0xF3A1942E, 0x13E3A1D7, 0xFAF2B0BF, + 0x2D5A5E20, 0xC44B4F48, 0x24097AB1, 0xCD186BD9, 0x3FFC1702, 0xD6ED066A, 0x36AF3393, 0xDFBE22FB, + 0xD7BDA1FC, 0x3EACB094, 0xDEEE856D, 0x37FF9405, 0xC51BE8DE, 0x2C0AF9B6, 0xCC48CC4F, 0x2559DD27, + 0xF2F133B8, 0x1BE022D0, 0xFBA21729, 0x12B30641, 0xE0577A9A, 0x09466BF2, 0xE9045E0B, 0x00154F63, + 0x9D248574, 0x7435941C, 0x9477A1E5, 0x7D66B08D, 0x8F82CC56, 0x6693DD3E, 0x86D1E8C7, 0x6FC0F9AF, + 0xB8681730, 0x51790658, 0xB13B33A1, 0x582A22C9, 0xAACE5E12, 0x43DF4F7A, 0xA39D7A83, 0x4A8C6BEB, + 0xB39A7C8D, 0x5A8B6DE5, 0xBAC9581C, 0x53D84974, 0xA13C35AF, 0x482D24C7, 0xA86F113E, 0x417E0056, + 0x96D6EEC9, 0x7FC7FFA1, 0x9F85CA58, 0x7694DB30, 0x8470A7EB, 0x6D61B683, 0x8D23837A, 0x64329212, + 0xF9035805, 0x1012496D, 0xF0507C94, 0x19416DFC, 0xEBA51127, 0x02B4004F, 0xE2F635B6, 0x0BE724DE, + 0xDC4FCA41, 0x355EDB29, 0xD51CEED0, 0x3C0DFFB8, 0xCEE98363, 0x27F8920B, 0xC7BAA7F2, 0x2EABB69A, + 0x26A8359D, 0xCFB924F5, 0x2FFB110C, 0xC6EA0064, 0x340E7CBF, 0xDD1F6DD7, 0x3D5D582E, 0xD44C4946, + 0x03E4A7D9, 0xEAF5B6B1, 0x0AB78348, 0xE3A69220, 0x1142EEFB, 0xF853FF93, 0x1811CA6A, 0xF100DB02, + 0x6C311115, 0x8520007D, 0x65623584, 0x8C7324EC, 0x7E975837, 0x9786495F, 0x77C47CA6, 0x9ED56DCE, + 0x497D8351, 0xA06C9239, 0x402EA7C0, 0xA93FB6A8, 0x5BDBCA73, 0xB2CADB1B, 0x5288EEE2, 0xBB99FF8A}; + +for (val=0; val <= 0xFF; val++) { + memset (data, val, sizeof (data)); + if (valcrc32[val] != eth_crc32 (0, data, sizeof (data))) { + printf("Unexpected CRC for %d byte buffer containing 0x%02X. Expected %08X, got %08X\n", + (int)sizeof (data), val, valcrc32[val], eth_crc32 (0, data, sizeof (data))); + ++errors; + } + } +return (errors == 0) ? SCPE_OK : SCPE_IERR; +} + +static +t_stat eth_test_bpf (DEVICE *dptr) +{ +int errors = 0; +#ifdef USE_BPF +t_stat r; +DEVICE eth_tst; +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; +char buf[116+66*ETH_FILTER_MAX]; +char mac[20]; +ETH_MAC filter_address[3] = { + {0x04, 0x05, 0x06, 0x07, 0x08, 0x09}, + {0x09, 0x00, 0x2B, 0x02, 0x01, 0x07}, + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + }; +int addr_count; +ETH_MAC physical_addr = {0x04, 0x05, 0x06, 0x07, 0x08, 0x09}; +ETH_MAC host_nic_phy_hw_addr = {0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; +ETH_MAC *host_phy_addr_list[2] = {&host_nic_phy_hw_addr, NULL}; +int host_phy_addr_listindex; +ETH_MULTIHASH hash = {0x01, 0x40, 0x00, 0x00, 0x48, 0x88, 0x40, 0x00}; +ETH_MULTIHASH *hash_list[2] = {&hash, NULL}; +int hash_listindex; +int bpf_count = 0; +int bpf_construct_error_count = 0; +int bpf_compile_error_count = 0; +int bpf_compile_skip_count = 0; +#define SIM_PRINT_BPF_ARGUMENTS \ + if (1) { \ + sim_printf ("Eth: Input to BPF string construction:\n"); \ + sim_printf ("Eth: Reflections: %d\n", reflections); \ + sim_printf ("Eth: Filter Set:\n"); \ + for (i = 0; i < addr_count; i++) { \ + eth_mac_fmt(&filter_address[i], mac); \ + sim_printf ("Eth: Addr[%d]: %s\n", i, mac); \ + } \ + if (all_multicast) \ + sim_printf ("Eth: All Multicast\n"); \ + if (promiscuous) \ + sim_printf ("Eth: Promiscuous\n"); \ + if (hash_list[hash_listindex]) \ + sim_printf ("Eth: Multicast Hash: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",\ + (*hash_list[hash_listindex])[0], (*hash_list[hash_listindex])[1], (*hash_list[hash_listindex])[2], (*hash_list[hash_listindex])[3], \ + (*hash_list[hash_listindex])[4], (*hash_list[hash_listindex])[5], (*hash_list[hash_listindex])[6], (*hash_list[hash_listindex])[7]);\ + if (host_phy_addr_list[host_phy_addr_listindex]) { \ + eth_mac_fmt(host_phy_addr_list[host_phy_addr_listindex], mac);\ + sim_printf ("Eth: host_nic_phy_hw_addr: %s\n", mac); \ + } \ + } + + +memset (ð_tst, 0, sizeof(eth_tst)); +eth_device_count = _eth_devices(ETH_MAX_DEVICE, eth_list); +eth_opened = 0; +for (eth_num=0; eth_numname, eth_num, sim_error_text (r)); + continue; + } + ++eth_opened; + 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; + } + else { + if (sim_switches & SWMASK('D')) { + SIM_PRINT_BPF_ARGUMENTS; + sim_printf ("Eth: BPF string is: |%s|\n", buf); + } + 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; + } + } + } + } + } + } + } + eth_close(&dev); + } + +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) + sim_printf ("BPF Construct Errors: %d\n", bpf_construct_error_count); +if (bpf_compile_error_count) + sim_printf ("BPF Compile Errors: %d\n", bpf_compile_error_count); +if (bpf_compile_skip_count) + sim_printf ("BPF Compile Skipped: %d\n", bpf_compile_skip_count); +#endif /* USE_BPF */ +return (errors == 0) ? SCPE_OK : SCPE_IERR; +} + +#include + +t_stat sim_ether_test (DEVICE *dptr) +{ +t_stat stat = SCPE_OK; +SIM_TEST_INIT; + +sim_printf ("Testing %s device sim_ether APIs\n", dptr->name); + +SIM_TEST(eth_test_crc32 (dptr)); +SIM_TEST(eth_test_bpf (dptr)); +return stat; +} #endif /* USE_NETWORK */ diff --git a/sim_ether.h b/sim_ether.h index b331086d..598f8b89 100644 --- a/sim_ether.h +++ b/sim_ether.h @@ -349,7 +349,7 @@ t_stat eth_filter_hash (ETH_DEV* dev, int addr_count, /* set filter on incomin ETH_MULTIHASH* const hash); t_stat eth_check_address_conflict (ETH_DEV* dev, ETH_MAC* const address); -int eth_devices (int max, ETH_LIST* dev); /* get ethernet devices on host */ +const char *eth_version (void); /* Version of dynamically loaded library (pcap) */ void eth_setcrc (ETH_DEV* dev, int need_crc); /* enable/disable CRC mode */ t_stat eth_set_async (ETH_DEV* dev, int latency); /* set read behavior to be async */ t_stat eth_clr_async (ETH_DEV* dev); /* set read behavior to be not async */ @@ -378,8 +378,13 @@ void ethq_insert_data(ETH_QUE* que, int32 type, /* insert item into FIFO const uint8 *data, int used, size_t len, size_t crc_len, const uint8 *crc_data, int32 status); t_stat ethq_destroy(ETH_QUE* que); /* release FIFO queue */ - const char *eth_capabilities(void); +t_stat sim_ether_test (DEVICE *dptr); /* unit test routine */ + +#if !defined(SIM_TEST_INIT) /* Need stubs for test APIs */ +#define SIM_TEST_INIT +#define SIM_TEST(xxx) +#endif #ifdef __cplusplus }