Home | History | Annotate | Download | only in Udp6Dxe
      1 /** @file
      2   Contains all EFI_UDP6_PROTOCOL interfaces.
      3 
      4   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "Udp6Impl.h"
     17 
     18 EFI_UDP6_PROTOCOL  mUdp6Protocol = {
     19   Udp6GetModeData,
     20   Udp6Configure,
     21   Udp6Groups,
     22   Udp6Transmit,
     23   Udp6Receive,
     24   Udp6Cancel,
     25   Udp6Poll
     26 };
     27 
     28 
     29 /**
     30   This function copies the current operational settings of this EFI UDPv6 Protocol
     31   instance into user-supplied buffers. This function is used optionally to retrieve
     32   the operational mode data of underlying networks or drivers.
     33 
     34   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
     35   @param[out] Udp6ConfigData     The buffer in which the current UDP configuration
     36                                  data is returned. This parameter is optional and
     37                                  may be NULL.
     38   @param[out] Ip6ModeData        The buffer in which the current EFI IPv6 Protocol
     39                                  mode data is returned. This parameter is optional
     40                                  and may be NULL.
     41   @param[out] MnpConfigData      The buffer in which the current managed network
     42                                  configuration data is returned. This parameter is
     43                                  optional and may be NULL.
     44   @param[out] SnpModeData        The buffer in which the simple network mode data
     45                                  is returned. This parameter is optional and may be NULL.
     46 
     47   @retval EFI_SUCCESS            The mode data was read.
     48   @retval EFI_NOT_STARTED        When Udp6ConfigData is queried, no configuration
     49                                  data is  available because this instance has not
     50                                  been started.
     51   @retval EFI_INVALID_PARAMETER  This is NULL.
     52 
     53 **/
     54 EFI_STATUS
     55 EFIAPI
     56 Udp6GetModeData (
     57   IN  EFI_UDP6_PROTOCOL                *This,
     58   OUT EFI_UDP6_CONFIG_DATA             *Udp6ConfigData OPTIONAL,
     59   OUT EFI_IP6_MODE_DATA                *Ip6ModeData    OPTIONAL,
     60   OUT EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData  OPTIONAL,
     61   OUT EFI_SIMPLE_NETWORK_MODE          *SnpModeData    OPTIONAL
     62   )
     63 {
     64   UDP6_INSTANCE_DATA  *Instance;
     65   EFI_IP6_PROTOCOL    *Ip;
     66   EFI_TPL             OldTpl;
     67   EFI_STATUS          Status;
     68 
     69   if (This == NULL) {
     70     return EFI_INVALID_PARAMETER;
     71   }
     72 
     73   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
     74 
     75   if (!Instance->Configured && (Udp6ConfigData != NULL)) {
     76     return EFI_NOT_STARTED;
     77   }
     78 
     79   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
     80 
     81   if (Udp6ConfigData != NULL) {
     82     //
     83     // Set the Udp6ConfigData.
     84     //
     85     CopyMem (Udp6ConfigData, &Instance->ConfigData, sizeof (EFI_UDP6_CONFIG_DATA));
     86   }
     87 
     88   Ip = Instance->IpInfo->Ip.Ip6;
     89 
     90   //
     91   // Get the underlying Ip6ModeData, MnpConfigData and SnpModeData.
     92   //
     93   Status = Ip->GetModeData (Ip, Ip6ModeData, MnpConfigData, SnpModeData);
     94 
     95   gBS->RestoreTPL (OldTpl);
     96 
     97   return Status;
     98 }
     99 
    100 
    101 /**
    102   This function is used to do the following:
    103   Initialize and start this instance of the EFI UDPv6 Protocol.
    104   Change the filtering rules and operational parameters.
    105   Reset this instance of the EFI UDPv6 Protocol.
    106 
    107   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
    108   @param[in]  UdpConfigData      Pointer to the buffer to set the configuration
    109                                  data. This parameter is optional and may be NULL.
    110 
    111   @retval EFI_SUCCESS            The configuration settings were set, changed, or
    112                                  reset successfully.
    113   @retval EFI_NO_MAPPING         When the UdpConifgData.UseAnyStationAddress is set
    114                                  to true and there is no address available for the IP6
    115                                  driver to bind a source address to this instance.
    116   @retval EFI_INVALID_PARAMETER  One or more following conditions are TRUE:
    117                                  This is NULL.
    118                                  UdpConfigData.StationAddress is not a valid
    119                                  unicast IPv6 address.
    120                                  UdpConfigData.RemoteAddress is not a valid unicast
    121                                  IPv6  address if it is not zero.
    122   @retval EFI_ALREADY_STARTED    The EFI UDPv6 Protocol instance is already
    123                                  started/configured and must be stopped/reset
    124                                  before it can be reconfigured. Only TrafficClass,
    125                                  HopLimit, ReceiveTimeout, and  TransmitTimeout can
    126                                  be reconfigured without stopping the  current
    127                                  instance of the EFI UDPv6 Protocol.
    128   @retval EFI_ACCESS_DENIED      UdpConfigData.AllowDuplicatePort is FALSE and
    129                                  UdpConfigData.StationPort is already used by another
    130                                  instance.
    131   @retval EFI_OUT_OF_RESOURCES   The EFI UDPv6 Protocol driver cannot allocate
    132                                  memory for this EFI UDPv6 Protocol instance.
    133   @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred, and
    134                                  this instance was not opened.
    135 
    136 **/
    137 EFI_STATUS
    138 EFIAPI
    139 Udp6Configure (
    140   IN EFI_UDP6_PROTOCOL     *This,
    141   IN EFI_UDP6_CONFIG_DATA  *UdpConfigData OPTIONAL
    142   )
    143 {
    144   EFI_STATUS           Status;
    145   UDP6_INSTANCE_DATA   *Instance;
    146   UDP6_SERVICE_DATA    *Udp6Service;
    147   EFI_TPL              OldTpl;
    148   EFI_IPv6_ADDRESS     StationAddress;
    149   EFI_IPv6_ADDRESS     RemoteAddress;
    150   EFI_IP6_CONFIG_DATA  Ip6ConfigData;
    151   EFI_IPv6_ADDRESS     LocalAddr;
    152   EFI_IPv6_ADDRESS     RemoteAddr;
    153 
    154   if (This == NULL) {
    155     return EFI_INVALID_PARAMETER;
    156   }
    157 
    158   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
    159 
    160   if (!Instance->Configured && (UdpConfigData == NULL)) {
    161     return EFI_SUCCESS;
    162   }
    163 
    164   Udp6Service = Instance->Udp6Service;
    165   Status      = EFI_SUCCESS;
    166   ASSERT (Udp6Service != NULL);
    167 
    168   OldTpl      = gBS->RaiseTPL (TPL_CALLBACK);
    169 
    170   if (UdpConfigData != NULL) {
    171 
    172     IP6_COPY_ADDRESS (&StationAddress, &UdpConfigData->StationAddress);
    173     IP6_COPY_ADDRESS (&RemoteAddress, &UdpConfigData->RemoteAddress);
    174 
    175     if ((!NetIp6IsUnspecifiedAddr (&StationAddress) && !NetIp6IsValidUnicast (&StationAddress)) ||
    176         (!NetIp6IsUnspecifiedAddr (&RemoteAddress) && !NetIp6IsValidUnicast (&RemoteAddress))
    177         ){
    178       //
    179       // If not use default address, and StationAddress is not a valid unicast
    180       // if it is not IPv6 address or RemoteAddress is not a valid unicast IPv6
    181       // address if it is not 0.
    182       //
    183       Status = EFI_INVALID_PARAMETER;
    184       goto ON_EXIT;
    185     }
    186 
    187     if (Instance->Configured) {
    188       //
    189       // The instance is already configured, try to do the re-configuration.
    190       //
    191       if (!Udp6IsReconfigurable (&Instance->ConfigData, UdpConfigData)) {
    192         //
    193         // If the new configuration data wants to change some unreconfigurable
    194         // settings, return EFI_ALREADY_STARTED.
    195         //
    196         Status = EFI_ALREADY_STARTED;
    197         goto ON_EXIT;
    198       }
    199 
    200       //
    201       // Save the reconfigurable parameters.
    202       //
    203       Instance->ConfigData.TrafficClass    = UdpConfigData->TrafficClass;
    204       Instance->ConfigData.HopLimit        = UdpConfigData->HopLimit;
    205       Instance->ConfigData.ReceiveTimeout  = UdpConfigData->ReceiveTimeout;
    206       Instance->ConfigData.TransmitTimeout = UdpConfigData->TransmitTimeout;
    207     } else {
    208       //
    209       // Construct the Ip configuration data from the UdpConfigData.
    210       //
    211       Udp6BuildIp6ConfigData (UdpConfigData, &Ip6ConfigData);
    212 
    213       //
    214       // Configure the Ip instance wrapped in the IpInfo.
    215       //
    216       Status = IpIoConfigIp (Instance->IpInfo, &Ip6ConfigData);
    217       if (EFI_ERROR (Status)) {
    218         if (Status == EFI_NO_MAPPING) {
    219           Instance->IsNoMapping = TRUE;
    220         }
    221 
    222         goto ON_EXIT;
    223       }
    224 
    225       Instance->IsNoMapping = FALSE;
    226 
    227       //
    228       // Save the configuration data.
    229       //
    230       CopyMem (
    231         &Instance->ConfigData,
    232         UdpConfigData,
    233         sizeof (EFI_UDP6_CONFIG_DATA)
    234         );
    235       IP6_COPY_ADDRESS (&Instance->ConfigData.StationAddress, &Ip6ConfigData.StationAddress);
    236       //
    237       // Try to allocate the required port resource.
    238       //
    239       Status = Udp6Bind (&Udp6Service->ChildrenList, &Instance->ConfigData);
    240       if (EFI_ERROR (Status)) {
    241         //
    242         // Reset the ip instance if bind fails.
    243         //
    244         IpIoConfigIp (Instance->IpInfo, NULL);
    245         goto ON_EXIT;
    246       }
    247 
    248       //
    249       // Pre calculate the checksum for the pseudo head, ignore the UDP length first.
    250       //
    251       IP6_COPY_ADDRESS (&LocalAddr, &Instance->ConfigData.StationAddress);
    252       IP6_COPY_ADDRESS (&RemoteAddr, &Instance->ConfigData.RemoteAddress);
    253 
    254       Instance->HeadSum = NetIp6PseudoHeadChecksum (
    255                             &LocalAddr,
    256                             &RemoteAddr,
    257                             EFI_IP_PROTO_UDP,
    258                             0
    259                             );
    260 
    261       Instance->Configured = TRUE;
    262     }
    263   } else {
    264     //
    265     // UdpConfigData is NULL, reset the instance.
    266     //
    267     Instance->Configured  = FALSE;
    268     Instance->IsNoMapping = FALSE;
    269 
    270     //
    271     // Reset the Ip instance wrapped in the IpInfo.
    272     //
    273     IpIoConfigIp (Instance->IpInfo, NULL);
    274 
    275     //
    276     // Cancel all the user tokens.
    277     //
    278     Instance->Udp6Proto.Cancel (&Instance->Udp6Proto, NULL);
    279 
    280     //
    281     // Remove the buffered RxData for this instance.
    282     //
    283     Udp6FlushRcvdDgram (Instance);
    284 
    285     ASSERT (IsListEmpty (&Instance->DeliveredDgramQue));
    286   }
    287 
    288 ON_EXIT:
    289 
    290   gBS->RestoreTPL (OldTpl);
    291 
    292   return Status;
    293 }
    294 
    295 
    296 /**
    297   This function is used to enable and disable the multicast group filtering.
    298 
    299   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
    300   @param[in]  JoinFlag           Set to TRUE to join a multicast group. Set to
    301                                  FALSE to leave one or all multicast groups.
    302   @param[in]  MulticastAddress   Pointer to multicast group address to join or
    303                                  leave. This parameter is optional and may be NULL.
    304 
    305   @retval EFI_SUCCESS            The operation completed successfully.
    306   @retval EFI_NOT_STARTED        The EFI UDPv6 Protocol instance has not been
    307                                  started.
    308   @retval EFI_OUT_OF_RESOURCES   Could not allocate resources to join the group.
    309   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
    310                                  This is NULL.
    311                                  JoinFlag is TRUE and MulticastAddress is NULL.
    312                                  JoinFlag is TRUE and *MulticastAddress is not a
    313                                  valid  multicast address.
    314   @retval EFI_ALREADY_STARTED    The group address is already in the group table
    315                                  (when JoinFlag is TRUE).
    316   @retval EFI_NOT_FOUND          The group address is not in the group table (when
    317                                  JoinFlag is FALSE).
    318   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
    319 
    320 **/
    321 EFI_STATUS
    322 EFIAPI
    323 Udp6Groups (
    324   IN EFI_UDP6_PROTOCOL  *This,
    325   IN BOOLEAN            JoinFlag,
    326   IN EFI_IPv6_ADDRESS   *MulticastAddress OPTIONAL
    327   )
    328 {
    329   EFI_STATUS          Status;
    330   UDP6_INSTANCE_DATA  *Instance;
    331   EFI_IP6_PROTOCOL    *Ip;
    332   EFI_TPL             OldTpl;
    333   EFI_IPv6_ADDRESS    *McastIp;
    334 
    335   if ((This == NULL) || (JoinFlag && (MulticastAddress == NULL))) {
    336     return EFI_INVALID_PARAMETER;
    337   }
    338 
    339   McastIp = NULL;
    340 
    341   if (JoinFlag) {
    342     if (!IP6_IS_MULTICAST (MulticastAddress)) {
    343       return EFI_INVALID_PARAMETER;
    344     }
    345 
    346     McastIp = AllocateCopyPool (sizeof (EFI_IPv6_ADDRESS), MulticastAddress);
    347     if (McastIp == NULL) {
    348       return EFI_OUT_OF_RESOURCES;
    349     }
    350   }
    351 
    352   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
    353   if (!Instance->Configured) {
    354     return EFI_NOT_STARTED;
    355   }
    356 
    357   Ip      = Instance->IpInfo->Ip.Ip6;
    358 
    359   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
    360 
    361   //
    362   // Invoke the Ip instance the Udp6 instance consumes to do the group operation.
    363   //
    364   Status = Ip->Groups (Ip, JoinFlag, MulticastAddress);
    365 
    366   if (EFI_ERROR (Status)) {
    367     goto ON_EXIT;
    368   }
    369 
    370   //
    371   // Keep a local copy of the configured multicast IPs because IpIo receives
    372   // datagrams from the 0 station address IP instance and then UDP delivers to
    373   // the matched instance. This copy of multicast IPs is used to avoid receive
    374   // the mutlicast datagrams destinated to multicast IPs the other instances configured.
    375   //
    376   if (JoinFlag) {
    377 
    378     Status = NetMapInsertTail (&Instance->McastIps, (VOID *) McastIp, NULL);
    379   } else {
    380 
    381     NetMapIterate (&Instance->McastIps, Udp6LeaveGroup, MulticastAddress);
    382   }
    383 
    384 ON_EXIT:
    385 
    386   gBS->RestoreTPL (OldTpl);
    387 
    388   if (EFI_ERROR (Status)) {
    389     if (McastIp != NULL) {
    390       FreePool (McastIp);
    391     }
    392   }
    393 
    394   return Status;
    395 }
    396 
    397 
    398 
    399 /**
    400   This function places a sending request to this instance of the EFI UDPv6 Protocol,
    401   alongside the transmit data that was filled by the user.
    402 
    403   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
    404   @param[in]  Token              Pointer to the completion token that will be
    405                                  placed into the transmit queue.
    406 
    407   @retval EFI_SUCCESS            The data was queued for transmission.
    408   @retval EFI_NOT_STARTED        This EFI UDPv6 Protocol instance has not been
    409                                  started.
    410   @retval EFI_NO_MAPPING         The under-layer IPv6 driver was responsible for
    411                                  choosing a source address for this instance, but
    412                                  no  source address was available for use.
    413   @retval EFI_INVALID_PARAMETER  One or more of the following are TRUE:
    414                                  This is NULL.
    415                                  Token is NULL. Token.Event is NULL.
    416                                  Token.Packet.TxData is NULL.
    417                                  Token.Packet.TxData.FragmentCount is zero.
    418                                  Token.Packet.TxData.DataLength is not equal to the
    419                                  sum of fragment lengths.
    420                                  One or more of the
    421                                  Token.Packet.TxData.FragmentTable[].FragmentLength
    422                                  fields is zero.
    423                                  One or more of the
    424                                  Token.Packet.TxData.FragmentTable[].FragmentBuffer
    425                                  fields is NULL. One or more of the
    426                                  Token.Packet.TxData.UdpSessionData.DestinationAddres
    427                                  are not valid unicast IPv6
    428                                  addresses if the  UdpSessionData is not NULL.
    429                                  Token.Packet.TxData.UdpSessionData.
    430                                  DestinationAddress is NULL
    431                                  Token.Packet.TxData.UdpSessionData.
    432                                  DestinatioPort
    433                                  is zero.
    434                                  Token.Packet.TxData.UdpSessionData is NULL and this
    435                                  instance's UdpConfigData.RemoteAddress  is unspecified.
    436   @retval EFI_ACCESS_DENIED      The transmit completion token with the same
    437                                  Token.Event is already in the transmit queue.
    438   @retval EFI_NOT_READY          The completion token could not be queued because
    439                                  the transmit queue is full.
    440   @retval EFI_OUT_OF_RESOURCES   Could not queue the transmit data.
    441   @retval EFI_NOT_FOUND          There is no route to the destination network or
    442                                  address.
    443   @retval EFI_BAD_BUFFER_SIZE    The data length is greater than the maximum UDP
    444                                  packet size. Or, the length of the IP header + UDP
    445                                  header + data length is greater than MTU if
    446                                  DoNotFragment is TRUE.
    447 
    448 **/
    449 EFI_STATUS
    450 EFIAPI
    451 Udp6Transmit (
    452   IN EFI_UDP6_PROTOCOL          *This,
    453   IN EFI_UDP6_COMPLETION_TOKEN  *Token
    454   )
    455 {
    456   EFI_STATUS              Status;
    457   UDP6_INSTANCE_DATA      *Instance;
    458   EFI_TPL                 OldTpl;
    459   NET_BUF                 *Packet;
    460   EFI_UDP_HEADER          *Udp6Header;
    461   EFI_UDP6_CONFIG_DATA    *ConfigData;
    462   EFI_IPv6_ADDRESS        Source;
    463   EFI_IPv6_ADDRESS        Destination;
    464   EFI_UDP6_TRANSMIT_DATA  *TxData;
    465   EFI_UDP6_SESSION_DATA   *UdpSessionData;
    466   UDP6_SERVICE_DATA       *Udp6Service;
    467   IP_IO_OVERRIDE          Override;
    468   UINT16                  HeadSum;
    469   EFI_IP_ADDRESS          IpDestAddr;
    470 
    471   if ((This == NULL) || (Token == NULL)) {
    472     return EFI_INVALID_PARAMETER;
    473   }
    474 
    475   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
    476 
    477   if (!Instance->Configured) {
    478     return EFI_NOT_STARTED;
    479   }
    480 
    481   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    482 
    483   //
    484   // Validate the Token, if the token is invalid return the error code.
    485   //
    486   Status = Udp6ValidateTxToken (Instance, Token);
    487   if (EFI_ERROR (Status)) {
    488     goto ON_EXIT;
    489   }
    490 
    491   if (EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp6TokenExist, Token)) ||
    492       EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp6TokenExist, Token))
    493       ){
    494     //
    495     // Try to find a duplicate token in the two token maps, if found, return
    496     // EFI_ACCESS_DENIED.
    497     //
    498     Status = EFI_ACCESS_DENIED;
    499     goto ON_EXIT;
    500   }
    501 
    502   TxData = Token->Packet.TxData;
    503 
    504   //
    505   // Create a net buffer to hold the user buffer and the udp header.
    506   //
    507   Packet = NetbufFromExt (
    508              (NET_FRAGMENT *) TxData->FragmentTable,
    509              TxData->FragmentCount,
    510              UDP6_HEADER_SIZE,
    511              0,
    512              Udp6NetVectorExtFree,
    513              NULL
    514              );
    515   if (Packet == NULL) {
    516     Status = EFI_OUT_OF_RESOURCES;
    517     goto ON_EXIT;
    518   }
    519 
    520   //
    521   // Store the IpIo in ProtoData.
    522   //
    523   Udp6Service                        = Instance->Udp6Service;
    524   *((UINTN *) &Packet->ProtoData[0]) = (UINTN) (Udp6Service->IpIo);
    525 
    526   Udp6Header = (EFI_UDP_HEADER *) NetbufAllocSpace (Packet, UDP6_HEADER_SIZE, TRUE);
    527   ASSERT (Udp6Header != NULL);
    528   ConfigData = &Instance->ConfigData;
    529 
    530   //
    531   // Fill the udp header.
    532   //
    533   Udp6Header->SrcPort      = HTONS (ConfigData->StationPort);
    534   Udp6Header->DstPort      = HTONS (ConfigData->RemotePort);
    535   Udp6Header->Length       = HTONS ((UINT16) Packet->TotalSize);
    536   Udp6Header->Checksum     = 0;
    537   //
    538   // Set the UDP Header in NET_BUF, this UDP header is for IP6 can fast get the
    539   // Udp header for pseudoHeadCheckSum.
    540   //
    541   Packet->Udp    = Udp6Header;
    542   UdpSessionData = TxData->UdpSessionData;
    543 
    544   if (UdpSessionData != NULL) {
    545     //
    546     // Set the Destination according to the specified
    547     // UdpSessionData.
    548     //
    549 
    550     if (UdpSessionData->DestinationPort != 0) {
    551       Udp6Header->DstPort = HTONS (UdpSessionData->DestinationPort);
    552     }
    553 
    554     IP6_COPY_ADDRESS (&Source, &ConfigData->StationAddress);
    555     if (!NetIp6IsUnspecifiedAddr (&UdpSessionData->DestinationAddress)) {
    556       IP6_COPY_ADDRESS (&Destination, &UdpSessionData->DestinationAddress);
    557     } else {
    558       IP6_COPY_ADDRESS (&Destination, &ConfigData->RemoteAddress);
    559     }
    560 
    561     //
    562     //Calculate the pseudo head checksum using the overridden parameters.
    563     //
    564     if (!NetIp6IsUnspecifiedAddr (&ConfigData->StationAddress)) {
    565       HeadSum = NetIp6PseudoHeadChecksum (
    566                   &Source,
    567                   &Destination,
    568                   EFI_IP_PROTO_UDP,
    569                   0
    570                   );
    571 
    572       //
    573       // calculate the checksum.
    574       //
    575       Udp6Header->Checksum = Udp6Checksum (Packet, HeadSum);
    576       if (Udp6Header->Checksum == 0) {
    577         //
    578         // If the calculated checksum is 0, fill the Checksum field with all ones.
    579         //
    580         Udp6Header->Checksum = 0XFFFF;
    581       }
    582     } else {
    583       //
    584       // Set the checksum is zero if the ConfigData->StationAddress is unspcified
    585       // and the Ipv6 will fill the correct value of this checksum.
    586       //
    587       Udp6Header->Checksum = 0;
    588 
    589     }
    590   } else {
    591     //
    592     // UdpSessionData is NULL, use the address and port information previously configured.
    593     //
    594     IP6_COPY_ADDRESS (&Destination, &ConfigData->RemoteAddress);
    595 
    596     HeadSum = Instance->HeadSum;
    597     //
    598     // calculate the checksum.
    599     //
    600     Udp6Header->Checksum = Udp6Checksum (Packet, HeadSum);
    601     if (Udp6Header->Checksum == 0) {
    602       //
    603       // If the calculated checksum is 0, fill the Checksum field with all ones.
    604       //
    605       Udp6Header->Checksum = 0xffff;
    606     }
    607   }
    608 
    609 
    610 
    611   //
    612   // Fill the IpIo Override data.
    613   //
    614   Override.Ip6OverrideData.Protocol  = EFI_IP_PROTO_UDP;
    615   Override.Ip6OverrideData.HopLimit  = ConfigData->HopLimit;
    616   Override.Ip6OverrideData.FlowLabel = 0;
    617 
    618   //
    619   // Save the token into the TxToken map.
    620   //
    621   Status = NetMapInsertTail (&Instance->TxTokens, Token, Packet);
    622   if (EFI_ERROR (Status)) {
    623     goto FREE_PACKET;
    624   }
    625 
    626   //
    627   // Send out this datagram through IpIo.
    628   //
    629   if (UdpSessionData != NULL){
    630     IP6_COPY_ADDRESS (&(IpDestAddr.v6), &Destination);
    631   } else {
    632     ZeroMem (&IpDestAddr.v6, sizeof (EFI_IPv6_ADDRESS));
    633   }
    634 
    635   Status = IpIoSend (
    636              Udp6Service->IpIo,
    637              Packet,
    638              Instance->IpInfo,
    639              Instance,
    640              Token,
    641              &IpDestAddr,
    642              &Override
    643              );
    644   if (EFI_ERROR (Status)) {
    645     //
    646     // Remove this token from the TxTokens.
    647     //
    648     Udp6RemoveToken (&Instance->TxTokens, Token);
    649   }
    650 
    651 FREE_PACKET:
    652 
    653   NetbufFree (Packet);
    654 
    655 ON_EXIT:
    656 
    657   gBS->RestoreTPL (OldTpl);
    658 
    659   return Status;
    660 }
    661 
    662 
    663 /**
    664   This function places a completion token into the receive packet queue. This function
    665   is always asynchronous.
    666 
    667   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
    668   @param[in]  Token              Pointer to a token that is associated with the
    669                                  receive data descriptor.
    670 
    671   @retval EFI_SUCCESS            The receive completion token was cached.
    672   @retval EFI_NOT_STARTED        This EFI UDPv6 Protocol instance has not been
    673                                  started.
    674   @retval EFI_NO_MAPPING         When using a default address, configuration (DHCP,
    675                                  BOOTP, RARP, etc.) is not finished yet.
    676   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
    677                                  This is NULL. Token is NULL. Token.Event is NULL.
    678   @retval EFI_OUT_OF_RESOURCES   The receive completion token could not be queued
    679                                  due to a lack of system resources (usually
    680                                  memory).
    681   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
    682                                  The EFI UDPv6 Protocol instance has been reset to
    683                                  startup defaults.
    684   @retval EFI_ACCESS_DENIED      A receive completion token with the same
    685                                  Token.Event is already in the receive queue.
    686   @retval EFI_NOT_READY          The receive request could not be queued because
    687                                  the receive  queue is full.
    688 
    689 **/
    690 EFI_STATUS
    691 EFIAPI
    692 Udp6Receive (
    693   IN EFI_UDP6_PROTOCOL          *This,
    694   IN EFI_UDP6_COMPLETION_TOKEN  *Token
    695   )
    696 {
    697   EFI_STATUS          Status;
    698   UDP6_INSTANCE_DATA  *Instance;
    699   EFI_TPL             OldTpl;
    700 
    701   if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
    702     return EFI_INVALID_PARAMETER;
    703   }
    704 
    705   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
    706 
    707   if (!Instance->Configured) {
    708     return EFI_NOT_STARTED;
    709   }
    710 
    711   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    712 
    713   if (EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp6TokenExist, Token)) ||
    714       EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp6TokenExist, Token))
    715       ){
    716     //
    717     // Return EFI_ACCESS_DENIED if the specified token is already in the TxTokens or
    718     // RxTokens map.
    719     //
    720     Status = EFI_ACCESS_DENIED;
    721     goto ON_EXIT;
    722   }
    723 
    724   Token->Packet.RxData = NULL;
    725 
    726   //
    727   // Save the token into the RxTokens map.
    728   //
    729   Status = NetMapInsertTail (&Instance->RxTokens, Token, NULL);
    730   if (EFI_ERROR (Status)) {
    731     Status = EFI_NOT_READY;
    732     goto ON_EXIT;
    733   }
    734 
    735   //
    736   // If there is an icmp error, report it.
    737   //
    738   Udp6ReportIcmpError (Instance);
    739 
    740   //
    741   // Try to delivered the received datagrams.
    742   //
    743   Udp6InstanceDeliverDgram (Instance);
    744 
    745   //
    746   // Dispatch the DPC queued by the NotifyFunction of Token->Event.
    747   //
    748   DispatchDpc ();
    749 
    750 ON_EXIT:
    751 
    752   gBS->RestoreTPL (OldTpl);
    753 
    754   return Status;
    755 }
    756 
    757 
    758 /**
    759   This function is used to abort a pending transmit or receive request.
    760 
    761   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
    762   @param[in]  Token              Pointer to a token that has been issued by
    763                                  EFI_UDP6_PROTOCOL.Transmit() or
    764                                  EFI_UDP6_PROTOCOL.Receive(). This parameter is
    765                                  optional and may be NULL.
    766 
    767   @retval EFI_SUCCESS            The asynchronous I/O request was aborted, and
    768                                  Token.Event was  signaled. When Token is NULL, all
    769                                  pending requests are aborted and their events are
    770                                  signaled.
    771   @retval EFI_INVALID_PARAMETER  This is NULL.
    772   @retval EFI_NOT_STARTED        This instance has not been started.
    773   @retval EFI_NO_MAPPING         When using the default address, configuration
    774                                  (DHCP, BOOTP, RARP, etc.) is not finished yet.
    775   @retval EFI_NOT_FOUND          When Token is not NULL, the asynchronous I/O
    776                                  request is not found in the transmit or receive
    777                                  queue. It is either completed or not issued by
    778                                  Transmit() or Receive().
    779 
    780 **/
    781 EFI_STATUS
    782 EFIAPI
    783 Udp6Cancel (
    784   IN EFI_UDP6_PROTOCOL          *This,
    785   IN EFI_UDP6_COMPLETION_TOKEN  *Token OPTIONAL
    786   )
    787 {
    788   EFI_STATUS          Status;
    789   UDP6_INSTANCE_DATA  *Instance;
    790   EFI_TPL             OldTpl;
    791 
    792   if (This == NULL) {
    793     return EFI_INVALID_PARAMETER;
    794   }
    795 
    796   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
    797 
    798   if (!Instance->Configured) {
    799     return EFI_NOT_STARTED;
    800   }
    801 
    802   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    803 
    804   //
    805   // Cancle the tokens specified by Token for this instance.
    806   //
    807   Status = Udp6InstanceCancelToken (Instance, Token);
    808 
    809   //
    810   // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.
    811   //
    812   DispatchDpc ();
    813 
    814   gBS->RestoreTPL (OldTpl);
    815 
    816   return Status;
    817 }
    818 
    819 
    820 /**
    821   This function can be used by network drivers and applications to increase the rate that
    822   data packets are moved between the communications device and the transmit/receive queues.
    823 
    824   @param[in] This                Pointer to the EFI_UDP6_PROTOCOL instance.
    825 
    826   @retval EFI_SUCCESS            Incoming or outgoing data was processed.
    827   @retval EFI_INVALID_PARAMETER  This is NULL.
    828   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
    829   @retval EFI_TIMEOUT            Data was dropped out of the transmit and/or
    830                                  receive queue.
    831 
    832 **/
    833 EFI_STATUS
    834 EFIAPI
    835 Udp6Poll (
    836   IN EFI_UDP6_PROTOCOL  *This
    837   )
    838 {
    839   UDP6_INSTANCE_DATA  *Instance;
    840   EFI_IP6_PROTOCOL    *Ip;
    841 
    842   if (This == NULL) {
    843     return EFI_INVALID_PARAMETER;
    844   }
    845 
    846   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
    847   Ip       = Instance->IpInfo->Ip.Ip6;
    848 
    849   //
    850   // Invode the Ip instance consumed by the udp instance to do the poll operation.
    851   //
    852   return Ip->Poll (Ip);
    853 }
    854