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.

870 lines
25 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. net.c
  5. Abstract:
  6. This module implements the net boot file system used by the operating
  7. system loader.
  8. It only contains those functions which are firmware/BIOS dependent.
  9. Author:
  10. Chuck Lenzmeier (chuckl) 09-Jan-1997
  11. Revision History:
  12. --*/
  13. #include "bootlib.h"
  14. #include "stdio.h"
  15. #ifdef UINT16
  16. #undef UINT16
  17. #endif
  18. #ifdef INT16
  19. #undef INT16
  20. #endif
  21. #include <dhcp.h>
  22. #include <netfs.h>
  23. #include <pxe_cmn.h>
  24. #include <pxe_api.h>
  25. #include <udp_api.h>
  26. #include <tftp_api.h>
  27. #include "bootx86.h"
  28. #ifndef BOOL
  29. typedef int BOOL;
  30. #endif
  31. #ifndef FALSE
  32. #define FALSE 0
  33. #endif
  34. #ifndef TRUE
  35. #define TRUE 1
  36. #endif
  37. #ifndef BYTE
  38. typedef unsigned char BYTE;
  39. #endif
  40. #ifndef LPBYTE
  41. typedef BYTE *LPBYTE;
  42. #endif
  43. #define MAX_PATH 260
  44. //
  45. // Define global data.
  46. //
  47. CHAR NetBootPath[129];
  48. ULONG NetLocalIpAddress;
  49. ULONG NetLocalSubnetMask;
  50. ULONG NetServerIpAddress;
  51. ULONG NetGatewayIpAddress;
  52. UCHAR NetLocalHardwareAddress[16];
  53. UCHAR NetBootIniContents[1020 + 1]; // 4 * 255 = 1020 + 1
  54. UCHAR NetBootIniPath[256 + 1];
  55. USHORT NetMaxTranUnit = 0; // MTU
  56. USHORT NetHwAddrLen = 0; // actual length of hardware address
  57. USHORT NetHwType = 0; // Type of protocol at the hardware level from rfc1010
  58. UCHAR MyGuid[16];
  59. ULONG MyGuidLength = sizeof(MyGuid);
  60. BOOLEAN MyGuidValid = FALSE;
  61. ARC_STATUS
  62. FindDhcpOption(
  63. IN BOOTPLAYER * Packet,
  64. IN UCHAR Option,
  65. IN ULONG MaximumLength,
  66. OUT PUCHAR OptionData,
  67. OUT PULONG Length OPTIONAL,
  68. IN ULONG Instance OPTIONAL
  69. )
  70. /*++
  71. Routine Description:
  72. Searches a dhcp packet for a given option.
  73. Arguments:
  74. Packet - pointer to the dhcp packet. Caller is responsible for assuring
  75. that the packet is a valid dhcp packet.
  76. Option - the dhcp option we're searching for.
  77. MaximumLength - size in bytes of OptionData buffer.
  78. OptionData - buffer to receive the option.
  79. Length - if specified, receives the actual length of option copied.
  80. Instance - specifies which instance of the option you are searching for.
  81. If not specified (zero), then we just grab the first instance of the tag.
  82. Return Value:
  83. None.
  84. --*/
  85. {
  86. PUCHAR curOption;
  87. ULONG copyLength;
  88. ULONG i = 0;
  89. if (MaximumLength == 0) {
  90. return EINVAL;
  91. }
  92. RtlZeroMemory(OptionData, MaximumLength);
  93. //
  94. // Parse the DHCP options looking for a specific one.
  95. //
  96. curOption = &Packet->vendor.d[4]; // skip the magic cookie
  97. while ((curOption - (PUCHAR)Packet) < sizeof(BOOTPLAYER) &&
  98. *curOption != 0xff) {
  99. if (*curOption == DHCP_PAD) {
  100. //
  101. // just walk past any pad options
  102. // these will not have any length
  103. //
  104. curOption++;
  105. }
  106. else {
  107. if (*curOption == Option) {
  108. //
  109. // Found it, copy and leave.
  110. //
  111. if ( i == Instance ) {
  112. if (sizeof(BOOTPLAYER) <= curOption + 2 - (PUCHAR)Packet ||
  113. sizeof(BOOTPLAYER) <= curOption + 2 + curOption[1] - (PUCHAR)Packet ) {
  114. //
  115. // invalid option. it walked past the end of the packet
  116. //
  117. break;
  118. }
  119. if (curOption[1] > MaximumLength) {
  120. copyLength = MaximumLength;
  121. } else {
  122. copyLength = curOption[1];
  123. }
  124. RtlCopyMemory(OptionData,
  125. curOption+2,
  126. copyLength);
  127. if (ARGUMENT_PRESENT(Length)) {
  128. *Length = copyLength;
  129. }
  130. return ESUCCESS;
  131. }
  132. i++;
  133. }
  134. curOption = curOption + 2 + curOption[1];
  135. }
  136. }
  137. return EINVAL;
  138. }
  139. ARC_STATUS
  140. GetParametersFromRom (
  141. VOID
  142. )
  143. {
  144. SHORT status;
  145. t_PXENV_GET_BINL_INFO gbi;
  146. t_PXENV_UNDI_GET_INFORMATION info;
  147. BOOTPLAYER packet;
  148. ULONG temp;
  149. ULONG i;
  150. PCHAR p;
  151. NetLocalIpAddress = 0;
  152. NetGatewayIpAddress = 0;
  153. NetServerIpAddress = 0;
  154. NetLocalSubnetMask = 0;
  155. *NetBootPath = 0;
  156. RtlZeroMemory( NetBootIniContents, sizeof(NetBootIniContents) ) ;
  157. RtlZeroMemory( NetBootIniPath, sizeof(NetBootIniPath) ) ;
  158. //
  159. // Get client IP address, server IP address, default gateway IP address,
  160. // and subnet mask from the DHCP ACK packet.
  161. //
  162. RtlZeroMemory( &packet, sizeof(packet) ) ;
  163. gbi.packet_type = PXENV_PACKET_TYPE_DHCP_ACK;
  164. gbi.buffer_size = sizeof(packet);
  165. gbi.buffer_offset = (USHORT)((ULONG_PTR)&packet & 0x0f);
  166. gbi.buffer_segment = (USHORT)(((ULONG_PTR)&packet >> 4) & 0xffff);
  167. status = NETPC_ROM_SERVICES( PXENV_GET_BINL_INFO, &gbi );
  168. if ( status != PXENV_EXIT_SUCCESS ) {
  169. DPRINT( ERROR, ("PXENV_GET_BINL_INFO(1) failed with %x\n", status) );
  170. } else {
  171. NetLocalIpAddress = *(ULONG *)packet.yip;
  172. NetServerIpAddress = *(ULONG *)packet.sip;
  173. if (FindDhcpOption(&packet, DHCP_ROUTER, sizeof(temp), (PUCHAR)&temp, NULL, 0) == ESUCCESS) {
  174. NetGatewayIpAddress = temp;
  175. } else {
  176. NetGatewayIpAddress = *(ULONG *)packet.gip;
  177. }
  178. memcpy(NetLocalHardwareAddress, packet.caddr, 16);
  179. if (FindDhcpOption(&packet, DHCP_SUBNET, sizeof(temp), (PUCHAR)&temp, NULL, 0) == ESUCCESS) {
  180. NetLocalSubnetMask = temp;
  181. }
  182. }
  183. //
  184. // Values for client IP address, server IP address, default gateway IP address,
  185. // and subnet mask that are present in the BINL REPLY packet override those
  186. // in the DHCP ACK packet.
  187. //
  188. RtlZeroMemory( &packet, sizeof(packet) ) ;
  189. gbi.packet_type = PXENV_PACKET_TYPE_BINL_REPLY;
  190. gbi.buffer_size = sizeof(packet);
  191. gbi.buffer_offset = (USHORT)((ULONG_PTR)&packet & 0x0f);
  192. gbi.buffer_segment = (USHORT)(((ULONG_PTR)&packet >> 4) & 0xffff);
  193. status = NETPC_ROM_SERVICES( PXENV_GET_BINL_INFO, &gbi );
  194. if ( status != PXENV_EXIT_SUCCESS ) {
  195. DPRINT( ERROR, ("PXENV_GET_BINL_INFO(2) failed with %x\n", status) );
  196. return ENODEV;
  197. }
  198. if ( *(ULONG *)packet.yip != 0 ) {
  199. NetLocalIpAddress = *(ULONG *)packet.yip;
  200. }
  201. if ( *(ULONG *)packet.sip != 0 ) {
  202. NetServerIpAddress = *(ULONG *)packet.sip;
  203. }
  204. if (FindDhcpOption(&packet, DHCP_ROUTER, sizeof(temp), (PUCHAR)&temp, NULL, 0) == ESUCCESS) {
  205. NetGatewayIpAddress = temp;
  206. } else if ( *(ULONG *)packet.gip != 0 ) {
  207. NetGatewayIpAddress = *(ULONG *)packet.gip;
  208. }
  209. if (FindDhcpOption(&packet, DHCP_SUBNET, sizeof(temp), (PUCHAR)&temp, NULL, 0) == ESUCCESS) {
  210. NetLocalSubnetMask = temp;
  211. }
  212. DPRINT( ERROR, ("Client: %x, Subnet mask: %x; Server: %x; Gateway: %x\n",
  213. NetLocalIpAddress, NetLocalSubnetMask, NetServerIpAddress, NetGatewayIpAddress) );
  214. //
  215. // Find the path of the boot filename (the part before the actual name).
  216. //
  217. //
  218. // do the strncpy first. that way we know the string is null
  219. // terminated, and we are then allowed to use standard str
  220. // routines (like the strrchr below)
  221. //
  222. strncpy( NetBootPath, (PCHAR)packet.bootfile, sizeof(NetBootPath) );
  223. NetBootPath[sizeof(NetBootPath)-1] = '\0';
  224. p = strrchr(NetBootPath,'\\');
  225. if (p) {
  226. p += 1; // advance it past the '\'
  227. *p = '\0'; // terminate the path
  228. } else {
  229. NetBootPath[0] = '\0';
  230. }
  231. //
  232. // The BINL server could optionally specify two private DHCP option tags
  233. // that are used for processing boot.ini.
  234. //
  235. // DHCP_LOADER_BOOT_INI would contain the entire contents of boot.ini
  236. // and is limited to 1024 bytes. Note that each DHCP option tags is
  237. // to 255 bytes. Boot.ini contents can be broken into multiple instances
  238. // of the same tag. We support up to 4 instances = 1020 bytes.
  239. //
  240. for (i = 0; i < 4; i++) {
  241. if (FindDhcpOption( &packet,
  242. DHCP_LOADER_BOOT_INI,
  243. 255,
  244. &NetBootIniContents[i * 255],
  245. NULL,
  246. i) != ESUCCESS ) {
  247. break;
  248. }
  249. }
  250. //
  251. // DHCP_LOADER_BOOT_INI_PATH contains a path to a boot.ini file and is
  252. // ignored if DHCP_LOADER_BOOT_INI has been specified.
  253. //
  254. FindDhcpOption(&packet, DHCP_LOADER_BOOT_INI_PATH, sizeof(NetBootIniPath), NetBootIniPath, NULL, 0);
  255. //
  256. // Get UNDI information
  257. //
  258. RtlZeroMemory(&info, sizeof(info));
  259. status = NETPC_ROM_SERVICES( PXENV_UNDI_GET_INFORMATION, &info );
  260. if ((status != PXENV_EXIT_SUCCESS) || (info.Status != PXENV_EXIT_SUCCESS)) {
  261. DPRINT( ERROR, ("PXENV_UNDI_GET_INFORMATION failed with %x, status = %x\n", status, info.Status) );
  262. return ENODEV;
  263. }
  264. NetMaxTranUnit = info.MaxTranUnit;
  265. NetHwAddrLen = info.HwAddrLen;
  266. NetHwType = info.HwType;
  267. memcpy( NetLocalHardwareAddress, info.PermNodeAddress, ADDR_LEN );
  268. return ESUCCESS;
  269. }
  270. ARC_STATUS
  271. GetGuid(
  272. OUT PUCHAR *Guid,
  273. OUT PULONG GuidLength
  274. )
  275. /*++
  276. Routine Description:
  277. This routine returns the Guid of this machine.
  278. Arguments:
  279. Guid - Place to store pointer to the guid.
  280. GuidLength - Place to store the length in bytes of the guid.
  281. Return Value:
  282. ARC code indicating outcome.
  283. --*/
  284. {
  285. t_PXENV_GET_BINL_INFO gbi;
  286. BOOTPLAYER packet;
  287. SHORT romStatus;
  288. ARC_STATUS Status;
  289. UCHAR TmpBuffer[sizeof(MyGuid) + 1];
  290. if (!MyGuidValid) {
  291. RtlZeroMemory( &packet, sizeof(packet) ) ;
  292. gbi.packet_type = PXENV_PACKET_TYPE_BINL_REPLY;
  293. gbi.buffer_size = sizeof(packet);
  294. gbi.buffer_offset = (USHORT)((ULONG_PTR)&packet & 0x0f);
  295. gbi.buffer_segment = (USHORT)(((ULONG_PTR)&packet >> 4) & 0xffff);
  296. romStatus = NETPC_ROM_SERVICES( PXENV_GET_BINL_INFO, &gbi );
  297. if ( romStatus == PXENV_EXIT_SUCCESS ) {
  298. Status = FindDhcpOption(&packet,
  299. DHCP_CLIENT_GUID,
  300. sizeof(TmpBuffer),
  301. TmpBuffer,
  302. &MyGuidLength,
  303. 0);
  304. if (Status == ESUCCESS) {
  305. if (MyGuidLength > sizeof(MyGuid)) {
  306. //
  307. // use the end of the GUID if it's too large.
  308. //
  309. memcpy(MyGuid, TmpBuffer + (MyGuidLength - sizeof(MyGuid)), sizeof(MyGuid));
  310. MyGuidLength = sizeof(MyGuid);
  311. } else {
  312. memcpy(MyGuid, TmpBuffer, MyGuidLength);
  313. }
  314. *Guid = MyGuid;
  315. *GuidLength = MyGuidLength;
  316. MyGuidValid = TRUE;
  317. return ESUCCESS;
  318. }
  319. }
  320. //
  321. // Use the NIC hardware address as a GUID
  322. //
  323. memset(MyGuid, 0x0, sizeof(MyGuid));
  324. memcpy(MyGuid + sizeof(MyGuid) - sizeof(NetLocalHardwareAddress),
  325. NetLocalHardwareAddress,
  326. sizeof(NetLocalHardwareAddress)
  327. );
  328. MyGuidLength = sizeof(MyGuid);
  329. MyGuidValid = TRUE;
  330. }
  331. *Guid = MyGuid;
  332. *GuidLength = MyGuidLength;
  333. return ESUCCESS;
  334. }
  335. ULONG
  336. CalculateChecksum(
  337. IN PLONG Block,
  338. IN ULONG Length
  339. )
  340. /*++
  341. Routine Description:
  342. This routine calculates a simple two's-complement checksum of a block of
  343. memory. If the returned value is stored in the block (in a word that was
  344. zero during the calculation), then new checksum of the block will be zero.
  345. Arguments:
  346. Block - Address of a block of data. Must be 4-byte aligned.
  347. Length - Length of the block. Must be a multiple of 4.
  348. Return Value:
  349. ULONG - Two's complement additive checksum of the input block.
  350. --*/
  351. {
  352. LONG checksum = 0;
  353. ASSERT( ((ULONG_PTR)Block & 3) == 0 );
  354. ASSERT( (Length & 3) == 0 );
  355. for ( ; Length != 0; Length -= 4 ) {
  356. checksum += *Block;
  357. Block++;
  358. }
  359. return -checksum;
  360. }
  361. NTSTATUS
  362. NetSoftReboot(
  363. IN PUCHAR NextBootFile,
  364. IN ULONGLONG Param,
  365. IN PUCHAR RebootFile OPTIONAL,
  366. IN PUCHAR SifFile OPTIONAL,
  367. IN PUCHAR User OPTIONAL,
  368. IN PUCHAR Domain OPTIONAL,
  369. IN PUCHAR Password OPTIONAL,
  370. IN PUCHAR AdministratorPassword OPTIONAL
  371. )
  372. /*++
  373. Routine Description:
  374. This routine does a soft reboot by inserting a fake BINL packet into the ROM and
  375. then inserting the filename of the start of a TFTP command.
  376. Arguments:
  377. NextBootFile - Fully qualified path name of the file to download.
  378. Param - Reboot parameter to set.
  379. RebootFile - String identifying the file to reboot to when after the current reboot is done.
  380. SifFile - Optional SIF file to pass to the next loader.
  381. User/Domain/Password/AdministratorPassword - Optional credentials to pass to the next loader.
  382. Return Value:
  383. Should not return if successful.
  384. --*/
  385. {
  386. SHORT romStatus;
  387. NTSTATUS status = STATUS_SUCCESS;
  388. union {
  389. t_PXENV_UDP_CLOSE UdpClose;
  390. t_PXENV_TFTP_READ_FILE TftpReadFile;
  391. } command;
  392. t_PXENV_GET_BINL_INFO gbi;
  393. BOOTPLAYER * packet;
  394. PTFTP_RESTART_BLOCK restartBlock;
  395. PTFTP_RESTART_BLOCK_V1 restartBlockV1;
  396. DPRINT( TRACE, ("NetSoftReboot ( )\n") );
  397. ASSERT(NextBootFile != NULL);
  398. //
  399. // Store the reboot parameters in memory.
  400. //
  401. restartBlock = (PTFTP_RESTART_BLOCK)(0x7C00 + 0x8000 - sizeof(TFTP_RESTART_BLOCK));
  402. RtlZeroMemory(restartBlock, sizeof(TFTP_RESTART_BLOCK));
  403. BlSetHeadlessRestartBlock(restartBlock);
  404. if (AdministratorPassword) {
  405. RtlMoveMemory(restartBlock->AdministratorPassword,AdministratorPassword, OSC_ADMIN_PASSWORD_LEN);
  406. }
  407. restartBlockV1 = (PTFTP_RESTART_BLOCK_V1)(0x7C00 + 0x8000 - sizeof(TFTP_RESTART_BLOCK_V1));
  408. restartBlockV1->RebootParameter = Param;
  409. if (RebootFile != NULL) {
  410. strncpy(restartBlockV1->RebootFile, (PCHAR)RebootFile, sizeof(restartBlockV1->RebootFile));
  411. restartBlockV1->RebootFile[sizeof(restartBlockV1->RebootFile) - 1] = '\0';
  412. }
  413. if (SifFile != NULL) {
  414. strncpy(restartBlockV1->SifFile, (PCHAR)SifFile, sizeof(restartBlockV1->SifFile));
  415. restartBlockV1->SifFile[sizeof(restartBlockV1->SifFile) - 1] = '\0';
  416. }
  417. if (User != NULL) {
  418. strncpy(restartBlockV1->User, (PCHAR)User, sizeof(restartBlockV1->User));
  419. restartBlockV1->User[sizeof(restartBlockV1->User) - 1] = '\0';
  420. }
  421. if (Domain != NULL) {
  422. strncpy(restartBlockV1->Domain, (PCHAR)Domain, sizeof(restartBlockV1->Domain));
  423. restartBlockV1->Domain[sizeof(restartBlockV1->Domain) - 1] = '\0';
  424. }
  425. if (Password != NULL) {
  426. strncpy(restartBlockV1->Password, (PCHAR)Password, sizeof(restartBlockV1->Password));
  427. restartBlockV1->Password[sizeof(restartBlockV1->Password) - 1] = '\0';
  428. }
  429. //
  430. // Set the tag in the restart block and calculate and store the checksum.
  431. //
  432. restartBlockV1->Tag = 'rtsR';
  433. restartBlockV1->Checksum = CalculateChecksum((PLONG)(0x7C00 + 0x8000 - 128), 128);
  434. //
  435. // For all versions of RIS after NT5.0 we have a new datastructure which is
  436. // more adaptable for the future. For this section we have a different checksum,
  437. // do that now.
  438. //
  439. restartBlock->TftpRestartBlockVersion = TFTP_RESTART_BLOCK_VERSION;
  440. restartBlock->NewCheckSumLength = FIELD_OFFSET(TFTP_RESTART_BLOCK, RestartBlockV1);
  441. restartBlock->NewCheckSum = CalculateChecksum((PLONG)restartBlock,
  442. restartBlock->NewCheckSumLength);
  443. //
  444. // Modify the BINL reply that the ROM has stored so that
  445. // the file name looks like the one we are rebooting to
  446. // (this is so we can retrieve the path correctly after
  447. // reboot, so we know where to look for bootloader).
  448. //
  449. gbi.packet_type = PXENV_PACKET_TYPE_BINL_REPLY;
  450. gbi.buffer_size = 0;
  451. gbi.buffer_offset = 0;
  452. gbi.buffer_segment = 0;
  453. romStatus = NETPC_ROM_SERVICES( PXENV_GET_BINL_INFO, &gbi );
  454. if ( romStatus != PXENV_EXIT_SUCCESS ) {
  455. DPRINT( ERROR, ("PXENV_GET_BINL_INFO(1) failed with %x\n", romStatus) );
  456. return STATUS_UNSUCCESSFUL;
  457. }
  458. //
  459. // Now convert the segment/offset to a pointer and modify the
  460. // filename.
  461. //
  462. packet = (BOOTPLAYER *)UIntToPtr( ((gbi.buffer_segment << 4) + gbi.buffer_offset) );
  463. RtlZeroMemory(packet->bootfile, sizeof(packet->bootfile));
  464. strncpy((PCHAR)packet->bootfile, (PCHAR)NextBootFile, sizeof(packet->bootfile));
  465. packet->bootfile[sizeof(packet->bootfile)-1] = '\0';
  466. //
  467. // First tell the ROM to shut down its UDP layer.
  468. //
  469. RtlZeroMemory( &command, sizeof(command) );
  470. command.UdpClose.Status = 0;
  471. status = NETPC_ROM_SERVICES( PXENV_UDP_CLOSE, &command );
  472. if ( status != 0 ) {
  473. DPRINT( ERROR, ("NetSoftReboot: error %d from UDP_CLOSE\n", status) );
  474. }
  475. //
  476. // Now tell the ROM to reboot and do a TFTP read of the specified
  477. // file from the specifed server.
  478. //
  479. RtlZeroMemory( &command, sizeof(command) );
  480. command.TftpReadFile.BufferOffset = 0x7c00; // standard boot image location
  481. // 32K (max size allowed) less area for passing parameters
  482. command.TftpReadFile.BufferSize = 0x8000 - sizeof(TFTP_RESTART_BLOCK);
  483. *(ULONG *)command.TftpReadFile.ServerIPAddress = NetServerIpAddress;
  484. //
  485. // Determine whether we need to send via the gateway.
  486. //
  487. if ( (NetServerIpAddress & NetLocalSubnetMask) == (NetLocalIpAddress & NetLocalSubnetMask) ) {
  488. *(UINT32 *)command.TftpReadFile.GatewayIPAddress = 0;
  489. } else {
  490. *(UINT32 *)command.TftpReadFile.GatewayIPAddress = NetGatewayIpAddress;
  491. }
  492. strcpy((PCHAR)command.TftpReadFile.FileName, (PCHAR)NextBootFile);
  493. //
  494. // This should not return if it succeeds!
  495. //
  496. romStatus = NETPC_ROM_SERVICES( PXENV_RESTART_TFTP, &command );
  497. if ( (romStatus != 0) || (command.TftpReadFile.Status != 0) ) {
  498. DPRINT( ERROR, ("NetSoftReboot: Could not reboot to <%s>, %d/%d\n",
  499. NextBootFile, romStatus, command.TftpReadFile.Status) );
  500. status = STATUS_UNSUCCESSFUL;
  501. }
  502. return status;
  503. }
  504. VOID
  505. NetGetRebootParameters(
  506. OUT PULONGLONG Param OPTIONAL,
  507. OUT PUCHAR RebootFile OPTIONAL,
  508. OUT PUCHAR SifFile OPTIONAL,
  509. OUT PUCHAR User OPTIONAL,
  510. OUT PUCHAR Domain OPTIONAL,
  511. OUT PUCHAR Password OPTIONAL,
  512. OUT PUCHAR AdministratorPassword OPTIONAL,
  513. BOOLEAN ClearRestartBlock
  514. )
  515. /*++
  516. Routine Description:
  517. This routine reads the reboot parameters from the TFTP_RESTART_BLOCK
  518. that ends at physical address 0x7c00 + 0x8000
  519. and returns them. (then clearing the address)
  520. 0x7c00 is the base address for startrom.com
  521. 0x8000 is the largest startrom.com allowed.
  522. then we reserve some space at the end for parameters.
  523. Arguments:
  524. Param - Space for returning the value.
  525. RebootFile - Optional space for storing the file to reboot to when done here. (size >= char[128])
  526. SifFile - Optional space for storing a SIF file passed from whoever
  527. initiated the soft reboot.
  528. User/Domain/Password/AdministratorPassword - Optional space to store credentials passed across
  529. the soft reboot.
  530. ClearRestartBlock - If set to TRUE, it wipes out the memory here - should be done exactly once, at the
  531. last call to this function.
  532. Return Value:
  533. None.
  534. --*/
  535. {
  536. PTFTP_RESTART_BLOCK restartBlock;
  537. PTFTP_RESTART_BLOCK_V1 restartBlockV1;
  538. TFTP_RESTART_BLOCK nullRestartBlock;
  539. BOOLEAN restartBlockValid;
  540. restartBlock = (PTFTP_RESTART_BLOCK)(0x7C00 + 0x8000 - sizeof(TFTP_RESTART_BLOCK));
  541. restartBlockV1 = (PTFTP_RESTART_BLOCK_V1)(0x7C00 + 0x8000 - sizeof(TFTP_RESTART_BLOCK_V1));
  542. //
  543. // See if the block is valid. If it's not, we create a temporary empty
  544. // one so the copy logic below doesn't have to keep checking.
  545. //
  546. if ((restartBlockV1->Tag == 'rtsR') &&
  547. (CalculateChecksum((PLONG)(0x7C00 + 0x8000 - 128), 128) == 0)) {
  548. restartBlockValid = TRUE;
  549. } else {
  550. restartBlockValid = FALSE;
  551. RtlZeroMemory( &nullRestartBlock, sizeof(TFTP_RESTART_BLOCK) );
  552. restartBlock = &nullRestartBlock;
  553. }
  554. //
  555. // Copy out the parameters that were in the original TFTP_RESTART_BLOCK structure.
  556. // These shipped in Win2K.
  557. //
  558. // Unfortunetly we do not know the size of the parameters passed to us.
  559. // Assume they are no smaller than the fields in the restart block
  560. //
  561. if (Param != NULL) {
  562. *Param = restartBlockV1->RebootParameter;
  563. }
  564. if (RebootFile != NULL) {
  565. memcpy(RebootFile, restartBlockV1->RebootFile, sizeof(restartBlockV1->RebootFile));
  566. }
  567. if (SifFile != NULL) {
  568. memcpy(SifFile, restartBlockV1->SifFile, sizeof(restartBlockV1->SifFile));
  569. }
  570. if (User != NULL) {
  571. strncpy((PCHAR)User, restartBlockV1->User, sizeof(restartBlockV1->User));
  572. User[sizeof(restartBlockV1->User)-1] = '\0';
  573. }
  574. if (Domain != NULL) {
  575. strncpy((PCHAR)Domain, restartBlockV1->Domain, sizeof(restartBlockV1->Domain));
  576. Domain[sizeof(restartBlockV1->Domain)-1] = '\0';
  577. }
  578. if (Password != NULL) {
  579. strncpy((PCHAR)Password, restartBlockV1->Password, sizeof(restartBlockV1->Password));
  580. Password[sizeof(restartBlockV1->Password)-1] = '\0';
  581. }
  582. //
  583. // Now do a new check for all versions past Win2K
  584. //
  585. if (restartBlockValid) {
  586. ULONG RestartBlockChecksumPointer = 0;
  587. //
  588. // Figure out how much of the restart block needs to be checksumed.
  589. //
  590. RestartBlockChecksumPointer = (ULONG)restartBlockV1;
  591. RestartBlockChecksumPointer -= (restartBlock->NewCheckSumLength);
  592. RestartBlockChecksumPointer -= (sizeof(restartBlock->NewCheckSumLength));
  593. if ((restartBlock->NewCheckSumLength == 0) ||
  594. (CalculateChecksum((PLONG)(RestartBlockChecksumPointer), restartBlock->NewCheckSumLength) != 0)) {
  595. //
  596. // A pre-Win2K OsChooser has given us this block. Clear out all fields
  597. // that are post-Win2K and continue.
  598. //
  599. RtlZeroMemory(restartBlock, FIELD_OFFSET(TFTP_RESTART_BLOCK, RestartBlockV1));
  600. }
  601. }
  602. //
  603. // Now extract the parameters from the block.
  604. //
  605. if (restartBlock->TftpRestartBlockVersion == TFTP_RESTART_BLOCK_VERSION) {
  606. BlGetHeadlessRestartBlock(restartBlock, restartBlockValid);
  607. if (AdministratorPassword) {
  608. RtlMoveMemory(AdministratorPassword,restartBlock->AdministratorPassword, OSC_ADMIN_PASSWORD_LEN);
  609. }
  610. }
  611. if (restartBlockValid && ClearRestartBlock) {
  612. RtlZeroMemory(restartBlock, sizeof(TFTP_RESTART_BLOCK));
  613. }
  614. return;
  615. }
  616. ARC_STATUS
  617. NetFillNetworkLoaderBlock (
  618. PNETWORK_LOADER_BLOCK NetworkLoaderBlock
  619. )
  620. {
  621. SHORT status;
  622. t_PXENV_GET_BINL_INFO gbi;
  623. BOOTPLAYER packet;
  624. //
  625. // Get client IP address, server IP address, default gateway IP address,
  626. // and subnet mask from the DHCP ACK packet.
  627. //
  628. gbi.packet_type = PXENV_PACKET_TYPE_DHCP_ACK;
  629. gbi.buffer_size = sizeof(packet);
  630. gbi.buffer_offset = (USHORT)((ULONG_PTR)&packet & 0x0f);
  631. gbi.buffer_segment = (USHORT)(((ULONG_PTR)&packet >> 4) & 0xffff);
  632. status = NETPC_ROM_SERVICES( PXENV_GET_BINL_INFO, &gbi );
  633. if ( status != PXENV_EXIT_SUCCESS ) {
  634. DbgPrint("PXENV_GET_BINL_INFO(DHCPACK) failed with %x\n", status);
  635. return ENODEV;
  636. }
  637. NetworkLoaderBlock->DHCPServerACK = BlAllocateHeap(gbi.buffer_size);
  638. if (NetworkLoaderBlock->DHCPServerACK == NULL) {
  639. return ENOMEM;
  640. }
  641. memcpy( NetworkLoaderBlock->DHCPServerACK, &packet, gbi.buffer_size );
  642. NetworkLoaderBlock->DHCPServerACKLength = gbi.buffer_size;
  643. gbi.packet_type = PXENV_PACKET_TYPE_BINL_REPLY;
  644. gbi.buffer_size = sizeof(packet);
  645. gbi.buffer_offset = (USHORT)((ULONG_PTR)&packet & 0x0f);
  646. gbi.buffer_segment = (USHORT)(((ULONG_PTR)&packet >> 4) & 0xffff);
  647. status = NETPC_ROM_SERVICES( PXENV_GET_BINL_INFO, &gbi );
  648. if ( status != PXENV_EXIT_SUCCESS ) {
  649. DbgPrint("PXENV_GET_BINL_INFO(BINLREPLY) failed with %x\n", status);
  650. } else {
  651. NetworkLoaderBlock->BootServerReplyPacket = BlAllocateHeap(gbi.buffer_size);
  652. if (NetworkLoaderBlock->BootServerReplyPacket == NULL) {
  653. return ENOMEM;
  654. }
  655. memcpy( NetworkLoaderBlock->BootServerReplyPacket, &packet, gbi.buffer_size );
  656. NetworkLoaderBlock->BootServerReplyPacketLength = gbi.buffer_size;
  657. }
  658. return ESUCCESS;
  659. }