2 Support functions implementation for UefiPxeBc Driver.
4 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "PxeBcImpl.h"
13 Flush the previous configuration using the new station Ip address.
15 @param[in] Private The pointer to the PxeBc private data.
16 @param[in] StationIp The pointer to the station Ip address.
17 @param[in] SubnetMask The pointer to the subnet mask address for v4.
19 @retval EFI_SUCCESS Successfully flushed the previous configuration.
20 @retval Others Failed to flush using the new station Ip.
25 PXEBC_PRIVATE_DATA
*Private
,
26 EFI_IP_ADDRESS
*StationIp OPTIONAL
,
27 EFI_IP_ADDRESS
*SubnetMask OPTIONAL
30 EFI_PXE_BASE_CODE_MODE
*Mode
;
32 EFI_ARP_CONFIG_DATA ArpConfigData
;
34 Mode
= Private
->PxeBc
.Mode
;
36 ZeroMem (&ArpConfigData
, sizeof (EFI_ARP_CONFIG_DATA
));
38 if (Mode
->UsingIpv6
&& (StationIp
!= NULL
)) {
40 // Overwrite Udp6CfgData/Ip6CfgData StationAddress.
42 CopyMem (&Private
->Udp6CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
43 CopyMem (&Private
->Ip6CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
46 // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address.
48 Private
->Ip6
->Cancel (Private
->Ip6
, &Private
->Icmp6Token
);
49 Private
->Ip6
->Configure (Private
->Ip6
, NULL
);
51 Status
= Private
->Ip6
->Configure (Private
->Ip6
, &Private
->Ip6CfgData
);
52 if (EFI_ERROR (Status
)) {
56 Status
= Private
->Ip6
->Receive (Private
->Ip6
, &Private
->Icmp6Token
);
58 if (StationIp
!= NULL
) {
60 // Reconfigure the ARP instance with station Ip address.
62 ArpConfigData
.SwAddressType
= 0x0800;
63 ArpConfigData
.SwAddressLength
= (UINT8
)sizeof (EFI_IPv4_ADDRESS
);
64 ArpConfigData
.StationAddress
= StationIp
;
66 Private
->Arp
->Configure (Private
->Arp
, NULL
);
67 Private
->Arp
->Configure (Private
->Arp
, &ArpConfigData
);
70 // Overwrite Udp4CfgData/Ip4CfgData StationAddress.
72 CopyMem (&Private
->Udp4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
73 CopyMem (&Private
->Ip4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
76 if (SubnetMask
!= NULL
) {
78 // Overwrite Udp4CfgData/Ip4CfgData SubnetMask.
80 CopyMem (&Private
->Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
81 CopyMem (&Private
->Ip4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
84 if ((StationIp
!= NULL
) && (SubnetMask
!= NULL
)) {
86 // Updated the route table.
88 Mode
->RouteTableEntries
= 1;
89 Mode
->RouteTable
[0].IpAddr
.Addr
[0] = StationIp
->Addr
[0] & SubnetMask
->Addr
[0];
90 Mode
->RouteTable
[0].SubnetMask
.Addr
[0] = SubnetMask
->Addr
[0];
91 Mode
->RouteTable
[0].GwAddr
.Addr
[0] = 0;
94 if ((StationIp
!= NULL
) || (SubnetMask
!= NULL
)) {
96 // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
98 Private
->Ip4
->Cancel (Private
->Ip4
, &Private
->IcmpToken
);
99 Private
->Ip4
->Configure (Private
->Ip4
, NULL
);
101 Status
= Private
->Ip4
->Configure (Private
->Ip4
, &Private
->Ip4CfgData
);
102 if (EFI_ERROR (Status
)) {
106 Status
= Private
->Ip4
->Receive (Private
->Ip4
, &Private
->IcmpToken
);
115 Notify the callback function when an event is triggered.
117 @param[in] Event The triggered event.
118 @param[in] Context The opaque parameter to the function.
128 *((BOOLEAN
*)Context
) = TRUE
;
132 Do arp resolution from arp cache in PxeBcMode.
134 @param Mode The pointer to EFI_PXE_BASE_CODE_MODE.
135 @param Ip4Addr The Ip4 address for resolution.
136 @param MacAddress The resolved MAC address if the resolution is successful.
137 The value is undefined if the resolution fails.
139 @retval TRUE Found an matched entry.
140 @retval FALSE Did not find a matched entry.
145 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
146 IN EFI_IPv4_ADDRESS
*Ip4Addr
,
147 OUT EFI_MAC_ADDRESS
*MacAddress
152 ASSERT (!Mode
->UsingIpv6
);
155 // Check whether the current Arp cache in mode data contains this information or not.
157 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
158 if (EFI_IP4_EQUAL (&Mode
->ArpCache
[Index
].IpAddr
.v4
, Ip4Addr
)) {
161 &Mode
->ArpCache
[Index
].MacAddr
,
162 sizeof (EFI_MAC_ADDRESS
)
172 Update the arp cache periodically.
174 @param Event The pointer to EFI_PXE_BC_PROTOCOL.
175 @param Context Context of the timer event.
180 PxeBcArpCacheUpdate (
185 PXEBC_PRIVATE_DATA
*Private
;
186 EFI_PXE_BASE_CODE_MODE
*Mode
;
187 EFI_ARP_FIND_DATA
*ArpEntry
;
193 Private
= (PXEBC_PRIVATE_DATA
*)Context
;
194 Mode
= Private
->PxeBc
.Mode
;
196 ASSERT (!Mode
->UsingIpv6
);
199 // Get the current Arp cache from Arp driver.
201 Status
= Private
->Arp
->Find (
210 if (EFI_ERROR (Status
)) {
215 // Update the Arp cache in mode data.
217 Mode
->ArpCacheEntries
= MIN (EntryCount
, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES
);
219 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
221 &Mode
->ArpCache
[Index
].IpAddr
,
223 ArpEntry
->SwAddressLength
226 &Mode
->ArpCache
[Index
].MacAddr
,
227 (UINT8
*)(ArpEntry
+ 1) + ArpEntry
->SwAddressLength
,
228 ArpEntry
->HwAddressLength
230 ArpEntry
= (EFI_ARP_FIND_DATA
*)((UINT8
*)ArpEntry
+ EntryLength
);
235 Notify function to handle the received ICMP message in DPC.
237 @param Context The PXEBC private data.
242 PxeBcIcmpErrorDpcHandle (
247 EFI_IP4_RECEIVE_DATA
*RxData
;
248 EFI_IP4_PROTOCOL
*Ip4
;
249 PXEBC_PRIVATE_DATA
*Private
;
250 EFI_PXE_BASE_CODE_MODE
*Mode
;
256 Private
= (PXEBC_PRIVATE_DATA
*)Context
;
257 Mode
= &Private
->Mode
;
258 Status
= Private
->IcmpToken
.Status
;
259 RxData
= Private
->IcmpToken
.Packet
.RxData
;
262 ASSERT (!Mode
->UsingIpv6
);
264 if (Status
== EFI_ABORTED
) {
266 // It's triggered by user cancellation.
271 if (RxData
== NULL
) {
275 if (Status
!= EFI_ICMP_ERROR
) {
277 // The return status should be recognized as EFI_ICMP_ERROR.
282 if ((EFI_IP4 (RxData
->Header
->SourceAddress
) != 0) &&
283 (NTOHL (Mode
->SubnetMask
.Addr
[0]) != 0) &&
284 IP4_NET_EQUAL (NTOHL (Mode
->StationIp
.Addr
[0]), EFI_NTOHL (RxData
->Header
->SourceAddress
), NTOHL (Mode
->SubnetMask
.Addr
[0])) &&
285 !NetIp4IsUnicast (EFI_NTOHL (RxData
->Header
->SourceAddress
), NTOHL (Mode
->SubnetMask
.Addr
[0])))
288 // The source address of the received packet should be a valid unicast address.
293 if (!EFI_IP4_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v4
)) {
295 // The destination address of the received packet should be equal to the host address.
301 // The protocol has been configured to only receive ICMP packet.
303 ASSERT (RxData
->Header
->Protocol
== EFI_IP_PROTO_ICMP
);
305 Type
= *((UINT8
*)RxData
->FragmentTable
[0].FragmentBuffer
);
307 if ((Type
!= ICMP_DEST_UNREACHABLE
) &&
308 (Type
!= ICMP_SOURCE_QUENCH
) &&
309 (Type
!= ICMP_REDIRECT
) &&
310 (Type
!= ICMP_TIME_EXCEEDED
) &&
311 (Type
!= ICMP_PARAMETER_PROBLEM
))
314 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
320 // Copy the right ICMP error message into mode data.
323 IcmpError
= (UINT8
*)&Mode
->IcmpError
;
325 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
326 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
327 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
330 RxData
->FragmentTable
[Index
].FragmentBuffer
,
331 RxData
->FragmentTable
[Index
].FragmentLength
336 RxData
->FragmentTable
[Index
].FragmentBuffer
,
337 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
341 IcmpError
+= CopiedLen
;
345 gBS
->SignalEvent (RxData
->RecycleSignal
);
348 Private
->IcmpToken
.Status
= EFI_NOT_READY
;
349 Ip4
->Receive (Ip4
, &Private
->IcmpToken
);
353 Callback function to update the latest ICMP6 error message.
355 @param Event The event signalled.
356 @param Context The context passed in using the event notifier.
361 PxeBcIcmpErrorUpdate (
366 QueueDpc (TPL_CALLBACK
, PxeBcIcmpErrorDpcHandle
, Context
);
370 Notify function to handle the received ICMP6 message in DPC.
372 @param Context The PXEBC private data.
377 PxeBcIcmp6ErrorDpcHandle (
381 PXEBC_PRIVATE_DATA
*Private
;
382 EFI_IP6_RECEIVE_DATA
*RxData
;
383 EFI_IP6_PROTOCOL
*Ip6
;
384 EFI_PXE_BASE_CODE_MODE
*Mode
;
391 Private
= (PXEBC_PRIVATE_DATA
*)Context
;
392 Mode
= &Private
->Mode
;
393 Status
= Private
->Icmp6Token
.Status
;
394 RxData
= Private
->Icmp6Token
.Packet
.RxData
;
397 ASSERT (Mode
->UsingIpv6
);
399 if (Status
== EFI_ABORTED
) {
401 // It's triggered by user cancellation.
406 if (RxData
== NULL
) {
410 if (Status
!= EFI_ICMP_ERROR
) {
412 // The return status should be recognized as EFI_ICMP_ERROR.
417 if (!NetIp6IsValidUnicast (&RxData
->Header
->SourceAddress
)) {
419 // The source address of the received packet should be a valid unicast address.
424 if (!NetIp6IsUnspecifiedAddr (&Mode
->StationIp
.v6
) &&
425 !EFI_IP6_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v6
))
428 // The destination address of the received packet should be equal to the host address.
434 // The protocol has been configured to only receive ICMP packet.
436 ASSERT (RxData
->Header
->NextHeader
== IP6_ICMP
);
438 Type
= *((UINT8
*)RxData
->FragmentTable
[0].FragmentBuffer
);
440 if ((Type
!= ICMP_V6_DEST_UNREACHABLE
) &&
441 (Type
!= ICMP_V6_PACKET_TOO_BIG
) &&
442 (Type
!= ICMP_V6_TIME_EXCEEDED
) &&
443 (Type
!= ICMP_V6_PARAMETER_PROBLEM
))
446 // The type of the receveid packet should be an ICMP6 error message.
452 // Copy the right ICMP6 error message into mode data.
455 Icmp6Error
= (UINT8
*)&Mode
->IcmpError
;
457 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
458 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
459 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
462 RxData
->FragmentTable
[Index
].FragmentBuffer
,
463 RxData
->FragmentTable
[Index
].FragmentLength
468 RxData
->FragmentTable
[Index
].FragmentBuffer
,
469 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
473 Icmp6Error
+= CopiedLen
;
477 gBS
->SignalEvent (RxData
->RecycleSignal
);
480 Private
->Icmp6Token
.Status
= EFI_NOT_READY
;
481 Ip6
->Receive (Ip6
, &Private
->Icmp6Token
);
485 Callback function to update the latest ICMP6 error message.
487 @param Event The event signalled.
488 @param Context The context passed in using the event notifier.
493 PxeBcIcmp6ErrorUpdate (
498 QueueDpc (TPL_CALLBACK
, PxeBcIcmp6ErrorDpcHandle
, Context
);
502 This function is to configure a UDPv4 instance for UdpWrite.
504 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
505 @param[in] StationIp The pointer to the station address.
506 @param[in] SubnetMask The pointer to the subnet mask.
507 @param[in] Gateway The pointer to the gateway address.
508 @param[in, out] SrcPort The pointer to the source port.
509 @param[in] DoNotFragment If TRUE, fragment is not enabled.
510 Otherwise, fragment is enabled.
511 @param[in] Ttl The time to live field of the IP header.
512 @param[in] ToS The type of service field of the IP header.
514 @retval EFI_SUCCESS Successfully configured this instance.
515 @retval Others Failed to configure this instance.
519 PxeBcConfigUdp4Write (
520 IN EFI_UDP4_PROTOCOL
*Udp4
,
521 IN EFI_IPv4_ADDRESS
*StationIp
,
522 IN EFI_IPv4_ADDRESS
*SubnetMask
,
523 IN EFI_IPv4_ADDRESS
*Gateway
,
524 IN OUT UINT16
*SrcPort
,
525 IN BOOLEAN DoNotFragment
,
530 EFI_UDP4_CONFIG_DATA Udp4CfgData
;
533 ZeroMem (&Udp4CfgData
, sizeof (Udp4CfgData
));
535 Udp4CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
536 Udp4CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
537 Udp4CfgData
.TypeOfService
= ToS
;
538 Udp4CfgData
.TimeToLive
= Ttl
;
539 Udp4CfgData
.AllowDuplicatePort
= TRUE
;
540 Udp4CfgData
.DoNotFragment
= DoNotFragment
;
542 CopyMem (&Udp4CfgData
.StationAddress
, StationIp
, sizeof (*StationIp
));
543 CopyMem (&Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (*SubnetMask
));
545 Udp4CfgData
.StationPort
= *SrcPort
;
548 // Reset the UDPv4 instance.
550 Udp4
->Configure (Udp4
, NULL
);
552 Status
= Udp4
->Configure (Udp4
, &Udp4CfgData
);
553 if (!EFI_ERROR (Status
) && !EFI_IP4_EQUAL (Gateway
, &mZeroIp4Addr
)) {
555 // The basic configuration is OK, need to add the default route entry
557 Status
= Udp4
->Routes (Udp4
, FALSE
, &mZeroIp4Addr
, &mZeroIp4Addr
, Gateway
);
558 if (EFI_ERROR (Status
)) {
559 Udp4
->Configure (Udp4
, NULL
);
563 if (!EFI_ERROR (Status
) && (*SrcPort
== 0)) {
564 Udp4
->GetModeData (Udp4
, &Udp4CfgData
, NULL
, NULL
, NULL
);
565 *SrcPort
= Udp4CfgData
.StationPort
;
572 This function is to configure a UDPv6 instance for UdpWrite.
574 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
575 @param[in] StationIp The pointer to the station address.
576 @param[in, out] SrcPort The pointer to the source port.
578 @retval EFI_SUCCESS Successfully configured this instance.
579 @retval Others Failed to configure this instance.
583 PxeBcConfigUdp6Write (
584 IN EFI_UDP6_PROTOCOL
*Udp6
,
585 IN EFI_IPv6_ADDRESS
*StationIp
,
586 IN OUT UINT16
*SrcPort
589 EFI_UDP6_CONFIG_DATA CfgData
;
592 ZeroMem (&CfgData
, sizeof (EFI_UDP6_CONFIG_DATA
));
594 CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
595 CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
596 CfgData
.HopLimit
= PXEBC_DEFAULT_HOPLIMIT
;
597 CfgData
.AllowDuplicatePort
= TRUE
;
598 CfgData
.StationPort
= *SrcPort
;
600 CopyMem (&CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
603 // Reset the UDPv6 instance.
605 Udp6
->Configure (Udp6
, NULL
);
607 Status
= Udp6
->Configure (Udp6
, &CfgData
);
608 if (EFI_ERROR (Status
)) {
612 if (!EFI_ERROR (Status
) && (*SrcPort
== 0)) {
613 Udp6
->GetModeData (Udp6
, &CfgData
, NULL
, NULL
, NULL
);
614 *SrcPort
= CfgData
.StationPort
;
621 This function is to configure a UDPv4 instance for UdpWrite.
623 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
624 @param[in] Session The pointer to the UDP4 session data.
625 @param[in] TimeoutEvent The event for timeout.
626 @param[in] Gateway The pointer to the gateway address.
627 @param[in] HeaderSize An optional field which may be set to the length of a header
628 at HeaderPtr to be prefixed to the data at BufferPtr.
629 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
630 prefixed to the data at BufferPtr.
631 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
632 @param[in] BufferPtr A pointer to the data to be written.
634 @retval EFI_SUCCESS Successfully send out data using Udp4Write.
635 @retval Others Failed to send out data.
640 IN EFI_UDP4_PROTOCOL
*Udp4
,
641 IN EFI_UDP4_SESSION_DATA
*Session
,
642 IN EFI_EVENT TimeoutEvent
,
643 IN EFI_IPv4_ADDRESS
*Gateway OPTIONAL
,
644 IN UINTN
*HeaderSize OPTIONAL
,
645 IN VOID
*HeaderPtr OPTIONAL
,
646 IN UINTN
*BufferSize
,
650 EFI_UDP4_COMPLETION_TOKEN Token
;
651 EFI_UDP4_TRANSMIT_DATA
*TxData
;
659 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
661 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
662 TxLength
= sizeof (EFI_UDP4_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP4_FRAGMENT_DATA
);
663 TxData
= (EFI_UDP4_TRANSMIT_DATA
*)AllocateZeroPool (TxLength
);
664 if (TxData
== NULL
) {
665 return EFI_OUT_OF_RESOURCES
;
668 TxData
->FragmentCount
= FragCount
;
669 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
)*BufferSize
;
670 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
671 DataLength
= (UINT32
)*BufferSize
;
673 if (HeaderSize
!= NULL
) {
674 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
)*HeaderSize
;
675 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
676 DataLength
+= (UINT32
)*HeaderSize
;
679 if (Gateway
!= NULL
) {
680 TxData
->GatewayAddress
= Gateway
;
683 TxData
->UdpSessionData
= Session
;
684 TxData
->DataLength
= DataLength
;
685 Token
.Packet
.TxData
= TxData
;
686 Token
.Status
= EFI_NOT_READY
;
689 Status
= gBS
->CreateEvent (
696 if (EFI_ERROR (Status
)) {
700 Status
= Udp4
->Transmit (Udp4
, &Token
);
701 if (EFI_ERROR (Status
)) {
706 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
709 Token
.Status
== EFI_NOT_READY
&&
710 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
)))
715 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
718 if (Token
.Event
!= NULL
) {
719 gBS
->CloseEvent (Token
.Event
);
728 This function is to configure a UDPv4 instance for UdpWrite.
730 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
731 @param[in] Session The pointer to the UDP6 session data.
732 @param[in] TimeoutEvent The event for timeout.
733 @param[in] HeaderSize An optional field which may be set to the length of a header
734 at HeaderPtr to be prefixed to the data at BufferPtr.
735 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
736 prefixed to the data at BufferPtr.
737 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
738 @param[in] BufferPtr A pointer to the data to be written.
740 @retval EFI_SUCCESS Successfully sent out data using Udp6Write.
741 @retval Others Failed to send out data.
746 IN EFI_UDP6_PROTOCOL
*Udp6
,
747 IN EFI_UDP6_SESSION_DATA
*Session
,
748 IN EFI_EVENT TimeoutEvent
,
749 IN UINTN
*HeaderSize OPTIONAL
,
750 IN VOID
*HeaderPtr OPTIONAL
,
751 IN UINTN
*BufferSize
,
755 EFI_UDP6_COMPLETION_TOKEN Token
;
756 EFI_UDP6_TRANSMIT_DATA
*TxData
;
764 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
766 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
767 TxLength
= sizeof (EFI_UDP6_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP6_FRAGMENT_DATA
);
768 TxData
= (EFI_UDP6_TRANSMIT_DATA
*)AllocateZeroPool (TxLength
);
769 if (TxData
== NULL
) {
770 return EFI_OUT_OF_RESOURCES
;
773 TxData
->FragmentCount
= FragCount
;
774 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
)*BufferSize
;
775 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
776 DataLength
= (UINT32
)*BufferSize
;
778 if (HeaderSize
!= NULL
) {
779 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
)*HeaderSize
;
780 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
781 DataLength
+= (UINT32
)*HeaderSize
;
784 TxData
->UdpSessionData
= Session
;
785 TxData
->DataLength
= DataLength
;
786 Token
.Packet
.TxData
= TxData
;
787 Token
.Status
= EFI_NOT_READY
;
790 Status
= gBS
->CreateEvent (
797 if (EFI_ERROR (Status
)) {
801 Status
= Udp6
->Transmit (Udp6
, &Token
);
802 if (EFI_ERROR (Status
)) {
807 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
810 Token
.Status
== EFI_NOT_READY
&&
811 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
)))
816 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
819 if (Token
.Event
!= NULL
) {
820 gBS
->CloseEvent (Token
.Event
);
829 Check the received packet using the Ip filter.
831 @param[in] Mode The pointer to the mode data of PxeBc.
832 @param[in] Session The pointer to the current UDPv4 session.
833 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
835 @retval TRUE Passed the Ip filter successfully.
836 @retval FALSE Failed to pass the Ip filter.
840 PxeBcCheckByIpFilter (
841 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
846 EFI_IP_ADDRESS DestinationIp
;
849 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
) == 0) {
853 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS
) != 0) {
858 // Convert the destination address in session data to host order.
860 if (Mode
->UsingIpv6
) {
863 &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
,
864 sizeof (EFI_IPv6_ADDRESS
)
866 NTOHLLL (&DestinationIp
.v6
);
868 ZeroMem (&DestinationIp
, sizeof (EFI_IP_ADDRESS
));
871 &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
,
872 sizeof (EFI_IPv4_ADDRESS
)
874 EFI_NTOHL (DestinationIp
);
877 if (((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST
) != 0) &&
878 (IP4_IS_MULTICAST (DestinationIp
.Addr
[0]) ||
879 IP6_IS_MULTICAST (&DestinationIp
)))
884 if (((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
) != 0) &&
885 IP4_IS_LOCAL_BROADCAST (DestinationIp
.Addr
[0]))
887 ASSERT (!Mode
->UsingIpv6
);
891 if (((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
) != 0) &&
892 (EFI_IP4_EQUAL (&Mode
->StationIp
.v4
, &DestinationIp
) ||
893 EFI_IP6_EQUAL (&Mode
->StationIp
.v6
, &DestinationIp
)))
896 // Matched if the dest address is equal to the station address.
901 for (Index
= 0; Index
< Mode
->IpFilter
.IpCnt
; Index
++) {
902 ASSERT (Index
< EFI_PXE_BASE_CODE_MAX_IPCNT
);
903 if (EFI_IP4_EQUAL (&Mode
->IpFilter
.IpList
[Index
].v4
, &DestinationIp
) ||
904 EFI_IP6_EQUAL (&Mode
->IpFilter
.IpList
[Index
].v6
, &DestinationIp
))
907 // Matched if the dest address is equal to any of address in the filter list.
917 Filter the received packet using the destination Ip.
919 @param[in] Mode The pointer to the mode data of PxeBc.
920 @param[in] Session The pointer to the current UDPv4 session.
921 @param[in, out] DestIp The pointer to the destination Ip address.
922 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
924 @retval TRUE Passed the IPv4 filter successfully.
925 @retval FALSE Failed to pass the IPv4 filter.
930 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
932 IN OUT EFI_IP_ADDRESS
*DestIp
,
936 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
) != 0) {
938 // Copy the destination address from the received packet if accept any.
940 if (DestIp
!= NULL
) {
941 if (Mode
->UsingIpv6
) {
944 &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
,
945 sizeof (EFI_IPv6_ADDRESS
)
948 ZeroMem (DestIp
, sizeof (EFI_IP_ADDRESS
));
951 &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
,
952 sizeof (EFI_IPv4_ADDRESS
)
958 } else if ((DestIp
!= NULL
) &&
959 (EFI_IP4_EQUAL (DestIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
960 EFI_IP6_EQUAL (DestIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
)))
963 // The destination address in the received packet is matched if present.
966 } else if (EFI_IP4_EQUAL (&Mode
->StationIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
967 EFI_IP6_EQUAL (&Mode
->StationIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
))
970 // The destination address in the received packet is equal to the host address.
979 Check the received packet using the destination port.
981 @param[in] Mode The pointer to the mode data of PxeBc.
982 @param[in] Session The pointer to the current UDPv4 session.
983 @param[in, out] DestPort The pointer to the destination port.
984 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
986 @retval TRUE Passed the IPv4 filter successfully.
987 @retval FALSE Failed to pass the IPv4 filter.
991 PxeBcCheckByDestPort (
992 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
994 IN OUT UINT16
*DestPort
,
1000 if (Mode
->UsingIpv6
) {
1001 Port
= ((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationPort
;
1003 Port
= ((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationPort
;
1006 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT
) != 0) {
1008 // Return the destination port in the received packet if accept any.
1010 if (DestPort
!= NULL
) {
1015 } else if ((DestPort
!= NULL
) && (*DestPort
== Port
)) {
1017 // The destination port in the received packet is matched if present.
1026 Filter the received packet using the source Ip.
1028 @param[in] Mode The pointer to the mode data of PxeBc.
1029 @param[in] Session The pointer to the current UDPv4 session.
1030 @param[in, out] SrcIp The pointer to the source Ip address.
1031 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1033 @retval TRUE Passed the IPv4 filter successfully.
1034 @retval FALSE Failed to pass the IPv4 filter.
1038 PxeBcFilterBySrcIp (
1039 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1041 IN OUT EFI_IP_ADDRESS
*SrcIp
,
1045 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
) != 0) {
1047 // Copy the source address from the received packet if accept any.
1049 if (SrcIp
!= NULL
) {
1050 if (Mode
->UsingIpv6
) {
1053 &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
,
1054 sizeof (EFI_IPv6_ADDRESS
)
1057 ZeroMem (SrcIp
, sizeof (EFI_IP_ADDRESS
));
1060 &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
,
1061 sizeof (EFI_IPv4_ADDRESS
)
1067 } else if ((SrcIp
!= NULL
) &&
1068 (EFI_IP4_EQUAL (SrcIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
) ||
1069 EFI_IP6_EQUAL (SrcIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
)))
1072 // The source address in the received packet is matched if present.
1081 Filter the received packet using the source port.
1083 @param[in] Mode The pointer to the mode data of PxeBc.
1084 @param[in] Session The pointer to the current UDPv4 session.
1085 @param[in, out] SrcPort The pointer to the source port.
1086 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1088 @retval TRUE Passed the IPv4 filter successfully.
1089 @retval FALSE Failed to pass the IPv4 filter.
1093 PxeBcFilterBySrcPort (
1094 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1096 IN OUT UINT16
*SrcPort
,
1102 if (Mode
->UsingIpv6
) {
1103 Port
= ((EFI_UDP6_SESSION_DATA
*)Session
)->SourcePort
;
1105 Port
= ((EFI_UDP4_SESSION_DATA
*)Session
)->SourcePort
;
1108 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
) != 0) {
1110 // Return the source port in the received packet if accept any.
1112 if (SrcPort
!= NULL
) {
1117 } else if ((SrcPort
!= NULL
) && (*SrcPort
== Port
)) {
1119 // The source port in the received packet is matched if present.
1128 This function is to receive packet using Udp4Read.
1130 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
1131 @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN.
1132 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1133 @param[in] TimeoutEvent The event for timeout.
1134 @param[in] OpFlags The UDP operation flags.
1135 @param[in] IsDone The pointer to the IsDone flag.
1136 @param[out] IsMatched The pointer to the IsMatched flag.
1137 @param[in, out] DestIp The pointer to the destination address.
1138 @param[in, out] DestPort The pointer to the destination port.
1139 @param[in, out] SrcIp The pointer to the source address.
1140 @param[in, out] SrcPort The pointer to the source port.
1142 @retval EFI_SUCCESS Successfully read the data using Udp4.
1143 @retval Others Failed to send out data.
1148 IN EFI_UDP4_PROTOCOL
*Udp4
,
1149 IN EFI_UDP4_COMPLETION_TOKEN
*Token
,
1150 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1151 IN EFI_EVENT TimeoutEvent
,
1154 OUT BOOLEAN
*IsMatched
,
1155 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1156 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1157 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1158 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1161 EFI_UDP4_RECEIVE_DATA
*RxData
;
1162 EFI_UDP4_SESSION_DATA
*Session
;
1165 Token
->Status
= EFI_NOT_READY
;
1168 Status
= Udp4
->Receive (Udp4
, Token
);
1169 if (EFI_ERROR (Status
)) {
1174 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1176 while (!(*IsDone
) &&
1177 Token
->Status
== EFI_NOT_READY
&&
1178 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
)))
1181 // Poll the token until reply/ICMPv6 error message received or timeout.
1184 if ((Token
->Status
== EFI_ICMP_ERROR
) ||
1185 (Token
->Status
== EFI_NETWORK_UNREACHABLE
) ||
1186 (Token
->Status
== EFI_HOST_UNREACHABLE
) ||
1187 (Token
->Status
== EFI_PROTOCOL_UNREACHABLE
) ||
1188 (Token
->Status
== EFI_PORT_UNREACHABLE
))
1194 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1196 if (!EFI_ERROR (Status
)) {
1198 // check whether this packet matches the filters
1200 RxData
= Token
->Packet
.RxData
;
1201 Session
= &RxData
->UdpSession
;
1203 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1206 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1210 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1214 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1218 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1221 if (!(*IsMatched
)) {
1223 // Recycle the receiving buffer if not matched.
1225 gBS
->SignalEvent (RxData
->RecycleSignal
);
1233 This function is to receive packets using Udp6Read.
1235 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
1236 @param[in] Token The pointer to EFI_UDP6_COMPLETION_TOKEN.
1237 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1238 @param[in] TimeoutEvent The event for timeout.
1239 @param[in] OpFlags The UDP operation flags.
1240 @param[in] IsDone The pointer to the IsDone flag.
1241 @param[out] IsMatched The pointer to the IsMatched flag.
1242 @param[in, out] DestIp The pointer to the destination address.
1243 @param[in, out] DestPort The pointer to the destination port.
1244 @param[in, out] SrcIp The pointer to the source address.
1245 @param[in, out] SrcPort The pointer to the source port.
1247 @retval EFI_SUCCESS Successfully read data using Udp6.
1248 @retval Others Failed to send out data.
1253 IN EFI_UDP6_PROTOCOL
*Udp6
,
1254 IN EFI_UDP6_COMPLETION_TOKEN
*Token
,
1255 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1256 IN EFI_EVENT TimeoutEvent
,
1259 OUT BOOLEAN
*IsMatched
,
1260 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1261 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1262 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1263 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1266 EFI_UDP6_RECEIVE_DATA
*RxData
;
1267 EFI_UDP6_SESSION_DATA
*Session
;
1270 Token
->Status
= EFI_NOT_READY
;
1273 Status
= Udp6
->Receive (Udp6
, Token
);
1274 if (EFI_ERROR (Status
)) {
1279 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1281 while (!(*IsDone
) &&
1282 Token
->Status
== EFI_NOT_READY
&&
1283 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
)))
1286 // Poll the token until reply/ICMPv6 error message received or timeout.
1289 if ((Token
->Status
== EFI_ICMP_ERROR
) ||
1290 (Token
->Status
== EFI_NETWORK_UNREACHABLE
) ||
1291 (Token
->Status
== EFI_HOST_UNREACHABLE
) ||
1292 (Token
->Status
== EFI_PROTOCOL_UNREACHABLE
) ||
1293 (Token
->Status
== EFI_PORT_UNREACHABLE
))
1299 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1301 if (!EFI_ERROR (Status
)) {
1303 // check whether this packet matches the filters
1305 RxData
= Token
->Packet
.RxData
;
1306 Session
= &RxData
->UdpSession
;
1308 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1311 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1315 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1319 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1323 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1326 if (!(*IsMatched
)) {
1328 // Recycle the receiving buffer if not matched.
1330 gBS
->SignalEvent (RxData
->RecycleSignal
);
1338 This function is to display the IPv4 address.
1340 @param[in] Ip The pointer to the IPv4 address.
1345 IN EFI_IPv4_ADDRESS
*Ip
1350 for (Index
= 0; Index
< 4; Index
++) {
1351 AsciiPrint ("%d", Ip
->Addr
[Index
]);
1359 This function is to display the IPv6 address.
1361 @param[in] Ip The pointer to the IPv6 address.
1366 IN EFI_IPv6_ADDRESS
*Ip
1371 for (Index
= 0; Index
< 16; Index
++) {
1372 if (Ip
->Addr
[Index
] != 0) {
1373 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1381 if (((Ip
->Addr
[Index
] & 0xf0) == 0) && (Ip
->Addr
[Index
- 1] != 0)) {
1385 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1393 This function is to convert UINTN to ASCII string with the required formatting.
1395 @param[in] Number Numeric value to be converted.
1396 @param[in] Buffer The pointer to the buffer for ASCII string.
1397 @param[in] Length The length of the required format.
1401 PxeBcUintnToAscDecWithFormat (
1409 for ( ; Length
> 0; Length
--) {
1410 Remainder
= Number
% 10;
1412 Buffer
[Length
- 1] = (UINT8
)('0' + Remainder
);
1417 This function is to convert a UINTN to a ASCII string, and return the
1418 actual length of the buffer.
1420 @param[in] Number Numeric value to be converted.
1421 @param[in] Buffer The pointer to the buffer for ASCII string.
1422 @param[in] BufferSize The maxsize of the buffer.
1424 @return Length The actual length of the ASCII string.
1428 PxeBcUintnToAscDec (
1443 TempStr
[Index
] = (CHAR8
)('0' + (Number
% 10));
1444 Number
= (UINTN
)(Number
/ 10);
1445 } while (Number
!= 0);
1447 AsciiStrCpyS ((CHAR8
*)Buffer
, BufferSize
, &TempStr
[Index
]);
1449 Length
= AsciiStrLen ((CHAR8
*)Buffer
);
1455 This function is to convert unicode hex number to a UINT8.
1457 @param[out] Digit The converted UINT8 for output.
1458 @param[in] Char The unicode hex number to be converted.
1460 @retval EFI_SUCCESS Successfully converted the unicode hex.
1461 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.
1465 PxeBcUniHexToUint8 (
1470 if ((Char
>= L
'0') && (Char
<= L
'9')) {
1471 *Digit
= (UINT8
)(Char
- L
'0');
1475 if ((Char
>= L
'A') && (Char
<= L
'F')) {
1476 *Digit
= (UINT8
)(Char
- L
'A' + 0x0A);
1480 if ((Char
>= L
'a') && (Char
<= L
'f')) {
1481 *Digit
= (UINT8
)(Char
- L
'a' + 0x0A);
1485 return EFI_INVALID_PARAMETER
;
1489 Calculate the elapsed time.
1491 @param[in] Private The pointer to PXE private data
1496 IN PXEBC_PRIVATE_DATA
*Private
1500 UINT64 CurrentStamp
;
1501 UINT64 ElapsedTimeValue
;
1504 // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.
1506 ZeroMem (&Time
, sizeof (EFI_TIME
));
1507 gRT
->GetTime (&Time
, NULL
);
1508 CurrentStamp
= MultU64x32 (
1509 ((((UINT32
)(Time
.Year
- 1900) * 360 + (Time
.Month
- 1) * 30 + (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 + Time
.Minute
) * 60 + Time
.Second
,
1518 // Sentinel value of 0 means that this is the first DHCP packet that we are
1519 // sending and that we need to initialize the value. First DHCP Solicit
1520 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
1522 if (Private
->ElapsedTime
== 0) {
1523 Private
->ElapsedTime
= CurrentStamp
;
1525 ElapsedTimeValue
= CurrentStamp
- Private
->ElapsedTime
;
1528 // If elapsed time cannot fit in two bytes, set it to 0xffff.
1530 if (ElapsedTimeValue
> 0xffff) {
1531 ElapsedTimeValue
= 0xffff;
1535 // Save the elapsed time
1537 Private
->ElapsedTime
= ElapsedTimeValue
;