2 Support functions implementation for UefiPxeBc Driver.
4 Copyright (c) 2007 - 2018, 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
, OPTIONAL
34 EFI_IP_ADDRESS
*SubnetMask OPTIONAL
37 EFI_PXE_BASE_CODE_MODE
*Mode
;
39 EFI_ARP_CONFIG_DATA ArpConfigData
;
41 Mode
= Private
->PxeBc
.Mode
;
43 ZeroMem (&ArpConfigData
, sizeof (EFI_ARP_CONFIG_DATA
));
45 if (Mode
->UsingIpv6
&& StationIp
!= NULL
) {
47 // Overwrite Udp6CfgData/Ip6CfgData StationAddress.
49 CopyMem (&Private
->Udp6CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
50 CopyMem (&Private
->Ip6CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
53 // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address.
55 Private
->Ip6
->Cancel (Private
->Ip6
, &Private
->Icmp6Token
);
56 Private
->Ip6
->Configure (Private
->Ip6
, NULL
);
58 Status
= Private
->Ip6
->Configure (Private
->Ip6
, &Private
->Ip6CfgData
);
59 if (EFI_ERROR (Status
)) {
63 Status
= Private
->Ip6
->Receive (Private
->Ip6
, &Private
->Icmp6Token
);
65 if (StationIp
!= NULL
) {
67 // Reconfigure the ARP instance with station Ip address.
69 ArpConfigData
.SwAddressType
= 0x0800;
70 ArpConfigData
.SwAddressLength
= (UINT8
) sizeof (EFI_IPv4_ADDRESS
);
71 ArpConfigData
.StationAddress
= StationIp
;
73 Private
->Arp
->Configure (Private
->Arp
, NULL
);
74 Private
->Arp
->Configure (Private
->Arp
, &ArpConfigData
);
77 // Overwrite Udp4CfgData/Ip4CfgData StationAddress.
79 CopyMem (&Private
->Udp4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
80 CopyMem (&Private
->Ip4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
83 if (SubnetMask
!= NULL
) {
85 // Overwrite Udp4CfgData/Ip4CfgData SubnetMask.
87 CopyMem (&Private
->Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
88 CopyMem (&Private
->Ip4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
91 if (StationIp
!= NULL
&& SubnetMask
!= NULL
) {
93 // Updated the route table.
95 Mode
->RouteTableEntries
= 1;
96 Mode
->RouteTable
[0].IpAddr
.Addr
[0] = StationIp
->Addr
[0] & SubnetMask
->Addr
[0];
97 Mode
->RouteTable
[0].SubnetMask
.Addr
[0] = SubnetMask
->Addr
[0];
98 Mode
->RouteTable
[0].GwAddr
.Addr
[0] = 0;
101 if (StationIp
!= NULL
|| SubnetMask
!= NULL
) {
103 // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
105 Private
->Ip4
->Cancel (Private
->Ip4
, &Private
->IcmpToken
);
106 Private
->Ip4
->Configure (Private
->Ip4
, NULL
);
108 Status
= Private
->Ip4
->Configure (Private
->Ip4
, &Private
->Ip4CfgData
);
109 if (EFI_ERROR (Status
)) {
113 Status
= Private
->Ip4
->Receive (Private
->Ip4
, &Private
->IcmpToken
);
123 Notify the callback function when an event is triggered.
125 @param[in] Event The triggered event.
126 @param[in] Context The opaque parameter to the function.
136 *((BOOLEAN
*) Context
) = TRUE
;
141 Do arp resolution from arp cache in PxeBcMode.
143 @param Mode The pointer to EFI_PXE_BASE_CODE_MODE.
144 @param Ip4Addr The Ip4 address for resolution.
145 @param MacAddress The resoluted MAC address if the resolution is successful.
146 The value is undefined if the resolution fails.
148 @retval TRUE Found an matched entry.
149 @retval FALSE Did not find a matched entry.
154 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
155 IN EFI_IPv4_ADDRESS
*Ip4Addr
,
156 OUT EFI_MAC_ADDRESS
*MacAddress
161 ASSERT (!Mode
->UsingIpv6
);
164 // Check whether the current Arp cache in mode data contains this information or not.
166 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
167 if (EFI_IP4_EQUAL (&Mode
->ArpCache
[Index
].IpAddr
.v4
, Ip4Addr
)) {
170 &Mode
->ArpCache
[Index
].MacAddr
,
171 sizeof (EFI_MAC_ADDRESS
)
182 Update the arp cache periodically.
184 @param Event The pointer to EFI_PXE_BC_PROTOCOL.
185 @param Context Context of the timer event.
190 PxeBcArpCacheUpdate (
195 PXEBC_PRIVATE_DATA
*Private
;
196 EFI_PXE_BASE_CODE_MODE
*Mode
;
197 EFI_ARP_FIND_DATA
*ArpEntry
;
203 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
204 Mode
= Private
->PxeBc
.Mode
;
206 ASSERT (!Mode
->UsingIpv6
);
209 // Get the current Arp cache from Arp driver.
211 Status
= Private
->Arp
->Find (
220 if (EFI_ERROR (Status
)) {
225 // Update the Arp cache in mode data.
227 Mode
->ArpCacheEntries
= MIN (EntryCount
, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES
);
229 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
231 &Mode
->ArpCache
[Index
].IpAddr
,
233 ArpEntry
->SwAddressLength
236 &Mode
->ArpCache
[Index
].MacAddr
,
237 (UINT8
*) (ArpEntry
+ 1) + ArpEntry
->SwAddressLength
,
238 ArpEntry
->HwAddressLength
240 ArpEntry
= (EFI_ARP_FIND_DATA
*) ((UINT8
*) ArpEntry
+ EntryLength
);
246 Notify function to handle the received ICMP message in DPC.
248 @param Context The PXEBC private data.
253 PxeBcIcmpErrorDpcHandle (
258 EFI_IP4_RECEIVE_DATA
*RxData
;
259 EFI_IP4_PROTOCOL
*Ip4
;
260 PXEBC_PRIVATE_DATA
*Private
;
261 EFI_PXE_BASE_CODE_MODE
*Mode
;
267 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
268 Mode
= &Private
->Mode
;
269 Status
= Private
->IcmpToken
.Status
;
270 RxData
= Private
->IcmpToken
.Packet
.RxData
;
273 ASSERT (!Mode
->UsingIpv6
);
275 if (Status
== EFI_ABORTED
) {
277 // It's triggered by user cancellation.
282 if (RxData
== NULL
) {
286 if (Status
!= EFI_ICMP_ERROR
) {
288 // The return status should be recognized as EFI_ICMP_ERROR.
293 if (EFI_IP4 (RxData
->Header
->SourceAddress
) != 0 &&
294 (NTOHL (Mode
->SubnetMask
.Addr
[0]) != 0) &&
295 IP4_NET_EQUAL (NTOHL(Mode
->StationIp
.Addr
[0]), EFI_NTOHL (RxData
->Header
->SourceAddress
), NTOHL (Mode
->SubnetMask
.Addr
[0])) &&
296 !NetIp4IsUnicast (EFI_NTOHL (RxData
->Header
->SourceAddress
), NTOHL (Mode
->SubnetMask
.Addr
[0]))) {
298 // The source address of the received packet should be a valid unicast address.
303 if (!EFI_IP4_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v4
)) {
305 // The destination address of the received packet should be equal to the host address.
311 // The protocol has been configured to only receive ICMP packet.
313 ASSERT (RxData
->Header
->Protocol
== EFI_IP_PROTO_ICMP
);
315 Type
= *((UINT8
*) RxData
->FragmentTable
[0].FragmentBuffer
);
317 if (Type
!= ICMP_DEST_UNREACHABLE
&&
318 Type
!= ICMP_SOURCE_QUENCH
&&
319 Type
!= ICMP_REDIRECT
&&
320 Type
!= ICMP_TIME_EXCEEDED
&&
321 Type
!= ICMP_PARAMETER_PROBLEM
) {
323 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
329 // Copy the right ICMP error message into mode data.
332 IcmpError
= (UINT8
*) &Mode
->IcmpError
;
334 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
335 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
336 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
339 RxData
->FragmentTable
[Index
].FragmentBuffer
,
340 RxData
->FragmentTable
[Index
].FragmentLength
345 RxData
->FragmentTable
[Index
].FragmentBuffer
,
346 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
349 IcmpError
+= CopiedLen
;
353 gBS
->SignalEvent (RxData
->RecycleSignal
);
356 Private
->IcmpToken
.Status
= EFI_NOT_READY
;
357 Ip4
->Receive (Ip4
, &Private
->IcmpToken
);
362 Callback function to update the latest ICMP6 error message.
364 @param Event The event signalled.
365 @param Context The context passed in using the event notifier.
370 PxeBcIcmpErrorUpdate (
375 QueueDpc (TPL_CALLBACK
, PxeBcIcmpErrorDpcHandle
, Context
);
380 Notify function to handle the received ICMP6 message in DPC.
382 @param Context The PXEBC private data.
387 PxeBcIcmp6ErrorDpcHandle (
391 PXEBC_PRIVATE_DATA
*Private
;
392 EFI_IP6_RECEIVE_DATA
*RxData
;
393 EFI_IP6_PROTOCOL
*Ip6
;
394 EFI_PXE_BASE_CODE_MODE
*Mode
;
401 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
402 Mode
= &Private
->Mode
;
403 Status
= Private
->Icmp6Token
.Status
;
404 RxData
= Private
->Icmp6Token
.Packet
.RxData
;
407 ASSERT (Mode
->UsingIpv6
);
409 if (Status
== EFI_ABORTED
) {
411 // It's triggered by user cancellation.
416 if (RxData
== NULL
) {
420 if (Status
!= EFI_ICMP_ERROR
) {
422 // The return status should be recognized as EFI_ICMP_ERROR.
427 if (!NetIp6IsValidUnicast (&RxData
->Header
->SourceAddress
)) {
429 // The source address of the received packet should be a valid unicast address.
434 if (!NetIp6IsUnspecifiedAddr (&Mode
->StationIp
.v6
) &&
435 !EFI_IP6_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v6
)) {
437 // The destination address of the received packet should be equal to the host address.
443 // The protocol has been configured to only receive ICMP packet.
445 ASSERT (RxData
->Header
->NextHeader
== IP6_ICMP
);
447 Type
= *((UINT8
*) RxData
->FragmentTable
[0].FragmentBuffer
);
449 if (Type
!= ICMP_V6_DEST_UNREACHABLE
&&
450 Type
!= ICMP_V6_PACKET_TOO_BIG
&&
451 Type
!= ICMP_V6_TIME_EXCEEDED
&&
452 Type
!= ICMP_V6_PARAMETER_PROBLEM
) {
454 // The type of the receveid packet should be an ICMP6 error message.
460 // Copy the right ICMP6 error message into mode data.
463 Icmp6Error
= (UINT8
*) &Mode
->IcmpError
;
465 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
466 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
467 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
470 RxData
->FragmentTable
[Index
].FragmentBuffer
,
471 RxData
->FragmentTable
[Index
].FragmentLength
476 RxData
->FragmentTable
[Index
].FragmentBuffer
,
477 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
480 Icmp6Error
+= CopiedLen
;
484 gBS
->SignalEvent (RxData
->RecycleSignal
);
487 Private
->Icmp6Token
.Status
= EFI_NOT_READY
;
488 Ip6
->Receive (Ip6
, &Private
->Icmp6Token
);
493 Callback function to update the latest ICMP6 error message.
495 @param Event The event signalled.
496 @param Context The context passed in using the event notifier.
501 PxeBcIcmp6ErrorUpdate (
506 QueueDpc (TPL_CALLBACK
, PxeBcIcmp6ErrorDpcHandle
, Context
);
511 This function is to configure a UDPv4 instance for UdpWrite.
513 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
514 @param[in] StationIp The pointer to the station address.
515 @param[in] SubnetMask The pointer to the subnet mask.
516 @param[in] Gateway The pointer to the gateway address.
517 @param[in, out] SrcPort The pointer to the source port.
518 @param[in] DoNotFragment If TRUE, fragment is not enabled.
519 Otherwise, fragment is enabled.
520 @param[in] Ttl The time to live field of the IP header.
521 @param[in] ToS The type of service field of the IP header.
523 @retval EFI_SUCCESS Successfully configured this instance.
524 @retval Others Failed to configure this instance.
528 PxeBcConfigUdp4Write (
529 IN EFI_UDP4_PROTOCOL
*Udp4
,
530 IN EFI_IPv4_ADDRESS
*StationIp
,
531 IN EFI_IPv4_ADDRESS
*SubnetMask
,
532 IN EFI_IPv4_ADDRESS
*Gateway
,
533 IN OUT UINT16
*SrcPort
,
534 IN BOOLEAN DoNotFragment
,
539 EFI_UDP4_CONFIG_DATA Udp4CfgData
;
542 ZeroMem (&Udp4CfgData
, sizeof (Udp4CfgData
));
544 Udp4CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
545 Udp4CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
546 Udp4CfgData
.TypeOfService
= ToS
;
547 Udp4CfgData
.TimeToLive
= Ttl
;
548 Udp4CfgData
.AllowDuplicatePort
= TRUE
;
549 Udp4CfgData
.DoNotFragment
= DoNotFragment
;
551 CopyMem (&Udp4CfgData
.StationAddress
, StationIp
, sizeof (*StationIp
));
552 CopyMem (&Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (*SubnetMask
));
554 Udp4CfgData
.StationPort
= *SrcPort
;
557 // Reset the UDPv4 instance.
559 Udp4
->Configure (Udp4
, NULL
);
561 Status
= Udp4
->Configure (Udp4
, &Udp4CfgData
);
562 if (!EFI_ERROR (Status
) && !EFI_IP4_EQUAL (Gateway
, &mZeroIp4Addr
)) {
564 // The basic configuration is OK, need to add the default route entry
566 Status
= Udp4
->Routes (Udp4
, FALSE
, &mZeroIp4Addr
, &mZeroIp4Addr
, Gateway
);
567 if (EFI_ERROR (Status
)) {
568 Udp4
->Configure (Udp4
, NULL
);
572 if (!EFI_ERROR (Status
) && *SrcPort
== 0) {
573 Udp4
->GetModeData (Udp4
, &Udp4CfgData
, NULL
, NULL
, NULL
);
574 *SrcPort
= Udp4CfgData
.StationPort
;
582 This function is to configure a UDPv6 instance for UdpWrite.
584 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
585 @param[in] StationIp The pointer to the station address.
586 @param[in, out] SrcPort The pointer to the source port.
588 @retval EFI_SUCCESS Successfully configured this instance.
589 @retval Others Failed to configure this instance.
593 PxeBcConfigUdp6Write (
594 IN EFI_UDP6_PROTOCOL
*Udp6
,
595 IN EFI_IPv6_ADDRESS
*StationIp
,
596 IN OUT UINT16
*SrcPort
599 EFI_UDP6_CONFIG_DATA CfgData
;
602 ZeroMem (&CfgData
, sizeof (EFI_UDP6_CONFIG_DATA
));
604 CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
605 CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
606 CfgData
.HopLimit
= PXEBC_DEFAULT_HOPLIMIT
;
607 CfgData
.AllowDuplicatePort
= TRUE
;
608 CfgData
.StationPort
= *SrcPort
;
610 CopyMem (&CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
613 // Reset the UDPv6 instance.
615 Udp6
->Configure (Udp6
, NULL
);
617 Status
= Udp6
->Configure (Udp6
, &CfgData
);
618 if (EFI_ERROR (Status
)) {
622 if (!EFI_ERROR (Status
) && *SrcPort
== 0) {
623 Udp6
->GetModeData (Udp6
, &CfgData
, NULL
, NULL
, NULL
);
624 *SrcPort
= CfgData
.StationPort
;
632 This function is to configure a UDPv4 instance for UdpWrite.
634 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
635 @param[in] Session The pointer to the UDP4 session data.
636 @param[in] TimeoutEvent The event for timeout.
637 @param[in] Gateway The pointer to the gateway address.
638 @param[in] HeaderSize An optional field which may be set to the length of a header
639 at HeaderPtr to be prefixed to the data at BufferPtr.
640 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
641 prefixed to the data at BufferPtr.
642 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
643 @param[in] BufferPtr A pointer to the data to be written.
645 @retval EFI_SUCCESS Successfully send out data using Udp4Write.
646 @retval Others Failed to send out data.
651 IN EFI_UDP4_PROTOCOL
*Udp4
,
652 IN EFI_UDP4_SESSION_DATA
*Session
,
653 IN EFI_EVENT TimeoutEvent
,
654 IN EFI_IPv4_ADDRESS
*Gateway OPTIONAL
,
655 IN UINTN
*HeaderSize OPTIONAL
,
656 IN VOID
*HeaderPtr OPTIONAL
,
657 IN UINTN
*BufferSize
,
661 EFI_UDP4_COMPLETION_TOKEN Token
;
662 EFI_UDP4_TRANSMIT_DATA
*TxData
;
670 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
672 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
673 TxLength
= sizeof (EFI_UDP4_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP4_FRAGMENT_DATA
);
674 TxData
= (EFI_UDP4_TRANSMIT_DATA
*) AllocateZeroPool (TxLength
);
675 if (TxData
== NULL
) {
676 return EFI_OUT_OF_RESOURCES
;
679 TxData
->FragmentCount
= FragCount
;
680 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
) *BufferSize
;
681 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
682 DataLength
= (UINT32
) *BufferSize
;
684 if (HeaderSize
!= NULL
) {
685 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) *HeaderSize
;
686 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
687 DataLength
+= (UINT32
) *HeaderSize
;
690 if (Gateway
!= NULL
) {
691 TxData
->GatewayAddress
= Gateway
;
694 TxData
->UdpSessionData
= Session
;
695 TxData
->DataLength
= DataLength
;
696 Token
.Packet
.TxData
= TxData
;
697 Token
.Status
= EFI_NOT_READY
;
700 Status
= gBS
->CreateEvent (
707 if (EFI_ERROR (Status
)) {
711 Status
= Udp4
->Transmit (Udp4
, &Token
);
712 if (EFI_ERROR (Status
)) {
717 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
720 Token
.Status
== EFI_NOT_READY
&&
721 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
725 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
728 if (Token
.Event
!= NULL
) {
729 gBS
->CloseEvent (Token
.Event
);
738 This function is to configure a UDPv4 instance for UdpWrite.
740 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
741 @param[in] Session The pointer to the UDP6 session data.
742 @param[in] TimeoutEvent The event for timeout.
743 @param[in] HeaderSize An optional field which may be set to the length of a header
744 at HeaderPtr to be prefixed to the data at BufferPtr.
745 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
746 prefixed to the data at BufferPtr.
747 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
748 @param[in] BufferPtr A pointer to the data to be written.
750 @retval EFI_SUCCESS Successfully sent out data using Udp6Write.
751 @retval Others Failed to send out data.
756 IN EFI_UDP6_PROTOCOL
*Udp6
,
757 IN EFI_UDP6_SESSION_DATA
*Session
,
758 IN EFI_EVENT TimeoutEvent
,
759 IN UINTN
*HeaderSize OPTIONAL
,
760 IN VOID
*HeaderPtr OPTIONAL
,
761 IN UINTN
*BufferSize
,
765 EFI_UDP6_COMPLETION_TOKEN Token
;
766 EFI_UDP6_TRANSMIT_DATA
*TxData
;
774 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
776 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
777 TxLength
= sizeof (EFI_UDP6_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP6_FRAGMENT_DATA
);
778 TxData
= (EFI_UDP6_TRANSMIT_DATA
*) AllocateZeroPool (TxLength
);
779 if (TxData
== NULL
) {
780 return EFI_OUT_OF_RESOURCES
;
783 TxData
->FragmentCount
= FragCount
;
784 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
) *BufferSize
;
785 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
786 DataLength
= (UINT32
) *BufferSize
;
788 if (HeaderSize
!= NULL
) {
789 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) *HeaderSize
;
790 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
791 DataLength
+= (UINT32
) *HeaderSize
;
794 TxData
->UdpSessionData
= Session
;
795 TxData
->DataLength
= DataLength
;
796 Token
.Packet
.TxData
= TxData
;
797 Token
.Status
= EFI_NOT_READY
;
800 Status
= gBS
->CreateEvent (
807 if (EFI_ERROR (Status
)) {
811 Status
= Udp6
->Transmit (Udp6
, &Token
);
812 if (EFI_ERROR (Status
)) {
817 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
820 Token
.Status
== EFI_NOT_READY
&&
821 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
825 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
828 if (Token
.Event
!= NULL
) {
829 gBS
->CloseEvent (Token
.Event
);
838 Check the received packet using the Ip filter.
840 @param[in] Mode The pointer to the mode data of PxeBc.
841 @param[in] Session The pointer to the current UDPv4 session.
842 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
844 @retval TRUE Passed the Ip filter successfully.
845 @retval FALSE Failed to pass the Ip filter.
849 PxeBcCheckByIpFilter (
850 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
855 EFI_IP_ADDRESS DestinationIp
;
858 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
) == 0) {
862 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS
) != 0) {
867 // Convert the destination address in session data to host order.
869 if (Mode
->UsingIpv6
) {
872 &((EFI_UDP6_SESSION_DATA
*) Session
)->DestinationAddress
,
873 sizeof (EFI_IPv6_ADDRESS
)
875 NTOHLLL (&DestinationIp
.v6
);
877 ZeroMem (&DestinationIp
, sizeof (EFI_IP_ADDRESS
));
880 &((EFI_UDP4_SESSION_DATA
*) Session
)->DestinationAddress
,
881 sizeof (EFI_IPv4_ADDRESS
)
883 EFI_NTOHL (DestinationIp
);
886 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST
) != 0 &&
887 (IP4_IS_MULTICAST (DestinationIp
.Addr
[0]) ||
888 IP6_IS_MULTICAST (&DestinationIp
))) {
892 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
) != 0 &&
893 IP4_IS_LOCAL_BROADCAST (DestinationIp
.Addr
[0])) {
894 ASSERT (!Mode
->UsingIpv6
);
898 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
) != 0 &&
899 (EFI_IP4_EQUAL (&Mode
->StationIp
.v4
, &DestinationIp
) ||
900 EFI_IP6_EQUAL (&Mode
->StationIp
.v6
, &DestinationIp
))) {
902 // Matched if the dest address is equal to the station address.
907 for (Index
= 0; Index
< Mode
->IpFilter
.IpCnt
; Index
++) {
908 ASSERT (Index
< EFI_PXE_BASE_CODE_MAX_IPCNT
);
909 if (EFI_IP4_EQUAL (&Mode
->IpFilter
.IpList
[Index
].v4
, &DestinationIp
) ||
910 EFI_IP6_EQUAL (&Mode
->IpFilter
.IpList
[Index
].v6
, &DestinationIp
)) {
912 // Matched if the dest address is equal to any of address in the filter list.
923 Filter the received packet using the destination Ip.
925 @param[in] Mode The pointer to the mode data of PxeBc.
926 @param[in] Session The pointer to the current UDPv4 session.
927 @param[in, out] DestIp The pointer to the destination Ip address.
928 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
930 @retval TRUE Passed the IPv4 filter successfully.
931 @retval FALSE Failed to pass the IPv4 filter.
936 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
938 IN OUT EFI_IP_ADDRESS
*DestIp
,
942 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP
) != 0) {
944 // Copy the destination address from the received packet if accept any.
946 if (DestIp
!= NULL
) {
947 if (Mode
->UsingIpv6
) {
950 &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
,
951 sizeof (EFI_IPv6_ADDRESS
)
954 ZeroMem (DestIp
, sizeof (EFI_IP_ADDRESS
));
957 &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
,
958 sizeof (EFI_IPv4_ADDRESS
)
964 } else if (DestIp
!= NULL
&&
965 (EFI_IP4_EQUAL (DestIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
966 EFI_IP6_EQUAL (DestIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
))) {
968 // The destination address in the received packet is matched if present.
971 } else if (EFI_IP4_EQUAL (&Mode
->StationIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
972 EFI_IP6_EQUAL (&Mode
->StationIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
)) {
974 // The destination address in the received packet is equal to the host address.
984 Check the received packet using the destination port.
986 @param[in] Mode The pointer to the mode data of PxeBc.
987 @param[in] Session The pointer to the current UDPv4 session.
988 @param[in, out] DestPort The pointer to the destination port.
989 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
991 @retval TRUE Passed the IPv4 filter successfully.
992 @retval FALSE Failed to pass the IPv4 filter.
996 PxeBcCheckByDestPort (
997 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
999 IN OUT UINT16
*DestPort
,
1005 if (Mode
->UsingIpv6
) {
1006 Port
= ((EFI_UDP6_SESSION_DATA
*) Session
)->DestinationPort
;
1008 Port
= ((EFI_UDP4_SESSION_DATA
*) Session
)->DestinationPort
;
1011 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT
) != 0) {
1013 // Return the destination port in the received packet if accept any.
1015 if (DestPort
!= NULL
) {
1019 } else if (DestPort
!= NULL
&& *DestPort
== Port
) {
1021 // The destination port in the received packet is matched if present.
1031 Filter the received packet using the source Ip.
1033 @param[in] Mode The pointer to the mode data of PxeBc.
1034 @param[in] Session The pointer to the current UDPv4 session.
1035 @param[in, out] SrcIp The pointer to the source Ip address.
1036 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1038 @retval TRUE Passed the IPv4 filter successfully.
1039 @retval FALSE Failed to pass the IPv4 filter.
1043 PxeBcFilterBySrcIp (
1044 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1046 IN OUT EFI_IP_ADDRESS
*SrcIp
,
1050 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
) != 0) {
1052 // Copy the source address from the received packet if accept any.
1054 if (SrcIp
!= NULL
) {
1055 if (Mode
->UsingIpv6
) {
1058 &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
,
1059 sizeof (EFI_IPv6_ADDRESS
)
1062 ZeroMem (SrcIp
, sizeof (EFI_IP_ADDRESS
));
1065 &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
,
1066 sizeof (EFI_IPv4_ADDRESS
)
1072 } else if (SrcIp
!= NULL
&&
1073 (EFI_IP4_EQUAL (SrcIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
) ||
1074 EFI_IP6_EQUAL (SrcIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
))) {
1076 // The source address in the received packet is matched if present.
1086 Filter the received packet using the source port.
1088 @param[in] Mode The pointer to the mode data of PxeBc.
1089 @param[in] Session The pointer to the current UDPv4 session.
1090 @param[in, out] SrcPort The pointer to the source port.
1091 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1093 @retval TRUE Passed the IPv4 filter successfully.
1094 @retval FALSE Failed to pass the IPv4 filter.
1098 PxeBcFilterBySrcPort (
1099 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1101 IN OUT UINT16
*SrcPort
,
1107 if (Mode
->UsingIpv6
) {
1108 Port
= ((EFI_UDP6_SESSION_DATA
*) Session
)->SourcePort
;
1110 Port
= ((EFI_UDP4_SESSION_DATA
*) Session
)->SourcePort
;
1113 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
) != 0) {
1115 // Return the source port in the received packet if accept any.
1117 if (SrcPort
!= NULL
) {
1121 } else if (SrcPort
!= NULL
&& *SrcPort
== Port
) {
1123 // The source port in the received packet is matched if present.
1133 This function is to receive packet using Udp4Read.
1135 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
1136 @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN.
1137 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1138 @param[in] TimeoutEvent The event for timeout.
1139 @param[in] OpFlags The UDP operation flags.
1140 @param[in] IsDone The pointer to the IsDone flag.
1141 @param[out] IsMatched The pointer to the IsMatched flag.
1142 @param[in, out] DestIp The pointer to the destination address.
1143 @param[in, out] DestPort The pointer to the destination port.
1144 @param[in, out] SrcIp The pointer to the source address.
1145 @param[in, out] SrcPort The pointer to the source port.
1147 @retval EFI_SUCCESS Successfully read the data using Udp4.
1148 @retval Others Failed to send out data.
1153 IN EFI_UDP4_PROTOCOL
*Udp4
,
1154 IN EFI_UDP4_COMPLETION_TOKEN
*Token
,
1155 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1156 IN EFI_EVENT TimeoutEvent
,
1159 OUT BOOLEAN
*IsMatched
,
1160 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1161 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1162 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1163 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1166 EFI_UDP4_RECEIVE_DATA
*RxData
;
1167 EFI_UDP4_SESSION_DATA
*Session
;
1170 Token
->Status
= EFI_NOT_READY
;
1173 Status
= Udp4
->Receive (Udp4
, Token
);
1174 if (EFI_ERROR (Status
)) {
1179 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1181 while (!(*IsDone
) &&
1182 Token
->Status
== EFI_NOT_READY
&&
1183 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1185 // Poll the token utill reply/ICMPv6 error message received or timeout.
1188 if (Token
->Status
== EFI_ICMP_ERROR
||
1189 Token
->Status
== EFI_NETWORK_UNREACHABLE
||
1190 Token
->Status
== EFI_HOST_UNREACHABLE
||
1191 Token
->Status
== EFI_PROTOCOL_UNREACHABLE
||
1192 Token
->Status
== EFI_PORT_UNREACHABLE
) {
1197 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1199 if (!EFI_ERROR (Status
)) {
1201 // check whether this packet matches the filters
1203 RxData
= Token
->Packet
.RxData
;
1204 Session
= &RxData
->UdpSession
;
1206 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1209 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1213 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1217 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1221 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1224 if (!(*IsMatched
)) {
1226 // Recycle the receiving buffer if not matched.
1228 gBS
->SignalEvent (RxData
->RecycleSignal
);
1237 This function is to receive packets using Udp6Read.
1239 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
1240 @param[in] Token The pointer to EFI_UDP6_COMPLETION_TOKEN.
1241 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1242 @param[in] TimeoutEvent The event for timeout.
1243 @param[in] OpFlags The UDP operation flags.
1244 @param[in] IsDone The pointer to the IsDone flag.
1245 @param[out] IsMatched The pointer to the IsMatched flag.
1246 @param[in, out] DestIp The pointer to the destination address.
1247 @param[in, out] DestPort The pointer to the destination port.
1248 @param[in, out] SrcIp The pointer to the source address.
1249 @param[in, out] SrcPort The pointer to the source port.
1251 @retval EFI_SUCCESS Successfully read data using Udp6.
1252 @retval Others Failed to send out data.
1257 IN EFI_UDP6_PROTOCOL
*Udp6
,
1258 IN EFI_UDP6_COMPLETION_TOKEN
*Token
,
1259 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1260 IN EFI_EVENT TimeoutEvent
,
1263 OUT BOOLEAN
*IsMatched
,
1264 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1265 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1266 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1267 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1270 EFI_UDP6_RECEIVE_DATA
*RxData
;
1271 EFI_UDP6_SESSION_DATA
*Session
;
1274 Token
->Status
= EFI_NOT_READY
;
1277 Status
= Udp6
->Receive (Udp6
, Token
);
1278 if (EFI_ERROR (Status
)) {
1283 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1285 while (!(*IsDone
) &&
1286 Token
->Status
== EFI_NOT_READY
&&
1287 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1289 // Poll the token utill reply/ICMPv6 error message received or timeout.
1292 if (Token
->Status
== EFI_ICMP_ERROR
||
1293 Token
->Status
== EFI_NETWORK_UNREACHABLE
||
1294 Token
->Status
== EFI_HOST_UNREACHABLE
||
1295 Token
->Status
== EFI_PROTOCOL_UNREACHABLE
||
1296 Token
->Status
== EFI_PORT_UNREACHABLE
) {
1301 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1303 if (!EFI_ERROR (Status
)) {
1305 // check whether this packet matches the filters
1307 RxData
= Token
->Packet
.RxData
;
1308 Session
= &RxData
->UdpSession
;
1310 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1313 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1317 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1321 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1325 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1328 if (!(*IsMatched
)) {
1330 // Recycle the receiving buffer if not matched.
1332 gBS
->SignalEvent (RxData
->RecycleSignal
);
1341 This function is to display the IPv4 address.
1343 @param[in] Ip The pointer to the IPv4 address.
1348 IN EFI_IPv4_ADDRESS
*Ip
1353 for (Index
= 0; Index
< 4; Index
++) {
1354 AsciiPrint ("%d", Ip
->Addr
[Index
]);
1363 This function is to display the IPv6 address.
1365 @param[in] Ip The pointer to the IPv6 address.
1370 IN EFI_IPv6_ADDRESS
*Ip
1375 for (Index
= 0; Index
< 16; Index
++) {
1377 if (Ip
->Addr
[Index
] != 0) {
1378 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1384 if (((Ip
->Addr
[Index
] & 0xf0) == 0) && (Ip
->Addr
[Index
- 1] != 0)) {
1387 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1396 This function is to convert UINTN to ASCII string with the required formatting.
1398 @param[in] Number Numeric value to be converted.
1399 @param[in] Buffer The pointer to the buffer for ASCII string.
1400 @param[in] Length The length of the required format.
1404 PxeBcUintnToAscDecWithFormat (
1412 for (; Length
> 0; Length
--) {
1413 Remainder
= Number
% 10;
1415 Buffer
[Length
- 1] = (UINT8
) ('0' + Remainder
);
1421 This function is to convert a UINTN to a ASCII string, and return the
1422 actual length of the buffer.
1424 @param[in] Number Numeric value to be converted.
1425 @param[in] Buffer The pointer to the buffer for ASCII string.
1426 @param[in] BufferSize The maxsize of the buffer.
1428 @return Length The actual length of the ASCII string.
1432 PxeBcUintnToAscDec (
1447 TempStr
[Index
] = (CHAR8
) ('0' + (Number
% 10));
1448 Number
= (UINTN
) (Number
/ 10);
1449 } while (Number
!= 0);
1451 AsciiStrCpyS ((CHAR8
*) Buffer
, BufferSize
, &TempStr
[Index
]);
1453 Length
= AsciiStrLen ((CHAR8
*) Buffer
);
1460 This function is to convert unicode hex number to a UINT8.
1462 @param[out] Digit The converted UINT8 for output.
1463 @param[in] Char The unicode hex number to be converted.
1465 @retval EFI_SUCCESS Successfully converted the unicode hex.
1466 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.
1470 PxeBcUniHexToUint8 (
1475 if ((Char
>= L
'0') && (Char
<= L
'9')) {
1476 *Digit
= (UINT8
) (Char
- L
'0');
1480 if ((Char
>= L
'A') && (Char
<= L
'F')) {
1481 *Digit
= (UINT8
) (Char
- L
'A' + 0x0A);
1485 if ((Char
>= L
'a') && (Char
<= L
'f')) {
1486 *Digit
= (UINT8
) (Char
- L
'a' + 0x0A);
1490 return EFI_INVALID_PARAMETER
;
1494 Calculate the elapsed time.
1496 @param[in] Private The pointer to PXE private data
1501 IN PXEBC_PRIVATE_DATA
*Private
1505 UINT64 CurrentStamp
;
1506 UINT64 ElapsedTimeValue
;
1509 // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.
1511 ZeroMem (&Time
, sizeof (EFI_TIME
));
1512 gRT
->GetTime (&Time
, NULL
);
1513 CurrentStamp
= MultU64x32 (
1514 ((((UINT32
)(Time
.Year
- 1900) * 360 + (Time
.Month
- 1) * 30 + (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 + Time
.Minute
) * 60 + Time
.Second
,
1523 // Sentinel value of 0 means that this is the first DHCP packet that we are
1524 // sending and that we need to initialize the value. First DHCP Solicit
1525 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
1527 if (Private
->ElapsedTime
== 0) {
1528 Private
->ElapsedTime
= CurrentStamp
;
1530 ElapsedTimeValue
= CurrentStamp
- Private
->ElapsedTime
;
1533 // If elapsed time cannot fit in two bytes, set it to 0xffff.
1535 if (ElapsedTimeValue
> 0xffff) {
1536 ElapsedTimeValue
= 0xffff;
1539 // Save the elapsed time
1541 Private
->ElapsedTime
= ElapsedTimeValue
;