/*++ Copyright (c) 1995 Microsoft Corporation Module Name: net\ip\rtrmgr\init.c Abstract: IP Router Manager code Revision History: Gurdeep Singh Pall 6/14/95 Created --*/ #include "allinc.h" DWORD RtrMgrMIBEntryCreate( IN DWORD dwRoutingPid, IN DWORD dwEntrySize, IN LPVOID lpEntry ); DWORD RtrMgrMIBEntryDelete( IN DWORD dwRoutingPid, IN DWORD dwEntrySize, IN LPVOID lpEntry ); DWORD RtrMgrMIBEntryGet( IN DWORD dwRoutingPid, IN DWORD dwInEntrySize, IN LPVOID lpInEntry, IN OUT LPDWORD lpOutEntrySize, OUT LPVOID lpOutEntry ); DWORD RtrMgrMIBEntryGetFirst( IN DWORD dwRoutingPid, IN DWORD dwInEntrySize, IN LPVOID lpInEntry, IN OUT LPDWORD lpOutEntrySize, OUT LPVOID lpOutEntry ); DWORD RtrMgrMIBEntryGetNext( IN DWORD dwRoutingPid, IN DWORD dwInEntrySize, IN LPVOID lpInEntry, IN OUT LPDWORD lpOutEntrySize, OUT LPVOID lpOutEntry ); DWORD RtrMgrMIBEntrySet( IN DWORD dwRoutingPid, IN DWORD dwEntrySize, IN LPVOID lpEntry ); DWORD InitRouter( PRTR_INFO_BLOCK_HEADER pGlobalInfo ) /*++ Routine Description: Loads routing protocols, loads bootp agent, opens the approp. drivers, and starts the worker thread. Arguments: GlobalInfo passed in by DIM Return Value: NO_ERROR or some error code --*/ { HANDLE hThread; DWORD dwResult, dwTid, i; PGLOBAL_INFO pInfo; PRTR_TOC_ENTRY pToc; IPSNMPInfo ipsiInfo; RTM_ENTITY_INFO entityInfo; PIP_NAT_GLOBAL_INFO pNatInfo; PMIB_IPFORWARDTABLE pInitRouteTable; PROUTE_LIST_ENTRY prl; MGM_CALLBACKS mgmCallbacks; ROUTER_MANAGER_CONFIG mgmConfig; TraceEnter("InitRouter"); // // Initialize all the locks (MIB handlers and ICB_LIST/PROTOCOL_CB_LIST) // VERY IMPORTANT, since we break out of this and try and do a cleanup // which needs the lists and the locks, WE MUST initialize the lists // and the locks BEFORE the first abnormal exit from this function // for(i = 0; i < NUM_LOCKS; i++) { RtlInitializeResource(&g_LockTable[i]); } // // Init the list head for interfaces // InitializeListHead(&ICBList); // // Initialize ICB Hash lookup table and the Adapter to Interface Hash // for (i=0; iInfoSize is 0)) { LogErr0(NO_GLOBAL_INFO, ERROR_NO_DATA); Trace0(ERR, "InitRouter: No Global Info - can not start router"); TraceLeave("InitRouter"); return ERROR_CAN_NOT_COMPLETE; } pInfo = (PGLOBAL_INFO)GetInfoFromTocEntry(pGlobalInfo, pToc); if(pInfo is NULL) { LogErr0(NO_GLOBAL_INFO, ERROR_NO_DATA); Trace0(ERR, "InitRouter: No Global Info - can not start router"); TraceLeave("InitRouter"); return ERROR_CAN_NOT_COMPLETE; } #pragma warning(push) #pragma warning(disable:4296) if((pInfo->dwLoggingLevel > IPRTR_LOGGING_INFO) or (pInfo->dwLoggingLevel < IPRTR_LOGGING_NONE)) #pragma warning(pop) { Trace1(ERR, "InitRouter: Global info has invalid logging level of %d", pInfo->dwLoggingLevel); g_dwLoggingLevel = IPRTR_LOGGING_INFO; } else { g_dwLoggingLevel = pInfo->dwLoggingLevel; } // // Allocate private heap // IPRouterHeap = HeapCreate(0, 5000, 0); if(IPRouterHeap is NULL) { dwResult = GetLastError() ; Trace1(ERR, "InitRouter: Error %d creating IPRouterHeap", dwResult) ; TraceLeave("InitRouter"); return dwResult ; } // // Create the events needed to talk to the routing protocols, // DIM and WANARP // g_hRoutingProtocolEvent = CreateEvent(NULL,FALSE,FALSE,NULL); g_hStopRouterEvent = CreateEvent(NULL,FALSE,FALSE,NULL); g_hSetForwardingEvent = CreateEvent(NULL,FALSE,FALSE,NULL); g_hForwardingChangeEvent = CreateEvent(NULL,FALSE,FALSE,NULL); g_hDemandDialEvent = CreateEvent(NULL,FALSE,FALSE,NULL); g_hIpInIpEvent = CreateEvent(NULL,FALSE,FALSE,NULL); g_hStackChangeEvent = CreateEvent(NULL,FALSE,FALSE,NULL); g_hRtrDiscSocketEvent = CreateEvent(NULL,FALSE,FALSE,NULL); g_hMHbeatSocketEvent = CreateEvent(NULL,FALSE,FALSE,NULL); g_hMcMiscSocketEvent = CreateEvent(NULL,FALSE,FALSE,NULL); g_hMzapSocketEvent = CreateEvent(NULL,FALSE,FALSE,NULL); for(i = 0; i < NUM_MCAST_IRPS; i++) { g_hMcastEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL); } for(i = 0; i < NUM_ROUTE_CHANGE_IRPS; i++) { g_hRouteChangeEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL); } g_hRtrDiscTimer = CreateWaitableTimer(NULL, FALSE, NULL); g_hRasAdvTimer = CreateWaitableTimer(NULL, FALSE, NULL); g_hMzapTimer = CreateWaitableTimer(NULL, FALSE, NULL); if((g_hRoutingProtocolEvent is NULL) or (g_hStopRouterEvent is NULL) or (g_hSetForwardingEvent is NULL) or (g_hForwardingChangeEvent is NULL) or (g_hDemandDialEvent is NULL) or (g_hIpInIpEvent is NULL) or (g_hStackChangeEvent is NULL) or (g_hRtrDiscSocketEvent is NULL) or (g_hRtrDiscTimer is NULL) or (g_hRasAdvTimer is NULL) or (g_hMcMiscSocketEvent is NULL) or (g_hMzapSocketEvent is NULL) or (g_hMHbeatSocketEvent is NULL)) { Trace0(ERR, "InitRouter: Couldnt create the needed events and timer"); TraceLeave("InitRouter"); return ERROR_CAN_NOT_COMPLETE; } for(i = 0; i < NUM_MCAST_IRPS; i++) { if(g_hMcastEvents[i] is NULL) { Trace0(ERR, "InitRouter: Couldnt create the mcast events"); TraceLeave("InitRouter"); return ERROR_CAN_NOT_COMPLETE; } } for(i = 0; i < NUM_ROUTE_CHANGE_IRPS; i++) { if(g_hRouteChangeEvents[i] is NULL) { Trace0(ERR, "InitRouter: Couldnt create the mcast events"); TraceLeave("InitRouter"); return ERROR_CAN_NOT_COMPLETE; } } Trace0(GLOBAL, "InitRouter: Created necessary events and timer"); dwResult = MprConfigServerConnect(NULL, &g_hMprConfig); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: Error %d calling MprConfigServerConnect", dwResult); return dwResult; } g_sinAllSystemsAddr.sin_family = AF_INET; g_sinAllSystemsAddr.sin_addr.s_addr = ALL_SYSTEMS_MULTICAST_GROUP; g_sinAllSystemsAddr.sin_port = 0; g_pIpHeader = (PIP_HEADER)g_pdwIpAndIcmpBuf; g_wsaIpRcvBuf.buf = (PBYTE)g_pIpHeader; g_wsaIpRcvBuf.len = ICMP_RCV_BUFFER_LEN * sizeof(DWORD); g_wsaMcRcvBuf.buf = g_byMcMiscBuffer; g_wsaMcRcvBuf.len = sizeof(g_byMcMiscBuffer); // // Get all the routes that are in the stack and store them away // pInitRouteTable = NULL; InitializeListHead( &g_leStackRoutesToRestore ); dwResult = AllocateAndGetIpForwardTableFromStack(&pInitRouteTable, FALSE, IPRouterHeap, 0); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: Couldnt get initial routes. Error %d", dwResult); } else { if(pInitRouteTable->dwNumEntries isnot 0) { TraceRoute0( ROUTE, "Init. table routes\n" ); for ( i = 0; i < pInitRouteTable-> dwNumEntries; i++ ) { if (pInitRouteTable->table[i].dwForwardProto != MIB_IPPROTO_NETMGMT) { continue; } TraceRoute3( ROUTE, "%d.%d.%d.%d/%d.%d.%d.%d, type 0x%x", PRINT_IPADDR( pInitRouteTable-> table[i].dwForwardDest ), PRINT_IPADDR( pInitRouteTable-> table[i].dwForwardMask ), pInitRouteTable-> table[i].dwForwardType ); // // Allocate and store route in a linked list // prl = HeapAlloc( IPRouterHeap, HEAP_ZERO_MEMORY, sizeof(ROUTE_LIST_ENTRY) ); if (prl is NULL) { Trace2( ERR, "InitRouter: error %d allocating %d bytes " "for stack route entry", ERROR_NOT_ENOUGH_MEMORY, sizeof(ROUTE_LIST_ENTRY) ); dwResult = ERROR_NOT_ENOUGH_MEMORY; break; } InitializeListHead( &prl->leRouteList ); prl->mibRoute = pInitRouteTable-> table[i]; InsertTailList( &g_leStackRoutesToRestore, &prl->leRouteList ); } if (dwResult isnot NO_ERROR) { while (!IsListEmpty(&g_leStackRoutesToRestore)) { prl = (PROUTE_LIST_ENTRY) RemoveHeadList( &g_leStackRoutesToRestore ); HeapFree(IPRouterHeap, 0, prl); } } } HeapFree(IPRouterHeap, 0, pInitRouteTable); pInitRouteTable = NULL; } // // The route table is created implicitly by RTM at the // time of the first registration call (see call below) // // // Setup common params for all registrations with RTMv2 // entityInfo.RtmInstanceId = 0; // routerId; entityInfo.AddressFamily = AF_INET; entityInfo.EntityId.EntityInstanceId = 0; // // Register with RTM using the appropriate proto ids // // // This 1st registration is also used for performing // RTM operations common for all these registrations, // As an example it is used to get any changed dests. // entityInfo.EntityId.EntityProtocolId = PROTO_IP_LOCAL; dwResult = RtmRegisterEntity(&entityInfo, NULL, RtmEventCallback, FALSE, &g_rtmProfile, &g_hLocalRoute); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: RtmRegisterClient for local routes failed %d", dwResult) ; TraceLeave("InitRouter"); return dwResult ; } // Also register for dest change notifications dwResult = RtmRegisterForChangeNotification(g_hLocalRoute, RTM_VIEW_MASK_UCAST, RTM_CHANGE_TYPE_FORWARDING, NULL, &g_hNotification); if (dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: RtmRegisterForChangeNotificaition failed %d", dwResult) ; TraceLeave("InitRouter"); return dwResult ; } // // Register more times for each type of route // entityInfo.EntityId.EntityProtocolId = PROTO_IP_NT_AUTOSTATIC; dwResult = RtmRegisterEntity(&entityInfo, NULL, NULL, FALSE, &g_rtmProfile, &g_hAutoStaticRoute); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: RtmRegisterClient for AutoStatic routes failed %d", dwResult) ; TraceLeave("InitRouter"); return dwResult ; } entityInfo.EntityId.EntityProtocolId = PROTO_IP_NT_STATIC; dwResult = RtmRegisterEntity(&entityInfo, NULL, NULL, FALSE, &g_rtmProfile, &g_hStaticRoute); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: RtmRegisterClient for Static routes failed %d", dwResult) ; TraceLeave("InitRouter"); return dwResult ; } entityInfo.EntityId.EntityProtocolId = PROTO_IP_NT_STATIC_NON_DOD; dwResult = RtmRegisterEntity(&entityInfo, NULL, NULL, FALSE, &g_rtmProfile, &g_hNonDodRoute); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: RtmRegisterClient for DOD routes failed %d", dwResult) ; TraceLeave("InitRouter"); return dwResult ; } entityInfo.EntityId.EntityProtocolId = PROTO_IP_NETMGMT; dwResult = RtmRegisterEntity(&entityInfo, NULL, RtmEventCallback, FALSE, &g_rtmProfile, &g_hNetMgmtRoute); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: RtmRegisterClient for NetMgmt routes failed %d", dwResult) ; TraceLeave("InitRouter"); return dwResult ; } // Also register for marked dest change notifications dwResult = RtmRegisterForChangeNotification(g_hNetMgmtRoute, RTM_VIEW_MASK_UCAST, RTM_CHANGE_TYPE_ALL | RTM_NOTIFY_ONLY_MARKED_DESTS, NULL, &g_hDefaultRouteNotification); if (dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: RtmRegisterForChangeNotificaition failed %d", dwResult) ; TraceLeave("InitRouter"); return dwResult ; } g_rgRtmHandles[0].dwProtoId = PROTO_IP_LOCAL; g_rgRtmHandles[0].hRouteHandle = g_hLocalRoute; g_rgRtmHandles[0].bStatic = FALSE; g_rgRtmHandles[1].dwProtoId = PROTO_IP_NT_AUTOSTATIC; g_rgRtmHandles[1].hRouteHandle = g_hAutoStaticRoute; g_rgRtmHandles[1].bStatic = TRUE; g_rgRtmHandles[2].dwProtoId = PROTO_IP_NT_STATIC; g_rgRtmHandles[2].hRouteHandle = g_hStaticRoute; g_rgRtmHandles[2].bStatic = TRUE; g_rgRtmHandles[3].dwProtoId = PROTO_IP_NT_STATIC_NON_DOD; g_rgRtmHandles[3].hRouteHandle = g_hNonDodRoute; g_rgRtmHandles[3].bStatic = TRUE; g_rgRtmHandles[4].dwProtoId = PROTO_IP_NETMGMT; g_rgRtmHandles[4].hRouteHandle = g_hNetMgmtRoute; g_rgRtmHandles[4].bStatic = FALSE; // // Initialize MGM // mgmConfig.dwLogLevel = g_dwLoggingLevel; mgmConfig.dwIfTableSize = MGM_IF_TABLE_SIZE; mgmConfig.dwGrpTableSize = MGM_GROUP_TABLE_SIZE; mgmConfig.dwSrcTableSize = MGM_SOURCE_TABLE_SIZE; mgmConfig.pfnAddMfeCallback = SetMfe; mgmConfig.pfnDeleteMfeCallback = DeleteMfe; mgmConfig.pfnGetMfeCallback = GetMfe; mgmConfig.pfnHasBoundaryCallback = RmHasBoundary; dwResult = MgmInitialize(&mgmConfig, &mgmCallbacks); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: Error %d initializing MGM\n", dwResult); TraceLeave("InitRouter"); return dwResult; } // // Store callbacks into MGM // g_pfnMgmMfeDeleted = mgmCallbacks.pfnMfeDeleteIndication; g_pfnMgmNewPacket = mgmCallbacks.pfnNewPacketIndication; g_pfnMgmBlockGroups = mgmCallbacks.pfnBlockGroups; g_pfnMgmUnBlockGroups = mgmCallbacks.pfnUnBlockGroups; g_pfnMgmWrongIf = mgmCallbacks.pfnWrongIfIndication; if(OpenIPDriver() isnot NO_ERROR) { Trace0(ERR, "InitRouter: Couldnt open IP driver"); TraceLeave("InitRouter"); return ERROR_OPEN_FAILED; } // // Do the multicast initialization // dwResult = OpenMulticastDriver(); if(dwResult isnot NO_ERROR) { Trace0(ERR, "InitRoute: Could not open IP Multicast device"); // // not an error, just continue; // } else { // // Find if we are in multicast mode // dwResult = StartMulticast(); if(dwResult isnot NO_ERROR) { Trace0(ERR, "InitRoute: Could not start multicast"); } } if(!RouterRoleLanOnly) { if((dwResult = InitializeWanArp()) isnot NO_ERROR) { Trace0(ERR, "InitRouter: Couldnt open WanArp driver"); TraceLeave("InitRouter"); return dwResult; } } SetPriorityInfo(pGlobalInfo); SetScopeInfo(pGlobalInfo); if((dwResult = InitializeMibHandler()) isnot NO_ERROR) { Trace1(ERR, "InitRouter: InitializeMibHandler failed, returned %d", dwResult); TraceLeave("InitRouter"); return dwResult; } // // Create Worker thread // hThread = CreateThread(NULL, 0, (PVOID) WorkerThread, pGlobalInfo, 0, &dwTid) ; if(hThread is NULL) { dwResult = GetLastError () ; Trace1(ERR, "InitRouter: CreateThread failed %d", dwResult); TraceLeave("InitRouter"); return dwResult ; } else { CloseHandle(hThread); } dwResult = OpenIpIpKey(); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InitRouter: Error %d opening ipinip key", dwResult); return ERROR_CAN_NOT_COMPLETE; } // // We load are routing protocols after all our own initialization, // since we dont know how they will interact with us // ENTER_WRITER(ICB_LIST); ENTER_WRITER(PROTOCOL_CB_LIST); LoadRoutingProtocols (pGlobalInfo); EXIT_LOCK(PROTOCOL_CB_LIST); EXIT_LOCK(ICB_LIST); TraceLeave("InitRouter"); return NO_ERROR; } DWORD LoadRoutingProtocols( PRTR_INFO_BLOCK_HEADER pGlobalInfo ) /*++ Routine Description: Loads and initializes all the routing protocols configured Called with ICBListLock and RoutingProcotoclCBListLock held Arguments GlobalInfo passed in by DIM Return Value: NO_ERROR or some error code --*/ { DWORD i, j, dwSize, dwNumProtoEntries, dwResult; PPROTO_CB pNewProtocolCb; PWCHAR pwszDllNames ; // array of dll names MPR_PROTOCOL_0 *pmpProtocolInfo; PVOID pvInfo; BOOL bFound; TraceEnter("LoadRoutingProtocols"); dwResult = MprSetupProtocolEnum(PID_IP, (PBYTE *)(&pmpProtocolInfo), &dwNumProtoEntries); if(dwResult isnot NO_ERROR) { Trace1(ERR, "LoadRoutingProtocols: Error %d loading protocol info from registry", dwResult); TraceLeave("LoadRoutingProtocols"); return dwResult; } for(i=0; i < pGlobalInfo->TocEntriesCount; i++) { ULONG ulStructureVersion, ulStructureSize, ulStructureCount; DWORD dwType; // // Read each TOC and see if it is PROTO_TYPE_UCAST/MCAST // If it does it is a loadable protocol and we get its info // from the registry // dwType = TYPE_FROM_PROTO_ID(pGlobalInfo->TocEntry[i].InfoType); if((dwType < PROTO_TYPE_MS1) and (pGlobalInfo->TocEntry[i].InfoSize > 0)) { bFound = FALSE; for(j = 0; j < dwNumProtoEntries; j ++) { if(pmpProtocolInfo[j].dwProtocolId is pGlobalInfo->TocEntry[i].InfoType) { // // well great, we have found it // bFound = TRUE; break; } } if(!bFound) { Trace1(ERR, "LoadRoutingProtocols: Couldnt find information for protocol ID %d", pGlobalInfo->TocEntry[i].InfoType); continue; } // // load library on the dll name provided // dwSize = (wcslen(pmpProtocolInfo[j].wszProtocol) + wcslen(pmpProtocolInfo[j].wszDLLName) + 2) * sizeof(WCHAR) + sizeof(PROTO_CB); pNewProtocolCb = HeapAlloc(IPRouterHeap, HEAP_ZERO_MEMORY, dwSize); if (pNewProtocolCb is NULL) { Trace2(ERR, "LoadRoutingProtocols: Error allocating %d bytes for %S", dwSize, pmpProtocolInfo[j].wszProtocol); continue ; } pvInfo = GetInfoFromTocEntry(pGlobalInfo, &(pGlobalInfo->TocEntry[i])); //ulStructureVersion = pGlobalInfo->TocEntry[i].InfoVersion; ulStructureVersion = 0x500; ulStructureSize = pGlobalInfo->TocEntry[i].InfoSize; ulStructureCount = pGlobalInfo->TocEntry[i].Count; dwResult = LoadProtocol(&(pmpProtocolInfo[j]), pNewProtocolCb, pvInfo, ulStructureVersion, ulStructureSize, ulStructureCount); if(dwResult isnot NO_ERROR) { Trace2(ERR, "LoadRoutingProtocols: %S failed to load: %d", pmpProtocolInfo[j].wszProtocol, dwResult); HeapFree (IPRouterHeap, 0, pNewProtocolCb) ; } else { pNewProtocolCb->posOpState = RTR_STATE_RUNNING ; // // Insert this routing protocol in the list of routing // protocols // InsertTailList(&g_leProtoCbList, &pNewProtocolCb->leList) ; Trace1(GLOBAL, "LoadRoutingProtocols: %S successfully initialized", pmpProtocolInfo[j].wszProtocol) ; TotalRoutingProtocols++ ; } } } MprSetupProtocolFree(pmpProtocolInfo); TraceLeave("LoadRoutingProtocols"); return NO_ERROR ; } DWORD StartDriverAndOpenHandle( PCHAR pszServiceName, PWCHAR pwszDriverName, PHANDLE phDevice ) /*++ Routine Description: Creates a handle to the IP NAT service on the local machine Then tries to start the service. Loops till the service starts. Can potentially loop forever. Then creates a handle to the device. Arguments None Return Value: NO_ERROR or some error code --*/ { NTSTATUS status; UNICODE_STRING nameString; IO_STATUS_BLOCK ioStatusBlock; OBJECT_ATTRIBUTES objectAttributes; SC_HANDLE schSCManager, schService; DWORD dwErr; SERVICE_STATUS ssStatus; BOOL bErr, bRet; ULONG ulCount; TraceEnter("StartDriver"); schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (schSCManager is NULL) { dwErr = GetLastError(); Trace2(ERR, "StartDriver: Error %d opening svc controller for %s", dwErr, pszServiceName); TraceLeave("StartDriver"); return ERROR_OPEN_FAILED; } schService = OpenService(schSCManager, pszServiceName, SERVICE_ALL_ACCESS); if(schService is NULL) { dwErr = GetLastError(); Trace2(ERR, "StartDriver: Error %d opening %s", dwErr, pszServiceName); CloseServiceHandle(schSCManager); TraceLeave("StartDriver"); return ERROR_OPEN_FAILED; } __try { bRet = FALSE; bErr = QueryServiceStatus(schService, &ssStatus); if(!bErr) { dwErr = GetLastError(); Trace2(ERR, "StartDriver: Error %d querying %s status to see if it is already running", dwErr, pszServiceName); __leave; } // // If the driver is running, we shut it down. This forces a // cleanup of all its internal data structures. // if(ssStatus.dwCurrentState isnot SERVICE_STOPPED) { if(!ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus)) { dwErr = GetLastError(); Trace2(ERR, "StartDriver: %s was running at init time. Attempts to stop it caused error %d", pszServiceName, dwErr); } else { Sleep(1000); // // Now loop for 10 seconds waiting for the service to stop // ulCount = 0; while(ulCount < 5) { bErr = QueryServiceStatus(schService, &ssStatus); if(!bErr) { dwErr = GetLastError(); break; } else { if (ssStatus.dwCurrentState is SERVICE_STOPPED) { break; } else { ulCount++; Sleep(2000); } } } if(ssStatus.dwCurrentState isnot SERVICE_STOPPED) { if(ulCount is 5) { dwErr = ERROR_SERVICE_REQUEST_TIMEOUT; } Trace2(ERR, "StartDriver: Error %d stopping %s which was running at init time", dwErr, pszServiceName); __leave; } } } // // Query the service status one more time to see // if it is now stopped (because it was never running // or because it was started and we managed to stop // it successfully // bErr = QueryServiceStatus(schService, &ssStatus); if(!bErr) { dwErr = GetLastError(); Trace2(ERR, "StartDriver: Error %d querying %s status to see if it is stopped", dwErr, pszServiceName); __leave; } if(ssStatus.dwCurrentState is SERVICE_STOPPED) { // // Ok so at this time the service is stopped, lets start the // service // if(!StartService(schService, 0, NULL)) { dwErr = GetLastError(); Trace2(ERR, "StartDriver: Error %d starting %s", dwErr, pszServiceName); __leave; } // // Sleep for 1 second to avoid loop // Sleep(1000); ulCount = 0; // // We will wait for 30 seconds for the driver to start // while(ulCount < 6) { bErr = QueryServiceStatus(schService, &ssStatus); if(!bErr) { dwErr = GetLastError(); break; } else { if (ssStatus.dwCurrentState is SERVICE_RUNNING) { break; } else { ulCount++; Sleep(5000); } } } if(ssStatus.dwCurrentState isnot SERVICE_RUNNING) { if(ulCount is 6) { dwErr = ERROR_SERVICE_REQUEST_TIMEOUT; } Trace2(ERR, "StartDriver: Error %d starting %s", dwErr, pszServiceName); __leave; } } // // Now the service is definitely up and running // RtlInitUnicodeString(&nameString, pwszDriverName); InitializeObjectAttributes(&objectAttributes, &nameString, OBJ_CASE_INSENSITIVE, NULL, NULL); status = NtCreateFile(phDevice, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, 0, NULL, 0); if(!NT_SUCCESS(status)) { Trace2(ERR, "StartDriver: NtStatus %x creating handle to %S", status, pwszDriverName); __leave; } bRet = TRUE; } __finally { CloseServiceHandle(schSCManager); CloseServiceHandle(schService); TraceLeave("StartDriver"); } if(!bRet) { return ERROR_OPEN_FAILED; } else { return NO_ERROR; } } DWORD OpenIPDriver( VOID ) /*++ Routine Description: Opens a handle to the IP Driver Arguments None Return Value: NO_ERROR or some error code --*/ { NTSTATUS status; UNICODE_STRING nameString; IO_STATUS_BLOCK ioStatusBlock; OBJECT_ATTRIBUTES objectAttributes; DWORD dwResult = NO_ERROR; TraceEnter("OpenIPDriver"); do { RtlInitUnicodeString(&nameString, DD_IP_DEVICE_NAME); InitializeObjectAttributes(&objectAttributes, &nameString, OBJ_CASE_INSENSITIVE, NULL, NULL); status = NtCreateFile(&g_hIpDevice, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, 0, NULL, 0); if(!NT_SUCCESS(status)) { Trace1(ERR, "OpenIPDriver: Couldnt create IP driver handle. NtStatus %x", status); dwResult = ERROR_OPEN_FAILED; break; } // // Open change notification handle to TCPIP stack // ZeroMemory(&ioStatusBlock, sizeof(IO_STATUS_BLOCK)); #if 1 status = NtCreateFile( &g_hIpRouteChangeDevice, GENERIC_EXECUTE, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, 0, NULL, 0 ); #else g_hIpRouteChangeDevice = CreateFile( TEXT("\\\\.\\Ip"), GENERIC_EXECUTE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_OVERLAPPED, NULL ); if (g_hIpRouteChangeDevice is NULL) #endif if (!NT_SUCCESS(status)) { Trace1( ERR, "OpenIPDriver: Couldnt create change notificatio handle." "NtStatus %x", status ); dwResult = ERROR_OPEN_FAILED; CloseHandle( g_hIpDevice ); g_hIpDevice = NULL; } g_IpNotifyData.Version = IPNotifySynchronization; g_IpNotifyData.Add = 0; } while( FALSE ); TraceLeave("OpenIPDriver"); return dwResult; } DWORD OpenMulticastDriver( VOID ) { NTSTATUS status; UNICODE_STRING nameString; IO_STATUS_BLOCK ioStatusBlock; OBJECT_ATTRIBUTES objectAttributes; DWORD i; TraceEnter("OpenMulticastDriver"); RtlInitUnicodeString(&nameString, DD_IPMCAST_DEVICE_NAME); InitializeObjectAttributes(&objectAttributes, &nameString, OBJ_CASE_INSENSITIVE, NULL, NULL); status = NtCreateFile(&g_hMcastDevice, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, 0, NULL, 0); if(status isnot STATUS_SUCCESS) { Trace2(MCAST, "OpenMulticastDriver: Device Name %S could not be opened -> error code %d\n", DD_IPMCAST_DEVICE_NAME, status); g_hMcastDevice = NULL; return ERROR_OPEN_FAILED; } TraceLeave("OpenMulticastDriver"); return NO_ERROR; } DWORD EnableNetbtBcastForwarding( DWORD dwEnable ) /*++ Routine description: Sets the NETBT proxy mode to enable NETBT broadcast forwarding. This enables RAS clients to resolve names (and consequently) access resources on the networks (LANs) connected to the RAS server without having WINS/DNS configured. Arguements : Return Value : NO_ERROR --*/ { HKEY hkWanarpAdapter = NULL, hkNetbtParameters = NULL, hkNetbtInterface = NULL; DWORD dwSize = 0, dwResult, dwType = 0, dwMode = 0, dwFlags; PBYTE pbBuffer = NULL; PWCHAR pwcGuid; WCHAR wszNetbtInterface[256] = L"\0"; TraceEnter("EnableNetbtBcastForwarding"); do { // // Step I // Query appropriate WANARP regsitry keys to find GUID // corresponding to Internal (RAS server adapter) // dwResult = RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\NdisWanIP", 0, KEY_READ, &hkWanarpAdapter ); if (dwResult isnot NO_ERROR) { Trace1( ERR, "EnableNetbtBcastForwarding : error %d opening" "NdisWanIP key\n", dwResult ); break; } // // query size of buffer required. // dwResult = RegQueryValueExW( hkWanarpAdapter, L"IpConfig", NULL, &dwType, (PBYTE)NULL, &dwSize ); if (dwResult isnot NO_ERROR) { Trace1( ERR, "EnableNetbtBcastForwarding : error %d querying" "IPConfig value\n", dwResult ); break; } // // Allocate buffer for value // pbBuffer = (PBYTE) HeapAlloc( GetProcessHeap(), 0, dwSize ); if ( pbBuffer == NULL ) { dwResult = GetLastError(); Trace2( ERR, "EnableNetbtBcastForwarding : error %d allocating buffer of" "size %d for IPConfig value", dwResult, dwSize ); break; } // // query registry value of IPConfig // dwResult = RegQueryValueExW( hkWanarpAdapter, L"IpConfig", NULL, &dwType, (PBYTE)pbBuffer, &dwSize ); if ( (dwResult isnot NO_ERROR) || (dwType != REG_MULTI_SZ) ) { Trace1( ERR, "EnableNetbtBcastForwarding : error %d querying" "IPConfig value\n", dwResult ); break; } // // Extract the GUID of the Internal (RAS Server) adapter // pwcGuid = wcschr( (PWCHAR)pbBuffer, '{' ); Trace1( INIT, "Internal adapter GUID is %lS", pwcGuid ); // // Step II // // Save the old setting for NETBT PROXY mode. This will be restored // when the RRAS server is stopped. and set the new PROXY mode // // // open NETBT Key // dwResult = RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services\\Netbt\\Parameters", 0, KEY_READ | KEY_WRITE, &hkNetbtParameters ); if (dwResult isnot NO_ERROR) { Trace1( ERR, "EnableNetbtBcastForwarding : error %d opening" "Netbt\\Parameters key\n", dwResult ); break; } // // query EnableProxy mode // dwSize = sizeof( DWORD ); dwMode = 0; dwResult = RegQueryValueExW( hkNetbtParameters, L"EnableProxy", NULL, &dwType, (PBYTE)&dwMode, &dwSize ); if (dwResult isnot NO_ERROR) { // // It is possible the key is not present esp. if this // is the first time you are running RRAS or if the // key has been manually deleted // In this case assume proxy is set to 0 (disabled) // g_dwOldNetbtProxyMode = 0; } else { g_dwOldNetbtProxyMode = dwMode; } Trace1( INIT, "Netbt Proxy mode in registry is %d", dwMode ); // // Set the NETBT proxy mode to enable/disable broadcast forwarding // // // if NETBT broadcast fwdg is disabled, make sure // the the EnableProxy setting matches that // if ( dwEnable == 0 ) { // // Netbt broadcast fwd'g is disabled // if ( dwMode == 2 ) { // // But the registry setting does not reflect this // g_dwOldNetbtProxyMode = 0; dwMode = 0; Trace1( INIT, "Forcing Netbt Proxy mode to be %d", g_dwOldNetbtProxyMode ); } } else { // // Note: Need a #define value for netbt proxy mode // dwMode = 2; } Trace2( INIT, "Old Netbt Proxy mode is %d, New Nebt Proxy Mode is %d", g_dwOldNetbtProxyMode, dwMode ); dwResult = RegSetValueExW( hkNetbtParameters, L"EnableProxy", 0, REG_DWORD, (PBYTE) &dwMode, dwSize ); if ( dwResult != NO_ERROR ) { Trace1( ERR, "EnableNetbtBcastForwarding : error %d setting" "EnableProxy value\n", dwResult ); break; } // // Step III: // // Check for RASFlags under NETBT_TCPIP_{RAS_SERVER_GUID} key // // // Open interface key under NETBT // wcscpy( wszNetbtInterface, L"System\\CurrentControlSet\\Services\\Netbt\\Parameters\\Interfaces\\Tcpip_" ); wcscat( wszNetbtInterface, pwcGuid ); dwResult = RegOpenKeyExW( HKEY_LOCAL_MACHINE, wszNetbtInterface, 0, KEY_READ | KEY_WRITE, &hkNetbtInterface ); if (dwResult isnot NO_ERROR) { Trace2( ERR, "EnableNetbtBcastForwarding : error %d opening" "%ls key\n", dwResult, wszNetbtInterface ); break; } // // query RASFlags value // // If present // leave as is. // else // create and set it to 0x00000001 to disable NETBT // broadcasts on WAN. // dwFlags = 0; dwResult = RegQueryValueExW( hkNetbtInterface, L"RASFlags", NULL, &dwType, (PBYTE)&dwFlags, &dwSize ); if (dwResult isnot NO_ERROR) { // // It is possible the key is not present esp. if this // is the first time you are running RRAS or if the // key has been manually deleted // In this case set RASFlags to 1 (default behavior). // dwFlags = 1; dwResult = RegSetValueExW( hkNetbtInterface, L"RASFlags", 0, REG_DWORD, (PBYTE) &dwFlags, sizeof( DWORD ) ); if ( dwResult != NO_ERROR ) { Trace1( ERR, "error %d setting RASFlags", dwResult ); } } else { // // RASFlags value is already present. leave it as is. // Trace1( INIT, "RASFlags already present with value %d", dwFlags ); } // // Close NETBT keys. Doing so to avoid any contention issues // with the NETBT.SYS driver trying to read them in the following // function // RegCloseKey( hkNetbtParameters ); hkNetbtParameters = NULL; RegCloseKey( hkNetbtInterface ); hkNetbtInterface = NULL; dwResult = ForceNetbtRegistryRead(); } while (FALSE); if ( hkWanarpAdapter ) { RegCloseKey( hkWanarpAdapter ); } if ( hkNetbtParameters ) { RegCloseKey( hkNetbtParameters ); } if ( hkNetbtInterface ) { RegCloseKey( hkNetbtInterface ); } if ( pbBuffer ) { HeapFree( GetProcessHeap(), 0, pbBuffer ); } TraceLeave("EnableNetbtBcastForwarding"); return dwResult; } DWORD RestoreNetbtBcastForwardingMode( VOID ) /*++ Routine description: Return the NETBT proxy mode setting to its original setting Arguements : Return Value : --*/ { DWORD dwResult, dwSize = 0; HKEY hkNetbtParameters = NULL; TraceEnter("RestoreNetbtBcastForwardingMode"); do { // // open NETBT Key // dwResult = RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services\\Netbt\\Parameters", 0, KEY_READ | KEY_WRITE, &hkNetbtParameters ); if (dwResult isnot NO_ERROR) { Trace1( ERR, "EnableNetbtBcastForwarding : error %d opening" "Netbt\\Parameters key\n", dwResult ); break; } // // restore EnableProxy mode // dwSize = sizeof( DWORD ); dwResult = RegSetValueExW( hkNetbtParameters, L"EnableProxy", 0, REG_DWORD, (PBYTE) &g_dwOldNetbtProxyMode, dwSize ); if ( dwResult != NO_ERROR ) { Trace1( ERR, "EnableNetbtBcastForwarding : error %d setting" "EnableProxy value\n", dwResult ); break; } dwResult = ForceNetbtRegistryRead(); } while (FALSE); TraceLeave("RestoreNetbtBcastForwardingMode"); return dwResult; } DWORD ForceNetbtRegistryRead( VOID ) /*++ Routine description: Issue IOCTL to NETBT to re-read its registry setting. Arguements : Return Value : --*/ { DWORD dwErr = NO_ERROR; NTSTATUS status; UNICODE_STRING nameString; IO_STATUS_BLOCK ioStatusBlock; OBJECT_ATTRIBUTES objectAttributes; HANDLE hNetbtDevice = NULL; TraceEnter("ForceNetbtRegistryRead"); do { // // Step I: // // Open NETBT driver // RtlInitUnicodeString( &nameString, L"\\Device\\NetbiosSmb" ); InitializeObjectAttributes( &objectAttributes, &nameString, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtCreateFile( &hNetbtDevice, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, 0, NULL, 0 ); if (!NT_SUCCESS(status)) { Trace1( ERR, "ForceNetbtRegistryRead: Couldnt create NETBT driver handle. NtStatus %x", status ); dwErr = ERROR_OPEN_FAILED; break; } // // Issue IOCTL to re-read registry // status = NtDeviceIoControlFile( hNetbtDevice, NULL, NULL, NULL, &ioStatusBlock, IOCTL_NETBT_REREAD_REGISTRY, NULL, 0, NULL, 0 ); if (!NT_SUCCESS(status)) { Trace1( ERR, "ForceNetbtRegistryRead: Failed IOCTL call to NETBT, status %x", status ); dwErr = ERROR_UNKNOWN; break; } } while ( FALSE ); // // Close NETBT driver // CloseHandle( hNetbtDevice ); TraceLeave("ForceNetbtRegistryRead"); return dwErr; } DWORD InitializeMibHandler( VOID ) /*++ Routine Description: Initalizes the heaps and Locks needed by the MIB handling code Arguments: None Return Value: NO_ERROR or some error code --*/ { DWORD i,dwResult, dwIpIfSize, dwMibSize; BOOL fUpdate; TraceEnter("InitializeMibHandler"); // // Assert the size of MIB to stack mappings for which direct copy is // being done // dwIpIfSize = IFE_FIXED_SIZE + MAX_IFDESCR_LEN; dwMibSize = sizeof(MIB_IFROW) - FIELD_OFFSET(MIB_IFROW, dwIndex); IpRtAssert(dwIpIfSize is dwMibSize); IpRtAssert(sizeof(MIB_ICMP) is sizeof(ICMPSNMPInfo)); IpRtAssert(sizeof(MIB_UDPSTATS) is sizeof(UDPStats)); IpRtAssert(sizeof(MIB_UDPROW) is sizeof(UDPEntry)); IpRtAssert(sizeof(MIB_TCPSTATS) is sizeof(TCPStats)); IpRtAssert(sizeof(MIB_TCPROW) is sizeof(TCPConnTableEntry)); IpRtAssert(sizeof(MIB_IPSTATS) is sizeof(IPSNMPInfo)); IpRtAssert(sizeof(MIB_IPADDRROW) is sizeof(IPAddrEntry)); IpRtAssert(sizeof(MIB_IPNETROW) is sizeof(IPNetToMediaEntry)); g_dwStartTime = GetCurrentTime(); __try { // // We dont initialize the locks since we do it in one shot at the // beginning of StartRouter // // // Now Create the heaps. Since only writers Alloc from the heap we // are already guaranteed serialization, so lets not ask for it again // Let all initial size be 1K, this doesnt really cost any thing // since the memory is not committed // We will just allocate a minimum size for the cache tables so // that the startup doesnt barf // #define INIT_TABLE_SIZE 10 g_hIfHeap = HeapCreate(HEAP_NO_SERIALIZE,1000,0); if(g_hIfHeap is NULL) { dwResult = GetLastError(); Trace1(ERR, "InitializeMibHandler: Couldnt allocate IF Heap. Error %d", dwResult); __leave; } g_hUdpHeap = HeapCreate(HEAP_NO_SERIALIZE,1000,0); if(g_hUdpHeap is NULL) { dwResult = GetLastError(); Trace1(ERR, "InitializeMibHandler: Couldnt allocate UDP Heap. Error %d", dwResult); __leave; } g_UdpInfo.pUdpTable = HeapAlloc(g_hUdpHeap, HEAP_NO_SERIALIZE, SIZEOF_UDPTABLE(INIT_TABLE_SIZE)); if(g_UdpInfo.pUdpTable is NULL) { dwResult = ERROR_NOT_ENOUGH_MEMORY; Trace0(ERR, "InitializeMibHandler: Couldnt allocate UDP table"); __leave; } g_UdpInfo.dwTotalEntries = INIT_TABLE_SIZE; g_hTcpHeap = HeapCreate(HEAP_NO_SERIALIZE,1000,0); if(g_hTcpHeap is NULL) { dwResult = GetLastError(); Trace1(ERR, "InitializeMibHandler: Couldnt allocate TCP Heap. Error %d", dwResult); __leave; } g_TcpInfo.pTcpTable = HeapAlloc(g_hTcpHeap, HEAP_NO_SERIALIZE, SIZEOF_TCPTABLE(INIT_TABLE_SIZE)); if(g_TcpInfo.pTcpTable is NULL) { dwResult = ERROR_NOT_ENOUGH_MEMORY; Trace0(ERR, "InitializeMibHandler: Couldnt allocate TCP table"); __leave; } g_TcpInfo.dwTotalEntries = INIT_TABLE_SIZE; g_hIpAddrHeap = HeapCreate(HEAP_NO_SERIALIZE,1000,0); if(g_hIpAddrHeap is NULL) { dwResult = GetLastError(); Trace1(ERR, "InitializeMibHandler: Couldnt allocate IP Addr Heap. Error %d", dwResult); __leave; } g_IpInfo.pAddrTable = HeapAlloc(g_hIpAddrHeap, HEAP_NO_SERIALIZE, SIZEOF_IPADDRTABLE(INIT_TABLE_SIZE)); if(g_IpInfo.pAddrTable is NULL) { dwResult = ERROR_NOT_ENOUGH_MEMORY; Trace0(ERR, "InitializeMibHandler: Couldnt allocate IP Addr table."); __leave; } g_IpInfo.dwTotalAddrEntries = INIT_TABLE_SIZE; g_hIpForwardHeap = HeapCreate(HEAP_NO_SERIALIZE,1000,0); if(g_hIpForwardHeap is NULL) { dwResult = GetLastError(); Trace1(ERR, "InitializeMibHandler: Couldnt allocate IP Forward Heap. Error %d", dwResult); __leave; } g_IpInfo.pForwardTable = HeapAlloc(g_hIpForwardHeap, HEAP_NO_SERIALIZE, SIZEOF_IPFORWARDTABLE(INIT_TABLE_SIZE)); if(g_IpInfo.pForwardTable is NULL) { dwResult = ERROR_NOT_ENOUGH_MEMORY; Trace0(ERR, "InitializeMibHandler: Couldnt allocate IP Forward table"); __leave; } g_IpInfo.dwTotalForwardEntries = INIT_TABLE_SIZE; g_hIpNetHeap = HeapCreate(HEAP_NO_SERIALIZE,1000,0); if(g_hIpNetHeap is NULL) { dwResult = GetLastError(); Trace1(ERR, "InitializeMibHandler: Couldnt allocate IP Net Heap. Error %d", dwResult); __leave; } g_IpInfo.pNetTable = HeapAlloc(g_hIpNetHeap, HEAP_NO_SERIALIZE, SIZEOF_IPNETTABLE(INIT_TABLE_SIZE)); if(g_IpInfo.pNetTable is NULL) { dwResult = ERROR_NOT_ENOUGH_MEMORY; Trace0(ERR, "InitializeMibHandler: Couldnt allocate IP Net table"); __leave; } g_IpInfo.dwTotalNetEntries = INIT_TABLE_SIZE; // // Now set up the caches // for(i = 0; i < NUM_CACHE; i++) { g_LastUpdateTable[i] = 0; if(UpdateCache(i,&fUpdate) isnot NO_ERROR) { Trace1(ERR, "InitializeMibHandler: Couldnt update %s Cache", CacheToA(i)); //__leave; } } dwResult = NO_ERROR; } __finally { TraceLeave("InitializeMibHandler"); } return dwResult; }