diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib')
3 files changed, 1181 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib/DxeUdpIoLib.c b/src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib/DxeUdpIoLib.c new file mode 100644 index 00000000..6b04fb98 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib/DxeUdpIoLib.c @@ -0,0 +1,1119 @@ +/** @file + Help functions to access UDP service, it is used by both the DHCP and MTFTP. + +Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Uefi.h> + +#include <Protocol/Udp4.h> +#include <Protocol/Udp6.h> + +#include <Library/UdpIoLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DpcLib.h> + + +/** + Free a UDP_TX_TOKEN. The TX event is closed. + + @param[in] TxToken The UDP_TX_TOKEN to release. + +**/ +VOID +UdpIoFreeTxToken ( + IN UDP_TX_TOKEN *TxToken + ) +{ + + if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + gBS->CloseEvent (TxToken->Token.Udp4.Event); + } else if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) { + gBS->CloseEvent (TxToken->Token.Udp6.Event); + } else { + ASSERT (FALSE); + } + + FreePool (TxToken); +} + +/** + Free a UDP_RX_TOKEN. The RX event is closed. + + @param[in] RxToken The UDP_RX_TOKEN to release. + +**/ +VOID +UdpIoFreeRxToken ( + IN UDP_RX_TOKEN *RxToken + ) +{ + if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + gBS->CloseEvent (RxToken->Token.Udp4.Event); + } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) { + gBS->CloseEvent (RxToken->Token.Udp6.Event); + } else { + ASSERT (FALSE); + } + + FreePool (RxToken); +} + +/** + The callback function when the packet is sent by UDP. + + It will remove the packet from the local list then call + the packet owner's callback function set by UdpIoSendDatagram. + + @param[in] Context The UDP TX Token. + +**/ +VOID +EFIAPI +UdpIoOnDgramSentDpc ( + IN VOID *Context + ) +{ + UDP_TX_TOKEN *TxToken; + + TxToken = (UDP_TX_TOKEN *) Context; + ASSERT (TxToken->Signature == UDP_IO_TX_SIGNATURE); + ASSERT ((TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); + + RemoveEntryList (&TxToken->Link); + + if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp4.Status, TxToken->Context); + } else { + TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp6.Status, TxToken->Context); + } + + UdpIoFreeTxToken (TxToken); +} + +/** + Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK. + + @param[in] Event The event signaled. + @param[in] Context The UDP TX Token. + +**/ +VOID +EFIAPI +UdpIoOnDgramSent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK + // + QueueDpc (TPL_CALLBACK, UdpIoOnDgramSentDpc, Context); +} + +/** + Recycle the received UDP data. + + @param[in] Context The UDP_RX_TOKEN. + +**/ +VOID +EFIAPI +UdpIoRecycleDgram ( + IN VOID *Context + ) +{ + UDP_RX_TOKEN *RxToken; + + RxToken = (UDP_RX_TOKEN *) Context; + + if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + gBS->SignalEvent (RxToken->Token.Udp4.Packet.RxData->RecycleSignal); + } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) { + gBS->SignalEvent (RxToken->Token.Udp6.Packet.RxData->RecycleSignal); + } else { + ASSERT (FALSE); + } + + UdpIoFreeRxToken (RxToken); +} + +/** + The event handle for UDP receive request. + + It will build a NET_BUF from the received UDP data, then deliver it + to the receiver. + + @param[in] Context The UDP RX token. + +**/ +VOID +EFIAPI +UdpIoOnDgramRcvdDpc ( + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *Token; + VOID *RxData; + VOID *Session; + UDP_RX_TOKEN *RxToken; + UDP_END_POINT EndPoint; + NET_BUF *Netbuf; + + RxToken = (UDP_RX_TOKEN *) Context; + + ZeroMem (&EndPoint, sizeof(UDP_END_POINT)); + + ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) && + (RxToken == RxToken->UdpIo->RecvRequest)); + + ASSERT ((RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); + + // + // Clear the receive request first in case that the caller + // wants to restart the receive in the callback. + // + RxToken->UdpIo->RecvRequest = NULL; + + if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + Token = &RxToken->Token.Udp4; + RxData = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.RxData; + Status = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status; + } else { + Token = &RxToken->Token.Udp6; + RxData = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.RxData; + Status = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status; + } + + if (EFI_ERROR (Status) || RxData == NULL) { + if (Status != EFI_ABORTED) { + // + // Invoke the CallBack only if the reception is not actively aborted. + // + RxToken->CallBack (NULL, NULL, Status, RxToken->Context); + } + + UdpIoFreeRxToken (RxToken); + return; + } + + // + // Build a NET_BUF from the UDP receive data, then deliver it up. + // + if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + if (((EFI_UDP4_RECEIVE_DATA *) RxData)->DataLength == 0) { + // + // Discard zero length data payload packet. + // + goto Resume; + } + + Netbuf = NetbufFromExt ( + (NET_FRAGMENT *)((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentTable, + ((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentCount, + 0, + (UINT32) RxToken->HeadLen, + UdpIoRecycleDgram, + RxToken + ); + + if (Netbuf == NULL) { + gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal); + RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context); + + UdpIoFreeRxToken (RxToken); + return; + } + + Session = &((EFI_UDP4_RECEIVE_DATA *) RxData)->UdpSession; + EndPoint.LocalPort = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort; + EndPoint.RemotePort = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort; + + CopyMem ( + &EndPoint.LocalAddr, + &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress, + sizeof (EFI_IPv4_ADDRESS) + ); + + CopyMem ( + &EndPoint.RemoteAddr, + &((EFI_UDP4_SESSION_DATA *) Session)->SourceAddress, + sizeof (EFI_IPv4_ADDRESS) + ); + + EndPoint.LocalAddr.Addr[0] = NTOHL (EndPoint.LocalAddr.Addr[0]); + EndPoint.RemoteAddr.Addr[0] = NTOHL (EndPoint.RemoteAddr.Addr[0]); + } else { + if (((EFI_UDP6_RECEIVE_DATA *) RxData)->DataLength == 0) { + // + // Discard zero length data payload packet. + // + goto Resume; + } + + Netbuf = NetbufFromExt ( + (NET_FRAGMENT *)((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentTable, + ((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentCount, + 0, + (UINT32) RxToken->HeadLen, + UdpIoRecycleDgram, + RxToken + ); + + if (Netbuf == NULL) { + gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal); + RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context); + + UdpIoFreeRxToken (RxToken); + return; + } + + Session = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession; + EndPoint.LocalPort = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort; + EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort; + + CopyMem ( + &EndPoint.LocalAddr, + &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress, + sizeof (EFI_IPv6_ADDRESS) + ); + + CopyMem ( + &EndPoint.RemoteAddr, + &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress, + sizeof (EFI_IPv6_ADDRESS) + ); + + Ip6Swap128 (&EndPoint.LocalAddr.v6); + Ip6Swap128 (&EndPoint.RemoteAddr.v6); + } + + RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context); + return; + +Resume: + if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal); + RxToken->UdpIo->Protocol.Udp4->Receive (RxToken->UdpIo->Protocol.Udp4, &RxToken->Token.Udp4); + } else { + gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal); + RxToken->UdpIo->Protocol.Udp6->Receive (RxToken->UdpIo->Protocol.Udp6, &RxToken->Token.Udp6); + } +} + +/** + Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK. + + @param[in] Event The UDP receive request event. + @param[in] Context The UDP RX token. + +**/ +VOID +EFIAPI +UdpIoOnDgramRcvd ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK + // + QueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context); +} + +/** + Create a UDP_RX_TOKEN to wrap the request. + + @param[in] UdpIo The UdpIo to receive packets from. + @param[in] CallBack The function to call when receive finished. + @param[in] Context The opaque parameter to the CallBack. + @param[in] HeadLen The head length to reserve for the packet. + + @return The Wrapped request or NULL if failed to allocate resources or some errors happened. + +**/ +UDP_RX_TOKEN * +UdpIoCreateRxToken ( + IN UDP_IO *UdpIo, + IN UDP_IO_CALLBACK CallBack, + IN VOID *Context, + IN UINT32 HeadLen + ) +{ + UDP_RX_TOKEN *Token; + EFI_STATUS Status; + + ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); + + Token = AllocatePool (sizeof (UDP_RX_TOKEN)); + + if (Token == NULL) { + return NULL; + } + + Token->Signature = UDP_IO_RX_SIGNATURE; + Token->UdpIo = UdpIo; + Token->CallBack = CallBack; + Token->Context = Context; + Token->HeadLen = HeadLen; + + if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + + Token->Token.Udp4.Status = EFI_NOT_READY; + Token->Token.Udp4.Packet.RxData = NULL; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + UdpIoOnDgramRcvd, + Token, + &Token->Token.Udp4.Event + ); + } else { + + Token->Token.Udp6.Status = EFI_NOT_READY; + Token->Token.Udp6.Packet.RxData = NULL; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + UdpIoOnDgramRcvd, + Token, + &Token->Token.Udp6.Event + ); + } + + + if (EFI_ERROR (Status)) { + FreePool (Token); + return NULL; + } + + return Token; +} + +/** + Wrap a transmit request into a new created UDP_TX_TOKEN. + + If Packet is NULL, then ASSERT(). + If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT(). + + @param[in] UdpIo The UdpIo to send packet to. + @param[in] Packet The user's packet. + @param[in] EndPoint The local and remote access point. + @param[in] Gateway The overridden next hop. + @param[in] CallBack The function to call when transmission completed. + @param[in] Context The opaque parameter to the call back. + + @return The wrapped transmission request or NULL if failed to allocate resources + or for some errors. + +**/ +UDP_TX_TOKEN * +UdpIoCreateTxToken ( + IN UDP_IO *UdpIo, + IN NET_BUF *Packet, + IN UDP_END_POINT *EndPoint OPTIONAL, + IN EFI_IP_ADDRESS *Gateway OPTIONAL, + IN UDP_IO_CALLBACK CallBack, + IN VOID *Context + ) +{ + UDP_TX_TOKEN *TxToken; + VOID *Token; + VOID *Data; + EFI_STATUS Status; + UINT32 Count; + UINTN Size; + IP4_ADDR Ip; + + ASSERT (Packet != NULL); + ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); + + if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1); + } else { + Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP6_FRAGMENT_DATA) * (Packet->BlockOpNum - 1); + } + + TxToken = AllocatePool (Size); + + if (TxToken == NULL) { + return NULL; + } + + TxToken->Signature = UDP_IO_TX_SIGNATURE; + InitializeListHead (&TxToken->Link); + + TxToken->UdpIo = UdpIo; + TxToken->CallBack = CallBack; + TxToken->Packet = Packet; + TxToken->Context = Context; + + Token = &(TxToken->Token); + Count = Packet->BlockOpNum; + + if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + + ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + UdpIoOnDgramSent, + TxToken, + &((EFI_UDP4_COMPLETION_TOKEN *) Token)->Event + ); + + if (EFI_ERROR (Status)) { + FreePool (TxToken); + return NULL; + } + + Data = &(TxToken->Data.Udp4); + ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.TxData = Data; + + ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = NULL; + ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = NULL; + ((EFI_UDP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize; + + NetbufBuildExt ( + Packet, + (NET_FRAGMENT *)((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentTable, + &Count + ); + + ((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentCount = Count; + + if (EndPoint != NULL) { + Ip = HTONL (EndPoint->LocalAddr.Addr[0]); + CopyMem ( + &TxToken->Session.Udp4.SourceAddress, + &Ip, + sizeof (EFI_IPv4_ADDRESS) + ); + + Ip = HTONL (EndPoint->RemoteAddr.Addr[0]); + CopyMem ( + &TxToken->Session.Udp4.DestinationAddress, + &Ip, + sizeof (EFI_IPv4_ADDRESS) + ); + + TxToken->Session.Udp4.SourcePort = EndPoint->LocalPort; + TxToken->Session.Udp4.DestinationPort = EndPoint->RemotePort; + ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp4); + } + + if (Gateway != NULL && (Gateway->Addr[0] != 0)) { + Ip = HTONL (Gateway->Addr[0]); + CopyMem (&TxToken->Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS)); + ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = &TxToken->Gateway; + } + + } else { + + ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + UdpIoOnDgramSent, + TxToken, + &((EFI_UDP6_COMPLETION_TOKEN *) Token)->Event + ); + + if (EFI_ERROR (Status)) { + FreePool (TxToken); + return NULL; + } + + Data = &(TxToken->Data.Udp6); + ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.TxData = Data; + ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = NULL; + ((EFI_UDP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize; + + NetbufBuildExt ( + Packet, + (NET_FRAGMENT *)((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentTable, + &Count + ); + + ((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentCount = Count; + + if (EndPoint != NULL) { + CopyMem ( + &TxToken->Session.Udp6.SourceAddress, + &EndPoint->LocalAddr.v6, + sizeof(EFI_IPv6_ADDRESS) + ); + + CopyMem ( + &TxToken->Session.Udp6.DestinationAddress, + &EndPoint->RemoteAddr.v6, + sizeof(EFI_IPv6_ADDRESS) + ); + + TxToken->Session.Udp6.SourcePort = EndPoint->LocalPort; + TxToken->Session.Udp6.DestinationPort = EndPoint->RemotePort; + ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp6); + } + } + + return TxToken; +} + +/** + Creates a UDP_IO to access the UDP service. It creates and configures + a UDP child. + + If Configure is NULL, then ASSERT(). + If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT(). + + It locates the UDP service binding prototype on the Controller parameter + uses the UDP service binding prototype to create a UDP child (also known as + a UDP instance) configures the UDP child by calling Configure function prototype. + Any failures in creating or configuring the UDP child return NULL for failure. + + @param[in] Controller The controller that has the UDP service binding. + protocol installed. + @param[in] ImageHandle The image handle for the driver. + @param[in] Configure The function to configure the created UDP child. + @param[in] UdpVersion The UDP protocol version, UDP4 or UDP6. + @param[in] Context The opaque parameter for the Configure function. + + @return Newly-created UDP_IO or NULL if failed. + +**/ +UDP_IO * +EFIAPI +UdpIoCreateIo ( + IN EFI_HANDLE Controller, + IN EFI_HANDLE ImageHandle, + IN UDP_IO_CONFIG Configure, + IN UINT8 UdpVersion, + IN VOID *Context + ) +{ + UDP_IO *UdpIo; + EFI_STATUS Status; + + ASSERT (Configure != NULL); + ASSERT ((UdpVersion == UDP_IO_UDP4_VERSION) || (UdpVersion == UDP_IO_UDP6_VERSION)); + + UdpIo = AllocatePool (sizeof (UDP_IO)); + + if (UdpIo == NULL) { + return NULL; + } + + UdpIo->UdpVersion = UdpVersion; + UdpIo->Signature = UDP_IO_SIGNATURE; + InitializeListHead (&UdpIo->Link); + UdpIo->RefCnt = 1; + + UdpIo->Controller = Controller; + UdpIo->Image = ImageHandle; + + InitializeListHead (&UdpIo->SentDatagram); + UdpIo->RecvRequest = NULL; + UdpIo->UdpHandle = NULL; + + if (UdpVersion == UDP_IO_UDP4_VERSION) { + // + // Create a UDP child then open and configure it + // + Status = NetLibCreateServiceChild ( + Controller, + ImageHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + &UdpIo->UdpHandle + ); + + if (EFI_ERROR (Status)) { + goto FREE_MEM; + } + + Status = gBS->OpenProtocol ( + UdpIo->UdpHandle, + &gEfiUdp4ProtocolGuid, + (VOID **) &UdpIo->Protocol.Udp4, + ImageHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto FREE_CHILD; + } + + if (EFI_ERROR (Configure (UdpIo, Context))) { + goto CLOSE_PROTOCOL; + } + + Status = UdpIo->Protocol.Udp4->GetModeData ( + UdpIo->Protocol.Udp4, + NULL, + NULL, + NULL, + &UdpIo->SnpMode + ); + + if (EFI_ERROR (Status)) { + goto CLOSE_PROTOCOL; + } + + } else { + + Status = NetLibCreateServiceChild ( + Controller, + ImageHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + &UdpIo->UdpHandle + ); + + if (EFI_ERROR (Status)) { + goto FREE_MEM; + } + + Status = gBS->OpenProtocol ( + UdpIo->UdpHandle, + &gEfiUdp6ProtocolGuid, + (VOID **) &UdpIo->Protocol.Udp6, + ImageHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + goto FREE_CHILD; + } + + if (EFI_ERROR (Configure (UdpIo, Context))) { + goto CLOSE_PROTOCOL; + } + + Status = UdpIo->Protocol.Udp6->GetModeData ( + UdpIo->Protocol.Udp6, + NULL, + NULL, + NULL, + &UdpIo->SnpMode + ); + + if (EFI_ERROR (Status)) { + goto CLOSE_PROTOCOL; + } + } + + return UdpIo; + +CLOSE_PROTOCOL: + if (UdpVersion == UDP_IO_UDP4_VERSION) { + gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, ImageHandle, Controller); + } else { + gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp6ProtocolGuid, ImageHandle, Controller); + } + +FREE_CHILD: + if (UdpVersion == UDP_IO_UDP4_VERSION) { + NetLibDestroyServiceChild ( + Controller, + ImageHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + UdpIo->UdpHandle + ); + } else { + NetLibDestroyServiceChild ( + Controller, + ImageHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + UdpIo->UdpHandle + ); + } + +FREE_MEM: + FreePool (UdpIo); + return NULL; +} + +/** + Cancel all the sent datagram that pass the selection criteria of ToCancel. + + If ToCancel is NULL, all the datagrams are cancelled. + If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT(). + + @param[in] UdpIo The UDP_IO to cancel packet. + @param[in] IoStatus The IoStatus to return to the packet owners. + @param[in] ToCancel The select function to test whether to cancel this + packet or not. + @param[in] Context The opaque parameter to the ToCancel. + +**/ +VOID +EFIAPI +UdpIoCancelDgrams ( + IN UDP_IO *UdpIo, + IN EFI_STATUS IoStatus, + IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL + IN VOID *Context OPTIONAL + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *Next; + UDP_TX_TOKEN *TxToken; + + ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); + + NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) { + TxToken = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link); + + if ((ToCancel == NULL) || (ToCancel (TxToken, Context))) { + + if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4); + } else { + UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6); + } + } + } +} + +/** + Free the UDP_IO and all its related resources. + + If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT(). + + The function will cancel all sent datagram and receive request. + + @param[in] UdpIo The UDP_IO to free. + + @retval EFI_SUCCESS The UDP_IO is freed. + @retval Others Failed to free UDP_IO. + +**/ +EFI_STATUS +EFIAPI +UdpIoFreeIo ( + IN UDP_IO *UdpIo + ) +{ + EFI_STATUS Status; + UDP_RX_TOKEN *RxToken; + + ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); + + // + // Cancel all the sent datagram and receive requests. The + // callbacks of transmit requests are executed to allow the + // caller to release the resource. The callback of receive + // request are NOT executed. This is because it is most + // likely that the current user of the UDP IO port is closing + // itself. + // + UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL); + + if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + + if ((RxToken = UdpIo->RecvRequest) != NULL) { + Status = UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Close then destroy the Udp4 child + // + Status = gBS->CloseProtocol ( + UdpIo->UdpHandle, + &gEfiUdp4ProtocolGuid, + UdpIo->Image, + UdpIo->Controller + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = NetLibDestroyServiceChild ( + UdpIo->Controller, + UdpIo->Image, + &gEfiUdp4ServiceBindingProtocolGuid, + UdpIo->UdpHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + } else { + + if ((RxToken = UdpIo->RecvRequest) != NULL) { + Status = UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Close then destroy the Udp6 child + // + Status = gBS->CloseProtocol ( + UdpIo->UdpHandle, + &gEfiUdp6ProtocolGuid, + UdpIo->Image, + UdpIo->Controller + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = NetLibDestroyServiceChild ( + UdpIo->Controller, + UdpIo->Image, + &gEfiUdp6ServiceBindingProtocolGuid, + UdpIo->UdpHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + if (!IsListEmpty(&UdpIo->Link)) { + RemoveEntryList (&UdpIo->Link); + } + + FreePool (UdpIo); + return EFI_SUCCESS; +} + + +/** + Clean up the UDP_IO without freeing it. The function is called when + user wants to re-use the UDP_IO later. + + If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT(). + + It will release all the transmitted datagrams and receive request. It will + also configure NULL for the UDP instance. + + @param[in] UdpIo The UDP_IO to clean up. + +**/ +VOID +EFIAPI +UdpIoCleanIo ( + IN UDP_IO *UdpIo + ) +{ + UDP_RX_TOKEN *RxToken; + + ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); + + // + // Cancel all the sent datagram and receive requests. + // + UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL); + + if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + if ((RxToken = UdpIo->RecvRequest) != NULL) { + UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4); + } + + UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, NULL); + + } else { + if ((RxToken = UdpIo->RecvRequest) != NULL) { + UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6); + } + + UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, NULL); + } +} + +/** + Send a packet through the UDP_IO. + + If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT(). + + The packet will be wrapped in UDP_TX_TOKEN. Function Callback will be called + when the packet is sent. The optional parameter EndPoint overrides the default + address pair if specified. + + @param[in] UdpIo The UDP_IO to send the packet through. + @param[in] Packet The packet to send. + @param[in] EndPoint The local and remote access point. Override the + default address pair set during configuration. + @param[in] Gateway The gateway to use. + @param[in] CallBack The function being called when packet is + transmitted or failed. + @param[in] Context The opaque parameter passed to CallBack. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet. + @retval EFI_SUCCESS The packet is successfully delivered to UDP for + transmission. + +**/ +EFI_STATUS +EFIAPI +UdpIoSendDatagram ( + IN UDP_IO *UdpIo, + IN NET_BUF *Packet, + IN UDP_END_POINT *EndPoint OPTIONAL, + IN EFI_IP_ADDRESS *Gateway OPTIONAL, + IN UDP_IO_CALLBACK CallBack, + IN VOID *Context + ) +{ + UDP_TX_TOKEN *TxToken; + EFI_STATUS Status; + + ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); + + TxToken = UdpIoCreateTxToken (UdpIo, Packet, EndPoint, Gateway, CallBack, Context); + + if (TxToken == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Insert the tx token into SendDatagram list before transmitting it. Remove + // it from the list if the returned status is not EFI_SUCCESS. + // + InsertHeadList (&UdpIo->SentDatagram, &TxToken->Link); + + if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + Status = UdpIo->Protocol.Udp4->Transmit (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4); + } else { + Status = UdpIo->Protocol.Udp6->Transmit (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6); + } + + if (EFI_ERROR (Status)) { + RemoveEntryList (&TxToken->Link); + UdpIoFreeTxToken (TxToken); + return Status; + } + + return EFI_SUCCESS; +} + + +/** + The select function to cancel a single sent datagram. + + @param[in] Token The UDP_TX_TOKEN to test against + @param[in] Context The NET_BUF of the sent datagram + + @retval TRUE The packet is to be cancelled. + @retval FALSE The packet is not to be cancelled. +**/ +BOOLEAN +EFIAPI +UdpIoCancelSingleDgram ( + IN UDP_TX_TOKEN *Token, + IN VOID *Context + ) +{ + NET_BUF *Packet; + + Packet = (NET_BUF *) Context; + + if (Token->Packet == Packet) { + return TRUE; + } + + return FALSE; +} + +/** + Cancel a single sent datagram. + + @param[in] UdpIo The UDP_IO to cancel the packet from + @param[in] Packet The packet to cancel + +**/ +VOID +EFIAPI +UdpIoCancelSentDatagram ( + IN UDP_IO *UdpIo, + IN NET_BUF *Packet + ) +{ + UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet); +} + +/** + Issue a receive request to the UDP_IO. + + If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT(). + + This function is called when upper-layer needs packet from UDP for processing. + Only one receive request is acceptable at a time so a common usage model is + to invoke this function inside its Callback function when the former packet + is processed. + + @param[in] UdpIo The UDP_IO to receive the packet from. + @param[in] CallBack The call back function to execute when the packet + is received. + @param[in] Context The opaque context passed to Callback. + @param[in] HeadLen The length of the upper-layer's protocol header. + + @retval EFI_ALREADY_STARTED There is already a pending receive request. Only + one receive request is supported at a time. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_SUCCESS The receive request is issued successfully. + @retval EFI_UNSUPPORTED The UDP version in UDP_IO is not supported. + +**/ +EFI_STATUS +EFIAPI +UdpIoRecvDatagram ( + IN UDP_IO *UdpIo, + IN UDP_IO_CALLBACK CallBack, + IN VOID *Context, + IN UINT32 HeadLen + ) +{ + UDP_RX_TOKEN *RxToken; + EFI_STATUS Status; + + ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); + + if (UdpIo->RecvRequest != NULL) { + return EFI_ALREADY_STARTED; + } + + RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen); + + if (RxToken == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + UdpIo->RecvRequest = RxToken; + if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + Status = UdpIo->Protocol.Udp4->Receive (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4); + } else { + Status = UdpIo->Protocol.Udp6->Receive (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6); + } + + if (EFI_ERROR (Status)) { + UdpIo->RecvRequest = NULL; + UdpIoFreeRxToken (RxToken); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf b/src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf new file mode 100644 index 00000000..97c53e24 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf @@ -0,0 +1,46 @@ +## @file +# This library instance provides UDP services by consuming EFI UDPv4/UDPv6 Protocols. +# +# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeUpdIoLib + MODULE_UNI_FILE = DxeUpdIoLib.uni + FILE_GUID = 7E615AA1-41EE-49d4-B7E9-1D7A60AA5C8D + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = UdpIoLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + DxeUdpIoLib.c + +[Packages] + MdePkg/MdePkg.dec + NetworkPkg/NetworkPkg.dec + + +[LibraryClasses] + BaseLib + DebugLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + DpcLib + +[Protocols] + gEfiUdp4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiUdp4ProtocolGuid ## SOMETIMES_CONSUMES + gEfiUdp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiUdp6ProtocolGuid ## SOMETIMES_CONSUMES + diff --git a/src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib/DxeUpdIoLib.uni b/src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib/DxeUpdIoLib.uni new file mode 100644 index 00000000..bc949059 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeUdpIoLib/DxeUpdIoLib.uni @@ -0,0 +1,16 @@ +// /** @file
+// This library instance provides UDP services by consuming EFI UDPv4/UDPv6 Protocols.
+//
+// This library instance provides UDP services by consuming EFI UDPv4/UDPv6 Protocols.
+//
+// Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides UDP services by consuming EFI UDPv4/UDPv6 Protocols"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library instance provides UDP services by consuming EFI UDPv4/UDPv6 Protocols."
+
|