2 Support functions implementation for UefiPxeBc Driver.
4 Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "PxeBcImpl.h"
20 Flush the previous configration using the new station Ip address.
22 @param[in] Private The pointer to the PxeBc private data.
23 @param[in] StationIp The pointer to the station Ip address.
24 @param[in] SubnetMask The pointer to the subnet mask address for v4.
26 @retval EFI_SUCCESS Successfully flushed the previous configuration.
27 @retval Others Failed to flush using the new station Ip.
32 PXEBC_PRIVATE_DATA
*Private
,
33 EFI_IP_ADDRESS
*StationIp
,
34 EFI_IP_ADDRESS
*SubnetMask OPTIONAL
37 EFI_PXE_BASE_CODE_MODE
*Mode
;
40 ASSERT (StationIp
!= NULL
);
42 Mode
= Private
->PxeBc
.Mode
;
45 if (Mode
->UsingIpv6
) {
47 CopyMem (&Private
->Udp6CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
48 CopyMem (&Private
->Ip6CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
51 // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address.
53 Private
->Ip6
->Cancel (Private
->Ip6
, &Private
->Icmp6Token
);
54 Private
->Ip6
->Configure (Private
->Ip6
, NULL
);
56 Status
= Private
->Ip6
->Configure (Private
->Ip6
, &Private
->Ip6CfgData
);
57 if (EFI_ERROR (Status
)) {
61 Status
= Private
->Ip6
->Receive (Private
->Ip6
, &Private
->Icmp6Token
);
63 ASSERT (SubnetMask
!= NULL
);
64 CopyMem (&Private
->Udp4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
65 CopyMem (&Private
->Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
66 CopyMem (&Private
->Ip4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
67 CopyMem (&Private
->Ip4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
70 // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
72 Private
->Ip4
->Cancel (Private
->Ip4
, &Private
->IcmpToken
);
73 Private
->Ip4
->Configure (Private
->Ip4
, NULL
);
75 Status
= Private
->Ip4
->Configure (Private
->Ip4
, &Private
->Ip4CfgData
);
76 if (EFI_ERROR (Status
)) {
80 Status
= Private
->Ip4
->Receive (Private
->Ip4
, &Private
->IcmpToken
);
89 Notify the callback function when an event is triggered.
91 @param[in] Event The triggered event.
92 @param[in] Context The opaque parameter to the function.
102 *((BOOLEAN
*) Context
) = TRUE
;
107 Do arp resolution from arp cache in PxeBcMode.
109 @param Mode The pointer to EFI_PXE_BASE_CODE_MODE.
110 @param Ip4Addr The Ip4 address for resolution.
111 @param MacAddress The resoluted MAC address if the resolution is successful.
112 The value is undefined if the resolution fails.
114 @retval TRUE Found an matched entry.
115 @retval FALSE Did not find a matched entry.
120 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
121 IN EFI_IPv4_ADDRESS
*Ip4Addr
,
122 OUT EFI_MAC_ADDRESS
*MacAddress
127 ASSERT (!Mode
->UsingIpv6
);
130 // Check whether the current Arp cache in mode data contains this information or not.
132 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
133 if (EFI_IP4_EQUAL (&Mode
->ArpCache
[Index
].IpAddr
.v4
, Ip4Addr
)) {
136 &Mode
->ArpCache
[Index
].MacAddr
,
137 sizeof (EFI_MAC_ADDRESS
)
148 Update the arp cache periodically.
150 @param Event The pointer to EFI_PXE_BC_PROTOCOL.
151 @param Context Context of the timer event.
156 PxeBcArpCacheUpdate (
161 PXEBC_PRIVATE_DATA
*Private
;
162 EFI_PXE_BASE_CODE_MODE
*Mode
;
163 EFI_ARP_FIND_DATA
*ArpEntry
;
169 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
170 Mode
= Private
->PxeBc
.Mode
;
172 ASSERT (!Mode
->UsingIpv6
);
175 // Get the current Arp cache from Arp driver.
177 Status
= Private
->Arp
->Find (
186 if (EFI_ERROR (Status
)) {
191 // Update the Arp cache in mode data.
193 Mode
->ArpCacheEntries
= MIN (EntryCount
, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES
);
195 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
197 &Mode
->ArpCache
[Index
].IpAddr
,
199 ArpEntry
->SwAddressLength
202 &Mode
->ArpCache
[Index
].MacAddr
,
203 (UINT8
*) (ArpEntry
+ 1) + ArpEntry
->SwAddressLength
,
204 ArpEntry
->HwAddressLength
206 ArpEntry
= (EFI_ARP_FIND_DATA
*) ((UINT8
*) ArpEntry
+ EntryLength
);
212 Notify function to handle the received ICMP message in DPC.
214 @param Context The PXEBC private data.
219 PxeBcIcmpErrorDpcHandle (
224 EFI_IP4_RECEIVE_DATA
*RxData
;
225 EFI_IP4_PROTOCOL
*Ip4
;
226 PXEBC_PRIVATE_DATA
*Private
;
227 EFI_PXE_BASE_CODE_MODE
*Mode
;
233 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
234 Mode
= &Private
->Mode
;
235 Status
= Private
->IcmpToken
.Status
;
236 RxData
= Private
->IcmpToken
.Packet
.RxData
;
239 ASSERT (!Mode
->UsingIpv6
);
241 if (Status
== EFI_ABORTED
) {
243 // It's triggered by user cancellation.
248 if (RxData
== NULL
) {
252 if (Status
!= EFI_ICMP_ERROR
) {
254 // The return status should be recognized as EFI_ICMP_ERROR.
256 gBS
->SignalEvent (RxData
->RecycleSignal
);
260 if (EFI_IP4 (RxData
->Header
->SourceAddress
) != 0 &&
261 !NetIp4IsUnicast (EFI_NTOHL (RxData
->Header
->SourceAddress
), 0)) {
263 // The source address of the received packet should be a valid unicast address.
265 gBS
->SignalEvent (RxData
->RecycleSignal
);
269 if (!EFI_IP4_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v4
)) {
271 // The destination address of the received packet should be equal to the host address.
273 gBS
->SignalEvent (RxData
->RecycleSignal
);
277 if (RxData
->Header
->Protocol
!= EFI_IP_PROTO_ICMP
) {
279 // The protocol value in the header of the receveid packet should be EFI_IP_PROTO_ICMP.
281 gBS
->SignalEvent (RxData
->RecycleSignal
);
285 Type
= *((UINT8
*) RxData
->FragmentTable
[0].FragmentBuffer
);
287 if (Type
!= ICMP_DEST_UNREACHABLE
&&
288 Type
!= ICMP_SOURCE_QUENCH
&&
289 Type
!= ICMP_REDIRECT
&&
290 Type
!= ICMP_TIME_EXCEEDED
&&
291 Type
!= ICMP_PARAMETER_PROBLEM
) {
293 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
295 gBS
->SignalEvent (RxData
->RecycleSignal
);
300 // Copy the right ICMP error message into mode data.
303 IcmpError
= (UINT8
*) &Mode
->IcmpError
;
305 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
306 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
307 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
310 RxData
->FragmentTable
[Index
].FragmentBuffer
,
311 RxData
->FragmentTable
[Index
].FragmentLength
316 RxData
->FragmentTable
[Index
].FragmentBuffer
,
317 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
320 IcmpError
+= CopiedLen
;
324 Private
->IcmpToken
.Status
= EFI_NOT_READY
;
325 Ip4
->Receive (Ip4
, &Private
->IcmpToken
);
330 Callback function to update the latest ICMP6 error message.
332 @param Event The event signalled.
333 @param Context The context passed in using the event notifier.
338 PxeBcIcmpErrorUpdate (
343 QueueDpc (TPL_CALLBACK
, PxeBcIcmpErrorDpcHandle
, Context
);
348 Notify function to handle the received ICMP6 message in DPC.
350 @param Context The PXEBC private data.
355 PxeBcIcmp6ErrorDpcHandle (
359 PXEBC_PRIVATE_DATA
*Private
;
360 EFI_IP6_RECEIVE_DATA
*RxData
;
361 EFI_IP6_PROTOCOL
*Ip6
;
362 EFI_PXE_BASE_CODE_MODE
*Mode
;
369 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
370 Mode
= &Private
->Mode
;
371 Status
= Private
->Icmp6Token
.Status
;
372 RxData
= Private
->Icmp6Token
.Packet
.RxData
;
375 ASSERT (Mode
->UsingIpv6
);
377 if (Status
== EFI_ABORTED
) {
379 // It's triggered by user cancellation.
384 if (RxData
== NULL
) {
388 if (Status
!= EFI_ICMP_ERROR
) {
390 // The return status should be recognized as EFI_ICMP_ERROR.
392 gBS
->SignalEvent (RxData
->RecycleSignal
);
396 if (!NetIp6IsValidUnicast (&RxData
->Header
->SourceAddress
)) {
398 // The source address of the received packet should be a valid unicast address.
400 gBS
->SignalEvent (RxData
->RecycleSignal
);
404 if (!NetIp6IsUnspecifiedAddr (&Mode
->StationIp
.v6
) &&
405 !EFI_IP6_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v6
)) {
407 // The destination address of the received packet should be equal to the host address.
409 gBS
->SignalEvent (RxData
->RecycleSignal
);
413 if (RxData
->Header
->NextHeader
!= IP6_ICMP
) {
415 // The nextheader in the header of the receveid packet should be IP6_ICMP.
417 gBS
->SignalEvent (RxData
->RecycleSignal
);
421 Type
= *((UINT8
*) RxData
->FragmentTable
[0].FragmentBuffer
);
423 if (Type
!= ICMP_V6_DEST_UNREACHABLE
&&
424 Type
!= ICMP_V6_PACKET_TOO_BIG
&&
425 Type
!= ICMP_V6_PACKET_TOO_BIG
&&
426 Type
!= ICMP_V6_PARAMETER_PROBLEM
) {
428 // The type of the receveid packet should be an ICMP6 error message.
430 gBS
->SignalEvent (RxData
->RecycleSignal
);
435 // Copy the right ICMP6 error message into mode data.
438 Icmp6Error
= (UINT8
*) &Mode
->IcmpError
;
440 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
441 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
442 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
445 RxData
->FragmentTable
[Index
].FragmentBuffer
,
446 RxData
->FragmentTable
[Index
].FragmentLength
451 RxData
->FragmentTable
[Index
].FragmentBuffer
,
452 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
455 Icmp6Error
+= CopiedLen
;
459 Private
->Icmp6Token
.Status
= EFI_NOT_READY
;
460 Ip6
->Receive (Ip6
, &Private
->Icmp6Token
);
465 Callback function to update the latest ICMP6 error message.
467 @param Event The event signalled.
468 @param Context The context passed in using the event notifier.
473 PxeBcIcmp6ErrorUpdate (
478 QueueDpc (TPL_CALLBACK
, PxeBcIcmp6ErrorDpcHandle
, Context
);
483 This function is to configure a UDPv4 instance for UdpWrite.
485 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
486 @param[in] StationIp The pointer to the station address.
487 @param[in] SubnetMask The pointer to the subnet mask.
488 @param[in] Gateway The pointer to the gateway address.
489 @param[in, out] SrcPort The pointer to the source port.
490 @param[in] DoNotFragment If TRUE, fragment is not enabled.
491 Otherwise, fragment is enabled.
493 @retval EFI_SUCCESS Successfully configured this instance.
494 @retval Others Failed to configure this instance.
498 PxeBcConfigUdp4Write (
499 IN EFI_UDP4_PROTOCOL
*Udp4
,
500 IN EFI_IPv4_ADDRESS
*StationIp
,
501 IN EFI_IPv4_ADDRESS
*SubnetMask
,
502 IN EFI_IPv4_ADDRESS
*Gateway
,
503 IN OUT UINT16
*SrcPort
,
504 IN BOOLEAN DoNotFragment
507 EFI_UDP4_CONFIG_DATA Udp4CfgData
;
510 ZeroMem (&Udp4CfgData
, sizeof (Udp4CfgData
));
512 Udp4CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
513 Udp4CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
514 Udp4CfgData
.TypeOfService
= DEFAULT_ToS
;
515 Udp4CfgData
.TimeToLive
= DEFAULT_TTL
;
516 Udp4CfgData
.AllowDuplicatePort
= TRUE
;
517 Udp4CfgData
.DoNotFragment
= DoNotFragment
;
519 CopyMem (&Udp4CfgData
.StationAddress
, StationIp
, sizeof (*StationIp
));
520 CopyMem (&Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (*SubnetMask
));
522 Udp4CfgData
.StationPort
= *SrcPort
;
525 // Reset the UDPv4 instance.
527 Udp4
->Configure (Udp4
, NULL
);
529 Status
= Udp4
->Configure (Udp4
, &Udp4CfgData
);
530 if (!EFI_ERROR (Status
) && !EFI_IP4_EQUAL (Gateway
, &mZeroIp4Addr
)) {
532 // The basic configuration is OK, need to add the default route entry
534 Status
= Udp4
->Routes (Udp4
, FALSE
, &mZeroIp4Addr
, &mZeroIp4Addr
, Gateway
);
535 if (EFI_ERROR (Status
)) {
536 Udp4
->Configure (Udp4
, NULL
);
540 if (!EFI_ERROR (Status
) && *SrcPort
== 0) {
541 Udp4
->GetModeData (Udp4
, &Udp4CfgData
, NULL
, NULL
, NULL
);
542 *SrcPort
= Udp4CfgData
.StationPort
;
550 This function is to configure a UDPv6 instance for UdpWrite.
552 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
553 @param[in] StationIp The pointer to the station address.
554 @param[in, out] SrcPort The pointer to the source port.
556 @retval EFI_SUCCESS Successfully configured this instance.
557 @retval Others Failed to configure this instance.
561 PxeBcConfigUdp6Write (
562 IN EFI_UDP6_PROTOCOL
*Udp6
,
563 IN EFI_IPv6_ADDRESS
*StationIp
,
564 IN OUT UINT16
*SrcPort
567 EFI_UDP6_CONFIG_DATA CfgData
;
570 ZeroMem (&CfgData
, sizeof (EFI_UDP6_CONFIG_DATA
));
572 CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
573 CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
574 CfgData
.HopLimit
= PXEBC_DEFAULT_HOPLIMIT
;
575 CfgData
.AllowDuplicatePort
= TRUE
;
576 CfgData
.StationPort
= *SrcPort
;
578 CopyMem (&CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
581 // Reset the UDPv6 instance.
583 Udp6
->Configure (Udp6
, NULL
);
585 Status
= Udp6
->Configure (Udp6
, &CfgData
);
586 if (EFI_ERROR (Status
)) {
590 if (!EFI_ERROR (Status
) && *SrcPort
== 0) {
591 Udp6
->GetModeData (Udp6
, &CfgData
, NULL
, NULL
, NULL
);
592 *SrcPort
= CfgData
.StationPort
;
600 This function is to configure a UDPv4 instance for UdpWrite.
602 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
603 @param[in] Session The pointer to the UDP4 session data.
604 @param[in] TimeoutEvent The event for timeout.
605 @param[in] Gateway The pointer to the gateway address.
606 @param[in] HeaderSize An optional field which may be set to the length of a header
607 at HeaderPtr to be prefixed to the data at BufferPtr.
608 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
609 prefixed to the data at BufferPtr.
610 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
611 @param[in] BufferPtr A pointer to the data to be written.
613 @retval EFI_SUCCESS Successfully send out data using Udp4Write.
614 @retval Others Failed to send out data.
619 IN EFI_UDP4_PROTOCOL
*Udp4
,
620 IN EFI_UDP4_SESSION_DATA
*Session
,
621 IN EFI_EVENT TimeoutEvent
,
622 IN EFI_IPv4_ADDRESS
*Gateway OPTIONAL
,
623 IN UINTN
*HeaderSize OPTIONAL
,
624 IN VOID
*HeaderPtr OPTIONAL
,
625 IN UINTN
*BufferSize
,
629 EFI_UDP4_COMPLETION_TOKEN Token
;
630 EFI_UDP4_TRANSMIT_DATA
*TxData
;
638 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
640 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
641 TxLength
= sizeof (EFI_UDP4_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP4_FRAGMENT_DATA
);
642 TxData
= (EFI_UDP4_TRANSMIT_DATA
*) AllocateZeroPool (TxLength
);
643 if (TxData
== NULL
) {
644 return EFI_OUT_OF_RESOURCES
;
647 TxData
->FragmentCount
= FragCount
;
648 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
) *BufferSize
;
649 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
650 DataLength
= (UINT32
) *BufferSize
;
652 if (HeaderSize
!= NULL
) {
653 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) *HeaderSize
;
654 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
655 DataLength
+= (UINT32
) *HeaderSize
;
658 if (Gateway
!= NULL
) {
659 TxData
->GatewayAddress
= Gateway
;
662 TxData
->UdpSessionData
= Session
;
663 TxData
->DataLength
= DataLength
;
664 Token
.Packet
.TxData
= TxData
;
665 Token
.Status
= EFI_NOT_READY
;
668 Status
= gBS
->CreateEvent (
675 if (EFI_ERROR (Status
)) {
679 Status
= Udp4
->Transmit (Udp4
, &Token
);
680 if (EFI_ERROR (Status
)) {
685 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
688 Token
.Status
== EFI_NOT_READY
&&
689 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
693 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
696 if (Token
.Event
!= NULL
) {
697 gBS
->CloseEvent (Token
.Event
);
706 This function is to configure a UDPv4 instance for UdpWrite.
708 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
709 @param[in] Session The pointer to the UDP6 session data.
710 @param[in] TimeoutEvent The event for timeout.
711 @param[in] HeaderSize An optional field which may be set to the length of a header
712 at HeaderPtr to be prefixed to the data at BufferPtr.
713 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
714 prefixed to the data at BufferPtr.
715 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
716 @param[in] BufferPtr A pointer to the data to be written.
718 @retval EFI_SUCCESS Successfully sent out data using Udp6Write.
719 @retval Others Failed to send out data.
724 IN EFI_UDP6_PROTOCOL
*Udp6
,
725 IN EFI_UDP6_SESSION_DATA
*Session
,
726 IN EFI_EVENT TimeoutEvent
,
727 IN UINTN
*HeaderSize OPTIONAL
,
728 IN VOID
*HeaderPtr OPTIONAL
,
729 IN UINTN
*BufferSize
,
733 EFI_UDP6_COMPLETION_TOKEN Token
;
734 EFI_UDP6_TRANSMIT_DATA
*TxData
;
742 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
744 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
745 TxLength
= sizeof (EFI_UDP6_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP6_FRAGMENT_DATA
);
746 TxData
= (EFI_UDP6_TRANSMIT_DATA
*) AllocateZeroPool (TxLength
);
747 if (TxData
== NULL
) {
748 return EFI_OUT_OF_RESOURCES
;
751 TxData
->FragmentCount
= FragCount
;
752 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
) *BufferSize
;
753 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
754 DataLength
= (UINT32
) *BufferSize
;
756 if (HeaderSize
!= NULL
) {
757 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) *HeaderSize
;
758 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
759 DataLength
+= (UINT32
) *HeaderSize
;
762 TxData
->UdpSessionData
= Session
;
763 TxData
->DataLength
= DataLength
;
764 Token
.Packet
.TxData
= TxData
;
765 Token
.Status
= EFI_NOT_READY
;
768 Status
= gBS
->CreateEvent (
775 if (EFI_ERROR (Status
)) {
779 Status
= Udp6
->Transmit (Udp6
, &Token
);
780 if (EFI_ERROR (Status
)) {
785 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
788 Token
.Status
== EFI_NOT_READY
&&
789 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
793 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
796 if (Token
.Event
!= NULL
) {
797 gBS
->CloseEvent (Token
.Event
);
806 Check the received packet using the Ip filter.
808 @param[in] Mode The pointer to the mode data of PxeBc.
809 @param[in] Session The pointer to the current UDPv4 session.
810 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
812 @retval TRUE Passed the Ip filter successfully.
813 @retval FALSE Failed to pass the Ip filter.
817 PxeBcCheckByIpFilter (
818 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
823 EFI_IP_ADDRESS DestinationIp
;
826 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
) == 0) {
830 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS
) != 0) {
835 // Convert the destination address in session data to host order.
837 if (Mode
->UsingIpv6
) {
840 &((EFI_UDP6_SESSION_DATA
*) Session
)->DestinationAddress
,
841 sizeof (EFI_IPv6_ADDRESS
)
843 NTOHLLL (&DestinationIp
.v6
);
845 ZeroMem (&DestinationIp
, sizeof (EFI_IP_ADDRESS
));
848 &((EFI_UDP4_SESSION_DATA
*) Session
)->DestinationAddress
,
849 sizeof (EFI_IPv4_ADDRESS
)
851 EFI_NTOHL (DestinationIp
);
854 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST
) != 0 &&
855 (IP4_IS_MULTICAST (DestinationIp
.Addr
[0]) ||
856 IP6_IS_MULTICAST (&DestinationIp
))) {
860 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
) != 0 &&
861 IP4_IS_LOCAL_BROADCAST (DestinationIp
.Addr
[0])) {
862 ASSERT (!Mode
->UsingIpv6
);
866 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
) != 0 &&
867 (EFI_IP4_EQUAL (&Mode
->StationIp
.v4
, &DestinationIp
) ||
868 EFI_IP6_EQUAL (&Mode
->StationIp
.v6
, &DestinationIp
))) {
870 // Matched if the dest address is equal to the station address.
875 for (Index
= 0; Index
< Mode
->IpFilter
.IpCnt
; Index
++) {
876 ASSERT (Index
< EFI_PXE_BASE_CODE_MAX_IPCNT
);
877 if (EFI_IP4_EQUAL (&Mode
->IpFilter
.IpList
[Index
].v4
, &DestinationIp
) ||
878 EFI_IP6_EQUAL (&Mode
->IpFilter
.IpList
[Index
].v6
, &DestinationIp
)) {
880 // Matched if the dest address is equal to any of address in the filter list.
891 Filter the received packet using the destination Ip.
893 @param[in] Mode The pointer to the mode data of PxeBc.
894 @param[in] Session The pointer to the current UDPv4 session.
895 @param[in, out] DestIp The pointer to the destination Ip address.
896 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
898 @retval TRUE Passed the IPv4 filter successfully.
899 @retval FALSE Failed to pass the IPv4 filter.
904 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
906 IN OUT EFI_IP_ADDRESS
*DestIp
,
910 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
) != 0) {
912 // Copy the destination address from the received packet if accept any.
914 if (DestIp
!= NULL
) {
915 if (Mode
->UsingIpv6
) {
918 &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
,
919 sizeof (EFI_IPv6_ADDRESS
)
922 ZeroMem (DestIp
, sizeof (EFI_IP_ADDRESS
));
925 &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
,
926 sizeof (EFI_IPv4_ADDRESS
)
932 } else if (DestIp
!= NULL
&&
933 (EFI_IP4_EQUAL (DestIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
934 EFI_IP6_EQUAL (DestIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
))) {
936 // The destination address in the received packet is matched if present.
939 } else if (EFI_IP4_EQUAL (&Mode
->StationIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
940 EFI_IP6_EQUAL (&Mode
->StationIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
)) {
942 // The destination address in the received packet is equal to the host address.
952 Check the received packet using the destination port.
954 @param[in] Mode The pointer to the mode data of PxeBc.
955 @param[in] Session The pointer to the current UDPv4 session.
956 @param[in, out] DestPort The pointer to the destination port.
957 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
959 @retval TRUE Passed the IPv4 filter successfully.
960 @retval FALSE Failed to pass the IPv4 filter.
964 PxeBcCheckByDestPort (
965 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
967 IN OUT UINT16
*DestPort
,
973 if (Mode
->UsingIpv6
) {
974 Port
= ((EFI_UDP6_SESSION_DATA
*) Session
)->DestinationPort
;
976 Port
= ((EFI_UDP4_SESSION_DATA
*) Session
)->DestinationPort
;
979 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT
) != 0) {
981 // Return the destination port in the received packet if accept any.
983 if (DestPort
!= NULL
) {
987 } else if (DestPort
!= NULL
&& *DestPort
== Port
) {
989 // The destination port in the received packet is matched if present.
999 Filter the received packet using the source Ip.
1001 @param[in] Mode The pointer to the mode data of PxeBc.
1002 @param[in] Session The pointer to the current UDPv4 session.
1003 @param[in, out] SrcIp The pointer to the source Ip address.
1004 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1006 @retval TRUE Passed the IPv4 filter successfully.
1007 @retval FALSE Failed to pass the IPv4 filter.
1011 PxeBcFilterBySrcIp (
1012 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1014 IN OUT EFI_IP_ADDRESS
*SrcIp
,
1018 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
) != 0) {
1020 // Copy the source address from the received packet if accept any.
1022 if (SrcIp
!= NULL
) {
1023 if (Mode
->UsingIpv6
) {
1026 &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
,
1027 sizeof (EFI_IPv6_ADDRESS
)
1030 ZeroMem (SrcIp
, sizeof (EFI_IP_ADDRESS
));
1033 &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
,
1034 sizeof (EFI_IPv4_ADDRESS
)
1040 } else if (SrcIp
!= NULL
&&
1041 (EFI_IP4_EQUAL (SrcIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
) ||
1042 EFI_IP6_EQUAL (SrcIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
))) {
1044 // The source address in the received packet is matched if present.
1054 Filter the received packet using the source port.
1056 @param[in] Mode The pointer to the mode data of PxeBc.
1057 @param[in] Session The pointer to the current UDPv4 session.
1058 @param[in, out] SrcPort The pointer to the source port.
1059 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1061 @retval TRUE Passed the IPv4 filter successfully.
1062 @retval FALSE Failed to pass the IPv4 filter.
1066 PxeBcFilterBySrcPort (
1067 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1069 IN OUT UINT16
*SrcPort
,
1075 if (Mode
->UsingIpv6
) {
1076 Port
= ((EFI_UDP6_SESSION_DATA
*) Session
)->SourcePort
;
1078 Port
= ((EFI_UDP4_SESSION_DATA
*) Session
)->SourcePort
;
1081 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
) != 0) {
1083 // Return the source port in the received packet if accept any.
1085 if (SrcPort
!= NULL
) {
1089 } else if (SrcPort
!= NULL
&& *SrcPort
== Port
) {
1091 // The source port in the received packet is matched if present.
1101 This function is to receive packet using Udp4Read.
1103 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
1104 @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN.
1105 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1106 @param[in] TimeoutEvent The event for timeout.
1107 @param[in] OpFlags The UDP operation flags.
1108 @param[in] IsDone The pointer to the IsDone flag.
1109 @param[out] IsMatched The pointer to the IsMatched flag.
1110 @param[in, out] DestIp The pointer to the destination address.
1111 @param[in, out] DestPort The pointer to the destination port.
1112 @param[in, out] SrcIp The pointer to the source address.
1113 @param[in, out] SrcPort The pointer to the source port.
1115 @retval EFI_SUCCESS Successfully read the data using Udp4.
1116 @retval Others Failed to send out data.
1121 IN EFI_UDP4_PROTOCOL
*Udp4
,
1122 IN EFI_UDP4_COMPLETION_TOKEN
*Token
,
1123 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1124 IN EFI_EVENT TimeoutEvent
,
1127 OUT BOOLEAN
*IsMatched
,
1128 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1129 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1130 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1131 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1134 EFI_UDP4_RECEIVE_DATA
*RxData
;
1135 EFI_UDP4_SESSION_DATA
*Session
;
1138 Token
->Status
= EFI_NOT_READY
;
1141 Status
= Udp4
->Receive (Udp4
, Token
);
1142 if (EFI_ERROR (Status
)) {
1147 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1149 while (!(*IsDone
) &&
1150 Token
->Status
== EFI_NOT_READY
&&
1151 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1153 // Poll the token utill reply/ICMPv6 error message received or timeout.
1156 if (Token
->Status
== EFI_ICMP_ERROR
||
1157 Token
->Status
== EFI_NETWORK_UNREACHABLE
||
1158 Token
->Status
== EFI_HOST_UNREACHABLE
||
1159 Token
->Status
== EFI_PROTOCOL_UNREACHABLE
||
1160 Token
->Status
== EFI_PORT_UNREACHABLE
) {
1165 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1167 if (!EFI_ERROR (Status
)) {
1169 // check whether this packet matches the filters
1171 RxData
= Token
->Packet
.RxData
;
1172 Session
= &RxData
->UdpSession
;
1174 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1177 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1181 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1185 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1189 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1192 if (!(*IsMatched
)) {
1194 // Recycle the receiving buffer if not matched.
1196 gBS
->SignalEvent (RxData
->RecycleSignal
);
1205 This function is to receive packets using Udp6Read.
1207 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
1208 @param[in] Token The pointer to EFI_UDP6_COMPLETION_TOKEN.
1209 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1210 @param[in] TimeoutEvent The event for timeout.
1211 @param[in] OpFlags The UDP operation flags.
1212 @param[in] IsDone The pointer to the IsDone flag.
1213 @param[out] IsMatched The pointer to the IsMatched flag.
1214 @param[in, out] DestIp The pointer to the destination address.
1215 @param[in, out] DestPort The pointer to the destination port.
1216 @param[in, out] SrcIp The pointer to the source address.
1217 @param[in, out] SrcPort The pointer to the source port.
1219 @retval EFI_SUCCESS Successfully read data using Udp6.
1220 @retval Others Failed to send out data.
1225 IN EFI_UDP6_PROTOCOL
*Udp6
,
1226 IN EFI_UDP6_COMPLETION_TOKEN
*Token
,
1227 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1228 IN EFI_EVENT TimeoutEvent
,
1231 OUT BOOLEAN
*IsMatched
,
1232 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1233 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1234 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1235 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1238 EFI_UDP6_RECEIVE_DATA
*RxData
;
1239 EFI_UDP6_SESSION_DATA
*Session
;
1242 Token
->Status
= EFI_NOT_READY
;
1245 Status
= Udp6
->Receive (Udp6
, Token
);
1246 if (EFI_ERROR (Status
)) {
1251 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1253 while (!(*IsDone
) &&
1254 Token
->Status
== EFI_NOT_READY
&&
1255 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1257 // Poll the token utill reply/ICMPv6 error message received or timeout.
1260 if (Token
->Status
== EFI_ICMP_ERROR
||
1261 Token
->Status
== EFI_NETWORK_UNREACHABLE
||
1262 Token
->Status
== EFI_HOST_UNREACHABLE
||
1263 Token
->Status
== EFI_PROTOCOL_UNREACHABLE
||
1264 Token
->Status
== EFI_PORT_UNREACHABLE
) {
1269 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1271 if (!EFI_ERROR (Status
)) {
1273 // check whether this packet matches the filters
1275 RxData
= Token
->Packet
.RxData
;
1276 Session
= &RxData
->UdpSession
;
1278 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1281 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1285 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1289 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1293 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1296 if (!(*IsMatched
)) {
1298 // Recycle the receiving buffer if not matched.
1300 gBS
->SignalEvent (RxData
->RecycleSignal
);
1309 This function is to display the IPv4 address.
1311 @param[in] Ip The pointer to the IPv4 address.
1316 IN EFI_IPv4_ADDRESS
*Ip
1321 for (Index
= 0; Index
< 4; Index
++) {
1322 AsciiPrint ("%d", Ip
->Addr
[Index
]);
1331 This function is to display the IPv6 address.
1333 @param[in] Ip The pointer to the IPv6 address.
1338 IN EFI_IPv6_ADDRESS
*Ip
1343 for (Index
= 0; Index
< 16; Index
++) {
1345 if (Ip
->Addr
[Index
] != 0) {
1346 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1352 if (((Ip
->Addr
[Index
] & 0xf0) == 0) && (Ip
->Addr
[Index
- 1] != 0)) {
1355 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1364 This function is to convert UINTN to ASCII string with the required formatting.
1366 @param[in] Number Numeric value to be converted.
1367 @param[in] Buffer The pointer to the buffer for ASCII string.
1368 @param[in] Length The length of the required format.
1372 PxeBcUintnToAscDecWithFormat (
1380 while (Length
> 0) {
1382 Remainder
= Number
% 10;
1384 Buffer
[Length
] = (UINT8
) ('0' + Remainder
);
1390 This function is to convert a UINTN to a ASCII string, and return the
1391 actual length of the buffer.
1393 @param[in] Number Numeric value to be converted.
1394 @param[in] Buffer The pointer to the buffer for ASCII string.
1396 @return Length The actual length of the ASCII string.
1400 PxeBcUintnToAscDec (
1414 TempStr
[Index
] = (CHAR8
) ('0' + (Number
% 10));
1415 Number
= (UINTN
) (Number
/ 10);
1416 } while (Number
!= 0);
1418 AsciiStrCpy ((CHAR8
*) Buffer
, &TempStr
[Index
]);
1420 Length
= AsciiStrLen ((CHAR8
*) Buffer
);
1427 This function is to convert unicode hex number to a UINT8.
1429 @param[out] Digit The converted UINT8 for output.
1430 @param[in] Char The unicode hex number to be converted.
1432 @retval EFI_SUCCESS Successfully converted the unicode hex.
1433 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.
1437 PxeBcUniHexToUint8 (
1442 if ((Char
>= L
'0') && (Char
<= L
'9')) {
1443 *Digit
= (UINT8
) (Char
- L
'0');
1447 if ((Char
>= L
'A') && (Char
<= L
'F')) {
1448 *Digit
= (UINT8
) (Char
- L
'A' + 0x0A);
1452 if ((Char
>= L
'a') && (Char
<= L
'f')) {
1453 *Digit
= (UINT8
) (Char
- L
'a' + 0x0A);
1457 return EFI_INVALID_PARAMETER
;
1461 Calculate the elapsed time.
1463 @param[in] Private The pointer to PXE private data
1468 IN PXEBC_PRIVATE_DATA
*Private
1472 UINT64 CurrentStamp
;
1473 UINT64 ElapsedTimeValue
;
1476 // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.
1478 ZeroMem (&Time
, sizeof (EFI_TIME
));
1479 gRT
->GetTime (&Time
, NULL
);
1480 CurrentStamp
= (UINT64
)
1482 ((((((Time
.Year
- 1900) * 360 +
1483 (Time
.Month
- 1)) * 30 +
1484 (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 +
1485 Time
.Minute
) * 60 + Time
.Second
) * 100
1486 + DivU64x32(Time
.Nanosecond
, 10000000)
1490 // Sentinel value of 0 means that this is the first DHCP packet that we are
1491 // sending and that we need to initialize the value. First DHCP Solicit
1492 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
1494 if (Private
->ElapsedTime
== 0) {
1495 Private
->ElapsedTime
= CurrentStamp
;
1497 ElapsedTimeValue
= CurrentStamp
- Private
->ElapsedTime
;
1500 // If elapsed time cannot fit in two bytes, set it to 0xffff.
1502 if (ElapsedTimeValue
> 0xffff) {
1503 ElapsedTimeValue
= 0xffff;
1506 // Save the elapsed time
1508 Private
->ElapsedTime
= ElapsedTimeValue
;