/*++ Copyright (c) 2001 Microsoft Corporation Module Name: winpenet.c Abstract: This module contains code to control the startup of the network in the WinPE environment. It relies upon the existence of WINBOM.INI and the following sections: [WinPE.net] Startnet = YES | NO - Specifies whether to start networking. Ipconfig = DHCP | x.x.x.x - Specifies DHCP or a static IP address. SubnetMask = x.x.x.x - SubnetMask for the static IP. Gateway = x.x.x.x - Default gateway for the static IP. Author: Adrian Cosma (acosma) - 1/18/2001 Revision History: --*/ // // Includes // #include "factoryp.h" #include // // Defines // typedef HRESULT (PASCAL *PRegisterServer)(VOID); // // Static strings // const static TCHAR DEF_GATEWAY_METRIC[] = _T("1\0"); // Need to NULLCHRs at the end since this goes into a REG_MULTI_SZ. const static TCHAR REGSTR_TCPIP[] = _T("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"); // // Local function declarations // static BOOL InstallNetComponents(VOID); static BOOL RegisterDll(VOID); // // Function implementations // static BOOL InstallNetComponents(VOID) { TCHAR szCmdLine[MAX_PATH] = NULLSTR; DWORD dwExitCode = 0; BOOL bRet = TRUE; lstrcpyn(szCmdLine, _T("-winpe"), AS ( szCmdLine ) ) ; if ( !InvokeExternalApplicationEx(_T("netcfg"), szCmdLine, &dwExitCode, INFINITE, TRUE) ) { FacLogFile(0 | LOG_ERR, IDS_ERR_NETWORKCOMP); bRet = FALSE; } return bRet; } static BOOL RegisterDll(VOID) { HMODULE hDll = NULL; BOOL bRet = FALSE; PRegisterServer pRegisterServer = NULL; if ( (hDll = LoadLibrary(_T("netcfgx.dll"))) && (pRegisterServer = (PRegisterServer) GetProcAddress(hDll, "DllRegisterServer")) && (S_OK == pRegisterServer()) ) { FacLogFileStr(3, _T("Succesfully registered netcfg.dll.\n")); bRet = TRUE; } else { FacLogFile(0 | LOG_ERR, IDS_ERR_REGISTERNETCFG); } if (hDll) FreeLibrary(hDll); return bRet; } BOOL WinpeNet(LPSTATEDATA lpStateData) { LPTSTR lpszWinBOMPath = lpStateData->lpszWinBOMPath; SC_HANDLE hSCM = NULL; TCHAR szBuf[MAX_WINPE_PROFILE_STRING] = NULLSTR; BOOL bRet = TRUE; // Make sure that the user wants us to do networking. // GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, INI_KEY_WBOM_WINPE_NET_STARTNET, NULLSTR, szBuf, AS(szBuf), lpszWinBOMPath); // If user does not want to start networking just return success. // if ( 0 == LSTRCMPI(szBuf, WBOM_NO) ) return TRUE; // Register dll. // Run netcfg -winpe. // Install network card. // See if the user wants to use a static IP. // if ( RegisterDll() && SetupMiniNT() && InstallNetComponents() && ConfigureNetwork(g_szWinBOMPath) ) { // // Start Services for networking. // if ( hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS) ) { // DHCP also starts tcpip and netbt. // The workstation service should already be started by the installer. // if ( (StartMyService(_T("dhcp"), hSCM) != NO_ERROR) || (StartMyService(_T("nla"), hSCM) != NO_ERROR) ) { FacLogFile(0 | LOG_ERR, IDS_ERR_NETSERVICES); bRet = FALSE; } else if ( IsRemoteBoot() ) { // If this was a remote boot, tell NetBT to reload the WINS addresses... // ISSUE-2002/09/26-acosma,brucegr - Can DHCP say its started before we get an address? // ForceNetbtRegistryRead(); } CloseServiceHandle(hSCM); } else { FacLogFile(0 | LOG_ERR, IDS_ERR_SCM); bRet = FALSE; } } else { FacLogFile(0 | LOG_ERR, IDS_ERR_SETUPNETWORK); bRet = FALSE; } return bRet; } BOOL DisplayWinpeNet(LPSTATEDATA lpStateData) { return ( !IniSettingExists(lpStateData->lpszWinBOMPath, INI_KEY_WBOM_WINPE_NET, INI_KEY_WBOM_WINPE_NET_STARTNET, INI_VAL_WBOM_NO) ); } BOOL ConfigureNetwork(LPTSTR lpszWinBOMPath) { TCHAR szBuf[MAX_WINPE_PROFILE_STRING] = NULLSTR; CHAR szBufA[MAX_WINPE_PROFILE_STRING] = { 0 }; TCHAR szReg[MAX_WINPE_PROFILE_STRING] = NULLSTR; TCHAR szIpAddress[MAX_WINPE_PROFILE_STRING] = NULLSTR; TCHAR szSubnetMask[MAX_WINPE_PROFILE_STRING] = NULLSTR; HKEY hKey = NULL; // Reg Key to interfaces. HKEY hKeyI = NULL; // Reg Key to specific network interface. DWORD dwDis = 0; TCHAR szRegKey[MAX_PATH] = NULLSTR; DWORD dwEnableDHCP = 0; BOOL fErr = FALSE; szBuf[0] = NULLCHR; GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, WBOM_WINPE_NET_IPADDRESS, NULLSTR, szBuf, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath); // Convert the string to ANSI // if ( szBuf[0] && WideCharToMultiByte(CP_ACP, 0, szBuf, -1, szBufA, AS(szBufA), NULL, NULL) ) { // If it's DHCP don't do anything. Just return TRUE. // if ( 0 == LSTRCMPI(szBuf, _T("DHCP")) ) return TRUE; if ( INADDR_NONE == inet_addr(szBufA) ) { FacLogFile(0 | LOG_ERR, IDS_ERR_INVALIDIP , szBuf); return FALSE; } } else // if there is no IpConfig entry return success (same as DHCP) return TRUE; // Save the IpAddress. lstrcpyn(szIpAddress, szBuf, AS ( szIpAddress ) ); szBuf[0] = NULLCHR; GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, WBOM_WINPE_NET_SUBNETMASK, NULLSTR, szBuf, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath); // Convert the string to ANSI // if ( szBuf[0] && WideCharToMultiByte(CP_ACP,0, szBuf, -1, szBufA, AS(szBufA), NULL, NULL) ) { if ( INADDR_NONE == inet_addr(szBufA) ) { FacLogFile(0 | LOG_ERR, IDS_ERR_INVALIDMASK , szBuf); return FALSE; } } else // If we got this far we need to have a subnet mask { FacLogFile(0 | LOG_ERR, IDS_ERR_NOMASK); return FALSE; } // Save the SubnetMask. lstrcpyn(szSubnetMask, szBuf, AS ( szSubnetMask ) ); // // Write the settings to the registry. // // Make sure that the strings are terminated by two NULLCHRs. // szIpAddress[lstrlen(szIpAddress) + 1] = NULLCHR; szSubnetMask[lstrlen(szSubnetMask) + 1] = NULLCHR; // Assuming that there is only one interface in the system. // if ( (RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_TCPIP, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDis) == ERROR_SUCCESS) && (RegEnumKey(hKey, 0, szRegKey, AS(szRegKey)) == ERROR_SUCCESS) && szRegKey[0] && (RegCreateKeyEx(hKey, szRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyI, &dwDis) == ERROR_SUCCESS) ) { if ( ERROR_SUCCESS != (RegSetValueEx(hKeyI, _T("IPAddress"), 0, REG_MULTI_SZ, (CONST LPBYTE) szIpAddress, ( lstrlen(szIpAddress) + 2 ) * sizeof(TCHAR))) || ERROR_SUCCESS != (RegSetValueEx(hKeyI, _T("SubnetMask"), 0, REG_MULTI_SZ, (CONST LPBYTE) szSubnetMask, ( lstrlen(szSubnetMask) + 2 ) * sizeof(TCHAR))) || ERROR_SUCCESS != (RegSetValueEx(hKeyI, _T("EnableDHCP"), 0, REG_DWORD, (CONST LPBYTE) &dwEnableDHCP, sizeof(dwEnableDHCP))) ) { FacLogFile(0 | LOG_ERR, IDS_ERR_IPREGISTRY); fErr = TRUE; } else { // // If the gateway is not specified we don't care. We're just not going to add this // if it's not there. // szBuf[0] = NULLCHR; GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, WBOM_WINPE_NET_GATEWAY, NULLSTR, szBuf, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath); if ( szBuf[0] && WideCharToMultiByte(CP_ACP,0, szBuf, -1, szBufA, AS(szBufA), NULL, NULL) ) { if ( INADDR_NONE == inet_addr(szBufA) ) { FacLogFile(0 | LOG_ERR, IDS_ERR_INVALIDGW, szBuf); fErr = TRUE; } else { szBuf[lstrlen(szBuf) + 1] = NULLCHR; if ( (RegSetValueEx(hKeyI, _T("DefaultGateway"), 0, REG_MULTI_SZ, (CONST LPBYTE) szBuf, ( lstrlen(szBuf) + 2 ) * sizeof(TCHAR)) != ERROR_SUCCESS) || (RegSetValueEx(hKeyI, _T("DefaultGatewayMetric"), 0, REG_MULTI_SZ, (CONST LPBYTE) DEF_GATEWAY_METRIC, ( lstrlen(DEF_GATEWAY_METRIC) + 2 ) * sizeof(TCHAR)) != ERROR_SUCCESS) ) { FacLogFile(0 | LOG_ERR, IDS_ERR_GWREGISTRY); fErr = TRUE; } } } } RegCloseKey(hKeyI); } else { FacLogFile(0 | LOG_ERR, IDS_ERR_IPREGISTRY); } // It is possible that the subkey failed to open so this takes care of a possible leak. // if (hKey) RegCloseKey(hKey); return (!fErr); } static DWORD WaitForServiceStart(SC_HANDLE schService) { SERVICE_STATUS ssStatus; DWORD dwOldCheckPoint; DWORD dwStartTickCount; DWORD dwWaitTime; DWORD dwStatus = NO_ERROR; if ( schService ) { // // Service start is now pending. // Check the status until the service is no longer start pending. // if ( QueryServiceStatus( schService, &ssStatus) ) { // Save the tick count and initial checkpoint. // dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; while (ssStatus.dwCurrentState == SERVICE_START_PENDING) { // Do not wait longer than the wait hint. A good interval is // one tenth the wait hint, but no less than 1 second and no // more than 10 seconds. // dwWaitTime = ssStatus.dwWaitHint / 10; if( dwWaitTime < 1000 ) dwWaitTime = 1000; else if ( dwWaitTime > 10000 ) dwWaitTime = 10000; Sleep( dwWaitTime ); // Check the status again. // if (!QueryServiceStatus( schService, // handle to service &ssStatus) ) // address of structure break; if ( ssStatus.dwCheckPoint > dwOldCheckPoint ) { // The service is making progress. // dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; } else { if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint) { // No progress made within the wait hint // break; } } } if (ssStatus.dwCurrentState == SERVICE_RUNNING) { dwStatus = NO_ERROR; } else { // Set the return value to the last error. // dwStatus = GetLastError(); } } } return dwStatus; } DWORD WaitForServiceStartName(LPTSTR lpszServiceName) { SC_HANDLE hSCM = NULL; SC_HANDLE schService = NULL; DWORD dwStatus = NO_ERROR; if ( lpszServiceName ) { if ( hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS) ) { if ( schService = OpenService(hSCM, lpszServiceName, SERVICE_ALL_ACCESS) ) { dwStatus = WaitForServiceStart(schService); CloseServiceHandle(schService); } else { dwStatus = GetLastError(); FacLogFile(0 | LOG_ERR, IDS_ERR_SERVICE, lpszServiceName); } CloseServiceHandle(hSCM); } else { dwStatus = GetLastError(); FacLogFile(0 | LOG_ERR, IDS_ERR_SCM); } } else { dwStatus = E_INVALIDARG; } return dwStatus; } // Start a service. // DWORD StartMyService(LPTSTR lpszServiceName, SC_HANDLE schSCManager) { SC_HANDLE schService; DWORD dwStatus = NO_ERROR; FacLogFileStr(3, _T("Starting service: %s\n"), lpszServiceName); if ( NULL != (schService = OpenService(schSCManager, lpszServiceName, SERVICE_ALL_ACCESS)) && StartService(schService, 0, NULL) ) { dwStatus = WaitForServiceStart(schService); } if ( schService ) CloseServiceHandle(schService); return dwStatus; }