2 Support functions implementation for UefiPxeBc Driver.
4 Copyright (c) 2007 - 2011, 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
);
62 if (EFI_ERROR (Status
)) {
67 ASSERT (SubnetMask
!= NULL
);
68 CopyMem (&Private
->Udp4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
69 CopyMem (&Private
->Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
70 CopyMem (&Private
->Ip4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
71 CopyMem (&Private
->Ip4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
74 // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
76 Private
->Ip4
->Cancel (Private
->Ip4
, &Private
->IcmpToken
);
77 Private
->Ip4
->Configure (Private
->Ip4
, NULL
);
79 Status
= Private
->Ip4
->Configure (Private
->Ip4
, &Private
->Ip4CfgData
);
80 if (EFI_ERROR (Status
)) {
84 Status
= Private
->Ip4
->Receive (Private
->Ip4
, &Private
->IcmpToken
);
85 if (EFI_ERROR (Status
)) {
97 Notify the callback function when an event is triggered.
99 @param[in] Event The triggered event.
100 @param[in] Context The opaque parameter to the function.
110 *((BOOLEAN
*) Context
) = TRUE
;
115 Do arp resolution from arp cache in PxeBcMode.
117 @param Mode The pointer to EFI_PXE_BASE_CODE_MODE.
118 @param Ip4Addr The Ip4 address for resolution.
119 @param MacAddress The resoluted MAC address if the resolution is successful.
120 The value is undefined if the resolution fails.
122 @retval TRUE Found an matched entry.
123 @retval FALSE Did not find a matched entry.
128 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
129 IN EFI_IPv4_ADDRESS
*Ip4Addr
,
130 OUT EFI_MAC_ADDRESS
*MacAddress
135 ASSERT (!Mode
->UsingIpv6
);
138 // Check whether the current Arp cache in mode data contains this information or not.
140 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
141 if (EFI_IP4_EQUAL (&Mode
->ArpCache
[Index
].IpAddr
.v4
, Ip4Addr
)) {
144 &Mode
->ArpCache
[Index
].MacAddr
,
145 sizeof (EFI_MAC_ADDRESS
)
156 Update the arp cache periodically.
158 @param Event The pointer to EFI_PXE_BC_PROTOCOL.
159 @param Context Context of the timer event.
164 PxeBcArpCacheUpdate (
169 PXEBC_PRIVATE_DATA
*Private
;
170 EFI_PXE_BASE_CODE_MODE
*Mode
;
171 EFI_ARP_FIND_DATA
*ArpEntry
;
177 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
178 Mode
= Private
->PxeBc
.Mode
;
180 ASSERT (!Mode
->UsingIpv6
);
183 // Get the current Arp cache from Arp driver.
185 Status
= Private
->Arp
->Find (
194 if (EFI_ERROR (Status
)) {
199 // Update the Arp cache in mode data.
201 Mode
->ArpCacheEntries
= MIN (EntryCount
, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES
);
203 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
205 &Mode
->ArpCache
[Index
].IpAddr
,
207 ArpEntry
->SwAddressLength
210 &Mode
->ArpCache
[Index
].MacAddr
,
211 (UINT8
*) (ArpEntry
+ 1) + ArpEntry
->SwAddressLength
,
212 ArpEntry
->HwAddressLength
214 ArpEntry
= (EFI_ARP_FIND_DATA
*) ((UINT8
*) ArpEntry
+ EntryLength
);
220 Notify function to handle the received ICMP message in DPC.
222 @param Context The PXEBC private data.
227 PxeBcIcmpErrorDpcHandle (
232 EFI_IP4_RECEIVE_DATA
*RxData
;
233 EFI_IP4_PROTOCOL
*Ip4
;
234 PXEBC_PRIVATE_DATA
*Private
;
235 EFI_PXE_BASE_CODE_MODE
*Mode
;
241 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
242 Mode
= &Private
->Mode
;
243 Status
= Private
->IcmpToken
.Status
;
244 RxData
= Private
->IcmpToken
.Packet
.RxData
;
247 ASSERT (!Mode
->UsingIpv6
);
249 if (Status
== EFI_ABORTED
) {
251 // It's triggered by user cancellation.
256 if (RxData
== NULL
) {
260 if (Status
!= EFI_ICMP_ERROR
) {
262 // The return status should be recognized as EFI_ICMP_ERROR.
264 gBS
->SignalEvent (RxData
->RecycleSignal
);
268 if (EFI_IP4 (RxData
->Header
->SourceAddress
) != 0 &&
269 !NetIp4IsUnicast (EFI_NTOHL (RxData
->Header
->SourceAddress
), 0)) {
271 // The source address of the received packet should be a valid unicast address.
273 gBS
->SignalEvent (RxData
->RecycleSignal
);
277 if (!EFI_IP4_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v4
)) {
279 // The destination address of the received packet should be equal to the host address.
281 gBS
->SignalEvent (RxData
->RecycleSignal
);
285 if (RxData
->Header
->Protocol
!= EFI_IP_PROTO_ICMP
) {
287 // The protocol value in the header of the receveid packet should be EFI_IP_PROTO_ICMP.
289 gBS
->SignalEvent (RxData
->RecycleSignal
);
293 Type
= *((UINT8
*) RxData
->FragmentTable
[0].FragmentBuffer
);
295 if (Type
!= ICMP_DEST_UNREACHABLE
&&
296 Type
!= ICMP_SOURCE_QUENCH
&&
297 Type
!= ICMP_REDIRECT
&&
298 Type
!= ICMP_TIME_EXCEEDED
&&
299 Type
!= ICMP_PARAMETER_PROBLEM
) {
301 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
303 gBS
->SignalEvent (RxData
->RecycleSignal
);
308 // Copy the right ICMP error message into mode data.
311 IcmpError
= (UINT8
*) &Mode
->IcmpError
;
313 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
314 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
315 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
318 RxData
->FragmentTable
[Index
].FragmentBuffer
,
319 RxData
->FragmentTable
[Index
].FragmentLength
324 RxData
->FragmentTable
[Index
].FragmentBuffer
,
325 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
328 IcmpError
+= CopiedLen
;
332 Private
->IcmpToken
.Status
= EFI_NOT_READY
;
333 Ip4
->Receive (Ip4
, &Private
->IcmpToken
);
338 Callback function to update the latest ICMP6 error message.
340 @param Event The event signalled.
341 @param Context The context passed in using the event notifier.
346 PxeBcIcmpErrorUpdate (
351 QueueDpc (TPL_CALLBACK
, PxeBcIcmpErrorDpcHandle
, Context
);
356 Notify function to handle the received ICMP6 message in DPC.
358 @param Context The PXEBC private data.
363 PxeBcIcmp6ErrorDpcHandle (
367 PXEBC_PRIVATE_DATA
*Private
;
368 EFI_IP6_RECEIVE_DATA
*RxData
;
369 EFI_IP6_PROTOCOL
*Ip6
;
370 EFI_PXE_BASE_CODE_MODE
*Mode
;
377 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
378 Mode
= &Private
->Mode
;
379 Status
= Private
->Icmp6Token
.Status
;
380 RxData
= Private
->Icmp6Token
.Packet
.RxData
;
383 ASSERT (Mode
->UsingIpv6
);
385 if (Status
== EFI_ABORTED
) {
387 // It's triggered by user cancellation.
392 if (RxData
== NULL
) {
396 if (Status
!= EFI_ICMP_ERROR
) {
398 // The return status should be recognized as EFI_ICMP_ERROR.
400 gBS
->SignalEvent (RxData
->RecycleSignal
);
404 if (!NetIp6IsValidUnicast (&RxData
->Header
->SourceAddress
)) {
406 // The source address of the received packet should be a valid unicast address.
408 gBS
->SignalEvent (RxData
->RecycleSignal
);
412 if (!NetIp6IsUnspecifiedAddr (&Mode
->StationIp
.v6
) &&
413 !EFI_IP6_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v6
)) {
415 // The destination address of the received packet should be equal to the host address.
417 gBS
->SignalEvent (RxData
->RecycleSignal
);
421 if (RxData
->Header
->NextHeader
!= IP6_ICMP
) {
423 // The nextheader in the header of the receveid packet should be IP6_ICMP.
425 gBS
->SignalEvent (RxData
->RecycleSignal
);
429 Type
= *((UINT8
*) RxData
->FragmentTable
[0].FragmentBuffer
);
431 if (Type
!= ICMP_V6_DEST_UNREACHABLE
&&
432 Type
!= ICMP_V6_PACKET_TOO_BIG
&&
433 Type
!= ICMP_V6_PACKET_TOO_BIG
&&
434 Type
!= ICMP_V6_PARAMETER_PROBLEM
) {
436 // The type of the receveid packet should be an ICMP6 error message.
438 gBS
->SignalEvent (RxData
->RecycleSignal
);
443 // Copy the right ICMP6 error message into mode data.
446 Icmp6Error
= (UINT8
*) &Mode
->IcmpError
;
448 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
449 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
450 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
453 RxData
->FragmentTable
[Index
].FragmentBuffer
,
454 RxData
->FragmentTable
[Index
].FragmentLength
459 RxData
->FragmentTable
[Index
].FragmentBuffer
,
460 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
463 Icmp6Error
+= CopiedLen
;
467 Private
->Icmp6Token
.Status
= EFI_NOT_READY
;
468 Ip6
->Receive (Ip6
, &Private
->Icmp6Token
);
473 Callback function to update the latest ICMP6 error message.
475 @param Event The event signalled.
476 @param Context The context passed in using the event notifier.
481 PxeBcIcmp6ErrorUpdate (
486 QueueDpc (TPL_CALLBACK
, PxeBcIcmp6ErrorDpcHandle
, Context
);
491 This function is to configure a UDPv4 instance for UdpWrite.
493 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
494 @param[in] StationIp The pointer to the station address.
495 @param[in] SubnetMask The pointer to the subnet mask.
496 @param[in] Gateway The pointer to the gateway address.
497 @param[in, out] SrcPort The pointer to the source port.
498 @param[in] DoNotFragment If TRUE, fragment is not enabled.
499 Otherwise, fragment is enabled.
501 @retval EFI_SUCCESS Successfully configured this instance.
502 @retval Others Failed to configure this instance.
506 PxeBcConfigUdp4Write (
507 IN EFI_UDP4_PROTOCOL
*Udp4
,
508 IN EFI_IPv4_ADDRESS
*StationIp
,
509 IN EFI_IPv4_ADDRESS
*SubnetMask
,
510 IN EFI_IPv4_ADDRESS
*Gateway
,
511 IN OUT UINT16
*SrcPort
,
512 IN BOOLEAN DoNotFragment
515 EFI_UDP4_CONFIG_DATA Udp4CfgData
;
518 ZeroMem (&Udp4CfgData
, sizeof (Udp4CfgData
));
520 Udp4CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
521 Udp4CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
522 Udp4CfgData
.TypeOfService
= DEFAULT_ToS
;
523 Udp4CfgData
.TimeToLive
= DEFAULT_TTL
;
524 Udp4CfgData
.AllowDuplicatePort
= TRUE
;
525 Udp4CfgData
.DoNotFragment
= DoNotFragment
;
527 CopyMem (&Udp4CfgData
.StationAddress
, StationIp
, sizeof (*StationIp
));
528 CopyMem (&Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (*SubnetMask
));
530 Udp4CfgData
.StationPort
= *SrcPort
;
533 // Reset the UDPv4 instance.
535 Udp4
->Configure (Udp4
, NULL
);
537 Status
= Udp4
->Configure (Udp4
, &Udp4CfgData
);
538 if (!EFI_ERROR (Status
) && !EFI_IP4_EQUAL (Gateway
, &mZeroIp4Addr
)) {
540 // The basic configuration is OK, need to add the default route entry
542 Status
= Udp4
->Routes (Udp4
, FALSE
, &mZeroIp4Addr
, &mZeroIp4Addr
, Gateway
);
543 if (EFI_ERROR (Status
)) {
544 Udp4
->Configure (Udp4
, NULL
);
548 if (!EFI_ERROR (Status
) && *SrcPort
== 0) {
549 Udp4
->GetModeData (Udp4
, &Udp4CfgData
, NULL
, NULL
, NULL
);
550 *SrcPort
= Udp4CfgData
.StationPort
;
558 This function is to configure a UDPv6 instance for UdpWrite.
560 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
561 @param[in] StationIp The pointer to the station address.
562 @param[in, out] SrcPort The pointer to the source port.
564 @retval EFI_SUCCESS Successfully configured this instance.
565 @retval Others Failed to configure this instance.
569 PxeBcConfigUdp6Write (
570 IN EFI_UDP6_PROTOCOL
*Udp6
,
571 IN EFI_IPv6_ADDRESS
*StationIp
,
572 IN OUT UINT16
*SrcPort
575 EFI_UDP6_CONFIG_DATA CfgData
;
578 ZeroMem (&CfgData
, sizeof (EFI_UDP6_CONFIG_DATA
));
580 CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
581 CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
582 CfgData
.HopLimit
= PXEBC_DEFAULT_HOPLIMIT
;
583 CfgData
.AllowDuplicatePort
= TRUE
;
584 CfgData
.StationPort
= *SrcPort
;
586 CopyMem (&CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
589 // Reset the UDPv6 instance.
591 Udp6
->Configure (Udp6
, NULL
);
593 Status
= Udp6
->Configure (Udp6
, &CfgData
);
594 if (EFI_ERROR (Status
)) {
598 if (!EFI_ERROR (Status
) && *SrcPort
== 0) {
599 Udp6
->GetModeData (Udp6
, &CfgData
, NULL
, NULL
, NULL
);
600 *SrcPort
= CfgData
.StationPort
;
608 This function is to configure a UDPv4 instance for UdpWrite.
610 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
611 @param[in] Session The pointer to the UDP4 session data.
612 @param[in] TimeoutEvent The event for timeout.
613 @param[in] Gateway The pointer to the gateway address.
614 @param[in] HeaderSize An optional field which may be set to the length of a header
615 at HeaderPtr to be prefixed to the data at BufferPtr.
616 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
617 prefixed to the data at BufferPtr.
618 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
619 @param[in] BufferPtr A pointer to the data to be written.
621 @retval EFI_SUCCESS Successfully send out data using Udp4Write.
622 @retval Others Failed to send out data.
627 IN EFI_UDP4_PROTOCOL
*Udp4
,
628 IN EFI_UDP4_SESSION_DATA
*Session
,
629 IN EFI_EVENT TimeoutEvent
,
630 IN EFI_IPv4_ADDRESS
*Gateway OPTIONAL
,
631 IN UINTN
*HeaderSize OPTIONAL
,
632 IN VOID
*HeaderPtr OPTIONAL
,
633 IN UINTN
*BufferSize
,
637 EFI_UDP4_COMPLETION_TOKEN Token
;
638 EFI_UDP4_TRANSMIT_DATA
*TxData
;
646 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
648 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
649 TxLength
= sizeof (EFI_UDP4_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP4_FRAGMENT_DATA
);
650 TxData
= (EFI_UDP4_TRANSMIT_DATA
*) AllocateZeroPool (TxLength
);
651 if (TxData
== NULL
) {
652 return EFI_OUT_OF_RESOURCES
;
655 TxData
->FragmentCount
= FragCount
;
656 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
) *BufferSize
;
657 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
658 DataLength
= (UINT32
) *BufferSize
;
660 if (HeaderSize
!= NULL
) {
661 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) *HeaderSize
;
662 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
663 DataLength
+= (UINT32
) *HeaderSize
;
666 if (Gateway
!= NULL
) {
667 TxData
->GatewayAddress
= Gateway
;
670 TxData
->UdpSessionData
= Session
;
671 TxData
->DataLength
= DataLength
;
672 Token
.Packet
.TxData
= TxData
;
673 Token
.Status
= EFI_NOT_READY
;
676 Status
= gBS
->CreateEvent (
683 if (EFI_ERROR (Status
)) {
687 Status
= Udp4
->Transmit (Udp4
, &Token
);
688 if (EFI_ERROR (Status
)) {
693 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
696 Token
.Status
== EFI_NOT_READY
&&
697 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
701 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
704 if (Token
.Event
!= NULL
) {
705 gBS
->CloseEvent (Token
.Event
);
714 This function is to configure a UDPv4 instance for UdpWrite.
716 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
717 @param[in] Session The pointer to the UDP6 session data.
718 @param[in] TimeoutEvent The event for timeout.
719 @param[in] HeaderSize An optional field which may be set to the length of a header
720 at HeaderPtr to be prefixed to the data at BufferPtr.
721 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
722 prefixed to the data at BufferPtr.
723 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
724 @param[in] BufferPtr A pointer to the data to be written.
726 @retval EFI_SUCCESS Successfully sent out data using Udp6Write.
727 @retval Others Failed to send out data.
732 IN EFI_UDP6_PROTOCOL
*Udp6
,
733 IN EFI_UDP6_SESSION_DATA
*Session
,
734 IN EFI_EVENT TimeoutEvent
,
735 IN UINTN
*HeaderSize OPTIONAL
,
736 IN VOID
*HeaderPtr OPTIONAL
,
737 IN UINTN
*BufferSize
,
741 EFI_UDP6_COMPLETION_TOKEN Token
;
742 EFI_UDP6_TRANSMIT_DATA
*TxData
;
750 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
752 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
753 TxLength
= sizeof (EFI_UDP6_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP6_FRAGMENT_DATA
);
754 TxData
= (EFI_UDP6_TRANSMIT_DATA
*) AllocateZeroPool (TxLength
);
755 if (TxData
== NULL
) {
756 return EFI_OUT_OF_RESOURCES
;
759 TxData
->FragmentCount
= FragCount
;
760 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
) *BufferSize
;
761 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
762 DataLength
= (UINT32
) *BufferSize
;
764 if (HeaderSize
!= NULL
) {
765 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) *HeaderSize
;
766 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
767 DataLength
+= (UINT32
) *HeaderSize
;
770 TxData
->UdpSessionData
= Session
;
771 TxData
->DataLength
= DataLength
;
772 Token
.Packet
.TxData
= TxData
;
773 Token
.Status
= EFI_NOT_READY
;
776 Status
= gBS
->CreateEvent (
783 if (EFI_ERROR (Status
)) {
787 Status
= Udp6
->Transmit (Udp6
, &Token
);
788 if (EFI_ERROR (Status
)) {
793 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
796 Token
.Status
== EFI_NOT_READY
&&
797 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
801 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
804 if (Token
.Event
!= NULL
) {
805 gBS
->CloseEvent (Token
.Event
);
814 Check the received packet using the Ip filter.
816 @param[in] Mode The pointer to the mode data of PxeBc.
817 @param[in] Session The pointer to the current UDPv4 session.
818 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
820 @retval TRUE Passed the Ip filter successfully.
821 @retval FALSE Failed to pass the Ip filter.
825 PxeBcCheckByIpFilter (
826 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
831 EFI_IP_ADDRESS DestinationIp
;
834 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
) == 0) {
838 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS
) != 0) {
843 // Convert the destination address in session data to host order.
845 if (Mode
->UsingIpv6
) {
848 &((EFI_UDP6_SESSION_DATA
*) Session
)->DestinationAddress
,
849 sizeof (EFI_IPv6_ADDRESS
)
851 NTOHLLL (&DestinationIp
.v6
);
853 ZeroMem (&DestinationIp
, sizeof (EFI_IP_ADDRESS
));
856 &((EFI_UDP4_SESSION_DATA
*) Session
)->DestinationAddress
,
857 sizeof (EFI_IPv4_ADDRESS
)
859 EFI_NTOHL (DestinationIp
);
862 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST
) != 0 &&
863 (IP4_IS_MULTICAST (DestinationIp
.Addr
[0]) ||
864 IP6_IS_MULTICAST (&DestinationIp
))) {
868 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
) != 0 &&
869 IP4_IS_LOCAL_BROADCAST (DestinationIp
.Addr
[0])) {
870 ASSERT (!Mode
->UsingIpv6
);
874 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
) != 0 &&
875 (EFI_IP4_EQUAL (&Mode
->StationIp
.v4
, &DestinationIp
) ||
876 EFI_IP6_EQUAL (&Mode
->StationIp
.v6
, &DestinationIp
))) {
878 // Matched if the dest address is equal to the station address.
883 for (Index
= 0; Index
< Mode
->IpFilter
.IpCnt
; Index
++) {
884 ASSERT (Index
< EFI_PXE_BASE_CODE_MAX_IPCNT
);
885 if (EFI_IP4_EQUAL (&Mode
->IpFilter
.IpList
[Index
].v4
, &DestinationIp
) ||
886 EFI_IP6_EQUAL (&Mode
->IpFilter
.IpList
[Index
].v6
, &DestinationIp
)) {
888 // Matched if the dest address is equal to any of address in the filter list.
899 Filter the received packet using the destination Ip.
901 @param[in] Mode The pointer to the mode data of PxeBc.
902 @param[in] Session The pointer to the current UDPv4 session.
903 @param[in, out] DestIp The pointer to the destination Ip address.
904 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
906 @retval TRUE Passed the IPv4 filter successfully.
907 @retval FALSE Failed to pass the IPv4 filter.
912 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
914 IN OUT EFI_IP_ADDRESS
*DestIp
,
918 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
) != 0) {
920 // Copy the destination address from the received packet if accept any.
922 if (DestIp
!= NULL
) {
923 if (Mode
->UsingIpv6
) {
926 &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
,
927 sizeof (EFI_IPv6_ADDRESS
)
930 ZeroMem (DestIp
, sizeof (EFI_IP_ADDRESS
));
933 &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
,
934 sizeof (EFI_IPv4_ADDRESS
)
940 } else if (DestIp
!= NULL
&&
941 (EFI_IP4_EQUAL (DestIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
942 EFI_IP6_EQUAL (DestIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
))) {
944 // The destination address in the received packet is matched if present.
947 } else if (EFI_IP4_EQUAL (&Mode
->StationIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
948 EFI_IP6_EQUAL (&Mode
->StationIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
)) {
950 // The destination address in the received packet is equal to the host address.
960 Check the received packet using the destination port.
962 @param[in] Mode The pointer to the mode data of PxeBc.
963 @param[in] Session The pointer to the current UDPv4 session.
964 @param[in, out] DestPort The pointer to the destination port.
965 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
967 @retval TRUE Passed the IPv4 filter successfully.
968 @retval FALSE Failed to pass the IPv4 filter.
972 PxeBcCheckByDestPort (
973 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
975 IN OUT UINT16
*DestPort
,
981 if (Mode
->UsingIpv6
) {
982 Port
= ((EFI_UDP6_SESSION_DATA
*) Session
)->DestinationPort
;
984 Port
= ((EFI_UDP4_SESSION_DATA
*) Session
)->DestinationPort
;
987 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT
) != 0) {
989 // Return the destination port in the received packet if accept any.
991 if (DestPort
!= NULL
) {
995 } else if (DestPort
!= NULL
&& *DestPort
== Port
) {
997 // The destination port in the received packet is matched if present.
1007 Filter the received packet using the source Ip.
1009 @param[in] Mode The pointer to the mode data of PxeBc.
1010 @param[in] Session The pointer to the current UDPv4 session.
1011 @param[in, out] SrcIp The pointer to the source Ip address.
1012 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1014 @retval TRUE Passed the IPv4 filter successfully.
1015 @retval FALSE Failed to pass the IPv4 filter.
1019 PxeBcFilterBySrcIp (
1020 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1022 IN OUT EFI_IP_ADDRESS
*SrcIp
,
1026 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
) != 0) {
1028 // Copy the source address from the received packet if accept any.
1030 if (SrcIp
!= NULL
) {
1031 if (Mode
->UsingIpv6
) {
1034 &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
,
1035 sizeof (EFI_IPv6_ADDRESS
)
1038 ZeroMem (SrcIp
, sizeof (EFI_IP_ADDRESS
));
1041 &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
,
1042 sizeof (EFI_IPv4_ADDRESS
)
1048 } else if (SrcIp
!= NULL
&&
1049 (EFI_IP4_EQUAL (SrcIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
) ||
1050 EFI_IP6_EQUAL (SrcIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
))) {
1052 // The source address in the received packet is matched if present.
1062 Filter the received packet using the source port.
1064 @param[in] Mode The pointer to the mode data of PxeBc.
1065 @param[in] Session The pointer to the current UDPv4 session.
1066 @param[in, out] SrcPort The pointer to the source port.
1067 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1069 @retval TRUE Passed the IPv4 filter successfully.
1070 @retval FALSE Failed to pass the IPv4 filter.
1074 PxeBcFilterBySrcPort (
1075 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1077 IN OUT UINT16
*SrcPort
,
1083 if (Mode
->UsingIpv6
) {
1084 Port
= ((EFI_UDP6_SESSION_DATA
*) Session
)->SourcePort
;
1086 Port
= ((EFI_UDP4_SESSION_DATA
*) Session
)->SourcePort
;
1089 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
) != 0) {
1091 // Return the source port in the received packet if accept any.
1093 if (SrcPort
!= NULL
) {
1097 } else if (SrcPort
!= NULL
&& *SrcPort
== Port
) {
1099 // The source port in the received packet is matched if present.
1109 This function is to receive packet using Udp4Read.
1111 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
1112 @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN.
1113 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1114 @param[in] TimeoutEvent The event for timeout.
1115 @param[in] OpFlags The UDP operation flags.
1116 @param[in] IsDone The pointer to the IsDone flag.
1117 @param[out] IsMatched The pointer to the IsMatched flag.
1118 @param[in, out] DestIp The pointer to the destination address.
1119 @param[in, out] DestPort The pointer to the destination port.
1120 @param[in, out] SrcIp The pointer to the source address.
1121 @param[in, out] SrcPort The pointer to the source port.
1123 @retval EFI_SUCCESS Successfully read the data using Udp4.
1124 @retval Others Failed to send out data.
1129 IN EFI_UDP4_PROTOCOL
*Udp4
,
1130 IN EFI_UDP4_COMPLETION_TOKEN
*Token
,
1131 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1132 IN EFI_EVENT TimeoutEvent
,
1135 OUT BOOLEAN
*IsMatched
,
1136 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1137 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1138 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1139 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1142 EFI_UDP4_RECEIVE_DATA
*RxData
;
1143 EFI_UDP4_SESSION_DATA
*Session
;
1146 Token
->Status
= EFI_NOT_READY
;
1149 Status
= Udp4
->Receive (Udp4
, Token
);
1150 if (EFI_ERROR (Status
)) {
1155 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1157 while (!(*IsDone
) &&
1158 Token
->Status
== EFI_NOT_READY
&&
1159 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1161 // Poll the token utill reply/ICMPv6 error message received or timeout.
1164 if (Token
->Status
== EFI_ICMP_ERROR
||
1165 Token
->Status
== EFI_NETWORK_UNREACHABLE
||
1166 Token
->Status
== EFI_HOST_UNREACHABLE
||
1167 Token
->Status
== EFI_PROTOCOL_UNREACHABLE
||
1168 Token
->Status
== EFI_PORT_UNREACHABLE
) {
1173 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1175 if (!EFI_ERROR (Status
)) {
1177 // check whether this packet matches the filters
1179 RxData
= Token
->Packet
.RxData
;
1180 Session
= &RxData
->UdpSession
;
1182 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1185 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1189 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1193 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1197 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1200 if (!(*IsMatched
)) {
1202 // Recycle the receiving buffer if not matched.
1204 gBS
->SignalEvent (RxData
->RecycleSignal
);
1213 This function is to receive packets using Udp6Read.
1215 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
1216 @param[in] Token The pointer to EFI_UDP6_COMPLETION_TOKEN.
1217 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1218 @param[in] TimeoutEvent The event for timeout.
1219 @param[in] OpFlags The UDP operation flags.
1220 @param[in] IsDone The pointer to the IsDone flag.
1221 @param[out] IsMatched The pointer to the IsMatched flag.
1222 @param[in, out] DestIp The pointer to the destination address.
1223 @param[in, out] DestPort The pointer to the destination port.
1224 @param[in, out] SrcIp The pointer to the source address.
1225 @param[in, out] SrcPort The pointer to the source port.
1227 @retval EFI_SUCCESS Successfully read data using Udp6.
1228 @retval Others Failed to send out data.
1233 IN EFI_UDP6_PROTOCOL
*Udp6
,
1234 IN EFI_UDP6_COMPLETION_TOKEN
*Token
,
1235 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1236 IN EFI_EVENT TimeoutEvent
,
1239 OUT BOOLEAN
*IsMatched
,
1240 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1241 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1242 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1243 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1246 EFI_UDP6_RECEIVE_DATA
*RxData
;
1247 EFI_UDP6_SESSION_DATA
*Session
;
1250 Token
->Status
= EFI_NOT_READY
;
1253 Status
= Udp6
->Receive (Udp6
, Token
);
1254 if (EFI_ERROR (Status
)) {
1259 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1261 while (!(*IsDone
) &&
1262 Token
->Status
== EFI_NOT_READY
&&
1263 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1265 // Poll the token utill reply/ICMPv6 error message received or timeout.
1268 if (Token
->Status
== EFI_ICMP_ERROR
||
1269 Token
->Status
== EFI_NETWORK_UNREACHABLE
||
1270 Token
->Status
== EFI_HOST_UNREACHABLE
||
1271 Token
->Status
== EFI_PROTOCOL_UNREACHABLE
||
1272 Token
->Status
== EFI_PORT_UNREACHABLE
) {
1277 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1279 if (!EFI_ERROR (Status
)) {
1281 // check whether this packet matches the filters
1283 RxData
= Token
->Packet
.RxData
;
1284 Session
= &RxData
->UdpSession
;
1286 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1289 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1293 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1297 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1301 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1304 if (!(*IsMatched
)) {
1306 // Recycle the receiving buffer if not matched.
1308 gBS
->SignalEvent (RxData
->RecycleSignal
);
1317 This function is to display the IPv4 address.
1319 @param[in] Ip The pointer to the IPv4 address.
1324 IN EFI_IPv4_ADDRESS
*Ip
1329 for (Index
= 0; Index
< 4; Index
++) {
1330 AsciiPrint ("%d", Ip
->Addr
[Index
]);
1339 This function is to display the IPv6 address.
1341 @param[in] Ip The pointer to the IPv6 address.
1346 IN EFI_IPv6_ADDRESS
*Ip
1351 for (Index
= 0; Index
< 16; Index
++) {
1353 if (Ip
->Addr
[Index
] != 0) {
1354 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1360 if (((Ip
->Addr
[Index
] & 0xf0) == 0) && (Ip
->Addr
[Index
- 1] != 0)) {
1363 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1372 This function is to convert UINTN to ASCII string with the required formatting.
1374 @param[in] Number Numeric value to be converted.
1375 @param[in] Buffer The pointer to the buffer for ASCII string.
1376 @param[in] Length The length of the required format.
1380 PxeBcUintnToAscDecWithFormat (
1388 while (Length
> 0) {
1390 Remainder
= Number
% 10;
1392 Buffer
[Length
] = (UINT8
) ('0' + Remainder
);
1398 This function is to convert a UINTN to a ASCII string, and return the
1399 actual length of the buffer.
1401 @param[in] Number Numeric value to be converted.
1402 @param[in] Buffer The pointer to the buffer for ASCII string.
1404 @return Length The actual length of the ASCII string.
1408 PxeBcUintnToAscDec (
1422 TempStr
[Index
] = (CHAR8
) ('0' + (Number
% 10));
1423 Number
= (UINTN
) (Number
/ 10);
1424 } while (Number
!= 0);
1426 AsciiStrCpy ((CHAR8
*) Buffer
, &TempStr
[Index
]);
1428 Length
= AsciiStrLen ((CHAR8
*) Buffer
);
1435 This function is to convert unicode hex number to a UINT8.
1437 @param[out] Digit The converted UINT8 for output.
1438 @param[in] Char The unicode hex number to be converted.
1440 @retval EFI_SUCCESS Successfully converted the unicode hex.
1441 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.
1445 PxeBcUniHexToUint8 (
1450 if ((Char
>= L
'0') && (Char
<= L
'9')) {
1451 *Digit
= (UINT8
) (Char
- L
'0');
1455 if ((Char
>= L
'A') && (Char
<= L
'F')) {
1456 *Digit
= (UINT8
) (Char
- L
'A' + 0x0A);
1460 if ((Char
>= L
'a') && (Char
<= L
'f')) {
1461 *Digit
= (UINT8
) (Char
- L
'a' + 0x0A);
1465 return EFI_INVALID_PARAMETER
;
1469 Calculate the elapsed time.
1471 @param[in] Private The pointer to PXE private data
1476 IN PXEBC_PRIVATE_DATA
*Private
1480 UINT64 CurrentStamp
;
1481 UINT64 ElapsedTimeValue
;
1484 // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.
1486 ZeroMem (&Time
, sizeof (EFI_TIME
));
1487 gRT
->GetTime (&Time
, NULL
);
1488 CurrentStamp
= (UINT64
)
1490 ((((((Time
.Year
- 1900) * 360 +
1491 (Time
.Month
- 1)) * 30 +
1492 (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 +
1493 Time
.Minute
) * 60 + Time
.Second
) * 100
1494 + DivU64x32(Time
.Nanosecond
, 10000000)
1498 // Sentinel value of 0 means that this is the first DHCP packet that we are
1499 // sending and that we need to initialize the value. First DHCP Solicit
1500 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
1502 if (Private
->ElapsedTime
== 0) {
1503 Private
->ElapsedTime
= CurrentStamp
;
1505 ElapsedTimeValue
= CurrentStamp
- Private
->ElapsedTime
;
1508 // If elapsed time cannot fit in two bytes, set it to 0xffff.
1510 if (ElapsedTimeValue
> 0xffff) {
1511 ElapsedTimeValue
= 0xffff;
1514 // Save the elapsed time
1516 Private
->ElapsedTime
= ElapsedTimeValue
;