/*++ Copyright (c) 1995 Microsoft Corporation Module Name: net\rtm\rtmdlg.c Abstract: Routing Table Manager DLL. Debugging code to display table entries in dialog box Author: Vadim Eydelman Revision History: --*/ #include "pchrtm.h" #pragma hdrstop #if DBG #define IP_PROTOCOL RR_RoutingProtocol #define IP_INTERFACE RR_InterfaceID #define IP_METRIC RR_FamilySpecificData.FSD_Metric1 #define IP_TIMESTAMP RR_TimeStamp #define IP_NET_NUM RR_Network.N_NetNumber #define IP_NET_MSK RR_Network.N_NetMask #define IP_NEXT_HOP_NUM RR_NextHopAddress.N_NetNumber #define IP_NEXT_HOP_MSK RR_NextHopAddress.N_NetMask #define IP_ADPTER_INDEX RR_FamilySpecificData.FSD_AdapterIndex #define IP_PROTOCOL_METRIC RR_FamilySpecificData.FSD_ProtocolMetric #define IP_PSD RR_ProtocolSpecificData #define IPX_PROTOCOL RR_RoutingProtocol #define IPX_INTERFACE RR_InterfaceID #define IPX_METRIC RR_FamilySpecificData.FSD_TickCount #define IPX_TIMESTAMP RR_TimeStamp #define IPX_NET_NUM RR_Network.N_NetNumber #define IPX_NEXT_HOP_MAC RR_NextHopAddress.NHA_Mac #define IPX_HOP_COUNT RR_FamilySpecificData.FSD_HopCount #define IPX_PSD RR_ProtocolSpecificData // Make table accessible to debugging code extern RTM_TABLE Tables[RTM_NUM_OF_PROTOCOL_FAMILIES]; // Define protype internal to rtm.c VOID ConsolidateNetNumberLists ( PRTM_TABLE Table // Table for which operation is performed ); DWORD DbgLevel = 0; DWORD MaxTicks = MAXULONG; DWORD MaxMessages=10000; HANDLE RTDlgThreadHdl; ULONG DisplayedTableIdx = 0xFFFFFFFF; HWND RTDlg=NULL; // Internal function prototypes INT_PTR CALLBACK RTDlgProc ( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ); INT PrintRoute ( char *buffer, PRTM_ROUTE_NODE node, BOOLEAN full ); VOID FillUpRouteLB ( ); #define DLLInstanceHdl ((HANDLE)param) DWORD WINAPI RTDialogThread ( LPVOID param ) { MSG msg; DWORD status; BOOLEAN Done = FALSE; HANDLE RegChangeEvt; HKEY regHdl; DWORD length, disposition, value; RegChangeEvt = CreateEvent (NULL, FALSE, TRUE, NULL); ASSERTERR (RegChangeEvt!=NULL); status = RegCreateKeyEx (HKEY_LOCAL_MACHINE, TEXT ("System\\CurrentControlSet\\Services\\RemoteAccess\\RTM"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, ®Hdl, &disposition ); ASSERTMSG ("Can't create registry key. ", status==NO_ERROR); length = sizeof (DWORD); status = RegQueryValueEx (regHdl, TicksWrapAroundValueName, NULL, NULL, (PUCHAR)&value, &length); if (status==NO_ERROR) MaxTicks = value; length = sizeof (DWORD); status = RegQueryValueEx (regHdl, MaxMessagesValueName, NULL, NULL, (PUCHAR)&value, &length); if (status==NO_ERROR) MaxMessages = value; while (!Done) { status = MsgWaitForMultipleObjects (1, &RegChangeEvt, FALSE, INFINITE, QS_ALLINPUT); if (status==(WAIT_OBJECT_0+1)) { while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message==WM_QUIT) { Done = TRUE; break; } else if (!IsWindow(RTDlg) || !IsDialogMessage(RTDlg, &msg)) { TranslateMessage (&msg); DispatchMessage (&msg); } } } else if (status==WAIT_OBJECT_0) { length = sizeof (DWORD); status = RegQueryValueEx (regHdl, DbgLevelValueName, NULL, NULL, (PUCHAR)&DbgLevel, &length); if (status!=NO_ERROR) DbgLevel = 0; IF_DEBUG (DISPLAY_TABLE) { if (!IsWindow(RTDlg)) { RTDlg = CreateDialog (DLLInstanceHdl, MAKEINTRESOURCE (IDD_RTM_TABLE), NULL, &RTDlgProc); ASSERTERR (RTDlg!=NULL); } } else { if (IsWindow (RTDlg)) { DestroyWindow (RTDlg); RTDlg = NULL; } } status = RegNotifyChangeKeyValue (regHdl, FALSE, REG_NOTIFY_CHANGE_LAST_SET, RegChangeEvt, TRUE); ASSERTMSG ("Can't start registry notifications. ", status==NO_ERROR); } } if (IsWindow (RTDlg)) { DestroyWindow (RTDlg); RTDlg = NULL; } RegCloseKey (regHdl); return 0; } #undef DLLInstanceHdl // Dialog box procedure INT_PTR CALLBACK RTDlgProc ( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { BOOL res = FALSE; char buf[32]; int idx; TIMER_BASIC_INFORMATION TimerInfo; DWORD status; switch (uMsg) { case WM_INITDIALOG: // Dialog is being created // Fill in protocol family combo box SendDlgItemMessage (hDlg, IDC_PROTOCOL_FAMILY, CB_INSERTSTRING, RTM_PROTOCOL_FAMILY_IPX, (LPARAM)"IPX" ); SendDlgItemMessage (hDlg, IDC_PROTOCOL_FAMILY, CB_INSERTSTRING, RTM_PROTOCOL_FAMILY_IP, (LPARAM)"IP" ); DisplayedTableIdx = RTM_PROTOCOL_FAMILY_IPX; SendDlgItemMessage (hDlg, IDC_PROTOCOL_FAMILY, CB_SETCURSEL, DisplayedTableIdx, 0 ); // Start timer (updates improvized clock) SetTimer (hDlg, 0, 1000, NULL); res = TRUE; break; case WM_COMMAND: // Process child window messages only switch (LOWORD(wParam)) { case IDCANCEL: res = FALSE; break; case IDC_PROTOCOL_FAMILY: if (HIWORD(wParam)==CBN_SELENDOK) { DWORD newFamily = (DWORD)SendMessage ( (HWND)lParam, CB_GETCURSEL, 0, 0); if ((newFamily!=CB_ERR) && (newFamily!=DisplayedTableIdx)) { // Change the displayed table if // user makes different selection DisplayedTableIdx = newFamily; SendDlgItemMessage (hDlg, IDL_ROUTES, LB_RESETCONTENT, 0, 0); if (Tables[DisplayedTableIdx].RT_Heap!=NULL) { ConsolidateNetNumberLists (&Tables[DisplayedTableIdx]); FillUpRouteLB (); } } } break; // case IDL_ROUTES: // // Update entry on which user double clicks // if (HIWORD(wParam)==LBN_SELCHANGE) // UpdateLBSelections (); // break; case IDB_RESYNC: SendDlgItemMessage (hDlg, IDL_ROUTES, LB_RESETCONTENT, 0, 0); if (Tables[DisplayedTableIdx].RT_Heap!=NULL) { ConsolidateNetNumberLists (&Tables[DisplayedTableIdx]); FillUpRouteLB (); } break; } break; case WM_TIMER: // Update improvised clock sprintf (buf, "%08d", GetTickCount ()/1000); SendDlgItemMessage (hDlg, IDT_TICK_COUNT, WM_SETTEXT, 0, (LPARAM)buf); status = NtQueryTimer ( Tables[DisplayedTableIdx].RT_ExpirationTimer, TimerBasicInformation, &TimerInfo, sizeof (TimerInfo), NULL); if (NT_SUCCESS (status)) { if (!TimerInfo.TimerState) sprintf (buf, "%08d", (ULONG)((LONGLONG)TimerInfo.RemainingTime.QuadPart /(10000*1000))); else sprintf (buf, "Not set"); } else sprintf (buf, "error"); SendDlgItemMessage (hDlg, IDT_EXPIRATION, WM_SETTEXT, 0, (LPARAM)buf); status = NtQueryTimer ( Tables[DisplayedTableIdx].RT_UpdateTimer, TimerBasicInformation, &TimerInfo, sizeof (TimerInfo), NULL); if (NT_SUCCESS (status)) { if (!TimerInfo.TimerState) sprintf (buf, "%08d", (ULONG)((LONGLONG)TimerInfo.RemainingTime.QuadPart /(10000*1000))); else sprintf (buf, "Not set"); } else sprintf (buf, "error"); SendDlgItemMessage (hDlg, IDT_UPDATE, WM_SETTEXT, 0, (LPARAM)buf); res = TRUE; break; case RT_ADDROUTE: SendDlgItemMessage (hDlg, IDL_ROUTES, LB_INSERTSTRING, wParam, lParam); // Trace2 (ANY, "%2d - %s added\n", wParam, lParam); GlobalFree ((VOID *)lParam); res = TRUE; break; case RT_DELETEROUTE: idx = (int) SendDlgItemMessage (hDlg, IDL_ROUTES, LB_FINDSTRING, (WPARAM)0, lParam); if (idx!=LB_ERR) SendDlgItemMessage (hDlg, IDL_ROUTES, LB_DELETESTRING, (WPARAM)idx, 0); // Trace2 (ANY, "%2d - %s deleted\n", idx, lParam); GlobalFree ((VOID *)lParam); res = TRUE; break; case WM_DESTROY: DisplayedTableIdx = 0xFFFFFFFF; break; } return res; } // Prints route information INT PrintRoute ( char *buf, // Buffer to print to PRTM_ROUTE_NODE node, // Route to print BOOLEAN full // Print everything (including variable part) ) { INT res; switch (DisplayedTableIdx) { case RTM_PROTOCOL_FAMILY_IPX: res = sprintf (buf, " %08x ", ((PRTM_IPX_ROUTE)&node->RN_Route)->IPX_NET_NUM ); break; case RTM_PROTOCOL_FAMILY_IP: res = sprintf (buf, "%08x-%08x", ((PRTM_IP_ROUTE)&node->RN_Route)->IP_NET_NUM, ((PRTM_IP_ROUTE)&node->RN_Route)->IP_NET_MSK ); break; } res += sprintf (&buf[res], " %4d %4d", node->RN_Route.XX_INTERFACE, node->RN_Route.XX_PROTOCOL); switch (DisplayedTableIdx) { case RTM_PROTOCOL_FAMILY_IPX: res += sprintf (&buf[res], " %02x%02x%02x%02x%02x%02x ", ((PRTM_IPX_ROUTE)&node->RN_Route)->IPX_NEXT_HOP_MAC[0], ((PRTM_IPX_ROUTE)&node->RN_Route)->IPX_NEXT_HOP_MAC[1], ((PRTM_IPX_ROUTE)&node->RN_Route)->IPX_NEXT_HOP_MAC[2], ((PRTM_IPX_ROUTE)&node->RN_Route)->IPX_NEXT_HOP_MAC[3], ((PRTM_IPX_ROUTE)&node->RN_Route)->IPX_NEXT_HOP_MAC[4], ((PRTM_IPX_ROUTE)&node->RN_Route)->IPX_NEXT_HOP_MAC[5] ); break; case RTM_PROTOCOL_FAMILY_IP: res += sprintf (&buf[res], " %08x-%08x", ((PRTM_IP_ROUTE)&node->RN_Route)->IP_NEXT_HOP_NUM, ((PRTM_IP_ROUTE)&node->RN_Route)->IP_NEXT_HOP_MSK ); break; } if (full) { switch (DisplayedTableIdx) { case RTM_PROTOCOL_FAMILY_IPX: res += sprintf (&buf[res], " %6d %08d %1d %1d", ((PRTM_IPX_ROUTE)&node->RN_Route)->IPX_METRIC, node->RN_ExpirationTime/1000, IsBest (node), IsEnabled (node)); break; case RTM_PROTOCOL_FAMILY_IP: res += sprintf (&buf[res], " %6d %08d %1d %1d", ((PRTM_IP_ROUTE)&node->RN_Route)->IP_METRIC, node->RN_ExpirationTime/1000, IsBest (node), IsEnabled (node)); break; } } return res; } // Fills list box with all routes in the current table VOID FillUpRouteLB ( void ) { PLIST_ENTRY cur; INT idx=0; PRTM_TABLE Table = &Tables[DisplayedTableIdx]; // Make sure we own the table while printing EnterSyncList (Table, &Table->RT_NetNumberMasterList, TRUE); cur = Table->RT_NetNumberMasterList.RSL_Head.Flink; while (cur!=&Table->RT_NetNumberMasterList.RSL_Head) { PRTM_ROUTE_NODE node = CONTAINING_RECORD (cur, RTM_ROUTE_NODE, RN_Links[RTM_NET_NUMBER_LIST_LINK]); if (!IsEnumerator (node)) AddRouteToLB (Table, node, idx++); cur = cur->Flink; } LeaveSyncList (Table, &Table->RT_NetNumberMasterList); } // Insert line with item data at specified position in the list box VOID AddRouteToLB ( PRTM_TABLE Table, PRTM_ROUTE_NODE node, INT idx ) { char *buf; if (IsWindow (RTDlg) && (Table==&Tables[DisplayedTableIdx])) { buf = (char *)GlobalAlloc (GMEM_FIXED, 80); // Print node PrintRoute (buf, node, TRUE); // Insert at specified position SendNotifyMessage (RTDlg, RT_ADDROUTE, (WPARAM)idx, (LPARAM)buf); } } // Deletes route line from the list box VOID DeleteRouteFromLB ( PRTM_TABLE Table, PRTM_ROUTE_NODE node ) { char *buf; if (IsWindow (RTDlg) && (Table==&Tables[DisplayedTableIdx])) { buf = (char *)GlobalAlloc (GMEM_FIXED, 80); // Print route info PrintRoute (buf, node, FALSE); // Find corresponding line in the list SendNotifyMessage (RTDlg, RT_DELETEROUTE, 0, (LPARAM)buf); } } #endif