X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FLibrary%2FDxeUdpIoLib%2FDxeUdpIoLib.c;h=a27f03aab91414c891918e777eb27bb0bf6f83aa;hp=84bc295bb14bc139a60853f2abfb8a92d62a63cf;hb=e798cd87ca9a3a30c4cea50c5f5de84e10a8bc5a;hpb=cbf316f20726bb31b7c37424601643790dbd02d9 diff --git a/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c b/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c index 84bc295bb1..a27f03aab9 100644 --- a/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c +++ b/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c @@ -1,174 +1,332 @@ /** @file + Help functions to access UDP service, it is used by both the DHCP and MTFTP. -Copyright (c) 2006 - 2007, Intel Corporation +Copyright (c) 2005 - 2009, Intel Corporation.
All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at +which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ +#include -Module Name: +#include +#include - Udp4Io.c +#include +#include +#include +#include +#include +#include +#include -Abstract: - Help functions to access UDP service, it is used by both the DHCP and MTFTP. +/** + 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 + ) +{ -#include + 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); + } -#include + FreePool (TxToken); +} -#include -#include -#include -#include -#include +/** + Free a UDP_RX_TOKEN. The RX event is closed. -STATIC + @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. -STATIC +**/ VOID EFIAPI -UdpIoOnDgramRcvd ( - IN EFI_EVENT Event, +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); +} /** - Wrap a transmit request into a UDP_TX_TOKEN. + The event handle for UDP receive request. - @param UdpIo The UdpIo port to send packet to - @param Packet The user's packet - @param EndPoint The local and remote access point - @param Gateway The overrided next hop - @param CallBack The function to call when transmission completed. - @param Context The opaque parameter to the call back + It will build a NET_BUF from the recieved UDP data, then deliver it + to the receiver. - @return The wrapped transmission request or NULL if failed to allocate resources. + @param[in] Context The UDP RX token. **/ -STATIC -UDP_TX_TOKEN * -UdpIoWrapTx ( - IN UDP_IO_PORT *UdpIo, - IN NET_BUF *Packet, - IN UDP_POINTS *EndPoint, OPTIONAL - IN IP4_ADDR Gateway, - IN UDP_IO_CALLBACK CallBack, +VOID +EFIAPI +UdpIoOnDgramRcvdDpc ( IN VOID *Context ) { - UDP_TX_TOKEN *Token; - EFI_UDP4_COMPLETION_TOKEN *UdpToken; - EFI_UDP4_TRANSMIT_DATA *UdpTxData; EFI_STATUS Status; - UINT32 Count; + VOID *Token; + VOID *RxData; + VOID *Session; + UDP_RX_TOKEN *RxToken; + UDP_END_POINT EndPoint; + NET_BUF *Netbuf; - Token = NetAllocatePool (sizeof (UDP_TX_TOKEN) + - sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1)); + RxToken = (UDP_RX_TOKEN *) Context; - if (Token == NULL) { - return NULL; - } + ZeroMem (&EndPoint, sizeof(UDP_END_POINT)); - Token->Signature = UDP_IO_TX_SIGNATURE; - NetListInit (&Token->Link); + ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) && + (RxToken == RxToken->UdpIo->RecvRequest)); - Token->UdpIo = UdpIo; - Token->CallBack = CallBack; - Token->Packet = Packet; - Token->Context = Context; + ASSERT ((RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); - UdpToken = &(Token->UdpToken); - UdpToken->Status = EFI_NOT_READY; + // + // 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; + } - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_CALLBACK, - UdpIoOnDgramSent, - Token, - &UdpToken->Event - ); + 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); + } - if (EFI_ERROR (Status)) { - NetFreePool (Token); - return NULL; + UdpIoFreeRxToken (RxToken); + return; } - UdpTxData = &Token->UdpTxData; - UdpToken->Packet.TxData = UdpTxData; + // + // Build a NET_BUF from the UDP receive data, then deliver it up. + // + if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + + 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; + } - UdpTxData->UdpSessionData = NULL; - UdpTxData->GatewayAddress = NULL; + 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 { + + 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; + } - if (EndPoint != NULL) { - EFI_IP4 (Token->UdpSession.SourceAddress) = HTONL (EndPoint->LocalAddr); - EFI_IP4 (Token->UdpSession.DestinationAddress) = HTONL (EndPoint->RemoteAddr); - Token->UdpSession.SourcePort = EndPoint->LocalPort; - Token->UdpSession.DestinationPort = EndPoint->RemotePort; - UdpTxData->UdpSessionData = &Token->UdpSession; - } + Session = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession; + EndPoint.LocalPort = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort; + EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort; - if (Gateway != 0) { - EFI_IP4 (Token->Gateway) = HTONL (Gateway); - UdpTxData->GatewayAddress = &Token->Gateway; - } + CopyMem ( + &EndPoint.LocalAddr, + &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress, + sizeof (EFI_IPv6_ADDRESS) + ); - UdpTxData->DataLength = Packet->TotalSize; - Count = Packet->BlockOpNum; - NetbufBuildExt (Packet, (NET_FRAGMENT *) UdpTxData->FragmentTable, &Count); - UdpTxData->FragmentCount = Count; + CopyMem ( + &EndPoint.RemoteAddr, + &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress, + sizeof (EFI_IPv6_ADDRESS) + ); - return Token; -} + Ip6Swap128 (&EndPoint.LocalAddr.v6); + Ip6Swap128 (&EndPoint.RemoteAddr.v6); + } + RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context); +} /** - Free a UDP_TX_TOKEN. The event is closed and memory released. - - @param Token The UDP_TX_TOKEN to release. + Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK. - @return None + @param[in] Event The UDP receive request event. + @param[in] Context The UDP RX token. **/ VOID -UdpIoFreeTxToken ( - IN UDP_TX_TOKEN *Token +EFIAPI +UdpIoOnDgramRcvd ( + IN EFI_EVENT Event, + IN VOID *Context ) { - gBS->CloseEvent (Token->UdpToken.Event); - NetFreePool (Token); + // + // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK + // + QueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context); } - /** Create a UDP_RX_TOKEN to wrap the request. - @param UdpIo The UdpIo to receive packets from - @param CallBack The function to call when receive finished. - @param Context The opaque parameter to the CallBack - @param HeadLen The head length to reserver for the packet. + @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 reserver for the packet. - @return The Wrapped request or NULL if failed to allocate resources. + @return The Wrapped request or NULL if failed to allocate resources or some errors happened. **/ UDP_RX_TOKEN * UdpIoCreateRxToken ( - IN UDP_IO_PORT *UdpIo, + IN UDP_IO *UdpIo, IN UDP_IO_CALLBACK CallBack, IN VOID *Context, IN UINT32 HeadLen @@ -177,7 +335,10 @@ UdpIoCreateRxToken ( UDP_RX_TOKEN *Token; EFI_STATUS Status; - Token = NetAllocatePool (sizeof (UDP_RX_TOKEN)); + ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); + + Token = AllocatePool (sizeof (UDP_RX_TOKEN)); if (Token == NULL) { return NULL; @@ -189,197 +350,442 @@ UdpIoCreateRxToken ( Token->Context = Context; Token->HeadLen = HeadLen; - Token->UdpToken.Status = EFI_NOT_READY; - Token->UdpToken.Packet.RxData = NULL; + 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 + ); + } - Status = gBS->CreateEvent ( - EVT_NOTIFY_SIGNAL, - TPL_CALLBACK, - UdpIoOnDgramRcvd, - Token, - &Token->UdpToken.Event - ); if (EFI_ERROR (Status)) { - NetFreePool (Token); + FreePool (Token); return NULL; } return Token; } - /** - Free a receive request wrap. + Wrap a transmit request into a new created UDP_TX_TOKEN. - @param Token The receive request to release. + @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 overrided next hop. + @param[in] CallBack The function to call when transmission completed. + @param[in] Context The opaque parameter to the call back. - @return None + @return The wrapped transmission request or NULL if failed to allocate resources + or for some errors. **/ -VOID -UdpIoFreeRxToken ( - IN UDP_RX_TOKEN *Token +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 ) { - gBS->CloseEvent (Token->UdpToken.Event); - NetFreePool (Token); -} + 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; +} /** - Create a UDP IO port to access the UDP service. It will - create and configure a UDP child. + Creates a UDP_IO to access the UDP service. It creates and configures + a UDP child. + + 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 Controller The controller that has the UDP service binding - protocol installed. - @param Image The image handle for the driver. - @param Configure The function to configure the created UDP child - @param Context The opaque parameter for the Configure funtion. + @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 funtion. - @return A point to just created UDP IO port or NULL if failed. + @return Newly-created UDP_IO or NULL if failed. **/ -UDP_IO_PORT * -UdpIoCreatePort ( +UDP_IO * +EFIAPI +UdpIoCreateIo ( IN EFI_HANDLE Controller, - IN EFI_HANDLE Image, + IN EFI_HANDLE ImageHandle, IN UDP_IO_CONFIG Configure, + IN UINT8 UdpVersion, IN VOID *Context ) { - UDP_IO_PORT *UdpIo; + UDP_IO *UdpIo; EFI_STATUS Status; ASSERT (Configure != NULL); + ASSERT ((UdpVersion == UDP_IO_UDP4_VERSION) || (UdpVersion == UDP_IO_UDP6_VERSION)); - UdpIo = NetAllocatePool (sizeof (UDP_IO_PORT)); + UdpIo = AllocatePool (sizeof (UDP_IO)); if (UdpIo == NULL) { return NULL; } + UdpIo->UdpVersion = UdpVersion; UdpIo->Signature = UDP_IO_SIGNATURE; - NetListInit (&UdpIo->Link); + InitializeListHead (&UdpIo->Link); UdpIo->RefCnt = 1; UdpIo->Controller = Controller; - UdpIo->Image = Image; + UdpIo->Image = ImageHandle; - NetListInit (&UdpIo->SentDatagram); + InitializeListHead (&UdpIo->SentDatagram); UdpIo->RecvRequest = NULL; UdpIo->UdpHandle = NULL; - // - // Create a UDP child then open and configure it - // - Status = NetLibCreateServiceChild ( - Controller, - Image, - &gEfiUdp4ServiceBindingProtocolGuid, - &UdpIo->UdpHandle - ); + 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; + } - 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; + } - Status = gBS->OpenProtocol ( - UdpIo->UdpHandle, - &gEfiUdp4ProtocolGuid, - &UdpIo->Udp, - Image, - Controller, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); + if (EFI_ERROR (Configure (UdpIo, Context))) { + goto CLOSE_PROTOCOL; + } - if (EFI_ERROR (Status)) { - goto FREE_CHILD; - } + Status = UdpIo->Protocol.Udp4->GetModeData ( + UdpIo->Protocol.Udp4, + NULL, + NULL, + NULL, + &UdpIo->SnpMode + ); - if (EFI_ERROR (Configure (UdpIo, Context))) { - goto CLOSE_PROTOCOL; - } + if (EFI_ERROR (Status)) { + goto CLOSE_PROTOCOL; + } - Status = UdpIo->Udp->GetModeData (UdpIo->Udp, NULL, NULL, NULL, &UdpIo->SnpMode); + } else { - if (EFI_ERROR (Status)) { - goto CLOSE_PROTOCOL; + 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: - gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, Image, Controller); + if (UdpVersion == UDP_IO_UDP4_VERSION) { + gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, ImageHandle, Controller); + } else { + gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp6ProtocolGuid, ImageHandle, Controller); + } FREE_CHILD: - NetLibDestroyServiceChild ( - Controller, - Image, - &gEfiUdp4ServiceBindingProtocolGuid, - UdpIo->UdpHandle - ); + if (UdpVersion == UDP_IO_UDP4_VERSION) { + NetLibDestroyServiceChild ( + Controller, + ImageHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + UdpIo->UdpHandle + ); + } else { + NetLibDestroyServiceChild ( + Controller, + ImageHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + UdpIo->UdpHandle + ); + } FREE_MEM: - NetFreePool (UdpIo); + FreePool (UdpIo); return NULL; } - /** - Cancel all the sent datagram that pass the selection of ToCancel. + Cancel all the sent datagram that pass the selection criteria of ToCancel. If ToCancel is NULL, all the datagrams are cancelled. - @param UdpIo The UDP IO port to cancel packet - @param IoStatus The IoStatus to return to the packet owners. - @param ToCancel The select funtion to test whether to cancel this - packet or not. - @param Context The opaque parameter to the ToCancel. - - @return None + @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 funtion to test whether to cancel this + packet or not. + @param[in] Context The opaque parameter to the ToCancel. **/ -STATIC VOID +EFIAPI UdpIoCancelDgrams ( - IN UDP_IO_PORT *UdpIo, + IN UDP_IO *UdpIo, IN EFI_STATUS IoStatus, IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL IN VOID *Context ) { - NET_LIST_ENTRY *Entry; - NET_LIST_ENTRY *Next; - UDP_TX_TOKEN *Token; + 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) { - Token = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link); + TxToken = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link); - if ((ToCancel == NULL) || (ToCancel (Token, Context))) { - NetListRemoveEntry (Entry); - UdpIo->Udp->Cancel (UdpIo->Udp, &Token->UdpToken); - Token->CallBack (Token->Packet, NULL, IoStatus, Token->Context); - UdpIoFreeTxToken (Token); + 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 port and all its related resources including - all the transmitted packet. + Free the UDP_IO and all its related resources. - @param UdpIo The UDP IO port to free. + The function will cancel all sent datagram and receive request. - @retval EFI_SUCCESS The UDP IO port is freed. + @param[in] UdpIo The UDP_IO to free. + + @retval EFI_SUCCESS The UDP_IO is freed. **/ EFI_STATUS -UdpIoFreePort ( - IN UDP_IO_PORT *UdpIo +EFIAPI +UdpIoFreeIo ( + IN UDP_IO *UdpIo ) { - UDP_RX_TOKEN *RxToken; + 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 @@ -391,156 +797,181 @@ UdpIoFreePort ( // UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL); - if ((RxToken = UdpIo->RecvRequest) != NULL) { - UdpIo->RecvRequest = NULL; - UdpIo->Udp->Cancel (UdpIo->Udp, &RxToken->UdpToken); - UdpIoFreeRxToken (RxToken); + if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + + if ((RxToken = UdpIo->RecvRequest) != NULL) { + UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4); + } + + // + // Close then destory the Udp4 child + // + gBS->CloseProtocol ( + UdpIo->UdpHandle, + &gEfiUdp4ProtocolGuid, + UdpIo->Image, + UdpIo->Controller + ); + + NetLibDestroyServiceChild ( + UdpIo->Controller, + UdpIo->Image, + &gEfiUdp4ServiceBindingProtocolGuid, + UdpIo->UdpHandle + ); + + } else { + + if ((RxToken = UdpIo->RecvRequest) != NULL) { + UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6); + } + + // + // Close then destory the Udp6 child + // + gBS->CloseProtocol ( + UdpIo->UdpHandle, + &gEfiUdp6ProtocolGuid, + UdpIo->Image, + UdpIo->Controller + ); + + NetLibDestroyServiceChild ( + UdpIo->Controller, + UdpIo->Image, + &gEfiUdp6ServiceBindingProtocolGuid, + UdpIo->UdpHandle + ); + } + + if (!IsListEmpty(&UdpIo->Link)) { + RemoveEntryList (&UdpIo->Link); } - // - // Close then destory the UDP child - // - gBS->CloseProtocol ( - UdpIo->UdpHandle, - &gEfiUdp4ProtocolGuid, - UdpIo->Image, - UdpIo->Controller - ); - - NetLibDestroyServiceChild ( - UdpIo->Controller, - UdpIo->Image, - &gEfiUdp4ServiceBindingProtocolGuid, - UdpIo->UdpHandle - ); - - NetListRemoveEntry (&UdpIo->Link); - NetFreePool (UdpIo); + FreePool (UdpIo); return EFI_SUCCESS; } /** - Clean up the UDP IO port. It will release all the transmitted - datagrams and receive request. It will also configure NULL the - UDP child. + Clean up the UDP_IO without freeing it. The function is called when + user wants to re-use the UDP_IO later. - @param UdpIo UDP IO port to clean up. + It will release all the transmitted datagrams and receive request. It will + also configure NULL for the UDP instance. - @return None + @param[in] UdpIo The UDP_IO to clean up. **/ VOID -UdpIoCleanPort ( - IN UDP_IO_PORT *UdpIo +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 ((RxToken = UdpIo->RecvRequest) != NULL) { - UdpIo->RecvRequest = NULL; - UdpIo->Udp->Cancel (UdpIo->Udp, &RxToken->UdpToken); - UdpIoFreeRxToken (RxToken); - } - - UdpIo->Udp->Configure (UdpIo->Udp, NULL); -} - - -/** - 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. - - @param Event The event signalled. - @param Context The UDP TX Token. - - @return None - -**/ -STATIC -VOID -EFIAPI -UdpIoOnDgramSent ( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - UDP_TX_TOKEN *Token; + if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) { + if ((RxToken = UdpIo->RecvRequest) != NULL) { + UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4); + } - Token = (UDP_TX_TOKEN *) Context; - ASSERT (Token->Signature == UDP_IO_TX_SIGNATURE); + UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, NULL); - NetListRemoveEntry (&Token->Link); - Token->CallBack (Token->Packet, NULL, Token->UdpToken.Status, Token->Context); + } else { + if ((RxToken = UdpIo->RecvRequest) != NULL) { + UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6); + } - UdpIoFreeTxToken (Token); + UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, NULL); + } } - /** - Send a packet through the UDP IO port. - - @param UdpIo The UDP IO Port to send the packet through - @param Packet The packet to send - @param EndPoint The local and remote access point - @param Gateway The gateway to use - @param CallBack The call back function to call when packet is - transmitted or failed. - @param Context The opque parameter to the CallBack - - @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet + Send a packet through the UDP_IO. + + 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_PORT *UdpIo, + IN UDP_IO *UdpIo, IN NET_BUF *Packet, - IN UDP_POINTS *EndPoint, OPTIONAL - IN IP4_ADDR Gateway, + IN UDP_END_POINT *EndPoint OPTIONAL, + IN EFI_IP_ADDRESS *Gateway OPTIONAL, IN UDP_IO_CALLBACK CallBack, IN VOID *Context ) { - UDP_TX_TOKEN *Token; + UDP_TX_TOKEN *TxToken; EFI_STATUS Status; - Token = UdpIoWrapTx (UdpIo, Packet, EndPoint, Gateway, CallBack, Context); + ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) || + (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION)); - if (Token == NULL) { + TxToken = UdpIoCreateTxToken (UdpIo, Packet, EndPoint, Gateway, CallBack, Context); + + if (TxToken == NULL) { return EFI_OUT_OF_RESOURCES; } - Status = UdpIo->Udp->Transmit (UdpIo->Udp, &Token->UdpToken); + // + // 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)) { - UdpIoFreeTxToken (Token); + RemoveEntryList (&TxToken->Link); + UdpIoFreeTxToken (TxToken); return Status; } - NetListInsertHead (&UdpIo->SentDatagram, &Token->Link); return EFI_SUCCESS; } /** - The selection function to cancel a single sent datagram. + The select function to cancel a single sent datagram. - @param Token The UDP TX token to test againist. - @param Context The context - - @return TRUE if the packet is to be cancelled, otherwise FALSE. + @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. **/ -STATIC BOOLEAN +EFIAPI UdpIoCancelSingleDgram ( IN UDP_TX_TOKEN *Token, IN VOID *Context @@ -557,171 +988,80 @@ UdpIoCancelSingleDgram ( return FALSE; } - /** Cancel a single sent datagram. - @param UdpIo The UDP IO port to cancel the packet from - @param Packet The packet to cancel - - @return None + @param[in] UdpIo The UDP_IO to cancel the packet from + @param[in] Packet The packet to cancel **/ VOID +EFIAPI UdpIoCancelSentDatagram ( - IN UDP_IO_PORT *UdpIo, + IN UDP_IO *UdpIo, IN NET_BUF *Packet ) { UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet); } - -/** - Recycle the received UDP data. - - @param Context The UDP_RX_TOKEN - - @return None - -**/ -STATIC -VOID -UdpIoRecycleDgram ( - IN VOID *Context - ) -{ - UDP_RX_TOKEN *Token; - - Token = (UDP_RX_TOKEN *) Context; - gBS->SignalEvent (Token->UdpToken.Packet.RxData->RecycleSignal); - UdpIoFreeRxToken (Token); -} - - /** - The event handle for UDP receive request. It will build - a NET_BUF from the recieved UDP data, then deliver it - to the receiver. - - @param Event The UDP receive request event - @param Context The UDP RX token. - - @return None - -**/ -STATIC -VOID -EFIAPI -UdpIoOnDgramRcvd ( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - EFI_UDP4_COMPLETION_TOKEN *UdpToken; - EFI_UDP4_RECEIVE_DATA *UdpRxData; - EFI_UDP4_SESSION_DATA *UdpSession; - UDP_RX_TOKEN *Token; - UDP_POINTS Points; - NET_BUF *Netbuf; - - Token = (UDP_RX_TOKEN *) Context; - - ASSERT ((Token->Signature == UDP_IO_RX_SIGNATURE) && - (Token == Token->UdpIo->RecvRequest)); - - // - // Clear the receive request first in case that the caller - // wants to restart the receive in the callback. - // - Token->UdpIo->RecvRequest = NULL; - - UdpToken = &Token->UdpToken; - UdpRxData = UdpToken->Packet.RxData; - - if (EFI_ERROR (UdpToken->Status) || (UdpRxData == NULL)) { - Token->CallBack (NULL, NULL, UdpToken->Status, Token->Context); - UdpIoFreeRxToken (Token); - - goto ON_EXIT; - } - - // - // Build a NET_BUF from the UDP receive data, then deliver it up. - // - Netbuf = NetbufFromExt ( - (NET_FRAGMENT *) UdpRxData->FragmentTable, - UdpRxData->FragmentCount, - 0, - (UINT32) Token->HeadLen, - UdpIoRecycleDgram, - Token - ); - - if (Netbuf == NULL) { - gBS->SignalEvent (UdpRxData->RecycleSignal); - Token->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, Token->Context); - - UdpIoFreeRxToken (Token); - goto ON_EXIT; - } - - UdpSession = &UdpRxData->UdpSession; - Points.LocalAddr = EFI_NTOHL (UdpSession->DestinationAddress); - Points.LocalPort = UdpSession->DestinationPort; - Points.RemoteAddr = EFI_NTOHL (UdpSession->SourceAddress); - Points.RemotePort = UdpSession->SourcePort; - - Token->CallBack (Netbuf, &Points, EFI_SUCCESS, Token->Context); - -ON_EXIT: - return; -} + Issue a receive request to the UDP_IO. + 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. -/** - Issue a receive request to the UDP IO port. - - @param UdpIo The UDP IO port to recieve the packet from. - @param CallBack The call back function to execute when receive - finished. - @param Context The opque context to the call back - @param HeadLen The lenght of the application's header + @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. - @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource. + 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_PORT *UdpIo, + IN UDP_IO *UdpIo, IN UDP_IO_CALLBACK CallBack, IN VOID *Context, IN UINT32 HeadLen ) { - UDP_RX_TOKEN *Token; + 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; } - Token = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen); + RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen); - if (Token == NULL) { + if (RxToken == NULL) { return EFI_OUT_OF_RESOURCES; } - Status = UdpIo->Udp->Receive (UdpIo->Udp, &Token->UdpToken); + 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)) { - UdpIoFreeRxToken (Token); - return Status; + UdpIo->RecvRequest = NULL; + UdpIoFreeRxToken (RxToken); } - UdpIo->RecvRequest = Token; - return EFI_SUCCESS; + return Status; }