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.

1298 lines
36 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. helper.c
  5. Abstract:
  6. Helper functions for the loader.
  7. Author:
  8. Adam Barr (adamba) Aug 29, 1997
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. adamba 08-29-97 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include <pxe_cmn.h>
  18. #include <pxe_api.h>
  19. #include <undi_api.h>
  20. #include <ntexapi.h>
  21. #ifdef EFI
  22. #define BINL_PORT 0x0FAB // 4011 (decimal) in little-endian
  23. #else
  24. #define BINL_PORT 0xAB0F // 4011 (decimal) in big-endian
  25. #endif
  26. //
  27. // This removes macro redefinitions which appear because we define __RPC_DOS__,
  28. // but rpc.h defines __RPC_WIN32__
  29. //
  30. #pragma warning(disable:4005)
  31. //
  32. // As of 12/17/98, SECURITY_DOS is *not* defined - adamba
  33. //
  34. #if defined(SECURITY_DOS)
  35. //
  36. // These appear because we defined SECURITY_DOS
  37. //
  38. #define __far
  39. #define __pascal
  40. #define __loadds
  41. #endif
  42. #include <security.h>
  43. #include <rpc.h>
  44. #include <spseal.h>
  45. #ifdef EFI
  46. #include "bldr.h"
  47. #include "efi.h"
  48. #include "efip.h"
  49. #include "bldria64.h"
  50. #include "extern.h"
  51. #endif
  52. #if defined(SECURITY_DOS)
  53. //
  54. // PSECURITY_STRING is not supposed to be used when SECURITY_DOS is
  55. // defined -- it should be a WCHAR*. Unfortunately ntlmsp.h breaks
  56. // this rule and even uses the SECURITY_STRING structure, which there
  57. // is really no equivalent for in 16-bit mode.
  58. //
  59. typedef SEC_WCHAR * SECURITY_STRING; // more-or-less the intention where it is used
  60. typedef SEC_WCHAR * PSECURITY_STRING;
  61. #endif
  62. #include <ntlmsp.h>
  63. extern ULONG TftpSecurityHandle;
  64. extern CtxtHandle TftpClientContextHandle;
  65. extern BOOLEAN TftpClientContextHandleValid;
  66. //
  67. // From conn.c.
  68. //
  69. ULONG
  70. ConnItoa (
  71. IN ULONG Value,
  72. OUT PUCHAR Buffer
  73. );
  74. #if defined(REMOTE_BOOT_SECURITY)
  75. ULONG
  76. ConnAtosign (
  77. IN PUCHAR Buffer,
  78. IN ULONG SignLength,
  79. OUT PUCHAR Sign
  80. );
  81. #endif // defined(REMOTE_BOOT_SECURITY)
  82. ULONG
  83. ConnSafeAtol (
  84. IN PUCHAR Buffer,
  85. IN PUCHAR BufferEnd
  86. );
  87. // for now, we pull the hack mac list and code so that we only support new ROMs
  88. #ifdef EFI
  89. #pragma pack(1)
  90. typedef struct {
  91. UINT16 VendorId;
  92. UINT16 DeviceId;
  93. UINT16 Command;
  94. UINT16 Status;
  95. UINT8 RevisionID;
  96. UINT8 ClassCode[3];
  97. UINT8 CacheLineSize;
  98. UINT8 LaytencyTimer;
  99. UINT8 HeaderType;
  100. UINT8 BIST;
  101. } PCI_DEVICE_INDEPENDENT_REGION;
  102. typedef struct {
  103. UINT32 Bar[6];
  104. UINT32 CISPtr;
  105. UINT16 SubsystemVendorID;
  106. UINT16 SubsystemID;
  107. UINT32 ExpansionRomBar;
  108. UINT32 Reserved[2];
  109. UINT8 InterruptLine;
  110. UINT8 InterruptPin;
  111. UINT8 MinGnt;
  112. UINT8 MaxLat;
  113. } PCI_DEVICE_HEADER_TYPE_REGION;
  114. typedef struct {
  115. PCI_DEVICE_INDEPENDENT_REGION Hdr;
  116. PCI_DEVICE_HEADER_TYPE_REGION Device;
  117. } PCI_TYPE00;
  118. NTSTATUS
  119. NetQueryCardInfo(
  120. IN OUT PNET_CARD_INFO CardInfo
  121. )
  122. /*++
  123. Routine Description:
  124. This routine queries the ROM for information about the card.
  125. Arguments:
  126. CardInfo - returns the structure defining the card.
  127. Return Value:
  128. STATUS_SUCCESS
  129. STATUS_UNSUCCESSFUL
  130. --*/
  131. {
  132. EFI_STATUS Status = EFI_UNSUPPORTED;
  133. EFI_DEVICE_PATH *DevicePath = NULL;
  134. EFI_DEVICE_PATH *OriginalRootDevicePath = NULL;
  135. EFI_DEVICE_PATH_ALIGNED DevicePathAligned;
  136. UINT16 BusNumber = 0;
  137. UINT8 DeviceNumber = 0;
  138. UINT8 FunctionNumber = 0;
  139. BOOLEAN FoundACPIDevice = FALSE;
  140. BOOLEAN FoundPCIDevice = FALSE;
  141. EFI_GUID DeviceIoProtocol = DEVICE_IO_PROTOCOL;
  142. EFI_HANDLE MyHandle;
  143. EFI_DEVICE_IO_INTERFACE *IoDev;
  144. RtlZeroMemory(CardInfo, sizeof(NET_CARD_INFO));
  145. //
  146. // Get the device path for the NIC that we're using for PXE.
  147. //
  148. FlipToPhysical();
  149. Status = EfiST->BootServices->HandleProtocol( PXEHandle,
  150. &EfiDevicePathProtocol,
  151. &DevicePath );
  152. FlipToVirtual();
  153. if( Status != EFI_SUCCESS ) {
  154. DbgPrint( "NetQueryCardInfo: HandleProtocol(1) failed (%x)\n", Status);
  155. return (ARC_STATUS)Status;
  156. }
  157. FlipToPhysical();
  158. EfiAlignDp( &DevicePathAligned,
  159. DevicePath,
  160. DevicePathNodeLength(DevicePath));
  161. FlipToVirtual();
  162. //
  163. // Save off this root DevicePath in case we need it later.
  164. //
  165. OriginalRootDevicePath = DevicePath;
  166. //
  167. // Now we need to read the PCI header information from the specific
  168. // card. To do that, we need to dig out the BusNumber, DeviceNumber and
  169. // FunctionNumber that help describe this PCI device.
  170. //
  171. //
  172. // AcpiDevicePath = (ACPI_HID_DEVICE_PATH *)&DevicePathAligned;
  173. // BusNumber = AcpiDevicePath->UID
  174. //
  175. // PciDevicePath = (PCI_DEVICE_PATH *)&DevicePathAligned;
  176. // DeviceNumber = PciDevicePath->Device
  177. // FunctionNumber = PciDevicePath->Function
  178. //
  179. FlipToPhysical();
  180. while( DevicePathAligned.DevPath.Type != END_DEVICE_PATH_TYPE ) {
  181. if( (DevicePathAligned.DevPath.Type == ACPI_DEVICE_PATH) &&
  182. (DevicePathAligned.DevPath.SubType == ACPI_DP) ) {
  183. //
  184. // We'll find the BusNumber here.
  185. //
  186. ACPI_HID_DEVICE_PATH *AcpiDevicePath;
  187. AcpiDevicePath = (ACPI_HID_DEVICE_PATH *)&DevicePathAligned;
  188. BusNumber = (UINT16)AcpiDevicePath->UID;
  189. FoundACPIDevice = TRUE;
  190. }
  191. if( (DevicePathAligned.DevPath.Type == HARDWARE_DEVICE_PATH) &&
  192. (DevicePathAligned.DevPath.SubType == HW_PCI_DP) ) {
  193. //
  194. // We'll find the BusNumber here.
  195. //
  196. PCI_DEVICE_PATH *PciDevicePath;
  197. PciDevicePath = (PCI_DEVICE_PATH *)&DevicePathAligned;
  198. DeviceNumber = PciDevicePath->Device;
  199. FunctionNumber = PciDevicePath->Function;
  200. FoundPCIDevice = TRUE;
  201. }
  202. //
  203. // Get the next structure in our packed array.
  204. //
  205. DevicePath = NextDevicePathNode( DevicePath );
  206. EfiAlignDp(&DevicePathAligned,
  207. DevicePath,
  208. DevicePathNodeLength(DevicePath));
  209. }
  210. FlipToVirtual();
  211. //
  212. // Derive the function pointer that will allow us to read from
  213. // PCI space.
  214. //
  215. DevicePath = OriginalRootDevicePath;
  216. FlipToPhysical();
  217. Status = EfiST->BootServices->LocateDevicePath( &DeviceIoProtocol,
  218. &DevicePath,
  219. &MyHandle );
  220. FlipToVirtual();
  221. if( Status != EFI_SUCCESS ) {
  222. DbgPrint( "NetQueryCardInfo: LocateDevicePath failed (%X)\n", Status);
  223. return (ARC_STATUS)Status;
  224. }
  225. FlipToPhysical();
  226. Status = EfiST->BootServices->HandleProtocol( MyHandle,
  227. &DeviceIoProtocol,
  228. (VOID*)&IoDev );
  229. FlipToVirtual();
  230. if( Status != EFI_SUCCESS ) {
  231. DbgPrint( "NetQueryCardInfo: HandleProtocol(2) failed (%X)\n", Status);
  232. return (ARC_STATUS)Status;
  233. }
  234. //
  235. // We've got the Bus, Device, and Function number for this device. Go read
  236. // his header (with the PCI-Read function that we just derived) and get
  237. // the information we're after.
  238. //
  239. if( FoundPCIDevice && FoundACPIDevice ) {
  240. UINT64 Address;
  241. PCI_TYPE00 Pci;
  242. DbgPrint( "NetQueryCardInfo: Found all the config info for the device.\n" );
  243. DbgPrint( " BusNumber: %d DeviceNumber: %d FunctionNumber: %d\n", BusNumber, DeviceNumber, FunctionNumber );
  244. //
  245. // Generate the address, then read the PCI header from the device.
  246. //
  247. Address = EFI_PCI_ADDRESS( BusNumber, DeviceNumber, FunctionNumber );
  248. RtlZeroMemory(&Pci, sizeof(PCI_TYPE00));
  249. FlipToPhysical();
  250. Status = IoDev->Pci.Read( IoDev,
  251. IO_UINT32,
  252. Address,
  253. sizeof(PCI_TYPE00) / sizeof(UINT32),
  254. &Pci );
  255. FlipToVirtual();
  256. if( Status != EFI_SUCCESS ) {
  257. DbgPrint( "NetQueryCardInfo: Pci.Read failed (%X)\n", Status);
  258. return (ARC_STATUS)Status;
  259. }
  260. //
  261. // It all worked. Copy the information from the device into
  262. // the CardInfo structure and exit.
  263. //
  264. CardInfo->NicType = 2; // He's PCI
  265. CardInfo->pci.Vendor_ID = Pci.Hdr.VendorId;
  266. CardInfo->pci.Dev_ID = Pci.Hdr.DeviceId;
  267. CardInfo->pci.Rev = Pci.Hdr.RevisionID;
  268. // SubSys_ID is actually ((SubsystemID << 16) | SubsystemVendorID)
  269. CardInfo->pci.Subsys_ID = Pci.Device.SubsystemID;
  270. CardInfo->pci.Subsys_ID = (CardInfo->pci.Subsys_ID << 16) | (Pci.Device.SubsystemVendorID);
  271. #if DBG
  272. DbgPrint( "\n" );
  273. DbgPrint( "NetQueryCardInfo: Pci.Hdr.VendorId %x\n", Pci.Hdr.VendorId );
  274. DbgPrint( " Pci.Hdr.DeviceId %x\n", Pci.Hdr.DeviceId );
  275. DbgPrint( " Pci.Hdr.Command %x\n", Pci.Hdr.Command );
  276. DbgPrint( " Pci.Hdr.Status %x\n", Pci.Hdr.Status );
  277. DbgPrint( " Pci.Hdr.RevisionID %x\n", Pci.Hdr.RevisionID );
  278. DbgPrint( " Pci.Hdr.HeaderType %x\n", Pci.Hdr.HeaderType );
  279. DbgPrint( " Pci.Hdr.BIST %x\n", Pci.Hdr.BIST );
  280. DbgPrint( " Pci.Device.SubsystemVendorID %x\n", Pci.Device.SubsystemVendorID );
  281. DbgPrint( " Pci.Device.SubsystemID %x\n", Pci.Device.SubsystemID );
  282. DbgPrint( "\n" );
  283. DbgPrint( "NetQueryCardInfo: CardInfo->NicType %x\n", CardInfo->NicType );
  284. DbgPrint( " CardInfo->pci.Vendor_ID %x\n", CardInfo->pci.Vendor_ID );
  285. DbgPrint( " CardInfo->pci.Dev_ID %x\n", CardInfo->pci.Dev_ID );
  286. DbgPrint( " CardInfo->pci.Rev %x\n", CardInfo->pci.Rev );
  287. DbgPrint( " CardInfo->pci.Subsys_ID %x\n", CardInfo->pci.Subsys_ID );
  288. DbgPrint( "\n" );
  289. #endif
  290. Status = STATUS_SUCCESS;
  291. } else {
  292. DbgPrint( "NetQueryCardInfo: Failed to find all the config info for the device.\n" );
  293. }
  294. return STATUS_SUCCESS;
  295. }
  296. #else
  297. NTSTATUS
  298. NetQueryCardInfo(
  299. IN OUT PNET_CARD_INFO CardInfo
  300. )
  301. /*++
  302. Routine Description:
  303. This routine queries the ROM for information about the card.
  304. Arguments:
  305. CardInfo - returns the structure defining the card.
  306. Return Value:
  307. STATUS_SUCCESS
  308. STATUS_UNSUCCESSFUL
  309. --*/
  310. {
  311. ULONG status;
  312. t_PXENV_UNDI_GET_NIC_TYPE nicType;
  313. RtlZeroMemory(CardInfo, sizeof(NET_CARD_INFO));
  314. status = RomGetNicType( &nicType );
  315. if ((status != PXENV_EXIT_SUCCESS) || (nicType.Status != PXENV_EXIT_SUCCESS)) {
  316. #if DBG
  317. DbgPrint( "RomGetNicType returned 0x%x, nicType.Status = 0x%x. Time to upgrade your netcard ROM\n",
  318. status, nicType.Status );
  319. #endif
  320. status = STATUS_UNSUCCESSFUL;
  321. } else {
  322. #if DBG
  323. if ( nicType.NicType == 2 ) {
  324. DbgPrint( "Vendor_ID: %04x, Dev_ID: %04x\n",
  325. nicType.pci_pnp_info.pci.Vendor_ID,
  326. nicType.pci_pnp_info.pci.Dev_ID );
  327. DbgPrint( "Base_Class: %02x, Sub_Class: %02x, Prog_Intf: %02x\n",
  328. nicType.pci_pnp_info.pci.Base_Class,
  329. nicType.pci_pnp_info.pci.Sub_Class,
  330. nicType.pci_pnp_info.pci.Prog_Intf );
  331. DbgPrint( "Rev: %02x, BusDevFunc: %04x, SubSystem: %04x\n",
  332. nicType.pci_pnp_info.pci.Rev,
  333. nicType.pci_pnp_info.pci.BusDevFunc,
  334. nicType.pci_pnp_info.pci.Subsys_ID );
  335. } else {
  336. DbgPrint( "NicType: 0x%x EISA_Dev_ID: %08x\n",
  337. nicType.NicType,
  338. nicType.pci_pnp_info.pnp.EISA_Dev_ID );
  339. DbgPrint( "Base_Class: %02x, Sub_Class: %02x, Prog_Intf: %02x\n",
  340. nicType.pci_pnp_info.pnp.Base_Class,
  341. nicType.pci_pnp_info.pnp.Sub_Class,
  342. nicType.pci_pnp_info.pnp.Prog_Intf );
  343. DbgPrint( "CardSelNum: %04x\n",
  344. nicType.pci_pnp_info.pnp.CardSelNum );
  345. }
  346. #endif
  347. //
  348. // The call worked, so copy the information.
  349. //
  350. CardInfo->NicType = nicType.NicType;
  351. if (nicType.NicType == 2) {
  352. CardInfo->pci.Vendor_ID = nicType.pci_pnp_info.pci.Vendor_ID;
  353. CardInfo->pci.Dev_ID = nicType.pci_pnp_info.pci.Dev_ID;
  354. CardInfo->pci.Base_Class = nicType.pci_pnp_info.pci.Base_Class;
  355. CardInfo->pci.Sub_Class = nicType.pci_pnp_info.pci.Sub_Class;
  356. CardInfo->pci.Prog_Intf = nicType.pci_pnp_info.pci.Prog_Intf;
  357. CardInfo->pci.Rev = nicType.pci_pnp_info.pci.Rev;
  358. CardInfo->pci.BusDevFunc = nicType.pci_pnp_info.pci.BusDevFunc;
  359. CardInfo->pci.Subsys_ID = nicType.pci_pnp_info.pci.Subsys_ID;
  360. status = STATUS_SUCCESS;
  361. } else {
  362. status = STATUS_UNSUCCESSFUL;
  363. }
  364. }
  365. return status;
  366. }
  367. #endif // EFI
  368. NTSTATUS
  369. UdpSendAndReceiveForNetQuery(
  370. IN PVOID SendBuffer,
  371. IN ULONG SendBufferLength,
  372. IN ULONG SendRemoteHost,
  373. IN USHORT SendRemotePort,
  374. IN ULONG SendRetryCount,
  375. IN PVOID ReceiveBuffer,
  376. IN ULONG ReceiveBufferLength,
  377. IN ULONG ReceiveTimeout,
  378. IN ULONG ReceiveSignatureCount,
  379. IN PCHAR ReceiveSignatures[]
  380. )
  381. {
  382. ULONG i, j;
  383. ULONG length;
  384. ULONG RemoteHost;
  385. USHORT RemotePort;
  386. //
  387. // Try sending the packet SendRetryCount times, until we receive
  388. // a response with the right signature, waiting ReceiveTimeout
  389. // each time.
  390. //
  391. for (i = 0; i < SendRetryCount; i++) {
  392. length = UdpSend(
  393. SendBuffer,
  394. SendBufferLength,
  395. SendRemoteHost,
  396. SendRemotePort);
  397. if ( length != SendBufferLength ) {
  398. DbgPrint("UdpSend only sent %d bytes, not %d\n", length, SendBufferLength);
  399. return STATUS_UNEXPECTED_NETWORK_ERROR;
  400. }
  401. ReReceive:
  402. //
  403. // NULL out the first 12 bytes in case we get shorter data.
  404. //
  405. memset(ReceiveBuffer, 0x0, 12);
  406. length = UdpReceive(
  407. ReceiveBuffer,
  408. ReceiveBufferLength,
  409. &RemoteHost,
  410. &RemotePort,
  411. ReceiveTimeout);
  412. if ( length == 0 ) {
  413. DPRINT( ERROR, ("UdpReceive timed out\n") );
  414. continue;
  415. }
  416. //
  417. // Make sure the signature is one of the ones we expect.
  418. //
  419. for (j = 0; j < ReceiveSignatureCount; j++) {
  420. if (memcmp(ReceiveBuffer, ReceiveSignatures[j], 4) == 0) {
  421. return STATUS_SUCCESS;
  422. }
  423. }
  424. DbgPrint("UdpReceive got wrong signature\n");
  425. // ISSUE NTRAID #60513: CLEAN THIS UP -- but the idea is not to UdpSend
  426. // again just because we got a bad signature. Still need to respect the
  427. // original ReceiveTimeout however!
  428. goto ReReceive;
  429. }
  430. //
  431. // We timed out.
  432. //
  433. return STATUS_IO_TIMEOUT;
  434. }
  435. #define NETCARD_REQUEST_RESPONSE_BUFFER_SIZE 4096
  436. UCHAR NetCardResponseBuffer[NETCARD_REQUEST_RESPONSE_BUFFER_SIZE];
  437. NTSTATUS
  438. NetQueryDriverInfo(
  439. IN PNET_CARD_INFO CardInfo,
  440. IN PCHAR SetupPath,
  441. IN PCHAR NtBootPathName,
  442. IN OUT PWCHAR HardwareId,
  443. IN ULONG HardwareIdLength,
  444. IN OUT PWCHAR DriverName,
  445. IN OUT PCHAR DriverNameAnsi OPTIONAL,
  446. IN ULONG DriverNameLength,
  447. IN OUT PWCHAR ServiceName,
  448. IN ULONG ServiceNameLength,
  449. OUT PCHAR * Registry,
  450. OUT ULONG * RegistryLength
  451. )
  452. /*++
  453. Routine Description:
  454. This routine does an exchange with the server to get information
  455. about the card described by CardInfo.
  456. Arguments:
  457. CardInfo - Information about the card.
  458. SetupPath - UNC path (with only a single leading backslash) to our setup directory
  459. NtBootPathName - UNC path (with only a single leading backslash) to our boot directory
  460. HardwareId - returns the hardware ID of the card.
  461. HardwareIdLength - the length (in bytes) of the passed-in HardwareId buffer.
  462. DriverName - returns the name of the driver.
  463. DriverNameAnsi - if present, returns the name of the driver in ANSI.
  464. DriverNameLength - the length (in bytes) of the passed-in DriverName buffer
  465. (it is assumed that DriverNameAnsi is at least half this length).
  466. ServiceName - returns the service key of the driver.
  467. ServiceNameLength - the length (in bytes) of the passed-in ServiceName buffer.
  468. Registry - if needed, allocates and returns extra registry parameters
  469. for the card.
  470. RegistryLength - the length of Registry.
  471. Return Value:
  472. STATUS_SUCCESS
  473. STATUS_BUFFER_OVERFLOW if either of the buffers are too small.
  474. STATUS_INSUFFICIENT_RESOURCES if we cannot allocate memory for Registry.
  475. STATUS_IO_TIMEOUT if we can't get a response from the server.
  476. --*/
  477. {
  478. NTSTATUS Status;
  479. USHORT localPort;
  480. PNETCARD_REQUEST_PACKET requestPacket;
  481. PCHAR ReceiveSignatures[2];
  482. PCHAR ReceiveBuffer;
  483. ULONG GuidLength;
  484. PUCHAR Guid;
  485. ULONG sendSize;
  486. PNETCARD_REQUEST_PACKET allocatedRequestPacket = NULL;
  487. //
  488. // Get the local UDP port.
  489. //
  490. localPort = UdpUnicastDestinationPort;
  491. //
  492. // Now construct the outgoing packet.
  493. //
  494. //
  495. // Don't allocate ReceiveBuffer. We're about to call UdpSend, and he's
  496. // going to want a physical address on ia64. If we just use a static
  497. // here, the virtual-physical mapping will be 1-to-1. This isn't a big
  498. // deal since the allocation is hardcoded to NETCARD_REQUEST_RESPONSE_BUFFER_SIZE
  499. // and is never freed anyway.
  500. //
  501. // ReceiveBuffer = BlAllocateHeap( NETCARD_REQUEST_RESPONSE_BUFFER_SIZE );
  502. //
  503. ReceiveBuffer = NetCardResponseBuffer;
  504. if (ReceiveBuffer == NULL) {
  505. return STATUS_BUFFER_OVERFLOW;
  506. }
  507. requestPacket = (PNETCARD_REQUEST_PACKET) ReceiveBuffer;
  508. RtlCopyMemory(requestPacket->Signature, NetcardRequestSignature, sizeof(requestPacket->Signature));
  509. requestPacket->Length = sizeof(NETCARD_REQUEST_PACKET) - FIELD_OFFSET(NETCARD_REQUEST_PACKET, Version);
  510. requestPacket->Version = OSCPKT_NETCARD_REQUEST_VERSION;
  511. #if defined(_ALPHA_)
  512. #if defined(_AXP64)
  513. requestPacket->Architecture = PROCESSOR_ARCHITECTURE_ALPHA64;
  514. #else
  515. requestPacket->Architecture = PROCESSOR_ARCHITECTURE_ALPHA;
  516. #endif
  517. #endif
  518. #if defined(_MIPS_)
  519. requestPacket->Architecture = PROCESSOR_ARCHITECTURE_MIPS;
  520. #endif
  521. #if defined(_PPC_)
  522. requestPacket->Architecture = PROCESSOR_ARCHITECTURE_PPC;
  523. #endif
  524. #if defined(_IA64_)
  525. requestPacket->Architecture = PROCESSOR_ARCHITECTURE_IA64;
  526. #endif
  527. #if defined(_X86_)
  528. requestPacket->Architecture = PROCESSOR_ARCHITECTURE_INTEL;
  529. #endif
  530. requestPacket->SetupDirectoryLength = SetupPath ? (strlen( SetupPath ) + 1) : 0;
  531. #if defined(REMOTE_BOOT)
  532. if (NtBootPathName != NULL) {
  533. ULONG bufferOffset;
  534. requestPacket->FileCheckAndCopy = (ULONG)TRUE;
  535. //
  536. // make it a fully qualified UNC by sticking on a leading slash and
  537. // appending the "\system32\drivers" to form the full drivers
  538. // directory path.
  539. //
  540. requestPacket->DriverDirectoryLength = sizeof( "\\\\System32\\Drivers" );
  541. requestPacket->DriverDirectoryLength += strlen( NtBootPathName );
  542. sendSize = sizeof(NETCARD_REQUEST_PACKET) +
  543. requestPacket->DriverDirectoryLength +
  544. requestPacket->SetupDirectoryLength;
  545. requestPacket->DriverDirectoryPath[0] = '\\';
  546. strcpy( &requestPacket->DriverDirectoryPath[1], NtBootPathName );
  547. strcat( requestPacket->DriverDirectoryPath, "\\SYSTEM32\\DRIVERS" );
  548. bufferOffset = strlen( requestPacket->DriverDirectoryPath ) + 1;
  549. if (requestPacket->SetupDirectoryLength) {
  550. requestPacket->DriverDirectoryPath[bufferOffset++] = '\\';
  551. strcpy( &requestPacket->DriverDirectoryPath[bufferOffset], SetupPath );
  552. }
  553. } else {
  554. requestPacket->FileCheckAndCopy = (ULONG)FALSE;
  555. requestPacket->DriverDirectoryLength = 0;
  556. #endif
  557. sendSize = sizeof(NETCARD_REQUEST_PACKET) + requestPacket->SetupDirectoryLength;
  558. if (requestPacket->SetupDirectoryLength) {
  559. requestPacket->SetupDirectoryPath[0] = '\\';
  560. strcpy( &requestPacket->SetupDirectoryPath[1], SetupPath );
  561. }
  562. #if defined(REMOTE_BOOT)
  563. }
  564. #endif
  565. GetGuid(&Guid, &GuidLength);
  566. if (GuidLength == sizeof(requestPacket->Guid)) {
  567. memcpy(requestPacket->Guid, Guid, GuidLength);
  568. }
  569. RtlCopyMemory(&requestPacket->CardInfo, CardInfo, sizeof(NET_CARD_INFO));
  570. ReceiveSignatures[0] = NetcardResponseSignature;
  571. ReceiveSignatures[1] = NetcardErrorSignature;
  572. Status = UdpSendAndReceiveForNetQuery(
  573. requestPacket,
  574. sendSize,
  575. NetServerIpAddress,
  576. BINL_PORT,
  577. 4, // retry count
  578. ReceiveBuffer,
  579. NETCARD_REQUEST_RESPONSE_BUFFER_SIZE,
  580. 60, // receive timeout... may have to parse INF files
  581. 2,
  582. ReceiveSignatures
  583. );
  584. if (Status == STATUS_SUCCESS) {
  585. PWCHAR stringInPacket;
  586. ULONG maxOffset;
  587. UNICODE_STRING uString;
  588. ULONG len;
  589. PNETCARD_RESPONSE_PACKET responsePacket;
  590. responsePacket = (PNETCARD_RESPONSE_PACKET)ReceiveBuffer;
  591. if (responsePacket->Status != STATUS_SUCCESS) {
  592. return responsePacket->Status;
  593. }
  594. if (responsePacket->Length < sizeof( NETCARD_RESPONSE_PACKET )) {
  595. return STATUS_UNSUCCESSFUL;
  596. }
  597. //
  598. // The exchange succeeded, so copy the results back.
  599. //
  600. maxOffset = NETCARD_REQUEST_RESPONSE_BUFFER_SIZE -
  601. sizeof( NETCARD_RESPONSE_PACKET );
  602. if (responsePacket->HardwareIdOffset < sizeof(NETCARD_RESPONSE_PACKET) ||
  603. responsePacket->HardwareIdOffset >= maxOffset ) {
  604. return STATUS_BUFFER_OVERFLOW;
  605. }
  606. //
  607. // pick up the hardwareId string. It's given to us as an offset
  608. // within the packet to a unicode null terminated string.
  609. //
  610. stringInPacket = (PWCHAR)(PCHAR)((PCHAR)responsePacket +
  611. responsePacket->HardwareIdOffset );
  612. RtlInitUnicodeString( &uString, stringInPacket );
  613. if (uString.Length + sizeof(WCHAR) > HardwareIdLength) {
  614. return STATUS_BUFFER_OVERFLOW;
  615. }
  616. RtlCopyMemory( HardwareId, uString.Buffer, uString.Length + sizeof(WCHAR));
  617. //
  618. // pick up the driverName string. It's given to us as an offset
  619. // within the packet to a unicode null terminated string.
  620. //
  621. stringInPacket = (PWCHAR)(PCHAR)((PCHAR)responsePacket +
  622. responsePacket->DriverNameOffset );
  623. RtlInitUnicodeString( &uString, stringInPacket );
  624. if (uString.Length + sizeof(WCHAR) > DriverNameLength) {
  625. return STATUS_BUFFER_OVERFLOW;
  626. }
  627. RtlCopyMemory( DriverName, uString.Buffer, uString.Length + sizeof(WCHAR));
  628. //
  629. // we convert this one into ansi if the caller requested
  630. //
  631. if (ARGUMENT_PRESENT(DriverNameAnsi)) {
  632. RtlUnicodeToMultiByteN( DriverNameAnsi,
  633. DriverNameLength,
  634. NULL,
  635. uString.Buffer,
  636. uString.Length + sizeof(WCHAR));
  637. }
  638. //
  639. // pick up the serviceName string. It's given to us as an offset
  640. // within the packet to a unicode null terminated string.
  641. //
  642. stringInPacket = (PWCHAR)(PCHAR)((PCHAR)responsePacket +
  643. responsePacket->ServiceNameOffset );
  644. RtlInitUnicodeString( &uString, stringInPacket );
  645. if (uString.Length + sizeof(WCHAR) > ServiceNameLength) {
  646. return STATUS_BUFFER_OVERFLOW;
  647. }
  648. RtlCopyMemory( ServiceName, uString.Buffer, uString.Length + sizeof(WCHAR));
  649. //
  650. // If any extra registry params were passed back, allocate/copy those.
  651. //
  652. *RegistryLength = responsePacket->RegistryLength;
  653. if (*RegistryLength) {
  654. *Registry = BlAllocateHeap(*RegistryLength);
  655. if (*Registry == NULL) {
  656. return STATUS_INSUFFICIENT_RESOURCES;
  657. }
  658. stringInPacket = (PWCHAR)(PCHAR)((PCHAR)responsePacket +
  659. responsePacket->RegistryOffset );
  660. RtlCopyMemory(*Registry, stringInPacket, *RegistryLength);
  661. } else {
  662. *Registry = NULL;
  663. }
  664. }
  665. return Status;
  666. }
  667. #if defined(REMOTE_BOOT)
  668. NTSTATUS
  669. UdpSendAndReceiveForIpsec(
  670. IN PVOID SendBuffer,
  671. IN ULONG SendBufferLength,
  672. IN ULONG SendRemoteHost,
  673. IN USHORT SendRemotePort,
  674. IN PVOID ReceiveBuffer,
  675. IN ULONG ReceiveBufferLength,
  676. IN ULONG ReceiveTimeout
  677. )
  678. {
  679. ULONG i, j;
  680. ULONG length;
  681. ULONG RemoteHost;
  682. USHORT RemotePort;
  683. length = UdpSend(
  684. SendBuffer,
  685. SendBufferLength,
  686. SendRemoteHost,
  687. SendRemotePort);
  688. if ( length != SendBufferLength ) {
  689. DbgPrint("UdpSend only sent %d bytes, not %d\n", length, SendBufferLength);
  690. return STATUS_UNEXPECTED_NETWORK_ERROR;
  691. }
  692. length = UdpReceive(
  693. ReceiveBuffer,
  694. ReceiveBufferLength,
  695. &RemoteHost,
  696. &RemotePort,
  697. ReceiveTimeout);
  698. if ( length == 0 ) {
  699. DPRINT( ERROR, ("UdpReceive timed out\n") );
  700. return STATUS_IO_TIMEOUT;
  701. }
  702. return STATUS_SUCCESS;
  703. }
  704. ULONG
  705. ConnItoa (
  706. IN ULONG Value,
  707. OUT PUCHAR Buffer
  708. );
  709. ULONG
  710. ConnSafeAtol (
  711. IN PUCHAR Buffer,
  712. IN PUCHAR BufferEnd
  713. );
  714. NTSTATUS
  715. NetPrepareIpsec(
  716. IN ULONG InboundSpi,
  717. OUT ULONG * SessionKey,
  718. OUT ULONG * OutboundSpi
  719. )
  720. /*++
  721. Routine Description:
  722. This routine does an exchange with the server to set up for a future
  723. IPSEC conversation. We pass him the SPI we will use for our inbound
  724. conversation (from the server to us). He replies with the the session
  725. key that he has generated and the outbound SPI he has gotten (for the
  726. conversation from us to him). We also return the IP address of the
  727. server in this call.
  728. Arguments:
  729. InboundSpi - The SPI for the conversation from the server to us. This
  730. is typically generated by the caller, and will later be passed to
  731. IPSEC in an IOCTL_IPSEC_SET_SPI.
  732. SessionKey - Returns the server-generated session key.
  733. OutboundSpi - The server will take the information we give him and
  734. call IOCTL_IPSEC_GET_SPI, this returns the SPI he is assigned for
  735. the conversation from us to the server.
  736. Return Value:
  737. STATUS_SUCCESS
  738. STATUS_BUFFER_OVERFLOW if either of the buffers are too small.
  739. STATUS_INSUFFICIENT_RESOURCES if we cannot allocate memory for Registry.
  740. STATUS_IO_TIMEOUT if we can't get a response from the server.
  741. --*/
  742. {
  743. NTSTATUS Status;
  744. USHORT localPort;
  745. CHAR SendBuffer[128];
  746. PCHAR SendBufferLoc;
  747. PCHAR ReceiveSignatures[2];
  748. CHAR ReceiveBuffer[512];
  749. CHAR SignBuffer[NTLMSSP_MESSAGE_SIGNATURE_SIZE];
  750. CHAR KeyBuffer[4];
  751. ULONG SendCount = 0;
  752. ULONG SecurityHandle;
  753. ULONG Nibble;
  754. PUCHAR CurLoc, Options;
  755. BOOLEAN SpiReceived, SecurityReceived, SignReceived, KeyReceived;
  756. SecBufferDesc SignMessage;
  757. SecBuffer SigBuffers[2];
  758. SECURITY_STATUS SecStatus;
  759. //
  760. // Get the local UDP port.
  761. //
  762. localPort = UdpUnicastDestinationPort;
  763. //
  764. // Loop until we get a valid response.
  765. //
  766. while (SendCount < 5) {
  767. //
  768. // Construct the outgoing TFTP packet. We increment the
  769. // sequence number by one each time. We have to make sure
  770. // that the response we receive matches our last sequence
  771. // numbet sent since the server may generate a new key each
  772. // time.
  773. //
  774. SendBuffer[0] = 0;
  775. SendBuffer[1] = 17;
  776. SendBuffer[2] = 0x00;
  777. SendBuffer[3] = (UCHAR)(SendCount + 1);
  778. SendBufferLoc = SendBuffer+4;
  779. strcpy(SendBufferLoc, "spi");
  780. SendBufferLoc += sizeof("spi");
  781. SendBufferLoc += ConnItoa(InboundSpi, SendBufferLoc);
  782. #if defined(REMOTE_BOOT_SECURITY)
  783. strcpy(SendBufferLoc, "security");
  784. SendBufferLoc += sizeof("security");
  785. SendBufferLoc += ConnItoa(TftpSecurityHandle, SendBufferLoc);
  786. #endif // defined(REMOTE_BOOT_SECURITY)
  787. memset(ReceiveBuffer, 0x0, sizeof(ReceiveBuffer));
  788. Status = UdpSendAndReceiveForIpsec(
  789. SendBuffer,
  790. (ULONG)(SendBufferLoc - SendBuffer),
  791. NetServerIpAddress,
  792. TFTP_PORT,
  793. ReceiveBuffer,
  794. sizeof(ReceiveBuffer),
  795. 3 // receive timeout
  796. );
  797. if (Status == STATUS_SUCCESS) {
  798. if ((ReceiveBuffer[1] == 17) &&
  799. (ReceiveBuffer[3] == (UCHAR)(SendCount+1))) {
  800. Options = ReceiveBuffer+4;
  801. SpiReceived = FALSE;
  802. SecurityReceived = FALSE;
  803. SignReceived = FALSE;
  804. KeyReceived = FALSE;
  805. while (*Options != '\0') {
  806. if (strcmp(Options, "spi") == 0) {
  807. Options += sizeof("spi");
  808. *OutboundSpi = ConnSafeAtol(Options, ReceiveBuffer+sizeof(ReceiveBuffer));
  809. if (*OutboundSpi != (ULONG)-1) {
  810. SpiReceived = TRUE;
  811. }
  812. Options += strlen(Options) + 1;
  813. } else if (strcmp(Options, "security") == 0) {
  814. Options += sizeof("security");
  815. SecurityHandle = ConnSafeAtol(Options, ReceiveBuffer + sizeof(ReceiveBuffer));
  816. if (SecurityHandle != (ULONG)-1) {
  817. SecurityReceived = TRUE;
  818. }
  819. Options += strlen(Options) + 1;
  820. } else if (strcmp(Options, "sign") == 0) {
  821. Options += sizeof("sign");
  822. Options += ConnAtosign(Options, sizeof(SignBuffer), SignBuffer);
  823. SignReceived = TRUE;
  824. } else if (strcmp(Options, "key") == 0) {
  825. Options += sizeof("key");
  826. Options += ConnAtosign(Options, sizeof(KeyBuffer), KeyBuffer);
  827. KeyReceived = TRUE;
  828. } else {
  829. //
  830. // Unknown option.
  831. //
  832. break;
  833. }
  834. }
  835. #if defined(REMOTE_BOOT_SECURITY)
  836. if (SpiReceived && SecurityReceived && SignReceived && KeyReceived) {
  837. if (SecurityHandle != TftpSecurityHandle) {
  838. DbgPrint("Got incorrect security handle in response\n");
  839. Status = STATUS_INVALID_HANDLE;
  840. } else {
  841. //
  842. // Decrypt the key using the sign.
  843. //
  844. SigBuffers[1].pvBuffer = SignBuffer;
  845. SigBuffers[1].cbBuffer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
  846. SigBuffers[1].BufferType = SECBUFFER_TOKEN;
  847. SigBuffers[0].pvBuffer = KeyBuffer;
  848. SigBuffers[0].cbBuffer = sizeof(KeyBuffer);
  849. SigBuffers[0].BufferType = SECBUFFER_DATA;
  850. SignMessage.pBuffers = SigBuffers;
  851. SignMessage.cBuffers = 2;
  852. SignMessage.ulVersion = 0;
  853. ASSERT (TftpClientContextHandleValid);
  854. SecStatus = UnsealMessage(
  855. &TftpClientContextHandle,
  856. &SignMessage,
  857. 0,
  858. 0 );
  859. if ( SecStatus != SEC_E_OK ) {
  860. DbgPrint("NetPrepareIpsec: UnsealMessage failed %x\n", SecStatus);
  861. Status = STATUS_UNEXPECTED_NETWORK_ERROR;
  862. } else {
  863. *SessionKey = *(PULONG)KeyBuffer;
  864. DbgPrint("NetPrepareIpsec: Send SPI %d, got key %d (%lx) and response %d\n",
  865. InboundSpi, *SessionKey, *SessionKey, *OutboundSpi);
  866. Status = STATUS_SUCCESS;
  867. break; // exit (SendCount < 5) loop
  868. }
  869. }
  870. } else {
  871. DbgPrint("Response had no SPI, security, sign, or key!\n");
  872. Status = STATUS_UNSUCCESSFUL;
  873. }
  874. #else // defined(REMOTE_BOOT_SECURITY)
  875. if (SpiReceived && KeyReceived) {
  876. // if (SendCount == 0) { DbgPrint("SKIPPING!!\n"); ++SendCount; continue; } // drop a frame to test retry
  877. *SessionKey = *(PULONG)KeyBuffer;
  878. DbgPrint("NetPrepareIpsec: Send SPI %d, got key %d (%lx) and response %d\n",
  879. InboundSpi, *SessionKey, *SessionKey, *OutboundSpi);
  880. Status = STATUS_SUCCESS;
  881. break; // exit (SendCount < 5) loop
  882. } else {
  883. DbgPrint("Response had no SPI or key!\n");
  884. Status = STATUS_UNSUCCESSFUL;
  885. }
  886. #endif // defined(REMOTE_BOOT_SECURITY)
  887. } else {
  888. DbgPrint("Got bogus response from IPSEC request!!\n");
  889. Status = STATUS_UNSUCCESSFUL;
  890. }
  891. }
  892. ++SendCount;
  893. }
  894. return Status;
  895. }
  896. #endif // defined(REMOTE_BOOT)
  897. #if defined(REMOTE_BOOT)
  898. NTSTATUS
  899. NetCopyHalAndKernel(
  900. IN PCHAR HalName,
  901. IN PCHAR Guid,
  902. IN ULONG GuidLength
  903. )
  904. /*++
  905. Routine Description:
  906. This routine takes a detected HAL name and this machine's GUID, passing them
  907. to the BINL server
  908. Arguments:
  909. HalName - The detected Hal.
  910. Guid - The Guid for this machine.
  911. GuidLength - Number of bytes in Guid.
  912. Return Value:
  913. Status - STATUS_SUCCESS if all goes well.
  914. --*/
  915. {
  916. NTSTATUS Status;
  917. USHORT localPort;
  918. HAL_REQUEST_PACKET requestPacket;
  919. HAL_RESPONSE_PACKET responsePacket;
  920. PCHAR ReceiveSignatures[1];
  921. //
  922. // Get the local UDP port.
  923. //
  924. localPort = UdpUnicastDestinationPort;
  925. //
  926. // Now construct the outgoing packet.
  927. //
  928. RtlCopyMemory(requestPacket.Signature, HalRequestSignature, sizeof(requestPacket.Signature));
  929. requestPacket.Length = sizeof(HAL_REQUEST_PACKET) - FIELD_OFFSET(HAL_REQUEST_PACKET, Guid);
  930. strcpy(requestPacket.HalName, HalName);
  931. memset(requestPacket.Guid, 0x0, sizeof(requestPacket.Guid));
  932. memcpy(requestPacket.Guid, Guid, GuidLength);
  933. requestPacket.GuidLength = GuidLength;
  934. ReceiveSignatures[0] = HalResponseSignature;
  935. Status = UdpSendAndReceiveForNetQuery(
  936. &requestPacket,
  937. sizeof(HAL_REQUEST_PACKET),
  938. NetServerIpAddress,
  939. BINL_PORT,
  940. 4, // retry count
  941. &responsePacket,
  942. sizeof(responsePacket),
  943. 15, // receive timeout
  944. 2,
  945. ReceiveSignatures
  946. );
  947. if (Status == STATUS_SUCCESS) {
  948. Status = responsePacket.Status;
  949. }
  950. return Status;
  951. }
  952. #endif // defined(REMOTE_BOOT)