Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

432 lines
13 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. winpenet.c
  5. Abstract:
  6. This module contains code to control the startup of the network in the WinPE environment.
  7. It relies upon the existence of WINBOM.INI and the following sections:
  8. [WinPE.net]
  9. Startnet = YES | NO - Specifies whether to start networking.
  10. Ipconfig = DHCP | x.x.x.x - Specifies DHCP or a static IP address.
  11. SubnetMask = x.x.x.x - SubnetMask for the static IP.
  12. Gateway = x.x.x.x - Default gateway for the static IP.
  13. Author:
  14. Adrian Cosma (acosma) - 1/18/2001
  15. Revision History:
  16. --*/
  17. //
  18. // Includes
  19. //
  20. #include "factoryp.h"
  21. #include <winsock2.h>
  22. //
  23. // Defines
  24. //
  25. typedef HRESULT (PASCAL *PRegisterServer)(VOID);
  26. //
  27. // Static strings
  28. //
  29. const static TCHAR DEF_GATEWAY_METRIC[] = _T("1\0"); // Need to NULLCHRs at the end since this goes into a REG_MULTI_SZ.
  30. const static TCHAR REGSTR_TCPIP[] = _T("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
  31. //
  32. // Local function declarations
  33. //
  34. static BOOL InstallNetComponents(VOID);
  35. static BOOL RegisterDll(VOID);
  36. //
  37. // Function implementations
  38. //
  39. static BOOL InstallNetComponents(VOID)
  40. {
  41. TCHAR szCmdLine[MAX_PATH] = NULLSTR;
  42. DWORD dwExitCode = 0;
  43. BOOL bRet = TRUE;
  44. lstrcpyn(szCmdLine, _T("-winpe"), AS ( szCmdLine ) ) ;
  45. if ( !InvokeExternalApplicationEx(_T("netcfg"), szCmdLine, &dwExitCode, INFINITE, TRUE) )
  46. {
  47. FacLogFile(0 | LOG_ERR, IDS_ERR_NETWORKCOMP);
  48. bRet = FALSE;
  49. }
  50. return bRet;
  51. }
  52. static BOOL RegisterDll(VOID)
  53. {
  54. HMODULE hDll = NULL;
  55. BOOL bRet = FALSE;
  56. PRegisterServer pRegisterServer = NULL;
  57. if ( (hDll = LoadLibrary(_T("netcfgx.dll"))) &&
  58. (pRegisterServer = (PRegisterServer) GetProcAddress(hDll, "DllRegisterServer")) &&
  59. (S_OK == pRegisterServer()) )
  60. {
  61. FacLogFileStr(3, _T("Succesfully registered netcfg.dll.\n"));
  62. bRet = TRUE;
  63. }
  64. else
  65. {
  66. FacLogFile(0 | LOG_ERR, IDS_ERR_REGISTERNETCFG);
  67. }
  68. if (hDll)
  69. FreeLibrary(hDll);
  70. return bRet;
  71. }
  72. BOOL WinpeNet(LPSTATEDATA lpStateData)
  73. {
  74. LPTSTR lpszWinBOMPath = lpStateData->lpszWinBOMPath;
  75. SC_HANDLE hSCM = NULL;
  76. TCHAR szBuf[MAX_WINPE_PROFILE_STRING] = NULLSTR;
  77. BOOL bRet = TRUE;
  78. // Make sure that the user wants us to do networking.
  79. //
  80. GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, INI_KEY_WBOM_WINPE_NET_STARTNET, NULLSTR, szBuf, AS(szBuf), lpszWinBOMPath);
  81. // If user does not want to start networking just return success.
  82. //
  83. if ( 0 == LSTRCMPI(szBuf, WBOM_NO) )
  84. return TRUE;
  85. // Register dll.
  86. // Run netcfg -winpe.
  87. // Install network card.
  88. // See if the user wants to use a static IP.
  89. //
  90. if ( RegisterDll() &&
  91. SetupMiniNT() &&
  92. InstallNetComponents() &&
  93. ConfigureNetwork(g_szWinBOMPath)
  94. )
  95. {
  96. //
  97. // Start Services for networking.
  98. //
  99. if ( hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS) )
  100. {
  101. // DHCP also starts tcpip and netbt.
  102. // The workstation service should already be started by the installer.
  103. //
  104. if ( (StartMyService(_T("dhcp"), hSCM) != NO_ERROR) ||
  105. (StartMyService(_T("nla"), hSCM) != NO_ERROR)
  106. )
  107. {
  108. FacLogFile(0 | LOG_ERR, IDS_ERR_NETSERVICES);
  109. bRet = FALSE;
  110. }
  111. CloseServiceHandle(hSCM);
  112. }
  113. else
  114. {
  115. FacLogFile(0 | LOG_ERR, IDS_ERR_SCM);
  116. bRet = FALSE;
  117. }
  118. }
  119. else
  120. {
  121. FacLogFile(0 | LOG_ERR, IDS_ERR_SETUPNETWORK);
  122. bRet = FALSE;
  123. }
  124. return bRet;
  125. }
  126. BOOL DisplayWinpeNet(LPSTATEDATA lpStateData)
  127. {
  128. return ( !IniSettingExists(lpStateData->lpszWinBOMPath, INI_KEY_WBOM_WINPE_NET, INI_KEY_WBOM_WINPE_NET_STARTNET, INI_VAL_WBOM_NO) );
  129. }
  130. BOOL ConfigureNetwork(LPTSTR lpszWinBOMPath)
  131. {
  132. TCHAR szBuf[MAX_WINPE_PROFILE_STRING] = NULLSTR;
  133. CHAR szBufA[MAX_WINPE_PROFILE_STRING] = { 0 };
  134. TCHAR szReg[MAX_WINPE_PROFILE_STRING] = NULLSTR;
  135. TCHAR szIpAddress[MAX_WINPE_PROFILE_STRING] = NULLSTR;
  136. TCHAR szSubnetMask[MAX_WINPE_PROFILE_STRING] = NULLSTR;
  137. HKEY hKey = NULL; // Reg Key to interfaces.
  138. HKEY hKeyI = NULL; // Reg Key to specific network interface.
  139. DWORD dwDis = 0;
  140. TCHAR szRegKey[MAX_PATH] = NULLSTR;
  141. DWORD dwEnableDHCP = 0;
  142. BOOL fErr = FALSE;
  143. szBuf[0] = NULLCHR;
  144. GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, WBOM_WINPE_NET_IPADDRESS, NULLSTR, szBuf, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
  145. // Convert the string to ANSI
  146. //
  147. if ( szBuf[0] &&
  148. WideCharToMultiByte(CP_ACP, 0, szBuf, -1, szBufA, AS(szBufA), NULL, NULL) )
  149. {
  150. // If it's DHCP don't do anything. Just return TRUE.
  151. //
  152. if ( 0 == LSTRCMPI(szBuf, _T("DHCP")) )
  153. return TRUE;
  154. if ( INADDR_NONE == inet_addr(szBufA) )
  155. {
  156. FacLogFile(0 | LOG_ERR, IDS_ERR_INVALIDIP , szBuf);
  157. return FALSE;
  158. }
  159. }
  160. else // if there is no IpConfig entry return success (same as DHCP)
  161. return TRUE;
  162. // Save the IpAddress.
  163. lstrcpyn(szIpAddress, szBuf, AS ( szIpAddress ) );
  164. szBuf[0] = NULLCHR;
  165. GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, WBOM_WINPE_NET_SUBNETMASK, NULLSTR, szBuf, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
  166. // Convert the string to ANSI
  167. //
  168. if ( szBuf[0] &&
  169. WideCharToMultiByte(CP_ACP,0, szBuf, -1, szBufA, AS(szBufA), NULL, NULL) )
  170. {
  171. if ( INADDR_NONE == inet_addr(szBufA) )
  172. {
  173. FacLogFile(0 | LOG_ERR, IDS_ERR_INVALIDMASK , szBuf);
  174. return FALSE;
  175. }
  176. }
  177. else // If we got this far we need to have a subnet mask
  178. {
  179. FacLogFile(0 | LOG_ERR, IDS_ERR_NOMASK);
  180. return FALSE;
  181. }
  182. // Save the SubnetMask.
  183. lstrcpyn(szSubnetMask, szBuf, AS ( szSubnetMask ) );
  184. //
  185. // Write the settings to the registry.
  186. //
  187. // Make sure that the strings are terminated by two NULLCHRs.
  188. //
  189. szIpAddress[lstrlen(szIpAddress) + 1] = NULLCHR;
  190. szSubnetMask[lstrlen(szSubnetMask) + 1] = NULLCHR;
  191. // Assuming that there is only one interface in the system.
  192. //
  193. if ( (RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_TCPIP, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDis) == ERROR_SUCCESS) &&
  194. (RegEnumKey(hKey, 0, szRegKey, AS(szRegKey)) == ERROR_SUCCESS) &&
  195. szRegKey[0] &&
  196. (RegCreateKeyEx(hKey, szRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyI, &dwDis) == ERROR_SUCCESS) )
  197. {
  198. if ( ERROR_SUCCESS != (RegSetValueEx(hKeyI, _T("IPAddress"), 0, REG_MULTI_SZ, (CONST LPBYTE) szIpAddress, ( lstrlen(szIpAddress) + 2 ) * sizeof(TCHAR))) ||
  199. ERROR_SUCCESS != (RegSetValueEx(hKeyI, _T("SubnetMask"), 0, REG_MULTI_SZ, (CONST LPBYTE) szSubnetMask, ( lstrlen(szSubnetMask) + 2 ) * sizeof(TCHAR))) ||
  200. ERROR_SUCCESS != (RegSetValueEx(hKeyI, _T("EnableDHCP"), 0, REG_DWORD, (CONST LPBYTE) &dwEnableDHCP, sizeof(dwEnableDHCP))) )
  201. {
  202. FacLogFile(0 | LOG_ERR, IDS_ERR_IPREGISTRY);
  203. fErr = TRUE;
  204. }
  205. else
  206. {
  207. //
  208. // If the gateway is not specified we don't care. We're just not going to add this
  209. // if it's not there.
  210. //
  211. szBuf[0] = NULLCHR;
  212. GetPrivateProfileString(INI_KEY_WBOM_WINPE_NET, WBOM_WINPE_NET_GATEWAY, NULLSTR, szBuf, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
  213. if ( szBuf[0] &&
  214. WideCharToMultiByte(CP_ACP,0, szBuf, -1, szBufA, AS(szBufA), NULL, NULL) )
  215. {
  216. if ( INADDR_NONE == inet_addr(szBufA) )
  217. {
  218. FacLogFile(0 | LOG_ERR, IDS_ERR_INVALIDGW, szBuf);
  219. fErr = TRUE;
  220. }
  221. else
  222. {
  223. szBuf[lstrlen(szBuf) + 1] = NULLCHR;
  224. if ( (RegSetValueEx(hKeyI, _T("DefaultGateway"), 0, REG_MULTI_SZ, (CONST LPBYTE) szBuf, ( lstrlen(szBuf) + 2 ) * sizeof(TCHAR)) != ERROR_SUCCESS) ||
  225. (RegSetValueEx(hKeyI, _T("DefaultGatewayMetric"), 0, REG_MULTI_SZ, (CONST LPBYTE) DEF_GATEWAY_METRIC, ( lstrlen(DEF_GATEWAY_METRIC) + 2 ) * sizeof(TCHAR)) != ERROR_SUCCESS) )
  226. {
  227. FacLogFile(0 | LOG_ERR, IDS_ERR_GWREGISTRY);
  228. fErr = TRUE;
  229. }
  230. }
  231. }
  232. }
  233. RegCloseKey(hKeyI);
  234. }
  235. else
  236. {
  237. FacLogFile(0 | LOG_ERR, IDS_ERR_IPREGISTRY);
  238. }
  239. // It is possible that the subkey failed to open so this takes care of a possible leak.
  240. //
  241. if (hKey)
  242. RegCloseKey(hKey);
  243. return (!fErr);
  244. }
  245. static DWORD WaitForServiceStart(SC_HANDLE schService)
  246. {
  247. SERVICE_STATUS ssStatus;
  248. DWORD dwOldCheckPoint;
  249. DWORD dwStartTickCount;
  250. DWORD dwWaitTime;
  251. DWORD dwStatus = NO_ERROR;
  252. if ( schService )
  253. {
  254. //
  255. // Service start is now pending.
  256. // Check the status until the service is no longer start pending.
  257. //
  258. if ( QueryServiceStatus( schService, &ssStatus) )
  259. {
  260. // Save the tick count and initial checkpoint.
  261. //
  262. dwStartTickCount = GetTickCount();
  263. dwOldCheckPoint = ssStatus.dwCheckPoint;
  264. while (ssStatus.dwCurrentState == SERVICE_START_PENDING)
  265. {
  266. // Do not wait longer than the wait hint. A good interval is
  267. // one tenth the wait hint, but no less than 1 second and no
  268. // more than 10 seconds.
  269. //
  270. dwWaitTime = ssStatus.dwWaitHint / 10;
  271. if( dwWaitTime < 1000 )
  272. dwWaitTime = 1000;
  273. else if ( dwWaitTime > 10000 )
  274. dwWaitTime = 10000;
  275. Sleep( dwWaitTime );
  276. // Check the status again.
  277. //
  278. if (!QueryServiceStatus(
  279. schService, // handle to service
  280. &ssStatus) ) // address of structure
  281. break;
  282. if ( ssStatus.dwCheckPoint > dwOldCheckPoint )
  283. {
  284. // The service is making progress.
  285. //
  286. dwStartTickCount = GetTickCount();
  287. dwOldCheckPoint = ssStatus.dwCheckPoint;
  288. }
  289. else
  290. {
  291. if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)
  292. {
  293. // No progress made within the wait hint
  294. //
  295. break;
  296. }
  297. }
  298. }
  299. if (ssStatus.dwCurrentState == SERVICE_RUNNING)
  300. {
  301. dwStatus = NO_ERROR;
  302. }
  303. else
  304. {
  305. // Set the return value to the last error.
  306. //
  307. dwStatus = GetLastError();
  308. }
  309. }
  310. }
  311. return dwStatus;
  312. }
  313. DWORD WaitForServiceStartName(LPTSTR lpszServiceName)
  314. {
  315. SC_HANDLE hSCM = NULL;
  316. SC_HANDLE schService = NULL;
  317. DWORD dwStatus = NO_ERROR;
  318. if ( lpszServiceName )
  319. {
  320. if ( hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS) )
  321. {
  322. if ( schService = OpenService(hSCM, lpszServiceName, SERVICE_ALL_ACCESS) )
  323. {
  324. dwStatus = WaitForServiceStart(schService);
  325. CloseServiceHandle(schService);
  326. }
  327. else
  328. {
  329. dwStatus = GetLastError();
  330. FacLogFile(0 | LOG_ERR, IDS_ERR_SERVICE, lpszServiceName);
  331. }
  332. CloseServiceHandle(hSCM);
  333. }
  334. else
  335. {
  336. dwStatus = GetLastError();
  337. FacLogFile(0 | LOG_ERR, IDS_ERR_SCM);
  338. }
  339. }
  340. else
  341. {
  342. dwStatus = E_INVALIDARG;
  343. }
  344. return dwStatus;
  345. }
  346. // Start a service.
  347. //
  348. DWORD StartMyService(LPTSTR lpszServiceName, SC_HANDLE schSCManager)
  349. {
  350. SC_HANDLE schService;
  351. DWORD dwStatus = NO_ERROR;
  352. FacLogFileStr(3, _T("Starting service: %s\n"), lpszServiceName);
  353. if ( NULL != (schService = OpenService(schSCManager, lpszServiceName, SERVICE_ALL_ACCESS)) &&
  354. StartService(schService, 0, NULL) )
  355. {
  356. dwStatus = WaitForServiceStart(schService);
  357. }
  358. if ( schService )
  359. CloseServiceHandle(schService);
  360. return dwStatus;
  361. }