Leaked source code of windows server 2003
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.

2629 lines
78 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. netboot.c
  5. Abstract:
  6. This module contains the code to initialize network boot.
  7. Author:
  8. Chuck Lenzmeier (chuckl) December 27, 1996
  9. Environment:
  10. Kernel mode, system initialization code
  11. Revision History:
  12. Colin Watson (colinw) November 1997 Add CSC support
  13. --*/
  14. #include "iop.h"
  15. #pragma hdrstop
  16. #include <regstrp.h>
  17. #include <ntddip.h>
  18. #include <nbtioctl.h>
  19. #include <ntddnfs.h>
  20. #include <ntddbrow.h>
  21. #include <ntddtcp.h>
  22. #include <setupblk.h>
  23. #include <remboot.h>
  24. #ifdef ALLOC_DATA_PRAGMA
  25. #pragma const_seg("INITCONST")
  26. #endif
  27. #include <oscpkt.h>
  28. #include <windef.h>
  29. #include <tdiinfo.h>
  30. #ifndef NT
  31. #define NT
  32. #include <ipinfo.h>
  33. #undef NT
  34. #else
  35. #include <ipinfo.h>
  36. #endif
  37. #include <devguid.h>
  38. extern BOOLEAN ExpInTextModeSetup;
  39. BOOLEAN IopRemoteBootCardInitialized = FALSE;
  40. //
  41. // TCP/IP definitions
  42. //
  43. #define DEFAULT_DEST 0
  44. #define DEFAULT_DEST_MASK 0
  45. #define DEFAULT_METRIC 1
  46. NTSTATUS
  47. IopWriteIpAddressToRegistry(
  48. HANDLE handle,
  49. PWCHAR regkey,
  50. PUCHAR value
  51. );
  52. NTSTATUS
  53. IopTCPQueryInformationEx(
  54. IN HANDLE TCPHandle,
  55. IN TDIObjectID FAR *ID,
  56. OUT void FAR *Buffer,
  57. IN OUT DWORD FAR *BufferSize,
  58. IN OUT BYTE FAR *Context
  59. );
  60. NTSTATUS
  61. IopTCPSetInformationEx(
  62. IN HANDLE TCPHandle,
  63. IN TDIObjectID FAR *ID,
  64. IN void FAR *Buffer,
  65. IN DWORD FAR BufferSize
  66. );
  67. NTSTATUS
  68. IopSetDefaultGateway(
  69. IN ULONG GatewayAddress
  70. );
  71. NTSTATUS
  72. IopCacheNetbiosNameForIpAddress(
  73. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  74. );
  75. VOID
  76. IopAssignNetworkDriveLetter (
  77. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  78. );
  79. //
  80. // The following allows the I/O system's initialization routines to be
  81. // paged out of memory.
  82. //
  83. #ifdef ALLOC_PRAGMA
  84. __inline long
  85. htonl(long x);
  86. #pragma alloc_text(INIT,IopAddRemoteBootValuesToRegistry)
  87. #pragma alloc_text(INIT,IopStartNetworkForRemoteBoot)
  88. #pragma alloc_text(INIT,IopStartTcpIpForRemoteBoot)
  89. #pragma alloc_text(INIT,IopIsRemoteBootCard)
  90. #pragma alloc_text(INIT,IopSetupRemoteBootCard)
  91. #pragma alloc_text(INIT,IopAssignNetworkDriveLetter)
  92. #pragma alloc_text(INIT,IopWriteIpAddressToRegistry)
  93. #pragma alloc_text(INIT,IopSetDefaultGateway)
  94. #pragma alloc_text(INIT,htonl)
  95. #pragma alloc_text(INIT,IopCacheNetbiosNameForIpAddress)
  96. #pragma alloc_text(INIT,IopTCPQueryInformationEx)
  97. #pragma alloc_text(INIT,IopTCPSetInformationEx)
  98. #endif
  99. NTSTATUS
  100. IopAddRemoteBootValuesToRegistry (
  101. PLOADER_PARAMETER_BLOCK LoaderBlock
  102. )
  103. {
  104. NTSTATUS status = STATUS_SUCCESS;
  105. HANDLE handle;
  106. HANDLE serviceHandle;
  107. OBJECT_ATTRIBUTES objectAttributes;
  108. UNICODE_STRING string;
  109. CHAR addressA[16];
  110. WCHAR addressW[16];
  111. STRING addressStringA;
  112. UNICODE_STRING addressStringW;
  113. PUCHAR addressPointer;
  114. PUCHAR p;
  115. PUCHAR q;
  116. PUCHAR ntName;
  117. PWCHAR imagePath;
  118. STRING ansiString;
  119. UNICODE_STRING unicodeString;
  120. UNICODE_STRING dnsNameString;
  121. UNICODE_STRING netbiosNameString;
  122. ULONG tmpValue;
  123. ULONG bufferLength;
  124. PUCHAR buffer = NULL;
  125. //
  126. // allocate a scratch buffer, making it as large as we'll need.
  127. //
  128. bufferLength = sizeof("\\Device\\LanmanRedirector") + strlen(LoaderBlock->NtBootPathName);
  129. if (LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_IS_TEXTMODE) {
  130. bufferLength = max(
  131. bufferLength,
  132. sizeof("\\Device\\LanmanRedirector") + strlen(LoaderBlock->SetupLoaderBlock->MachineDirectoryPath));
  133. }
  134. bufferLength = max(
  135. bufferLength,
  136. sizeof(L"system32\\drivers\\") + wcslen(LoaderBlock->SetupLoaderBlock->NetbootCardDriverName)*sizeof(WCHAR));
  137. buffer = ExAllocatePoolWithTag( NonPagedPool, bufferLength, 'bRoI' );
  138. if (buffer == NULL) {
  139. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to allocate buffer\n"));
  140. status = STATUS_INSUFFICIENT_RESOURCES;
  141. goto cleanup;
  142. }
  143. ntName = buffer;
  144. imagePath = (PWCHAR)buffer;
  145. if (LoaderBlock->SetupLoaderBlock->ComputerName[0] != 0) {
  146. //
  147. // Convert the name to a Netbios name.
  148. //
  149. _wcsupr( LoaderBlock->SetupLoaderBlock->ComputerName );
  150. RtlInitUnicodeString( &dnsNameString, LoaderBlock->SetupLoaderBlock->ComputerName );
  151. status = RtlDnsHostNameToComputerName(
  152. &netbiosNameString,
  153. &dnsNameString,
  154. TRUE); // allocate netbiosNameString
  155. if ( !NT_SUCCESS(status) ) {
  156. KdPrint(( "IopAddRemoteBootValuesToRegistry: Failed RtlDnsHostNameToComputerName: %x\n", status ));
  157. goto cleanup;
  158. }
  159. //
  160. // Add a value for the computername.
  161. //
  162. IopWstrToUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName" );
  163. InitializeObjectAttributes(
  164. &objectAttributes,
  165. &string,
  166. OBJ_CASE_INSENSITIVE,
  167. NULL,
  168. NULL
  169. );
  170. status = NtOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
  171. if ( !NT_SUCCESS(status) ) {
  172. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open ComputerName key: %x\n", status ));
  173. RtlFreeUnicodeString( &netbiosNameString );
  174. goto cleanup;
  175. }
  176. IopWstrToUnicodeString( &string, L"ComputerName" );
  177. status = NtSetValueKey(
  178. handle,
  179. &string,
  180. 0,
  181. REG_SZ,
  182. netbiosNameString.Buffer,
  183. netbiosNameString.Length + sizeof(WCHAR)
  184. );
  185. NtClose( handle );
  186. RtlFreeUnicodeString( &netbiosNameString );
  187. if ( !NT_SUCCESS(status) ) {
  188. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to set ComputerName value: %x\n", status ));
  189. goto cleanup;
  190. }
  191. //
  192. // Add a value for the host name.
  193. //
  194. IopWstrToUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters" );
  195. InitializeObjectAttributes(
  196. &objectAttributes,
  197. &string,
  198. OBJ_CASE_INSENSITIVE,
  199. NULL,
  200. NULL
  201. );
  202. status = NtOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
  203. if ( !NT_SUCCESS(status) ) {
  204. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open Tcpip\\Parameters key: %x\n", status ));
  205. goto cleanup;
  206. }
  207. _wcslwr( LoaderBlock->SetupLoaderBlock->ComputerName );
  208. IopWstrToUnicodeString( &string, L"Hostname" );
  209. status = NtSetValueKey(
  210. handle,
  211. &string,
  212. 0,
  213. REG_SZ,
  214. LoaderBlock->SetupLoaderBlock->ComputerName,
  215. (wcslen(LoaderBlock->SetupLoaderBlock->ComputerName) + 1) * sizeof(WCHAR)
  216. );
  217. NtClose( handle );
  218. if ( !NT_SUCCESS(status) ) {
  219. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to set Hostname value: %x\n", status ));
  220. goto cleanup;
  221. }
  222. }
  223. //
  224. // If the UNC path to the system files is supplied then store it in the registry.
  225. //
  226. ASSERT( _stricmp(LoaderBlock->ArcBootDeviceName,"net(0)") == 0 );
  227. IopWstrToUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control" );
  228. InitializeObjectAttributes(
  229. &objectAttributes,
  230. &string,
  231. OBJ_CASE_INSENSITIVE,
  232. NULL,
  233. NULL
  234. );
  235. status = NtOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
  236. if ( !NT_SUCCESS(status) ) {
  237. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open Control key: %x\n", status ));
  238. goto skiproot;
  239. }
  240. p = strrchr( LoaderBlock->NtBootPathName, '\\' ); // find last separator
  241. if ( (p != NULL) && (*(p+1) == 0) ) {
  242. //
  243. // NtBootPathName ends with a backslash, so we need to back up
  244. // to the previous backslash.
  245. //
  246. q = p;
  247. *q = 0;
  248. p = strrchr( LoaderBlock->NtBootPathName, '\\' ); // find last separator
  249. *q = '\\';
  250. }
  251. if ( p == NULL ) {
  252. KdPrint(( "IopAddRemoteBootValuesToRegistry: malformed NtBootPathName: %s\n", LoaderBlock->NtBootPathName ));
  253. NtClose( handle );
  254. goto skiproot;
  255. }
  256. *p = 0; // terminate \server\share\images\machine
  257. strcpy( ntName, "\\Device\\LanmanRedirector");
  258. strcat( ntName, LoaderBlock->NtBootPathName ); // append \server\share\images\machine
  259. *p = '\\';
  260. RtlInitAnsiString( &ansiString, ntName );
  261. status = RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, TRUE );
  262. if (!NT_SUCCESS(status)) {
  263. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to convert RemoteBootRoot value: %x\n", status ));
  264. } else {
  265. IopWstrToUnicodeString( &string, L"RemoteBootRoot" );
  266. status = NtSetValueKey(
  267. handle,
  268. &string,
  269. 0,
  270. REG_SZ,
  271. unicodeString.Buffer,
  272. unicodeString.Length + sizeof(WCHAR)
  273. );
  274. RtlFreeUnicodeString( &unicodeString );
  275. if ( !NT_SUCCESS(status) ) {
  276. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to set RemoteBootRoot value: %x\n", status ));
  277. }
  278. }
  279. if ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_IS_TEXTMODE) != 0) {
  280. strcpy( ntName, "\\Device\\LanmanRedirector");
  281. strcat( ntName, LoaderBlock->SetupLoaderBlock->MachineDirectoryPath );
  282. RtlInitAnsiString( &ansiString, ntName );
  283. status = RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, TRUE );
  284. if ( !NT_SUCCESS(status) ) {
  285. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to convert RemoteBootMachineDirectory value: %x\n", status ));
  286. } else {
  287. IopWstrToUnicodeString( &string, L"RemoteBootMachineDirectory" );
  288. status = NtSetValueKey(
  289. handle,
  290. &string,
  291. 0,
  292. REG_SZ,
  293. unicodeString.Buffer,
  294. unicodeString.Length + sizeof(WCHAR)
  295. );
  296. RtlFreeUnicodeString( &unicodeString );
  297. if ( !NT_SUCCESS(status) ) {
  298. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to set RemoteBootMachineDirectory value: %x\n", status ));
  299. }
  300. }
  301. }
  302. NtClose( handle );
  303. skiproot:
  304. //
  305. // Add registry values for the IP address and subnet mask received
  306. // from DHCP. These are stored under the Tcpip service key and are
  307. // read by both Tcpip and Netbt. The adapter name used is the known
  308. // GUID for the NetbootCard.
  309. //
  310. IopWstrToUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\{54C7D140-09EF-11D1-B25A-F5FE627ED95E}" );
  311. InitializeObjectAttributes(
  312. &objectAttributes,
  313. &string,
  314. OBJ_CASE_INSENSITIVE,
  315. NULL,
  316. NULL
  317. );
  318. status = NtOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
  319. if ( !NT_SUCCESS(status) ) {
  320. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open Tcpip\\Parameters\\Interfaces\\{54C7D140-09EF-11D1-B25A-F5FE627ED95E} key: %x\n", status ));
  321. goto cleanup;
  322. }
  323. status = IopWriteIpAddressToRegistry(handle,
  324. L"DhcpIPAddress",
  325. (PUCHAR)&(LoaderBlock->SetupLoaderBlock->IpAddress)
  326. );
  327. if ( !NT_SUCCESS(status)) {
  328. NtClose(handle);
  329. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to write DhcpIPAddress: %x\n", status ));
  330. goto cleanup;
  331. }
  332. status = IopWriteIpAddressToRegistry(handle,
  333. L"DhcpSubnetMask",
  334. (PUCHAR)&(LoaderBlock->SetupLoaderBlock->SubnetMask)
  335. );
  336. if ( !NT_SUCCESS(status)) {
  337. NtClose(handle);
  338. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to write DhcpSubnetMask: %x\n", status ));
  339. goto cleanup;
  340. }
  341. status = IopWriteIpAddressToRegistry(handle,
  342. L"DhcpDefaultGateway",
  343. (PUCHAR)&(LoaderBlock->SetupLoaderBlock->DefaultRouter)
  344. );
  345. NtClose(handle);
  346. if ( !NT_SUCCESS(status)) {
  347. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to write DhcpDefaultGateway: %x\n", status ));
  348. goto cleanup;
  349. }
  350. //
  351. // Create the service key for the netboot card. We need to have
  352. // the Type value there or the card won't be initialized.
  353. //
  354. status = IopOpenRegistryKeyEx(&handle,
  355. NULL,
  356. &CmRegistryMachineSystemCurrentControlSetServices,
  357. KEY_ALL_ACCESS
  358. );
  359. if (!NT_SUCCESS(status)) {
  360. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open CurrentControlSet\\Services: %x\n", status ));
  361. goto cleanup;
  362. }
  363. RtlInitUnicodeString(&string, LoaderBlock->SetupLoaderBlock->NetbootCardServiceName);
  364. InitializeObjectAttributes(&objectAttributes,
  365. &string,
  366. OBJ_CASE_INSENSITIVE,
  367. handle,
  368. (PSECURITY_DESCRIPTOR)NULL
  369. );
  370. status = ZwCreateKey(&serviceHandle,
  371. KEY_ALL_ACCESS,
  372. &objectAttributes,
  373. 0,
  374. (PUNICODE_STRING)NULL,
  375. 0,
  376. &tmpValue // disposition
  377. );
  378. ZwClose(handle);
  379. if (!NT_SUCCESS(status)) {
  380. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open/create netboot card service key: %x\n", status ));
  381. goto cleanup;
  382. }
  383. //
  384. // Store the image path.
  385. //
  386. IopWstrToUnicodeString(&string, L"ImagePath");
  387. wcscpy(imagePath, L"system32\\drivers\\");
  388. wcscat(imagePath, LoaderBlock->SetupLoaderBlock->NetbootCardDriverName);
  389. status = ZwSetValueKey(serviceHandle,
  390. &string,
  391. TITLE_INDEX_VALUE,
  392. REG_SZ,
  393. imagePath,
  394. (wcslen(imagePath) + 1) * sizeof(WCHAR)
  395. );
  396. if (!NT_SUCCESS(status)) {
  397. NtClose(serviceHandle);
  398. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to write ImagePath: %x\n", status ));
  399. goto cleanup;
  400. }
  401. //
  402. // Store the type.
  403. //
  404. IopWstrToUnicodeString(&string, L"Type");
  405. tmpValue = 1;
  406. status = ZwSetValueKey(serviceHandle,
  407. &string,
  408. TITLE_INDEX_VALUE,
  409. REG_DWORD,
  410. &tmpValue,
  411. sizeof(tmpValue)
  412. );
  413. NtClose(serviceHandle);
  414. if (!NT_SUCCESS(status)) {
  415. KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to write Type: %x\n", status ));
  416. }
  417. cleanup:
  418. if (buffer) {
  419. ExFreePool( buffer );
  420. buffer = NULL;
  421. }
  422. return status;
  423. }
  424. NTSTATUS
  425. IopStartNetworkForRemoteBoot (
  426. PLOADER_PARAMETER_BLOCK LoaderBlock
  427. )
  428. {
  429. NTSTATUS status;
  430. HANDLE dgHandle;
  431. HANDLE keyHandle;
  432. OBJECT_ATTRIBUTES objectAttributes;
  433. IO_STATUS_BLOCK ioStatusBlock;
  434. UNICODE_STRING string;
  435. UNICODE_STRING computerName;
  436. UNICODE_STRING domainName;
  437. PUCHAR buffer;
  438. ULONG bufferLength;
  439. PLMR_REQUEST_PACKET rrp;
  440. PLMDR_REQUEST_PACKET drrp;
  441. WKSTA_INFO_502 wkstaConfig;
  442. WKSTA_TRANSPORT_INFO_0 wkstaTransportInfo;
  443. LARGE_INTEGER interval;
  444. ULONG length;
  445. PKEY_VALUE_PARTIAL_INFORMATION keyValue;
  446. BOOLEAN startDatagramReceiver;
  447. ULONG enumerateAttempts;
  448. HANDLE RdrHandle;
  449. HANDLE eventHandle;
  450. //
  451. // Initialize for cleanup.
  452. //
  453. buffer = NULL;
  454. computerName.Buffer = NULL;
  455. domainName.Buffer = NULL;
  456. dgHandle = NULL;
  457. RdrHandle = NULL;
  458. eventHandle = NULL;
  459. //
  460. // Allocate a temporary buffer. It has to be big enough for all the
  461. // various FSCTLs we send down.
  462. //
  463. bufferLength = max(sizeof(LMR_REQUEST_PACKET) + (MAX_PATH + 1) * sizeof(WCHAR) +
  464. (DNLEN + 1) * sizeof(WCHAR),
  465. max(sizeof(LMDR_REQUEST_PACKET),
  466. FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + MAX_PATH));
  467. bufferLength = max(bufferLength, sizeof(LMMR_RI_INITIALIZE_SECRET));
  468. buffer = ExAllocatePoolWithTag( NonPagedPool, bufferLength, 'bRoI' );
  469. if (buffer == NULL) {
  470. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to allocate buffer\n"));
  471. status = STATUS_INSUFFICIENT_RESOURCES;
  472. goto cleanup;
  473. }
  474. rrp = (PLMR_REQUEST_PACKET)buffer;
  475. drrp = (PLMDR_REQUEST_PACKET)buffer;
  476. //
  477. // Open the redirector and the datagram receiver.
  478. //
  479. IopWstrToUnicodeString( &string, L"\\Device\\LanmanRedirector" );
  480. InitializeObjectAttributes(
  481. &objectAttributes,
  482. &string,
  483. OBJ_CASE_INSENSITIVE,
  484. NULL,
  485. NULL
  486. );
  487. status = NtCreateFile(
  488. &RdrHandle,
  489. GENERIC_READ | GENERIC_WRITE,
  490. &objectAttributes,
  491. &ioStatusBlock,
  492. NULL,
  493. 0,
  494. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  495. FILE_OPEN,
  496. FILE_SYNCHRONOUS_IO_NONALERT,
  497. NULL,
  498. 0
  499. );
  500. if ( !NT_SUCCESS(status) ) {
  501. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to open redirector: %x\n", status ));
  502. goto cleanup;
  503. }
  504. IopWstrToUnicodeString( &string, DD_BROWSER_DEVICE_NAME_U );
  505. InitializeObjectAttributes(
  506. &objectAttributes,
  507. &string,
  508. OBJ_CASE_INSENSITIVE,
  509. NULL,
  510. NULL
  511. );
  512. status = NtCreateFile(
  513. &dgHandle,
  514. GENERIC_READ | GENERIC_WRITE,
  515. &objectAttributes,
  516. &ioStatusBlock,
  517. NULL,
  518. 0,
  519. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  520. FILE_OPEN,
  521. FILE_SYNCHRONOUS_IO_NONALERT,
  522. NULL,
  523. 0
  524. );
  525. if ( !NT_SUCCESS(status) ) {
  526. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to open datagram receiver: %x\n", status ));
  527. goto cleanup;
  528. }
  529. status = NtCreateEvent(
  530. &eventHandle,
  531. EVENT_ALL_ACCESS,
  532. NULL,
  533. SynchronizationEvent,
  534. FALSE );
  535. if ( !NT_SUCCESS(status) ) {
  536. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to createevent redirector: %x\n", status ));
  537. goto cleanup;
  538. }
  539. //
  540. // If the setup loader block has a disk secret in it provided by the
  541. // loader, pass this down to the redirector (do this before sending
  542. // the LMR_START, since that uses this information).
  543. //
  544. {
  545. PLMMR_RI_INITIALIZE_SECRET RbInit = (PLMMR_RI_INITIALIZE_SECRET)buffer;
  546. ASSERT(LoaderBlock->SetupLoaderBlock->NetBootSecret != NULL);
  547. RtlCopyMemory(
  548. &RbInit->Secret,
  549. LoaderBlock->SetupLoaderBlock->NetBootSecret,
  550. sizeof(RI_SECRET));
  551. status = NtFsControlFile(
  552. RdrHandle,
  553. eventHandle,
  554. NULL,
  555. NULL,
  556. &ioStatusBlock,
  557. FSCTL_LMMR_RI_INITIALIZE_SECRET,
  558. buffer,
  559. sizeof(LMMR_RI_INITIALIZE_SECRET),
  560. NULL,
  561. 0
  562. );
  563. if (status == STATUS_PENDING) {
  564. NtWaitForSingleObject(
  565. eventHandle,
  566. FALSE,
  567. NULL);
  568. status = ioStatusBlock.Status;
  569. }
  570. if ( NT_SUCCESS(status) ) {
  571. status = ioStatusBlock.Status;
  572. }
  573. NtClearEvent( eventHandle );
  574. if ( !NT_SUCCESS(status) ) {
  575. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to FSCTL(RB initialize) redirector: %x\n", status ));
  576. goto cleanup;
  577. }
  578. }
  579. //
  580. // Read the computer name and domain name from the registry so we
  581. // can give them to the datagram receiver. During textmode setup
  582. // the domain name will not be there, so we won't start the datagram
  583. // receiver, which is fine.
  584. //
  585. IopWstrToUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName" );
  586. InitializeObjectAttributes(
  587. &objectAttributes,
  588. &string,
  589. OBJ_CASE_INSENSITIVE,
  590. NULL,
  591. NULL
  592. );
  593. status = NtOpenKey( &keyHandle, KEY_ALL_ACCESS, &objectAttributes );
  594. if ( !NT_SUCCESS(status) ) {
  595. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to open ComputerName key: %x\n", status ));
  596. goto cleanup;
  597. }
  598. IopWstrToUnicodeString( &string, L"ComputerName" );
  599. keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  600. RtlZeroMemory(buffer, bufferLength);
  601. status = NtQueryValueKey(
  602. keyHandle,
  603. &string,
  604. KeyValuePartialInformation,
  605. keyValue,
  606. bufferLength,
  607. &length);
  608. NtClose( keyHandle );
  609. if ( !NT_SUCCESS(status) ) {
  610. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to query ComputerName value: %x\n", status ));
  611. goto cleanup;
  612. }
  613. if ( !RtlCreateUnicodeString(&computerName, (PWSTR)keyValue->Data) ) {
  614. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to create ComputerName string\n" ));
  615. status = STATUS_INSUFFICIENT_RESOURCES;
  616. goto cleanup;
  617. }
  618. domainName.Length = 0;
  619. IopWstrToUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\DomainName" );
  620. InitializeObjectAttributes(
  621. &objectAttributes,
  622. &string,
  623. OBJ_CASE_INSENSITIVE,
  624. NULL,
  625. NULL
  626. );
  627. status = NtOpenKey( &keyHandle, KEY_ALL_ACCESS, &objectAttributes );
  628. if ( !NT_SUCCESS(status) ) {
  629. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to open DomainName key: %x\n", status ));
  630. startDatagramReceiver = FALSE;
  631. } else {
  632. IopWstrToUnicodeString( &string, L"DomainName" );
  633. keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  634. RtlZeroMemory(buffer, bufferLength);
  635. status = NtQueryValueKey(
  636. keyHandle,
  637. &string,
  638. KeyValuePartialInformation,
  639. keyValue,
  640. bufferLength,
  641. &length);
  642. NtClose( keyHandle );
  643. if ( !NT_SUCCESS(status) ) {
  644. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to query Domain value: %x\n", status ));
  645. startDatagramReceiver = FALSE;
  646. } else {
  647. if ( !RtlCreateUnicodeString(&domainName, (PWSTR)keyValue->Data) ) {
  648. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to create DomainName string\n" ));
  649. status = STATUS_INSUFFICIENT_RESOURCES;
  650. goto cleanup;
  651. }
  652. startDatagramReceiver = TRUE;
  653. }
  654. }
  655. //
  656. // Tell the redir to start.
  657. //
  658. rrp->Type = ConfigInformation;
  659. rrp->Version = REQUEST_PACKET_VERSION;
  660. rrp->Parameters.Start.RedirectorNameLength = computerName.Length;
  661. RtlCopyMemory(rrp->Parameters.Start.RedirectorName,
  662. computerName.Buffer,
  663. computerName.Length);
  664. rrp->Parameters.Start.DomainNameLength = domainName.Length;
  665. RtlCopyMemory(((PUCHAR)rrp->Parameters.Start.RedirectorName) + computerName.Length,
  666. domainName.Buffer,
  667. domainName.Length);
  668. RtlFreeUnicodeString(&computerName);
  669. RtlFreeUnicodeString(&domainName);
  670. wkstaConfig.wki502_char_wait = 3600;
  671. wkstaConfig.wki502_maximum_collection_count = 16;
  672. wkstaConfig.wki502_collection_time = 250;
  673. wkstaConfig.wki502_keep_conn = 600;
  674. wkstaConfig.wki502_max_cmds = 5;
  675. wkstaConfig.wki502_sess_timeout = 45;
  676. wkstaConfig.wki502_siz_char_buf = 512;
  677. wkstaConfig.wki502_max_threads = 17;
  678. wkstaConfig.wki502_lock_quota = 6144;
  679. wkstaConfig.wki502_lock_increment = 10;
  680. wkstaConfig.wki502_lock_maximum = 500;
  681. wkstaConfig.wki502_pipe_increment = 10;
  682. wkstaConfig.wki502_pipe_maximum = 500;
  683. wkstaConfig.wki502_cache_file_timeout = 40;
  684. wkstaConfig.wki502_dormant_file_limit = 45;
  685. wkstaConfig.wki502_read_ahead_throughput = MAXULONG;
  686. wkstaConfig.wki502_num_mailslot_buffers = 3;
  687. wkstaConfig.wki502_num_srv_announce_buffers = 20;
  688. wkstaConfig.wki502_max_illegal_datagram_events = 5;
  689. wkstaConfig.wki502_illegal_datagram_event_reset_frequency = 60;
  690. wkstaConfig.wki502_log_election_packets = FALSE;
  691. wkstaConfig.wki502_use_opportunistic_locking = TRUE;
  692. wkstaConfig.wki502_use_unlock_behind = TRUE;
  693. wkstaConfig.wki502_use_close_behind = TRUE;
  694. wkstaConfig.wki502_buf_named_pipes = TRUE;
  695. wkstaConfig.wki502_use_lock_read_unlock = TRUE;
  696. wkstaConfig.wki502_utilize_nt_caching = TRUE;
  697. wkstaConfig.wki502_use_raw_read = TRUE;
  698. wkstaConfig.wki502_use_raw_write = TRUE;
  699. wkstaConfig.wki502_use_write_raw_data = TRUE;
  700. wkstaConfig.wki502_use_encryption = TRUE;
  701. wkstaConfig.wki502_buf_files_deny_write = TRUE;
  702. wkstaConfig.wki502_buf_read_only_files = TRUE;
  703. wkstaConfig.wki502_force_core_create_mode = TRUE;
  704. wkstaConfig.wki502_use_512_byte_max_transfer = FALSE;
  705. status = NtFsControlFile(
  706. RdrHandle,
  707. eventHandle,
  708. NULL,
  709. NULL,
  710. &ioStatusBlock,
  711. FSCTL_LMR_START | 0x80000000,
  712. rrp,
  713. sizeof(LMR_REQUEST_PACKET) +
  714. rrp->Parameters.Start.RedirectorNameLength +
  715. rrp->Parameters.Start.DomainNameLength,
  716. &wkstaConfig,
  717. sizeof(wkstaConfig)
  718. );
  719. if (status == STATUS_PENDING) {
  720. NtWaitForSingleObject(
  721. eventHandle,
  722. FALSE,
  723. NULL);
  724. status = ioStatusBlock.Status;
  725. }
  726. if ( NT_SUCCESS(status) ) {
  727. status = ioStatusBlock.Status;
  728. }
  729. if ( !NT_SUCCESS(status) ) {
  730. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to FSCTL(start) redirector: %x\n", status ));
  731. goto cleanup;
  732. }
  733. NtClearEvent( eventHandle );
  734. if (startDatagramReceiver) {
  735. //
  736. // Tell the datagram receiver to start.
  737. //
  738. drrp->Version = LMDR_REQUEST_PACKET_VERSION;
  739. drrp->Parameters.Start.NumberOfMailslotBuffers = 16;
  740. drrp->Parameters.Start.NumberOfServerAnnounceBuffers = 20;
  741. drrp->Parameters.Start.IllegalDatagramThreshold = 5;
  742. drrp->Parameters.Start.EventLogResetFrequency = 60;
  743. drrp->Parameters.Start.LogElectionPackets = FALSE;
  744. drrp->Parameters.Start.IsLanManNt = FALSE;
  745. status = NtDeviceIoControlFile(
  746. dgHandle,
  747. eventHandle,
  748. NULL,
  749. NULL,
  750. &ioStatusBlock,
  751. IOCTL_LMDR_START,
  752. drrp,
  753. sizeof(LMDR_REQUEST_PACKET),
  754. NULL,
  755. 0
  756. );
  757. if ( status == STATUS_PENDING ) {
  758. NtWaitForSingleObject(
  759. eventHandle,
  760. FALSE,
  761. NULL);
  762. status = ioStatusBlock.Status;
  763. }
  764. if ( NT_SUCCESS(status) ) {
  765. status = ioStatusBlock.Status;
  766. }
  767. NtClearEvent( eventHandle );
  768. NtClose( dgHandle );
  769. dgHandle = NULL;
  770. if ( !NT_SUCCESS(status) ) {
  771. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to IOCTL(start) datagram receiver: %x\n", status ));
  772. goto cleanup;
  773. }
  774. } else {
  775. NtClose( dgHandle );
  776. dgHandle = NULL;
  777. //
  778. // Tell the redir to bind to the transports.
  779. //
  780. // Note: In the current redirector implementation, this call just
  781. // tells the redirector to register for TDI PnP notifications.
  782. // Starting the datagram receiver also does this, so we only issue
  783. // this FSCTL if we're not starting the datagram receiver.
  784. //
  785. status = NtFsControlFile(
  786. RdrHandle,
  787. eventHandle,
  788. NULL,
  789. NULL,
  790. &ioStatusBlock,
  791. FSCTL_LMR_BIND_TO_TRANSPORT | 0x80000000,
  792. NULL,
  793. 0,
  794. NULL,
  795. 0
  796. );
  797. if ( status == STATUS_PENDING ) {
  798. NtWaitForSingleObject(
  799. eventHandle,
  800. FALSE,
  801. NULL);
  802. status = ioStatusBlock.Status;
  803. }
  804. if ( NT_SUCCESS(status) ) {
  805. status = ioStatusBlock.Status;
  806. }
  807. NtClearEvent( eventHandle );
  808. if ( !NT_SUCCESS(status) ) {
  809. KdPrint(( "IopStartNetworkForRemoteBoot: Unable to FSCTL(bind) redirector: %x\n", status ));
  810. goto cleanup;
  811. }
  812. }
  813. {
  814. //
  815. // Loop until the redirector is bound to the transport. It may take a
  816. // while because TDI defers notification of binding to a worker thread.
  817. // We start with a half a second wait and double it each time, trying
  818. // five times total.
  819. //
  820. interval.QuadPart = -500 * 1000 * 10; // 1/2 second, relative
  821. enumerateAttempts = 0;
  822. while (TRUE) {
  823. KeDelayExecutionThread(KernelMode, FALSE, &interval);
  824. RtlZeroMemory(rrp, sizeof(LMR_REQUEST_PACKET));
  825. rrp->Type = EnumerateTransports;
  826. rrp->Version = REQUEST_PACKET_VERSION;
  827. status = NtFsControlFile(
  828. RdrHandle,
  829. NULL,
  830. NULL,
  831. NULL,
  832. &ioStatusBlock,
  833. FSCTL_LMR_ENUMERATE_TRANSPORTS,
  834. rrp,
  835. sizeof(LMR_REQUEST_PACKET),
  836. &wkstaTransportInfo,
  837. sizeof(wkstaTransportInfo)
  838. );
  839. if ( NT_SUCCESS(status) ) {
  840. status = ioStatusBlock.Status;
  841. }
  842. if ( !NT_SUCCESS(status) ) {
  843. //KdPrint(( "IopStartNetworkForRemoteBoot: Unable to FSCTL(enumerate) redirector: %x\n", status ));
  844. } else if (rrp->Parameters.Get.TotalBytesNeeded == 0) {
  845. //KdPrint(( "IopStartNetworkForRemoteBoot: FSCTL(enumerate) returned 0 entries\n" ));
  846. } else {
  847. break;
  848. }
  849. ++enumerateAttempts;
  850. if (enumerateAttempts == 5) {
  851. KdPrint(( "IopStartNetworkForRemoteBoot: Redirector didn't start\n" ));
  852. status = STATUS_REDIRECTOR_NOT_STARTED;
  853. goto cleanup;
  854. }
  855. interval.QuadPart *= 2;
  856. }
  857. }
  858. //
  859. // Prime the transport.
  860. //
  861. IopSetDefaultGateway(LoaderBlock->SetupLoaderBlock->DefaultRouter);
  862. IopCacheNetbiosNameForIpAddress(LoaderBlock);
  863. IopAssignNetworkDriveLetter(LoaderBlock);
  864. cleanup:
  865. RtlFreeUnicodeString( &computerName );
  866. RtlFreeUnicodeString( &domainName );
  867. if ( buffer != NULL ) {
  868. ExFreePool( buffer );
  869. }
  870. if ( dgHandle != NULL ) {
  871. NtClose( dgHandle );
  872. }
  873. if (eventHandle) {
  874. NtClose( eventHandle );
  875. }
  876. if (RdrHandle) {
  877. NtClose( RdrHandle );
  878. }
  879. return status;
  880. }
  881. VOID
  882. IopAssignNetworkDriveLetter (
  883. PLOADER_PARAMETER_BLOCK LoaderBlock
  884. )
  885. {
  886. PUCHAR p;
  887. PUCHAR q;
  888. PUCHAR ntName;
  889. STRING ansiString;
  890. UNICODE_STRING unicodeString;
  891. UNICODE_STRING unicodeString2;
  892. NTSTATUS status;
  893. //
  894. // Create the symbolic link of X: to the redirector. We do this
  895. // after the redirector has loaded, but before AssignDriveLetters
  896. // is called the first time in textmode setup (once that has
  897. // happened, the drive letters will stick).
  898. //
  899. // Note that we use X: for the textmode setup phase of a remote
  900. // installation. But for a true remote boot, we use C:.
  901. //
  902. if ((LoaderBlock->SetupLoaderBlock->Flags & (SETUPBLK_FLAGS_REMOTE_INSTALL |
  903. SETUPBLK_FLAGS_SYSPREP_INSTALL)) != 0) {
  904. IopWstrToUnicodeString( &unicodeString2, L"\\DosDevices\\X:");
  905. } else {
  906. IopWstrToUnicodeString( &unicodeString2, L"\\DosDevices\\C:");
  907. }
  908. //
  909. // If this is a remote boot setup boot, NtBootPathName is of the
  910. // form \<server>\<share>\setup\<install-directory>\<platform>.
  911. // We want the root of the X: drive to be the root of the install
  912. // directory.
  913. //
  914. // If this is a normal remote boot, NtBootPathName is of the form
  915. // \<server>\<share>\images\<machine>\winnt. We want the root of
  916. // the X: drive to be the root of the machine directory.
  917. //
  918. // Thus in either case, we need to remove the last element of the
  919. // path.
  920. //
  921. p = strrchr( LoaderBlock->NtBootPathName, '\\' ); // find last separator
  922. if ( (p != NULL) && (*(p+1) == 0) ) {
  923. //
  924. // NtBootPathName ends with a backslash, so we need to back up
  925. // to the previous backslash.
  926. //
  927. q = p;
  928. *q = 0;
  929. p = strrchr( LoaderBlock->NtBootPathName, '\\' ); // find last separator
  930. *q = '\\';
  931. }
  932. if ( p == NULL ) {
  933. KdPrint(( "IopAssignNetworkDriveLetter: malformed NtBootPathName: %s\n", LoaderBlock->NtBootPathName ));
  934. KeBugCheck( ASSIGN_DRIVE_LETTERS_FAILED );
  935. }
  936. *p = 0; // terminate \server\share\images\machine
  937. ntName = ExAllocatePoolWithTag(
  938. NonPagedPool,
  939. sizeof("\\Device\\LanmanRedirector") + strlen(LoaderBlock->NtBootPathName),
  940. 'bRoI' );
  941. if (!ntName) {
  942. KdPrint(( "IopAssignNetworkDriveLetter: unable to alloc memory" ));
  943. KeBugCheck( ASSIGN_DRIVE_LETTERS_FAILED );
  944. }
  945. strcpy( ntName, "\\Device\\LanmanRedirector");
  946. strcat( ntName, LoaderBlock->NtBootPathName ); // append \server\share\images\machine
  947. RtlInitAnsiString( &ansiString, ntName );
  948. status = RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, TRUE );
  949. if (!NT_SUCCESS(status)) {
  950. KdPrint(( "IopAssignNetworkDriveLetter: unable to convert DOS link for redirected boot drive: %x\n", status ));
  951. KeBugCheck( ASSIGN_DRIVE_LETTERS_FAILED );
  952. }
  953. status = IoCreateSymbolicLink(&unicodeString2, &unicodeString);
  954. if (!NT_SUCCESS(status)) {
  955. KdPrint(( "IopAssignNetworkDriveLetter: unable to create DOS link for redirected boot drive: %x\n", status ));
  956. KeBugCheck( ASSIGN_DRIVE_LETTERS_FAILED );
  957. }
  958. // DbgPrint("IopAssignNetworkDriveLetter: assigned %wZ to %wZ\n", &unicodeString2, &unicodeString);
  959. RtlFreeUnicodeString( &unicodeString );
  960. *p = '\\'; // restore string
  961. ExFreePool( ntName );
  962. return;
  963. }
  964. NTSTATUS
  965. IopStartTcpIpForRemoteBoot (
  966. PLOADER_PARAMETER_BLOCK LoaderBlock
  967. )
  968. {
  969. UNICODE_STRING IpString;
  970. NTSTATUS status = STATUS_SUCCESS;
  971. HANDLE handle = NULL;
  972. HANDLE eventHandle = NULL;
  973. OBJECT_ATTRIBUTES objectAttributes;
  974. IO_STATUS_BLOCK ioStatusBlock;
  975. IP_SET_ADDRESS_REQUEST IpRequest;
  976. RtlInitUnicodeString( &IpString, DD_IP_DEVICE_NAME );
  977. InitializeObjectAttributes(
  978. &objectAttributes,
  979. &IpString,
  980. OBJ_CASE_INSENSITIVE,
  981. NULL,
  982. NULL
  983. );
  984. RtlZeroMemory(&IpRequest, sizeof(IpRequest));
  985. IpRequest.Context = (USHORT)2;
  986. IpRequest.Address = LoaderBlock->SetupLoaderBlock->IpAddress;
  987. IpRequest.SubnetMask = LoaderBlock->SetupLoaderBlock->SubnetMask;
  988. status = NtCreateFile(
  989. &handle,
  990. GENERIC_READ | GENERIC_WRITE,
  991. &objectAttributes,
  992. &ioStatusBlock,
  993. NULL,
  994. 0,
  995. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  996. FILE_OPEN,
  997. FILE_SYNCHRONOUS_IO_NONALERT,
  998. NULL,
  999. 0
  1000. );
  1001. if ( !NT_SUCCESS(status) ) {
  1002. KdPrint(( "IopStartTcpIpForRemoteBoot: Unable to open IP: %x\n", status ));
  1003. goto cleanup;
  1004. }
  1005. status = NtCreateEvent(
  1006. &eventHandle,
  1007. EVENT_ALL_ACCESS,
  1008. NULL,
  1009. SynchronizationEvent,
  1010. FALSE );
  1011. if ( !NT_SUCCESS(status)) {
  1012. KdPrint(( "IopStartTcpIpForRemoteBoot: Unable to create event: %x\n", status ));
  1013. goto cleanup;
  1014. }
  1015. status = NtDeviceIoControlFile(
  1016. handle,
  1017. eventHandle,
  1018. NULL,
  1019. NULL,
  1020. &ioStatusBlock,
  1021. IOCTL_IP_SET_ADDRESS,
  1022. &IpRequest,
  1023. sizeof(IP_SET_ADDRESS_REQUEST),
  1024. NULL,
  1025. 0
  1026. );
  1027. if ( status == STATUS_PENDING ) {
  1028. NtWaitForSingleObject(
  1029. eventHandle,
  1030. FALSE,
  1031. NULL);
  1032. status = ioStatusBlock.Status;
  1033. }
  1034. if ( !NT_SUCCESS(status) ) {
  1035. KdPrint(( "IopStartTcpIpForRemoteBoot: Unable to IOCTL IP: %x\n", status ));
  1036. //
  1037. // if we got a duplicate name error this means that there is another
  1038. // network node with the same address as us. This is a fatal
  1039. // error, and we bugcheck with the ip address as a parameter so that
  1040. // the network administrator can determine how they assigned duplicate
  1041. // addresses on the network.
  1042. //
  1043. if (status == STATUS_DUPLICATE_NAME) {
  1044. KeBugCheckEx(
  1045. NETWORK_BOOT_DUPLICATE_ADDRESS,
  1046. LoaderBlock->SetupLoaderBlock->IpAddress,
  1047. 0,
  1048. 0,
  1049. 0 );
  1050. }
  1051. goto cleanup;
  1052. }
  1053. cleanup:
  1054. if (eventHandle != NULL) {
  1055. NtClose( handle );
  1056. }
  1057. if (handle != NULL) {
  1058. NtClose( handle );
  1059. }
  1060. return status;
  1061. }
  1062. BOOLEAN
  1063. IopIsRemoteBootCard(
  1064. IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements,
  1065. IN PLOADER_PARAMETER_BLOCK LoaderBlock,
  1066. IN PWCHAR HwIds
  1067. )
  1068. /*++
  1069. Routine Description:
  1070. This function determines if the card described by the hwIds is the
  1071. remote boot network card. It checks against the hardware ID for the
  1072. card that is stored in the setup loader block.
  1073. THIS ASSUMES THAT IOREMOTEBOOTCLIENT IS TRUE AND THAT LOADERBLOCK
  1074. IS VALID.
  1075. Arguments:
  1076. DeviceNode - Device node for the card in question.
  1077. LoaderBlock - Supplies a pointer to the loader parameter block that was
  1078. created by the OS Loader.
  1079. HwIds - The hardware IDs for the device in question.
  1080. Return Value:
  1081. TRUE or FALSE.
  1082. --*/
  1083. {
  1084. PSETUP_LOADER_BLOCK setupLoaderBlock;
  1085. PWCHAR curHwId;
  1086. //
  1087. // setupLoaderBlock will always be non-NULL if we are
  1088. // remote booting, even if we are not in setup.
  1089. //
  1090. setupLoaderBlock = LoaderBlock->SetupLoaderBlock;
  1091. //
  1092. // Scan through the HwIds for a match.
  1093. //
  1094. curHwId = HwIds;
  1095. while (*curHwId != L'\0') {
  1096. #if defined (_IA64_)
  1097. //
  1098. // On IA64, PXE may not have told the BINL service enough details about
  1099. // the NIC hardware, so the PNP ID may not be exact. We should test against
  1100. // the PNP ID of the that BINL gave setupldr and then to us.
  1101. //
  1102. if (_wcsnicmp(curHwId, setupLoaderBlock->NetbootCardHardwareId, wcslen(setupLoaderBlock->NetbootCardHardwareId)) == 0) {
  1103. #else
  1104. if (wcscmp(curHwId, setupLoaderBlock->NetbootCardHardwareId) == 0) {
  1105. #endif
  1106. ULONG BusNumber, DeviceNumber, FunctionNumber;
  1107. //
  1108. // PCI's encoding is this: fff ddddd
  1109. // PXE's encoding is this: ddddd fff
  1110. //
  1111. BusNumber = (ULONG)((((PNET_CARD_INFO)setupLoaderBlock->NetbootCardInfo)->pci.BusDevFunc) >> 8);
  1112. DeviceNumber = (ULONG)(((((PNET_CARD_INFO)setupLoaderBlock->NetbootCardInfo)->pci.BusDevFunc) & 0xf8) >> 3);
  1113. FunctionNumber = (ULONG)(((((PNET_CARD_INFO)setupLoaderBlock->NetbootCardInfo)->pci.BusDevFunc) & 0x3));
  1114. KdPrint(("IopIsRemoteBootCard: FOUND %ws\n", setupLoaderBlock->NetbootCardHardwareId));
  1115. if ((ResourceRequirements->BusNumber != BusNumber) ||
  1116. ((ResourceRequirements->SlotNumber & 0x1f) != DeviceNumber) ||
  1117. (((ResourceRequirements->SlotNumber >> 5) & 0x3) != FunctionNumber)) {
  1118. KdPrint(("IopIsRemoteBootCard: ignoring non-matching card:\n"));
  1119. KdPrint((" devnode bus %d, busdevfunc bus %d\n",
  1120. ResourceRequirements->BusNumber,
  1121. BusNumber));
  1122. KdPrint((" devnode slot %d (%d %d), busdevfunc slot %d (%d %d)\n",
  1123. ResourceRequirements->SlotNumber,
  1124. (ResourceRequirements->SlotNumber & 0x1f),
  1125. ((ResourceRequirements->SlotNumber >> 5) & 0x3),
  1126. (ULONG)(((PNET_CARD_INFO)setupLoaderBlock->NetbootCardInfo)->pci.BusDevFunc),
  1127. DeviceNumber,
  1128. FunctionNumber));
  1129. return FALSE;
  1130. } else {
  1131. return TRUE;
  1132. }
  1133. }
  1134. curHwId += (wcslen(curHwId) + 1);
  1135. }
  1136. return FALSE;
  1137. }
  1138. NTSTATUS
  1139. IopSetupRemoteBootCard(
  1140. IN PLOADER_PARAMETER_BLOCK LoaderBlock,
  1141. IN HANDLE UniqueIdHandle,
  1142. IN PUNICODE_STRING UnicodeDeviceInstance
  1143. )
  1144. /*++
  1145. Routine Description:
  1146. This function modifies the registry to set up the netboot card.
  1147. We must do this here since the card is needed to boot, we can't
  1148. wait for the class installer to run.
  1149. THIS ASSUMES THAT IOREMOTEBOOTCLIENT IS TRUE.
  1150. Arguments:
  1151. LoaderBlock - Supplies a pointer to the loader parameter block that was
  1152. created by the OS Loader.
  1153. UniqueIdHandle - A handle to the device's unique node under the
  1154. Enum key.
  1155. UnicodeDeviceInstance - The device instance assigned to the device.
  1156. Return Value:
  1157. Status of the operation.
  1158. --*/
  1159. {
  1160. PSETUP_LOADER_BLOCK setupLoaderBlock;
  1161. UNICODE_STRING unicodeName, pnpInstanceId, keyName;
  1162. HANDLE tmpHandle;
  1163. HANDLE parametersHandle = NULL;
  1164. HANDLE currentControlSetHandle = NULL;
  1165. HANDLE remoteBootHandle = NULL;
  1166. HANDLE instanceHandle = NULL;
  1167. PWCHAR componentIdBuffer, curComponentIdLoc;
  1168. PCHAR registryList;
  1169. ULONG componentIdLength;
  1170. WCHAR tempNameBuffer[32];
  1171. WCHAR tempValueBuffer[128];
  1172. NTSTATUS status;
  1173. ULONG tmpValue, length;
  1174. PKEY_VALUE_PARTIAL_INFORMATION keyValue;
  1175. PKEY_VALUE_BASIC_INFORMATION keyValueBasic;
  1176. UCHAR dataBuffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + 128];
  1177. ULONG enumerateIndex;
  1178. OBJECT_ATTRIBUTES objectAttributes;
  1179. ULONG disposition;
  1180. //
  1181. // If we already think we have initialized a remote boot card, then
  1182. // exit (should not really happen once we identify cards using the
  1183. // bus/slot.
  1184. //
  1185. if (IopRemoteBootCardInitialized) {
  1186. return STATUS_SUCCESS;
  1187. }
  1188. //
  1189. // setupLoaderBlock will always be non-NULL if we are
  1190. // remote booting, even if we are not in setup.
  1191. //
  1192. setupLoaderBlock = LoaderBlock->SetupLoaderBlock;
  1193. //
  1194. // Open the current control set.
  1195. //
  1196. status = IopOpenRegistryKeyEx(&currentControlSetHandle,
  1197. NULL,
  1198. &CmRegistryMachineSystemCurrentControlSet,
  1199. KEY_ALL_ACCESS
  1200. );
  1201. if (!NT_SUCCESS(status)) {
  1202. goto cleanup;
  1203. }
  1204. //
  1205. // Open the Control\RemoteBoot key, which may not exist.
  1206. //
  1207. IopWstrToUnicodeString(&unicodeName, L"Control\\RemoteBoot");
  1208. InitializeObjectAttributes(&objectAttributes,
  1209. &unicodeName,
  1210. OBJ_CASE_INSENSITIVE,
  1211. currentControlSetHandle,
  1212. (PSECURITY_DESCRIPTOR)NULL
  1213. );
  1214. status = ZwCreateKey(&remoteBootHandle,
  1215. KEY_ALL_ACCESS,
  1216. &objectAttributes,
  1217. 0,
  1218. (PUNICODE_STRING)NULL,
  1219. 0,
  1220. &disposition
  1221. );
  1222. if (!NT_SUCCESS(status)) {
  1223. goto cleanup;
  1224. }
  1225. //
  1226. // Open the key where the netui code stores information about the cards.
  1227. // During textmode setup this will fail because the Control\Network
  1228. // key is not there. After that it should work, although we may need
  1229. // to create the last node in the path.
  1230. //
  1231. IopWstrToUnicodeString(&unicodeName, L"Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\{54C7D140-09EF-11D1-B25A-F5FE627ED95E}");
  1232. InitializeObjectAttributes(&objectAttributes,
  1233. &unicodeName,
  1234. OBJ_CASE_INSENSITIVE,
  1235. currentControlSetHandle,
  1236. (PSECURITY_DESCRIPTOR)NULL
  1237. );
  1238. status = ZwCreateKey(&instanceHandle,
  1239. KEY_ALL_ACCESS,
  1240. &objectAttributes,
  1241. 0,
  1242. (PUNICODE_STRING)NULL,
  1243. 0,
  1244. &disposition
  1245. );
  1246. if (NT_SUCCESS(status)) {
  1247. //
  1248. // If the PnpInstanceID of the first netboot card matches the one
  1249. // for this device node, and the NET_CARD_INFO that the loader
  1250. // found is the same as the one we saved, then this is the same
  1251. // card with the same instance ID as before, so we don't need to
  1252. // do anything.
  1253. //
  1254. IopWstrToUnicodeString(&unicodeName, L"PnPInstanceID");
  1255. keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)dataBuffer;
  1256. RtlZeroMemory(dataBuffer, sizeof(dataBuffer));
  1257. status = ZwQueryValueKey(
  1258. instanceHandle,
  1259. &unicodeName,
  1260. KeyValuePartialInformation,
  1261. keyValue,
  1262. sizeof(dataBuffer),
  1263. &length);
  1264. //
  1265. // Check that it matches. We can init the string because we zeroed
  1266. // the dataBuffer before reading the key, so even if the
  1267. // registry value had no NULL at the end that is OK.
  1268. //
  1269. if ((NT_SUCCESS(status)) &&
  1270. (keyValue->Type == REG_SZ)) {
  1271. RtlInitUnicodeString(&pnpInstanceId, (PWSTR)(keyValue->Data));
  1272. if (RtlEqualUnicodeString(UnicodeDeviceInstance, &pnpInstanceId, TRUE)) {
  1273. //
  1274. // Instance ID matched, see if the NET_CARD_INFO matches.
  1275. //
  1276. IopWstrToUnicodeString(&unicodeName, L"NetCardInfo");
  1277. RtlZeroMemory(dataBuffer, sizeof(dataBuffer));
  1278. status = ZwQueryValueKey(
  1279. remoteBootHandle,
  1280. &unicodeName,
  1281. KeyValuePartialInformation,
  1282. keyValue,
  1283. sizeof(dataBuffer),
  1284. &length);
  1285. if ((NT_SUCCESS(status)) &&
  1286. (keyValue->Type == REG_BINARY) &&
  1287. (keyValue->DataLength == sizeof(NET_CARD_INFO)) &&
  1288. (memcmp(keyValue->Data, setupLoaderBlock->NetbootCardInfo, sizeof(NET_CARD_INFO)) == 0)) {
  1289. //
  1290. // Everything matched, so no need to do any setup.
  1291. //
  1292. status = STATUS_SUCCESS;
  1293. goto cleanup;
  1294. }
  1295. }
  1296. }
  1297. }
  1298. //
  1299. // We come through here if the saved registry data was missing or
  1300. // not correct. Write all the relevant values to the registry.
  1301. //
  1302. //
  1303. // Service name is in the loader block.
  1304. //
  1305. IopWstrToUnicodeString(&unicodeName, REGSTR_VALUE_SERVICE);
  1306. status = ZwSetValueKey(UniqueIdHandle,
  1307. &unicodeName,
  1308. TITLE_INDEX_VALUE,
  1309. REG_SZ,
  1310. setupLoaderBlock->NetbootCardServiceName,
  1311. (wcslen(setupLoaderBlock->NetbootCardServiceName) + 1) * sizeof(WCHAR)
  1312. );
  1313. if (!NT_SUCCESS(status)) {
  1314. goto cleanup;
  1315. }
  1316. //
  1317. // ClassGUID is the known net card GUID.
  1318. //
  1319. IopWstrToUnicodeString(&unicodeName, REGSTR_VALUE_CLASSGUID);
  1320. status = ZwSetValueKey(UniqueIdHandle,
  1321. &unicodeName,
  1322. TITLE_INDEX_VALUE,
  1323. REG_SZ,
  1324. L"{4D36E972-E325-11CE-BFC1-08002BE10318}",
  1325. sizeof(L"{4D36E972-E325-11CE-BFC1-08002BE10318}")
  1326. );
  1327. if (!NT_SUCCESS(status)) {
  1328. goto cleanup;
  1329. }
  1330. //
  1331. // Driver is the first net card.
  1332. //
  1333. IopWstrToUnicodeString(&unicodeName, REGSTR_VALUE_DRIVER);
  1334. status = ZwSetValueKey(UniqueIdHandle,
  1335. &unicodeName,
  1336. TITLE_INDEX_VALUE,
  1337. REG_SZ,
  1338. L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\0000",
  1339. sizeof(L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\0000")
  1340. );
  1341. if (!NT_SUCCESS(status)) {
  1342. goto cleanup;
  1343. }
  1344. //
  1345. // Open a handle for card parameters. We write RemoteBootCard plus
  1346. // whatever the BINL server told us to write.
  1347. //
  1348. status = IopOpenRegistryKeyEx(&tmpHandle,
  1349. NULL,
  1350. &CmRegistryMachineSystemCurrentControlSetControlClass,
  1351. KEY_ALL_ACCESS
  1352. );
  1353. if (!NT_SUCCESS(status)) {
  1354. goto cleanup;
  1355. }
  1356. IopWstrToUnicodeString(&unicodeName, L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\0000");
  1357. status = IopOpenRegistryKeyEx(&parametersHandle,
  1358. tmpHandle,
  1359. &unicodeName,
  1360. KEY_ALL_ACCESS
  1361. );
  1362. ZwClose(tmpHandle);
  1363. if (!NT_SUCCESS(status)) {
  1364. goto cleanup;
  1365. }
  1366. //
  1367. // We know that this is a different NIC, so remove all the old parameters.
  1368. //
  1369. keyValueBasic = (PKEY_VALUE_BASIC_INFORMATION)dataBuffer;
  1370. enumerateIndex = 0;
  1371. while (TRUE) {
  1372. RtlZeroMemory(dataBuffer, sizeof(dataBuffer));
  1373. status = ZwEnumerateValueKey(
  1374. parametersHandle,
  1375. enumerateIndex,
  1376. KeyValueBasicInformation,
  1377. keyValueBasic,
  1378. sizeof(dataBuffer),
  1379. &length
  1380. );
  1381. if (status == STATUS_NO_MORE_ENTRIES) {
  1382. status = STATUS_SUCCESS;
  1383. break;
  1384. }
  1385. if (!NT_SUCCESS(status)) {
  1386. goto cleanup;
  1387. }
  1388. //
  1389. // We don't delete "NetCfgInstanceID", it won't change and
  1390. // its presence signifies to the net class installer that
  1391. // this is a replacement not a clean install.
  1392. //
  1393. if (_wcsicmp(keyValueBasic->Name, L"NetCfgInstanceID") != 0) {
  1394. RtlInitUnicodeString(&keyName, keyValueBasic->Name);
  1395. status = ZwDeleteValueKey(
  1396. parametersHandle,
  1397. &keyName
  1398. );
  1399. if (!NT_SUCCESS(status)) {
  1400. goto cleanup;
  1401. }
  1402. } else {
  1403. enumerateIndex = 1; // leave NetCfgInstanceID at index 0
  1404. }
  1405. }
  1406. //
  1407. // Write a parameter called RemoteBootCard set to TRUE, this
  1408. // is primarily so NDIS can recognize this as such.
  1409. //
  1410. IopWstrToUnicodeString(&unicodeName, L"RemoteBootCard");
  1411. tmpValue = 1;
  1412. status = ZwSetValueKey(parametersHandle,
  1413. &unicodeName,
  1414. TITLE_INDEX_VALUE,
  1415. REG_DWORD,
  1416. &tmpValue,
  1417. sizeof(tmpValue)
  1418. );
  1419. if (!NT_SUCCESS(status)) {
  1420. goto cleanup;
  1421. }
  1422. //
  1423. // Store any other parameters sent from the server.
  1424. //
  1425. registryList = setupLoaderBlock->NetbootCardRegistry;
  1426. if (registryList != NULL) {
  1427. STRING aString;
  1428. UNICODE_STRING uString, uString2;
  1429. //
  1430. // The registry list is a series of name\0type\0value\0, with
  1431. // a final \0 at the end. It is in ANSI, not UNICODE.
  1432. //
  1433. // All values are stored under parametersHandle. Type is 1 for
  1434. // DWORD and 2 for SZ.
  1435. //
  1436. uString.Buffer = tempNameBuffer;
  1437. uString.MaximumLength = sizeof(tempNameBuffer);
  1438. while (*registryList != '\0') {
  1439. //
  1440. // First the name.
  1441. //
  1442. RtlInitString(&aString, registryList);
  1443. status = RtlAnsiStringToUnicodeString(&uString, &aString, FALSE);
  1444. if (!NT_SUCCESS(status)) {
  1445. goto cleanup;
  1446. }
  1447. //
  1448. // Now the type.
  1449. //
  1450. registryList += (strlen(registryList) + 1);
  1451. if (*registryList == '1') {
  1452. //
  1453. // A DWORD, parse it.
  1454. //
  1455. registryList += 2; // skip "1\0"
  1456. tmpValue = 0;
  1457. while (*registryList != '\0') {
  1458. tmpValue = (tmpValue * 10) + (*registryList - '0');
  1459. ++registryList;
  1460. }
  1461. status = ZwSetValueKey(parametersHandle,
  1462. &uString,
  1463. TITLE_INDEX_VALUE,
  1464. REG_DWORD,
  1465. &tmpValue,
  1466. sizeof(tmpValue)
  1467. );
  1468. if (!NT_SUCCESS(status)) {
  1469. goto cleanup;
  1470. }
  1471. registryList += (strlen(registryList) + 1);
  1472. } else if (*registryList == '2') {
  1473. //
  1474. // An SZ, convert to Unicode.
  1475. //
  1476. registryList += 2; // skip "2\0"
  1477. uString2.Buffer = tempValueBuffer;
  1478. uString2.MaximumLength = sizeof(tempValueBuffer);
  1479. RtlInitAnsiString(&aString, registryList);
  1480. status = RtlAnsiStringToUnicodeString(&uString2, &aString, FALSE);
  1481. if (!NT_SUCCESS(status)) {
  1482. goto cleanup;
  1483. }
  1484. status = ZwSetValueKey(parametersHandle,
  1485. &uString,
  1486. TITLE_INDEX_VALUE,
  1487. REG_SZ,
  1488. uString2.Buffer,
  1489. uString2.Length + sizeof(WCHAR)
  1490. );
  1491. if (!NT_SUCCESS(status)) {
  1492. goto cleanup;
  1493. }
  1494. registryList += (strlen(registryList) + 1);
  1495. } else {
  1496. //
  1497. // Not "1" or "2", so stop processing registryList.
  1498. //
  1499. break;
  1500. }
  1501. }
  1502. }
  1503. //
  1504. // Save the NET_CARD_INFO so we can check it next time.
  1505. //
  1506. IopWstrToUnicodeString(&unicodeName, L"NetCardInfo");
  1507. status = ZwSetValueKey(remoteBootHandle,
  1508. &unicodeName,
  1509. TITLE_INDEX_VALUE,
  1510. REG_BINARY,
  1511. setupLoaderBlock->NetbootCardInfo,
  1512. sizeof(NET_CARD_INFO)
  1513. );
  1514. if (!NT_SUCCESS(status)) {
  1515. goto cleanup;
  1516. }
  1517. //
  1518. // Save the hardware ID, driver name, and service name,
  1519. // so the loader can read those if the server is down
  1520. // on subsequent boots.
  1521. //
  1522. IopWstrToUnicodeString(&unicodeName, L"HardwareId");
  1523. status = ZwSetValueKey(remoteBootHandle,
  1524. &unicodeName,
  1525. TITLE_INDEX_VALUE,
  1526. REG_SZ,
  1527. setupLoaderBlock->NetbootCardHardwareId,
  1528. (wcslen(setupLoaderBlock->NetbootCardHardwareId) + 1) * sizeof(WCHAR)
  1529. );
  1530. if (!NT_SUCCESS(status)) {
  1531. goto cleanup;
  1532. }
  1533. IopWstrToUnicodeString(&unicodeName, L"DriverName");
  1534. status = ZwSetValueKey(remoteBootHandle,
  1535. &unicodeName,
  1536. TITLE_INDEX_VALUE,
  1537. REG_SZ,
  1538. setupLoaderBlock->NetbootCardDriverName,
  1539. (wcslen(setupLoaderBlock->NetbootCardDriverName) + 1) * sizeof(WCHAR)
  1540. );
  1541. if (!NT_SUCCESS(status)) {
  1542. goto cleanup;
  1543. }
  1544. IopWstrToUnicodeString(&unicodeName, L"ServiceName");
  1545. status = ZwSetValueKey(remoteBootHandle,
  1546. &unicodeName,
  1547. TITLE_INDEX_VALUE,
  1548. REG_SZ,
  1549. setupLoaderBlock->NetbootCardServiceName,
  1550. (wcslen(setupLoaderBlock->NetbootCardServiceName) + 1) * sizeof(WCHAR)
  1551. );
  1552. if (!NT_SUCCESS(status)) {
  1553. goto cleanup;
  1554. }
  1555. //
  1556. // Save the device instance, in case we need to ID the card later.
  1557. //
  1558. IopWstrToUnicodeString(&unicodeName, L"DeviceInstance");
  1559. status = ZwSetValueKey(remoteBootHandle,
  1560. &unicodeName,
  1561. TITLE_INDEX_VALUE,
  1562. REG_SZ,
  1563. UnicodeDeviceInstance->Buffer,
  1564. UnicodeDeviceInstance->Length + sizeof(WCHAR)
  1565. );
  1566. if (!NT_SUCCESS(status)) {
  1567. goto cleanup;
  1568. }
  1569. //
  1570. // Make sure we only pick one card to setup this way!
  1571. //
  1572. IopRemoteBootCardInitialized = TRUE;
  1573. cleanup:
  1574. if (instanceHandle != NULL) {
  1575. ZwClose(instanceHandle);
  1576. }
  1577. if (remoteBootHandle != NULL) {
  1578. ZwClose(remoteBootHandle);
  1579. }
  1580. if (parametersHandle != NULL) {
  1581. ZwClose(parametersHandle);
  1582. }
  1583. if (currentControlSetHandle != NULL) {
  1584. ZwClose(currentControlSetHandle);
  1585. }
  1586. return status;
  1587. }
  1588. NTSTATUS
  1589. IopWriteIpAddressToRegistry(
  1590. HANDLE handle,
  1591. PWCHAR regkey,
  1592. PUCHAR value
  1593. )
  1594. {
  1595. NTSTATUS status;
  1596. UNICODE_STRING string;
  1597. CHAR addressA[17];
  1598. WCHAR addressW[17];
  1599. STRING addressStringA;
  1600. UNICODE_STRING addressStringW;
  1601. RtlInitUnicodeString( &string, regkey );
  1602. RtlZeroMemory(addressW,sizeof(addressW));
  1603. //
  1604. // note that value is PUCHAR, therefore the largest
  1605. // each %d could expand to is 255, which means that our
  1606. // buffer cannot overflow.
  1607. //
  1608. sprintf(addressA, "%d.%d.%d.%d",
  1609. value[0],
  1610. value[1],
  1611. value[2],
  1612. value[3]);
  1613. RtlInitAnsiString(&addressStringA, addressA);
  1614. addressStringW.Buffer = addressW;
  1615. addressStringW.MaximumLength = sizeof(addressW);
  1616. status = RtlAnsiStringToUnicodeString(&addressStringW, &addressStringA, FALSE);
  1617. if ( !NT_SUCCESS(status) ) {
  1618. KdPrint(( "IopWriteIpAddressToRegistry: Unable to convert %ws value: %x\n", regkey, status ));
  1619. goto cleanup;
  1620. }
  1621. //
  1622. // we are setting a REG_MULTI_SZ, this has an extra NULL at the
  1623. // end of it. Our buffer has an extra character in it to account
  1624. // for this.
  1625. //
  1626. status = NtSetValueKey(
  1627. handle,
  1628. &string,
  1629. 0,
  1630. REG_MULTI_SZ,
  1631. addressW,
  1632. addressStringW.Length + sizeof(WCHAR)
  1633. );
  1634. if ( !NT_SUCCESS(status) ) {
  1635. KdPrint(( "IopWriteIpAddressToRegistry: Unable to set %ws value: %x\n", regkey, status ));
  1636. goto cleanup;
  1637. }
  1638. cleanup:
  1639. return status;
  1640. }
  1641. NTSTATUS
  1642. IopSetDefaultGateway(
  1643. IN ULONG GatewayAddress
  1644. )
  1645. /*++
  1646. Routine Description:
  1647. This function adds a default gateway entry from the router table.
  1648. Arguments:
  1649. GatewayAddress - Address of the default gateway.
  1650. Return Value:
  1651. Error Code.
  1652. --*/
  1653. {
  1654. NTSTATUS Status;
  1655. HANDLE Handle = NULL;
  1656. BYTE Context[CONTEXT_SIZE];
  1657. TDIObjectID ID;
  1658. DWORD Size;
  1659. IPSNMPInfo IPStats;
  1660. IPAddrEntry *AddrTable = NULL;
  1661. DWORD NumReturned;
  1662. DWORD Type;
  1663. DWORD i;
  1664. DWORD MatchIndex;
  1665. IPRouteEntry RouteEntry;
  1666. OBJECT_ATTRIBUTES objectAttributes;
  1667. UNICODE_STRING NameString;
  1668. IO_STATUS_BLOCK ioStatusBlock;
  1669. if (GatewayAddress == 0) {
  1670. return STATUS_SUCCESS;
  1671. }
  1672. RtlInitUnicodeString( &NameString, DD_TCP_DEVICE_NAME );
  1673. InitializeObjectAttributes(
  1674. &objectAttributes,
  1675. &NameString,
  1676. OBJ_CASE_INSENSITIVE,
  1677. NULL,
  1678. NULL
  1679. );
  1680. Status = NtCreateFile(
  1681. &Handle,
  1682. GENERIC_READ | GENERIC_WRITE,
  1683. &objectAttributes,
  1684. &ioStatusBlock,
  1685. NULL,
  1686. 0,
  1687. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1688. FILE_OPEN,
  1689. FILE_SYNCHRONOUS_IO_NONALERT,
  1690. NULL,
  1691. 0
  1692. );
  1693. if ( !NT_SUCCESS(Status) ) {
  1694. KdPrint(( "IopSetDefaultGateway: Unable to open TCPIP: %x\n", Status ));
  1695. return Status;
  1696. }
  1697. //
  1698. // Get the NetAddr info, to find an interface index for the gateway.
  1699. //
  1700. ID.toi_entity.tei_entity = CL_NL_ENTITY;
  1701. ID.toi_entity.tei_instance = 0;
  1702. ID.toi_class = INFO_CLASS_PROTOCOL;
  1703. ID.toi_type = INFO_TYPE_PROVIDER;
  1704. ID.toi_id = IP_MIB_STATS_ID;
  1705. Size = sizeof(IPStats);
  1706. memset(&IPStats, 0x0, Size);
  1707. memset(Context, 0x0, CONTEXT_SIZE);
  1708. Status = IopTCPQueryInformationEx(
  1709. Handle,
  1710. &ID,
  1711. &IPStats,
  1712. &Size,
  1713. Context);
  1714. if (!NT_SUCCESS(Status)) {
  1715. KdPrint(( "IopSetDefaultGateway: Unable to query TCPIP(1): %x\n", Status ));
  1716. goto Cleanup;
  1717. }
  1718. Size = IPStats.ipsi_numaddr * sizeof(IPAddrEntry);
  1719. AddrTable = ExAllocatePoolWithTag(PagedPool, Size, 'bRoI');
  1720. if (AddrTable == NULL) {
  1721. Status = STATUS_NO_MEMORY;
  1722. goto Cleanup;
  1723. }
  1724. ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  1725. memset(Context, 0x0, CONTEXT_SIZE);
  1726. Status = IopTCPQueryInformationEx(
  1727. Handle,
  1728. &ID,
  1729. AddrTable,
  1730. &Size,
  1731. Context);
  1732. if (!NT_SUCCESS(Status)) {
  1733. KdPrint(( "IopSetDefaultGateway: Unable to query TCPIP(2): %x\n", Status ));
  1734. goto Cleanup;
  1735. }
  1736. NumReturned = Size/sizeof(IPAddrEntry);
  1737. //
  1738. // We've got the address table. Loop through it. If we find an exact
  1739. // match for the gateway, then we're adding or deleting a direct route
  1740. // and we're done. Otherwise try to find a match on the subnet mask,
  1741. // and remember the first one we find.
  1742. //
  1743. Type = IRE_TYPE_INDIRECT;
  1744. for (i = 0, MatchIndex = 0xffff; i < NumReturned; i++) {
  1745. if( AddrTable[i].iae_addr == GatewayAddress ) {
  1746. //
  1747. // Found an exact match.
  1748. //
  1749. MatchIndex = i;
  1750. Type = IRE_TYPE_DIRECT;
  1751. break;
  1752. }
  1753. //
  1754. // The next hop is on the same subnet as this address. If
  1755. // we haven't already found a match, remember this one.
  1756. //
  1757. if ( (MatchIndex == 0xffff) &&
  1758. (AddrTable[i].iae_addr != 0) &&
  1759. (AddrTable[i].iae_mask != 0) &&
  1760. ((AddrTable[i].iae_addr & AddrTable[i].iae_mask) ==
  1761. (GatewayAddress & AddrTable[i].iae_mask)) ) {
  1762. MatchIndex = i;
  1763. }
  1764. }
  1765. //
  1766. // We've looked at all of the entries. See if we found a match.
  1767. //
  1768. if (MatchIndex == 0xffff) {
  1769. //
  1770. // Didn't find a match.
  1771. //
  1772. Status = STATUS_UNSUCCESSFUL;
  1773. KdPrint(( "IopSetDefaultGateway: Unable to find match for gateway\n" ));
  1774. goto Cleanup;
  1775. }
  1776. //
  1777. // We've found a match. Fill in the route entry, and call the
  1778. // Set API.
  1779. //
  1780. RouteEntry.ire_dest = DEFAULT_DEST;
  1781. RouteEntry.ire_index = AddrTable[MatchIndex].iae_index;
  1782. RouteEntry.ire_metric1 = DEFAULT_METRIC;
  1783. RouteEntry.ire_metric2 = (DWORD)(-1);
  1784. RouteEntry.ire_metric3 = (DWORD)(-1);
  1785. RouteEntry.ire_metric4 = (DWORD)(-1);
  1786. RouteEntry.ire_nexthop = GatewayAddress;
  1787. RouteEntry.ire_type = Type;
  1788. RouteEntry.ire_proto = IRE_PROTO_NETMGMT;
  1789. RouteEntry.ire_age = 0;
  1790. RouteEntry.ire_mask = DEFAULT_DEST_MASK;
  1791. RouteEntry.ire_metric5 = (DWORD)(-1);
  1792. RouteEntry.ire_context = 0;
  1793. Size = sizeof(RouteEntry);
  1794. ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  1795. Status = IopTCPSetInformationEx(
  1796. Handle,
  1797. &ID,
  1798. &RouteEntry,
  1799. Size );
  1800. if (!NT_SUCCESS(Status)) {
  1801. KdPrint(( "IopSetDefaultGateway: Unable to set default gateway: %x\n", Status ));
  1802. }
  1803. NtClose(Handle);
  1804. Handle = NULL;
  1805. Cleanup:
  1806. if (Handle != NULL) {
  1807. NtClose(Handle);
  1808. }
  1809. if( AddrTable != NULL ) {
  1810. ExFreePool( AddrTable );
  1811. }
  1812. return Status;
  1813. }
  1814. __inline long
  1815. htonl(long x)
  1816. {
  1817. return((((x) >> 24) & 0x000000FFL) |
  1818. (((x) >> 8) & 0x0000FF00L) |
  1819. (((x) << 8) & 0x00FF0000L) |
  1820. (((x) << 24) & 0xFF000000L));
  1821. }
  1822. NTSTATUS
  1823. IopCacheNetbiosNameForIpAddress(
  1824. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  1825. )
  1826. /*++
  1827. Routine Description:
  1828. This function takes an IP address, and submits it to NetBt for name resolution.
  1829. Arguments:
  1830. IpAddress - Address to resolve
  1831. Return Value:
  1832. Error Code.
  1833. --*/
  1834. {
  1835. NTSTATUS Status;
  1836. HANDLE Handle = NULL;
  1837. BYTE Context[CONTEXT_SIZE];
  1838. DWORD Size;
  1839. OBJECT_ATTRIBUTES objectAttributes;
  1840. UNICODE_STRING NameString;
  1841. IO_STATUS_BLOCK ioStatusBlock;
  1842. tREMOTE_CACHE cacheInfo;
  1843. PCHAR serverName;
  1844. PCHAR endOfServerName;
  1845. HANDLE EventHandle;
  1846. //
  1847. // Open NetBT.
  1848. //
  1849. RtlInitUnicodeString(
  1850. &NameString,
  1851. L"\\Device\\NetBT_Tcpip_{54C7D140-09EF-11D1-B25A-F5FE627ED95E}"
  1852. );
  1853. InitializeObjectAttributes(
  1854. &objectAttributes,
  1855. &NameString,
  1856. OBJ_CASE_INSENSITIVE,
  1857. NULL,
  1858. NULL
  1859. );
  1860. Status = NtCreateFile(
  1861. &Handle,
  1862. GENERIC_READ | GENERIC_WRITE,
  1863. &objectAttributes,
  1864. &ioStatusBlock,
  1865. NULL,
  1866. 0,
  1867. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1868. FILE_OPEN,
  1869. FILE_SYNCHRONOUS_IO_NONALERT,
  1870. NULL,
  1871. 0
  1872. );
  1873. if ( !NT_SUCCESS(Status) ) {
  1874. KdPrint(( "IopCacheNetbiosNameForIpAddress: Unable to open NETBT: %x\n", Status ));
  1875. return Status;
  1876. }
  1877. //
  1878. // Get the server's name.
  1879. //
  1880. // If this is a remote boot setup boot, NtBootPathName is of the
  1881. // form \<server>\<share>\setup\<install-directory>\<platform>.
  1882. // If this is a normal remote boot, NtBootPathName is of the form
  1883. // \<server>\<share>\images\<machine>\winnt.
  1884. //
  1885. // Thus in either case, we need to isolate the first element of the
  1886. // path.
  1887. //
  1888. serverName = LoaderBlock->NtBootPathName;
  1889. if ( *serverName == '\\' ) {
  1890. serverName++;
  1891. }
  1892. endOfServerName = strchr( serverName, '\\' );
  1893. if ( endOfServerName == NULL ) {
  1894. endOfServerName = strchr( serverName, '\0' );
  1895. }
  1896. //
  1897. // Fill in the tREMOTE_CACHE structure.
  1898. //
  1899. memset(&cacheInfo, 0x0, sizeof(cacheInfo));
  1900. memset(cacheInfo.name, ' ', NETBIOS_NAMESIZE);
  1901. ASSERT(NETBIOS_NAMESIZE >= (ULONG)(endOfServerName - serverName));
  1902. memcpy(
  1903. cacheInfo.name,
  1904. serverName,
  1905. min(
  1906. (ULONG)(endOfServerName - serverName),
  1907. NETBIOS_NAMESIZE));
  1908. cacheInfo.IpAddress = htonl(LoaderBlock->SetupLoaderBlock->ServerIpAddress);
  1909. cacheInfo.Ttl = MAXULONG;
  1910. //
  1911. // Submit the IOCTL.
  1912. //
  1913. Status = NtCreateEvent(
  1914. &EventHandle,
  1915. EVENT_ALL_ACCESS,
  1916. NULL,
  1917. SynchronizationEvent,
  1918. FALSE );
  1919. if ( !NT_SUCCESS(Status) ) {
  1920. KdPrint(( "IopCacheNetbiosNameForIpAddress: Unable to createevent: %x\n", Status ));
  1921. NtClose(Handle);
  1922. return(Status);
  1923. }
  1924. Status = NtDeviceIoControlFile(
  1925. Handle,
  1926. EventHandle,
  1927. NULL,
  1928. NULL,
  1929. &ioStatusBlock,
  1930. IOCTL_NETBT_ADD_TO_REMOTE_TABLE,
  1931. &cacheInfo,
  1932. sizeof(cacheInfo),
  1933. Context,
  1934. sizeof(Context)
  1935. );
  1936. if (Status == STATUS_PENDING) {
  1937. NtWaitForSingleObject(
  1938. EventHandle,
  1939. FALSE,
  1940. NULL);
  1941. Status = ioStatusBlock.Status;
  1942. }
  1943. if ( NT_SUCCESS(Status) ) {
  1944. Status = ioStatusBlock.Status;
  1945. }
  1946. if ( !NT_SUCCESS(Status) ) {
  1947. KdPrint(( "IopCacheNetbiosNameForIpAddress: Adapter status failed: %x\n", Status ));
  1948. }
  1949. NtClose(Handle);
  1950. NtClose(EventHandle);
  1951. return Status;
  1952. }
  1953. NTSTATUS
  1954. IopTCPQueryInformationEx(
  1955. IN HANDLE TCPHandle,
  1956. IN TDIObjectID FAR *ID,
  1957. OUT void FAR *Buffer,
  1958. IN OUT DWORD FAR *BufferSize,
  1959. IN OUT BYTE FAR *Context
  1960. )
  1961. /*++
  1962. Routine Description:
  1963. This routine provides the interface to the TDI QueryInformationEx
  1964. facility of the TCP/IP stack on NT. Someday, this facility will be
  1965. part of TDI.
  1966. Arguments:
  1967. TCPHandle - Open handle to the TCP driver
  1968. ID - The TDI Object ID to query
  1969. Buffer - Data buffer to contain the query results
  1970. BufferSize - Pointer to the size of the results buffer. Filled in
  1971. with the amount of results data on return.
  1972. Context - Context value for the query. Should be zeroed for a
  1973. new query. It will be filled with context
  1974. information for linked enumeration queries.
  1975. Return Value:
  1976. An NTSTATUS value.
  1977. --*/
  1978. {
  1979. TCP_REQUEST_QUERY_INFORMATION_EX queryBuffer;
  1980. DWORD queryBufferSize;
  1981. NTSTATUS status;
  1982. IO_STATUS_BLOCK ioStatusBlock;
  1983. HANDLE EventHandle = NULL;
  1984. if (TCPHandle == NULL) {
  1985. return(STATUS_INVALID_PARAMETER);
  1986. }
  1987. queryBufferSize = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
  1988. memcpy(&(queryBuffer.ID), ID, sizeof(TDIObjectID));
  1989. memcpy(&(queryBuffer.Context), Context, CONTEXT_SIZE);
  1990. status = NtCreateEvent(
  1991. &EventHandle,
  1992. EVENT_ALL_ACCESS,
  1993. NULL,
  1994. SynchronizationEvent,
  1995. FALSE );
  1996. if (!NT_SUCCESS(status)) {
  1997. return(status);
  1998. }
  1999. status = NtDeviceIoControlFile(
  2000. TCPHandle, // Driver handle
  2001. EventHandle, // Event
  2002. NULL, // APC Routine
  2003. NULL, // APC context
  2004. &ioStatusBlock, // Status block
  2005. IOCTL_TCP_QUERY_INFORMATION_EX, // Control code
  2006. &queryBuffer, // Input buffer
  2007. queryBufferSize, // Input buffer size
  2008. Buffer, // Output buffer
  2009. *BufferSize // Output buffer size
  2010. );
  2011. if (status == STATUS_PENDING) {
  2012. NtWaitForSingleObject(
  2013. EventHandle,
  2014. FALSE,
  2015. NULL);
  2016. status = ioStatusBlock.Status;
  2017. }
  2018. if ( NT_SUCCESS(status) ) {
  2019. status = ioStatusBlock.Status;
  2020. }
  2021. if (status == STATUS_SUCCESS) {
  2022. //
  2023. // Copy the return context to the caller's context buffer
  2024. //
  2025. memcpy(Context, &(queryBuffer.Context), CONTEXT_SIZE);
  2026. *BufferSize = (ULONG)ioStatusBlock.Information;
  2027. status = ioStatusBlock.Status;
  2028. } else {
  2029. *BufferSize = 0;
  2030. }
  2031. NtClose(EventHandle);
  2032. return(status);
  2033. }
  2034. NTSTATUS
  2035. IopTCPSetInformationEx(
  2036. IN HANDLE TCPHandle,
  2037. IN TDIObjectID FAR *ID,
  2038. IN void FAR *Buffer,
  2039. IN DWORD FAR BufferSize
  2040. )
  2041. /*++
  2042. Routine Description:
  2043. This routine provides the interface to the TDI SetInformationEx
  2044. facility of the TCP/IP stack on NT. Someday, this facility will be
  2045. part of TDI.
  2046. Arguments:
  2047. TCPHandle - Open handle to the TCP driver
  2048. ID - The TDI Object ID to set
  2049. Buffer - Data buffer containing the information to be set
  2050. BufferSize - The size of the set data buffer.
  2051. Return Value:
  2052. An NTSTATUS value.
  2053. --*/
  2054. {
  2055. PTCP_REQUEST_SET_INFORMATION_EX setBuffer;
  2056. NTSTATUS status;
  2057. IO_STATUS_BLOCK ioStatusBlock;
  2058. DWORD setBufferSize;
  2059. HANDLE EventHandle;
  2060. if (TCPHandle == NULL) {
  2061. return(STATUS_INVALID_PARAMETER);
  2062. }
  2063. setBufferSize = FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) + BufferSize;
  2064. setBuffer = ExAllocatePoolWithTag(PagedPool, setBufferSize, 'bRoI');
  2065. if (setBuffer == NULL) {
  2066. return(STATUS_INSUFFICIENT_RESOURCES);
  2067. }
  2068. setBuffer->BufferSize = BufferSize;
  2069. memcpy(&(setBuffer->ID), ID, sizeof(TDIObjectID));
  2070. memcpy(&(setBuffer->Buffer[0]), Buffer, BufferSize);
  2071. status = NtCreateEvent(
  2072. &EventHandle,
  2073. EVENT_ALL_ACCESS,
  2074. NULL,
  2075. SynchronizationEvent,
  2076. FALSE );
  2077. if (!NT_SUCCESS(status)) {
  2078. ExFreePool(setBuffer);
  2079. return(status);
  2080. }
  2081. status = NtDeviceIoControlFile(
  2082. TCPHandle, // Driver handle
  2083. EventHandle, // Event
  2084. NULL, // APC Routine
  2085. NULL, // APC context
  2086. &ioStatusBlock, // Status block
  2087. IOCTL_TCP_SET_INFORMATION_EX, // Control code
  2088. setBuffer, // Input buffer
  2089. setBufferSize, // Input buffer size
  2090. NULL, // Output buffer
  2091. 0 // Output buffer size
  2092. );
  2093. if (status == STATUS_PENDING) {
  2094. NtWaitForSingleObject(
  2095. EventHandle,
  2096. FALSE,
  2097. NULL);
  2098. status = ioStatusBlock.Status;
  2099. }
  2100. if ( NT_SUCCESS(status) ) {
  2101. status = ioStatusBlock.Status;
  2102. }
  2103. NtClose(EventHandle);
  2104. ExFreePool(setBuffer);
  2105. return(status);
  2106. }
  2107. #ifdef ALLOC_DATA_PRAGMA
  2108. #pragma const_seg()
  2109. #endif