summaryrefslogtreecommitdiffstats
path: root/NetworkPkg/Udp6Dxe/Udp6Main.c
diff options
context:
space:
mode:
Diffstat (limited to 'NetworkPkg/Udp6Dxe/Udp6Main.c')
-rw-r--r--NetworkPkg/Udp6Dxe/Udp6Main.c855
1 files changed, 855 insertions, 0 deletions
diff --git a/NetworkPkg/Udp6Dxe/Udp6Main.c b/NetworkPkg/Udp6Dxe/Udp6Main.c
new file mode 100644
index 0000000000..0cad596276
--- /dev/null
+++ b/NetworkPkg/Udp6Dxe/Udp6Main.c
@@ -0,0 +1,855 @@
+/** @file
+ Contains all EFI_UDP6_PROTOCOL interfaces.
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ 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
+ 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 "Udp6Impl.h"
+
+EFI_UDP6_PROTOCOL mUdp6Protocol = {
+ Udp6GetModeData,
+ Udp6Configure,
+ Udp6Groups,
+ Udp6Transmit,
+ Udp6Receive,
+ Udp6Cancel,
+ Udp6Poll
+};
+
+
+/**
+ This function copies the current operational settings of this EFI UDPv6 Protocol
+ instance into user-supplied buffers. This function is used optionally to retrieve
+ the operational mode data of underlying networks or drivers.
+
+ @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance.
+ @param[out] Udp6ConfigData The buffer in which the current UDP configuration
+ data is returned. This parameter is optional and
+ may be NULL.
+ @param[out] Ip6ModeData The buffer in which the current EFI IPv6 Protocol
+ mode data is returned. This parameter is optional
+ and may be NULL.
+ @param[out] MnpConfigData The buffer in which the current managed network
+ configuration data is returned. This parameter is
+ optional and may be NULL.
+ @param[out] SnpModeData The buffer in which the simple network mode data
+ is returned. This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS The mode data was read.
+ @retval EFI_NOT_STARTED When Udp6ConfigData is queried, no configuration
+ data is available because this instance has not
+ been started.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+Udp6GetModeData (
+ IN EFI_UDP6_PROTOCOL *This,
+ OUT EFI_UDP6_CONFIG_DATA *Udp6ConfigData OPTIONAL,
+ OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL,
+ OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
+ OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
+ )
+{
+ UDP6_INSTANCE_DATA *Instance;
+ EFI_IP6_PROTOCOL *Ip;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured && (Udp6ConfigData != NULL)) {
+ return EFI_NOT_STARTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (Udp6ConfigData != NULL) {
+ //
+ // Set the Udp6ConfigData.
+ //
+ CopyMem (Udp6ConfigData, &Instance->ConfigData, sizeof (EFI_UDP6_CONFIG_DATA));
+ }
+
+ Ip = Instance->IpInfo->Ip.Ip6;
+
+ //
+ // Get the underlying Ip6ModeData, MnpConfigData and SnpModeData.
+ //
+ Status = Ip->GetModeData (Ip, Ip6ModeData, MnpConfigData, SnpModeData);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function is used to do the following:
+ Initialize and start this instance of the EFI UDPv6 Protocol.
+ Change the filtering rules and operational parameters.
+ Reset this instance of the EFI UDPv6 Protocol.
+
+ @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance.
+ @param[in] UdpConfigData Pointer to the buffer to set the configuration
+ data. This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS The configuration settings were set, changed, or
+ reset successfully.
+ @retval EFI_NO_MAPPING When the UdpConifgData.UseAnyStationAddress is set
+ to true and there is no address available for the IP6
+ driver to bind a source address to this instance.
+ @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE:
+ This is NULL.
+ UdpConfigData.StationAddress is not a valid
+ unicast IPv6 address.
+ UdpConfigData.RemoteAddress is not a valid unicast
+ IPv6 address if it is not zero.
+ @retval EFI_ALREADY_STARTED The EFI UDPv6 Protocol instance is already
+ started/configured and must be stopped/reset
+ before it can be reconfigured. Only TrafficClass,
+ HopLimit, ReceiveTimeout, and TransmitTimeout can
+ be reconfigured without stopping the current
+ instance of the EFI UDPv6 Protocol.
+ @retval EFI_ACCESS_DENIED UdpConfigData.AllowDuplicatePort is FALSE and
+ UdpConfigData.StationPort is already used by another
+ instance.
+ @retval EFI_OUT_OF_RESOURCES The EFI UDPv6 Protocol driver cannot allocate
+ memory for this EFI UDPv6 Protocol instance.
+ @retval EFI_DEVICE_ERROR An unexpected network or system error occurred, and
+ this instance was not opened.
+
+**/
+EFI_STATUS
+EFIAPI
+Udp6Configure (
+ IN EFI_UDP6_PROTOCOL *This,
+ IN EFI_UDP6_CONFIG_DATA *UdpConfigData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UDP6_INSTANCE_DATA *Instance;
+ UDP6_SERVICE_DATA *Udp6Service;
+ EFI_TPL OldTpl;
+ EFI_IPv6_ADDRESS StationAddress;
+ EFI_IPv6_ADDRESS RemoteAddress;
+ EFI_IP6_CONFIG_DATA Ip6ConfigData;
+ EFI_IPv6_ADDRESS LocalAddr;
+ EFI_IPv6_ADDRESS RemoteAddr;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured && (UdpConfigData == NULL)) {
+ return EFI_SUCCESS;
+ }
+
+ Udp6Service = Instance->Udp6Service;
+ Status = EFI_SUCCESS;
+ ASSERT (Udp6Service != NULL);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (UdpConfigData != NULL) {
+
+ IP6_COPY_ADDRESS (&StationAddress, &UdpConfigData->StationAddress);
+ IP6_COPY_ADDRESS (&RemoteAddress, &UdpConfigData->RemoteAddress);
+
+ if ((!NetIp6IsUnspecifiedAddr (&StationAddress) && !NetIp6IsValidUnicast (&StationAddress)) ||
+ (!NetIp6IsUnspecifiedAddr (&RemoteAddress) && !NetIp6IsValidUnicast (&RemoteAddress))
+ ){
+ //
+ // If not use default address, and StationAddress is not a valid unicast
+ // if it is not IPv6 address or RemoteAddress is not a valid unicast IPv6
+ // address if it is not 0.
+ //
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (Instance->Configured) {
+ //
+ // The instance is already configured, try to do the re-configuration.
+ //
+ if (!Udp6IsReconfigurable (&Instance->ConfigData, UdpConfigData)) {
+ //
+ // If the new configuration data wants to change some unreconfigurable
+ // settings, return EFI_ALREADY_STARTED.
+ //
+ Status = EFI_ALREADY_STARTED;
+ goto ON_EXIT;
+ }
+
+ //
+ // Save the reconfigurable parameters.
+ //
+ Instance->ConfigData.TrafficClass = UdpConfigData->TrafficClass;
+ Instance->ConfigData.HopLimit = UdpConfigData->HopLimit;
+ Instance->ConfigData.ReceiveTimeout = UdpConfigData->ReceiveTimeout;
+ Instance->ConfigData.TransmitTimeout = UdpConfigData->TransmitTimeout;
+ } else {
+ //
+ // Construct the Ip configuration data from the UdpConfigData.
+ //
+ Udp6BuildIp6ConfigData (UdpConfigData, &Ip6ConfigData);
+
+ //
+ // Configure the Ip instance wrapped in the IpInfo.
+ //
+ Status = IpIoConfigIp (Instance->IpInfo, &Ip6ConfigData);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NO_MAPPING) {
+ Instance->IsNoMapping = TRUE;
+ }
+
+ goto ON_EXIT;
+ }
+
+ Instance->IsNoMapping = FALSE;
+
+ //
+ // Save the configuration data.
+ //
+ CopyMem (
+ &Instance->ConfigData,
+ UdpConfigData,
+ sizeof (EFI_UDP6_CONFIG_DATA)
+ );
+ IP6_COPY_ADDRESS (&Instance->ConfigData.StationAddress, &Ip6ConfigData.StationAddress);
+ //
+ // Try to allocate the required port resource.
+ //
+ Status = Udp6Bind (&Udp6Service->ChildrenList, &Instance->ConfigData);
+ if (EFI_ERROR (Status)) {
+ //
+ // Reset the ip instance if bind fails.
+ //
+ IpIoConfigIp (Instance->IpInfo, NULL);
+ goto ON_EXIT;
+ }
+
+ //
+ // Pre calculate the checksum for the pseudo head, ignore the UDP length first.
+ //
+ IP6_COPY_ADDRESS (&LocalAddr, &Instance->ConfigData.StationAddress);
+ IP6_COPY_ADDRESS (&RemoteAddr, &Instance->ConfigData.RemoteAddress);
+
+ Instance->HeadSum = NetIp6PseudoHeadChecksum (
+ &LocalAddr,
+ &RemoteAddr,
+ EFI_IP_PROTO_UDP,
+ 0
+ );
+
+ Instance->Configured = TRUE;
+ }
+ } else {
+ //
+ // UdpConfigData is NULL, reset the instance.
+ //
+ Instance->Configured = FALSE;
+ Instance->IsNoMapping = FALSE;
+
+ //
+ // Reset the Ip instance wrapped in the IpInfo.
+ //
+ IpIoConfigIp (Instance->IpInfo, NULL);
+
+ //
+ // Cancel all the user tokens.
+ //
+ Status = Instance->Udp6Proto.Cancel (&Instance->Udp6Proto, NULL);
+
+ //
+ // Remove the buffered RxData for this instance.
+ //
+ Udp6FlushRcvdDgram (Instance);
+
+ ASSERT (IsListEmpty (&Instance->DeliveredDgramQue));
+ }
+
+ Status = Udp6SetVariableData (Instance->Udp6Service);
+
+ON_EXIT:
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function is used to enable and disable the multicast group filtering.
+
+ @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance.
+ @param[in] JoinFlag Set to TRUE to join a multicast group. Set to
+ FALSE to leave one or all multicast groups.
+ @param[in] MulticastAddress Pointer to multicast group address to join or
+ leave. This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_NOT_STARTED The EFI UDPv6 Protocol instance has not been
+ started.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate resources to join the group.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL.
+ JoinFlag is TRUE and MulticastAddress is NULL.
+ JoinFlag is TRUE and *MulticastAddress is not a
+ valid multicast address.
+ @retval EFI_ALREADY_STARTED The group address is already in the group table
+ (when JoinFlag is TRUE).
+ @retval EFI_NOT_FOUND The group address is not in the group table (when
+ JoinFlag is FALSE).
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+Udp6Groups (
+ IN EFI_UDP6_PROTOCOL *This,
+ IN BOOLEAN JoinFlag,
+ IN EFI_IPv6_ADDRESS *MulticastAddress OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UDP6_INSTANCE_DATA *Instance;
+ EFI_IP6_PROTOCOL *Ip;
+ EFI_TPL OldTpl;
+ EFI_IPv6_ADDRESS *McastIp;
+
+ if ((This == NULL) || (JoinFlag && (MulticastAddress == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ McastIp = NULL;
+
+ if (JoinFlag) {
+ if (!IP6_IS_MULTICAST (MulticastAddress)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ McastIp = AllocateCopyPool (sizeof (EFI_IPv6_ADDRESS), MulticastAddress);
+ if (McastIp == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
+ if (!Instance->Configured) {
+ return EFI_NOT_STARTED;
+ }
+
+ Ip = Instance->IpInfo->Ip.Ip6;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Invoke the Ip instance the Udp6 instance consumes to do the group operation.
+ //
+ Status = Ip->Groups (Ip, JoinFlag, MulticastAddress);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Keep a local copy of the configured multicast IPs because IpIo receives
+ // datagrams from the 0 station address IP instance and then UDP delivers to
+ // the matched instance. This copy of multicast IPs is used to avoid receive
+ // the mutlicast datagrams destinated to multicast IPs the other instances configured.
+ //
+ if (JoinFlag) {
+
+ Status = NetMapInsertTail (&Instance->McastIps, (VOID *) McastIp, NULL);
+ } else {
+
+ NetMapIterate (&Instance->McastIps, Udp6LeaveGroup, MulticastAddress);
+ }
+
+ON_EXIT:
+
+ gBS->RestoreTPL (OldTpl);
+
+ if (EFI_ERROR (Status)) {
+ if (McastIp != NULL) {
+ FreePool (McastIp);
+ }
+ }
+
+ return Status;
+}
+
+
+
+/**
+ This function places a sending request to this instance of the EFI UDPv6 Protocol,
+ alongside the transmit data that was filled by the user.
+
+ @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance.
+ @param[in] Token Pointer to the completion token that will be
+ placed into the transmit queue.
+
+ @retval EFI_SUCCESS The data was queued for transmission.
+ @retval EFI_NOT_STARTED This EFI UDPv6 Protocol instance has not been
+ started.
+ @retval EFI_NO_MAPPING The under-layer IPv6 driver was responsible for
+ choosing a source address for this instance, but
+ no source address was available for use.
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
+ This is NULL.
+ Token is NULL. Token.Event is NULL.
+ Token.Packet.TxData is NULL.
+ Token.Packet.TxData.FragmentCount is zero.
+ Token.Packet.TxData.DataLength is not equal to the
+ sum of fragment lengths.
+ One or more of the
+ Token.Packet.TxData.FragmentTable[].FragmentLength
+ fields is zero.
+ One or more of the
+ Token.Packet.TxData.FragmentTable[].FragmentBuffer
+ fields is NULL. One or more of the
+ Token.Packet.TxData.UdpSessionData.DestinationAddres
+ are not valid unicast IPv6
+ addresses if the UdpSessionData is not NULL.
+ Token.Packet.TxData.UdpSessionData.
+ DestinationAddress is NULL
+ Token.Packet.TxData.UdpSessionData.
+ DestinatioPort
+ is zero.
+ Token.Packet.TxData.UdpSessionData is NULL and this
+ instance's UdpConfigData.RemoteAddress is unspecified.
+ @retval EFI_ACCESS_DENIED The transmit completion token with the same
+ Token.Event is already in the transmit queue.
+ @retval EFI_NOT_READY The completion token could not be queued because
+ the transmit queue is full.
+ @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.
+ @retval EFI_NOT_FOUND There is no route to the destination network or
+ address.
+ @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP
+ packet size. Or, the length of the IP header + UDP
+ header + data length is greater than MTU if
+ DoNotFragment is TRUE.
+
+**/
+EFI_STATUS
+EFIAPI
+Udp6Transmit (
+ IN EFI_UDP6_PROTOCOL *This,
+ IN EFI_UDP6_COMPLETION_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ UDP6_INSTANCE_DATA *Instance;
+ EFI_TPL OldTpl;
+ NET_BUF *Packet;
+ EFI_UDP_HEADER *Udp6Header;
+ EFI_UDP6_CONFIG_DATA *ConfigData;
+ EFI_IPv6_ADDRESS Source;
+ EFI_IPv6_ADDRESS Destination;
+ EFI_UDP6_TRANSMIT_DATA *TxData;
+ EFI_UDP6_SESSION_DATA *UdpSessionData;
+ UDP6_SERVICE_DATA *Udp6Service;
+ IP_IO_OVERRIDE Override;
+ UINT16 HeadSum;
+ EFI_IP_ADDRESS IpDestAddr;
+
+ if ((This == NULL) || (Token == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured) {
+ return EFI_NOT_STARTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Validate the Token, if the token is invalid return the error code.
+ //
+ Status = Udp6ValidateTxToken (Instance, Token);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ if (EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp6TokenExist, Token)) ||
+ EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp6TokenExist, Token))
+ ){
+ //
+ // Try to find a duplicate token in the two token maps, if found, return
+ // EFI_ACCESS_DENIED.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto ON_EXIT;
+ }
+
+ TxData = Token->Packet.TxData;
+
+ //
+ // Create a net buffer to hold the user buffer and the udp header.
+ //
+ Packet = NetbufFromExt (
+ (NET_FRAGMENT *) TxData->FragmentTable,
+ TxData->FragmentCount,
+ UDP6_HEADER_SIZE,
+ 0,
+ Udp6NetVectorExtFree,
+ NULL
+ );
+ if (Packet == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Store the IpIo in ProtoData.
+ //
+ Udp6Service = Instance->Udp6Service;
+ *((UINTN *) &Packet->ProtoData[0]) = (UINTN) (Udp6Service->IpIo);
+
+ Udp6Header = (EFI_UDP_HEADER *) NetbufAllocSpace (Packet, UDP6_HEADER_SIZE, TRUE);
+ ASSERT (Udp6Header != NULL);
+ ConfigData = &Instance->ConfigData;
+
+ //
+ // Fill the udp header.
+ //
+ Udp6Header->SrcPort = HTONS (ConfigData->StationPort);
+ Udp6Header->DstPort = HTONS (ConfigData->RemotePort);
+ Udp6Header->Length = HTONS ((UINT16) Packet->TotalSize);
+ Udp6Header->Checksum = 0;
+ //
+ // Set the UDP Header in NET_BUF, this UDP header is for IP6 can fast get the
+ // Udp header for pseudoHeadCheckSum.
+ //
+ Packet->Udp = Udp6Header;
+ UdpSessionData = TxData->UdpSessionData;
+
+ if (UdpSessionData != NULL) {
+ //
+ // Set the Destination according to the specified
+ // UdpSessionData.
+ //
+
+ if (UdpSessionData->DestinationPort != 0) {
+ Udp6Header->DstPort = HTONS (UdpSessionData->DestinationPort);
+ }
+
+ IP6_COPY_ADDRESS (&Source, &ConfigData->StationAddress);
+ if (!NetIp6IsUnspecifiedAddr (&UdpSessionData->DestinationAddress)) {
+ IP6_COPY_ADDRESS (&Destination, &UdpSessionData->DestinationAddress);
+ } else {
+ IP6_COPY_ADDRESS (&Destination, &ConfigData->RemoteAddress);
+ }
+
+ //
+ //Calculate the pseudo head checksum using the overridden parameters.
+ //
+ if (!NetIp6IsUnspecifiedAddr (&ConfigData->StationAddress)) {
+ HeadSum = NetIp6PseudoHeadChecksum (
+ &Source,
+ &Destination,
+ EFI_IP_PROTO_UDP,
+ 0
+ );
+
+ //
+ // calculate the checksum.
+ //
+ Udp6Header->Checksum = Udp6Checksum (Packet, HeadSum);
+ if (Udp6Header->Checksum == 0) {
+ //
+ // If the calculated checksum is 0, fill the Checksum field with all ones.
+ //
+ Udp6Header->Checksum = 0XFFFF;
+ }
+ } else {
+ //
+ // Set the checksum is zero if the ConfigData->StationAddress is unspcified
+ // and the Ipv6 will fill the correct value of this checksum.
+ //
+ Udp6Header->Checksum = 0;
+
+ }
+ } else {
+ //
+ // UdpSessionData is NULL, use the address and port information previously configured.
+ //
+ IP6_COPY_ADDRESS (&Destination, &ConfigData->RemoteAddress);
+
+ HeadSum = Instance->HeadSum;
+ //
+ // calculate the checksum.
+ //
+ Udp6Header->Checksum = Udp6Checksum (Packet, HeadSum);
+ if (Udp6Header->Checksum == 0) {
+ //
+ // If the calculated checksum is 0, fill the Checksum field with all ones.
+ //
+ Udp6Header->Checksum = 0xffff;
+ }
+ }
+
+
+
+ //
+ // Fill the IpIo Override data.
+ //
+ Override.Ip6OverrideData.Protocol = EFI_IP_PROTO_UDP;
+ Override.Ip6OverrideData.HopLimit = ConfigData->HopLimit;
+ Override.Ip6OverrideData.FlowLabel = 0;
+
+ //
+ // Save the token into the TxToken map.
+ //
+ Status = NetMapInsertTail (&Instance->TxTokens, Token, Packet);
+ if (EFI_ERROR (Status)) {
+ goto FREE_PACKET;
+ }
+
+ //
+ // Send out this datagram through IpIo.
+ //
+ if (UdpSessionData != NULL){
+ IP6_COPY_ADDRESS (&(IpDestAddr.v6), &Destination);
+ } else {
+ ZeroMem (&IpDestAddr.v6, sizeof (EFI_IPv6_ADDRESS));
+ }
+
+ Status = IpIoSend (
+ Udp6Service->IpIo,
+ Packet,
+ Instance->IpInfo,
+ Instance,
+ Token,
+ &IpDestAddr,
+ &Override
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Remove this token from the TxTokens.
+ //
+ Udp6RemoveToken (&Instance->TxTokens, Token);
+ }
+
+FREE_PACKET:
+
+ NetbufFree (Packet);
+
+ON_EXIT:
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function places a completion token into the receive packet queue. This function
+ is always asynchronous.
+
+ @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance.
+ @param[in] Token Pointer to a token that is associated with the
+ receive data descriptor.
+
+ @retval EFI_SUCCESS The receive completion token was cached.
+ @retval EFI_NOT_STARTED This EFI UDPv6 Protocol instance has not been
+ started.
+ @retval EFI_NO_MAPPING When using a default address, configuration (DHCP,
+ BOOTP, RARP, etc.) is not finished yet.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ This is NULL. Token is NULL. Token.Event is NULL.
+ @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued
+ due to a lack of system resources (usually
+ memory).
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ The EFI UDPv6 Protocol instance has been reset to
+ startup defaults.
+ @retval EFI_ACCESS_DENIED A receive completion token with the same
+ Token.Event is already in the receive queue.
+ @retval EFI_NOT_READY The receive request could not be queued because
+ the receive queue is full.
+
+**/
+EFI_STATUS
+EFIAPI
+Udp6Receive (
+ IN EFI_UDP6_PROTOCOL *This,
+ IN EFI_UDP6_COMPLETION_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ UDP6_INSTANCE_DATA *Instance;
+ EFI_TPL OldTpl;
+
+ if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured) {
+ return EFI_NOT_STARTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp6TokenExist, Token)) ||
+ EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp6TokenExist, Token))
+ ){
+ //
+ // Return EFI_ACCESS_DENIED if the specified token is already in the TxTokens or
+ // RxTokens map.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto ON_EXIT;
+ }
+
+ Token->Packet.RxData = NULL;
+
+ //
+ // Save the token into the RxTokens map.
+ //
+ Status = NetMapInsertTail (&Instance->RxTokens, Token, NULL);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_READY;
+ goto ON_EXIT;
+ }
+
+ //
+ // If there is an icmp error, report it.
+ //
+ Udp6ReportIcmpError (Instance);
+
+ //
+ // Try to delivered the received datagrams.
+ //
+ Udp6InstanceDeliverDgram (Instance);
+
+ //
+ // Dispatch the DPC queued by the NotifyFunction of Token->Event.
+ //
+ DispatchDpc ();
+
+ON_EXIT:
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function is used to abort a pending transmit or receive request.
+
+ @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance.
+ @param[in] Token Pointer to a token that has been issued by
+ EFI_UDP6_PROTOCOL.Transmit() or
+ EFI_UDP6_PROTOCOL.Receive(). This parameter is
+ optional and may be NULL.
+
+ @retval EFI_SUCCESS The asynchronous I/O request was aborted, and
+ Token.Event was signaled. When Token is NULL, all
+ pending requests are aborted and their events are
+ signaled.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_NOT_STARTED This instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration
+ (DHCP, BOOTP, RARP, etc.) is not finished yet.
+ @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O
+ request is not found in the transmit or receive
+ queue. It is either completed or not issued by
+ Transmit() or Receive().
+
+**/
+EFI_STATUS
+EFIAPI
+Udp6Cancel (
+ IN EFI_UDP6_PROTOCOL *This,
+ IN EFI_UDP6_COMPLETION_TOKEN *Token OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UDP6_INSTANCE_DATA *Instance;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
+
+ if (!Instance->Configured) {
+ return EFI_NOT_STARTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Cancle the tokens specified by Token for this instance.
+ //
+ Status = Udp6InstanceCancelToken (Instance, Token);
+
+ //
+ // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.
+ //
+ DispatchDpc ();
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ This function can be used by network drivers and applications to increase the rate that
+ data packets are moved between the communications device and the transmit/receive queues.
+
+ @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Incoming or outgoing data was processed.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval EFI_TIMEOUT Data was dropped out of the transmit and/or
+ receive queue.
+
+**/
+EFI_STATUS
+EFIAPI
+Udp6Poll (
+ IN EFI_UDP6_PROTOCOL *This
+ )
+{
+ UDP6_INSTANCE_DATA *Instance;
+ EFI_IP6_PROTOCOL *Ip;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
+ Ip = Instance->IpInfo->Ip.Ip6;
+
+ //
+ // Invode the Ip instance consumed by the udp instance to do the poll operation.
+ //
+ return Ip->Poll (Ip);
+}