/* * File: print.c * Description: This file contains the implementation of the print * utilities for the NLB KD extensions. * Author: Created by shouse, 1.4.01 */ #include "nlbkd.h" #include "utils.h" #include "print.h" /* * Function: PrintUsage * Description: Prints usage information for the specified context. * Author: Created by shouse, 1.5.01 */ void PrintUsage (ULONG dwContext) { /* Display the appropriate help. */ switch (dwContext) { case USAGE_ADAPTERS: dprintf("Usage: nlbadapters [verbosity]\n"); dprintf(" [verbosity]: 0 (LOW) Prints minimal detail for adapters in use (default)\n"); dprintf(" 1 (MEDIUM) Prints adapter state for adapters in use\n"); dprintf(" 2 (HIGH) Prints adapter state for ALL NLB adapter blocks\n"); break; case USAGE_ADAPTER: dprintf("Usage: nlbadapter [verbosity]\n"); dprintf(" [verbosity]: 0 (LOW) Prints minimal detail for the specified adapter\n"); dprintf(" 1 (MEDIUM) Prints adapter state for the specified adapter (default)\n"); dprintf(" 2 (HIGH) Recurses into NLB context with LOW verbosity\n"); break; case USAGE_CONTEXT: dprintf("Usage: nlbctxt [verbosity]\n"); dprintf(" [verbosity]: 0 (LOW) Prints fundamental NLB configuration and state (default)\n"); dprintf(" 1 (MEDIUM) Prints resource state and packet statistics\n"); dprintf(" 2 (HIGH) Recurses into parameters and load with LOW verbosity\n"); break; case USAGE_PARAMS: dprintf("Usage: nlbparams [verbosity]\n"); dprintf(" [verbosity]: 0 (LOW) Prints fundamental NLB configuration parameters (default)\n"); dprintf(" 1 (MEDIUM) Prints all configured port rules\n"); dprintf(" 2 (HIGH) Prints extra miscellaneous configuration\n"); break; case USAGE_LOAD: dprintf("Usage: nlbload [verbosity]\n"); dprintf(" [verbosity]: 0 (LOW) Prints fundamental load state and configuration\n"); dprintf(" 1 (MEDIUM) Prints the state of all port rules and bins\n"); dprintf(" 2 (HIGH) Prints the NLB heartbeat information\n"); break; case USAGE_RESP: dprintf("Usage: nlbresp [direction]\n"); dprintf(" [direction]: 0 (RECEIVE) Packet is on the receive path (default)\n"); dprintf(" 1 (SEND) Packet is on the send path\n"); break; case USAGE_CONNQ: dprintf("Usage: nlbconnq [max entries]\n"); dprintf(" [max entries]: Maximum number of entries to print (default is ALL)\n"); break; case USAGE_MAP: dprintf("Usage: nlbmap [protocol] [packet type]\n"); dprintf(" [protocol]: TCP or UDP (default is TCP)\n"); dprintf(" [packet type]: For TCP connections, one of SYN, DATA, FIN or RST (default is SYN)\n"); dprintf("\n"); dprintf(" IP Address can be in dotted notation or network byte order DWORDs\n"); break; default: dprintf("No usage information available.\n"); break; } } /* * Function: PrintAdapter * Description: Prints the contents of the MAIN_ADAPTER structure at the specified verbosity. * LOW (0) prints only the adapter address and device name. * MEDIUM (1) additionally prints the status flags (init, bound, annouce, etc.). * HIGH (2) recurses into the context structure and prints it at MEDIUM verbosity. * Author: Created by shouse, 1.5.01 */ void PrintAdapter (ULONG64 pAdapter, ULONG dwVerbosity) { WCHAR szString[256]; ULONG dwValue; ULONG64 pAddr; /* Make sure the address is non-NULL. */ if (!pAdapter) { dprintf("Error: NLB adapter block is NULL.\n"); return; } dprintf("NLB Adapter Block 0x%p\n", pAdapter); /* Get the MAIN_ADAPTER_CODE from the structure to make sure that this address indeed points to a valid NLB adapter block. */ GetFieldValue(pAdapter, MAIN_ADAPTER, MAIN_ADAPTER_FIELD_CODE, dwValue); if (dwValue != MAIN_ADAPTER_CODE) { dprintf(" Error: Invalid NLB adapter block. Wrong code found (0x%08x).\n", dwValue); return; } /* Retrieve the used/unused state of the adapter. */ GetFieldValue(pAdapter, MAIN_ADAPTER, MAIN_ADAPTER_FIELD_USED, dwValue); if (!dwValue) dprintf(" This adapter is unused.\n"); else { /* Get the pointer to and length of the device to which NLB is bound. */ GetFieldValue(pAdapter, MAIN_ADAPTER, MAIN_ADAPTER_FIELD_NAME_LENGTH, dwValue); GetFieldValue(pAdapter, MAIN_ADAPTER, MAIN_ADAPTER_FIELD_NAME, pAddr); /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szString, dwValue); dprintf(" Physical device name: %ls\n", szString); } /* If we're printing at low verbosity, bail out here. */ if (dwVerbosity == VERBOSITY_LOW) return; /* Determine whether or not the adapter has been initialized. */ GetFieldValue(pAdapter, MAIN_ADAPTER, MAIN_ADAPTER_FIELD_INITED, dwValue); dprintf(" Context state initialized: %s\n", (dwValue) ? "Yes" : "No"); /* Determine whether or not NLB has been bound to the stack yet. */ GetFieldValue(pAdapter, MAIN_ADAPTER, MAIN_ADAPTER_FIELD_BOUND, dwValue); dprintf(" NLB bound to adapter: %s\n", (dwValue) ? "Yes" : "No"); /* Determine whether or not TCP/IP has been bound to the NLB virtual adapter or not. */ GetFieldValue(pAdapter, MAIN_ADAPTER, MAIN_ADAPTER_FIELD_ANNOUNCED, dwValue); dprintf(" NLB miniport announced: %s\n", (dwValue) ? "Yes" : "No"); /* Get the offset of the NLB context pointer. */ if (GetFieldOffset(MAIN_ADAPTER, MAIN_ADAPTER_FIELD_CONTEXT, &dwValue)) dprintf("Can't get offset of %s in %s\n", MAIN_ADAPTER_FIELD_CONTEXT, MAIN_ADAPTER); else { pAddr = pAdapter + dwValue; /* Retrieve the pointer. */ pAddr = GetPointerFromAddress(pAddr); dprintf(" %sNLB context: 0x%p\n", (pAddr && (dwVerbosity == VERBOSITY_HIGH)) ? "-" : (pAddr) ? "+" : " ", pAddr); } /* If we're printing at medium verbosity, bail out here. */ if (dwVerbosity == VERBOSITY_MEDIUM) return; /* Print the context information (always with LOW verbosity during recursion. */ if (pAddr) { dprintf("\n"); PrintContext(pAddr, VERBOSITY_LOW); } } /* * Function: PrintContext * Description: Prints the contents of the MAIN_CTXT structure at the specified verbosity. * LOW (0) prints fundamental NLB configuration and state. * MEDIUM (1) additionally prints the resource state (pools, allocations, etc). * HIGH (2) further prints other miscelaneous information. * Author: Created by shouse, 1.5.01 */ void PrintContext (ULONG64 pContext, ULONG dwVerbosity) { WCHAR szNICName[CVY_MAX_VIRTUAL_NIC]; ULONGLONG dwwValue; IN_ADDR dwIPAddr; CHAR * szString; UCHAR szMAC[6]; ULONG64 pAddr; ULONG dwValue; /* Make sure the address is non-NULL. */ if (!pContext) { dprintf("Error: NLB context block is NULL.\n"); return; } dprintf("NLB Context Block 0x%p\n", pContext); /* Get the MAIN_CTXT_CODE from the structure to make sure that this address indeed points to a valid NLB context block. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CODE, dwValue); if (dwValue != MAIN_CTXT_CODE) { dprintf(" Error: Invalid NLB context block. Wrong code found (0x%08x).\n", dwValue); return; } /* Get the offset of the NLB virtual NIC name. */ if (GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_VIRTUAL_NIC, &dwValue)) dprintf("Can't get offset of %s in %s\n", MAIN_CTXT_FIELD_VIRTUAL_NIC, MAIN_CTXT); else { pAddr = pContext + dwValue; /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szNICName, CVY_MAX_VIRTUAL_NIC); dprintf(" NLB virtual NIC name: %ls\n", szNICName); } /* Get the convoy enabled status. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_ENABLED, dwValue); dprintf(" NLB enabled: %s ", (dwValue) ? "Yes" : "No"); /* Get the draining status. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_DRAINING, dwValue); if (dwValue) dprintf("(Draining) "); /* Get the suspended status. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_SUSPENDED, dwValue); if (dwValue) dprintf("(Suspended) "); /* Get the stopping status. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_STOPPING, dwValue); if (dwValue) dprintf("(Stopping) "); dprintf("\n"); /* Get the adapter index. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_ADAPTER_ID, dwValue); dprintf(" NLB adapter ID: %u\n", dwValue); dprintf("\n"); /* Get the adapter medium. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_MEDIUM, dwValue); dprintf(" Network medium: %s\n", (dwValue == NdisMedium802_3) ? "802.3" : "FDDI"); /* Get the media connect status. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_MEDIA_CONNECT, dwValue); dprintf(" Network connect status: %s\n", (dwValue) ? "Connected" : "Disconnected"); /* Get the media connect status. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_FRAME_SIZE, dwValue); dprintf(" Frame size (MTU): %u\n", dwValue); /* Get the media connect status. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_MCAST_LIST_SIZE, dwValue); dprintf(" Multicast MAC list size: %u\n", dwValue); /* Determine dynamic MAC address support. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_MAC_OPTIONS, dwValue); dprintf(" Dynamic MAC address support: %s\n", (dwValue & NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE) ? "Yes" : "No"); dprintf("\n"); dprintf(" NDIS handles\n"); /* Get the NDIS bind handle. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_BIND_HANDLE, pAddr); dprintf(" Bind handle: 0x%p\n", pAddr); /* Get the NDIS unbind handle. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_UNBIND_HANDLE, pAddr); dprintf(" Unbind handle: 0x%p\n", pAddr); /* Get the NDIS MAC handle. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_MAC_HANDLE, pAddr); dprintf(" MAC handle: 0x%p\n", pAddr); /* Get the NDIS protocol handle. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_PROT_HANDLE, pAddr); dprintf(" Protocol handle: 0x%p\n", pAddr); dprintf("\n"); dprintf(" Cluster IP settings\n"); /* Get the cluster IP address, which is a DWORD, and convert it to a string. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CL_IP_ADDR, dwValue); dwIPAddr.S_un.S_addr = dwValue; szString = inet_ntoa(dwIPAddr); dprintf(" IP address: %s\n", szString); /* Get the cluster net mask, which is a DWORD, and convert it to a string. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CL_NET_MASK, dwValue); dwIPAddr.S_un.S_addr = dwValue; szString = inet_ntoa(dwIPAddr); dprintf(" Netmask: %s\n", szString); /* Get the offset of the cluster MAC address and retrieve the MAC from that address. */ if (GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_CL_MAC_ADDR, &dwValue)) dprintf("Can't get offset of %s in %s\n", MAIN_CTXT_FIELD_CL_MAC_ADDR, MAIN_CTXT); else { pAddr = pContext + dwValue; GetMAC(pAddr, szMAC, 6); dprintf(" MAC address: %02X-%02X-%02X-%02X-%02X-%02X\n", ((PUCHAR)(szMAC))[0], ((PUCHAR)(szMAC))[1], ((PUCHAR)(szMAC))[2], ((PUCHAR)(szMAC))[3], ((PUCHAR)(szMAC))[4], ((PUCHAR)(szMAC))[5]); } /* Get the cluster broadcast address, which is a DWORD, and convert it to a string. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CL_BROADCAST, dwValue); dwIPAddr.S_un.S_addr = dwValue; szString = inet_ntoa(dwIPAddr); dprintf(" Broadcast address: %s\n", szString); /* Get the IGMP multicast IP address, which is a DWORD, and convert it to a string. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_IGMP_MCAST_IP, dwValue); dwIPAddr.S_un.S_addr = dwValue; szString = inet_ntoa(dwIPAddr); dprintf(" IGMP multicast IP address: %s\n", szString); dprintf("\n"); dprintf(" Dedicated IP settings\n"); /* Get the dedicated IP address, which is a DWORD, and convert it to a string. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_DED_IP_ADDR, dwValue); dwIPAddr.S_un.S_addr = dwValue; szString = inet_ntoa(dwIPAddr); dprintf(" IP address: %s\n", szString); /* Get the dedicated net mask, which is a DWORD, and convert it to a string. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_DED_NET_MASK, dwValue); dwIPAddr.S_un.S_addr = dwValue; szString = inet_ntoa(dwIPAddr); dprintf(" Netmask: %s\n", szString); /* Get the dedicated broadcast address, which is a DWORD, and convert it to a string. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_DED_BROADCAST, dwValue); dwIPAddr.S_un.S_addr = dwValue; szString = inet_ntoa(dwIPAddr); dprintf(" Broadcast address: %s\n", szString); /* Get the offset of the dedicated MAC address and retrieve the MAC from that address. */ if (GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_DED_MAC_ADDR, &dwValue)) dprintf("Can't get offset of %s in %s\n", MAIN_CTXT_FIELD_DED_MAC_ADDR, MAIN_CTXT); else { pAddr = pContext + dwValue; GetMAC(pAddr, szMAC, 6); dprintf(" MAC address: %02X-%02X-%02X-%02X-%02X-%02X\n", ((PUCHAR)(szMAC))[0], ((PUCHAR)(szMAC))[1], ((PUCHAR)(szMAC))[2], ((PUCHAR)(szMAC))[3], ((PUCHAR)(szMAC))[4], ((PUCHAR)(szMAC))[5]); } dprintf("\n"); #if defined (SBH) dprintf(" Cluster MAC addresses\n"); /* Get the offset of the unicast MAC address and retrieve the MAC from that address. */ if (GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_UNICAST_MAC_ADDR, &dwValue)) dprintf("Can't get offset of %s in %s\n", MAIN_CTXT_FIELD_UNICAST_MAC_ADDR, MAIN_CTXT); else { pAddr = pContext + dwValue; GetMAC(pAddr, szMAC, 6); dprintf(" Unicast: %02X-%02X-%02X-%02X-%02X-%02X\n", ((PUCHAR)(szMAC))[0], ((PUCHAR)(szMAC))[1], ((PUCHAR)(szMAC))[2], ((PUCHAR)(szMAC))[3], ((PUCHAR)(szMAC))[4], ((PUCHAR)(szMAC))[5]); } /* Get the offset of the multicast MAC address and retrieve the MAC from that address. */ if (GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_MULTICAST_MAC_ADDR, &dwValue)) dprintf("Can't get offset of %s in %s\n", MAIN_CTXT_FIELD_MULTICAST_MAC_ADDR, MAIN_CTXT); else { pAddr = pContext + dwValue; GetMAC(pAddr, szMAC, 6); dprintf(" Multicast: %02X-%02X-%02X-%02X-%02X-%02X\n", ((PUCHAR)(szMAC))[0], ((PUCHAR)(szMAC))[1], ((PUCHAR)(szMAC))[2], ((PUCHAR)(szMAC))[3], ((PUCHAR)(szMAC))[4], ((PUCHAR)(szMAC))[5]); } /* Get the offset of the IGMP MAC address and retrieve the MAC from that address. */ if (GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_IGMP_MAC_ADDR, &dwValue)) dprintf("Can't get offset of %s in %s\n", MAIN_CTXT_FIELD_IGMP_MAC_ADDR, MAIN_CTXT); else { pAddr = pContext + dwValue; GetMAC(pAddr, szMAC, 6); dprintf(" IGMP: %02X-%02X-%02X-%02X-%02X-%02X\n", ((PUCHAR)(szMAC))[0], ((PUCHAR)(szMAC))[1], ((PUCHAR)(szMAC))[2], ((PUCHAR)(szMAC))[3], ((PUCHAR)(szMAC))[4], ((PUCHAR)(szMAC))[5]); } dprintf("\n"); #endif /* SBH */ /* Get the offset of the BDA teaming information for this context. */ if (GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_BDA_TEAMING, &dwValue)) dprintf("Can't get offset of %s in %s\n", MAIN_CTXT_FIELD_BDA_TEAMING, MAIN_CTXT); else { pAddr = pContext + dwValue; /* Print the bi-directional affinity teaming state. */ PrintBDAMember(pAddr); } dprintf("\n"); /* Get the current heartbeat period. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_PING_TIMEOUT, dwValue); dprintf(" Current heartbeat period: %u millisecond(s)\n", dwValue); /* Get the current IGMP join counter. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_IGMP_TIMEOUT, dwValue); dprintf(" Time since last IGMP join: %.1f second(s)\n", (float)(dwValue/1000.0)); /* If we're printing at low verbosity, go to the end and print the load and params pointers. */ if (dwVerbosity == VERBOSITY_LOW) goto end; dprintf("\n"); dprintf(" Send packet pools\n"); /* Get the state of the send packet pool. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_EXHAUSTED, dwValue); dprintf(" Pool exhausted: %s\n", (dwValue) ? "Yes" : "No"); /* Get the number of send packet pools allocated. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_SEND_POOLS_ALLOCATED, dwValue); dprintf(" Pools allocated: %u\n", dwValue); /* Get the number of send packets allocated. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_SEND_PACKETS_ALLOCATED, dwValue); dprintf(" Packets allocated: %u\n", dwValue); /* Get the current send packet pool. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_SEND_POOL_CURRENT, dwValue); dprintf(" Current pool: %u\n", dwValue); /* Get the number of pending send packets (outstanding). */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_SEND_OUTSTANDING, dwValue); dprintf(" Packets outstanding: %u\n", dwValue); dprintf("\n"); dprintf(" Receive packet pools\n"); /* Get the receive "out of resoures" counter. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_RECV_NO_BUF, dwValue); dprintf(" Allocation failures: %u\n", dwValue); /* Get the number of receive packet pools allocated. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_RECV_POOLS_ALLOCATED, dwValue); dprintf(" Pools allocated: %u\n", dwValue); /* Get the number of receive packets allocated. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_RECV_PACKETS_ALLOCATED, dwValue); dprintf(" Packets allocated: %u\n", dwValue); /* Get the current receive packet pool. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_RECV_POOL_CURRENT, dwValue); dprintf(" Current pool: %u\n", dwValue); /* Get the number of pending receive packets (outstanding). */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_RECV_OUTSTANDING, dwValue); dprintf(" Packets outstanding: %u\n", dwValue); dprintf("\n"); dprintf(" Ping/IGMP packet pool (not accurate yet)\n"); /* Get the receive "out of resoures" counter. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_PING_NO_BUF, dwValue); dprintf(" Allocation failures: %u\n", dwValue); /* Get the number of ping/igmp packets allocated. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_PING_PACKETS_ALLOCATED, dwValue); dprintf(" Packets allocated: %u\n", dwValue); /* Get the number of pending ping/igmp packets (outstanding). */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_PING_OUTSTANDING, dwValue); dprintf(" Packets outstanding: %u\n", dwValue); dprintf("\n"); dprintf(" Receive buffer pools\n"); /* Get the number of receive buffer pools allocated. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_BUF_POOLS_ALLOCATED, dwValue); dprintf(" Pools allocated: %u\n", dwValue); /* Get the number of receive buffers allocated. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_BUFS_ALLOCATED, dwValue); dprintf(" Buffers allocated: %u\n", dwValue); /* Get the number of pending receive buffers (outstanding). */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_BUFS_OUTSTANDING, dwValue); dprintf(" Buffers outstanding: %u\n", dwValue); dprintf("\n"); dprintf(" NLB Main Protocol Reserved buffers\n"); /* Get the address of the resp lookaside list, then use it to get the size of the list and the total number of allocations and frees. */ GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_RESP, &dwValue); pAddr = pContext + dwValue; GetFieldValue(pAddr, GENERAL_LOOKASIDE, GENERAL_LOOKASIDE_FIELD_ALLOCATES, dwValue); dprintf(" Total allocations: %u\n", dwValue); GetFieldValue(pAddr, GENERAL_LOOKASIDE, GENERAL_LOOKASIDE_FIELD_FREES, dwValue); dprintf(" Total frees: %u\n", dwValue); GetFieldValue(pAddr, GENERAL_LOOKASIDE, GENERAL_LOOKASIDE_FIELD_SIZE, dwValue); dprintf(" Current lookaside list size: %u\n", dwValue); dprintf("\n"); dprintf(" Sent Received\n"); dprintf(" Statistics ---------- ----------\n"); /* Get the number of successful sends. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_XMIT_OK, dwValue); dprintf(" Successful: %10u", dwValue); /* Get the number of successful receives. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_RECV_OK, dwValue); dprintf(" %10u\n", dwValue); /* Get the number of unsuccessful sends. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_XMIT_ERROR, dwValue); dprintf(" Unsuccessful: %10u", dwValue); /* Get the number of unsuccessful receives. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_RECV_ERROR, dwValue); dprintf(" %10u\n", dwValue); /* Get the number of directed frames transmitted. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_XMIT_FRAMES_DIR, dwValue); dprintf(" Directed packets: %10u", dwValue); /* Get the number of directed frames received. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_RECV_FRAMES_DIR, dwValue); dprintf(" %10u\n", dwValue); /* Get the number of directed bytes transmitted. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_XMIT_BYTES_DIR, dwwValue); dprintf(" Directed bytes: %10u", dwwValue); /* Get the number of directed bytes received. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_RECV_BYTES_DIR, dwwValue); dprintf(" %10u\n", dwValue); /* Get the number of multicast frames transmitted. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_XMIT_FRAMES_MCAST, dwValue); dprintf(" Multicast packets: %10u", dwValue); /* Get the number of multicast frames received. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_RECV_FRAMES_MCAST, dwValue); dprintf(" %10u\n", dwValue); /* Get the number of multicast bytes transmitted. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_XMIT_BYTES_MCAST, dwwValue); dprintf(" Multicast bytes: %10u", dwwValue); /* Get the number of multicast bytes received. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_RECV_BYTES_MCAST, dwwValue); dprintf(" %10u\n", dwValue); /* Get the number of broadcast frames transmitted. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_XMIT_FRAMES_BCAST, dwValue); dprintf(" Broadcast packets: %10u", dwValue); /* Get the number of broadcast frames received. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_RECV_FRAMES_BCAST, dwValue); dprintf(" %10u\n", dwValue); /* Get the number of broadcast bytes transmitted. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_XMIT_BYTES_BCAST, dwwValue); dprintf(" Broadcast bytes: %10u", dwwValue); /* Get the number of broadcast bytes received. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CNTR_RECV_BYTES_BCAST, dwwValue); dprintf(" %10u\n", dwValue); end: dprintf("\n"); /* Get the pointer to the NLB load. */ GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_LOAD, &dwValue); pAddr = pContext + dwValue; dprintf(" %sNLB load: 0x%p\n", (pAddr && (dwVerbosity == VERBOSITY_HIGH)) ? "-" : (pAddr) ? "+" : " ", pAddr); /* Print the load information if verbosity is high. */ if (pAddr && (dwVerbosity == VERBOSITY_HIGH)) { dprintf("\n"); PrintLoad(pAddr, VERBOSITY_LOW); dprintf("\n"); } /* Get the pointer to the NLB parameters. */ GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_PARAMS, &dwValue); pAddr = pContext + dwValue; dprintf(" %sNLB parameters: 0x%p ", (pAddr && (dwVerbosity == VERBOSITY_HIGH)) ? "-" : (pAddr) ? "+" : " ", pAddr); /* Get the validity of the NLB parameter block. */ GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_PARAMS_VALID, dwValue); dprintf("(%s)\n", (dwValue) ? "Valid" : "Invalid"); /* Print the parameter information if verbosity is high. */ if (pAddr && (dwVerbosity == VERBOSITY_HIGH)) { dprintf("\n"); PrintParams(pAddr, VERBOSITY_LOW); } } /* * Function: PrintParams * Description: Prints the contents of the CVY_PARAMS structure at the specified verbosity. * LOW (0) prints fundamental configuration parameters. * MEDIUM (1) prints all configured port rules. * HIGH (2) prints other miscellaneous configuration. * Author: Created by shouse, 1.21.01 */ void PrintParams (ULONG64 pParams, ULONG dwVerbosity) { WCHAR szString[256]; ULONG64 pAddr; ULONG dwValue; /* Make sure the address is non-NULL. */ if (!pParams) { dprintf("Error: NLB parameter block is NULL.\n"); return; } /* Get the parameter version number. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_VERSION, dwValue); dprintf("NLB Parameters Block 0x%p (Version %d)\n", pParams, dwValue); /* Get the host priority. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_HOST_PRIORITY, dwValue); dprintf(" Host priority: %u\n", dwValue); /* Get the initial cluster state flag. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_INITIAL_STATE, dwValue); dprintf(" Initial cluster state: %s\n", (dwValue) ? "Active" : "Inactive"); dprintf("\n"); /* Get the multicast support flag. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_MULTICAST_SUPPORT, dwValue); dprintf(" Multicast support enabled: %s\n", (dwValue) ? "Yes" : "No"); /* Get the IGMP support flag. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_IGMP_SUPPORT, dwValue); dprintf(" IGMP multicast support enabled: %s\n", (dwValue) ? "Yes" : "No"); dprintf("\n"); dprintf(" Remote control settings\n"); /* Get the remote control support flag. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_REMOTE_CONTROL_ENABLED, dwValue); dprintf(" Enabled: %s\n", (dwValue) ? "Yes" : "No"); /* Get the remote control port. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_REMOTE_CONTROL_PORT, dwValue); dprintf(" Port number: %u\n", dwValue); /* Get the host priority. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_REMOTE_CONTROL_PASSWD, dwValue); dprintf(" Password: 0x%08x\n", dwValue); dprintf("\n"); dprintf(" Cluster IP settings\n"); /* Get the offset of the cluster IP address and retrieve the string from that address. */ if (GetFieldOffset(CVY_PARAMS, CVY_PARAMS_FIELD_CL_IP_ADDR, &dwValue)) dprintf("Can't get offset of %s in %s\n", CVY_PARAMS_FIELD_CL_IP_ADDR, CVY_PARAMS); else { pAddr = pParams + dwValue; /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szString, CVY_MAX_CL_IP_ADDR + 1); dprintf(" IP address: %ls\n", szString); } /* Get the offset of the cluster netmask and retrieve the string from that address. */ if (GetFieldOffset(CVY_PARAMS, CVY_PARAMS_FIELD_CL_NET_MASK, &dwValue)) dprintf("Can't get offset of %s in %s\n", CVY_PARAMS_FIELD_CL_NET_MASK, CVY_PARAMS); else { pAddr = pParams + dwValue; /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szString, CVY_MAX_CL_NET_MASK + 1); dprintf(" Netmask: %ls\n", szString); } /* Get the offset of the cluster MAC address and retrieve the MAC from that address. */ if (GetFieldOffset(CVY_PARAMS, CVY_PARAMS_FIELD_CL_MAC_ADDR, &dwValue)) dprintf("Can't get offset of %s in %s\n", CVY_PARAMS_FIELD_CL_MAC_ADDR, CVY_PARAMS); else { pAddr = pParams + dwValue; /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szString, CVY_MAX_NETWORK_ADDR + 1); dprintf(" MAC address: %ls\n", szString); } /* Get the offset of the cluster IGMP multicast address and retrieve the string from that address. */ if (GetFieldOffset(CVY_PARAMS, CVY_PARAMS_FIELD_CL_IGMP_ADDR, &dwValue)) dprintf("Can't get offset of %s in %s\n", CVY_PARAMS_FIELD_CL_IGMP_ADDR, CVY_PARAMS); else { pAddr = pParams + dwValue; /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szString, CVY_MAX_CL_IGMP_ADDR + 1); dprintf(" IGMP multicast IP address: %ls\n", szString); } /* Get the offset of the cluster name and retrieve the string from that address. */ if (GetFieldOffset(CVY_PARAMS, CVY_PARAMS_FIELD_CL_NAME, &dwValue)) dprintf("Can't get offset of %s in %s\n", CVY_PARAMS_FIELD_CL_NAME, CVY_PARAMS); else { pAddr = pParams + dwValue; /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szString, CVY_MAX_DOMAIN_NAME + 1); dprintf(" Domain name: %ls\n", szString); } dprintf("\n"); dprintf(" Dedicated IP settings\n"); /* Get the offset of the dedicated IP address and retrieve the string from that address. */ if (GetFieldOffset(CVY_PARAMS, CVY_PARAMS_FIELD_DED_IP_ADDR, &dwValue)) dprintf("Can't get offset of %s in %s\n", CVY_PARAMS_FIELD_DED_IP_ADDR, CVY_PARAMS); else { pAddr = pParams + dwValue; /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szString, CVY_MAX_DED_IP_ADDR + 1); dprintf(" IP address: %ls\n", szString); } /* Get the offset of the dedicated netmask and retrieve the string from that address. */ if (GetFieldOffset(CVY_PARAMS, CVY_PARAMS_FIELD_DED_NET_MASK, &dwValue)) dprintf("Can't get offset of %s in %s\n", CVY_PARAMS_FIELD_DED_NET_MASK, CVY_PARAMS); else { pAddr = pParams + dwValue; /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szString, CVY_MAX_DED_NET_MASK + 1); dprintf(" Netmask: %ls\n", szString); } dprintf("\n"); /* Get the offset of the BDA teaming parameters structure. */ if (GetFieldOffset(CVY_PARAMS, CVY_PARAMS_FIELD_BDA_TEAMING, &dwValue)) dprintf("Can't get offset of %s in %s\n", CVY_PARAMS_FIELD_BDA_TEAMING, CVY_PARAMS); else { ULONG64 pBDA = pParams + dwValue; /* Find out whether or not teaming is active on this adapter. */ GetFieldValue(pBDA, CVY_BDA, CVY_BDA_FIELD_ACTIVE, dwValue); dprintf(" Bi-directional affinity teaming: %s\n", (dwValue) ? "Active" : "Inactive"); /* Get the offset of the team ID and retrieve the string from that address. */ if (GetFieldOffset(CVY_BDA, CVY_BDA_FIELD_TEAM_ID, &dwValue)) dprintf("Can't get offset of %s in %s\n", CVY_BDA_FIELD_TEAM_ID, CVY_BDA); else { pAddr = pBDA + dwValue; /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szString, CVY_MAX_BDA_TEAM_ID + 1); dprintf(" Team ID: %ls\n", szString); } /* Get the master flag. */ GetFieldValue(pBDA, CVY_BDA, CVY_BDA_FIELD_MASTER, dwValue); dprintf(" Master: %s\n", (dwValue) ? "Yes" : "No"); /* Get the reverse hashing flag. */ GetFieldValue(pBDA, CVY_BDA, CVY_BDA_FIELD_REVERSE_HASH, dwValue); dprintf(" Reverse hashing: %s\n", (dwValue) ? "Yes" : "No"); } /* If we're printing at low verbosity, bail out here. */ if (dwVerbosity == VERBOSITY_LOW) return; dprintf("\n"); /* Get the offset of the port rules and pass it to PrintPortRules. */ if (GetFieldOffset(CVY_PARAMS, CVY_PARAMS_FIELD_PORT_RULES, &dwValue)) dprintf("Can't get offset of %s in %s\n", CVY_PARAMS_FIELD_PORT_RULES, CVY_PARAMS); else { pAddr = pParams + dwValue; /* Get the number of port rules. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_NUM_RULES, dwValue); PrintPortRules(dwValue, pAddr); } /* If we're printing at medium verbosity, bail out here. */ if (dwVerbosity == VERBOSITY_MEDIUM) return; dprintf("\n"); /* Get the heartbeat period. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_ALIVE_PERIOD, dwValue); dprintf(" Heartbeat period: %u millisecond(s)\n", dwValue); /* Get the heartbeat loss tolerance. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_ALIVE_TOLERANCE, dwValue); dprintf(" Heartbeat loss tolerance: %u\n", dwValue); dprintf("\n"); /* Get the number of remote control actions to allocate. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_NUM_ACTIONS, dwValue); dprintf(" Number of actions to allocate: %u\n", dwValue); /* Get the number of packets to allocate. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_NUM_PACKETS, dwValue); dprintf(" Number of packets to allocate: %u\n", dwValue); /* Get the number of heartbeats to allocate. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_NUM_PINGS, dwValue); dprintf(" Number of heartbeats to allocate: %u\n", dwValue); /* Get the number of descriptors per allocation. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_NUM_DESCR, dwValue); dprintf(" Descriptors per allocation: %u\n", dwValue); /* Get the maximum number of descriptor allocations. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_MAX_DESCR, dwValue); dprintf(" Maximum Descriptors allocations: %u\n", dwValue); dprintf("\n"); /* Get the NetBT support flag. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_NBT_SUPPORT, dwValue); dprintf(" NetBT support enabled: %s\n", (dwValue) ? "Yes" : "No"); /* Get the multicast spoof flag. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_MCAST_SPOOF, dwValue); dprintf(" Multicast spoofing enabled: %s\n", (dwValue) ? "Yes" : "No"); /* Get the netmon passthru flag. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_NETMON_PING, dwValue); dprintf(" Netmon heartbeat passthru enabled: %s\n", (dwValue) ? "Yes" : "No"); /* Get the mask source MAC flag. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_MASK_SRC_MAC, dwValue); dprintf(" Mask source MAC enabled: %s\n", (dwValue) ? "Yes" : "No"); /* Get the convert MAC flag. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_CONVERT_MAC, dwValue); dprintf(" IP to MAC conversion enabled: %s\n", (dwValue) ? "Yes" : "No"); dprintf("\n"); /* Get the IP change delay value. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_IP_CHANGE_DELAY, dwValue); dprintf(" IP change delay: %u millisecond(s)\n", dwValue); /* Get the dirty descriptor cleanup delay value. */ GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_CLEANUP_DELAY, dwValue); dprintf(" Dirty connection cleanup delay: %u millisecond(s)\n", dwValue); } /* * Function: PrintPortRules * Description: Prints the NLB port rules. * Author: Created by shouse, 1.21.01 */ void PrintPortRules (ULONG dwNumRules, ULONG64 pRules) { ULONG dwRuleSize; ULONG dwIndex; ULONG64 pAddr; /* Make sure the address is non-NULL. */ if (!pRules) { dprintf("Error: NLB port rule block is NULL.\n"); return; } dprintf(" Configured port rules (%u)\n", dwNumRules); /* If no port rules are present, print a notification. */ if (!dwNumRules) { dprintf(" There are no port rules configured on this cluster.\n"); return; } /* Print the column headers. */ dprintf(" Virtual IP Start End Protocol Mode Priority Load Weight Affinity\n"); dprintf(" --------------- ----- ----- -------- -------- -------- ----------- --------\n"); /* Find out the size of a CVY_RULE structure. */ dwRuleSize = GetTypeSize(CVY_RULE); /* Loop through all port rules and print the configuration. Note: The print statements are full of seemingly non-sensicle format strings, but trust me, they're right. */ for (dwIndex = 0; dwIndex < dwNumRules; dwIndex++) { IN_ADDR dwIPAddr; CHAR * szString; ULONG dwValue; USHORT wValue; /* Get the VIP. Convert from a DWORD to a string. */ GetFieldValue(pRules, CVY_RULE, CVY_RULE_FIELD_VIP, dwValue); if (dwValue != CVY_ALL_VIP) { dwIPAddr.S_un.S_addr = dwValue; szString = inet_ntoa(dwIPAddr); dprintf(" %-15s", szString); } else dprintf(" %-15s", "ALL VIPs"); /* Get the start port. */ GetFieldValue(pRules, CVY_RULE, CVY_RULE_FIELD_START_PORT, dwValue); dprintf(" %5u", dwValue); /* Get the end port. */ GetFieldValue(pRules, CVY_RULE, CVY_RULE_FIELD_END_PORT, dwValue); dprintf(" %5u", dwValue); /* Figure out the protocol. */ GetFieldValue(pRules, CVY_RULE, CVY_RULE_FIELD_PROTOCOL, dwValue); switch (dwValue) { case CVY_TCP: dprintf(" %s ", "TCP"); break; case CVY_UDP: dprintf(" %s ", "UDP"); break; case CVY_TCP_UDP: dprintf(" %s ", "Both"); break; default: dprintf(" %s", "Unknown"); break; } /* Find the rule mode. */ GetFieldValue(pRules, CVY_RULE, CVY_RULE_FIELD_MODE, dwValue); switch (dwValue) { case CVY_SINGLE: /* Print mode and priority. */ dprintf(" %s ", "Single"); /* Get the handling priority. */ GetFieldValue(pRules, CVY_RULE, CVY_RULE_FIELD_PRIORITY, dwValue); dprintf(" %2u ", dwValue); break; case CVY_MULTI: /* Print mode, weight and affinity. */ dprintf(" %s", "Multiple"); dprintf(" %8s", ""); /* Get the equal load flag. */ GetFieldValue(pRules, CVY_RULE, CVY_RULE_FIELD_EQUAL_LOAD, wValue); if (wValue) { dprintf(" %5s ", "Equal"); } else { /* If distribution is unequal, get the load weight. */ GetFieldValue(pRules, CVY_RULE, CVY_RULE_FIELD_LOAD_WEIGHT, dwValue); dprintf(" %3u ", dwValue); } /* Get the affinity for this rule. */ GetFieldValue(pRules, CVY_RULE, CVY_RULE_FIELD_AFFINITY, wValue); switch (wValue) { case CVY_AFFINITY_NONE: dprintf(" %s", "None"); break; case CVY_AFFINITY_SINGLE: dprintf(" %s", "Single"); break; case CVY_AFFINITY_CLASSC: dprintf(" %s", "Class C"); break; default: dprintf(" %s", "Unknown"); break; } break; case CVY_NEVER: /* Print the mode. */ dprintf(" %s", "Disabled"); break; default: break; } dprintf("\n"); /* Advance the pointer to the next index in the array of structures. */ pRules += dwRuleSize; } } /* * Function: PrintLoad * Description: Prints the contents of the CVY_LOAD structure at the specified verbosity. * LOW (0) * MEDIUM (1) * HIGH (2) * Author: Created by shouse, 1.21.01 */ void PrintLoad (ULONG64 pLoad, ULONG dwVerbosity) { WCHAR szString[256]; ULONG dwMissedPings[CVY_MAX_HOSTS]; BOOL dwDirtyBins[CVY_MAX_BINS]; ULONG64 pAddr; ULONG dwValue; ULONG dwHostID; BOOL bValue; /* Make sure the address is non-NULL. */ if (!pLoad) { dprintf("Error: NLB load block is NULL.\n"); return; } dprintf("NLB Load Block 0x%p\n", pLoad); /* Get the LOAD_CTXT_CODE from the structure to make sure that this address indeed points to a valid NLB load block. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_CODE, dwValue); if (dwValue != LOAD_CTXT_CODE) { dprintf(" Error: Invalid NLB load block. Wrong code found (0x%08x).\n", dwValue); return; } /* Get my host ID. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_HOST_ID, dwHostID); /* Determine whether or not the load context has been initialized. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_REF_COUNT, dwValue); dprintf(" Reference count: %u\n", dwValue); /* Determine whether or not the load context has been initialized. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_INIT, bValue); dprintf(" Load initialized: %s\n", (bValue) ? "Yes" : "No"); /* Determine whether or not the load context is active. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_ACTIVE, bValue); dprintf(" Load active: %s\n", (bValue) ? "Yes" : "No"); /* Get the number of total packets handled since last convergence. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_PACKET_COUNT, dwValue); dprintf(" Packets handled since convergence: %u\n", dwValue); /* Get the number of currently active connections. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_CONNECTIONS, dwValue); dprintf(" Current active connections: %u\n", dwValue); dprintf("\n"); /* Find out the level of consistency from incoming heartbeats. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_CONSISTENT, bValue); dprintf(" Consistent heartbeats detected: %s\n", (bValue) ? "Yes" : "No"); /* Have we seen duplicate host IDs? */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_DUP_HOST_ID, bValue); dprintf(" Duplicate host IDs: %s\n", (bValue) ? "Yes" : "No"); /* Have we seen duplicate handling priorities? */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_DUP_PRIORITY, bValue); dprintf(" Duplicate handling priorities: %s\n", (bValue) ? "Yes" : "No"); /* Have we seen inconsistent BDA teaming configuration? */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_BAD_TEAM_CONFIG, bValue); dprintf(" Inconsistent BDA teaming: %s\n", (bValue) ? "Yes" : "No"); /* Have we seen a different number of port rules? */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_BAD_NUM_RULES, bValue); dprintf(" Different number of port rules: %s\n", (bValue) ? "Yes" : "No"); /* Is the new host map bad? */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_BAD_NEW_MAP, bValue); dprintf(" Invalid new host map: %s\n", (bValue) ? "Yes" : "No"); /* Do the maps overlap? */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_OVERLAPPING_MAP, bValue); dprintf(" Overlapping maps: %s\n", (bValue) ? "Yes" : "No"); /* Was there an error in updating bins? */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_RECEIVING_BINS, bValue); dprintf(" Received bins already owned: %s\n", (bValue) ? "Yes" : "No"); /* Were there orphaned bins after an update? */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_ORPHANED_BINS, bValue); dprintf(" Orphaned bins: %s\n", (bValue) ? "Yes" : "No"); dprintf("\n"); /* Get the current host map. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_HOST_MAP, dwValue); dprintf(" Current host map: 0x%08x ", dwValue); /* If there are hosts in the map, print them. */ if (dwValue) { dprintf("("); PrintHostList(dwValue); dprintf(")"); } dprintf("\n"); /* Get the current map of pinged hosts. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_PING_MAP, dwValue); dprintf(" Ping'd host map: 0x%08x ", dwValue); /* If there are hosts in the map, print them. */ if (dwValue) { dprintf("("); PrintHostList(dwValue); dprintf(")"); } dprintf("\n"); /* Get the map from the last convergence. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_LAST_MAP, dwValue); dprintf(" Host map after last convergence: 0x%08x ", dwValue); /* If there are hosts in the map, print them. */ if (dwValue) { dprintf("("); PrintHostList(dwValue); dprintf(")"); } dprintf("\n"); dprintf("\n"); /* Get the stable host map. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_STABLE_MAP, dwValue); dprintf(" Stable host map: 0x%08x ", dwValue); /* If there are hosts in the map, print them. */ if (dwValue) { dprintf("("); PrintHostList(dwValue); dprintf(")"); } dprintf("\n"); /* Get the minimum number of timeouts with stable condition. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_MIN_STABLE, dwValue); dprintf(" Stable timeouts necessary: %u\n", dwValue); /* Get the number of local stable timeouts. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_LOCAL_STABLE, dwValue); dprintf(" Local stable timeouts: %u\n", dwValue); /* Get the number of global stable timeouts. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_ALL_STABLE, dwValue); dprintf(" Global stable timeouts: %u\n", dwValue); dprintf("\n"); /* Get the default timeout period. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_DEFAULT_TIMEOUT, dwValue); dprintf(" Default timeout interval: %u millisecond(s)\n", dwValue); /* Get the current timeout period. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_CURRENT_TIMEOUT, dwValue); dprintf(" Current timeout interval: %u millisecond(s)\n", dwValue); /* Get the ping miss tolerance. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_PING_TOLERANCE, dwValue); dprintf(" Missed ping tolerance: %u\n", dwValue); /* Get the missed ping array. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_PING_MISSED, dwMissedPings); dprintf(" Missed pings: "); PrintMissedPings(dwMissedPings); dprintf("\n"); /* Are we waiting for a cleanup? */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_CLEANUP_WAITING, bValue); dprintf(" Cleanup waiting: %s\n", (bValue) ? "Yes" : "No"); /* Get the cleanup timeout. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_CLEANUP_TIMEOUT, dwValue); dprintf(" Cleanup timeout: %.1f second(s)\n", (float)(dwValue/1000.0)); /* Get the current cleanup wait time. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_CLEANUP_CURRENT, dwValue); dprintf(" Current cleanup wait time: %.1f second(s)\n", (float)(dwValue/1000.0)); dprintf("\n"); /* Get the number of descriptors per allocation. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_DESCRIPTORS_PER_ALLOC, dwValue); dprintf(" Descriptors per allocation: %u\n", dwValue); /* Get the maximum number of allocations allowed. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_MAX_DESCRIPTOR_ALLOCS, dwValue); dprintf(" Maximum descriptor allocations: %u\n", dwValue); /* Get the number of allocations thusfar. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_NUM_DESCRIPTOR_ALLOCS, dwValue); dprintf(" Number of descriptor allocations: %u\n", dwValue); /* Get the inhibited allocations flag. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_INHIBITED_ALLOC, bValue); dprintf(" Allocations inhibited: %s\n", (bValue) ? "Yes" : "No"); /* Get the failed allocations flag. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_FAILED_ALLOC, bValue); dprintf(" Allocations failed: %s\n", (bValue) ? "Yes" : "No"); /* If wer're printing at low verbosity, bail out here. */ if (dwVerbosity == VERBOSITY_LOW) return; dprintf("\n"); /* Get the dirty bin array. */ GetFieldValue(pLoad, LOAD_CTXT, LOAD_CTXT_FIELD_DIRTY_BINS, dwDirtyBins); dprintf(" Dirty bins: "); /* Print the bins which have dirty connections. */ PrintDirtyBins(dwDirtyBins); dprintf("\n"); /* Get the offset of the port rule state structures and use PrintPortRuleState to print them. */ if (GetFieldOffset(LOAD_CTXT, LOAD_CTXT_FIELD_PORT_RULE_STATE, &dwValue)) dprintf("Can't get offset of %s in %s\n", LOAD_CTXT_FIELD_PORT_RULE_STATE, LOAD_CTXT); else { ULONG dwPortRuleStateSize; ULONG dwNumRules; ULONG dwIndex; ULONG dwTemp; /* Get the offset of the params pointer. */ if (GetFieldOffset(LOAD_CTXT, LOAD_CTXT_FIELD_PARAMS, &dwTemp)) dprintf("Can't get offset of %s in %s\n", LOAD_CTXT_FIELD_PARAMS, LOAD_CTXT); else { pAddr = pLoad + dwTemp; /* Retrieve the pointer. */ pAddr = GetPointerFromAddress(pAddr); /* Get the number of port rules from the params block. */ GetFieldValue(pAddr, CVY_PARAMS, CVY_PARAMS_FIELD_NUM_RULES, dwNumRules); /* Set the address of the port rule state array. */ pAddr = pLoad + dwValue; /* Find out the size of a BIN_STATE structure. */ dwPortRuleStateSize = GetTypeSize(BIN_STATE); /* NOTE: its "less than or equal" as opposed to "less than" because we need to include the DEFAULT port rule, which is always at index "num rules" (i.e. the last rule). */ for (dwIndex = 0; dwIndex <= dwNumRules; dwIndex++) { /* Print the state information for the port rule. */ PrintPortRuleState(pAddr, dwHostID, (dwIndex == dwNumRules) ? TRUE : FALSE); if (dwIndex < dwNumRules) dprintf("\n"); /* Advance the pointer to the next port rule. */ pAddr += dwPortRuleStateSize; } } } /* If wer're printing at medium verbosity, bail out here. */ if (dwVerbosity == VERBOSITY_MEDIUM) return; dprintf("\n"); dprintf(" Heartbeat message\n"); /* Get the offset of the heartbeat structure and use PrintHeartbeat to print it. */ if (GetFieldOffset(LOAD_CTXT, LOAD_CTXT_FIELD_PING, &dwValue)) dprintf("Can't get offset of %s in %s\n", LOAD_CTXT_FIELD_PING, LOAD_CTXT); else { pAddr = pLoad + dwValue; /* Print the NLB heartbeat contents. */ PrintHeartbeat(pAddr); } } /* * Function: PrintResp * Description: Prints the NLB private data associated with the given packet. * Author: Created by shouse, 1.31.01 */ void PrintResp (ULONG64 pPacket, ULONG dwDirection) { ULONG64 pPacketStack; ULONG bStackLeft; ULONG64 pProtReserved = 0; ULONG64 pIMReserved = 0; ULONG64 pMPReserved = 0; ULONG64 pResp; ULONG64 pAddr; ULONG dwValue; USHORT wValue; /* Make sure the address is non-NULL. */ if (!pPacket) { dprintf("Error: Packet is NULL.\n"); return; } /* Print a warning concerning the importance of knowing whether its a send or receive. */ dprintf("Assuming packet 0x%p is on the %s packet path. If this is\n", pPacket, (dwDirection == DIRECTION_RECEIVE) ? "RECEIVE" : "SEND"); dprintf(" incorrect, the information displayed below MAY be incorrect.\n"); dprintf("\n"); /* Get the current NDIS packet stack. */ pPacketStack = PrintCurrentPacketStack(pPacket, &bStackLeft); dprintf("\n"); if (pPacketStack) { /* Get the offset of the IMReserved field in the packet stack. */ if (GetFieldOffset(NDIS_PACKET_STACK, NDIS_PACKET_STACK_FIELD_IMRESERVED, &dwValue)) dprintf("Can't get offset of %s in %s\n", NDIS_PACKET_STACK_FIELD_IMRESERVED, NDIS_PACKET_STACK); else { pAddr = pPacketStack + dwValue; /* Get the resp pointer from the IMReserved field. */ pIMReserved = GetPointerFromAddress(pAddr); } } /* Get the offset of the MiniportReserved field in the packet. */ if (GetFieldOffset(NDIS_PACKET, NDIS_PACKET_FIELD_MPRESERVED, &dwValue)) dprintf("Can't get offset of %s in %s\n", NDIS_PACKET_FIELD_MPRESERVED, NDIS_PACKET); else { pAddr = pPacket + dwValue; /* Get the resp pointer from the MPReserved field. */ pMPReserved = GetPointerFromAddress(pAddr); } /* Get the offset of the ProtocolReserved field in the packet. */ if (GetFieldOffset(NDIS_PACKET, NDIS_PACKET_FIELD_PROTRESERVED, &dwValue)) dprintf("Can't get offset of %s in %s\n", NDIS_PACKET_FIELD_PROTRESERVED, NDIS_PACKET); else { pProtReserved = pPacket + dwValue; } /* Mimic #define MAIN_RESP_FIELD(pkt, left, ps, rsp, send) (from wlbs\driver\main.h). */ if (pPacketStack) { if (pIMReserved) pResp = pIMReserved; else if (dwDirection == DIRECTION_SEND) pResp = pProtReserved; else if (pMPReserved) pResp = pMPReserved; else pResp = pProtReserved; } else { if (dwDirection == DIRECTION_SEND) pResp = pProtReserved; else if (pMPReserved) pResp = pMPReserved; else pResp = pProtReserved; } dprintf("NLB Main Protocol Reserved Block 0x%p\n"); /* Get the offset of the miscellaneous pointer. */ if (GetFieldOffset(MAIN_PROTOCOL_RESERVED, MAIN_PROTOCOL_RESERVED_FIELD_MISCP, &dwValue)) dprintf("Can't get offset of %s in %s\n", MAIN_PROTOCOL_RESERVED_FIELD_MISCP, MAIN_PROTOCOL_RESERVED); else { pAddr = pResp + dwValue; /* Retrieve the pointer. */ pAddr = GetPointerFromAddress(pAddr); dprintf(" Miscellaneous pointer: 0x%p\n", pAddr); } /* Retrieve the packet type from the NLB private data. */ GetFieldValue(pResp, MAIN_PROTOCOL_RESERVED, MAIN_PROTOCOL_RESERVED_FIELD_TYPE, wValue); switch (wValue) { case MAIN_PACKET_TYPE_NONE: dprintf(" Packet type: %u (None)\n", wValue); break; case MAIN_PACKET_TYPE_PING: dprintf(" Packet type: %u (Heartbeat)\n", wValue); break; case MAIN_PACKET_TYPE_INDICATE: dprintf(" Packet type: %u (Indicate)\n", wValue); break; case MAIN_PACKET_TYPE_PASS: dprintf(" Packet type: %u (Passthrough)\n", wValue); break; case MAIN_PACKET_TYPE_CTRL: dprintf(" Packet type: %u (Remote Control)\n", wValue); break; case MAIN_PACKET_TYPE_TRANSFER: dprintf(" Packet type: %u (Transfer)\n", wValue); break; case MAIN_PACKET_TYPE_IGMP: dprintf(" Packet type: %u (IGMP)\n", wValue); break; default: dprintf(" Packet type: %u (Invalid)\n", wValue); break; } /* Retrieve the group from the NLB private data. */ GetFieldValue(pResp, MAIN_PROTOCOL_RESERVED, MAIN_PROTOCOL_RESERVED_FIELD_GROUP, wValue); switch (wValue) { case MAIN_FRAME_UNKNOWN: dprintf(" Packet type: %u (Unknown)\n", wValue); break; case MAIN_FRAME_DIRECTED: dprintf(" Packet type: %u (Directed)\n", wValue); break; case MAIN_FRAME_MULTICAST: dprintf(" Packet type: %u (Multicast)\n", wValue); break; case MAIN_FRAME_BROADCAST: dprintf(" Packet type: %u (Broadcast)\n", wValue); break; default: dprintf(" Packet type: %u (Invalid)\n", wValue); break; } /* Retrieve the data field from the NLB private data. */ GetFieldValue(pResp, MAIN_PROTOCOL_RESERVED, MAIN_PROTOCOL_RESERVED_FIELD_DATA, dwValue); dprintf(" Data: %u\n", dwValue); /* Retrieve the length field from the NLB private data. */ GetFieldValue(pResp, MAIN_PROTOCOL_RESERVED, MAIN_PROTOCOL_RESERVED_FIELD_LENGTH, dwValue); dprintf(" Length: %u\n", dwValue); } /* * Function: PrintCurrentPacketStack * Description: Retrieves the current packet stack for the specified packet. Note: this * is heavily dependent on the current NDIS packet stacking mechanics - any * changes to NDIS packet stacking could easily (will) break this. This * entire function mimics NdisIMGetCurrentPacketStack(). * Author: Created by shouse, 1.31.01 */ ULONG64 PrintCurrentPacketStack (ULONG64 pPacket, ULONG * bStackLeft) { ULONG64 pNumPacketStacks; ULONG64 pPacketWrapper; ULONG64 pPacketStack; ULONG dwNumPacketStacks; ULONG dwStackIndexSize; ULONG dwPacketStackSize; ULONG dwCurrentIndex; /* Make sure the address is non-NULL. */ if (!pPacket) { dprintf("Error: Packet is NULL.\n"); *bStackLeft = 0; return 0; } /* Get the address of the global variable containing the number of packet stacks. */ pNumPacketStacks = GetExpression(NDIS_PACKET_STACK_SIZE); if (!pNumPacketStacks) { ErrorCheckSymbols(NDIS_PACKET_STACK_SIZE); *bStackLeft = 0; return 0; } /* Get the number of packet stacks from the address. */ dwNumPacketStacks = GetUlongFromAddress(pNumPacketStacks); /* Find out the size of a STACK_INDEX structure. */ dwStackIndexSize = GetTypeSize(STACK_INDEX); /* Find out the size of a NDIS_PACKET_STACK structure. */ dwPacketStackSize = GetTypeSize(NDIS_PACKET_STACK); /* This is the calculation we're doing (from ndis\sys\wrapper.h): #define SIZE_PACKET_STACKS (sizeof(STACK_INDEX) + (sizeof(NDIS_PACKET_STACK) * ndisPacketStackSize)) */ pPacketStack = pPacket - (dwStackIndexSize + (dwPacketStackSize * dwNumPacketStacks)); /* The wrapper is the packet address minus the size of the stack index. See ndis\sys\wrapper.h. We need this to get the current stack index. */ pPacketWrapper = pPacket - dwStackIndexSize; dprintf("NDIS Packet Stack: 0x%p\n", pPacketStack); /* Retrieve the current stack index. */ GetFieldValue(pPacketWrapper, NDIS_PACKET_WRAPPER, NDIS_PACKET_WRAPPER_FIELD_STACK_INDEX, dwCurrentIndex); dprintf(" Current stack index: %d\n", dwCurrentIndex); if (dwCurrentIndex < dwNumPacketStacks) { /* If the current index is less than the number of stacks, then point the stack to the right address and determine whether or not there is stack room left. */ pPacketStack += dwCurrentIndex * dwPacketStackSize; *bStackLeft = (dwNumPacketStacks - dwCurrentIndex - 1) > 0; } else { /* If not, then we're out of stack space. */ pPacketStack = 0; *bStackLeft = 0; } dprintf(" Current packet stack: 0x%p\n", pPacketStack); dprintf(" Stack remaining: %s\n", (*bStackLeft) ? "Yes" : "No"); return pPacketStack; } /* * Function: PrintHostList * Description: Prints a list of hosts in a host map. * Author: Created by shouse, 2.1.01 */ void PrintHostList (ULONG dwHostMap) { BOOL bFirst = TRUE; ULONG dwHostNum = 1; /* As long as there are hosts still in the map, print them. */ while (dwHostMap) { /* If the least significant bit is set, print the host number. */ if (dwHostMap & 0x00000001) { /* If this is the first host printed, just print the number. */ if (bFirst) { dprintf("%u", dwHostNum); bFirst = FALSE; } else /* Otherwise, we need to print a comma first. */ dprintf(", %u", dwHostNum); } /* Increment the host number and shift the map to the right one bit. */ dwHostNum++; dwHostMap >>= 1; } } /* * Function: PrintMissedPings * Description: Prints a list hosts from which we are missing pings. * Author: Created by shouse, 2.1.01 */ void PrintMissedPings (ULONG dwMissedPings[]) { BOOL bMissing = FALSE; ULONG dwIndex; /* Loop through the entire array of missed pings. */ for (dwIndex = 0; dwIndex < CVY_MAX_HOSTS; dwIndex++) { /* If we're missing pings from this host, print the number missed and the host priority, which is the index (host ID) plus one. */ if (dwMissedPings[dwIndex]) { dprintf("\n Missing %u pings from Host %u", dwMissedPings[dwIndex], dwIndex + 1); /* Not the fact that we found at least one host with missing pings. */ bMissing = TRUE; } } /* If we're missing no pings, print "None". */ if (!bMissing) dprintf("None"); dprintf("\n"); } /* * Function: PrintDirtyBins * Description: Prints a list of bins with dirty connections. * Author: Created by shouse, 2.1.01 */ void PrintDirtyBins (BOOL dwDirtyBins[]) { BOOL bFirst = TRUE; ULONG dwIndex; /* Loop through the entire array of dirty bins. */ for (dwIndex = 0; dwIndex < CVY_MAX_BINS; dwIndex++) { if (dwDirtyBins[dwIndex]) { /* If this is the first bin printed, just print the number. */ if (bFirst) { dprintf("%u", dwIndex); bFirst = FALSE; } else /* Otherwise, we need to print a comma first. */ dprintf(", %u", dwIndex); } } /* If there are no dirty bins, print "None". */ if (bFirst) dprintf("None"); dprintf("\n"); } /* * Function: PrintHeartbeat * Description: Prints the contents of the NLB heartbeat structure. * Author: Created by shouse, 2.1.01 */ void PrintHeartbeat (ULONG64 pHeartbeat) { ULONG dwValue; USHORT wValue; ULONG dwIndex; ULONG dwRuleCode[CVY_MAX_RULES]; ULONGLONG ddwCurrentMap[CVY_MAX_RULES]; ULONGLONG ddwNewMap[CVY_MAX_RULES]; ULONGLONG ddwIdleMap[CVY_MAX_RULES]; ULONGLONG ddwReadyBins[CVY_MAX_RULES]; ULONG dwLoadAmount[CVY_MAX_RULES]; /* Make sure the address is non-NULL. */ if (!pHeartbeat) { dprintf("Error: Heartbeat is NULL.\n"); return; } /* Get the default host ID. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_DEFAULT_HOST_ID, wValue); dprintf(" DEFAULT host ID: %u (%u)\n", wValue, wValue + 1); /* Get my host ID. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_HOST_ID, wValue); dprintf(" My host ID: %u (%u)\n", wValue, wValue + 1); /* Get my host code. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_HOST_CODE, dwValue); dprintf(" Unique host code: 0x%08x\n", dwValue); /* Get the host state. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_STATE, wValue); dprintf(" Host state: "); switch (wValue) { case HST_CVG: dprintf("Converging\n"); break; case HST_STABLE: dprintf("Stable\n"); break; case HST_NORMAL: dprintf("Normal\n"); break; default: dprintf("Unknown\n"); break; } /* Get the teaming configuration code. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_TEAMING_CODE, dwValue); dprintf(" BDA teaming configuration: 0x%08x\n", dwValue); /* Get the packet count. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_PACKET_COUNT, dwValue); dprintf(" Packets handled: %u\n", dwValue); /* Get the number of port rules. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_NUM_RULES, wValue); dprintf(" Number of port rules: %u\n", wValue); /* Get the rule codes. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_RULE_CODE, dwRuleCode); /* Get the current bin map. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_CURRENT_MAP, ddwCurrentMap); /* Get the new bin map. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_NEW_MAP, ddwNewMap); /* Get the idle bin map. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_IDLE_MAP, ddwIdleMap); /* Get the ready bins map. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_READY_BINS, ddwReadyBins); /* Get the load amount for each rule. */ GetFieldValue(pHeartbeat, PING_MSG, PING_MSG_FIELD_LOAD_AMOUNT, dwLoadAmount); /* Loop through all port rules and spit out some information. */ for (dwIndex = 0; dwIndex < wValue; dwIndex++) { /* Decode the rule. See CVY_RULE_CODE_SET() in net\inc\wlbsparams.h. */ ULONG dwStartPort = dwRuleCode[dwIndex] & 0x00000fff; ULONG dwEndPort = (dwRuleCode[dwIndex] & 0x00fff000) >> 12; ULONG dwProtocol = (dwRuleCode[dwIndex] & 0x0f000000) >> 24; ULONG dwMode = (dwRuleCode[dwIndex] & 0x30000000) >> 28; ULONG dwAffinity = (dwRuleCode[dwIndex] & 0xc0000000) >> 30; dprintf(" Port rule %u\n", dwIndex + 1); /* Print out the bin maps and load weight. */ dprintf(" Rule code: 0x%08x ", dwRuleCode[dwIndex]); /* If this is the last port rule, then its the default port rule. */ if (dwIndex == (wValue - 1)) dprintf("(DEFAULT port rule)\n"); else { #if 0 /* Because rule codes are overlapped logical ORs, we can't necessarily get back the information that was put in, so we won't spit it out until we can guarantee that. */ /* Print out the port range - keep in mind that 16 bit port ranges are encoded in 12 bit numbers, so this may not be 100% accurate. */ dprintf("(%u - %u, ", dwStartPort, dwEndPort); /* Print the protocol. */ switch (dwProtocol) { case CVY_TCP: dprintf("TCP, "); break; case CVY_UDP: dprintf("UDP, "); break; case CVY_TCP_UDP: dprintf("TCP/UDP, "); break; default: dprintf("Unknown protocol, "); break; } /* Print the filtering mode. */ switch (dwMode) { case CVY_SINGLE: dprintf("Single host)\n"); break; case CVY_MULTI: dprintf("Multiple host, "); /* If this rule uses multiple host, then we also print the affinity. */ switch (dwAffinity) { case CVY_AFFINITY_NONE: dprintf("No affinity)\n"); break; case CVY_AFFINITY_SINGLE: dprintf("Single affinity)\n"); break; case CVY_AFFINITY_CLASSC: dprintf("Class C affinity)\n"); break; default: dprintf("Unknown affinity)\n"); break; } break; case CVY_NEVER: dprintf("Disabled)\n"); break; default: dprintf("Unknown filtering mode)\n"); break; } #else dprintf("\n"); #endif /* Print the load weight. */ dprintf(" Load weight: %u\n", dwLoadAmount[dwIndex]); } /* Print the bin maps for all rules, default or not. */ dprintf(" Current map: 0x%015I64x\n", ddwCurrentMap[dwIndex]); dprintf(" New map: 0x%015I64x\n", ddwNewMap[dwIndex]); dprintf(" Idle map: 0x%015I64x\n", ddwIdleMap[dwIndex]); dprintf(" Ready bins: 0x%015I64x\n", ddwReadyBins[dwIndex]); } } /* * Function: PrintPortRuleState * Description: Prints the state information for the port rule. * Author: Created by shouse, 2.5.01 */ void PrintPortRuleState (ULONG64 pPortRule, ULONG dwHostID, BOOL bDefault) { ULONG dwValue; ULONG dwMode; USHORT wValue; BOOL bValue; ULONGLONG ddwValue; /* Make sure the address is non-NULL. */ if (!pPortRule) { dprintf("Error: Port rule is NULL.\n"); return; } /* Get the BIN_STATE_CODE from the structure to make sure that this address indeed points to a valid NLB port rule state block. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_CODE, dwValue); if (dwValue != BIN_STATE_CODE) { dprintf(" Error: Invalid NLB port rule state block. Wrong code found (0x%08x).\n", dwValue); return; } /* Get the index of the rule - the "rule number". */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_INDEX, dwValue); dprintf(" Port rule %u\n", dwValue + 1); /* Is the port rule state initialized? */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_INITIALIZED, bValue); dprintf(" State initialized: %s\n", (bValue) ? "Yes" : "No"); /* Are the codes compatible? */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_COMPATIBLE, bValue); dprintf(" Compatibility detected: %s\n", (bValue) ? "Yes" : "No"); /* Is the port rule state initialized? */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_EQUAL, bValue); dprintf(" Equal load balancing: %s\n", (bValue) ? "Yes" : "No"); /* Get the filtering mode for this port rule. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_MODE, dwMode); dprintf(" Filtering mode: "); /* If this is the DEFAULT port rule, then jump to the bottom. */ if (bDefault) { dprintf("DEFAULT\n"); goto end; } switch (dwMode) { case CVY_SINGLE: dprintf("Single host\n"); break; case CVY_MULTI: dprintf("Multiple host\n"); break; case CVY_NEVER: dprintf("Disabled\n"); break; default: dprintf("Unknown\n"); break; } if (dwMode == CVY_MULTI) { /* Get the affinity for this port rule. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_AFFINITY, wValue); dprintf(" Affinity: "); switch (wValue) { case CVY_AFFINITY_NONE: dprintf("None\n"); break; case CVY_AFFINITY_SINGLE: dprintf("Single\n"); break; case CVY_AFFINITY_CLASSC: dprintf("Class C\n"); break; default: dprintf("Unknown\n"); break; } } /* Get the protocol(s) for this port rule. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_PROTOCOL, dwValue); dprintf(" Protocol(s): "); /* Print the protocol. */ switch (dwValue) { case CVY_TCP: dprintf("TCP\n"); break; case CVY_UDP: dprintf("UDP\n"); break; case CVY_TCP_UDP: dprintf("TCP/UDP\n"); break; default: dprintf("Unknown\n"); break; } /* In multiple host filtering, print the load information. For single host filtering, print the host priority information. */ if (dwMode == CVY_MULTI) { ULONG dwCurrentLoad[CVY_MAX_HOSTS]; /* Get the original load for this rule on this host. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_ORIGINAL_LOAD, dwValue); dprintf(" Configured load weight: %u\n", dwValue); /* Get the original load for this rule on this host. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_CURRENT_LOAD, dwCurrentLoad); dprintf(" Current load weight: %u/", dwCurrentLoad[dwHostID]); /* Get the total load for this rule on all hosts. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_TOTAL_LOAD, dwValue); dprintf("%u\n", dwValue); } else if (dwMode == CVY_SINGLE) { /* Get the host priority. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_ORIGINAL_LOAD, dwValue); dprintf(" Host priority: %u\n", dwValue); } end: /* Get the total number of active connections. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_TOTAL_CONNECTIONS, dwValue); dprintf(" Total active connections: %u\n", dwValue); /* Get the current map. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_CURRENT_MAP, ddwValue); dprintf(" Current map: 0x%015I64x\n", ddwValue); /* Get the all idle map. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_ALL_IDLE_MAP, ddwValue); dprintf(" All idle map: 0x%015I64x\n", ddwValue); /* Get the idle bins map. */ GetFieldValue(pPortRule, BIN_STATE, BIN_STATE_FIELD_IDLE_BINS, ddwValue); dprintf(" My idle map: 0x%015I64x\n", ddwValue); } /* * Function: PrintBDAMember * Description: Prints the BDA teaming configuration and state of a member. * Author: Created by shouse, 4.8.01 */ void PrintBDAMember (ULONG64 pMember) { ULONG64 pAddr; ULONG dwValue; /* Make sure the address is non-NULL. */ if (!pMember) { dprintf("Error: Member is NULL.\n"); return; } /* Find out whether or not teaming is active on this adapter. */ GetFieldValue(pMember, BDA_MEMBER, BDA_MEMBER_FIELD_ACTIVE, dwValue); dprintf(" Bi-directional affinity teaming: %s\n", (dwValue) ? "Active" : "Inactive"); /* Get the team-assigned member ID. */ GetFieldValue(pMember, BDA_MEMBER, BDA_MEMBER_FIELD_MEMBER_ID, dwValue); if (dwValue == CVY_BDA_INVALID_MEMBER_ID) dprintf(" Member ID: %s\n", "Invalid"); else dprintf(" Member ID: %u\n", dwValue); /* Get the master status flag. */ GetFieldValue(pMember, BDA_MEMBER, BDA_MEMBER_FIELD_MASTER, dwValue); dprintf(" Master: %s\n", (dwValue) ? "Yes" : "No"); /* Get the reverse hashing flag. */ GetFieldValue(pMember, BDA_MEMBER, BDA_MEMBER_FIELD_REVERSE_HASH, dwValue); dprintf(" Reverse hashing: %s\n", (dwValue) ? "Yes" : "No"); /* Get the pointer to the BDA team. */ GetFieldValue(pMember, BDA_MEMBER, BDA_MEMBER_FIELD_TEAM, pAddr); dprintf(" %sBDA team: 0x%p\n", (pAddr) ? "-" : "+", pAddr); /* If this adapter is part of a team, print out the team configuration and state. */ if (pAddr) { dprintf("\n"); PrintBDATeam(pAddr); } } /* * Function: PrintBDAMember * Description: Prints the BDA teaming configuration and state of a member. * Author: Created by shouse, 4.8.01 */ void PrintBDATeam (ULONG64 pTeam) { WCHAR szString[256]; ULONG64 pAddr; ULONG dwValue; /* Make sure the address is non-NULL. */ if (!pTeam) { dprintf("Error: Team is NULL.\n"); return; } dprintf(" BDA Team 0x%p\n", pTeam); /* Find out whether or not the team is active. */ GetFieldValue(pTeam, BDA_TEAM, BDA_TEAM_FIELD_ACTIVE, dwValue); dprintf(" Active: %s\n", (dwValue) ? "Yes" : "No"); /* Get the offset of the team ID and retrieve the string from that address. */ if (GetFieldOffset(BDA_TEAM, BDA_TEAM_FIELD_TEAM_ID, &dwValue)) dprintf("Can't get offset of %s in %s\n", BDA_TEAM_FIELD_TEAM_ID, BDA_TEAM); else { pAddr = pTeam + dwValue; /* Retrieve the contexts of the string and store it in a buffer. */ GetString(pAddr, szString, CVY_MAX_BDA_TEAM_ID + 1); dprintf(" Team ID: %ls\n", szString); } /* Get the current membership count. */ GetFieldValue(pTeam, BDA_TEAM, BDA_TEAM_FIELD_MEMBERSHIP_COUNT, dwValue); dprintf(" Number of members: %u\n", dwValue); /* Get the current membership list. */ GetFieldValue(pTeam, BDA_TEAM, BDA_TEAM_FIELD_MEMBERSHIP_FINGERPRINT, dwValue); dprintf(" Membership fingerprint: 0x%08x\n", dwValue); /* Get the current membership map. */ GetFieldValue(pTeam, BDA_TEAM, BDA_TEAM_FIELD_MEMBERSHIP_MAP, dwValue); dprintf(" Members: 0x%08x ", dwValue); /* If there are members in the map, print them. */ if (dwValue) { dprintf("("); PrintBDAMemberList(dwValue); dprintf(")"); } dprintf("\n"); /* Get the current consistency map. */ GetFieldValue(pTeam, BDA_TEAM, BDA_TEAM_FIELD_CONSISTENCY_MAP, dwValue); dprintf(" Consistent members: 0x%08x ", dwValue); /* If there are members in the map, print them. */ if (dwValue) { dprintf("("); PrintBDAMemberList(dwValue); dprintf(")"); } dprintf("\n"); /* Get the offset of the load module pointer. */ if (GetFieldOffset(BDA_TEAM, BDA_TEAM_FIELD_LOAD, &dwValue)) dprintf("Can't get offset of %s in %s\n", BDA_TEAM_FIELD_LOAD, BDA_TEAM); else { pAddr = pTeam + dwValue; /* Retrieve the pointer. */ pAddr = GetPointerFromAddress(pAddr); dprintf(" Load: 0x%p\n", pAddr); } /* Get the offset of the load lock pointer. */ if (GetFieldOffset(BDA_TEAM, BDA_TEAM_FIELD_LOAD_LOCK, &dwValue)) dprintf("Can't get offset of %s in %s\n", BDA_TEAM_FIELD_LOAD_LOCK, BDA_TEAM); else { pAddr = pTeam + dwValue; /* Retrieve the pointer. */ pAddr = GetPointerFromAddress(pAddr); dprintf(" Load lock: 0x%p\n", pAddr); } /* Get the offset of the previous pointer. */ if (GetFieldOffset(BDA_TEAM, BDA_TEAM_FIELD_PREV, &dwValue)) dprintf("Can't get offset of %s in %s\n", BDA_TEAM_FIELD_PREV, BDA_TEAM); else { pAddr = pTeam + dwValue; /* Retrieve the pointer. */ pAddr = GetPointerFromAddress(pAddr); dprintf(" Previous BDA Team: 0x%p\n", pAddr); } /* Get the offset of the next pointer. */ if (GetFieldOffset(BDA_TEAM, BDA_TEAM_FIELD_NEXT, &dwValue)) dprintf("Can't get offset of %s in %s\n", BDA_TEAM_FIELD_NEXT, BDA_TEAM); else { pAddr = pTeam + dwValue; /* Retrieve the pointer. */ pAddr = GetPointerFromAddress(pAddr); dprintf(" Next BDA Team: 0x%p\n", pAddr); } } /* * Function: PrintBDAMemberList * Description: Prints a list of members in a BDA membership or consistency map. * Author: Created by shouse, 4.8.01 */ void PrintBDAMemberList (ULONG dwMemberMap) { BOOL bFirst = TRUE; ULONG dwMemberNum = 0; /* As long as there are hosts still in the map, print them. */ while (dwMemberMap) { /* If the least significant bit is set, print the host number. */ if (dwMemberMap & 0x00000001) { /* If this is the first host printed, just print the number. */ if (bFirst) { dprintf("%u", dwMemberNum); bFirst = FALSE; } else /* Otherwise, we need to print a comma first. */ dprintf(", %u", dwMemberNum); } /* Increment the host number and shift the map to the right one bit. */ dwMemberNum++; dwMemberMap >>= 1; } } /* * Function: PrintQueue * Description: Prints MaxEntries entries in a connection descriptor queue. * Author: Created by shouse, 4.15.01 */ void PrintQueue (ULONG64 pQueue, ULONG dwMaxEntries) { } /* * Function: PrintMap * Description: Searches the given load module to determine who should accept this packet. If * state for this packet already exists, it is printed. * Author: Created by shouse, 4.15.01 */ void PrintMap (ULONG64 pLoad, ULONG dwClientIPAddress, ULONG dwClientPort, ULONG dwServerIPAddress, ULONG dwServerPort, BOOLEAN bIsTCP, TCP_PACKET_TYPE ePktType) { WCHAR szString[256]; ULONG64 pAddr; ULONG dwValue; /* Make sure the load address is non-NULL. */ if (!pLoad) { dprintf("Error: Load is NULL.\n"); return; } dprintf("Looking for connection tuple (0x%08x, %u, 0x%08x, %u, %s", dwClientIPAddress, dwClientPort, dwServerIPAddress, dwServerPort, (bIsTCP) ? "TCP" : "UDP"); if (bIsTCP) dprintf(" %s)\n", TCPPacketTypeToString(ePktType)); else dprintf(")\n"); dprintf("Map returned: %u\n", Map(dwClientIPAddress, dwServerIPAddress)); }