2 Support functions implementation for UefiPxeBc Driver.
4 Copyright (c) 2007 - 2010, 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"
21 This function returns SMBIOS string given the string number.
23 @param[in] Smbios The pointer to the SMBIOS structure
24 @param[in] StringNumber String number to return. 0 is used to skip all
25 strings and point to the next SMBIOS structure.
27 @return String The pointer to the next SMBIOS structure if
32 PxeBcGetSmbiosString (
33 IN SMBIOS_STRUCTURE_POINTER
*Smbios
,
34 IN UINT16 StringNumber
41 // Skip over formatted section.
43 String
= (CHAR8
*) (Smbios
->Raw
+ Smbios
->Hdr
->Length
);
46 // Look through unformated section.
48 for (Index
= 1; Index
<= StringNumber
|| StringNumber
== 0; Index
++) {
49 if (StringNumber
== Index
) {
56 while (*String
!= 0) {
63 // If double NULL then we are done.
64 // Return pointer to next structure in Smbios.
65 // if you pass in a 0 you will always get here
67 Smbios
->Raw
= (UINT8
*)++String
;
77 This function obtains the system guid and the serial number from the smbios table.
79 @param[out] SystemGuid The pointer of the returned system guid.
81 @retval EFI_SUCCESS Successfully obtained the system guid.
82 @retval EFI_NOT_FOUND Did not find the SMBIOS table.
87 OUT EFI_GUID
*SystemGuid
91 SMBIOS_TABLE_ENTRY_POINT
*SmbiosTable
;
92 SMBIOS_STRUCTURE_POINTER Smbios
;
93 SMBIOS_STRUCTURE_POINTER SmbiosEnd
;
97 Status
= EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid
, (VOID
**) &SmbiosTable
);
99 if (EFI_ERROR (Status
) || SmbiosTable
== NULL
) {
100 return EFI_NOT_FOUND
;
103 Smbios
.Hdr
= (SMBIOS_STRUCTURE
*) (UINTN
) SmbiosTable
->TableAddress
;
104 SmbiosEnd
.Raw
= (UINT8
*) (UINTN
) (SmbiosTable
->TableAddress
+ SmbiosTable
->TableLength
);
106 for (Index
= 0; Index
< SmbiosTable
->TableLength
; Index
++) {
107 if (Smbios
.Hdr
->Type
== 1) {
108 if (Smbios
.Hdr
->Length
< 0x19) {
110 // Older version did not support Guid and Serial number
115 // SMBIOS tables are byte packed so we need to do a byte copy to
116 // prevend alignment faults on Itanium-based platform.
118 CopyMem (SystemGuid
, &Smbios
.Type1
->Uuid
, sizeof (EFI_GUID
));
119 PxeBcGetSmbiosString (&Smbios
, Smbios
.Type1
->SerialNumber
);
124 // Make Smbios point to the next record
126 PxeBcGetSmbiosString (&Smbios
, 0);
128 if (Smbios
.Raw
>= SmbiosEnd
.Raw
) {
130 // SMBIOS 2.1 incorrectly stated the length of SmbiosTable as 0x1e.
131 // given this we must double check against the length of the structure.
137 return EFI_NOT_FOUND
;
142 Flush the previous configration using the new station Ip address.
144 @param[in] Private The pointer to the PxeBc private data.
145 @param[in] StationIp The pointer to the station Ip address.
146 @param[in] SubnetMask The pointer to the subnet mask address for v4.
148 @retval EFI_SUCCESS Successfully flushed the previous configuration.
149 @retval Others Failed to flush using the new station Ip.
154 PXEBC_PRIVATE_DATA
*Private
,
155 EFI_IP_ADDRESS
*StationIp
,
156 EFI_IP_ADDRESS
*SubnetMask OPTIONAL
159 EFI_PXE_BASE_CODE_MODE
*Mode
;
162 ASSERT (StationIp
!= NULL
);
164 Mode
= Private
->PxeBc
.Mode
;
165 Status
= EFI_SUCCESS
;
167 if (Mode
->UsingIpv6
) {
169 CopyMem (&Private
->Udp6CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
170 CopyMem (&Private
->Ip6CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
173 // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address.
175 Private
->Ip6
->Cancel (Private
->Ip6
, &Private
->Icmp6Token
);
176 Private
->Ip6
->Configure (Private
->Ip6
, NULL
);
178 Status
= Private
->Ip6
->Configure (Private
->Ip6
, &Private
->Ip6CfgData
);
179 if (EFI_ERROR (Status
)) {
183 Status
= Private
->Ip6
->Receive (Private
->Ip6
, &Private
->Icmp6Token
);
184 if (EFI_ERROR (Status
)) {
189 ASSERT (SubnetMask
!= NULL
);
190 CopyMem (&Private
->Udp4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
191 CopyMem (&Private
->Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
192 CopyMem (&Private
->Ip4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
193 CopyMem (&Private
->Ip4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
196 // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
198 Private
->Ip4
->Cancel (Private
->Ip4
, &Private
->IcmpToken
);
199 Private
->Ip4
->Configure (Private
->Ip4
, NULL
);
201 Status
= Private
->Ip4
->Configure (Private
->Ip4
, &Private
->Ip4CfgData
);
202 if (EFI_ERROR (Status
)) {
206 Status
= Private
->Ip4
->Receive (Private
->Ip4
, &Private
->IcmpToken
);
207 if (EFI_ERROR (Status
)) {
219 Notify the callback function when an event is triggered.
221 @param[in] Event The triggered event.
222 @param[in] Context The opaque parameter to the function.
232 *((BOOLEAN
*) Context
) = TRUE
;
237 Do arp resolution from arp cache in PxeBcMode.
239 @param Mode The pointer to EFI_PXE_BASE_CODE_MODE.
240 @param Ip4Addr The Ip4 address for resolution.
241 @param MacAddress The resoluted MAC address if the resolution is successful.
242 The value is undefined if the resolution fails.
244 @retval TRUE Found an matched entry.
245 @retval FALSE Did not find a matched entry.
250 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
251 IN EFI_IPv4_ADDRESS
*Ip4Addr
,
252 OUT EFI_MAC_ADDRESS
*MacAddress
257 ASSERT (!Mode
->UsingIpv6
);
260 // Check whether the current Arp cache in mode data contains this information or not.
262 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
263 if (EFI_IP4_EQUAL (&Mode
->ArpCache
[Index
].IpAddr
.v4
, Ip4Addr
)) {
266 &Mode
->ArpCache
[Index
].MacAddr
,
267 sizeof (EFI_MAC_ADDRESS
)
278 Update the arp cache periodically.
280 @param Event The pointer to EFI_PXE_BC_PROTOCOL.
281 @param Context Context of the timer event.
286 PxeBcArpCacheUpdate (
291 PXEBC_PRIVATE_DATA
*Private
;
292 EFI_PXE_BASE_CODE_MODE
*Mode
;
293 EFI_ARP_FIND_DATA
*ArpEntry
;
299 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
300 Mode
= Private
->PxeBc
.Mode
;
302 ASSERT (!Mode
->UsingIpv6
);
305 // Get the current Arp cache from Arp driver.
307 Status
= Private
->Arp
->Find (
316 if (EFI_ERROR (Status
)) {
321 // Update the Arp cache in mode data.
323 Mode
->ArpCacheEntries
= MIN (EntryCount
, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES
);
325 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
327 &Mode
->ArpCache
[Index
].IpAddr
,
329 ArpEntry
->SwAddressLength
332 &Mode
->ArpCache
[Index
].MacAddr
,
333 (UINT8
*) (ArpEntry
+ 1) + ArpEntry
->SwAddressLength
,
334 ArpEntry
->HwAddressLength
336 ArpEntry
= (EFI_ARP_FIND_DATA
*) ((UINT8
*) ArpEntry
+ EntryLength
);
342 Notify function to handle the received ICMP message in DPC.
344 @param Context The PXEBC private data.
349 PxeBcIcmpErrorDpcHandle (
354 EFI_IP4_RECEIVE_DATA
*RxData
;
355 EFI_IP4_PROTOCOL
*Ip4
;
356 PXEBC_PRIVATE_DATA
*Private
;
357 EFI_PXE_BASE_CODE_MODE
*Mode
;
363 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
364 Mode
= &Private
->Mode
;
365 Status
= Private
->IcmpToken
.Status
;
366 RxData
= Private
->IcmpToken
.Packet
.RxData
;
369 ASSERT (!Mode
->UsingIpv6
);
371 if (Status
== EFI_ABORTED
) {
373 // It's triggered by user cancellation.
378 if (RxData
== NULL
) {
382 if (Status
!= EFI_ICMP_ERROR
) {
384 // The return status should be recognized as EFI_ICMP_ERROR.
386 gBS
->SignalEvent (RxData
->RecycleSignal
);
390 if (EFI_IP4 (RxData
->Header
->SourceAddress
) != 0 &&
391 !NetIp4IsUnicast (EFI_NTOHL (RxData
->Header
->SourceAddress
), 0)) {
393 // The source address of the received packet should be a valid unicast address.
395 gBS
->SignalEvent (RxData
->RecycleSignal
);
399 if (!EFI_IP4_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v4
)) {
401 // The destination address of the received packet should be equal to the host address.
403 gBS
->SignalEvent (RxData
->RecycleSignal
);
407 if (RxData
->Header
->Protocol
!= EFI_IP_PROTO_ICMP
) {
409 // The protocol value in the header of the receveid packet should be EFI_IP_PROTO_ICMP.
411 gBS
->SignalEvent (RxData
->RecycleSignal
);
415 Type
= *((UINT8
*) RxData
->FragmentTable
[0].FragmentBuffer
);
417 if (Type
!= ICMP_DEST_UNREACHABLE
&&
418 Type
!= ICMP_SOURCE_QUENCH
&&
419 Type
!= ICMP_REDIRECT
&&
420 Type
!= ICMP_TIME_EXCEEDED
&&
421 Type
!= ICMP_PARAMETER_PROBLEM
) {
423 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
425 gBS
->SignalEvent (RxData
->RecycleSignal
);
430 // Copy the right ICMP error message into mode data.
433 IcmpError
= (UINT8
*) &Mode
->IcmpError
;
435 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
436 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
437 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
440 RxData
->FragmentTable
[Index
].FragmentBuffer
,
441 RxData
->FragmentTable
[Index
].FragmentLength
446 RxData
->FragmentTable
[Index
].FragmentBuffer
,
447 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
450 IcmpError
+= CopiedLen
;
454 Private
->IcmpToken
.Status
= EFI_NOT_READY
;
455 Ip4
->Receive (Ip4
, &Private
->IcmpToken
);
460 Callback function to update the latest ICMP6 error message.
462 @param Event The event signalled.
463 @param Context The context passed in using the event notifier.
468 PxeBcIcmpErrorUpdate (
473 QueueDpc (TPL_CALLBACK
, PxeBcIcmpErrorDpcHandle
, Context
);
478 Notify function to handle the received ICMP6 message in DPC.
480 @param Context The PXEBC private data.
485 PxeBcIcmp6ErrorDpcHandle (
489 PXEBC_PRIVATE_DATA
*Private
;
490 EFI_IP6_RECEIVE_DATA
*RxData
;
491 EFI_IP6_PROTOCOL
*Ip6
;
492 EFI_PXE_BASE_CODE_MODE
*Mode
;
499 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
500 Mode
= &Private
->Mode
;
501 Status
= Private
->Icmp6Token
.Status
;
502 RxData
= Private
->Icmp6Token
.Packet
.RxData
;
505 ASSERT (Mode
->UsingIpv6
);
507 if (Status
== EFI_ABORTED
) {
509 // It's triggered by user cancellation.
514 if (RxData
== NULL
) {
518 if (Status
!= EFI_ICMP_ERROR
) {
520 // The return status should be recognized as EFI_ICMP_ERROR.
522 gBS
->SignalEvent (RxData
->RecycleSignal
);
526 if (!NetIp6IsValidUnicast (&RxData
->Header
->SourceAddress
)) {
528 // The source address of the received packet should be a valid unicast address.
530 gBS
->SignalEvent (RxData
->RecycleSignal
);
534 if (!NetIp6IsUnspecifiedAddr (&Mode
->StationIp
.v6
) &&
535 !EFI_IP6_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v6
)) {
537 // The destination address of the received packet should be equal to the host address.
539 gBS
->SignalEvent (RxData
->RecycleSignal
);
543 if (RxData
->Header
->NextHeader
!= IP6_ICMP
) {
545 // The nextheader in the header of the receveid packet should be IP6_ICMP.
547 gBS
->SignalEvent (RxData
->RecycleSignal
);
551 Type
= *((UINT8
*) RxData
->FragmentTable
[0].FragmentBuffer
);
553 if (Type
!= ICMP_V6_DEST_UNREACHABLE
&&
554 Type
!= ICMP_V6_PACKET_TOO_BIG
&&
555 Type
!= ICMP_V6_PACKET_TOO_BIG
&&
556 Type
!= ICMP_V6_PARAMETER_PROBLEM
) {
558 // The type of the receveid packet should be an ICMP6 error message.
560 gBS
->SignalEvent (RxData
->RecycleSignal
);
565 // Copy the right ICMP6 error message into mode data.
568 Icmp6Error
= (UINT8
*) &Mode
->IcmpError
;
570 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
571 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
572 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
575 RxData
->FragmentTable
[Index
].FragmentBuffer
,
576 RxData
->FragmentTable
[Index
].FragmentLength
581 RxData
->FragmentTable
[Index
].FragmentBuffer
,
582 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
585 Icmp6Error
+= CopiedLen
;
589 Private
->Icmp6Token
.Status
= EFI_NOT_READY
;
590 Ip6
->Receive (Ip6
, &Private
->Icmp6Token
);
595 Callback function to update the latest ICMP6 error message.
597 @param Event The event signalled.
598 @param Context The context passed in using the event notifier.
603 PxeBcIcmp6ErrorUpdate (
608 QueueDpc (TPL_CALLBACK
, PxeBcIcmp6ErrorDpcHandle
, Context
);
613 This function is to configure a UDPv4 instance for UdpWrite.
615 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
616 @param[in] StationIp The pointer to the station address.
617 @param[in] SubnetMask The pointer to the subnet mask.
618 @param[in] Gateway The pointer to the gateway address.
619 @param[in, out] SrcPort The pointer to the source port.
620 @param[in] DoNotFragment If TRUE, fragment is not enabled.
621 Otherwise, fragment is enabled.
623 @retval EFI_SUCCESS Successfully configured this instance.
624 @retval Others Failed to configure this instance.
628 PxeBcConfigUdp4Write (
629 IN EFI_UDP4_PROTOCOL
*Udp4
,
630 IN EFI_IPv4_ADDRESS
*StationIp
,
631 IN EFI_IPv4_ADDRESS
*SubnetMask
,
632 IN EFI_IPv4_ADDRESS
*Gateway
,
633 IN OUT UINT16
*SrcPort
,
634 IN BOOLEAN DoNotFragment
637 EFI_UDP4_CONFIG_DATA Udp4CfgData
;
640 ZeroMem (&Udp4CfgData
, sizeof (Udp4CfgData
));
642 Udp4CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
643 Udp4CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
644 Udp4CfgData
.TypeOfService
= DEFAULT_ToS
;
645 Udp4CfgData
.TimeToLive
= DEFAULT_TTL
;
646 Udp4CfgData
.AllowDuplicatePort
= TRUE
;
647 Udp4CfgData
.DoNotFragment
= DoNotFragment
;
649 CopyMem (&Udp4CfgData
.StationAddress
, StationIp
, sizeof (*StationIp
));
650 CopyMem (&Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (*SubnetMask
));
652 Udp4CfgData
.StationPort
= *SrcPort
;
655 // Reset the UDPv4 instance.
657 Udp4
->Configure (Udp4
, NULL
);
659 Status
= Udp4
->Configure (Udp4
, &Udp4CfgData
);
660 if (!EFI_ERROR (Status
) && !EFI_IP4_EQUAL (Gateway
, &mZeroIp4Addr
)) {
662 // The basic configuration is OK, need to add the default route entry
664 Status
= Udp4
->Routes (Udp4
, FALSE
, &mZeroIp4Addr
, &mZeroIp4Addr
, Gateway
);
665 if (EFI_ERROR (Status
)) {
666 Udp4
->Configure (Udp4
, NULL
);
670 if (!EFI_ERROR (Status
) && *SrcPort
== 0) {
671 Udp4
->GetModeData (Udp4
, &Udp4CfgData
, NULL
, NULL
, NULL
);
672 *SrcPort
= Udp4CfgData
.StationPort
;
680 This function is to configure a UDPv6 instance for UdpWrite.
682 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
683 @param[in] StationIp The pointer to the station address.
684 @param[in, out] SrcPort The pointer to the source port.
686 @retval EFI_SUCCESS Successfully configured this instance.
687 @retval Others Failed to configure this instance.
691 PxeBcConfigUdp6Write (
692 IN EFI_UDP6_PROTOCOL
*Udp6
,
693 IN EFI_IPv6_ADDRESS
*StationIp
,
694 IN OUT UINT16
*SrcPort
697 EFI_UDP6_CONFIG_DATA CfgData
;
700 ZeroMem (&CfgData
, sizeof (EFI_UDP6_CONFIG_DATA
));
702 CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
703 CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
704 CfgData
.HopLimit
= PXEBC_DEFAULT_HOPLIMIT
;
705 CfgData
.AllowDuplicatePort
= TRUE
;
706 CfgData
.StationPort
= *SrcPort
;
708 CopyMem (&CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
711 // Reset the UDPv6 instance.
713 Udp6
->Configure (Udp6
, NULL
);
715 Status
= Udp6
->Configure (Udp6
, &CfgData
);
716 if (EFI_ERROR (Status
)) {
720 if (!EFI_ERROR (Status
) && *SrcPort
== 0) {
721 Udp6
->GetModeData (Udp6
, &CfgData
, NULL
, NULL
, NULL
);
722 *SrcPort
= CfgData
.StationPort
;
730 This function is to configure a UDPv4 instance for UdpWrite.
732 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
733 @param[in] Session The pointer to the UDP4 session data.
734 @param[in] TimeoutEvent The event for timeout.
735 @param[in] Gateway The pointer to the gateway address.
736 @param[in] HeaderSize An optional field which may be set to the length of a header
737 at HeaderPtr to be prefixed to the data at BufferPtr.
738 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
739 prefixed to the data at BufferPtr.
740 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
741 @param[in] BufferPtr A pointer to the data to be written.
743 @retval EFI_SUCCESS Successfully send out data using Udp4Write.
744 @retval Others Failed to send out data.
749 IN EFI_UDP4_PROTOCOL
*Udp4
,
750 IN EFI_UDP4_SESSION_DATA
*Session
,
751 IN EFI_EVENT TimeoutEvent
,
752 IN EFI_IPv4_ADDRESS
*Gateway OPTIONAL
,
753 IN UINTN
*HeaderSize OPTIONAL
,
754 IN VOID
*HeaderPtr OPTIONAL
,
755 IN UINTN
*BufferSize
,
759 EFI_UDP4_COMPLETION_TOKEN Token
;
760 EFI_UDP4_TRANSMIT_DATA
*TxData
;
768 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
770 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
771 TxLength
= sizeof (EFI_UDP4_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP4_FRAGMENT_DATA
);
772 TxData
= (EFI_UDP4_TRANSMIT_DATA
*) AllocateZeroPool (TxLength
);
773 if (TxData
== NULL
) {
774 return EFI_OUT_OF_RESOURCES
;
777 TxData
->FragmentCount
= FragCount
;
778 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
) *BufferSize
;
779 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
780 DataLength
= (UINT32
) *BufferSize
;
782 if (HeaderSize
!= NULL
) {
783 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) *HeaderSize
;
784 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
785 DataLength
+= (UINT32
) *HeaderSize
;
788 if (Gateway
!= NULL
) {
789 TxData
->GatewayAddress
= Gateway
;
792 TxData
->UdpSessionData
= Session
;
793 TxData
->DataLength
= DataLength
;
794 Token
.Packet
.TxData
= TxData
;
795 Token
.Status
= EFI_NOT_READY
;
798 Status
= gBS
->CreateEvent (
805 if (EFI_ERROR (Status
)) {
809 Status
= Udp4
->Transmit (Udp4
, &Token
);
810 if (EFI_ERROR (Status
)) {
815 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
818 Token
.Status
== EFI_NOT_READY
&&
819 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
823 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
826 if (Token
.Event
!= NULL
) {
827 gBS
->CloseEvent (Token
.Event
);
836 This function is to configure a UDPv4 instance for UdpWrite.
838 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
839 @param[in] Session The pointer to the UDP6 session data.
840 @param[in] TimeoutEvent The event for timeout.
841 @param[in] HeaderSize An optional field which may be set to the length of a header
842 at HeaderPtr to be prefixed to the data at BufferPtr.
843 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
844 prefixed to the data at BufferPtr.
845 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
846 @param[in] BufferPtr A pointer to the data to be written.
848 @retval EFI_SUCCESS Successfully sent out data using Udp6Write.
849 @retval Others Failed to send out data.
854 IN EFI_UDP6_PROTOCOL
*Udp6
,
855 IN EFI_UDP6_SESSION_DATA
*Session
,
856 IN EFI_EVENT TimeoutEvent
,
857 IN UINTN
*HeaderSize OPTIONAL
,
858 IN VOID
*HeaderPtr OPTIONAL
,
859 IN UINTN
*BufferSize
,
863 EFI_UDP6_COMPLETION_TOKEN Token
;
864 EFI_UDP6_TRANSMIT_DATA
*TxData
;
872 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
874 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
875 TxLength
= sizeof (EFI_UDP6_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP6_FRAGMENT_DATA
);
876 TxData
= (EFI_UDP6_TRANSMIT_DATA
*) AllocateZeroPool (TxLength
);
877 if (TxData
== NULL
) {
878 return EFI_OUT_OF_RESOURCES
;
881 TxData
->FragmentCount
= FragCount
;
882 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
) *BufferSize
;
883 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
884 DataLength
= (UINT32
) *BufferSize
;
886 if (HeaderSize
!= NULL
) {
887 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) *HeaderSize
;
888 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
889 DataLength
+= (UINT32
) *HeaderSize
;
892 TxData
->UdpSessionData
= Session
;
893 TxData
->DataLength
= DataLength
;
894 Token
.Packet
.TxData
= TxData
;
895 Token
.Status
= EFI_NOT_READY
;
898 Status
= gBS
->CreateEvent (
905 if (EFI_ERROR (Status
)) {
909 Status
= Udp6
->Transmit (Udp6
, &Token
);
910 if (EFI_ERROR (Status
)) {
915 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
918 Token
.Status
== EFI_NOT_READY
&&
919 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
923 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
926 if (Token
.Event
!= NULL
) {
927 gBS
->CloseEvent (Token
.Event
);
936 Check the received packet using the Ip filter.
938 @param[in] Mode The pointer to the mode data of PxeBc.
939 @param[in] Session The pointer to the current UDPv4 session.
940 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
942 @retval TRUE Passed the Ip filter successfully.
943 @retval FALSE Failed to pass the Ip filter.
947 PxeBcCheckByIpFilter (
948 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
953 EFI_IP_ADDRESS DestinationIp
;
956 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
) == 0) {
960 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS
) != 0) {
965 // Convert the destination address in session data to host order.
967 if (Mode
->UsingIpv6
) {
970 &((EFI_UDP6_SESSION_DATA
*) Session
)->DestinationAddress
,
971 sizeof (EFI_IPv6_ADDRESS
)
973 NTOHLLL (&DestinationIp
.v6
);
975 ZeroMem (&DestinationIp
, sizeof (EFI_IP_ADDRESS
));
978 &((EFI_UDP4_SESSION_DATA
*) Session
)->DestinationAddress
,
979 sizeof (EFI_IPv4_ADDRESS
)
981 EFI_NTOHL (DestinationIp
);
984 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST
) != 0 &&
985 (IP4_IS_MULTICAST (DestinationIp
.Addr
[0]) ||
986 IP6_IS_MULTICAST (&DestinationIp
))) {
990 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
) != 0 &&
991 IP4_IS_LOCAL_BROADCAST (DestinationIp
.Addr
[0])) {
992 ASSERT (!Mode
->UsingIpv6
);
996 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
) != 0 &&
997 (EFI_IP4_EQUAL (&Mode
->StationIp
.v4
, &DestinationIp
) ||
998 EFI_IP6_EQUAL (&Mode
->StationIp
.v6
, &DestinationIp
))) {
1000 // Matched if the dest address is equal to the station address.
1005 for (Index
= 0; Index
< Mode
->IpFilter
.IpCnt
; Index
++) {
1006 ASSERT (Index
< EFI_PXE_BASE_CODE_MAX_IPCNT
);
1007 if (EFI_IP4_EQUAL (&Mode
->IpFilter
.IpList
[Index
].v4
, &DestinationIp
) ||
1008 EFI_IP6_EQUAL (&Mode
->IpFilter
.IpList
[Index
].v6
, &DestinationIp
)) {
1010 // Matched if the dest address is equal to any of address in the filter list.
1021 Filter the received packet using the destination Ip.
1023 @param[in] Mode The pointer to the mode data of PxeBc.
1024 @param[in] Session The pointer to the current UDPv4 session.
1025 @param[in, out] DestIp The pointer to the destination Ip address.
1026 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1028 @retval TRUE Passed the IPv4 filter successfully.
1029 @retval FALSE Failed to pass the IPv4 filter.
1033 PxeBcCheckByDestIp (
1034 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1036 IN OUT EFI_IP_ADDRESS
*DestIp
,
1040 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
) != 0) {
1042 // Copy the destination address from the received packet if accept any.
1044 if (DestIp
!= NULL
) {
1045 if (Mode
->UsingIpv6
) {
1048 &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
,
1049 sizeof (EFI_IPv6_ADDRESS
)
1052 ZeroMem (DestIp
, sizeof (EFI_IP_ADDRESS
));
1055 &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
,
1056 sizeof (EFI_IPv4_ADDRESS
)
1062 } else if (DestIp
!= NULL
&&
1063 (EFI_IP4_EQUAL (DestIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
1064 EFI_IP6_EQUAL (DestIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
))) {
1066 // The destination address in the received packet is matched if present.
1069 } else if (EFI_IP4_EQUAL (&Mode
->StationIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
1070 EFI_IP6_EQUAL (&Mode
->StationIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
)) {
1072 // The destination address in the received packet is equal to the host address.
1082 Check the received packet using the destination port.
1084 @param[in] PxeBcMode The pointer to the mode data of PxeBc.
1085 @param[in] Session The pointer to the current UDPv4 session.
1086 @param[in, out] DestPort The pointer to the destination port.
1087 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1089 @retval TRUE Passed the IPv4 filter successfully.
1090 @retval FALSE Failed to pass the IPv4 filter.
1094 PxeBcCheckByDestPort (
1095 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1097 IN OUT UINT16
*DestPort
,
1103 if (Mode
->UsingIpv6
) {
1104 Port
= ((EFI_UDP6_SESSION_DATA
*) Session
)->DestinationPort
;
1106 Port
= ((EFI_UDP4_SESSION_DATA
*) Session
)->DestinationPort
;
1109 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT
) != 0) {
1111 // Return the destination port in the received packet if accept any.
1113 if (DestPort
!= NULL
) {
1117 } else if (DestPort
!= NULL
&& *DestPort
== Port
) {
1119 // The destination port in the received packet is matched if present.
1129 Filter the received packet using the source Ip.
1131 @param[in] Mode The pointer to the mode data of PxeBc.
1132 @param[in] Session The pointer to the current UDPv4 session.
1133 @param[in, out] SrcIp The pointer to the source Ip address.
1134 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1136 @retval TRUE Passed the IPv4 filter successfully.
1137 @retval FALSE Failed to pass the IPv4 filter.
1141 PxeBcFilterBySrcIp (
1142 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1144 IN OUT EFI_IP_ADDRESS
*SrcIp
,
1148 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
) != 0) {
1150 // Copy the source address from the received packet if accept any.
1152 if (SrcIp
!= NULL
) {
1153 if (Mode
->UsingIpv6
) {
1156 &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
,
1157 sizeof (EFI_IPv6_ADDRESS
)
1160 ZeroMem (SrcIp
, sizeof (EFI_IP_ADDRESS
));
1163 &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
,
1164 sizeof (EFI_IPv4_ADDRESS
)
1170 } else if (SrcIp
!= NULL
&&
1171 (EFI_IP4_EQUAL (SrcIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
) ||
1172 EFI_IP6_EQUAL (SrcIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
))) {
1174 // The source address in the received packet is matched if present.
1184 Filter the received packet using the source port.
1186 @param[in] Mode The pointer to the mode data of PxeBc.
1187 @param[in] Session The pointer to the current UDPv4 session.
1188 @param[in, out] SrcPort The pointer to the source port.
1189 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1191 @retval TRUE Passed the IPv4 filter successfully.
1192 @retval FALSE Failed to pass the IPv4 filter.
1196 PxeBcFilterBySrcPort (
1197 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1199 IN OUT UINT16
*SrcPort
,
1205 if (Mode
->UsingIpv6
) {
1206 Port
= ((EFI_UDP6_SESSION_DATA
*) Session
)->SourcePort
;
1208 Port
= ((EFI_UDP4_SESSION_DATA
*) Session
)->SourcePort
;
1211 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
) != 0) {
1213 // Return the source port in the received packet if accept any.
1215 if (SrcPort
!= NULL
) {
1219 } else if (SrcPort
!= NULL
&& *SrcPort
== Port
) {
1221 // The source port in the received packet is matched if present.
1231 This function is to receive packet using Udp4Read.
1233 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
1234 @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN.
1235 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1236 @param[in] TimeoutEvent The event for timeout.
1237 @param[in] OpFlags The UDP operation flags.
1238 @param[in] IsDone The pointer to the IsDone flag.
1239 @param[out] IsMatched The pointer to the IsMatched flag.
1240 @param[in, out] DestIp The pointer to the destination address.
1241 @param[in, out] DestPort The pointer to the destination port.
1242 @param[in, out] SrcIp The pointer to the source address.
1243 @param[in, out] SrcPort The pointer to the source port.
1245 @retval EFI_SUCCESS Successfully read the data using Udp4.
1246 @retval Others Failed to send out data.
1251 IN EFI_UDP4_PROTOCOL
*Udp4
,
1252 IN EFI_UDP4_COMPLETION_TOKEN
*Token
,
1253 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1254 IN EFI_EVENT TimeoutEvent
,
1257 OUT BOOLEAN
*IsMatched
,
1258 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1259 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1260 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1261 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1264 EFI_UDP4_RECEIVE_DATA
*RxData
;
1265 EFI_UDP4_SESSION_DATA
*Session
;
1268 Token
->Status
= EFI_NOT_READY
;
1271 Status
= Udp4
->Receive (Udp4
, Token
);
1272 if (EFI_ERROR (Status
)) {
1277 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1279 while (!(*IsDone
) &&
1280 Token
->Status
== EFI_NOT_READY
&&
1281 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1283 // Poll the token utill reply/ICMPv6 error message received or timeout.
1286 if (Token
->Status
== EFI_ICMP_ERROR
||
1287 Token
->Status
== EFI_NETWORK_UNREACHABLE
||
1288 Token
->Status
== EFI_HOST_UNREACHABLE
||
1289 Token
->Status
== EFI_PROTOCOL_UNREACHABLE
||
1290 Token
->Status
== EFI_PORT_UNREACHABLE
) {
1295 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1297 if (!EFI_ERROR (Status
)) {
1299 // check whether this packet matches the filters
1301 RxData
= Token
->Packet
.RxData
;
1302 Session
= &RxData
->UdpSession
;
1304 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1307 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1311 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1315 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1319 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1322 if (!(*IsMatched
)) {
1324 // Recycle the receiving buffer if not matched.
1326 gBS
->SignalEvent (RxData
->RecycleSignal
);
1335 This function is to receive packets using Udp6Read.
1337 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
1338 @param[in] Token The pointer to EFI_UDP6_COMPLETION_TOKEN.
1339 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1340 @param[in] TimeoutEvent The event for timeout.
1341 @param[in] OpFlags The UDP operation flags.
1342 @param[in] IsDone The pointer to the IsDone flag.
1343 @param[out] IsMatched The pointer to the IsMatched flag.
1344 @param[in, out] DestIp The pointer to the destination address.
1345 @param[in, out] DestPort The pointer to the destination port.
1346 @param[in, out] SrcIp The pointer to the source address.
1347 @param[in, out] SrcPort The pointer to the source port.
1349 @retval EFI_SUCCESS Successfully read data using Udp6.
1350 @retval Others Failed to send out data.
1355 IN EFI_UDP6_PROTOCOL
*Udp6
,
1356 IN EFI_UDP6_COMPLETION_TOKEN
*Token
,
1357 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1358 IN EFI_EVENT TimeoutEvent
,
1361 OUT BOOLEAN
*IsMatched
,
1362 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1363 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1364 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1365 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1368 EFI_UDP6_RECEIVE_DATA
*RxData
;
1369 EFI_UDP6_SESSION_DATA
*Session
;
1372 Token
->Status
= EFI_NOT_READY
;
1375 Status
= Udp6
->Receive (Udp6
, Token
);
1376 if (EFI_ERROR (Status
)) {
1381 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1383 while (!(*IsDone
) &&
1384 Token
->Status
== EFI_NOT_READY
&&
1385 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1387 // Poll the token utill reply/ICMPv6 error message received or timeout.
1390 if (Token
->Status
== EFI_ICMP_ERROR
||
1391 Token
->Status
== EFI_NETWORK_UNREACHABLE
||
1392 Token
->Status
== EFI_HOST_UNREACHABLE
||
1393 Token
->Status
== EFI_PROTOCOL_UNREACHABLE
||
1394 Token
->Status
== EFI_PORT_UNREACHABLE
) {
1399 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1401 if (!EFI_ERROR (Status
)) {
1403 // check whether this packet matches the filters
1405 RxData
= Token
->Packet
.RxData
;
1406 Session
= &RxData
->UdpSession
;
1408 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1411 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1415 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1419 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1423 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1426 if (!(*IsMatched
)) {
1428 // Recycle the receiving buffer if not matched.
1430 gBS
->SignalEvent (RxData
->RecycleSignal
);
1439 This function is to display the IPv4 address.
1441 @param[in] Ip The pointer to the IPv4 address.
1446 IN EFI_IPv4_ADDRESS
*Ip
1451 for (Index
= 0; Index
< 4; Index
++) {
1452 AsciiPrint ("%d", Ip
->Addr
[Index
]);
1461 This function is to display the IPv6 address.
1463 @param[in] Ip The pointer to the IPv6 address.
1468 IN EFI_IPv6_ADDRESS
*Ip
1473 for (Index
= 0; Index
< 16; Index
++) {
1475 if (Ip
->Addr
[Index
] != 0) {
1476 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1482 if (((Ip
->Addr
[Index
] & 0xf0) == 0) && (Ip
->Addr
[Index
- 1] != 0)) {
1485 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1494 This function is to convert UINTN to ASCII string with the required formatting.
1496 @param[in] Number Numeric value to be converted.
1497 @param[in] Buffer The pointer to the buffer for ASCII string.
1498 @param[in] Length The length of the required format.
1502 PxeBcUintnToAscDecWithFormat (
1510 while (Length
> 0) {
1512 Remainder
= Number
% 10;
1514 Buffer
[Length
] = (UINT8
) ('0' + Remainder
);
1520 This function is to convert a UINTN to a ASCII string, and return the
1521 actual length of the buffer.
1523 @param[in] Number Numeric value to be converted.
1524 @param[in] Buffer The pointer to the buffer for ASCII string.
1526 @return Length The actual length of the ASCII string.
1530 PxeBcUintnToAscDec (
1544 TempStr
[Index
] = (CHAR8
) ('0' + (Number
% 10));
1545 Number
= (UINTN
) (Number
/ 10);
1546 } while (Number
!= 0);
1548 AsciiStrCpy ((CHAR8
*) Buffer
, &TempStr
[Index
]);
1550 Length
= AsciiStrLen ((CHAR8
*) Buffer
);
1557 This function is to convert unicode hex number to a UINT8.
1559 @param[out] Digit The converted UINT8 for output.
1560 @param[in] Char The unicode hex number to be converted.
1562 @retval EFI_SUCCESS Successfully converted the unicode hex.
1563 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.
1567 PxeBcUniHexToUint8 (
1572 if ((Char
>= L
'0') && (Char
<= L
'9')) {
1573 *Digit
= (UINT8
) (Char
- L
'0');
1577 if ((Char
>= L
'A') && (Char
<= L
'F')) {
1578 *Digit
= (UINT8
) (Char
- L
'A' + 0x0A);
1582 if ((Char
>= L
'a') && (Char
<= L
'f')) {
1583 *Digit
= (UINT8
) (Char
- L
'a' + 0x0A);
1587 return EFI_INVALID_PARAMETER
;