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"
14 Flush the previous configuration using the new station Ip address.
16 @param[in] Private The pointer to the PxeBc private data.
17 @param[in] StationIp The pointer to the station Ip address.
18 @param[in] SubnetMask The pointer to the subnet mask address for v4.
20 @retval EFI_SUCCESS Successfully flushed the previous configuration.
21 @retval Others Failed to flush using the new station Ip.
26 PXEBC_PRIVATE_DATA
*Private
,
27 EFI_IP_ADDRESS
*StationIp
, OPTIONAL
28 EFI_IP_ADDRESS
*SubnetMask OPTIONAL
31 EFI_PXE_BASE_CODE_MODE
*Mode
;
33 EFI_ARP_CONFIG_DATA ArpConfigData
;
35 Mode
= Private
->PxeBc
.Mode
;
37 ZeroMem (&ArpConfigData
, sizeof (EFI_ARP_CONFIG_DATA
));
39 if (Mode
->UsingIpv6
&& StationIp
!= NULL
) {
41 // Overwrite Udp6CfgData/Ip6CfgData StationAddress.
43 CopyMem (&Private
->Udp6CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
44 CopyMem (&Private
->Ip6CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
47 // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address.
49 Private
->Ip6
->Cancel (Private
->Ip6
, &Private
->Icmp6Token
);
50 Private
->Ip6
->Configure (Private
->Ip6
, NULL
);
52 Status
= Private
->Ip6
->Configure (Private
->Ip6
, &Private
->Ip6CfgData
);
53 if (EFI_ERROR (Status
)) {
57 Status
= Private
->Ip6
->Receive (Private
->Ip6
, &Private
->Icmp6Token
);
59 if (StationIp
!= NULL
) {
61 // Reconfigure the ARP instance with station Ip address.
63 ArpConfigData
.SwAddressType
= 0x0800;
64 ArpConfigData
.SwAddressLength
= (UINT8
) sizeof (EFI_IPv4_ADDRESS
);
65 ArpConfigData
.StationAddress
= StationIp
;
67 Private
->Arp
->Configure (Private
->Arp
, NULL
);
68 Private
->Arp
->Configure (Private
->Arp
, &ArpConfigData
);
71 // Overwrite Udp4CfgData/Ip4CfgData StationAddress.
73 CopyMem (&Private
->Udp4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
74 CopyMem (&Private
->Ip4CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv4_ADDRESS
));
77 if (SubnetMask
!= NULL
) {
79 // Overwrite Udp4CfgData/Ip4CfgData SubnetMask.
81 CopyMem (&Private
->Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
82 CopyMem (&Private
->Ip4CfgData
.SubnetMask
, SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
85 if (StationIp
!= NULL
&& SubnetMask
!= NULL
) {
87 // Updated the route table.
89 Mode
->RouteTableEntries
= 1;
90 Mode
->RouteTable
[0].IpAddr
.Addr
[0] = StationIp
->Addr
[0] & SubnetMask
->Addr
[0];
91 Mode
->RouteTable
[0].SubnetMask
.Addr
[0] = SubnetMask
->Addr
[0];
92 Mode
->RouteTable
[0].GwAddr
.Addr
[0] = 0;
95 if (StationIp
!= NULL
|| SubnetMask
!= NULL
) {
97 // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
99 Private
->Ip4
->Cancel (Private
->Ip4
, &Private
->IcmpToken
);
100 Private
->Ip4
->Configure (Private
->Ip4
, NULL
);
102 Status
= Private
->Ip4
->Configure (Private
->Ip4
, &Private
->Ip4CfgData
);
103 if (EFI_ERROR (Status
)) {
107 Status
= Private
->Ip4
->Receive (Private
->Ip4
, &Private
->IcmpToken
);
117 Notify the callback function when an event is triggered.
119 @param[in] Event The triggered event.
120 @param[in] Context The opaque parameter to the function.
130 *((BOOLEAN
*) Context
) = TRUE
;
135 Do arp resolution from arp cache in PxeBcMode.
137 @param Mode The pointer to EFI_PXE_BASE_CODE_MODE.
138 @param Ip4Addr The Ip4 address for resolution.
139 @param MacAddress The resolved MAC address if the resolution is successful.
140 The value is undefined if the resolution fails.
142 @retval TRUE Found an matched entry.
143 @retval FALSE Did not find a matched entry.
148 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
149 IN EFI_IPv4_ADDRESS
*Ip4Addr
,
150 OUT EFI_MAC_ADDRESS
*MacAddress
155 ASSERT (!Mode
->UsingIpv6
);
158 // Check whether the current Arp cache in mode data contains this information or not.
160 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
161 if (EFI_IP4_EQUAL (&Mode
->ArpCache
[Index
].IpAddr
.v4
, Ip4Addr
)) {
164 &Mode
->ArpCache
[Index
].MacAddr
,
165 sizeof (EFI_MAC_ADDRESS
)
176 Update the arp cache periodically.
178 @param Event The pointer to EFI_PXE_BC_PROTOCOL.
179 @param Context Context of the timer event.
184 PxeBcArpCacheUpdate (
189 PXEBC_PRIVATE_DATA
*Private
;
190 EFI_PXE_BASE_CODE_MODE
*Mode
;
191 EFI_ARP_FIND_DATA
*ArpEntry
;
197 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
198 Mode
= Private
->PxeBc
.Mode
;
200 ASSERT (!Mode
->UsingIpv6
);
203 // Get the current Arp cache from Arp driver.
205 Status
= Private
->Arp
->Find (
214 if (EFI_ERROR (Status
)) {
219 // Update the Arp cache in mode data.
221 Mode
->ArpCacheEntries
= MIN (EntryCount
, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES
);
223 for (Index
= 0; Index
< Mode
->ArpCacheEntries
; Index
++) {
225 &Mode
->ArpCache
[Index
].IpAddr
,
227 ArpEntry
->SwAddressLength
230 &Mode
->ArpCache
[Index
].MacAddr
,
231 (UINT8
*) (ArpEntry
+ 1) + ArpEntry
->SwAddressLength
,
232 ArpEntry
->HwAddressLength
234 ArpEntry
= (EFI_ARP_FIND_DATA
*) ((UINT8
*) ArpEntry
+ EntryLength
);
240 Notify function to handle the received ICMP message in DPC.
242 @param Context The PXEBC private data.
247 PxeBcIcmpErrorDpcHandle (
252 EFI_IP4_RECEIVE_DATA
*RxData
;
253 EFI_IP4_PROTOCOL
*Ip4
;
254 PXEBC_PRIVATE_DATA
*Private
;
255 EFI_PXE_BASE_CODE_MODE
*Mode
;
261 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
262 Mode
= &Private
->Mode
;
263 Status
= Private
->IcmpToken
.Status
;
264 RxData
= Private
->IcmpToken
.Packet
.RxData
;
267 ASSERT (!Mode
->UsingIpv6
);
269 if (Status
== EFI_ABORTED
) {
271 // It's triggered by user cancellation.
276 if (RxData
== NULL
) {
280 if (Status
!= EFI_ICMP_ERROR
) {
282 // The return status should be recognized as EFI_ICMP_ERROR.
287 if (EFI_IP4 (RxData
->Header
->SourceAddress
) != 0 &&
288 (NTOHL (Mode
->SubnetMask
.Addr
[0]) != 0) &&
289 IP4_NET_EQUAL (NTOHL(Mode
->StationIp
.Addr
[0]), EFI_NTOHL (RxData
->Header
->SourceAddress
), NTOHL (Mode
->SubnetMask
.Addr
[0])) &&
290 !NetIp4IsUnicast (EFI_NTOHL (RxData
->Header
->SourceAddress
), NTOHL (Mode
->SubnetMask
.Addr
[0]))) {
292 // The source address of the received packet should be a valid unicast address.
297 if (!EFI_IP4_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v4
)) {
299 // The destination address of the received packet should be equal to the host address.
305 // The protocol has been configured to only receive ICMP packet.
307 ASSERT (RxData
->Header
->Protocol
== EFI_IP_PROTO_ICMP
);
309 Type
= *((UINT8
*) RxData
->FragmentTable
[0].FragmentBuffer
);
311 if (Type
!= ICMP_DEST_UNREACHABLE
&&
312 Type
!= ICMP_SOURCE_QUENCH
&&
313 Type
!= ICMP_REDIRECT
&&
314 Type
!= ICMP_TIME_EXCEEDED
&&
315 Type
!= ICMP_PARAMETER_PROBLEM
) {
317 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
323 // Copy the right ICMP error message into mode data.
326 IcmpError
= (UINT8
*) &Mode
->IcmpError
;
328 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
329 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
330 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
333 RxData
->FragmentTable
[Index
].FragmentBuffer
,
334 RxData
->FragmentTable
[Index
].FragmentLength
339 RxData
->FragmentTable
[Index
].FragmentBuffer
,
340 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
343 IcmpError
+= CopiedLen
;
347 gBS
->SignalEvent (RxData
->RecycleSignal
);
350 Private
->IcmpToken
.Status
= EFI_NOT_READY
;
351 Ip4
->Receive (Ip4
, &Private
->IcmpToken
);
356 Callback function to update the latest ICMP6 error message.
358 @param Event The event signalled.
359 @param Context The context passed in using the event notifier.
364 PxeBcIcmpErrorUpdate (
369 QueueDpc (TPL_CALLBACK
, PxeBcIcmpErrorDpcHandle
, Context
);
374 Notify function to handle the received ICMP6 message in DPC.
376 @param Context The PXEBC private data.
381 PxeBcIcmp6ErrorDpcHandle (
385 PXEBC_PRIVATE_DATA
*Private
;
386 EFI_IP6_RECEIVE_DATA
*RxData
;
387 EFI_IP6_PROTOCOL
*Ip6
;
388 EFI_PXE_BASE_CODE_MODE
*Mode
;
395 Private
= (PXEBC_PRIVATE_DATA
*) Context
;
396 Mode
= &Private
->Mode
;
397 Status
= Private
->Icmp6Token
.Status
;
398 RxData
= Private
->Icmp6Token
.Packet
.RxData
;
401 ASSERT (Mode
->UsingIpv6
);
403 if (Status
== EFI_ABORTED
) {
405 // It's triggered by user cancellation.
410 if (RxData
== NULL
) {
414 if (Status
!= EFI_ICMP_ERROR
) {
416 // The return status should be recognized as EFI_ICMP_ERROR.
421 if (!NetIp6IsValidUnicast (&RxData
->Header
->SourceAddress
)) {
423 // The source address of the received packet should be a valid unicast address.
428 if (!NetIp6IsUnspecifiedAddr (&Mode
->StationIp
.v6
) &&
429 !EFI_IP6_EQUAL (&RxData
->Header
->DestinationAddress
, &Mode
->StationIp
.v6
)) {
431 // The destination address of the received packet should be equal to the host address.
437 // The protocol has been configured to only receive ICMP packet.
439 ASSERT (RxData
->Header
->NextHeader
== IP6_ICMP
);
441 Type
= *((UINT8
*) RxData
->FragmentTable
[0].FragmentBuffer
);
443 if (Type
!= ICMP_V6_DEST_UNREACHABLE
&&
444 Type
!= ICMP_V6_PACKET_TOO_BIG
&&
445 Type
!= ICMP_V6_TIME_EXCEEDED
&&
446 Type
!= ICMP_V6_PARAMETER_PROBLEM
) {
448 // The type of the receveid packet should be an ICMP6 error message.
454 // Copy the right ICMP6 error message into mode data.
457 Icmp6Error
= (UINT8
*) &Mode
->IcmpError
;
459 for (Index
= 0; Index
< RxData
->FragmentCount
; Index
++) {
460 CopiedLen
+= RxData
->FragmentTable
[Index
].FragmentLength
;
461 if (CopiedLen
<= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)) {
464 RxData
->FragmentTable
[Index
].FragmentBuffer
,
465 RxData
->FragmentTable
[Index
].FragmentLength
470 RxData
->FragmentTable
[Index
].FragmentBuffer
,
471 CopiedLen
- sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR
)
474 Icmp6Error
+= CopiedLen
;
478 gBS
->SignalEvent (RxData
->RecycleSignal
);
481 Private
->Icmp6Token
.Status
= EFI_NOT_READY
;
482 Ip6
->Receive (Ip6
, &Private
->Icmp6Token
);
487 Callback function to update the latest ICMP6 error message.
489 @param Event The event signalled.
490 @param Context The context passed in using the event notifier.
495 PxeBcIcmp6ErrorUpdate (
500 QueueDpc (TPL_CALLBACK
, PxeBcIcmp6ErrorDpcHandle
, Context
);
505 This function is to configure a UDPv4 instance for UdpWrite.
507 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
508 @param[in] StationIp The pointer to the station address.
509 @param[in] SubnetMask The pointer to the subnet mask.
510 @param[in] Gateway The pointer to the gateway address.
511 @param[in, out] SrcPort The pointer to the source port.
512 @param[in] DoNotFragment If TRUE, fragment is not enabled.
513 Otherwise, fragment is enabled.
514 @param[in] Ttl The time to live field of the IP header.
515 @param[in] ToS The type of service field of the IP header.
517 @retval EFI_SUCCESS Successfully configured this instance.
518 @retval Others Failed to configure this instance.
522 PxeBcConfigUdp4Write (
523 IN EFI_UDP4_PROTOCOL
*Udp4
,
524 IN EFI_IPv4_ADDRESS
*StationIp
,
525 IN EFI_IPv4_ADDRESS
*SubnetMask
,
526 IN EFI_IPv4_ADDRESS
*Gateway
,
527 IN OUT UINT16
*SrcPort
,
528 IN BOOLEAN DoNotFragment
,
533 EFI_UDP4_CONFIG_DATA Udp4CfgData
;
536 ZeroMem (&Udp4CfgData
, sizeof (Udp4CfgData
));
538 Udp4CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
539 Udp4CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
540 Udp4CfgData
.TypeOfService
= ToS
;
541 Udp4CfgData
.TimeToLive
= Ttl
;
542 Udp4CfgData
.AllowDuplicatePort
= TRUE
;
543 Udp4CfgData
.DoNotFragment
= DoNotFragment
;
545 CopyMem (&Udp4CfgData
.StationAddress
, StationIp
, sizeof (*StationIp
));
546 CopyMem (&Udp4CfgData
.SubnetMask
, SubnetMask
, sizeof (*SubnetMask
));
548 Udp4CfgData
.StationPort
= *SrcPort
;
551 // Reset the UDPv4 instance.
553 Udp4
->Configure (Udp4
, NULL
);
555 Status
= Udp4
->Configure (Udp4
, &Udp4CfgData
);
556 if (!EFI_ERROR (Status
) && !EFI_IP4_EQUAL (Gateway
, &mZeroIp4Addr
)) {
558 // The basic configuration is OK, need to add the default route entry
560 Status
= Udp4
->Routes (Udp4
, FALSE
, &mZeroIp4Addr
, &mZeroIp4Addr
, Gateway
);
561 if (EFI_ERROR (Status
)) {
562 Udp4
->Configure (Udp4
, NULL
);
566 if (!EFI_ERROR (Status
) && *SrcPort
== 0) {
567 Udp4
->GetModeData (Udp4
, &Udp4CfgData
, NULL
, NULL
, NULL
);
568 *SrcPort
= Udp4CfgData
.StationPort
;
576 This function is to configure a UDPv6 instance for UdpWrite.
578 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
579 @param[in] StationIp The pointer to the station address.
580 @param[in, out] SrcPort The pointer to the source port.
582 @retval EFI_SUCCESS Successfully configured this instance.
583 @retval Others Failed to configure this instance.
587 PxeBcConfigUdp6Write (
588 IN EFI_UDP6_PROTOCOL
*Udp6
,
589 IN EFI_IPv6_ADDRESS
*StationIp
,
590 IN OUT UINT16
*SrcPort
593 EFI_UDP6_CONFIG_DATA CfgData
;
596 ZeroMem (&CfgData
, sizeof (EFI_UDP6_CONFIG_DATA
));
598 CfgData
.ReceiveTimeout
= PXEBC_DEFAULT_LIFETIME
;
599 CfgData
.TransmitTimeout
= PXEBC_DEFAULT_LIFETIME
;
600 CfgData
.HopLimit
= PXEBC_DEFAULT_HOPLIMIT
;
601 CfgData
.AllowDuplicatePort
= TRUE
;
602 CfgData
.StationPort
= *SrcPort
;
604 CopyMem (&CfgData
.StationAddress
, StationIp
, sizeof (EFI_IPv6_ADDRESS
));
607 // Reset the UDPv6 instance.
609 Udp6
->Configure (Udp6
, NULL
);
611 Status
= Udp6
->Configure (Udp6
, &CfgData
);
612 if (EFI_ERROR (Status
)) {
616 if (!EFI_ERROR (Status
) && *SrcPort
== 0) {
617 Udp6
->GetModeData (Udp6
, &CfgData
, NULL
, NULL
, NULL
);
618 *SrcPort
= CfgData
.StationPort
;
626 This function is to configure a UDPv4 instance for UdpWrite.
628 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
629 @param[in] Session The pointer to the UDP4 session data.
630 @param[in] TimeoutEvent The event for timeout.
631 @param[in] Gateway The pointer to the gateway address.
632 @param[in] HeaderSize An optional field which may be set to the length of a header
633 at HeaderPtr to be prefixed to the data at BufferPtr.
634 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
635 prefixed to the data at BufferPtr.
636 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
637 @param[in] BufferPtr A pointer to the data to be written.
639 @retval EFI_SUCCESS Successfully send out data using Udp4Write.
640 @retval Others Failed to send out data.
645 IN EFI_UDP4_PROTOCOL
*Udp4
,
646 IN EFI_UDP4_SESSION_DATA
*Session
,
647 IN EFI_EVENT TimeoutEvent
,
648 IN EFI_IPv4_ADDRESS
*Gateway OPTIONAL
,
649 IN UINTN
*HeaderSize OPTIONAL
,
650 IN VOID
*HeaderPtr OPTIONAL
,
651 IN UINTN
*BufferSize
,
655 EFI_UDP4_COMPLETION_TOKEN Token
;
656 EFI_UDP4_TRANSMIT_DATA
*TxData
;
664 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
666 FragCount
= (HeaderSize
!= NULL
) ? 2 : 1;
667 TxLength
= sizeof (EFI_UDP4_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP4_FRAGMENT_DATA
);
668 TxData
= (EFI_UDP4_TRANSMIT_DATA
*) AllocateZeroPool (TxLength
);
669 if (TxData
== NULL
) {
670 return EFI_OUT_OF_RESOURCES
;
673 TxData
->FragmentCount
= FragCount
;
674 TxData
->FragmentTable
[FragCount
- 1].FragmentLength
= (UINT32
) *BufferSize
;
675 TxData
->FragmentTable
[FragCount
- 1].FragmentBuffer
= BufferPtr
;
676 DataLength
= (UINT32
) *BufferSize
;
678 if (HeaderSize
!= NULL
) {
679 TxData
->FragmentTable
[0].FragmentLength
= (UINT32
) *HeaderSize
;
680 TxData
->FragmentTable
[0].FragmentBuffer
= HeaderPtr
;
681 DataLength
+= (UINT32
) *HeaderSize
;
684 if (Gateway
!= NULL
) {
685 TxData
->GatewayAddress
= Gateway
;
688 TxData
->UdpSessionData
= Session
;
689 TxData
->DataLength
= DataLength
;
690 Token
.Packet
.TxData
= TxData
;
691 Token
.Status
= EFI_NOT_READY
;
694 Status
= gBS
->CreateEvent (
701 if (EFI_ERROR (Status
)) {
705 Status
= Udp4
->Transmit (Udp4
, &Token
);
706 if (EFI_ERROR (Status
)) {
711 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
714 Token
.Status
== EFI_NOT_READY
&&
715 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
719 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
722 if (Token
.Event
!= NULL
) {
723 gBS
->CloseEvent (Token
.Event
);
732 This function is to configure a UDPv4 instance for UdpWrite.
734 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
735 @param[in] Session The pointer to the UDP6 session data.
736 @param[in] TimeoutEvent The event for timeout.
737 @param[in] HeaderSize An optional field which may be set to the length of a header
738 at HeaderPtr to be prefixed to the data at BufferPtr.
739 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
740 prefixed to the data at BufferPtr.
741 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
742 @param[in] BufferPtr A pointer to the data to be written.
744 @retval EFI_SUCCESS Successfully sent out data using Udp6Write.
745 @retval Others Failed to send out data.
750 IN EFI_UDP6_PROTOCOL
*Udp6
,
751 IN EFI_UDP6_SESSION_DATA
*Session
,
752 IN EFI_EVENT TimeoutEvent
,
753 IN UINTN
*HeaderSize OPTIONAL
,
754 IN VOID
*HeaderPtr OPTIONAL
,
755 IN UINTN
*BufferSize
,
759 EFI_UDP6_COMPLETION_TOKEN Token
;
760 EFI_UDP6_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_UDP6_TRANSMIT_DATA
) + (FragCount
- 1) * sizeof (EFI_UDP6_FRAGMENT_DATA
);
772 TxData
= (EFI_UDP6_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 TxData
->UdpSessionData
= Session
;
789 TxData
->DataLength
= DataLength
;
790 Token
.Packet
.TxData
= TxData
;
791 Token
.Status
= EFI_NOT_READY
;
794 Status
= gBS
->CreateEvent (
801 if (EFI_ERROR (Status
)) {
805 Status
= Udp6
->Transmit (Udp6
, &Token
);
806 if (EFI_ERROR (Status
)) {
811 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
814 Token
.Status
== EFI_NOT_READY
&&
815 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
819 Status
= (Token
.Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
.Status
;
822 if (Token
.Event
!= NULL
) {
823 gBS
->CloseEvent (Token
.Event
);
832 Check the received packet using the Ip filter.
834 @param[in] Mode The pointer to the mode data of PxeBc.
835 @param[in] Session The pointer to the current UDPv4 session.
836 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
838 @retval TRUE Passed the Ip filter successfully.
839 @retval FALSE Failed to pass the Ip filter.
843 PxeBcCheckByIpFilter (
844 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
849 EFI_IP_ADDRESS DestinationIp
;
852 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER
) == 0) {
856 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS
) != 0) {
861 // Convert the destination address in session data to host order.
863 if (Mode
->UsingIpv6
) {
866 &((EFI_UDP6_SESSION_DATA
*) Session
)->DestinationAddress
,
867 sizeof (EFI_IPv6_ADDRESS
)
869 NTOHLLL (&DestinationIp
.v6
);
871 ZeroMem (&DestinationIp
, sizeof (EFI_IP_ADDRESS
));
874 &((EFI_UDP4_SESSION_DATA
*) Session
)->DestinationAddress
,
875 sizeof (EFI_IPv4_ADDRESS
)
877 EFI_NTOHL (DestinationIp
);
880 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST
) != 0 &&
881 (IP4_IS_MULTICAST (DestinationIp
.Addr
[0]) ||
882 IP6_IS_MULTICAST (&DestinationIp
))) {
886 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST
) != 0 &&
887 IP4_IS_LOCAL_BROADCAST (DestinationIp
.Addr
[0])) {
888 ASSERT (!Mode
->UsingIpv6
);
892 if ((Mode
->IpFilter
.Filters
& EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP
) != 0 &&
893 (EFI_IP4_EQUAL (&Mode
->StationIp
.v4
, &DestinationIp
) ||
894 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
)) {
906 // 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
))) {
962 // The destination address in the received packet is matched if present.
965 } else if (EFI_IP4_EQUAL (&Mode
->StationIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->DestinationAddress
) ||
966 EFI_IP6_EQUAL (&Mode
->StationIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->DestinationAddress
)) {
968 // The destination address in the received packet is equal to the host address.
978 Check the received packet using the destination port.
980 @param[in] Mode The pointer to the mode data of PxeBc.
981 @param[in] Session The pointer to the current UDPv4 session.
982 @param[in, out] DestPort The pointer to the destination port.
983 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
985 @retval TRUE Passed the IPv4 filter successfully.
986 @retval FALSE Failed to pass the IPv4 filter.
990 PxeBcCheckByDestPort (
991 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
993 IN OUT UINT16
*DestPort
,
999 if (Mode
->UsingIpv6
) {
1000 Port
= ((EFI_UDP6_SESSION_DATA
*) Session
)->DestinationPort
;
1002 Port
= ((EFI_UDP4_SESSION_DATA
*) Session
)->DestinationPort
;
1005 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT
) != 0) {
1007 // Return the destination port in the received packet if accept any.
1009 if (DestPort
!= NULL
) {
1013 } else if (DestPort
!= NULL
&& *DestPort
== Port
) {
1015 // The destination port in the received packet is matched if present.
1025 Filter the received packet using the source Ip.
1027 @param[in] Mode The pointer to the mode data of PxeBc.
1028 @param[in] Session The pointer to the current UDPv4 session.
1029 @param[in, out] SrcIp The pointer to the source Ip address.
1030 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1032 @retval TRUE Passed the IPv4 filter successfully.
1033 @retval FALSE Failed to pass the IPv4 filter.
1037 PxeBcFilterBySrcIp (
1038 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1040 IN OUT EFI_IP_ADDRESS
*SrcIp
,
1044 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
) != 0) {
1046 // Copy the source address from the received packet if accept any.
1048 if (SrcIp
!= NULL
) {
1049 if (Mode
->UsingIpv6
) {
1052 &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
,
1053 sizeof (EFI_IPv6_ADDRESS
)
1056 ZeroMem (SrcIp
, sizeof (EFI_IP_ADDRESS
));
1059 &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
,
1060 sizeof (EFI_IPv4_ADDRESS
)
1066 } else if (SrcIp
!= NULL
&&
1067 (EFI_IP4_EQUAL (SrcIp
, &((EFI_UDP4_SESSION_DATA
*)Session
)->SourceAddress
) ||
1068 EFI_IP6_EQUAL (SrcIp
, &((EFI_UDP6_SESSION_DATA
*)Session
)->SourceAddress
))) {
1070 // The source address in the received packet is matched if present.
1080 Filter the received packet using the source port.
1082 @param[in] Mode The pointer to the mode data of PxeBc.
1083 @param[in] Session The pointer to the current UDPv4 session.
1084 @param[in, out] SrcPort The pointer to the source port.
1085 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1087 @retval TRUE Passed the IPv4 filter successfully.
1088 @retval FALSE Failed to pass the IPv4 filter.
1092 PxeBcFilterBySrcPort (
1093 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1095 IN OUT UINT16
*SrcPort
,
1101 if (Mode
->UsingIpv6
) {
1102 Port
= ((EFI_UDP6_SESSION_DATA
*) Session
)->SourcePort
;
1104 Port
= ((EFI_UDP4_SESSION_DATA
*) Session
)->SourcePort
;
1107 if ((OpFlags
& EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
) != 0) {
1109 // Return the source port in the received packet if accept any.
1111 if (SrcPort
!= NULL
) {
1115 } else if (SrcPort
!= NULL
&& *SrcPort
== Port
) {
1117 // The source port in the received packet is matched if present.
1127 This function is to receive packet using Udp4Read.
1129 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
1130 @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN.
1131 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1132 @param[in] TimeoutEvent The event for timeout.
1133 @param[in] OpFlags The UDP operation flags.
1134 @param[in] IsDone The pointer to the IsDone flag.
1135 @param[out] IsMatched The pointer to the IsMatched flag.
1136 @param[in, out] DestIp The pointer to the destination address.
1137 @param[in, out] DestPort The pointer to the destination port.
1138 @param[in, out] SrcIp The pointer to the source address.
1139 @param[in, out] SrcPort The pointer to the source port.
1141 @retval EFI_SUCCESS Successfully read the data using Udp4.
1142 @retval Others Failed to send out data.
1147 IN EFI_UDP4_PROTOCOL
*Udp4
,
1148 IN EFI_UDP4_COMPLETION_TOKEN
*Token
,
1149 IN EFI_PXE_BASE_CODE_MODE
*Mode
,
1150 IN EFI_EVENT TimeoutEvent
,
1153 OUT BOOLEAN
*IsMatched
,
1154 IN OUT EFI_IP_ADDRESS
*DestIp OPTIONAL
,
1155 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*DestPort OPTIONAL
,
1156 IN OUT EFI_IP_ADDRESS
*SrcIp OPTIONAL
,
1157 IN OUT EFI_PXE_BASE_CODE_UDP_PORT
*SrcPort OPTIONAL
1160 EFI_UDP4_RECEIVE_DATA
*RxData
;
1161 EFI_UDP4_SESSION_DATA
*Session
;
1164 Token
->Status
= EFI_NOT_READY
;
1167 Status
= Udp4
->Receive (Udp4
, Token
);
1168 if (EFI_ERROR (Status
)) {
1173 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1175 while (!(*IsDone
) &&
1176 Token
->Status
== EFI_NOT_READY
&&
1177 EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
1179 // Poll the token until reply/ICMPv6 error message received or timeout.
1182 if (Token
->Status
== EFI_ICMP_ERROR
||
1183 Token
->Status
== EFI_NETWORK_UNREACHABLE
||
1184 Token
->Status
== EFI_HOST_UNREACHABLE
||
1185 Token
->Status
== EFI_PROTOCOL_UNREACHABLE
||
1186 Token
->Status
== EFI_PORT_UNREACHABLE
) {
1191 Status
= (Token
->Status
== EFI_NOT_READY
) ? EFI_TIMEOUT
: Token
->Status
;
1193 if (!EFI_ERROR (Status
)) {
1195 // check whether this packet matches the filters
1197 RxData
= Token
->Packet
.RxData
;
1198 Session
= &RxData
->UdpSession
;
1200 *IsMatched
= PxeBcCheckByIpFilter (Mode
, Session
, OpFlags
);
1203 *IsMatched
= PxeBcCheckByDestIp (Mode
, Session
, DestIp
, OpFlags
);
1207 *IsMatched
= PxeBcCheckByDestPort (Mode
, Session
, DestPort
, OpFlags
);
1211 *IsMatched
= PxeBcFilterBySrcIp (Mode
, Session
, SrcIp
, OpFlags
);
1215 *IsMatched
= PxeBcFilterBySrcPort (Mode
, Session
, SrcPort
, OpFlags
);
1218 if (!(*IsMatched
)) {
1220 // Recycle the receiving buffer if not matched.
1222 gBS
->SignalEvent (RxData
->RecycleSignal
);
1231 This function is to receive packets using Udp6Read.
1233 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
1234 @param[in] Token The pointer to EFI_UDP6_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 data using Udp6.
1246 @retval Others Failed to send out data.
1251 IN EFI_UDP6_PROTOCOL
*Udp6
,
1252 IN EFI_UDP6_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_UDP6_RECEIVE_DATA
*RxData
;
1265 EFI_UDP6_SESSION_DATA
*Session
;
1268 Token
->Status
= EFI_NOT_READY
;
1271 Status
= Udp6
->Receive (Udp6
, 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 until 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 display the IPv4 address.
1337 @param[in] Ip The pointer to the IPv4 address.
1342 IN EFI_IPv4_ADDRESS
*Ip
1347 for (Index
= 0; Index
< 4; Index
++) {
1348 AsciiPrint ("%d", Ip
->Addr
[Index
]);
1357 This function is to display the IPv6 address.
1359 @param[in] Ip The pointer to the IPv6 address.
1364 IN EFI_IPv6_ADDRESS
*Ip
1369 for (Index
= 0; Index
< 16; Index
++) {
1371 if (Ip
->Addr
[Index
] != 0) {
1372 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1378 if (((Ip
->Addr
[Index
] & 0xf0) == 0) && (Ip
->Addr
[Index
- 1] != 0)) {
1381 AsciiPrint ("%x", Ip
->Addr
[Index
]);
1390 This function is to convert UINTN to ASCII string with the required formatting.
1392 @param[in] Number Numeric value to be converted.
1393 @param[in] Buffer The pointer to the buffer for ASCII string.
1394 @param[in] Length The length of the required format.
1398 PxeBcUintnToAscDecWithFormat (
1406 for (; Length
> 0; Length
--) {
1407 Remainder
= Number
% 10;
1409 Buffer
[Length
- 1] = (UINT8
) ('0' + Remainder
);
1415 This function is to convert a UINTN to a ASCII string, and return the
1416 actual length of the buffer.
1418 @param[in] Number Numeric value to be converted.
1419 @param[in] Buffer The pointer to the buffer for ASCII string.
1420 @param[in] BufferSize The maxsize of the buffer.
1422 @return Length The actual length of the ASCII string.
1426 PxeBcUintnToAscDec (
1441 TempStr
[Index
] = (CHAR8
) ('0' + (Number
% 10));
1442 Number
= (UINTN
) (Number
/ 10);
1443 } while (Number
!= 0);
1445 AsciiStrCpyS ((CHAR8
*) Buffer
, BufferSize
, &TempStr
[Index
]);
1447 Length
= AsciiStrLen ((CHAR8
*) Buffer
);
1454 This function is to convert unicode hex number to a UINT8.
1456 @param[out] Digit The converted UINT8 for output.
1457 @param[in] Char The unicode hex number to be converted.
1459 @retval EFI_SUCCESS Successfully converted the unicode hex.
1460 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.
1464 PxeBcUniHexToUint8 (
1469 if ((Char
>= L
'0') && (Char
<= L
'9')) {
1470 *Digit
= (UINT8
) (Char
- L
'0');
1474 if ((Char
>= L
'A') && (Char
<= L
'F')) {
1475 *Digit
= (UINT8
) (Char
- L
'A' + 0x0A);
1479 if ((Char
>= L
'a') && (Char
<= L
'f')) {
1480 *Digit
= (UINT8
) (Char
- L
'a' + 0x0A);
1484 return EFI_INVALID_PARAMETER
;
1488 Calculate the elapsed time.
1490 @param[in] Private The pointer to PXE private data
1495 IN PXEBC_PRIVATE_DATA
*Private
1499 UINT64 CurrentStamp
;
1500 UINT64 ElapsedTimeValue
;
1503 // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.
1505 ZeroMem (&Time
, sizeof (EFI_TIME
));
1506 gRT
->GetTime (&Time
, NULL
);
1507 CurrentStamp
= MultU64x32 (
1508 ((((UINT32
)(Time
.Year
- 1900) * 360 + (Time
.Month
- 1) * 30 + (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 + Time
.Minute
) * 60 + Time
.Second
,
1517 // Sentinel value of 0 means that this is the first DHCP packet that we are
1518 // sending and that we need to initialize the value. First DHCP Solicit
1519 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
1521 if (Private
->ElapsedTime
== 0) {
1522 Private
->ElapsedTime
= CurrentStamp
;
1524 ElapsedTimeValue
= CurrentStamp
- Private
->ElapsedTime
;
1527 // If elapsed time cannot fit in two bytes, set it to 0xffff.
1529 if (ElapsedTimeValue
> 0xffff) {
1530 ElapsedTimeValue
= 0xffff;
1533 // Save the elapsed time
1535 Private
->ElapsedTime
= ElapsedTimeValue
;