diff --git a/sim_ether.c b/sim_ether.c index 2cd6b1d8..eda0896b 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -562,6 +562,11 @@ void eth_packet_trace(ETH_DEV* dev, const uint8 *msg, int len, char* txt) eth_packet_trace_ex(dev, msg, len, txt, 0, dev->dbit); } +void eth_packet_trace_detail(ETH_DEV* dev, const uint8 *msg, int len, char* txt) +{ + eth_packet_trace_ex(dev, msg, len, txt, 1 , dev->dbit); +} + char* eth_getname(int number, char* name) { ETH_LIST list[ETH_MAX_DEVICE]; @@ -2070,12 +2075,23 @@ fprintf (st, " sim> ATTACH %s en0\n\n", dptr->name); return SCPE_OK; } +static int _eth_rand_byte() +{ +static int rand_initialized = 0; + +if (!rand_initialized) + srand((unsigned int)sim_os_msec()); +return (rand() & 0xFF); +} + t_stat eth_check_address_conflict (ETH_DEV* dev, ETH_MAC* const mac) { ETH_PACK send, recv; t_stat status; +uint32 i; int responses = 0; +uint32 offset, function; char mac_string[32]; eth_mac_fmt(mac, mac_string); @@ -2144,13 +2160,19 @@ sim_debug(dev->dbit, dev->dptr, "Determining Address Conflict for MAC address: % /* build a loopback forward request packet */ memset (&send, 0, sizeof(ETH_PACK)); send.len = ETH_MIN_PACKET; /* minimum packet size */ +for (i=0; i 0); @@ -2190,7 +2219,7 @@ t_stat eth_reflect(ETH_DEV* dev) /* 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. */ -ETH_MAC mac = {0xfe,0xff,0xff,0xff,0xff,0xfe}; +static ETH_MAC mac = {0xfe,0xff,0xff,0xff,0xff,0xfe}; sim_debug(dev->dbit, dev->dptr, "Determining Reflections...\n"); @@ -2215,14 +2244,18 @@ if (!packet) return SCPE_ARG; /* make sure packet is acceptable length */ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) { int loopback_self_frame = LOOPBACK_SELF_FRAME(packet->msg, packet->msg); + int loopback_physical_response = LOOPBACK_PHYSICAL_RESPONSE(dev, packet->msg); eth_packet_trace (dev, packet->msg, packet->len, "writing"); /* record sending of loopback packet (done before actual send to avoid race conditions with receiver) */ - if (loopback_self_frame) { - if (dev->have_host_nic_phy_addr) { + if (loopback_self_frame || loopback_physical_response) { + /* Direct loopback responses to the host physical address since our physical address + may not have been learned yet. */ + if (loopback_self_frame && dev->have_host_nic_phy_addr) { memcpy(&packet->msg[6], dev->host_nic_phy_hw_addr, sizeof(ETH_MAC)); memcpy(&packet->msg[18], dev->host_nic_phy_hw_addr, sizeof(ETH_MAC)); + eth_packet_trace (dev, packet->msg, packet->len, "writing-fixed"); } #ifdef USE_READER_THREAD pthread_mutex_lock (&dev->self_lock); @@ -2772,6 +2805,65 @@ switch (IP->proto) { } } +static int +_eth_process_loopback (ETH_DEV* dev, const u_char* data, uint32 len) +{ +int protocol = data[12] | (data[13] << 8); +ETH_PACK response; +uint32 offset, function; + +if (protocol != 0x0090) /* !ethernet loopback */ + return 0; + +if (LOOPBACK_REFLECTION_TEST_PACKET(dev, data)) + return 0; /* Ignore reflection check packet */ + +offset = 16 + (data[14] | (data[15] << 8)); +if (offset >= len) + return 0; +function = data[offset] | (data[offset+1] << 8); + +if (function != 2) /*forward*/ + return 0; + +/* The only packets we should be responding to are ones which + we received due to them being directed to our physical MAC address, + OR the Broadcast address OR to a Multicast address we're listening to + (we may receive others if we're in promiscuous mode, but shouldn't + respond to them) */ +if ((0 == (data[0]&1)) && /* Multicast or Broadcast */ + (0 != memcmp(dev->filter_address[0], data, sizeof(ETH_MAC)))) + return 0; + +/* Attempts to forward to multicast or broadcast addresses are explicitly + ignored by consuming the packet and doing nothing else */ +if (data[offset+2]&1) + return 1; + +eth_packet_trace (dev, data, len, "rcvd"); + +sim_debug(dev->dbit, dev->dptr, "_eth_process_loopback()\n"); + +/* create forward response packet */ +memset(&response, 0, sizeof(response)); +response.len = len; +memcpy(response.msg, data, len); +memcpy(&response.msg[0], &response.msg[offset+2], sizeof(ETH_MAC)); +memcpy(&response.msg[6], dev->filter_address[0], sizeof(ETH_MAC)); +offset += 8 - 16; /* Account for the Ethernet Header and Offset value in this number */ +response.msg[14] = offset & 0xFF; +response.msg[15] = (offset >> 8) & 0xFF; + +/* send response packet */ +eth_write(dev, &response, NULL); + +eth_packet_trace(dev, response.msg, response.len, ((function == 1) ? "loopbackreply" : "loopbackforward")); + +++dev->loopback_packets_processed; + +return 1; +} + static void _eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data) { @@ -2781,10 +2873,12 @@ int from_me = 0; int i; int bpf_used; -if ((dev->have_host_nic_phy_addr) && - (LOOPBACK_PHYSICAL_RESPONSE(dev->host_nic_phy_hw_addr, dev->physical_addr, data))) { +if (LOOPBACK_PHYSICAL_RESPONSE(dev, data)) { u_char *datacopy = (u_char *)malloc(header->len); + /* Since we changed the outgoing loopback packet to have the physical MAC address of the + host's interface instead of the programmatically set physical address of this pseudo + device, we restore parts of the modified packet back as needed */ memcpy(datacopy, data, header->len); memcpy(datacopy, dev->physical_addr, sizeof(ETH_MAC)); memcpy(datacopy+18, dev->physical_addr, sizeof(ETH_MAC)); @@ -2832,8 +2926,7 @@ switch (dev->eth_api) { /* detect reception of loopback packet to our physical address */ if ((LOOPBACK_SELF_FRAME(dev->physical_addr, data)) || - (dev->have_host_nic_phy_addr && - LOOPBACK_PHYSICAL_REFLECTION(dev->host_nic_phy_hw_addr, data))) { + (LOOPBACK_PHYSICAL_REFLECTION(dev, data))) { #ifdef USE_READER_THREAD pthread_mutex_lock (&dev->self_lock); #endif @@ -2860,6 +2953,8 @@ if (bpf_used ? to_me : (to_me && !from_me)) { ++dev->jumbo_truncated; return; } + if (_eth_process_loopback(dev, data, header->len)) + return; #if defined (USE_READER_THREAD) if (1) { int crc_len = 0; @@ -3415,6 +3510,8 @@ if (dev->packets_sent) fprintf(st, " Packets Sent: %d\n", dev->packets_sent); if (dev->packets_received) fprintf(st, " Packets Received: %d\n", dev->packets_received); +if (dev->loopback_packets_processed) + fprintf(st, " Loopback Packets: %d\n", dev->loopback_packets_processed); #if defined(USE_READER_THREAD) fprintf(st, " Asynch Interrupts: %s\n", dev->asynch_io?"Enabled":"Disabled"); if (dev->asynch_io) diff --git a/sim_ether.h b/sim_ether.h index fc14c0fb..f1dd6397 100644 --- a/sim_ether.h +++ b/sim_ether.h @@ -158,31 +158,42 @@ #define ETH_FRAME_SIZE (ETH_MAX_PACKET+ETH_CRC_SIZE) /* ethernet maximum frame size */ #define ETH_MIN_JUMBO_FRAME ETH_MAX_PACKET /* Threshold size for Jumbo Frame Processing */ -#define LOOPBACK_SELF_FRAME(phy_mac, msg) \ - (((msg)[12] == 0x90) && ((msg)[13] == 0x00) && \ - ((msg)[14] == 0x00) && ((msg)[15] == 0x00) && \ - ((msg)[16] == 0x02) && ((msg)[17] == 0x00) && \ - ((msg)[24] == 0x01) && ((msg)[25] == 0x00) && \ - (memcmp(phy_mac, (msg), 6) == 0) && \ - (memcmp(phy_mac, (msg)+6, 6) == 0) && \ - (memcmp(phy_mac, (msg)+18, 6) == 0)) +#define LOOPBACK_SELF_FRAME(phy_mac, msg) \ + (((msg)[12] == 0x90) && ((msg)[13] == 0x00) && /* Ethernet Loopback */ \ + ((msg)[16] == 0x02) && ((msg)[17] == 0x00) && /* Forward Function */ \ + ((msg)[24] == 0x01) && ((msg)[25] == 0x00) && /* Next Function - Reply */ \ + (memcmp(phy_mac, (msg), 6) == 0) && /* Ethernet Destination */ \ + (memcmp(phy_mac, (msg)+6, 6) == 0) && /* Ethernet Source */ \ + (memcmp(phy_mac, (msg)+18, 6) == 0)) /* Forward Address */ -#define LOOPBACK_PHYSICAL_RESPONSE(host_phy, phy_mac, msg) \ - (((msg)[12] == 0x90) && ((msg)[13] == 0x00) && \ - ((msg)[14] == 0x08) && ((msg)[15] == 0x00) && \ - ((msg)[16] == 0x02) && ((msg)[17] == 0x00) && \ - ((msg)[24] == 0x01) && ((msg)[25] == 0x00) && \ - (memcmp(host_phy, (msg)+18, 6) == 0) && \ - (memcmp(host_phy, (msg), 6) == 0) && \ - (memcmp(phy_mac, (msg)+6, 6) == 0)) +#define LOOPBACK_PHYSICAL_RESPONSE(dev, msg) \ + ((dev->have_host_nic_phy_addr) && \ + ((msg)[12] == 0x90) && ((msg)[13] == 0x00) && /* Ethernet Loopback */ \ + ((msg)[14] == 0x08) && ((msg)[15] == 0x00) && /* Skipcount - 8 */ \ + ((msg)[16] == 0x02) && ((msg)[17] == 0x00) && /* Last Function - Forward */ \ + ((msg)[24] == 0x01) && ((msg)[25] == 0x00) && /* Function - Reply */ \ + (memcmp(dev->host_nic_phy_hw_addr, (msg)+18, 6) == 0) && /* Forward Address - Host MAC */\ + (memcmp(dev->host_nic_phy_hw_addr, (msg), 6) == 0) && /* Ethernet Source - Host MAC */\ + (memcmp(dev->physical_addr, (msg)+6, 6) == 0)) /* Ethernet Source */ -#define LOOPBACK_PHYSICAL_REFLECTION(host_phy, msg) \ - (((msg)[12] == 0x90) && ((msg)[13] == 0x00) && \ - ((msg)[14] == 0x00) && ((msg)[15] == 0x00) && \ - ((msg)[16] == 0x02) && ((msg)[17] == 0x00) && \ - ((msg)[24] == 0x01) && ((msg)[25] == 0x00) && \ - (memcmp(host_phy, (msg)+6, 6) == 0) && \ - (memcmp(host_phy, (msg)+18, 6) == 0)) +#define LOOPBACK_PHYSICAL_REFLECTION(dev, msg) \ + ((dev->have_host_nic_phy_addr) && \ + ((msg)[12] == 0x90) && ((msg)[13] == 0x00) && /* Ethernet Loopback */ \ + ((msg)[16] == 0x02) && ((msg)[17] == 0x00) && /* Forward Function */ \ + ((msg)[24] == 0x01) && ((msg)[25] == 0x00) && /* Next Function - Reply */ \ + (memcmp(dev->host_nic_phy_hw_addr, (msg)+6, 6) == 0) && /* Ethernet Source - Host MAC */\ + (memcmp(dev->host_nic_phy_hw_addr, (msg)+18, 6) == 0)) /* Forward Address - Host MAC */ + +#define LOOPBACK_REFLECTION_TEST_PACKET(dev, msg) \ + ((dev->have_host_nic_phy_addr) && \ + ((msg)[12] == 0x90) && ((msg)[13] == 0x00) && /* Ethernet Loopback */ \ + ((msg)[14] == 0x00) && ((msg)[15] == 0x00) && /* Skipcount - 0 */ \ + ((msg)[16] == 0x02) && ((msg)[17] == 0x00) && /* Forward Function */ \ + ((msg)[24] == 0x01) && ((msg)[25] == 0x00) && /* Next Function - Reply */ \ + ((msg)[00] == 0xFE) && ((msg)[01] == 0xFF) && /* Ethernet Destination - Reflection Test MAC */\ + ((msg)[02] == 0xFF) && ((msg)[03] == 0xFF) && \ + ((msg)[04] == 0xFF) && ((msg)[05] == 0xFE) && \ + (memcmp(dev->host_nic_phy_hw_addr, (msg)+6, 6) == 0)) /* Ethernet Source - Host MAC */ struct eth_packet { uint8 msg[ETH_FRAME_SIZE]; /* ethernet frame (message) */ @@ -252,6 +263,7 @@ struct eth_device { uint32 jumbo_truncated; /* Giant Frames too big for capture buffer - Dropped */ uint32 packets_sent; /* Total Packets Sent */ uint32 packets_received; /* Total Packets Received */ + uint32 loopback_packets_processed; /* Total Loopback Packets Processed */ DEVICE* dptr; /* device ethernet is attached to */ uint32 dbit; /* debugging bit */ int reflections; /* packet reflections on interface */