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