PxeBcSupport.c 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539
  1. /** @file
  2. Support functions implementation for UefiPxeBc Driver.
  3. Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "PxeBcImpl.h"
  7. /**
  8. Flush the previous configuration using the new station Ip address.
  9. @param[in] Private The pointer to the PxeBc private data.
  10. @param[in] StationIp The pointer to the station Ip address.
  11. @param[in] SubnetMask The pointer to the subnet mask address for v4.
  12. @retval EFI_SUCCESS Successfully flushed the previous configuration.
  13. @retval Others Failed to flush using the new station Ip.
  14. **/
  15. EFI_STATUS
  16. PxeBcFlushStationIp (
  17. PXEBC_PRIVATE_DATA *Private,
  18. EFI_IP_ADDRESS *StationIp OPTIONAL,
  19. EFI_IP_ADDRESS *SubnetMask OPTIONAL
  20. )
  21. {
  22. EFI_PXE_BASE_CODE_MODE *Mode;
  23. EFI_STATUS Status;
  24. EFI_ARP_CONFIG_DATA ArpConfigData;
  25. Mode = Private->PxeBc.Mode;
  26. Status = EFI_SUCCESS;
  27. ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));
  28. if (Mode->UsingIpv6 && (StationIp != NULL)) {
  29. //
  30. // Overwrite Udp6CfgData/Ip6CfgData StationAddress.
  31. //
  32. CopyMem (&Private->Udp6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
  33. CopyMem (&Private->Ip6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
  34. //
  35. // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address.
  36. //
  37. Private->Ip6->Cancel (Private->Ip6, &Private->Icmp6Token);
  38. Private->Ip6->Configure (Private->Ip6, NULL);
  39. Status = Private->Ip6->Configure (Private->Ip6, &Private->Ip6CfgData);
  40. if (EFI_ERROR (Status)) {
  41. goto ON_EXIT;
  42. }
  43. Status = Private->Ip6->Receive (Private->Ip6, &Private->Icmp6Token);
  44. } else {
  45. if (StationIp != NULL) {
  46. //
  47. // Reconfigure the ARP instance with station Ip address.
  48. //
  49. ArpConfigData.SwAddressType = 0x0800;
  50. ArpConfigData.SwAddressLength = (UINT8)sizeof (EFI_IPv4_ADDRESS);
  51. ArpConfigData.StationAddress = StationIp;
  52. Private->Arp->Configure (Private->Arp, NULL);
  53. Private->Arp->Configure (Private->Arp, &ArpConfigData);
  54. //
  55. // Overwrite Udp4CfgData/Ip4CfgData StationAddress.
  56. //
  57. CopyMem (&Private->Udp4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));
  58. CopyMem (&Private->Ip4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));
  59. }
  60. if (SubnetMask != NULL) {
  61. //
  62. // Overwrite Udp4CfgData/Ip4CfgData SubnetMask.
  63. //
  64. CopyMem (&Private->Udp4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));
  65. CopyMem (&Private->Ip4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));
  66. }
  67. if ((StationIp != NULL) && (SubnetMask != NULL)) {
  68. //
  69. // Updated the route table.
  70. //
  71. Mode->RouteTableEntries = 1;
  72. Mode->RouteTable[0].IpAddr.Addr[0] = StationIp->Addr[0] & SubnetMask->Addr[0];
  73. Mode->RouteTable[0].SubnetMask.Addr[0] = SubnetMask->Addr[0];
  74. Mode->RouteTable[0].GwAddr.Addr[0] = 0;
  75. }
  76. if ((StationIp != NULL) || (SubnetMask != NULL)) {
  77. //
  78. // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
  79. //
  80. Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken);
  81. Private->Ip4->Configure (Private->Ip4, NULL);
  82. Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4CfgData);
  83. if (EFI_ERROR (Status)) {
  84. goto ON_EXIT;
  85. }
  86. Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpToken);
  87. }
  88. }
  89. ON_EXIT:
  90. return Status;
  91. }
  92. /**
  93. Notify the callback function when an event is triggered.
  94. @param[in] Event The triggered event.
  95. @param[in] Context The opaque parameter to the function.
  96. **/
  97. VOID
  98. EFIAPI
  99. PxeBcCommonNotify (
  100. IN EFI_EVENT Event,
  101. IN VOID *Context
  102. )
  103. {
  104. *((BOOLEAN *)Context) = TRUE;
  105. }
  106. /**
  107. Do arp resolution from arp cache in PxeBcMode.
  108. @param Mode The pointer to EFI_PXE_BASE_CODE_MODE.
  109. @param Ip4Addr The Ip4 address for resolution.
  110. @param MacAddress The resolved MAC address if the resolution is successful.
  111. The value is undefined if the resolution fails.
  112. @retval TRUE Found an matched entry.
  113. @retval FALSE Did not find a matched entry.
  114. **/
  115. BOOLEAN
  116. PxeBcCheckArpCache (
  117. IN EFI_PXE_BASE_CODE_MODE *Mode,
  118. IN EFI_IPv4_ADDRESS *Ip4Addr,
  119. OUT EFI_MAC_ADDRESS *MacAddress
  120. )
  121. {
  122. UINT32 Index;
  123. ASSERT (!Mode->UsingIpv6);
  124. //
  125. // Check whether the current Arp cache in mode data contains this information or not.
  126. //
  127. for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {
  128. if (EFI_IP4_EQUAL (&Mode->ArpCache[Index].IpAddr.v4, Ip4Addr)) {
  129. CopyMem (
  130. MacAddress,
  131. &Mode->ArpCache[Index].MacAddr,
  132. sizeof (EFI_MAC_ADDRESS)
  133. );
  134. return TRUE;
  135. }
  136. }
  137. return FALSE;
  138. }
  139. /**
  140. Update the arp cache periodically.
  141. @param Event The pointer to EFI_PXE_BC_PROTOCOL.
  142. @param Context Context of the timer event.
  143. **/
  144. VOID
  145. EFIAPI
  146. PxeBcArpCacheUpdate (
  147. IN EFI_EVENT Event,
  148. IN VOID *Context
  149. )
  150. {
  151. PXEBC_PRIVATE_DATA *Private;
  152. EFI_PXE_BASE_CODE_MODE *Mode;
  153. EFI_ARP_FIND_DATA *ArpEntry;
  154. UINT32 EntryLength;
  155. UINT32 EntryCount;
  156. UINT32 Index;
  157. EFI_STATUS Status;
  158. Private = (PXEBC_PRIVATE_DATA *)Context;
  159. Mode = Private->PxeBc.Mode;
  160. ASSERT (!Mode->UsingIpv6);
  161. //
  162. // Get the current Arp cache from Arp driver.
  163. //
  164. Status = Private->Arp->Find (
  165. Private->Arp,
  166. TRUE,
  167. NULL,
  168. &EntryLength,
  169. &EntryCount,
  170. &ArpEntry,
  171. TRUE
  172. );
  173. if (EFI_ERROR (Status)) {
  174. return;
  175. }
  176. //
  177. // Update the Arp cache in mode data.
  178. //
  179. Mode->ArpCacheEntries = MIN (EntryCount, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES);
  180. for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {
  181. CopyMem (
  182. &Mode->ArpCache[Index].IpAddr,
  183. ArpEntry + 1,
  184. ArpEntry->SwAddressLength
  185. );
  186. CopyMem (
  187. &Mode->ArpCache[Index].MacAddr,
  188. (UINT8 *)(ArpEntry + 1) + ArpEntry->SwAddressLength,
  189. ArpEntry->HwAddressLength
  190. );
  191. ArpEntry = (EFI_ARP_FIND_DATA *)((UINT8 *)ArpEntry + EntryLength);
  192. }
  193. }
  194. /**
  195. Notify function to handle the received ICMP message in DPC.
  196. @param Context The PXEBC private data.
  197. **/
  198. VOID
  199. EFIAPI
  200. PxeBcIcmpErrorDpcHandle (
  201. IN VOID *Context
  202. )
  203. {
  204. EFI_STATUS Status;
  205. EFI_IP4_RECEIVE_DATA *RxData;
  206. EFI_IP4_PROTOCOL *Ip4;
  207. PXEBC_PRIVATE_DATA *Private;
  208. EFI_PXE_BASE_CODE_MODE *Mode;
  209. UINT8 Type;
  210. UINTN Index;
  211. UINT32 CopiedLen;
  212. UINT8 *IcmpError;
  213. Private = (PXEBC_PRIVATE_DATA *)Context;
  214. Mode = &Private->Mode;
  215. Status = Private->IcmpToken.Status;
  216. RxData = Private->IcmpToken.Packet.RxData;
  217. Ip4 = Private->Ip4;
  218. ASSERT (!Mode->UsingIpv6);
  219. if (Status == EFI_ABORTED) {
  220. //
  221. // It's triggered by user cancellation.
  222. //
  223. return;
  224. }
  225. if (RxData == NULL) {
  226. goto ON_EXIT;
  227. }
  228. if (Status != EFI_ICMP_ERROR) {
  229. //
  230. // The return status should be recognized as EFI_ICMP_ERROR.
  231. //
  232. goto ON_RECYCLE;
  233. }
  234. if ((EFI_IP4 (RxData->Header->SourceAddress) != 0) &&
  235. (NTOHL (Mode->SubnetMask.Addr[0]) != 0) &&
  236. IP4_NET_EQUAL (NTOHL (Mode->StationIp.Addr[0]), EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0])) &&
  237. !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0])))
  238. {
  239. //
  240. // The source address of the received packet should be a valid unicast address.
  241. //
  242. goto ON_RECYCLE;
  243. }
  244. if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {
  245. //
  246. // The destination address of the received packet should be equal to the host address.
  247. //
  248. goto ON_RECYCLE;
  249. }
  250. //
  251. // The protocol has been configured to only receive ICMP packet.
  252. //
  253. ASSERT (RxData->Header->Protocol == EFI_IP_PROTO_ICMP);
  254. Type = *((UINT8 *)RxData->FragmentTable[0].FragmentBuffer);
  255. if ((Type != ICMP_DEST_UNREACHABLE) &&
  256. (Type != ICMP_SOURCE_QUENCH) &&
  257. (Type != ICMP_REDIRECT) &&
  258. (Type != ICMP_TIME_EXCEEDED) &&
  259. (Type != ICMP_PARAMETER_PROBLEM))
  260. {
  261. //
  262. // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
  263. //
  264. goto ON_RECYCLE;
  265. }
  266. //
  267. // Copy the right ICMP error message into mode data.
  268. //
  269. CopiedLen = 0;
  270. IcmpError = (UINT8 *)&Mode->IcmpError;
  271. for (Index = 0; Index < RxData->FragmentCount; Index++) {
  272. CopiedLen += RxData->FragmentTable[Index].FragmentLength;
  273. if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
  274. CopyMem (
  275. IcmpError,
  276. RxData->FragmentTable[Index].FragmentBuffer,
  277. RxData->FragmentTable[Index].FragmentLength
  278. );
  279. } else {
  280. CopyMem (
  281. IcmpError,
  282. RxData->FragmentTable[Index].FragmentBuffer,
  283. CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
  284. );
  285. }
  286. IcmpError += CopiedLen;
  287. }
  288. ON_RECYCLE:
  289. gBS->SignalEvent (RxData->RecycleSignal);
  290. ON_EXIT:
  291. Private->IcmpToken.Status = EFI_NOT_READY;
  292. Ip4->Receive (Ip4, &Private->IcmpToken);
  293. }
  294. /**
  295. Callback function to update the latest ICMP6 error message.
  296. @param Event The event signalled.
  297. @param Context The context passed in using the event notifier.
  298. **/
  299. VOID
  300. EFIAPI
  301. PxeBcIcmpErrorUpdate (
  302. IN EFI_EVENT Event,
  303. IN VOID *Context
  304. )
  305. {
  306. QueueDpc (TPL_CALLBACK, PxeBcIcmpErrorDpcHandle, Context);
  307. }
  308. /**
  309. Notify function to handle the received ICMP6 message in DPC.
  310. @param Context The PXEBC private data.
  311. **/
  312. VOID
  313. EFIAPI
  314. PxeBcIcmp6ErrorDpcHandle (
  315. IN VOID *Context
  316. )
  317. {
  318. PXEBC_PRIVATE_DATA *Private;
  319. EFI_IP6_RECEIVE_DATA *RxData;
  320. EFI_IP6_PROTOCOL *Ip6;
  321. EFI_PXE_BASE_CODE_MODE *Mode;
  322. EFI_STATUS Status;
  323. UINTN Index;
  324. UINT8 Type;
  325. UINT32 CopiedLen;
  326. UINT8 *Icmp6Error;
  327. Private = (PXEBC_PRIVATE_DATA *)Context;
  328. Mode = &Private->Mode;
  329. Status = Private->Icmp6Token.Status;
  330. RxData = Private->Icmp6Token.Packet.RxData;
  331. Ip6 = Private->Ip6;
  332. ASSERT (Mode->UsingIpv6);
  333. if (Status == EFI_ABORTED) {
  334. //
  335. // It's triggered by user cancellation.
  336. //
  337. return;
  338. }
  339. if (RxData == NULL) {
  340. goto ON_EXIT;
  341. }
  342. if (Status != EFI_ICMP_ERROR) {
  343. //
  344. // The return status should be recognized as EFI_ICMP_ERROR.
  345. //
  346. goto ON_RECYCLE;
  347. }
  348. if (!NetIp6IsValidUnicast (&RxData->Header->SourceAddress)) {
  349. //
  350. // The source address of the received packet should be a valid unicast address.
  351. //
  352. goto ON_RECYCLE;
  353. }
  354. if (!NetIp6IsUnspecifiedAddr (&Mode->StationIp.v6) &&
  355. !EFI_IP6_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v6))
  356. {
  357. //
  358. // The destination address of the received packet should be equal to the host address.
  359. //
  360. goto ON_RECYCLE;
  361. }
  362. //
  363. // The protocol has been configured to only receive ICMP packet.
  364. //
  365. ASSERT (RxData->Header->NextHeader == IP6_ICMP);
  366. Type = *((UINT8 *)RxData->FragmentTable[0].FragmentBuffer);
  367. if ((Type != ICMP_V6_DEST_UNREACHABLE) &&
  368. (Type != ICMP_V6_PACKET_TOO_BIG) &&
  369. (Type != ICMP_V6_TIME_EXCEEDED) &&
  370. (Type != ICMP_V6_PARAMETER_PROBLEM))
  371. {
  372. //
  373. // The type of the receveid packet should be an ICMP6 error message.
  374. //
  375. goto ON_RECYCLE;
  376. }
  377. //
  378. // Copy the right ICMP6 error message into mode data.
  379. //
  380. CopiedLen = 0;
  381. Icmp6Error = (UINT8 *)&Mode->IcmpError;
  382. for (Index = 0; Index < RxData->FragmentCount; Index++) {
  383. CopiedLen += RxData->FragmentTable[Index].FragmentLength;
  384. if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
  385. CopyMem (
  386. Icmp6Error,
  387. RxData->FragmentTable[Index].FragmentBuffer,
  388. RxData->FragmentTable[Index].FragmentLength
  389. );
  390. } else {
  391. CopyMem (
  392. Icmp6Error,
  393. RxData->FragmentTable[Index].FragmentBuffer,
  394. CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
  395. );
  396. }
  397. Icmp6Error += CopiedLen;
  398. }
  399. ON_RECYCLE:
  400. gBS->SignalEvent (RxData->RecycleSignal);
  401. ON_EXIT:
  402. Private->Icmp6Token.Status = EFI_NOT_READY;
  403. Ip6->Receive (Ip6, &Private->Icmp6Token);
  404. }
  405. /**
  406. Callback function to update the latest ICMP6 error message.
  407. @param Event The event signalled.
  408. @param Context The context passed in using the event notifier.
  409. **/
  410. VOID
  411. EFIAPI
  412. PxeBcIcmp6ErrorUpdate (
  413. IN EFI_EVENT Event,
  414. IN VOID *Context
  415. )
  416. {
  417. QueueDpc (TPL_CALLBACK, PxeBcIcmp6ErrorDpcHandle, Context);
  418. }
  419. /**
  420. This function is to configure a UDPv4 instance for UdpWrite.
  421. @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
  422. @param[in] StationIp The pointer to the station address.
  423. @param[in] SubnetMask The pointer to the subnet mask.
  424. @param[in] Gateway The pointer to the gateway address.
  425. @param[in, out] SrcPort The pointer to the source port.
  426. @param[in] DoNotFragment If TRUE, fragment is not enabled.
  427. Otherwise, fragment is enabled.
  428. @param[in] Ttl The time to live field of the IP header.
  429. @param[in] ToS The type of service field of the IP header.
  430. @retval EFI_SUCCESS Successfully configured this instance.
  431. @retval Others Failed to configure this instance.
  432. **/
  433. EFI_STATUS
  434. PxeBcConfigUdp4Write (
  435. IN EFI_UDP4_PROTOCOL *Udp4,
  436. IN EFI_IPv4_ADDRESS *StationIp,
  437. IN EFI_IPv4_ADDRESS *SubnetMask,
  438. IN EFI_IPv4_ADDRESS *Gateway,
  439. IN OUT UINT16 *SrcPort,
  440. IN BOOLEAN DoNotFragment,
  441. IN UINT8 Ttl,
  442. IN UINT8 ToS
  443. )
  444. {
  445. EFI_UDP4_CONFIG_DATA Udp4CfgData;
  446. EFI_STATUS Status;
  447. ZeroMem (&Udp4CfgData, sizeof (Udp4CfgData));
  448. Udp4CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME;
  449. Udp4CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;
  450. Udp4CfgData.TypeOfService = ToS;
  451. Udp4CfgData.TimeToLive = Ttl;
  452. Udp4CfgData.AllowDuplicatePort = TRUE;
  453. Udp4CfgData.DoNotFragment = DoNotFragment;
  454. CopyMem (&Udp4CfgData.StationAddress, StationIp, sizeof (*StationIp));
  455. CopyMem (&Udp4CfgData.SubnetMask, SubnetMask, sizeof (*SubnetMask));
  456. Udp4CfgData.StationPort = *SrcPort;
  457. //
  458. // Reset the UDPv4 instance.
  459. //
  460. Udp4->Configure (Udp4, NULL);
  461. Status = Udp4->Configure (Udp4, &Udp4CfgData);
  462. if (!EFI_ERROR (Status) && !EFI_IP4_EQUAL (Gateway, &mZeroIp4Addr)) {
  463. //
  464. // The basic configuration is OK, need to add the default route entry
  465. //
  466. Status = Udp4->Routes (Udp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, Gateway);
  467. if (EFI_ERROR (Status)) {
  468. Udp4->Configure (Udp4, NULL);
  469. }
  470. }
  471. if (!EFI_ERROR (Status) && (*SrcPort == 0)) {
  472. Udp4->GetModeData (Udp4, &Udp4CfgData, NULL, NULL, NULL);
  473. *SrcPort = Udp4CfgData.StationPort;
  474. }
  475. return Status;
  476. }
  477. /**
  478. This function is to configure a UDPv6 instance for UdpWrite.
  479. @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
  480. @param[in] StationIp The pointer to the station address.
  481. @param[in, out] SrcPort The pointer to the source port.
  482. @retval EFI_SUCCESS Successfully configured this instance.
  483. @retval Others Failed to configure this instance.
  484. **/
  485. EFI_STATUS
  486. PxeBcConfigUdp6Write (
  487. IN EFI_UDP6_PROTOCOL *Udp6,
  488. IN EFI_IPv6_ADDRESS *StationIp,
  489. IN OUT UINT16 *SrcPort
  490. )
  491. {
  492. EFI_UDP6_CONFIG_DATA CfgData;
  493. EFI_STATUS Status;
  494. ZeroMem (&CfgData, sizeof (EFI_UDP6_CONFIG_DATA));
  495. CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;
  496. CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME;
  497. CfgData.HopLimit = PXEBC_DEFAULT_HOPLIMIT;
  498. CfgData.AllowDuplicatePort = TRUE;
  499. CfgData.StationPort = *SrcPort;
  500. CopyMem (&CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
  501. //
  502. // Reset the UDPv6 instance.
  503. //
  504. Udp6->Configure (Udp6, NULL);
  505. Status = Udp6->Configure (Udp6, &CfgData);
  506. if (EFI_ERROR (Status)) {
  507. return Status;
  508. }
  509. if (!EFI_ERROR (Status) && (*SrcPort == 0)) {
  510. Udp6->GetModeData (Udp6, &CfgData, NULL, NULL, NULL);
  511. *SrcPort = CfgData.StationPort;
  512. }
  513. return Status;
  514. }
  515. /**
  516. This function is to configure a UDPv4 instance for UdpWrite.
  517. @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
  518. @param[in] Session The pointer to the UDP4 session data.
  519. @param[in] TimeoutEvent The event for timeout.
  520. @param[in] Gateway The pointer to the gateway address.
  521. @param[in] HeaderSize An optional field which may be set to the length of a header
  522. at HeaderPtr to be prefixed to the data at BufferPtr.
  523. @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
  524. prefixed to the data at BufferPtr.
  525. @param[in] BufferSize A pointer to the size of the data at BufferPtr.
  526. @param[in] BufferPtr A pointer to the data to be written.
  527. @retval EFI_SUCCESS Successfully send out data using Udp4Write.
  528. @retval Others Failed to send out data.
  529. **/
  530. EFI_STATUS
  531. PxeBcUdp4Write (
  532. IN EFI_UDP4_PROTOCOL *Udp4,
  533. IN EFI_UDP4_SESSION_DATA *Session,
  534. IN EFI_EVENT TimeoutEvent,
  535. IN EFI_IPv4_ADDRESS *Gateway OPTIONAL,
  536. IN UINTN *HeaderSize OPTIONAL,
  537. IN VOID *HeaderPtr OPTIONAL,
  538. IN UINTN *BufferSize,
  539. IN VOID *BufferPtr
  540. )
  541. {
  542. EFI_UDP4_COMPLETION_TOKEN Token;
  543. EFI_UDP4_TRANSMIT_DATA *TxData;
  544. UINT32 TxLength;
  545. UINT32 FragCount;
  546. UINT32 DataLength;
  547. BOOLEAN IsDone;
  548. EFI_STATUS Status;
  549. //
  550. // Arrange one fragment buffer for data, and another fragment buffer for header if has.
  551. //
  552. FragCount = (HeaderSize != NULL) ? 2 : 1;
  553. TxLength = sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA);
  554. TxData = (EFI_UDP4_TRANSMIT_DATA *)AllocateZeroPool (TxLength);
  555. if (TxData == NULL) {
  556. return EFI_OUT_OF_RESOURCES;
  557. }
  558. TxData->FragmentCount = FragCount;
  559. TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32)*BufferSize;
  560. TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
  561. DataLength = (UINT32)*BufferSize;
  562. if (HeaderSize != NULL) {
  563. TxData->FragmentTable[0].FragmentLength = (UINT32)*HeaderSize;
  564. TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
  565. DataLength += (UINT32)*HeaderSize;
  566. }
  567. if (Gateway != NULL) {
  568. TxData->GatewayAddress = Gateway;
  569. }
  570. TxData->UdpSessionData = Session;
  571. TxData->DataLength = DataLength;
  572. Token.Packet.TxData = TxData;
  573. Token.Status = EFI_NOT_READY;
  574. IsDone = FALSE;
  575. Status = gBS->CreateEvent (
  576. EVT_NOTIFY_SIGNAL,
  577. TPL_NOTIFY,
  578. PxeBcCommonNotify,
  579. &IsDone,
  580. &Token.Event
  581. );
  582. if (EFI_ERROR (Status)) {
  583. goto ON_EXIT;
  584. }
  585. Status = Udp4->Transmit (Udp4, &Token);
  586. if (EFI_ERROR (Status)) {
  587. goto ON_EXIT;
  588. }
  589. //
  590. // Poll the UDPv6 read instance if no packet received and no timeout triggered.
  591. //
  592. while (!IsDone &&
  593. Token.Status == EFI_NOT_READY &&
  594. EFI_ERROR (gBS->CheckEvent (TimeoutEvent)))
  595. {
  596. Udp4->Poll (Udp4);
  597. }
  598. Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;
  599. ON_EXIT:
  600. if (Token.Event != NULL) {
  601. gBS->CloseEvent (Token.Event);
  602. }
  603. FreePool (TxData);
  604. return Status;
  605. }
  606. /**
  607. This function is to configure a UDPv4 instance for UdpWrite.
  608. @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
  609. @param[in] Session The pointer to the UDP6 session data.
  610. @param[in] TimeoutEvent The event for timeout.
  611. @param[in] HeaderSize An optional field which may be set to the length of a header
  612. at HeaderPtr to be prefixed to the data at BufferPtr.
  613. @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
  614. prefixed to the data at BufferPtr.
  615. @param[in] BufferSize A pointer to the size of the data at BufferPtr.
  616. @param[in] BufferPtr A pointer to the data to be written.
  617. @retval EFI_SUCCESS Successfully sent out data using Udp6Write.
  618. @retval Others Failed to send out data.
  619. **/
  620. EFI_STATUS
  621. PxeBcUdp6Write (
  622. IN EFI_UDP6_PROTOCOL *Udp6,
  623. IN EFI_UDP6_SESSION_DATA *Session,
  624. IN EFI_EVENT TimeoutEvent,
  625. IN UINTN *HeaderSize OPTIONAL,
  626. IN VOID *HeaderPtr OPTIONAL,
  627. IN UINTN *BufferSize,
  628. IN VOID *BufferPtr
  629. )
  630. {
  631. EFI_UDP6_COMPLETION_TOKEN Token;
  632. EFI_UDP6_TRANSMIT_DATA *TxData;
  633. UINT32 TxLength;
  634. UINT32 FragCount;
  635. UINT32 DataLength;
  636. BOOLEAN IsDone;
  637. EFI_STATUS Status;
  638. //
  639. // Arrange one fragment buffer for data, and another fragment buffer for header if has.
  640. //
  641. FragCount = (HeaderSize != NULL) ? 2 : 1;
  642. TxLength = sizeof (EFI_UDP6_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP6_FRAGMENT_DATA);
  643. TxData = (EFI_UDP6_TRANSMIT_DATA *)AllocateZeroPool (TxLength);
  644. if (TxData == NULL) {
  645. return EFI_OUT_OF_RESOURCES;
  646. }
  647. TxData->FragmentCount = FragCount;
  648. TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32)*BufferSize;
  649. TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
  650. DataLength = (UINT32)*BufferSize;
  651. if (HeaderSize != NULL) {
  652. TxData->FragmentTable[0].FragmentLength = (UINT32)*HeaderSize;
  653. TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
  654. DataLength += (UINT32)*HeaderSize;
  655. }
  656. TxData->UdpSessionData = Session;
  657. TxData->DataLength = DataLength;
  658. Token.Packet.TxData = TxData;
  659. Token.Status = EFI_NOT_READY;
  660. IsDone = FALSE;
  661. Status = gBS->CreateEvent (
  662. EVT_NOTIFY_SIGNAL,
  663. TPL_NOTIFY,
  664. PxeBcCommonNotify,
  665. &IsDone,
  666. &Token.Event
  667. );
  668. if (EFI_ERROR (Status)) {
  669. goto ON_EXIT;
  670. }
  671. Status = Udp6->Transmit (Udp6, &Token);
  672. if (EFI_ERROR (Status)) {
  673. goto ON_EXIT;
  674. }
  675. //
  676. // Poll the UDPv6 read instance if no packet received and no timeout triggered.
  677. //
  678. while (!IsDone &&
  679. Token.Status == EFI_NOT_READY &&
  680. EFI_ERROR (gBS->CheckEvent (TimeoutEvent)))
  681. {
  682. Udp6->Poll (Udp6);
  683. }
  684. Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;
  685. ON_EXIT:
  686. if (Token.Event != NULL) {
  687. gBS->CloseEvent (Token.Event);
  688. }
  689. FreePool (TxData);
  690. return Status;
  691. }
  692. /**
  693. Check the received packet using the Ip filter.
  694. @param[in] Mode The pointer to the mode data of PxeBc.
  695. @param[in] Session The pointer to the current UDPv4 session.
  696. @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
  697. @retval TRUE Passed the Ip filter successfully.
  698. @retval FALSE Failed to pass the Ip filter.
  699. **/
  700. BOOLEAN
  701. PxeBcCheckByIpFilter (
  702. IN EFI_PXE_BASE_CODE_MODE *Mode,
  703. IN VOID *Session,
  704. IN UINT16 OpFlags
  705. )
  706. {
  707. EFI_IP_ADDRESS DestinationIp;
  708. UINTN Index;
  709. if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) == 0) {
  710. return TRUE;
  711. }
  712. if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) {
  713. return TRUE;
  714. }
  715. //
  716. // Convert the destination address in session data to host order.
  717. //
  718. if (Mode->UsingIpv6) {
  719. CopyMem (
  720. &DestinationIp,
  721. &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress,
  722. sizeof (EFI_IPv6_ADDRESS)
  723. );
  724. NTOHLLL (&DestinationIp.v6);
  725. } else {
  726. ZeroMem (&DestinationIp, sizeof (EFI_IP_ADDRESS));
  727. CopyMem (
  728. &DestinationIp,
  729. &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress,
  730. sizeof (EFI_IPv4_ADDRESS)
  731. );
  732. EFI_NTOHL (DestinationIp);
  733. }
  734. if (((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0) &&
  735. (IP4_IS_MULTICAST (DestinationIp.Addr[0]) ||
  736. IP6_IS_MULTICAST (&DestinationIp)))
  737. {
  738. return TRUE;
  739. }
  740. if (((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) &&
  741. IP4_IS_LOCAL_BROADCAST (DestinationIp.Addr[0]))
  742. {
  743. ASSERT (!Mode->UsingIpv6);
  744. return TRUE;
  745. }
  746. if (((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) &&
  747. (EFI_IP4_EQUAL (&Mode->StationIp.v4, &DestinationIp) ||
  748. EFI_IP6_EQUAL (&Mode->StationIp.v6, &DestinationIp)))
  749. {
  750. //
  751. // Matched if the dest address is equal to the station address.
  752. //
  753. return TRUE;
  754. }
  755. for (Index = 0; Index < Mode->IpFilter.IpCnt; Index++) {
  756. ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT);
  757. if (EFI_IP4_EQUAL (&Mode->IpFilter.IpList[Index].v4, &DestinationIp) ||
  758. EFI_IP6_EQUAL (&Mode->IpFilter.IpList[Index].v6, &DestinationIp))
  759. {
  760. //
  761. // Matched if the dest address is equal to any of address in the filter list.
  762. //
  763. return TRUE;
  764. }
  765. }
  766. return FALSE;
  767. }
  768. /**
  769. Filter the received packet using the destination Ip.
  770. @param[in] Mode The pointer to the mode data of PxeBc.
  771. @param[in] Session The pointer to the current UDPv4 session.
  772. @param[in, out] DestIp The pointer to the destination Ip address.
  773. @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
  774. @retval TRUE Passed the IPv4 filter successfully.
  775. @retval FALSE Failed to pass the IPv4 filter.
  776. **/
  777. BOOLEAN
  778. PxeBcCheckByDestIp (
  779. IN EFI_PXE_BASE_CODE_MODE *Mode,
  780. IN VOID *Session,
  781. IN OUT EFI_IP_ADDRESS *DestIp,
  782. IN UINT16 OpFlags
  783. )
  784. {
  785. if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) != 0) {
  786. //
  787. // Copy the destination address from the received packet if accept any.
  788. //
  789. if (DestIp != NULL) {
  790. if (Mode->UsingIpv6) {
  791. CopyMem (
  792. DestIp,
  793. &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress,
  794. sizeof (EFI_IPv6_ADDRESS)
  795. );
  796. } else {
  797. ZeroMem (DestIp, sizeof (EFI_IP_ADDRESS));
  798. CopyMem (
  799. DestIp,
  800. &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress,
  801. sizeof (EFI_IPv4_ADDRESS)
  802. );
  803. }
  804. }
  805. return TRUE;
  806. } else if ((DestIp != NULL) &&
  807. (EFI_IP4_EQUAL (DestIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||
  808. EFI_IP6_EQUAL (DestIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress)))
  809. {
  810. //
  811. // The destination address in the received packet is matched if present.
  812. //
  813. return TRUE;
  814. } else if (EFI_IP4_EQUAL (&Mode->StationIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||
  815. EFI_IP6_EQUAL (&Mode->StationIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress))
  816. {
  817. //
  818. // The destination address in the received packet is equal to the host address.
  819. //
  820. return TRUE;
  821. }
  822. return FALSE;
  823. }
  824. /**
  825. Check the received packet using the destination port.
  826. @param[in] Mode The pointer to the mode data of PxeBc.
  827. @param[in] Session The pointer to the current UDPv4 session.
  828. @param[in, out] DestPort The pointer to the destination port.
  829. @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
  830. @retval TRUE Passed the IPv4 filter successfully.
  831. @retval FALSE Failed to pass the IPv4 filter.
  832. **/
  833. BOOLEAN
  834. PxeBcCheckByDestPort (
  835. IN EFI_PXE_BASE_CODE_MODE *Mode,
  836. IN VOID *Session,
  837. IN OUT UINT16 *DestPort,
  838. IN UINT16 OpFlags
  839. )
  840. {
  841. UINT16 Port;
  842. if (Mode->UsingIpv6) {
  843. Port = ((EFI_UDP6_SESSION_DATA *)Session)->DestinationPort;
  844. } else {
  845. Port = ((EFI_UDP4_SESSION_DATA *)Session)->DestinationPort;
  846. }
  847. if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0) {
  848. //
  849. // Return the destination port in the received packet if accept any.
  850. //
  851. if (DestPort != NULL) {
  852. *DestPort = Port;
  853. }
  854. return TRUE;
  855. } else if ((DestPort != NULL) && (*DestPort == Port)) {
  856. //
  857. // The destination port in the received packet is matched if present.
  858. //
  859. return TRUE;
  860. }
  861. return FALSE;
  862. }
  863. /**
  864. Filter the received packet using the source Ip.
  865. @param[in] Mode The pointer to the mode data of PxeBc.
  866. @param[in] Session The pointer to the current UDPv4 session.
  867. @param[in, out] SrcIp The pointer to the source Ip address.
  868. @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
  869. @retval TRUE Passed the IPv4 filter successfully.
  870. @retval FALSE Failed to pass the IPv4 filter.
  871. **/
  872. BOOLEAN
  873. PxeBcFilterBySrcIp (
  874. IN EFI_PXE_BASE_CODE_MODE *Mode,
  875. IN VOID *Session,
  876. IN OUT EFI_IP_ADDRESS *SrcIp,
  877. IN UINT16 OpFlags
  878. )
  879. {
  880. if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0) {
  881. //
  882. // Copy the source address from the received packet if accept any.
  883. //
  884. if (SrcIp != NULL) {
  885. if (Mode->UsingIpv6) {
  886. CopyMem (
  887. SrcIp,
  888. &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress,
  889. sizeof (EFI_IPv6_ADDRESS)
  890. );
  891. } else {
  892. ZeroMem (SrcIp, sizeof (EFI_IP_ADDRESS));
  893. CopyMem (
  894. SrcIp,
  895. &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress,
  896. sizeof (EFI_IPv4_ADDRESS)
  897. );
  898. }
  899. }
  900. return TRUE;
  901. } else if ((SrcIp != NULL) &&
  902. (EFI_IP4_EQUAL (SrcIp, &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress) ||
  903. EFI_IP6_EQUAL (SrcIp, &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress)))
  904. {
  905. //
  906. // The source address in the received packet is matched if present.
  907. //
  908. return TRUE;
  909. }
  910. return FALSE;
  911. }
  912. /**
  913. Filter the received packet using the source port.
  914. @param[in] Mode The pointer to the mode data of PxeBc.
  915. @param[in] Session The pointer to the current UDPv4 session.
  916. @param[in, out] SrcPort The pointer to the source port.
  917. @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
  918. @retval TRUE Passed the IPv4 filter successfully.
  919. @retval FALSE Failed to pass the IPv4 filter.
  920. **/
  921. BOOLEAN
  922. PxeBcFilterBySrcPort (
  923. IN EFI_PXE_BASE_CODE_MODE *Mode,
  924. IN VOID *Session,
  925. IN OUT UINT16 *SrcPort,
  926. IN UINT16 OpFlags
  927. )
  928. {
  929. UINT16 Port;
  930. if (Mode->UsingIpv6) {
  931. Port = ((EFI_UDP6_SESSION_DATA *)Session)->SourcePort;
  932. } else {
  933. Port = ((EFI_UDP4_SESSION_DATA *)Session)->SourcePort;
  934. }
  935. if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0) {
  936. //
  937. // Return the source port in the received packet if accept any.
  938. //
  939. if (SrcPort != NULL) {
  940. *SrcPort = Port;
  941. }
  942. return TRUE;
  943. } else if ((SrcPort != NULL) && (*SrcPort == Port)) {
  944. //
  945. // The source port in the received packet is matched if present.
  946. //
  947. return TRUE;
  948. }
  949. return FALSE;
  950. }
  951. /**
  952. This function is to receive packet using Udp4Read.
  953. @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
  954. @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN.
  955. @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
  956. @param[in] TimeoutEvent The event for timeout.
  957. @param[in] OpFlags The UDP operation flags.
  958. @param[in] IsDone The pointer to the IsDone flag.
  959. @param[out] IsMatched The pointer to the IsMatched flag.
  960. @param[in, out] DestIp The pointer to the destination address.
  961. @param[in, out] DestPort The pointer to the destination port.
  962. @param[in, out] SrcIp The pointer to the source address.
  963. @param[in, out] SrcPort The pointer to the source port.
  964. @retval EFI_SUCCESS Successfully read the data using Udp4.
  965. @retval Others Failed to send out data.
  966. **/
  967. EFI_STATUS
  968. PxeBcUdp4Read (
  969. IN EFI_UDP4_PROTOCOL *Udp4,
  970. IN EFI_UDP4_COMPLETION_TOKEN *Token,
  971. IN EFI_PXE_BASE_CODE_MODE *Mode,
  972. IN EFI_EVENT TimeoutEvent,
  973. IN UINT16 OpFlags,
  974. IN BOOLEAN *IsDone,
  975. OUT BOOLEAN *IsMatched,
  976. IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL,
  977. IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL,
  978. IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL,
  979. IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL
  980. )
  981. {
  982. EFI_UDP4_RECEIVE_DATA *RxData;
  983. EFI_UDP4_SESSION_DATA *Session;
  984. EFI_STATUS Status;
  985. Token->Status = EFI_NOT_READY;
  986. *IsDone = FALSE;
  987. Status = Udp4->Receive (Udp4, Token);
  988. if (EFI_ERROR (Status)) {
  989. return Status;
  990. }
  991. //
  992. // Poll the UDPv6 read instance if no packet received and no timeout triggered.
  993. //
  994. while (!(*IsDone) &&
  995. Token->Status == EFI_NOT_READY &&
  996. EFI_ERROR (gBS->CheckEvent (TimeoutEvent)))
  997. {
  998. //
  999. // Poll the token until reply/ICMPv6 error message received or timeout.
  1000. //
  1001. Udp4->Poll (Udp4);
  1002. if ((Token->Status == EFI_ICMP_ERROR) ||
  1003. (Token->Status == EFI_NETWORK_UNREACHABLE) ||
  1004. (Token->Status == EFI_HOST_UNREACHABLE) ||
  1005. (Token->Status == EFI_PROTOCOL_UNREACHABLE) ||
  1006. (Token->Status == EFI_PORT_UNREACHABLE))
  1007. {
  1008. break;
  1009. }
  1010. }
  1011. Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;
  1012. if (!EFI_ERROR (Status)) {
  1013. //
  1014. // check whether this packet matches the filters
  1015. //
  1016. RxData = Token->Packet.RxData;
  1017. Session = &RxData->UdpSession;
  1018. *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);
  1019. if (*IsMatched) {
  1020. *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);
  1021. }
  1022. if (*IsMatched) {
  1023. *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);
  1024. }
  1025. if (*IsMatched) {
  1026. *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);
  1027. }
  1028. if (*IsMatched) {
  1029. *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);
  1030. }
  1031. if (!(*IsMatched)) {
  1032. //
  1033. // Recycle the receiving buffer if not matched.
  1034. //
  1035. gBS->SignalEvent (RxData->RecycleSignal);
  1036. }
  1037. }
  1038. return Status;
  1039. }
  1040. /**
  1041. This function is to receive packets using Udp6Read.
  1042. @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
  1043. @param[in] Token The pointer to EFI_UDP6_COMPLETION_TOKEN.
  1044. @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
  1045. @param[in] TimeoutEvent The event for timeout.
  1046. @param[in] OpFlags The UDP operation flags.
  1047. @param[in] IsDone The pointer to the IsDone flag.
  1048. @param[out] IsMatched The pointer to the IsMatched flag.
  1049. @param[in, out] DestIp The pointer to the destination address.
  1050. @param[in, out] DestPort The pointer to the destination port.
  1051. @param[in, out] SrcIp The pointer to the source address.
  1052. @param[in, out] SrcPort The pointer to the source port.
  1053. @retval EFI_SUCCESS Successfully read data using Udp6.
  1054. @retval Others Failed to send out data.
  1055. **/
  1056. EFI_STATUS
  1057. PxeBcUdp6Read (
  1058. IN EFI_UDP6_PROTOCOL *Udp6,
  1059. IN EFI_UDP6_COMPLETION_TOKEN *Token,
  1060. IN EFI_PXE_BASE_CODE_MODE *Mode,
  1061. IN EFI_EVENT TimeoutEvent,
  1062. IN UINT16 OpFlags,
  1063. IN BOOLEAN *IsDone,
  1064. OUT BOOLEAN *IsMatched,
  1065. IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL,
  1066. IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL,
  1067. IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL,
  1068. IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL
  1069. )
  1070. {
  1071. EFI_UDP6_RECEIVE_DATA *RxData;
  1072. EFI_UDP6_SESSION_DATA *Session;
  1073. EFI_STATUS Status;
  1074. Token->Status = EFI_NOT_READY;
  1075. *IsDone = FALSE;
  1076. Status = Udp6->Receive (Udp6, Token);
  1077. if (EFI_ERROR (Status)) {
  1078. return Status;
  1079. }
  1080. //
  1081. // Poll the UDPv6 read instance if no packet received and no timeout triggered.
  1082. //
  1083. while (!(*IsDone) &&
  1084. Token->Status == EFI_NOT_READY &&
  1085. EFI_ERROR (gBS->CheckEvent (TimeoutEvent)))
  1086. {
  1087. //
  1088. // Poll the token until reply/ICMPv6 error message received or timeout.
  1089. //
  1090. Udp6->Poll (Udp6);
  1091. if ((Token->Status == EFI_ICMP_ERROR) ||
  1092. (Token->Status == EFI_NETWORK_UNREACHABLE) ||
  1093. (Token->Status == EFI_HOST_UNREACHABLE) ||
  1094. (Token->Status == EFI_PROTOCOL_UNREACHABLE) ||
  1095. (Token->Status == EFI_PORT_UNREACHABLE))
  1096. {
  1097. break;
  1098. }
  1099. }
  1100. Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;
  1101. if (!EFI_ERROR (Status)) {
  1102. //
  1103. // check whether this packet matches the filters
  1104. //
  1105. RxData = Token->Packet.RxData;
  1106. Session = &RxData->UdpSession;
  1107. *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);
  1108. if (*IsMatched) {
  1109. *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);
  1110. }
  1111. if (*IsMatched) {
  1112. *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);
  1113. }
  1114. if (*IsMatched) {
  1115. *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);
  1116. }
  1117. if (*IsMatched) {
  1118. *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);
  1119. }
  1120. if (!(*IsMatched)) {
  1121. //
  1122. // Recycle the receiving buffer if not matched.
  1123. //
  1124. gBS->SignalEvent (RxData->RecycleSignal);
  1125. }
  1126. }
  1127. return Status;
  1128. }
  1129. /**
  1130. This function is to display the IPv4 address.
  1131. @param[in] Ip The pointer to the IPv4 address.
  1132. **/
  1133. VOID
  1134. PxeBcShowIp4Addr (
  1135. IN EFI_IPv4_ADDRESS *Ip
  1136. )
  1137. {
  1138. UINTN Index;
  1139. for (Index = 0; Index < 4; Index++) {
  1140. AsciiPrint ("%d", Ip->Addr[Index]);
  1141. if (Index < 3) {
  1142. AsciiPrint (".");
  1143. }
  1144. }
  1145. }
  1146. /**
  1147. This function is to display the IPv6 address.
  1148. @param[in] Ip The pointer to the IPv6 address.
  1149. **/
  1150. VOID
  1151. PxeBcShowIp6Addr (
  1152. IN EFI_IPv6_ADDRESS *Ip
  1153. )
  1154. {
  1155. UINTN Index;
  1156. for (Index = 0; Index < 16; Index++) {
  1157. if (Ip->Addr[Index] != 0) {
  1158. AsciiPrint ("%x", Ip->Addr[Index]);
  1159. }
  1160. Index++;
  1161. if (Index > 15) {
  1162. return;
  1163. }
  1164. if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {
  1165. AsciiPrint ("0");
  1166. }
  1167. AsciiPrint ("%x", Ip->Addr[Index]);
  1168. if (Index < 15) {
  1169. AsciiPrint (":");
  1170. }
  1171. }
  1172. }
  1173. /**
  1174. This function is to convert UINTN to ASCII string with the required formatting.
  1175. @param[in] Number Numeric value to be converted.
  1176. @param[in] Buffer The pointer to the buffer for ASCII string.
  1177. @param[in] Length The length of the required format.
  1178. **/
  1179. VOID
  1180. PxeBcUintnToAscDecWithFormat (
  1181. IN UINTN Number,
  1182. IN UINT8 *Buffer,
  1183. IN INTN Length
  1184. )
  1185. {
  1186. UINTN Remainder;
  1187. for ( ; Length > 0; Length--) {
  1188. Remainder = Number % 10;
  1189. Number /= 10;
  1190. Buffer[Length - 1] = (UINT8)('0' + Remainder);
  1191. }
  1192. }
  1193. /**
  1194. This function is to convert a UINTN to a ASCII string, and return the
  1195. actual length of the buffer.
  1196. @param[in] Number Numeric value to be converted.
  1197. @param[in] Buffer The pointer to the buffer for ASCII string.
  1198. @param[in] BufferSize The maxsize of the buffer.
  1199. @return Length The actual length of the ASCII string.
  1200. **/
  1201. UINTN
  1202. PxeBcUintnToAscDec (
  1203. IN UINTN Number,
  1204. IN UINT8 *Buffer,
  1205. IN UINTN BufferSize
  1206. )
  1207. {
  1208. UINTN Index;
  1209. UINTN Length;
  1210. CHAR8 TempStr[64];
  1211. Index = 63;
  1212. TempStr[Index] = 0;
  1213. do {
  1214. Index--;
  1215. TempStr[Index] = (CHAR8)('0' + (Number % 10));
  1216. Number = (UINTN)(Number / 10);
  1217. } while (Number != 0);
  1218. AsciiStrCpyS ((CHAR8 *)Buffer, BufferSize, &TempStr[Index]);
  1219. Length = AsciiStrLen ((CHAR8 *)Buffer);
  1220. return Length;
  1221. }
  1222. /**
  1223. This function is to convert unicode hex number to a UINT8.
  1224. @param[out] Digit The converted UINT8 for output.
  1225. @param[in] Char The unicode hex number to be converted.
  1226. @retval EFI_SUCCESS Successfully converted the unicode hex.
  1227. @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.
  1228. **/
  1229. EFI_STATUS
  1230. PxeBcUniHexToUint8 (
  1231. OUT UINT8 *Digit,
  1232. IN CHAR16 Char
  1233. )
  1234. {
  1235. if ((Char >= L'0') && (Char <= L'9')) {
  1236. *Digit = (UINT8)(Char - L'0');
  1237. return EFI_SUCCESS;
  1238. }
  1239. if ((Char >= L'A') && (Char <= L'F')) {
  1240. *Digit = (UINT8)(Char - L'A' + 0x0A);
  1241. return EFI_SUCCESS;
  1242. }
  1243. if ((Char >= L'a') && (Char <= L'f')) {
  1244. *Digit = (UINT8)(Char - L'a' + 0x0A);
  1245. return EFI_SUCCESS;
  1246. }
  1247. return EFI_INVALID_PARAMETER;
  1248. }
  1249. /**
  1250. Calculate the elapsed time.
  1251. @param[in] Private The pointer to PXE private data
  1252. **/
  1253. VOID
  1254. CalcElapsedTime (
  1255. IN PXEBC_PRIVATE_DATA *Private
  1256. )
  1257. {
  1258. EFI_TIME Time;
  1259. UINT64 CurrentStamp;
  1260. UINT64 ElapsedTimeValue;
  1261. //
  1262. // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.
  1263. //
  1264. ZeroMem (&Time, sizeof (EFI_TIME));
  1265. gRT->GetTime (&Time, NULL);
  1266. CurrentStamp = MultU64x32 (
  1267. ((((UINT32)(Time.Year - 1900) * 360 + (Time.Month - 1) * 30 + (Time.Day - 1)) * 24 + Time.Hour) * 60 + Time.Minute) * 60 + Time.Second,
  1268. 100
  1269. ) +
  1270. DivU64x32 (
  1271. Time.Nanosecond,
  1272. 10000000
  1273. );
  1274. //
  1275. // Sentinel value of 0 means that this is the first DHCP packet that we are
  1276. // sending and that we need to initialize the value. First DHCP Solicit
  1277. // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
  1278. //
  1279. if (Private->ElapsedTime == 0) {
  1280. Private->ElapsedTime = CurrentStamp;
  1281. } else {
  1282. ElapsedTimeValue = CurrentStamp - Private->ElapsedTime;
  1283. //
  1284. // If elapsed time cannot fit in two bytes, set it to 0xffff.
  1285. //
  1286. if (ElapsedTimeValue > 0xffff) {
  1287. ElapsedTimeValue = 0xffff;
  1288. }
  1289. //
  1290. // Save the elapsed time
  1291. //
  1292. Private->ElapsedTime = ElapsedTimeValue;
  1293. }
  1294. }