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.

609 lines
15 KiB

  1. #include "su.h"
  2. #include "pxe_cmn.h"
  3. #include "pxe_api.h"
  4. #include "tftp_api.h"
  5. #include "udp_api.h"
  6. #include "dhcp.h"
  7. #include "pxe.h"
  8. #define htons( a ) ((((a) & 0xFF00) >> 8) |\
  9. (((a) & 0x00FF) << 8))
  10. //
  11. // packet - Work buffer used to hold DHCP ACK and BINL REPLY packets.
  12. // These packets will be read into this buffer using the
  13. // PXENV API service PXENV_GET_BINL_INFO.
  14. //
  15. BOOTPLAYER packet;
  16. //
  17. // PxenvApiCall() - see su.asm for details
  18. //
  19. extern UINT16
  20. PxenvApiCall(
  21. UINT16 service,
  22. void far *param
  23. );
  24. //
  25. // GetPacket()
  26. //
  27. // Description:
  28. // Get cached packet from PXENV API.
  29. //
  30. // Passed:
  31. // packet := Far pointer to packet buffer
  32. // packet_type := see pxe_api.h for PXENV_PACKET_TYPE_xxx #defines
  33. //
  34. // Returns:
  35. // -1 := Packet could not be transfered to buffer
  36. // size := Number of bytes transfered into packet buffer
  37. //
  38. // Warning:
  39. // No check is made to see if buffer is actually large enough to
  40. // hold the entire packet. The buffer should be of type BOOTPLAYER.
  41. //
  42. SHORT
  43. GetPacket(
  44. void far *packet,
  45. UINT16 packet_type
  46. )
  47. {
  48. t_PXENV_GET_BINL_INFO gbi;
  49. //
  50. // Check for invalid parameters
  51. //
  52. if (packet == NULL) {
  53. BlPrint("\nGetPacket() NULL pointers\n");
  54. return -1;
  55. }
  56. //
  57. // Request size of packet by sending a size of zero.
  58. //
  59. gbi.packet_type = packet_type;
  60. gbi.buffer_size = 0;
  61. if (PxenvApiCall(PXENV_GET_BINL_INFO, &gbi) != PXENV_EXIT_SUCCESS) {
  62. BlPrint("\nGetPacket() PXENV API FAILURE #1\n");
  63. return -1;
  64. }
  65. //
  66. // Transfer cached packet into buffer.
  67. //
  68. gbi.buffer_offset = FP_OFF(packet);
  69. gbi.buffer_segment = FP_SEG(packet);
  70. if (PxenvApiCall(PXENV_GET_BINL_INFO, &gbi) != PXENV_EXIT_SUCCESS) {
  71. BlPrint("\nGetPacket() PXENV API FAILURE #2\n");
  72. return -1;
  73. }
  74. return (SHORT)gbi.buffer_size;
  75. }
  76. //
  77. // pFindOption()
  78. //
  79. // Description:
  80. // Find the desired Option in an options string
  81. // internal routine to allow FindOption/FindVendorOption
  82. // to share code.
  83. //
  84. // Passed:
  85. // Option := Option to be found
  86. // options := options string
  87. // pLength := IN Length of options string (16bit max)
  88. // OUT Length of option. (8bit max)
  89. //
  90. // Returns:
  91. // pointer to option data; NULL if not present
  92. //
  93. UINT32 *
  94. pFindOption(
  95. UINT8 Option,
  96. UINT8 *options,
  97. UINT16 *pLength
  98. )
  99. {
  100. UINT8 *end;
  101. if (options == NULL || pLength == NULL) {
  102. return NULL;
  103. }
  104. end = options + *pLength;
  105. *pLength = 0;
  106. //
  107. // walk down the packet looking for the desired option
  108. // type. be sure to check that the option will not
  109. // walk off the end of a malformed packet.
  110. // use length to indicate whether a valid
  111. // option was found
  112. //
  113. while ((options < end) &&
  114. (*options != 0xFF)
  115. ) {
  116. //
  117. // step over option pads
  118. //
  119. if ( *options == DHCP_PAD ) {
  120. options++;
  121. }
  122. else {
  123. if ( end <= options + 2 ||
  124. end <= options + 2 + options[1] ) {
  125. //
  126. // invalid option. it walked past the end of the packet
  127. //
  128. break;
  129. }
  130. if ( *options == Option ) {
  131. //
  132. // found the option. break out of loop
  133. //
  134. *pLength = options[1];
  135. break;
  136. }
  137. else {
  138. options += 2 + options[1];
  139. }
  140. }
  141. }
  142. return (*pLength != 0) ? (UINT32 *)(options + 2) : NULL;
  143. }
  144. //
  145. // FindOption()
  146. //
  147. // Description:
  148. // Find the subnet mask option in a DHCP packet.
  149. //
  150. // Passed:
  151. // Packet := IN Pointer to DHCP packet.
  152. // PacketLength := IN Length of DHCP packet.
  153. // pLength := OUT Length of option.
  154. //
  155. // Returns:
  156. // pointer to option data; NULL if not present
  157. //
  158. UINT32 *
  159. FindOption(
  160. UINT8 Option,
  161. BOOTPLAYER *Packet,
  162. UINT16 PacketLength,
  163. UINT8 *pLength
  164. )
  165. {
  166. UINT32 *retOption;
  167. UINT16 length;
  168. //
  169. // Verify parameters
  170. //
  171. if ( *((ULONG *)Packet->vendor.v.magic) != VM_RFC1048 ) {
  172. return NULL;
  173. }
  174. length = PacketLength;
  175. retOption = pFindOption(Option,
  176. (UINT8 *)&Packet->vendor.v.flags,
  177. &length
  178. );
  179. if (pLength != NULL) {
  180. *pLength = (UINT8)length;
  181. }
  182. return retOption;
  183. }
  184. UCHAR *
  185. FindVendorOption(
  186. UINT8 Option,
  187. UINT8 VendorOption,
  188. BOOTPLAYER *Packet,
  189. UINT16 PacketLength,
  190. UINT8 * pLength
  191. )
  192. {
  193. UINT8 *start;
  194. UINT16 cb;
  195. UCHAR *retOption;
  196. if (pLength != NULL) {
  197. *pLength = 0;
  198. }
  199. start = (UINT8*)FindOption( Option, Packet, PacketLength, (UINT8*)&cb );
  200. if (start == NULL) {
  201. return NULL;
  202. }
  203. retOption = (UCHAR *)pFindOption( VendorOption, start, &cb );
  204. if (pLength) {
  205. *pLength = (UINT8)cb;
  206. }
  207. return retOption;
  208. }
  209. //
  210. // strlen()
  211. //
  212. // Description:
  213. // Works like std C.
  214. //
  215. int
  216. strlen(UCHAR *s1)
  217. {
  218. int n = 0;
  219. if (s1 != NULL)
  220. while (*s1++)
  221. ++n;
  222. return n;
  223. }
  224. //
  225. // strcpy()
  226. //
  227. // Description:
  228. // Works like std C.
  229. //
  230. UCHAR *
  231. strcpy(UCHAR *s1, UCHAR *s2)
  232. {
  233. UCHAR *s = s1;
  234. if (s1 != NULL && s2 != NULL)
  235. while ((*s1++ = *s2++) != 0)
  236. ;
  237. return s;
  238. }
  239. //
  240. // strncpy()
  241. //
  242. // Description:
  243. // Works like std C.
  244. //
  245. UCHAR *
  246. strncpy(UCHAR *s1, UCHAR *s2, int n)
  247. {
  248. UCHAR *s = s1;
  249. if (s1 != NULL && s2 != NULL && n > 0)
  250. while (n--)
  251. if ((*s1++ = *s2++) == 0)
  252. break;
  253. return s;
  254. }
  255. //
  256. // memset()
  257. //
  258. // Description:
  259. // Works like std C.
  260. //
  261. PUCHAR
  262. memset(
  263. PUCHAR Destination,
  264. UCHAR Value,
  265. int Length
  266. )
  267. {
  268. while (Length--) {
  269. *Destination++ = Value;
  270. }
  271. return Destination;
  272. }
  273. //
  274. // PxenvTftp()
  275. //
  276. // Description:
  277. // Try to transfer the protect-mode loader using information from
  278. // DHCP ACK and BINL REPLY packets.
  279. //
  280. // Passed:
  281. // DownloadAddr := Physical address, in client machine, to transfer to.
  282. // FileName := File name sent down in BINL REPLY packet.
  283. //
  284. BOOLEAN
  285. PxenvTftp(
  286. )
  287. {
  288. UINT16 status;
  289. UINT16 packetLength;
  290. t_PXENV_TFTP_READ_FILE tftp;
  291. int pathLength;
  292. UINT32 clientIp;
  293. UINT32 serverIp;
  294. UINT32 gatewayIp;
  295. UINT32 *optionPtr;
  296. UINT32 subnetMask;
  297. UCHAR *FileName;
  298. UCHAR cb;
  299. UCHAR *optionVendor;
  300. //
  301. // Get the DHCP ACK packet.
  302. //
  303. if ((packetLength = GetPacket(&packet, PXENV_PACKET_TYPE_DHCP_ACK)) == -1) {
  304. return TRUE;
  305. }
  306. //
  307. // Get client IP address, server IP address, default gateway IP address,
  308. // and subnet mask from the DHCP ACK packet.
  309. //
  310. clientIp = *(UINT32 *)packet.yip;
  311. serverIp = *(UINT32 *)packet.sip;
  312. //BlPrint("PxenvTftp: DHCP ACK yip = %lx, sip = %lx\n", *(UINT32 *)packet.yip, *(UINT32 *)packet.sip);
  313. optionPtr = FindOption( DHCP_ROUTER, &packet, packetLength, NULL );
  314. if ( optionPtr != NULL ) {
  315. //BlPrint("PxenvTftp: DHCP ACK router = %lx\n", *optionPtr);
  316. gatewayIp = *optionPtr;
  317. } else {
  318. //BlPrint("PxenvTftp: DHCP ACK gip = %lx\n", *(UINT32 *)packet.gip);
  319. gatewayIp = *(UINT32 *)packet.gip;
  320. }
  321. optionPtr = FindOption( DHCP_SUBNET, &packet, packetLength, NULL );
  322. if ( optionPtr != NULL ) {
  323. //BlPrint("PxenvTftp: DHCP ACK subnet = %lx\n", *optionPtr);
  324. subnetMask = *optionPtr;
  325. } else {
  326. //BlPrint("PxenvTftp: DHCP ACK subnet not specified\n");
  327. subnetMask = 0;
  328. }
  329. //
  330. // Get the BINL REPLY packet.
  331. //
  332. if ((packetLength = GetPacket(&packet, PXENV_PACKET_TYPE_BINL_REPLY)) == -1) {
  333. return TRUE;
  334. }
  335. //
  336. // Values for client IP address, server IP address, default gateway IP address,
  337. // and subnet mask that are present in the BINL REPLY packet override those
  338. // in the DHCP ACK packet.
  339. //
  340. if ( *(UINT32 *)packet.yip != 0 ) {
  341. clientIp = *(UINT32 *)packet.yip;
  342. }
  343. if ( *(UINT32 *)packet.sip != 0 ) {
  344. serverIp = *(UINT32 *)packet.sip;
  345. }
  346. //BlPrint("PxenvTftp: BINL REPLY yip = %lx, sip = %lx\n", *(UINT32 *)packet.yip, *(UINT32 *)packet.sip);
  347. optionPtr = FindOption( DHCP_ROUTER, &packet, packetLength, NULL );
  348. if ( optionPtr != NULL ) {
  349. //BlPrint("PxenvTftp: BINL REPLY router = %lx\n", *optionPtr);
  350. gatewayIp = *optionPtr;
  351. } else if ( *(UINT32 *)packet.gip != 0 ) {
  352. //BlPrint("PxenvTftp: BINL REPLY router = %lx\n", *(UINT32 *)packet.gip);
  353. gatewayIp = *(UINT32 *)packet.gip;
  354. }
  355. optionPtr = FindOption( DHCP_SUBNET, &packet, packetLength, NULL );
  356. if ( optionPtr != NULL ) {
  357. //BlPrint("PxenvTftp: BINL REPLY subnet = %lx\n", *optionPtr);
  358. subnetMask = *optionPtr;
  359. }
  360. //
  361. // Determine whether we need to send packets via the gateway.
  362. //
  363. //BlPrint("PxenvTftp: clientIp = %lx, serverIp = %lx, subnet = %lx\n", clientIp, serverIp, subnetMask);
  364. //BlPrint(" router = %lx\n", gatewayIp);
  365. if ( (clientIp & subnetMask) == (serverIp & subnetMask) ) {
  366. //BlPrint("PxenvTftp: subnets match. clearing router address\n");
  367. gatewayIp = 0;
  368. }
  369. //PxenvApiCall(-1, NULL);
  370. //
  371. // Now fill in the TFTP TRANSFER parameter structure
  372. //
  373. memset( (PUCHAR)&tftp, 0, sizeof( tftp ) );
  374. //
  375. // Find the name and path of the NTLDR that we are going to download.
  376. // This is specified by a DHCP Vendor option tag. If this tag
  377. // is missing we will default to NTLDR and the same path as
  378. // startrom.com.
  379. //
  380. FileName = (UCHAR*)FindOption( DHCP_LOADER_PATH, &packet, packetLength, &cb );
  381. if ( FileName == NULL ) {
  382. //
  383. // We could not find the DHCP_LOADER_PATH. We will use the default name of
  384. // <path>\NTLDR where the <path> is the same as that used
  385. // to download startrom.com
  386. //
  387. strncpy(tftp.FileName, packet.bootfile, sizeof(tftp.FileName) - sizeof("NTLDR"));
  388. tftp.FileName[sizeof(tftp.FileName) - 1] = '\0';
  389. pathLength = strlen(tftp.FileName);
  390. while (pathLength > 0) {
  391. --pathLength;
  392. if (tftp.FileName[pathLength] == '\\') {
  393. ++pathLength; // advance it past the '\'
  394. break;
  395. }
  396. }
  397. strcpy(tftp.FileName + pathLength, "NTLDR");
  398. } else {
  399. // We found the DHCP_LOADER_PATH option. We will use that
  400. // as is to download the loader, unless it is too large.
  401. // Note that since the DHCP_LOADER_PATH size might include a
  402. // null terminator, we need to check to make sure that it
  403. // just might fit
  404. if ((cb > sizeof(tftp.FileName)) ||
  405. ((cb == sizeof(tftp.FileName)) && (FileName[cb] != '\0'))) {
  406. //BlPrint("PxenvTftp: DHCP_LOADER_PATH is too large = %s\n", FileName);
  407. return TRUE;
  408. }
  409. strncpy(tftp.FileName, FileName, cb);
  410. tftp.FileName[sizeof(tftp.FileName) - 1] = '\0';
  411. }
  412. //
  413. // Loader will be transfered to 1MB region and must not be more
  414. // than to 2MB in length.
  415. //
  416. tftp.BufferSize = 0x200000L;
  417. tftp.BufferOffset = 0x100000L;
  418. //
  419. // Set the Server and gateway address
  420. //
  421. *((UINT32 *)tftp.ServerIPAddress) = serverIp;
  422. *((UINT32 *)tftp.GatewayIPAddress) = gatewayIp;
  423. //
  424. // Check whether we are going to use multicast download or not. The
  425. // multicast options are set in a DHCP option tag (DHCP_LOADER_MCAST_OPTIONS).
  426. // These are encapsulated options and work the same way as Vendor options.
  427. // If these are missing then unicast transfer will be used.
  428. //
  429. optionVendor = FindVendorOption( DHCP_LOADER_MCAST_OPTIONS, PXE_MTFTP_IP, &packet, packetLength, &cb );
  430. if ( optionVendor != NULL && cb == 4 ) {
  431. *(UINT32*)tftp.McastIPAddress = *(UINT32*)optionVendor;
  432. optionVendor = FindVendorOption( DHCP_LOADER_MCAST_OPTIONS, PXE_MTFTP_CPORT, &packet, packetLength, &cb );
  433. if (optionVendor == NULL || cb != 2) {
  434. return TRUE;
  435. }
  436. tftp.TFTPClntPort = htons( *(UINT16*)optionVendor );
  437. optionVendor = FindVendorOption( DHCP_LOADER_MCAST_OPTIONS, PXE_MTFTP_SPORT, &packet, packetLength, &cb );
  438. if (optionVendor == NULL || cb != 2) {
  439. return TRUE;
  440. }
  441. tftp.TFTPSrvPort = htons( *(UINT16*)optionVendor );
  442. optionVendor = FindVendorOption( DHCP_LOADER_MCAST_OPTIONS, PXE_MTFTP_TMOUT, &packet, packetLength, &cb );
  443. if (optionVendor == NULL || cb != 1) {
  444. return TRUE;
  445. }
  446. tftp.TFTPOpenTimeOut = *(UINT8*)optionVendor;
  447. optionVendor = FindVendorOption( DHCP_LOADER_MCAST_OPTIONS, PXE_MTFTP_DELAY, &packet, packetLength, &cb );
  448. if (optionVendor == NULL || cb != 1) {
  449. return TRUE;
  450. }
  451. tftp.TFTPReopenDelay = *(UINT8*)optionVendor;
  452. }
  453. #if DBG
  454. BlPrint("Downloading Loader:\n");
  455. BlPrint("FileName = %s\n", tftp.FileName );
  456. BlPrint("BufferSize = %lx\n", tftp.BufferSize );
  457. BlPrint("BufferOffset = %lx\n", tftp.BufferOffset );
  458. BlPrint("ServerIPAddress = %d.%d.%d.%d\n",
  459. tftp.ServerIPAddress[0],
  460. tftp.ServerIPAddress[1],
  461. tftp.ServerIPAddress[2],
  462. tftp.ServerIPAddress[3] );
  463. BlPrint("GatewayIPAddress = %d.%d.%d.%d\n",
  464. tftp.GatewayIPAddress[0],
  465. tftp.GatewayIPAddress[1],
  466. tftp.GatewayIPAddress[2],
  467. tftp.GatewayIPAddress[3] );
  468. BlPrint("McastIPAddress = %d.%d.%d.%d\n",
  469. tftp.McastIPAddress[0],
  470. tftp.McastIPAddress[1],
  471. tftp.McastIPAddress[2],
  472. tftp.McastIPAddress[3] );
  473. BlPrint("TFTPClntPort = %d\n", htons( tftp.TFTPClntPort ) );
  474. BlPrint("TFTPSrvPort = %d\n", htons( tftp.TFTPSrvPort ) );
  475. BlPrint("TFTPOpenTimeOut = %d\n", tftp.TFTPOpenTimeOut );
  476. BlPrint("TFTPReopenDelay = %d\n", tftp.TFTPReopenDelay );
  477. BlPrint("\n\nPress any key to start download...\n" );
  478. _asm {
  479. push ax
  480. mov ax, 0
  481. int 16h
  482. pop ax
  483. }
  484. #endif
  485. //
  486. // Transfer image from TFTP server
  487. //
  488. status = PxenvApiCall(PXENV_TFTP_READ_FILE, &tftp);
  489. if (status != PXENV_EXIT_SUCCESS) {
  490. return TRUE;
  491. }
  492. return FALSE;
  493. }
  494. /* EOF - mtftp.c */