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.

555 lines
13 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. // FindOption()
  78. //
  79. // Description:
  80. // Find the subnet mask option in a DHCP packet.
  81. //
  82. // Passed:
  83. // Packet := IN Pointer to DHCP packet.
  84. // PacketLength := IN Length of DHCP packet.
  85. // pLength := OUT Length of option.
  86. //
  87. // Returns:
  88. // pointer to option data; NULL if not present
  89. //
  90. UINT32 *
  91. FindOption(
  92. UINT8 Option,
  93. BOOTPLAYER *Packet,
  94. UINT16 PacketLength,
  95. UINT8 * pLength
  96. )
  97. {
  98. UINT8 *options;
  99. UINT8 *end;
  100. //
  101. // Verify parameters
  102. //
  103. if (pLength != NULL) {
  104. *pLength = 0;
  105. }
  106. if ( *((ULONG *)Packet->vendor.v.magic) != VM_RFC1048 ) {
  107. return NULL;
  108. }
  109. end = (UINT8 *)Packet + PacketLength;
  110. for ( options = (UINT8 *)&Packet->vendor.v.flags;
  111. options < end; ) {
  112. if ( *options == Option ) {
  113. if (pLength != NULL) {
  114. *pLength = *(UINT8*)(options + 1);
  115. }
  116. return (UINT32 *)(options + 2);
  117. }
  118. if ( *options == 0xFF ) {
  119. return NULL;
  120. }
  121. if ( *options == DHCP_PAD ) {
  122. options++;
  123. } else {
  124. options += 2 + options[1];
  125. }
  126. }
  127. return NULL;
  128. }
  129. UCHAR *
  130. FindVendorOption(
  131. UINT8 Option,
  132. UINT8 VendorOption,
  133. BOOTPLAYER *Packet,
  134. UINT16 PacketLength,
  135. UINT8 * pLength
  136. )
  137. {
  138. UINT8 *start;
  139. UINT8 *options;
  140. UINT8 *end;
  141. UCHAR cb;
  142. if (pLength != NULL) {
  143. *pLength = 0;
  144. }
  145. start = (UINT8*)FindOption( Option, Packet, PacketLength, &cb );
  146. if (start == NULL) {
  147. return NULL;
  148. }
  149. end = (UINT8 *)start + cb;
  150. for ( options = start;
  151. options < end; ) {
  152. if ( *options == VendorOption ) {
  153. if (pLength != NULL) {
  154. *pLength = *(UINT8*)(options + 1);
  155. }
  156. return (UCHAR *)(options + 2);
  157. }
  158. if ( *options == 0xFF ) {
  159. return NULL;
  160. }
  161. if ( *options == DHCP_PAD ) {
  162. options++;
  163. } else {
  164. options += 2 + options[1];
  165. }
  166. }
  167. return NULL;
  168. }
  169. //
  170. // strlen()
  171. //
  172. // Description:
  173. // Works like std C.
  174. //
  175. int
  176. strlen(UCHAR *s1)
  177. {
  178. int n = 0;
  179. if (s1 != NULL)
  180. while (*s1++)
  181. ++n;
  182. return n;
  183. }
  184. //
  185. // strcpy()
  186. //
  187. // Description:
  188. // Works like std C.
  189. //
  190. UCHAR *
  191. strcpy(UCHAR *s1, UCHAR *s2)
  192. {
  193. UCHAR *s = s1;
  194. if (s1 != NULL && s2 != NULL)
  195. while ((*s1++ = *s2++) != 0)
  196. ;
  197. return s;
  198. }
  199. //
  200. // strncpy()
  201. //
  202. // Description:
  203. // Works like std C.
  204. //
  205. UCHAR *
  206. strncpy(UCHAR *s1, UCHAR *s2, int n)
  207. {
  208. UCHAR *s = s1;
  209. if (s1 != NULL && s2 != NULL && n > 0)
  210. while (n--)
  211. if ((*s1++ = *s2++) == 0)
  212. break;
  213. return s;
  214. }
  215. //
  216. // memset()
  217. //
  218. // Description:
  219. // Works like std C.
  220. //
  221. PUCHAR
  222. memset(
  223. PUCHAR Destination,
  224. UCHAR Value,
  225. int Length
  226. )
  227. {
  228. while (Length--) {
  229. *Destination++ = Value;
  230. }
  231. return Destination;
  232. }
  233. //
  234. // PxenvTftp()
  235. //
  236. // Description:
  237. // Try to transfer the protect-mode loader using information from
  238. // DHCP ACK and BINL REPLY packets.
  239. //
  240. // Passed:
  241. // DownloadAddr := Physical address, in client machine, to transfer to.
  242. // FileName := File name sent down in BINL REPLY packet.
  243. //
  244. BOOLEAN
  245. PxenvTftp(
  246. )
  247. {
  248. UINT16 status;
  249. UINT16 packetLength;
  250. t_PXENV_TFTP_READ_FILE tftp;
  251. int pathLength;
  252. UINT32 clientIp;
  253. UINT32 serverIp;
  254. UINT32 gatewayIp;
  255. UINT32 *optionPtr;
  256. UINT32 subnetMask;
  257. UCHAR *FileName;
  258. UCHAR cb;
  259. UCHAR *optionVendor;
  260. //
  261. // Get the DHCP ACK packet.
  262. //
  263. if ((packetLength = GetPacket(&packet, PXENV_PACKET_TYPE_DHCP_ACK)) == -1) {
  264. return TRUE;
  265. }
  266. //
  267. // Get client IP address, server IP address, default gateway IP address,
  268. // and subnet mask from the DHCP ACK packet.
  269. //
  270. clientIp = *(UINT32 *)packet.yip;
  271. serverIp = *(UINT32 *)packet.sip;
  272. //BlPrint("PxenvTftp: DHCP ACK yip = %lx, sip = %lx\n", *(UINT32 *)packet.yip, *(UINT32 *)packet.sip);
  273. optionPtr = FindOption( DHCP_ROUTER, &packet, packetLength, NULL );
  274. if ( optionPtr != NULL ) {
  275. //BlPrint("PxenvTftp: DHCP ACK router = %lx\n", *optionPtr);
  276. gatewayIp = *optionPtr;
  277. } else {
  278. //BlPrint("PxenvTftp: DHCP ACK gip = %lx\n", *(UINT32 *)packet.gip);
  279. gatewayIp = *(UINT32 *)packet.gip;
  280. }
  281. optionPtr = FindOption( DHCP_SUBNET, &packet, packetLength, NULL );
  282. if ( optionPtr != NULL ) {
  283. //BlPrint("PxenvTftp: DHCP ACK subnet = %lx\n", *optionPtr);
  284. subnetMask = *optionPtr;
  285. } else {
  286. //BlPrint("PxenvTftp: DHCP ACK subnet not specified\n");
  287. subnetMask = 0;
  288. }
  289. //
  290. // Get the BINL REPLY packet.
  291. //
  292. if ((packetLength = GetPacket(&packet, PXENV_PACKET_TYPE_BINL_REPLY)) == -1) {
  293. return TRUE;
  294. }
  295. //
  296. // Values for client IP address, server IP address, default gateway IP address,
  297. // and subnet mask that are present in the BINL REPLY packet override those
  298. // in the DHCP ACK packet.
  299. //
  300. if ( *(UINT32 *)packet.yip != 0 ) {
  301. clientIp = *(UINT32 *)packet.yip;
  302. }
  303. if ( *(UINT32 *)packet.sip != 0 ) {
  304. serverIp = *(UINT32 *)packet.sip;
  305. }
  306. //BlPrint("PxenvTftp: BINL REPLY yip = %lx, sip = %lx\n", *(UINT32 *)packet.yip, *(UINT32 *)packet.sip);
  307. optionPtr = FindOption( DHCP_ROUTER, &packet, packetLength, NULL );
  308. if ( optionPtr != NULL ) {
  309. //BlPrint("PxenvTftp: BINL REPLY router = %lx\n", *optionPtr);
  310. gatewayIp = *optionPtr;
  311. } else if ( *(UINT32 *)packet.gip != 0 ) {
  312. //BlPrint("PxenvTftp: BINL REPLY router = %lx\n", *(UINT32 *)packet.gip);
  313. gatewayIp = *(UINT32 *)packet.gip;
  314. }
  315. optionPtr = FindOption( DHCP_SUBNET, &packet, packetLength, NULL );
  316. if ( optionPtr != NULL ) {
  317. //BlPrint("PxenvTftp: BINL REPLY subnet = %lx\n", *optionPtr);
  318. subnetMask = *optionPtr;
  319. }
  320. //
  321. // Determine whether we need to send packets via the gateway.
  322. //
  323. //BlPrint("PxenvTftp: clientIp = %lx, serverIp = %lx, subnet = %lx\n", clientIp, serverIp, subnetMask);
  324. //BlPrint(" router = %lx\n", gatewayIp);
  325. if ( (clientIp & subnetMask) == (serverIp & subnetMask) ) {
  326. //BlPrint("PxenvTftp: subnets match. clearing router address\n");
  327. gatewayIp = 0;
  328. }
  329. //PxenvApiCall(-1, NULL);
  330. //
  331. // Now fill in the TFTP TRANSFER parameter structure
  332. //
  333. memset( (PUCHAR)&tftp, 0, sizeof( tftp ) );
  334. //
  335. // Find the name and path of the NTLDR that we are going to download.
  336. // This is specified by a DHCP Vendor option tag. If this tag
  337. // is missing we will default to NTLDR and the same path as
  338. // startrom.com.
  339. //
  340. FileName = (UCHAR*)FindOption( DHCP_LOADER_PATH, &packet, packetLength, &cb );
  341. if ( FileName == NULL || cb > 128 ) {
  342. //
  343. // We could not find the DHCP_LOADER_PATH or it was longer
  344. // than we expected. We will use the default name of
  345. // <path>\NTLDR where the <path> is the same as that used
  346. // to download startrom.com
  347. //
  348. pathLength = strlen(packet.bootfile);
  349. while (pathLength > 0) {
  350. --pathLength;
  351. if (packet.bootfile[pathLength] == '\\') {
  352. ++pathLength; // advance it past the '\'
  353. break;
  354. }
  355. }
  356. strncpy(tftp.FileName, packet.bootfile, pathLength);
  357. strcpy(tftp.FileName + pathLength, "NTLDR");
  358. } else {
  359. // We found the DHCP_LOADER_PATH option. We will use that
  360. // as is to download the loader
  361. strncpy(tftp.FileName, FileName, cb);
  362. }
  363. //
  364. // Loader will be transfered to 1MB region and must not be more
  365. // than to 2MB in length.
  366. //
  367. tftp.BufferSize = 0x200000L;
  368. tftp.BufferOffset = 0x100000L;
  369. //
  370. // Set the Server and gateway address
  371. //
  372. *((UINT32 *)tftp.ServerIPAddress) = serverIp;
  373. *((UINT32 *)tftp.GatewayIPAddress) = gatewayIp;
  374. //
  375. // Check whether we are going to use multicast download or not. The
  376. // multicast options are set in a DHCP option tag (DHCP_LOADER_MCAST_OPTIONS).
  377. // These are encapsulated options and work the same way as Vendor options.
  378. // If these are missing then unicast transfer will be used.
  379. //
  380. optionVendor = FindVendorOption( DHCP_LOADER_MCAST_OPTIONS, PXE_MTFTP_IP, &packet, packetLength, &cb );
  381. if ( optionVendor != NULL && cb == 4 ) {
  382. *(UINT32*)tftp.McastIPAddress = *(UINT32*)optionVendor;
  383. optionVendor = FindVendorOption( DHCP_LOADER_MCAST_OPTIONS, PXE_MTFTP_CPORT, &packet, packetLength, &cb );
  384. if (optionVendor == NULL || cb != 2) {
  385. return TRUE;
  386. }
  387. tftp.TFTPClntPort = htons( *(UINT16*)optionVendor );
  388. optionVendor = FindVendorOption( DHCP_LOADER_MCAST_OPTIONS, PXE_MTFTP_SPORT, &packet, packetLength, &cb );
  389. if (optionVendor == NULL || cb != 2) {
  390. return TRUE;
  391. }
  392. tftp.TFTPSrvPort = htons( *(UINT16*)optionVendor );
  393. optionVendor = FindVendorOption( DHCP_LOADER_MCAST_OPTIONS, PXE_MTFTP_TMOUT, &packet, packetLength, &cb );
  394. if (optionVendor == NULL || cb != 1) {
  395. return TRUE;
  396. }
  397. tftp.TFTPOpenTimeOut = *(UINT8*)optionVendor;
  398. optionVendor = FindVendorOption( DHCP_LOADER_MCAST_OPTIONS, PXE_MTFTP_DELAY, &packet, packetLength, &cb );
  399. if (optionVendor == NULL || cb != 1) {
  400. return TRUE;
  401. }
  402. tftp.TFTPReopenDelay = *(UINT8*)optionVendor;
  403. }
  404. #if DBG
  405. BlPrint("Downloading Loader:\n");
  406. BlPrint("FileName = %s\n", tftp.FileName );
  407. BlPrint("BufferSize = %lx\n", tftp.BufferSize );
  408. BlPrint("BufferOffset = %lx\n", tftp.BufferOffset );
  409. BlPrint("ServerIPAddress = %d.%d.%d.%d\n",
  410. tftp.ServerIPAddress[0],
  411. tftp.ServerIPAddress[1],
  412. tftp.ServerIPAddress[2],
  413. tftp.ServerIPAddress[3] );
  414. BlPrint("GatewayIPAddress = %d.%d.%d.%d\n",
  415. tftp.GatewayIPAddress[0],
  416. tftp.GatewayIPAddress[1],
  417. tftp.GatewayIPAddress[2],
  418. tftp.GatewayIPAddress[3] );
  419. BlPrint("McastIPAddress = %d.%d.%d.%d\n",
  420. tftp.McastIPAddress[0],
  421. tftp.McastIPAddress[1],
  422. tftp.McastIPAddress[2],
  423. tftp.McastIPAddress[3] );
  424. BlPrint("TFTPClntPort = %d\n", htons( tftp.TFTPClntPort ) );
  425. BlPrint("TFTPSrvPort = %d\n", htons( tftp.TFTPSrvPort ) );
  426. BlPrint("TFTPOpenTimeOut = %d\n", tftp.TFTPOpenTimeOut );
  427. BlPrint("TFTPReopenDelay = %d\n", tftp.TFTPReopenDelay );
  428. BlPrint("\n\nPress any key to start download...\n" );
  429. _asm {
  430. push ax
  431. mov ax, 0
  432. int 16h
  433. pop ax
  434. }
  435. #endif
  436. //
  437. // Transfer image from TFTP server
  438. //
  439. status = PxenvApiCall(PXENV_TFTP_READ_FILE, &tftp);
  440. if (status != PXENV_EXIT_SUCCESS) {
  441. return TRUE;
  442. }
  443. return FALSE;
  444. }
  445. /* EOF - mtftp.c */