PxeBcDhcp4.c 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757
  1. /** @file
  2. Functions implementation related with DHCPv4 for UefiPxeBc Driver.
  3. Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "PxeBcImpl.h"
  7. //
  8. // This is a map from the interested DHCP4 option tags' index to the tag value.
  9. //
  10. UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] = {
  11. DHCP4_TAG_BOOTFILE_LEN,
  12. DHCP4_TAG_VENDOR,
  13. DHCP4_TAG_OVERLOAD,
  14. DHCP4_TAG_MSG_TYPE,
  15. DHCP4_TAG_SERVER_ID,
  16. DHCP4_TAG_VENDOR_CLASS_ID,
  17. DHCP4_TAG_BOOTFILE
  18. };
  19. //
  20. // There are 4 times retries with the value of 4, 8, 16 and 32, refers to PXE2.1 spec.
  21. //
  22. UINT32 mPxeDhcpTimeout[4] = { 4, 8, 16, 32 };
  23. /**
  24. Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.
  25. @param[in] Buffer Pointer to the option buffer.
  26. @param[in] Length Length of the option buffer.
  27. @param[in] OptTag Tag of the required option.
  28. @retval NULL Failed to find the required option.
  29. @retval Others The position of the required option.
  30. **/
  31. EFI_DHCP4_PACKET_OPTION *
  32. PxeBcParseDhcp4Options (
  33. IN UINT8 *Buffer,
  34. IN UINT32 Length,
  35. IN UINT8 OptTag
  36. )
  37. {
  38. EFI_DHCP4_PACKET_OPTION *Option;
  39. UINT32 Offset;
  40. Option = (EFI_DHCP4_PACKET_OPTION *)Buffer;
  41. Offset = 0;
  42. while (Offset < Length && Option->OpCode != DHCP4_TAG_EOP) {
  43. if (Option->OpCode == OptTag) {
  44. //
  45. // Found the required option.
  46. //
  47. return Option;
  48. }
  49. //
  50. // Skip the current option to the next.
  51. //
  52. if (Option->OpCode == DHCP4_TAG_PAD) {
  53. Offset++;
  54. } else {
  55. Offset += Option->Length + 2;
  56. }
  57. Option = (EFI_DHCP4_PACKET_OPTION *)(Buffer + Offset);
  58. }
  59. return NULL;
  60. }
  61. /**
  62. Parse the PXE vendor options and extract the information from them.
  63. @param[in] Dhcp4Option Pointer to vendor options in buffer.
  64. @param[in] VendorOption Pointer to structure to store information in vendor options.
  65. **/
  66. VOID
  67. PxeBcParseVendorOptions (
  68. IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option,
  69. IN PXEBC_VENDOR_OPTION *VendorOption
  70. )
  71. {
  72. UINT32 *BitMap;
  73. UINT8 VendorOptionLen;
  74. EFI_DHCP4_PACKET_OPTION *PxeOption;
  75. UINT8 Offset;
  76. BitMap = VendorOption->BitMap;
  77. VendorOptionLen = Dhcp4Option->Length;
  78. PxeOption = (EFI_DHCP4_PACKET_OPTION *)&Dhcp4Option->Data[0];
  79. Offset = 0;
  80. ASSERT (PxeOption != NULL);
  81. while ((Offset < VendorOptionLen) && (PxeOption->OpCode != DHCP4_TAG_EOP)) {
  82. //
  83. // Parse all the interesting PXE vendor options one by one.
  84. //
  85. switch (PxeOption->OpCode) {
  86. case PXEBC_VENDOR_TAG_MTFTP_IP:
  87. CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
  88. break;
  89. case PXEBC_VENDOR_TAG_MTFTP_CPORT:
  90. CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));
  91. break;
  92. case PXEBC_VENDOR_TAG_MTFTP_SPORT:
  93. CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));
  94. break;
  95. case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:
  96. VendorOption->MtftpTimeout = *PxeOption->Data;
  97. break;
  98. case PXEBC_VENDOR_TAG_MTFTP_DELAY:
  99. VendorOption->MtftpDelay = *PxeOption->Data;
  100. break;
  101. case PXEBC_VENDOR_TAG_DISCOVER_CTRL:
  102. VendorOption->DiscoverCtrl = *PxeOption->Data;
  103. break;
  104. case PXEBC_VENDOR_TAG_DISCOVER_MCAST:
  105. CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
  106. break;
  107. case PXEBC_VENDOR_TAG_BOOT_SERVERS:
  108. VendorOption->BootSvrLen = PxeOption->Length;
  109. VendorOption->BootSvr = (PXEBC_BOOT_SVR_ENTRY *)PxeOption->Data;
  110. break;
  111. case PXEBC_VENDOR_TAG_BOOT_MENU:
  112. VendorOption->BootMenuLen = PxeOption->Length;
  113. VendorOption->BootMenu = (PXEBC_BOOT_MENU_ENTRY *)PxeOption->Data;
  114. break;
  115. case PXEBC_VENDOR_TAG_MENU_PROMPT:
  116. VendorOption->MenuPromptLen = PxeOption->Length;
  117. VendorOption->MenuPrompt = (PXEBC_MENU_PROMPT *)PxeOption->Data;
  118. break;
  119. case PXEBC_VENDOR_TAG_MCAST_ALLOC:
  120. CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
  121. CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));
  122. CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));
  123. break;
  124. case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:
  125. VendorOption->CredTypeLen = PxeOption->Length;
  126. VendorOption->CredType = (UINT32 *)PxeOption->Data;
  127. break;
  128. case PXEBC_VENDOR_TAG_BOOT_ITEM:
  129. CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));
  130. CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));
  131. break;
  132. default:
  133. //
  134. // Not interesting PXE vendor options.
  135. //
  136. break;
  137. }
  138. //
  139. // Set the bit map for the special PXE options.
  140. //
  141. SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);
  142. //
  143. // Continue to the next option.
  144. //
  145. if (PxeOption->OpCode == DHCP4_TAG_PAD) {
  146. Offset++;
  147. } else {
  148. Offset = (UINT8)(Offset + PxeOption->Length + 2);
  149. }
  150. PxeOption = (EFI_DHCP4_PACKET_OPTION *)(Dhcp4Option->Data + Offset);
  151. }
  152. }
  153. /**
  154. Build the options buffer for the DHCPv4 request packet.
  155. @param[in] Private Pointer to PxeBc private data.
  156. @param[out] OptList Pointer to the option pointer array.
  157. @param[in] Buffer Pointer to the buffer to contain the option list.
  158. @param[in] NeedMsgType If TRUE, it is necessary to include the Msg type option.
  159. Otherwise, it is not necessary.
  160. @return Index The count of the built-in options.
  161. **/
  162. UINT32
  163. PxeBcBuildDhcp4Options (
  164. IN PXEBC_PRIVATE_DATA *Private,
  165. OUT EFI_DHCP4_PACKET_OPTION **OptList,
  166. IN UINT8 *Buffer,
  167. IN BOOLEAN NeedMsgType
  168. )
  169. {
  170. UINT32 Index;
  171. PXEBC_DHCP4_OPTION_ENTRY OptEnt;
  172. UINT16 Value;
  173. Index = 0;
  174. OptList[0] = (EFI_DHCP4_PACKET_OPTION *)Buffer;
  175. if (NeedMsgType) {
  176. //
  177. // Append message type.
  178. //
  179. OptList[Index]->OpCode = DHCP4_TAG_MSG_TYPE;
  180. OptList[Index]->Length = 1;
  181. OptEnt.Mesg = (PXEBC_DHCP4_OPTION_MESG *)OptList[Index]->Data;
  182. OptEnt.Mesg->Type = PXEBC_DHCP4_MSG_TYPE_REQUEST;
  183. Index++;
  184. OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
  185. //
  186. // Append max message size.
  187. //
  188. OptList[Index]->OpCode = DHCP4_TAG_MAXMSG;
  189. OptList[Index]->Length = (UINT8)sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);
  190. OptEnt.MaxMesgSize = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *)OptList[Index]->Data;
  191. Value = NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE);
  192. CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));
  193. Index++;
  194. OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
  195. }
  196. //
  197. // Append parameter request list option.
  198. //
  199. OptList[Index]->OpCode = DHCP4_TAG_PARA_LIST;
  200. OptList[Index]->Length = 35;
  201. OptEnt.Para = (PXEBC_DHCP4_OPTION_PARA *)OptList[Index]->Data;
  202. OptEnt.Para->ParaList[0] = DHCP4_TAG_NETMASK;
  203. OptEnt.Para->ParaList[1] = DHCP4_TAG_TIME_OFFSET;
  204. OptEnt.Para->ParaList[2] = DHCP4_TAG_ROUTER;
  205. OptEnt.Para->ParaList[3] = DHCP4_TAG_TIME_SERVER;
  206. OptEnt.Para->ParaList[4] = DHCP4_TAG_NAME_SERVER;
  207. OptEnt.Para->ParaList[5] = DHCP4_TAG_DNS_SERVER;
  208. OptEnt.Para->ParaList[6] = DHCP4_TAG_HOSTNAME;
  209. OptEnt.Para->ParaList[7] = DHCP4_TAG_BOOTFILE_LEN;
  210. OptEnt.Para->ParaList[8] = DHCP4_TAG_DOMAINNAME;
  211. OptEnt.Para->ParaList[9] = DHCP4_TAG_ROOTPATH;
  212. OptEnt.Para->ParaList[10] = DHCP4_TAG_EXTEND_PATH;
  213. OptEnt.Para->ParaList[11] = DHCP4_TAG_EMTU;
  214. OptEnt.Para->ParaList[12] = DHCP4_TAG_TTL;
  215. OptEnt.Para->ParaList[13] = DHCP4_TAG_BROADCAST;
  216. OptEnt.Para->ParaList[14] = DHCP4_TAG_NIS_DOMAIN;
  217. OptEnt.Para->ParaList[15] = DHCP4_TAG_NIS_SERVER;
  218. OptEnt.Para->ParaList[16] = DHCP4_TAG_NTP_SERVER;
  219. OptEnt.Para->ParaList[17] = DHCP4_TAG_VENDOR;
  220. OptEnt.Para->ParaList[18] = DHCP4_TAG_REQUEST_IP;
  221. OptEnt.Para->ParaList[19] = DHCP4_TAG_LEASE;
  222. OptEnt.Para->ParaList[20] = DHCP4_TAG_SERVER_ID;
  223. OptEnt.Para->ParaList[21] = DHCP4_TAG_T1;
  224. OptEnt.Para->ParaList[22] = DHCP4_TAG_T2;
  225. OptEnt.Para->ParaList[23] = DHCP4_TAG_VENDOR_CLASS_ID;
  226. OptEnt.Para->ParaList[24] = DHCP4_TAG_TFTP;
  227. OptEnt.Para->ParaList[25] = DHCP4_TAG_BOOTFILE;
  228. OptEnt.Para->ParaList[26] = DHCP4_TAG_UUID;
  229. OptEnt.Para->ParaList[27] = 0x80;
  230. OptEnt.Para->ParaList[28] = 0x81;
  231. OptEnt.Para->ParaList[29] = 0x82;
  232. OptEnt.Para->ParaList[30] = 0x83;
  233. OptEnt.Para->ParaList[31] = 0x84;
  234. OptEnt.Para->ParaList[32] = 0x85;
  235. OptEnt.Para->ParaList[33] = 0x86;
  236. OptEnt.Para->ParaList[34] = 0x87;
  237. Index++;
  238. OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
  239. //
  240. // Append UUID/Guid-based client identifier option
  241. //
  242. OptList[Index]->OpCode = DHCP4_TAG_UUID;
  243. OptList[Index]->Length = (UINT8)sizeof (PXEBC_DHCP4_OPTION_UUID);
  244. OptEnt.Uuid = (PXEBC_DHCP4_OPTION_UUID *)OptList[Index]->Data;
  245. OptEnt.Uuid->Type = 0;
  246. Index++;
  247. OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
  248. if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *)OptEnt.Uuid->Guid))) {
  249. //
  250. // Zero the Guid to indicate NOT programmable if failed to get system Guid.
  251. //
  252. DEBUG ((DEBUG_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));
  253. ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));
  254. }
  255. //
  256. // Append client network device interface option
  257. //
  258. OptList[Index]->OpCode = DHCP4_TAG_UNDI;
  259. OptList[Index]->Length = (UINT8)sizeof (PXEBC_DHCP4_OPTION_UNDI);
  260. OptEnt.Undi = (PXEBC_DHCP4_OPTION_UNDI *)OptList[Index]->Data;
  261. if (Private->Nii != NULL) {
  262. OptEnt.Undi->Type = Private->Nii->Type;
  263. OptEnt.Undi->MajorVer = Private->Nii->MajorVer;
  264. OptEnt.Undi->MinorVer = Private->Nii->MinorVer;
  265. } else {
  266. OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;
  267. OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;
  268. OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;
  269. }
  270. Index++;
  271. OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
  272. //
  273. // Append client system architecture option
  274. //
  275. OptList[Index]->OpCode = DHCP4_TAG_ARCH;
  276. OptList[Index]->Length = (UINT8)sizeof (PXEBC_DHCP4_OPTION_ARCH);
  277. OptEnt.Arch = (PXEBC_DHCP4_OPTION_ARCH *)OptList[Index]->Data;
  278. Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);
  279. CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
  280. Index++;
  281. OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
  282. //
  283. // Append vendor class identify option
  284. //
  285. OptList[Index]->OpCode = DHCP4_TAG_VENDOR_CLASS_ID;
  286. OptList[Index]->Length = (UINT8)sizeof (PXEBC_DHCP4_OPTION_CLID);
  287. OptEnt.Clid = (PXEBC_DHCP4_OPTION_CLID *)OptList[Index]->Data;
  288. CopyMem (
  289. OptEnt.Clid,
  290. DEFAULT_CLASS_ID_DATA,
  291. sizeof (PXEBC_DHCP4_OPTION_CLID)
  292. );
  293. PxeBcUintnToAscDecWithFormat (
  294. EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,
  295. OptEnt.Clid->ArchitectureType,
  296. sizeof (OptEnt.Clid->ArchitectureType)
  297. );
  298. if (Private->Nii != NULL) {
  299. CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));
  300. PxeBcUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));
  301. PxeBcUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));
  302. }
  303. Index++;
  304. return Index;
  305. }
  306. /**
  307. Create a template DHCPv4 packet as a seed.
  308. @param[out] Seed Pointer to the seed packet.
  309. @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL.
  310. **/
  311. VOID
  312. PxeBcSeedDhcp4Packet (
  313. OUT EFI_DHCP4_PACKET *Seed,
  314. IN EFI_UDP4_PROTOCOL *Udp4
  315. )
  316. {
  317. EFI_SIMPLE_NETWORK_MODE Mode;
  318. EFI_DHCP4_HEADER *Header;
  319. //
  320. // Get IfType and HwAddressSize from SNP mode data.
  321. //
  322. Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode);
  323. Seed->Size = sizeof (EFI_DHCP4_PACKET);
  324. Seed->Length = sizeof (Seed->Dhcp4);
  325. Header = &Seed->Dhcp4.Header;
  326. ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
  327. Header->OpCode = PXEBC_DHCP4_OPCODE_REQUEST;
  328. Header->HwType = Mode.IfType;
  329. Header->HwAddrLen = (UINT8)Mode.HwAddressSize;
  330. CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);
  331. Seed->Dhcp4.Magik = PXEBC_DHCP4_MAGIC;
  332. Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;
  333. }
  334. /**
  335. Cache the DHCPv4 packet.
  336. @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.
  337. @param[in] Src Pointer to the DHCPv4 packet to be cached.
  338. @retval EFI_SUCCESS Packet is copied.
  339. @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
  340. **/
  341. EFI_STATUS
  342. PxeBcCacheDhcp4Packet (
  343. IN EFI_DHCP4_PACKET *Dst,
  344. IN EFI_DHCP4_PACKET *Src
  345. )
  346. {
  347. if (Dst->Size < Src->Length) {
  348. return EFI_BUFFER_TOO_SMALL;
  349. }
  350. CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);
  351. Dst->Length = Src->Length;
  352. return EFI_SUCCESS;
  353. }
  354. /**
  355. Parse the cached DHCPv4 packet, including all the options.
  356. @param[in] Cache4 Pointer to cached DHCPv4 packet.
  357. @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.
  358. @retval EFI_DEVICE_ERROR Failed to parse and invalid packet.
  359. **/
  360. EFI_STATUS
  361. PxeBcParseDhcp4Packet (
  362. IN PXEBC_DHCP4_PACKET_CACHE *Cache4
  363. )
  364. {
  365. EFI_DHCP4_PACKET *Offer;
  366. EFI_DHCP4_PACKET_OPTION **Options;
  367. EFI_DHCP4_PACKET_OPTION *Option;
  368. PXEBC_OFFER_TYPE OfferType;
  369. UINTN Index;
  370. BOOLEAN IsProxyOffer;
  371. BOOLEAN IsPxeOffer;
  372. UINT8 *Ptr8;
  373. BOOLEAN FileFieldOverloaded;
  374. IsProxyOffer = FALSE;
  375. IsPxeOffer = FALSE;
  376. FileFieldOverloaded = FALSE;
  377. ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));
  378. ZeroMem (&Cache4->VendorOpt, sizeof (Cache4->VendorOpt));
  379. Offer = &Cache4->Packet.Offer;
  380. Options = Cache4->OptList;
  381. //
  382. // Parse DHCPv4 options in this offer, and store the pointers.
  383. // First, try to parse DHCPv4 options from the DHCP optional parameters field.
  384. //
  385. for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
  386. Options[Index] = PxeBcParseDhcp4Options (
  387. Offer->Dhcp4.Option,
  388. GET_OPTION_BUFFER_LEN (Offer),
  389. mInterestedDhcp4Tags[Index]
  390. );
  391. }
  392. //
  393. // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
  394. // If yes, try to parse options from the BootFileName field, then ServerName field.
  395. //
  396. Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];
  397. if (Option != NULL) {
  398. if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) {
  399. FileFieldOverloaded = TRUE;
  400. for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
  401. if (Options[Index] == NULL) {
  402. Options[Index] = PxeBcParseDhcp4Options (
  403. (UINT8 *)Offer->Dhcp4.Header.BootFileName,
  404. sizeof (Offer->Dhcp4.Header.BootFileName),
  405. mInterestedDhcp4Tags[Index]
  406. );
  407. }
  408. }
  409. }
  410. if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) != 0) {
  411. for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
  412. if (Options[Index] == NULL) {
  413. Options[Index] = PxeBcParseDhcp4Options (
  414. (UINT8 *)Offer->Dhcp4.Header.ServerName,
  415. sizeof (Offer->Dhcp4.Header.ServerName),
  416. mInterestedDhcp4Tags[Index]
  417. );
  418. }
  419. }
  420. }
  421. }
  422. //
  423. // The offer with zero "yiaddr" is a proxy offer.
  424. //
  425. if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {
  426. IsProxyOffer = TRUE;
  427. }
  428. //
  429. // The offer with "PXEClient" is a PXE offer.
  430. //
  431. Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];
  432. if ((Option != NULL) && (Option->Length >= 9) &&
  433. (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0))
  434. {
  435. IsPxeOffer = TRUE;
  436. }
  437. //
  438. // Parse PXE vendor options in this offer, and store the contents/pointers.
  439. //
  440. Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR];
  441. if (IsPxeOffer && (Option != NULL)) {
  442. PxeBcParseVendorOptions (Option, &Cache4->VendorOpt);
  443. }
  444. //
  445. // Parse PXE boot file name:
  446. // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.
  447. // Otherwise, read from boot file field in DHCP header.
  448. //
  449. if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
  450. //
  451. // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
  452. // terminated string. So force to append null terminated character at the end of string.
  453. //
  454. Ptr8 = (UINT8 *)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];
  455. Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length;
  456. if (*(Ptr8 - 1) != '\0') {
  457. *Ptr8 = '\0';
  458. }
  459. } else if (!FileFieldOverloaded && (Offer->Dhcp4.Header.BootFileName[0] != 0)) {
  460. //
  461. // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.
  462. // Do not count dhcp option header here, or else will destroy the serverhostname.
  463. //
  464. Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)
  465. (&Offer->Dhcp4.Header.BootFileName[0] -
  466. OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));
  467. }
  468. //
  469. // Determine offer type of the DHCPv4 packet.
  470. //
  471. Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];
  472. if ((Option == NULL) || (Option->Data[0] == 0)) {
  473. //
  474. // It's a Bootp offer.
  475. //
  476. OfferType = PxeOfferTypeBootp;
  477. Option = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];
  478. if (Option == NULL) {
  479. //
  480. // If the Bootp offer without bootfilename, discard it.
  481. //
  482. return EFI_DEVICE_ERROR;
  483. }
  484. } else {
  485. if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
  486. //
  487. // It's a PXE10 offer with PXEClient and discover vendor option.
  488. //
  489. OfferType = IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDhcpPxe10;
  490. } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
  491. //
  492. // It's a WFM11a offer with PXEClient and mtftp vendor option.
  493. // But multi-cast download is not supported currently, so discard it.
  494. //
  495. return EFI_DEVICE_ERROR;
  496. } else if (IsPxeOffer) {
  497. //
  498. // It's a BINL offer only with PXEClient.
  499. //
  500. OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;
  501. } else {
  502. //
  503. // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.
  504. //
  505. OfferType = PxeOfferTypeDhcpOnly;
  506. }
  507. }
  508. Cache4->OfferType = OfferType;
  509. return EFI_SUCCESS;
  510. }
  511. /**
  512. Cache the DHCPv4 ack packet, and parse it on demand.
  513. @param[in] Private Pointer to PxeBc private data.
  514. @param[in] Ack Pointer to the DHCPv4 ack packet.
  515. @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
  516. @retval EFI_SUCCESS Cache and parse the packet successfully.
  517. @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
  518. **/
  519. EFI_STATUS
  520. PxeBcCopyDhcp4Ack (
  521. IN PXEBC_PRIVATE_DATA *Private,
  522. IN EFI_DHCP4_PACKET *Ack,
  523. IN BOOLEAN Verified
  524. )
  525. {
  526. EFI_PXE_BASE_CODE_MODE *Mode;
  527. EFI_STATUS Status;
  528. Mode = Private->PxeBc.Mode;
  529. Status = PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack);
  530. if (EFI_ERROR (Status)) {
  531. return Status;
  532. }
  533. if (Verified) {
  534. //
  535. // Parse the ack packet and store it into mode data if needed.
  536. //
  537. PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4);
  538. CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length);
  539. Mode->DhcpAckReceived = TRUE;
  540. }
  541. return EFI_SUCCESS;
  542. }
  543. /**
  544. Cache the DHCPv4 proxy offer packet according to the received order.
  545. @param[in] Private Pointer to PxeBc private data.
  546. @param[in] OfferIndex The received order of offer packets.
  547. @retval EFI_SUCCESS Cache and parse the packet successfully.
  548. @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
  549. **/
  550. EFI_STATUS
  551. PxeBcCopyProxyOffer (
  552. IN PXEBC_PRIVATE_DATA *Private,
  553. IN UINT32 OfferIndex
  554. )
  555. {
  556. EFI_PXE_BASE_CODE_MODE *Mode;
  557. EFI_DHCP4_PACKET *Offer;
  558. EFI_STATUS Status;
  559. ASSERT (OfferIndex < Private->OfferNum);
  560. ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);
  561. Mode = Private->PxeBc.Mode;
  562. Offer = &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer;
  563. //
  564. // Cache the proxy offer packet and parse it.
  565. //
  566. Status = PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer);
  567. if (EFI_ERROR (Status)) {
  568. return Status;
  569. }
  570. PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4);
  571. //
  572. // Store this packet into mode data.
  573. //
  574. CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length);
  575. Mode->ProxyOfferReceived = TRUE;
  576. return EFI_SUCCESS;
  577. }
  578. /**
  579. Retry to request bootfile name by the BINL offer.
  580. @param[in] Private Pointer to PxeBc private data.
  581. @param[in] Index The received order of offer packets.
  582. @retval EFI_SUCCESS Successfully retried to request bootfile name.
  583. @retval EFI_DEVICE_ERROR Failed to retry bootfile name.
  584. **/
  585. EFI_STATUS
  586. PxeBcRetryBinlOffer (
  587. IN PXEBC_PRIVATE_DATA *Private,
  588. IN UINT32 Index
  589. )
  590. {
  591. EFI_DHCP4_PACKET *Offer;
  592. EFI_IP_ADDRESS ServerIp;
  593. EFI_STATUS Status;
  594. PXEBC_DHCP4_PACKET_CACHE *Cache4;
  595. EFI_DHCP4_PACKET *Reply;
  596. ASSERT (Index < PXEBC_OFFER_MAX_NUM);
  597. ASSERT (
  598. Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpBinl ||
  599. Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeProxyBinl
  600. );
  601. Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
  602. //
  603. // Prefer to siaddr in header as next server address. If it's zero, then use option 54.
  604. //
  605. if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) {
  606. CopyMem (
  607. &ServerIp.Addr[0],
  608. Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
  609. sizeof (EFI_IPv4_ADDRESS)
  610. );
  611. } else {
  612. CopyMem (
  613. &ServerIp.Addr[0],
  614. &Offer->Dhcp4.Header.ServerAddr,
  615. sizeof (EFI_IPv4_ADDRESS)
  616. );
  617. }
  618. Private->IsDoDiscover = FALSE;
  619. Cache4 = &Private->ProxyOffer.Dhcp4;
  620. Reply = &Cache4->Packet.Offer;
  621. //
  622. // Send another request packet for bootfile name.
  623. //
  624. Status = PxeBcDhcp4Discover (
  625. Private,
  626. 0,
  627. NULL,
  628. FALSE,
  629. &ServerIp,
  630. 0,
  631. NULL
  632. );
  633. if (EFI_ERROR (Status)) {
  634. return Status;
  635. }
  636. //
  637. // Parse the reply for the last request packet.
  638. //
  639. Status = PxeBcParseDhcp4Packet (Cache4);
  640. if (EFI_ERROR (Status)) {
  641. return Status;
  642. }
  643. if ((Cache4->OfferType != PxeOfferTypeProxyPxe10) &&
  644. (Cache4->OfferType != PxeOfferTypeProxyWfm11a) &&
  645. (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL))
  646. {
  647. //
  648. // This BINL ack doesn't have discovery option set or multicast option set
  649. // or bootfile name specified.
  650. //
  651. return EFI_DEVICE_ERROR;
  652. }
  653. //
  654. // Store the reply into mode data.
  655. //
  656. Private->PxeBc.Mode->ProxyOfferReceived = TRUE;
  657. CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->Length);
  658. return EFI_SUCCESS;
  659. }
  660. /**
  661. Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
  662. @param[in] Private Pointer to PxeBc private data.
  663. @param[in] RcvdOffer Pointer to the received offer packet.
  664. @retval EFI_SUCCESS Cache and parse the packet successfully.
  665. @retval Others Operation failed.
  666. **/
  667. EFI_STATUS
  668. PxeBcCacheDhcp4Offer (
  669. IN PXEBC_PRIVATE_DATA *Private,
  670. IN EFI_DHCP4_PACKET *RcvdOffer
  671. )
  672. {
  673. PXEBC_DHCP4_PACKET_CACHE *Cache4;
  674. EFI_DHCP4_PACKET *Offer;
  675. PXEBC_OFFER_TYPE OfferType;
  676. EFI_STATUS Status;
  677. ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM);
  678. Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;
  679. Offer = &Cache4->Packet.Offer;
  680. //
  681. // Cache the content of DHCPv4 packet firstly.
  682. //
  683. Status = PxeBcCacheDhcp4Packet (Offer, RcvdOffer);
  684. if (EFI_ERROR (Status)) {
  685. return Status;
  686. }
  687. //
  688. // Validate the DHCPv4 packet, and parse the options and offer type.
  689. //
  690. if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) {
  691. return EFI_ABORTED;
  692. }
  693. //
  694. // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
  695. //
  696. OfferType = Cache4->OfferType;
  697. ASSERT (OfferType < PxeOfferTypeMax);
  698. if (OfferType == PxeOfferTypeBootp) {
  699. //
  700. // It's a Bootp offer, only cache the first one, and discard the others.
  701. //
  702. if (Private->OfferCount[OfferType] == 0) {
  703. Private->OfferIndex[OfferType][0] = Private->OfferNum;
  704. Private->OfferCount[OfferType] = 1;
  705. } else {
  706. return EFI_ABORTED;
  707. }
  708. } else {
  709. ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);
  710. if (IS_PROXY_DHCP_OFFER (Offer)) {
  711. //
  712. // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
  713. //
  714. Private->IsProxyRecved = TRUE;
  715. if (OfferType == PxeOfferTypeProxyBinl) {
  716. //
  717. // Cache all proxy BINL offers.
  718. //
  719. Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
  720. Private->OfferCount[OfferType]++;
  721. } else if (((OfferType == PxeOfferTypeProxyPxe10) || (OfferType == PxeOfferTypeProxyWfm11a)) &&
  722. (Private->OfferCount[OfferType] < 1))
  723. {
  724. //
  725. // Only cache the first PXE10/WFM11a offer, and discard the others.
  726. //
  727. Private->OfferIndex[OfferType][0] = Private->OfferNum;
  728. Private->OfferCount[OfferType] = 1;
  729. } else {
  730. return EFI_ABORTED;
  731. }
  732. } else {
  733. //
  734. // It's a DHCPv4 offer with yiaddr, and cache them all.
  735. //
  736. Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
  737. Private->OfferCount[OfferType]++;
  738. }
  739. }
  740. Private->OfferNum++;
  741. return EFI_SUCCESS;
  742. }
  743. /**
  744. Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.
  745. @param[in] Private Pointer to PxeBc private data.
  746. **/
  747. VOID
  748. PxeBcSelectDhcp4Offer (
  749. IN PXEBC_PRIVATE_DATA *Private
  750. )
  751. {
  752. UINT32 Index;
  753. UINT32 OfferIndex;
  754. EFI_DHCP4_PACKET *Offer;
  755. Private->SelectIndex = 0;
  756. if (Private->IsOfferSorted) {
  757. //
  758. // Select offer by default policy.
  759. //
  760. if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {
  761. //
  762. // 1. DhcpPxe10 offer
  763. //
  764. Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;
  765. } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {
  766. //
  767. // 2. DhcpWfm11a offer
  768. //
  769. Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;
  770. } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) &&
  771. (Private->OfferCount[PxeOfferTypeProxyPxe10] > 0))
  772. {
  773. //
  774. // 3. DhcpOnly offer and ProxyPxe10 offer.
  775. //
  776. Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
  777. Private->SelectProxyType = PxeOfferTypeProxyPxe10;
  778. } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) &&
  779. (Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0))
  780. {
  781. //
  782. // 4. DhcpOnly offer and ProxyWfm11a offer.
  783. //
  784. Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
  785. Private->SelectProxyType = PxeOfferTypeProxyWfm11a;
  786. } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {
  787. //
  788. // 5. DhcpBinl offer.
  789. //
  790. Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;
  791. } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) &&
  792. (Private->OfferCount[PxeOfferTypeProxyBinl] > 0))
  793. {
  794. //
  795. // 6. DhcpOnly offer and ProxyBinl offer.
  796. //
  797. Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
  798. Private->SelectProxyType = PxeOfferTypeProxyBinl;
  799. } else {
  800. //
  801. // 7. DhcpOnly offer with bootfilename.
  802. //
  803. for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {
  804. OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];
  805. if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
  806. Private->SelectIndex = OfferIndex + 1;
  807. break;
  808. }
  809. }
  810. //
  811. // 8. Bootp offer with bootfilename.
  812. //
  813. OfferIndex = Private->OfferIndex[PxeOfferTypeBootp][0];
  814. if ((Private->SelectIndex == 0) &&
  815. (Private->OfferCount[PxeOfferTypeBootp] > 0) &&
  816. (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL))
  817. {
  818. Private->SelectIndex = OfferIndex + 1;
  819. }
  820. }
  821. } else {
  822. //
  823. // Select offer by received order.
  824. //
  825. for (Index = 0; Index < Private->OfferNum; Index++) {
  826. Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
  827. if (IS_PROXY_DHCP_OFFER (Offer)) {
  828. //
  829. // Skip proxy offers
  830. //
  831. continue;
  832. }
  833. if (!Private->IsProxyRecved &&
  834. (Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpOnly) &&
  835. (Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL))
  836. {
  837. //
  838. // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
  839. //
  840. continue;
  841. }
  842. //
  843. // Record the index of the select offer.
  844. //
  845. Private->SelectIndex = Index + 1;
  846. break;
  847. }
  848. }
  849. }
  850. /**
  851. Handle the DHCPv4 offer packet.
  852. @param[in] Private Pointer to PxeBc private data.
  853. @retval EFI_SUCCESS Handled the DHCPv4 offer packet successfully.
  854. @retval EFI_NO_RESPONSE No response to the following request packet.
  855. @retval EFI_NOT_FOUND No boot filename received.
  856. @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.
  857. **/
  858. EFI_STATUS
  859. PxeBcHandleDhcp4Offer (
  860. IN PXEBC_PRIVATE_DATA *Private
  861. )
  862. {
  863. PXEBC_DHCP4_PACKET_CACHE *Cache4;
  864. EFI_DHCP4_PACKET_OPTION **Options;
  865. UINT32 Index;
  866. EFI_DHCP4_PACKET *Offer;
  867. PXEBC_OFFER_TYPE OfferType;
  868. UINT32 ProxyIndex;
  869. UINT32 SelectIndex;
  870. EFI_STATUS Status;
  871. EFI_PXE_BASE_CODE_MODE *Mode;
  872. EFI_DHCP4_PACKET *Ack;
  873. ASSERT (Private->SelectIndex > 0);
  874. SelectIndex = (UINT32)(Private->SelectIndex - 1);
  875. ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);
  876. Cache4 = &Private->OfferBuffer[SelectIndex].Dhcp4;
  877. Options = Cache4->OptList;
  878. Status = EFI_SUCCESS;
  879. if (Cache4->OfferType == PxeOfferTypeDhcpBinl) {
  880. //
  881. // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
  882. //
  883. if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) {
  884. Status = EFI_NO_RESPONSE;
  885. }
  886. } else if (Cache4->OfferType == PxeOfferTypeDhcpOnly) {
  887. if (Private->IsProxyRecved) {
  888. //
  889. // DhcpOnly offer is selected, so need try to request bootfile name.
  890. //
  891. ProxyIndex = 0;
  892. if (Private->IsOfferSorted) {
  893. //
  894. // The proxy offer should be determined if select by default policy.
  895. // IsOfferSorted means all offers are labeled by OfferIndex.
  896. //
  897. ASSERT (Private->SelectProxyType < PxeOfferTypeMax);
  898. ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);
  899. if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {
  900. //
  901. // Try all the cached ProxyBinl offer one by one to request bootfile name.
  902. //
  903. for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {
  904. ASSERT (Index < PXEBC_OFFER_MAX_NUM);
  905. ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];
  906. if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) {
  907. break;
  908. }
  909. }
  910. if (Index == Private->OfferCount[Private->SelectProxyType]) {
  911. Status = EFI_NO_RESPONSE;
  912. }
  913. } else {
  914. //
  915. // For other proxy offers, only one is buffered.
  916. //
  917. ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
  918. }
  919. } else {
  920. //
  921. // The proxy offer should not be determined if select by received order.
  922. //
  923. Status = EFI_NO_RESPONSE;
  924. for (Index = 0; Index < Private->OfferNum; Index++) {
  925. ASSERT (Index < PXEBC_OFFER_MAX_NUM);
  926. Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
  927. OfferType = Private->OfferBuffer[Index].Dhcp4.OfferType;
  928. if (!IS_PROXY_DHCP_OFFER (Offer)) {
  929. //
  930. // Skip non proxy DHCPv4 offers.
  931. //
  932. continue;
  933. }
  934. if (OfferType == PxeOfferTypeProxyBinl) {
  935. //
  936. // Try all the cached ProxyBinl offer one by one to request bootfile name.
  937. //
  938. if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) {
  939. continue;
  940. }
  941. }
  942. Private->SelectProxyType = OfferType;
  943. ProxyIndex = Index;
  944. Status = EFI_SUCCESS;
  945. break;
  946. }
  947. }
  948. if (!EFI_ERROR (Status) && (Private->SelectProxyType != PxeOfferTypeProxyBinl)) {
  949. //
  950. // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
  951. //
  952. Status = PxeBcCopyProxyOffer (Private, ProxyIndex);
  953. }
  954. } else {
  955. //
  956. // Otherwise, the bootfile name must be included in DhcpOnly offer.
  957. //
  958. if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
  959. Status = EFI_NOT_FOUND;
  960. }
  961. }
  962. }
  963. if (!EFI_ERROR (Status)) {
  964. //
  965. // All PXE boot information is ready by now.
  966. //
  967. Mode = Private->PxeBc.Mode;
  968. Offer = &Cache4->Packet.Offer;
  969. Ack = &Private->DhcpAck.Dhcp4.Packet.Ack;
  970. if (Cache4->OfferType == PxeOfferTypeBootp) {
  971. //
  972. // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply
  973. // should be taken as ack.
  974. //
  975. Ack = Offer;
  976. }
  977. Status = PxeBcCopyDhcp4Ack (Private, Ack, TRUE);
  978. if (EFI_ERROR (Status)) {
  979. return Status;
  980. }
  981. Mode->DhcpDiscoverValid = TRUE;
  982. }
  983. return Status;
  984. }
  985. /**
  986. EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
  987. to intercept events that occurred in the configuration process.
  988. @param[in] This Pointer to the EFI DHCPv4 Protocol.
  989. @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
  990. @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.
  991. @param[in] Dhcp4Event The event that occurs in the current state, which usually means a
  992. state transition.
  993. @param[in] Packet The DHCPv4 packet that is going to be sent or already received.
  994. @param[out] NewPacket The packet that is used to replace the above Packet.
  995. @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
  996. @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
  997. driver will continue to wait for more DHCPOFFER packets until the
  998. retry timeout expires.
  999. @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process
  1000. and return to the Dhcp4Init or Dhcp4InitReboot state.
  1001. **/
  1002. EFI_STATUS
  1003. EFIAPI
  1004. PxeBcDhcp4CallBack (
  1005. IN EFI_DHCP4_PROTOCOL *This,
  1006. IN VOID *Context,
  1007. IN EFI_DHCP4_STATE CurrentState,
  1008. IN EFI_DHCP4_EVENT Dhcp4Event,
  1009. IN EFI_DHCP4_PACKET *Packet OPTIONAL,
  1010. OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL
  1011. )
  1012. {
  1013. PXEBC_PRIVATE_DATA *Private;
  1014. EFI_PXE_BASE_CODE_MODE *Mode;
  1015. EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;
  1016. EFI_DHCP4_PACKET_OPTION *MaxMsgSize;
  1017. UINT16 Value;
  1018. EFI_STATUS Status;
  1019. BOOLEAN Received;
  1020. if ((Dhcp4Event != Dhcp4RcvdOffer) &&
  1021. (Dhcp4Event != Dhcp4SelectOffer) &&
  1022. (Dhcp4Event != Dhcp4SendDiscover) &&
  1023. (Dhcp4Event != Dhcp4RcvdAck))
  1024. {
  1025. return EFI_SUCCESS;
  1026. }
  1027. ASSERT (Packet != NULL);
  1028. Private = (PXEBC_PRIVATE_DATA *)Context;
  1029. Mode = Private->PxeBc.Mode;
  1030. Callback = Private->PxeBcCallback;
  1031. //
  1032. // Override the Maximum DHCP Message Size.
  1033. //
  1034. MaxMsgSize = PxeBcParseDhcp4Options (
  1035. Packet->Dhcp4.Option,
  1036. GET_OPTION_BUFFER_LEN (Packet),
  1037. DHCP4_TAG_MAXMSG
  1038. );
  1039. if (MaxMsgSize != NULL) {
  1040. Value = HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE);
  1041. CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));
  1042. }
  1043. //
  1044. // Callback to user if any packets sent or received.
  1045. //
  1046. if ((Dhcp4Event != Dhcp4SelectOffer) && (Callback != NULL)) {
  1047. Received = (BOOLEAN)(Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);
  1048. Status = Callback->Callback (
  1049. Callback,
  1050. Private->Function,
  1051. Received,
  1052. Packet->Length,
  1053. (EFI_PXE_BASE_CODE_PACKET *)&Packet->Dhcp4
  1054. );
  1055. if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
  1056. return EFI_ABORTED;
  1057. }
  1058. }
  1059. Status = EFI_SUCCESS;
  1060. switch (Dhcp4Event) {
  1061. case Dhcp4SendDiscover:
  1062. if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
  1063. //
  1064. // If the to be sent packet exceeds the maximum length, abort the DHCP process.
  1065. //
  1066. Status = EFI_ABORTED;
  1067. break;
  1068. }
  1069. //
  1070. // Cache the DHCPv4 discover packet to mode data directly.
  1071. // It need to check SendGuid as well as Dhcp4SendRequest.
  1072. //
  1073. CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length);
  1074. case Dhcp4SendRequest:
  1075. if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
  1076. //
  1077. // If the to be sent packet exceeds the maximum length, abort the DHCP process.
  1078. //
  1079. Status = EFI_ABORTED;
  1080. break;
  1081. }
  1082. if (Mode->SendGUID) {
  1083. //
  1084. // Send the system Guid instead of the MAC address as the hardware address if required.
  1085. //
  1086. if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *)Packet->Dhcp4.Header.ClientHwAddr))) {
  1087. //
  1088. // Zero the Guid to indicate NOT programmable if failed to get system Guid.
  1089. //
  1090. DEBUG ((DEBUG_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));
  1091. ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
  1092. }
  1093. Packet->Dhcp4.Header.HwAddrLen = (UINT8)sizeof (EFI_GUID);
  1094. }
  1095. break;
  1096. case Dhcp4RcvdOffer:
  1097. Status = EFI_NOT_READY;
  1098. if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
  1099. //
  1100. // Ignore the incoming packets which exceed the maximum length.
  1101. //
  1102. break;
  1103. }
  1104. if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {
  1105. //
  1106. // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
  1107. // the OfferIndex and OfferCount.
  1108. // If error happens, just ignore this packet and continue to wait more offer.
  1109. //
  1110. PxeBcCacheDhcp4Offer (Private, Packet);
  1111. }
  1112. break;
  1113. case Dhcp4SelectOffer:
  1114. ASSERT (NewPacket != NULL);
  1115. //
  1116. // Select offer by the default policy or by order, and record the SelectIndex
  1117. // and SelectProxyType.
  1118. //
  1119. PxeBcSelectDhcp4Offer (Private);
  1120. if (Private->SelectIndex == 0) {
  1121. Status = EFI_ABORTED;
  1122. } else {
  1123. *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;
  1124. }
  1125. break;
  1126. case Dhcp4RcvdAck:
  1127. //
  1128. // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data
  1129. // without verification.
  1130. //
  1131. ASSERT (Private->SelectIndex != 0);
  1132. Status = PxeBcCopyDhcp4Ack (Private, Packet, FALSE);
  1133. if (EFI_ERROR (Status)) {
  1134. Status = EFI_ABORTED;
  1135. }
  1136. break;
  1137. default:
  1138. break;
  1139. }
  1140. return Status;
  1141. }
  1142. /**
  1143. Build and send out the request packet for the bootfile, and parse the reply.
  1144. @param[in] Private Pointer to PxeBc private data.
  1145. @param[in] Type PxeBc option boot item type.
  1146. @param[in] Layer Pointer to option boot item layer.
  1147. @param[in] UseBis Use BIS or not.
  1148. @param[in] DestIp Pointer to the server address.
  1149. @param[in] IpCount The total count of the server address.
  1150. @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
  1151. @retval EFI_SUCCESS Successfully discovered boot file.
  1152. @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
  1153. @retval EFI_NOT_FOUND Can't get the PXE reply packet.
  1154. @retval Others Failed to discover boot file.
  1155. **/
  1156. EFI_STATUS
  1157. PxeBcDhcp4Discover (
  1158. IN PXEBC_PRIVATE_DATA *Private,
  1159. IN UINT16 Type,
  1160. IN UINT16 *Layer,
  1161. IN BOOLEAN UseBis,
  1162. IN EFI_IP_ADDRESS *DestIp,
  1163. IN UINT16 IpCount,
  1164. IN EFI_PXE_BASE_CODE_SRVLIST *SrvList
  1165. )
  1166. {
  1167. EFI_PXE_BASE_CODE_UDP_PORT Sport;
  1168. EFI_PXE_BASE_CODE_MODE *Mode;
  1169. EFI_DHCP4_PROTOCOL *Dhcp4;
  1170. EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;
  1171. BOOLEAN IsBCast;
  1172. EFI_STATUS Status;
  1173. UINT16 RepIndex;
  1174. UINT16 SrvIndex;
  1175. UINT16 TryIndex;
  1176. EFI_DHCP4_LISTEN_POINT ListenPoint;
  1177. EFI_DHCP4_PACKET *Response;
  1178. UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
  1179. EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
  1180. UINT32 OptCount;
  1181. EFI_DHCP4_PACKET_OPTION *PxeOpt;
  1182. PXEBC_OPTION_BOOT_ITEM *PxeBootItem;
  1183. UINT8 VendorOptLen;
  1184. UINT32 Xid;
  1185. Mode = Private->PxeBc.Mode;
  1186. Dhcp4 = Private->Dhcp4;
  1187. Status = EFI_SUCCESS;
  1188. ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
  1189. //
  1190. // Use broadcast if destination address not specified.
  1191. //
  1192. if (DestIp == NULL) {
  1193. Sport = PXEBC_DHCP4_S_PORT;
  1194. IsBCast = TRUE;
  1195. } else {
  1196. Sport = PXEBC_BS_DISCOVER_PORT;
  1197. IsBCast = FALSE;
  1198. }
  1199. if (!UseBis && (Layer != NULL)) {
  1200. *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
  1201. }
  1202. //
  1203. // Build all the options for the request packet.
  1204. //
  1205. OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE);
  1206. if (Private->IsDoDiscover) {
  1207. //
  1208. // Add vendor option of PXE_BOOT_ITEM
  1209. //
  1210. VendorOptLen = (UINT8)((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);
  1211. OptList[OptCount] = AllocateZeroPool (VendorOptLen);
  1212. if (OptList[OptCount] == NULL) {
  1213. return EFI_OUT_OF_RESOURCES;
  1214. }
  1215. OptList[OptCount]->OpCode = DHCP4_TAG_VENDOR;
  1216. OptList[OptCount]->Length = (UINT8)(VendorOptLen - 2);
  1217. PxeOpt = (EFI_DHCP4_PACKET_OPTION *)OptList[OptCount]->Data;
  1218. PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM;
  1219. PxeOpt->Length = (UINT8)sizeof (PXEBC_OPTION_BOOT_ITEM);
  1220. PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *)PxeOpt->Data;
  1221. PxeBootItem->Type = HTONS (Type);
  1222. PxeOpt->Data[PxeOpt->Length] = DHCP4_TAG_EOP;
  1223. if (Layer != NULL) {
  1224. PxeBootItem->Layer = HTONS (*Layer);
  1225. }
  1226. OptCount++;
  1227. }
  1228. //
  1229. // Build the request packet with seed packet and option list.
  1230. //
  1231. Status = Dhcp4->Build (
  1232. Dhcp4,
  1233. &Private->SeedPacket,
  1234. 0,
  1235. NULL,
  1236. OptCount,
  1237. OptList,
  1238. &Token.Packet
  1239. );
  1240. //
  1241. // Free the vendor option of PXE_BOOT_ITEM.
  1242. //
  1243. if (Private->IsDoDiscover) {
  1244. FreePool (OptList[OptCount - 1]);
  1245. }
  1246. if (EFI_ERROR (Status)) {
  1247. return Status;
  1248. }
  1249. if (Mode->SendGUID) {
  1250. if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *)Token.Packet->Dhcp4.Header.ClientHwAddr))) {
  1251. //
  1252. // Zero the Guid to indicate NOT programmable if failed to get system Guid.
  1253. //
  1254. DEBUG ((DEBUG_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));
  1255. ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
  1256. }
  1257. Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)sizeof (EFI_GUID);
  1258. }
  1259. //
  1260. // Set fields of the token for the request packet.
  1261. //
  1262. Xid = NET_RANDOM (NetRandomInitSeed ());
  1263. Token.Packet->Dhcp4.Header.Xid = HTONL (Xid);
  1264. Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)((IsBCast) ? 0x8000 : 0x0));
  1265. CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
  1266. Token.RemotePort = Sport;
  1267. if (IsBCast) {
  1268. SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
  1269. } else {
  1270. CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
  1271. }
  1272. CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
  1273. if (!IsBCast) {
  1274. Token.ListenPointCount = 1;
  1275. Token.ListenPoints = &ListenPoint;
  1276. Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT;
  1277. CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
  1278. CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
  1279. }
  1280. //
  1281. // Send out the request packet to discover the bootfile.
  1282. //
  1283. for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {
  1284. Token.TimeoutValue = (UINT16)(PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);
  1285. Token.Packet->Dhcp4.Header.Seconds = (UINT16)(PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));
  1286. Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
  1287. if (Token.Status != EFI_TIMEOUT) {
  1288. break;
  1289. }
  1290. }
  1291. if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {
  1292. //
  1293. // No server response our PXE request
  1294. //
  1295. Status = EFI_TIMEOUT;
  1296. }
  1297. if (!EFI_ERROR (Status)) {
  1298. RepIndex = 0;
  1299. SrvIndex = 0;
  1300. Response = Token.ResponseList;
  1301. //
  1302. // Find the right PXE Reply according to server address.
  1303. //
  1304. while (RepIndex < Token.ResponseCount) {
  1305. if (Response->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
  1306. SrvIndex = 0;
  1307. RepIndex++;
  1308. Response = (EFI_DHCP4_PACKET *)((UINT8 *)Response + Response->Size);
  1309. continue;
  1310. }
  1311. while (SrvIndex < IpCount) {
  1312. if (SrvList[SrvIndex].AcceptAnyResponse) {
  1313. break;
  1314. }
  1315. if ((SrvList[SrvIndex].Type == Type) &&
  1316. EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr))
  1317. {
  1318. break;
  1319. }
  1320. SrvIndex++;
  1321. }
  1322. if ((IpCount != SrvIndex) || (IpCount == 0)) {
  1323. break;
  1324. }
  1325. SrvIndex = 0;
  1326. RepIndex++;
  1327. Response = (EFI_DHCP4_PACKET *)((UINT8 *)Response + Response->Size);
  1328. }
  1329. if (RepIndex < Token.ResponseCount) {
  1330. //
  1331. // Cache the right PXE reply packet here, set valid flag later.
  1332. // Especially for PXE discover packet, store it into mode data here.
  1333. //
  1334. if (Private->IsDoDiscover) {
  1335. Status = PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response);
  1336. if (EFI_ERROR (Status)) {
  1337. goto ON_EXIT;
  1338. }
  1339. CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length);
  1340. } else {
  1341. Status = PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response);
  1342. if (EFI_ERROR (Status)) {
  1343. goto ON_EXIT;
  1344. }
  1345. }
  1346. } else {
  1347. //
  1348. // Not found the right PXE reply packet.
  1349. //
  1350. Status = EFI_NOT_FOUND;
  1351. }
  1352. }
  1353. ON_EXIT:
  1354. if (Token.ResponseList != NULL) {
  1355. FreePool (Token.ResponseList);
  1356. }
  1357. if (Token.Packet != NULL) {
  1358. FreePool (Token.Packet);
  1359. }
  1360. return Status;
  1361. }
  1362. /**
  1363. Switch the Ip4 policy to static.
  1364. @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
  1365. @retval EFI_SUCCESS The policy is already configured to static.
  1366. @retval Others Other error as indicated..
  1367. **/
  1368. EFI_STATUS
  1369. PxeBcSetIp4Policy (
  1370. IN PXEBC_PRIVATE_DATA *Private
  1371. )
  1372. {
  1373. EFI_STATUS Status;
  1374. EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
  1375. EFI_IP4_CONFIG2_POLICY Policy;
  1376. UINTN DataSize;
  1377. Ip4Config2 = Private->Ip4Config2;
  1378. DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
  1379. Status = Ip4Config2->GetData (
  1380. Ip4Config2,
  1381. Ip4Config2DataTypePolicy,
  1382. &DataSize,
  1383. &Policy
  1384. );
  1385. if (EFI_ERROR (Status)) {
  1386. return Status;
  1387. }
  1388. if (Policy != Ip4Config2PolicyStatic) {
  1389. Policy = Ip4Config2PolicyStatic;
  1390. Status = Ip4Config2->SetData (
  1391. Ip4Config2,
  1392. Ip4Config2DataTypePolicy,
  1393. sizeof (EFI_IP4_CONFIG2_POLICY),
  1394. &Policy
  1395. );
  1396. if (EFI_ERROR (Status)) {
  1397. return Status;
  1398. }
  1399. }
  1400. return EFI_SUCCESS;
  1401. }
  1402. /**
  1403. Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.
  1404. @param[in] Private Pointer to PxeBc private data.
  1405. @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL
  1406. @retval EFI_SUCCESS The D.O.R.A process successfully finished.
  1407. @retval Others Failed to finish the D.O.R.A process.
  1408. **/
  1409. EFI_STATUS
  1410. PxeBcDhcp4Dora (
  1411. IN PXEBC_PRIVATE_DATA *Private,
  1412. IN EFI_DHCP4_PROTOCOL *Dhcp4
  1413. )
  1414. {
  1415. EFI_PXE_BASE_CODE_MODE *PxeMode;
  1416. EFI_DHCP4_CONFIG_DATA Config;
  1417. EFI_DHCP4_MODE_DATA Mode;
  1418. EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
  1419. UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
  1420. UINT32 OptCount;
  1421. EFI_STATUS Status;
  1422. ASSERT (Dhcp4 != NULL);
  1423. Status = EFI_SUCCESS;
  1424. PxeMode = Private->PxeBc.Mode;
  1425. //
  1426. // Build option list for the request packet.
  1427. //
  1428. OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE);
  1429. ASSERT (OptCount > 0);
  1430. ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA));
  1431. ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
  1432. Config.OptionCount = OptCount;
  1433. Config.OptionList = OptList;
  1434. Config.Dhcp4Callback = PxeBcDhcp4CallBack;
  1435. Config.CallbackContext = Private;
  1436. Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;
  1437. Config.DiscoverTimeout = mPxeDhcpTimeout;
  1438. //
  1439. // Configure the DHCPv4 instance for PXE boot.
  1440. //
  1441. Status = Dhcp4->Configure (Dhcp4, &Config);
  1442. if (EFI_ERROR (Status)) {
  1443. goto ON_EXIT;
  1444. }
  1445. //
  1446. // Initialize the record fields for DHCPv4 offer in private data.
  1447. //
  1448. Private->IsProxyRecved = FALSE;
  1449. Private->OfferNum = 0;
  1450. ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
  1451. ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
  1452. Status = Dhcp4->Start (Dhcp4, NULL);
  1453. if (EFI_ERROR (Status)) {
  1454. if (Status == EFI_ICMP_ERROR) {
  1455. PxeMode->IcmpErrorReceived = TRUE;
  1456. }
  1457. if ((Status == EFI_TIMEOUT) && (Private->OfferNum > 0)) {
  1458. Status = EFI_NO_RESPONSE;
  1459. }
  1460. goto ON_EXIT;
  1461. }
  1462. //
  1463. // Get the acquired IPv4 address and store them.
  1464. //
  1465. Status = Dhcp4->GetModeData (Dhcp4, &Mode);
  1466. if (EFI_ERROR (Status)) {
  1467. goto ON_EXIT;
  1468. }
  1469. ASSERT (Mode.State == Dhcp4Bound);
  1470. CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
  1471. CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
  1472. CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
  1473. CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
  1474. CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
  1475. Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask);
  1476. if (EFI_ERROR (Status)) {
  1477. goto ON_EXIT;
  1478. }
  1479. //
  1480. // Check the selected offer whether BINL retry is needed.
  1481. //
  1482. Status = PxeBcHandleDhcp4Offer (Private);
  1483. AsciiPrint ("\n Station IP address is ");
  1484. PxeBcShowIp4Addr (&Private->StationIp.v4);
  1485. AsciiPrint ("\n");
  1486. ON_EXIT:
  1487. if (EFI_ERROR (Status)) {
  1488. Dhcp4->Stop (Dhcp4);
  1489. Dhcp4->Configure (Dhcp4, NULL);
  1490. } else {
  1491. ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
  1492. Dhcp4->Configure (Dhcp4, &Config);
  1493. Private->IsAddressOk = TRUE;
  1494. }
  1495. return Status;
  1496. }