Home | History | Annotate | Download | only in Ip6Dxe
      1 /** @file
      2   Implementation of EFI_IP6_PROTOCOL protocol interfaces.
      3 
      4   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
      6 
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php.
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "Ip6Impl.h"
     18 
     19 EFI_IPSEC2_PROTOCOL    *mIpSec = NULL;
     20 
     21 EFI_IP6_PROTOCOL mEfiIp6ProtocolTemplete = {
     22   EfiIp6GetModeData,
     23   EfiIp6Configure,
     24   EfiIp6Groups,
     25   EfiIp6Routes,
     26   EfiIp6Neighbors,
     27   EfiIp6Transmit,
     28   EfiIp6Receive,
     29   EfiIp6Cancel,
     30   EfiIp6Poll
     31 };
     32 
     33 /**
     34   Gets the current operational settings for this instance of the EFI IPv6 Protocol driver.
     35 
     36   The GetModeData() function returns the current operational mode data for this driver instance.
     37   The data fields in EFI_IP6_MODE_DATA are read only. This function is used optionally to
     38   retrieve the operational mode data of underlying networks or drivers.
     39 
     40   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
     41   @param[out] Ip6ModeData        Pointer to the EFI IPv6 Protocol mode data structure.
     42   @param[out] MnpConfigData      Pointer to the managed network configuration data structure.
     43   @param[out] SnpModeData        Pointer to the simple network mode data structure.
     44 
     45   @retval EFI_SUCCESS            The operation completed successfully.
     46   @retval EFI_INVALID_PARAMETER  This is NULL.
     47   @retval EFI_OUT_OF_RESOURCES   The required mode data could not be allocated.
     48 
     49 **/
     50 EFI_STATUS
     51 EFIAPI
     52 EfiIp6GetModeData (
     53   IN EFI_IP6_PROTOCOL                 *This,
     54   OUT EFI_IP6_MODE_DATA               *Ip6ModeData     OPTIONAL,
     55   OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData   OPTIONAL,
     56   OUT EFI_SIMPLE_NETWORK_MODE         *SnpModeData     OPTIONAL
     57   )
     58 {
     59   IP6_PROTOCOL              *IpInstance;
     60   IP6_SERVICE               *IpSb;
     61   IP6_INTERFACE             *IpIf;
     62   EFI_IP6_CONFIG_DATA       *Config;
     63   EFI_STATUS                Status;
     64   EFI_TPL                   OldTpl;
     65 
     66   if (This == NULL) {
     67     return EFI_INVALID_PARAMETER;
     68   }
     69 
     70   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
     71   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
     72   IpSb       = IpInstance->Service;
     73   IpIf       = IpInstance->Interface;
     74 
     75   if (IpSb->LinkLocalDadFail) {
     76     return EFI_INVALID_PARAMETER;
     77   }
     78 
     79   if (Ip6ModeData != NULL) {
     80     //
     81     // IsStarted is "whether the EfiIp6Configure has been called".
     82     // IsConfigured is "whether the station address has been configured"
     83     //
     84     Ip6ModeData->IsStarted     = (BOOLEAN) (IpInstance->State == IP6_STATE_CONFIGED);
     85     Ip6ModeData->MaxPacketSize = IpSb->MaxPacketSize;
     86     CopyMem (&Ip6ModeData->ConfigData, &IpInstance->ConfigData, sizeof (EFI_IP6_CONFIG_DATA));
     87     Ip6ModeData->IsConfigured  = FALSE;
     88 
     89     Ip6ModeData->AddressCount  = 0;
     90     Ip6ModeData->AddressList   = NULL;
     91 
     92     Ip6ModeData->GroupCount    = IpInstance->GroupCount;
     93     Ip6ModeData->GroupTable    = NULL;
     94 
     95     Ip6ModeData->RouteCount    = 0;
     96     Ip6ModeData->RouteTable    = NULL;
     97 
     98     Ip6ModeData->NeighborCount = 0;
     99     Ip6ModeData->NeighborCache = NULL;
    100 
    101     Ip6ModeData->PrefixCount   = 0;
    102     Ip6ModeData->PrefixTable   = NULL;
    103 
    104     Ip6ModeData->IcmpTypeCount = 23;
    105     Ip6ModeData->IcmpTypeList  = AllocateCopyPool (
    106                                    Ip6ModeData->IcmpTypeCount * sizeof (EFI_IP6_ICMP_TYPE),
    107                                    mIp6SupportedIcmp
    108                                    );
    109     if (Ip6ModeData->IcmpTypeList == NULL) {
    110       Status = EFI_OUT_OF_RESOURCES;
    111       goto Error;
    112     }
    113 
    114     //
    115     // Return the currently configured IPv6 addresses and corresponding prefix lengths.
    116     //
    117     Status = Ip6BuildEfiAddressList (
    118                IpSb,
    119                &Ip6ModeData->AddressCount,
    120                &Ip6ModeData->AddressList
    121                );
    122     if (EFI_ERROR (Status)) {
    123       goto Error;
    124     }
    125 
    126     //
    127     // Return the current station address for this IP child.
    128     // If UseAnyStationAddress is set to TRUE, IP6 driver will
    129     // select a source address from its address list. Otherwise use the
    130     // StationAddress in config data.
    131     //
    132     if (Ip6ModeData->IsStarted) {
    133       Config = &Ip6ModeData->ConfigData;
    134 
    135       if (IpIf->Configured || NetIp6IsUnspecifiedAddr (&Config->DestinationAddress)) {
    136         Ip6ModeData->IsConfigured = TRUE;
    137       } else {
    138         Ip6ModeData->IsConfigured = FALSE;
    139       }
    140 
    141       //
    142       // Build a EFI route table for user from the internal route table.
    143       //
    144       Status = Ip6BuildEfiRouteTable (
    145                  IpSb->RouteTable,
    146                  &Ip6ModeData->RouteCount,
    147                  &Ip6ModeData->RouteTable
    148                  );
    149 
    150       if (EFI_ERROR (Status)) {
    151         goto Error;
    152       }
    153     }
    154 
    155     if (Ip6ModeData->IsConfigured) {
    156       //
    157       // Return the joined multicast group addresses.
    158       //
    159       if (IpInstance->GroupCount != 0) {
    160         Ip6ModeData->GroupTable = AllocateCopyPool (
    161                                     IpInstance->GroupCount * sizeof (EFI_IPv6_ADDRESS),
    162                                     IpInstance->GroupList
    163                                     );
    164         if (Ip6ModeData->GroupTable == NULL) {
    165           Status = EFI_OUT_OF_RESOURCES;
    166           goto Error;
    167         }
    168       }
    169       //
    170       // Return the neighbor cache entries
    171       //
    172       Status = Ip6BuildEfiNeighborCache (
    173                  IpInstance,
    174                  &Ip6ModeData->NeighborCount,
    175                  &Ip6ModeData->NeighborCache
    176                  );
    177       if (EFI_ERROR (Status)) {
    178         goto Error;
    179       }
    180 
    181       //
    182       // Return the prefix table entries
    183       //
    184       Status = Ip6BuildPrefixTable (
    185                  IpInstance,
    186                  &Ip6ModeData->PrefixCount,
    187                  &Ip6ModeData->PrefixTable
    188                  );
    189       if (EFI_ERROR (Status)) {
    190         goto Error;
    191       }
    192 
    193     }
    194   }
    195 
    196   //
    197   // Get fresh mode data from MNP, since underlying media status may change
    198   //
    199   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, MnpConfigData, SnpModeData);
    200 
    201   goto Exit;
    202 
    203 Error:
    204   if (Ip6ModeData != NULL) {
    205     if (Ip6ModeData->AddressList != NULL) {
    206       FreePool (Ip6ModeData->AddressList);
    207     }
    208 
    209     if (Ip6ModeData->GroupTable != NULL) {
    210       FreePool (Ip6ModeData->GroupTable);
    211     }
    212 
    213     if (Ip6ModeData->RouteTable != NULL) {
    214       FreePool (Ip6ModeData->RouteTable);
    215     }
    216 
    217     if (Ip6ModeData->NeighborCache != NULL) {
    218       FreePool (Ip6ModeData->NeighborCache);
    219     }
    220 
    221     if (Ip6ModeData->PrefixTable != NULL) {
    222       FreePool (Ip6ModeData->PrefixTable);
    223     }
    224 
    225     if (Ip6ModeData->IcmpTypeList != NULL) {
    226       FreePool (Ip6ModeData->IcmpTypeList);
    227     }
    228   }
    229 
    230 Exit:
    231   gBS->RestoreTPL (OldTpl);
    232   return Status;
    233 }
    234 
    235 /**
    236   Validate that Ipv6 address is OK to be used as station address or next hop address/ neighbor.
    237 
    238   @param[in]  IpSb               The IP6 service instance.
    239   @param[in]  Ip                 The IPv6 address to validate.
    240   @param[in]  Flag               If TRUE, validate if the address is OK to be used
    241                                  as station address. If FALSE, validate if the
    242                                  address is OK to be used as the next hop address/
    243                                  neighbor.
    244 
    245   @retval TRUE                   The Ip address is valid and could be used.
    246   @retval FALSE                  Invalid Ip address.
    247 
    248 **/
    249 BOOLEAN
    250 Ip6IsValidAddress (
    251   IN IP6_SERVICE            *IpSb,
    252   IN EFI_IPv6_ADDRESS       *Ip,
    253   IN BOOLEAN                Flag
    254   )
    255 {
    256   if (!NetIp6IsUnspecifiedAddr (Ip)) {
    257     if (!NetIp6IsValidUnicast(Ip)) {
    258       return FALSE;
    259     }
    260     if (Ip6IsOneOfSetAddress (IpSb, Ip, NULL, NULL)) {
    261       return Flag;
    262     }
    263   } else {
    264     return Flag;
    265   }
    266 
    267   return (BOOLEAN) !Flag;
    268 }
    269 
    270 /**
    271   Validate whether the value of protocol is illegal or not. Protocol is the 'Next Header' field
    272   in the last IPv6 extension header, or basic IPv6 header is there's no extension header.
    273 
    274   @param[in]  Protocol           Default value of 'Next Header'
    275 
    276   @retval TRUE                   The protocol is illegal.
    277   @retval FALSE                  The protocol is legal.
    278 
    279 **/
    280 BOOLEAN
    281 Ip6IsIllegalProtocol (
    282   IN UINT8                  Protocol
    283   )
    284 {
    285   if (Protocol == IP6_HOP_BY_HOP || Protocol == EFI_IP_PROTO_ICMP || Protocol == IP4_PROTO_IGMP) {
    286     return TRUE;
    287   }
    288 
    289   if (Protocol == 41 || Protocol == 43 || Protocol == 44 || Protocol == 59 || Protocol == 60 || Protocol == 124) {
    290     return TRUE;
    291   }
    292 
    293   return FALSE;
    294 }
    295 
    296 /**
    297   Intiialize the IP6_PROTOCOL structure to the unconfigured states.
    298 
    299   @param[in]       IpSb                   The IP6 service instance.
    300   @param[in, out]  IpInstance             The IP6 child instance.
    301 
    302 **/
    303 VOID
    304 Ip6InitProtocol (
    305   IN IP6_SERVICE            *IpSb,
    306   IN OUT IP6_PROTOCOL       *IpInstance
    307   )
    308 {
    309   ASSERT ((IpSb != NULL) && (IpInstance != NULL));
    310 
    311   ZeroMem (IpInstance, sizeof (IP6_PROTOCOL));
    312 
    313   IpInstance->Signature = IP6_PROTOCOL_SIGNATURE;
    314   IpInstance->State     = IP6_STATE_UNCONFIGED;
    315   IpInstance->Service   = IpSb;
    316   IpInstance->GroupList = NULL;
    317   CopyMem (&IpInstance->Ip6Proto, &mEfiIp6ProtocolTemplete, sizeof (EFI_IP6_PROTOCOL));
    318 
    319   NetMapInit  (&IpInstance->RxTokens);
    320   NetMapInit  (&IpInstance->TxTokens);
    321   InitializeListHead (&IpInstance->Received);
    322   InitializeListHead (&IpInstance->Delivered);
    323 
    324   EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);
    325 }
    326 
    327 /**
    328   Configure the IP6 child. If the child is already configured,
    329   change the configuration parameter. Otherwise, configure it
    330   for the first time. The caller should validate the configuration
    331   before deliver them to it. It also don't do configure NULL.
    332 
    333   @param[in, out]  IpInstance         The IP6 child to configure.
    334   @param[in]       Config             The configure data.
    335 
    336   @retval EFI_SUCCESS            The IP6 child is successfully configured.
    337   @retval EFI_DEVICE_ERROR       Failed to free the pending transive or to
    338                                  configure  underlying MNP, or other errors.
    339   @retval EFI_NO_MAPPING         The IP6 child is configured to use the default
    340                                  address, but the default address hasn't been
    341                                  configured. The IP6 child doesn't need to be
    342                                  reconfigured when the default address is configured.
    343   @retval EFI_OUT_OF_RESOURCES   No more memory space is available.
    344   @retval other                  Other error occurs.
    345 
    346 **/
    347 EFI_STATUS
    348 Ip6ConfigProtocol (
    349   IN OUT IP6_PROTOCOL        *IpInstance,
    350   IN     EFI_IP6_CONFIG_DATA *Config
    351   )
    352 {
    353   IP6_SERVICE               *IpSb;
    354   IP6_INTERFACE             *IpIf;
    355   EFI_STATUS                Status;
    356   EFI_IP6_CONFIG_DATA       *Current;
    357   IP6_ADDRESS_INFO          *AddressInfo;
    358   BOOLEAN                   StationZero;
    359   BOOLEAN                   DestZero;
    360   EFI_IPv6_ADDRESS          Source;
    361   BOOLEAN                   AddrOk;
    362 
    363   IpSb    = IpInstance->Service;
    364   Current = &IpInstance->ConfigData;
    365 
    366   //
    367   // User is changing packet filters. It must be stopped
    368   // before the station address can be changed.
    369   //
    370   if (IpInstance->State == IP6_STATE_CONFIGED) {
    371     //
    372     // Cancel all the pending transmit/receive from upper layer
    373     //
    374     Status = Ip6Cancel (IpInstance, NULL);
    375 
    376     if (EFI_ERROR (Status)) {
    377       return EFI_DEVICE_ERROR;
    378     }
    379 
    380     CopyMem (Current, Config, sizeof (EFI_IP6_CONFIG_DATA));
    381     return EFI_SUCCESS;
    382   }
    383 
    384   //
    385   // Set up the interface.
    386   //
    387   StationZero = NetIp6IsUnspecifiedAddr (&Config->StationAddress);
    388   DestZero    = NetIp6IsUnspecifiedAddr (&Config->DestinationAddress);
    389 
    390   if (StationZero && DestZero) {
    391     //
    392     // StationAddress is still zero.
    393     //
    394 
    395     NET_GET_REF (IpSb->DefaultInterface);
    396     IpInstance->Interface = IpSb->DefaultInterface;
    397     InsertTailList (&IpSb->DefaultInterface->IpInstances, &IpInstance->AddrLink);
    398 
    399     CopyMem (Current, Config, sizeof (EFI_IP6_CONFIG_DATA));
    400     IpInstance->State = IP6_STATE_CONFIGED;
    401 
    402     return EFI_SUCCESS;
    403   }
    404 
    405   if (StationZero && !DestZero) {
    406     Status = Ip6SelectSourceAddress (IpSb, &Config->DestinationAddress, &Source);
    407     if (EFI_ERROR (Status)) {
    408       return Status;
    409     }
    410   } else {
    411     IP6_COPY_ADDRESS (&Source, &Config->StationAddress);
    412   }
    413 
    414   AddrOk = Ip6IsOneOfSetAddress (IpSb, &Source, &IpIf, &AddressInfo);
    415   if (AddrOk) {
    416     if (AddressInfo != NULL) {
    417       IpInstance->PrefixLength = AddressInfo->PrefixLength;
    418     } else {
    419       IpInstance->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;
    420     }
    421   } else {
    422     //
    423     // The specified source address is not one of the addresses IPv6 maintains.
    424     //
    425     return EFI_INVALID_PARAMETER;
    426   }
    427 
    428 
    429   NET_GET_REF (IpIf);
    430   IpInstance->Interface = IpIf;
    431   InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
    432 
    433   CopyMem (Current, Config, sizeof (EFI_IP6_CONFIG_DATA));
    434   IP6_COPY_ADDRESS (&Current->StationAddress, &Source);
    435   IpInstance->State = IP6_STATE_CONFIGED;
    436 
    437   return EFI_SUCCESS;
    438 }
    439 
    440 /**
    441   Clean up the IP6 child, and release all the resources used by it.
    442 
    443   @param[in, out]  IpInstance    The IP6 child to clean up.
    444 
    445   @retval EFI_SUCCESS            The IP6 child is cleaned up.
    446   @retval EFI_DEVICE_ERROR       Some resources failed to be released.
    447 
    448 **/
    449 EFI_STATUS
    450 Ip6CleanProtocol (
    451   IN OUT IP6_PROTOCOL            *IpInstance
    452   )
    453 {
    454   if (EFI_ERROR (Ip6Cancel (IpInstance, NULL))) {
    455     return EFI_DEVICE_ERROR;
    456   }
    457 
    458   if (EFI_ERROR (Ip6Groups (IpInstance, FALSE, NULL))) {
    459     return EFI_DEVICE_ERROR;
    460   }
    461 
    462   //
    463   // Some packets haven't been recycled. It is because either the
    464   // user forgets to recycle the packets, or because the callback
    465   // hasn't been called. Just leave it alone.
    466   //
    467   if (!IsListEmpty (&IpInstance->Delivered)) {
    468     ;
    469   }
    470 
    471   if (IpInstance->Interface != NULL) {
    472     RemoveEntryList (&IpInstance->AddrLink);
    473     Ip6CleanInterface (IpInstance->Interface, IpInstance);
    474     IpInstance->Interface = NULL;
    475   }
    476 
    477   if (IpInstance->GroupList != NULL) {
    478     FreePool (IpInstance->GroupList);
    479     IpInstance->GroupList   = NULL;
    480     IpInstance->GroupCount  = 0;
    481   }
    482 
    483   NetMapClean (&IpInstance->TxTokens);
    484 
    485   NetMapClean (&IpInstance->RxTokens);
    486 
    487   return EFI_SUCCESS;
    488 }
    489 
    490 /**
    491   Configure the MNP parameter used by IP. The IP driver uses one MNP
    492   child to transmit/receive frames. By default, it configures MNP
    493   to receive unicast/multicast/broadcast. Also, it will enable/disable
    494   the promiscuous receive according to whether there is IP child
    495   enable that or not. If Force is FALSE, it will iterate through
    496   all the IP children to check whether the promiscuous receive
    497   setting has been changed. If it hasn't been changed, it won't
    498   reconfigure the MNP. If Force is TRUE, the MNP is configured
    499   whether that is changed or not.
    500 
    501   @param[in]  IpSb               The IP6 service instance that is to be changed.
    502   @param[in]  Force              Force the configuration or not.
    503 
    504   @retval EFI_SUCCESS            The MNP successfully configured/reconfigured.
    505   @retval Others                 Configuration failed.
    506 
    507 **/
    508 EFI_STATUS
    509 Ip6ServiceConfigMnp (
    510   IN IP6_SERVICE            *IpSb,
    511   IN BOOLEAN                Force
    512   )
    513 {
    514   LIST_ENTRY                *Entry;
    515   LIST_ENTRY                *ProtoEntry;
    516   IP6_INTERFACE             *IpIf;
    517   IP6_PROTOCOL              *IpInstance;
    518   BOOLEAN                   Reconfig;
    519   BOOLEAN                   PromiscReceive;
    520   EFI_STATUS                Status;
    521 
    522   Reconfig       = FALSE;
    523   PromiscReceive = FALSE;
    524 
    525   if (!Force) {
    526     //
    527     // Iterate through the IP children to check whether promiscuous
    528     // receive setting has been changed. Update the interface's receive
    529     // filter also.
    530     //
    531     NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
    532 
    533       IpIf              = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
    534       IpIf->PromiscRecv = FALSE;
    535 
    536       NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {
    537         IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP6_PROTOCOL, AddrLink);
    538 
    539         if (IpInstance->ConfigData.AcceptPromiscuous) {
    540           IpIf->PromiscRecv = TRUE;
    541           PromiscReceive    = TRUE;
    542         }
    543       }
    544     }
    545 
    546     //
    547     // If promiscuous receive isn't changed, it isn't necessary to reconfigure.
    548     //
    549     if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {
    550       return EFI_SUCCESS;
    551     }
    552 
    553     Reconfig  = TRUE;
    554     IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;
    555   }
    556 
    557   Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);
    558 
    559   //
    560   // recover the original configuration if failed to set the configure.
    561   //
    562   if (EFI_ERROR (Status) && Reconfig) {
    563     IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;
    564   }
    565 
    566   return Status;
    567 }
    568 
    569 /**
    570   Assigns an IPv6 address and subnet mask to this EFI IPv6 Protocol driver instance.
    571 
    572   The Configure() function is used to set, change, or reset the operational parameters and filter
    573   settings for this EFI IPv6 Protocol instance. Until these parameters have been set, no network traffic
    574   can be sent or received by this instance. Once the parameters have been reset (by calling this
    575   function with Ip6ConfigData set to NULL), no more traffic can be sent or received until these
    576   parameters have been set again. Each EFI IPv6 Protocol instance can be started and stopped
    577   independently of each other by enabling or disabling their receive filter settings with the
    578   Configure() function.
    579 
    580   If Ip6ConfigData.StationAddress is a valid non-zero IPv6 unicast address, it is required
    581   to be one of the currently configured IPv6 addresses listed in the EFI IPv6 drivers, or else
    582   EFI_INVALID_PARAMETER will be returned. If Ip6ConfigData.StationAddress is
    583   unspecified, the IPv6 driver will bind a source address according to the source address selection
    584   algorithm. Clients could frequently call GetModeData() to check get currently configured IPv6
    585   address list in the EFI IPv6 driver. If both Ip6ConfigData.StationAddress and
    586   Ip6ConfigData.Destination are unspecified, when transmitting the packet afterwards, the
    587   source address filled in each outgoing IPv6 packet is decided based on the destination of this packet.
    588 
    589   If operational parameters are reset or changed, any pending transmit and receive requests will be
    590   cancelled. Their completion token status will be set to EFI_ABORTED and their events will be
    591   signaled.
    592 
    593   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
    594   @param[in]  Ip6ConfigData      Pointer to the EFI IPv6 Protocol configuration data structure.
    595                                  If NULL, reset the configuration data.
    596 
    597   @retval EFI_SUCCESS            The driver instance was successfully opened.
    598   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
    599                                  - This is NULL.
    600                                  - Ip6ConfigData.StationAddress is neither zero nor
    601                                    a unicast IPv6 address.
    602                                  - Ip6ConfigData.StationAddress is neither zero nor
    603                                    one of the configured IP addresses in the EFI IPv6 driver.
    604                                  - Ip6ConfigData.DefaultProtocol is illegal.
    605   @retval EFI_OUT_OF_RESOURCES   The EFI IPv6 Protocol driver instance data could not be allocated.
    606   @retval EFI_NO_MAPPING         The IPv6 driver was responsible for choosing a source address for
    607                                  this instance, but no source address was available for use.
    608   @retval EFI_ALREADY_STARTED    The interface is already open and must be stopped before the IPv6
    609                                  address or prefix length can be changed.
    610   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred. The EFI IPv6
    611                                  Protocol driver instance was not opened.
    612   @retval EFI_UNSUPPORTED        Default protocol specified through
    613                                  Ip6ConfigData.DefaulProtocol isn't supported.
    614 
    615 **/
    616 EFI_STATUS
    617 EFIAPI
    618 EfiIp6Configure (
    619   IN EFI_IP6_PROTOCOL          *This,
    620   IN EFI_IP6_CONFIG_DATA       *Ip6ConfigData OPTIONAL
    621   )
    622 {
    623   IP6_PROTOCOL              *IpInstance;
    624   EFI_IP6_CONFIG_DATA       *Current;
    625   EFI_TPL                   OldTpl;
    626   EFI_STATUS                Status;
    627   IP6_SERVICE               *IpSb;
    628 
    629   //
    630   // First, validate the parameters
    631   //
    632   if (This == NULL) {
    633     return EFI_INVALID_PARAMETER;
    634   }
    635 
    636   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
    637   IpSb       = IpInstance->Service;
    638 
    639   if (IpSb->LinkLocalDadFail && Ip6ConfigData != NULL) {
    640     return EFI_DEVICE_ERROR;
    641   }
    642 
    643   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
    644 
    645   Status     = EFI_INVALID_PARAMETER;
    646 
    647   //
    648   // Validate the configuration first.
    649   //
    650   if (Ip6ConfigData != NULL) {
    651     //
    652     // Check whether the station address is valid.
    653     //
    654     if (!Ip6IsValidAddress (IpSb, &Ip6ConfigData->StationAddress, TRUE)) {
    655        goto Exit;
    656     }
    657     //
    658     // Check whether the default protocol is valid.
    659     //
    660     if (Ip6IsIllegalProtocol (Ip6ConfigData->DefaultProtocol)) {
    661       goto Exit;
    662     }
    663 
    664     //
    665     // User can only update packet filters when already configured.
    666     // If it wants to change the station address, it must configure(NULL)
    667     // the instance firstly.
    668     //
    669     if (IpInstance->State == IP6_STATE_CONFIGED) {
    670       Current = &IpInstance->ConfigData;
    671 
    672       if (!EFI_IP6_EQUAL (&Current->StationAddress, &Ip6ConfigData->StationAddress)) {
    673         Status = EFI_ALREADY_STARTED;
    674         goto Exit;
    675       }
    676 
    677       if (NetIp6IsUnspecifiedAddr (&Current->StationAddress) && IP6_NO_MAPPING (IpInstance)) {
    678         Status = EFI_NO_MAPPING;
    679         goto Exit;
    680       }
    681     }
    682   }
    683 
    684   //
    685   // Configure the instance or clean it up.
    686   //
    687   if (Ip6ConfigData != NULL) {
    688     Status = Ip6ConfigProtocol (IpInstance, Ip6ConfigData);
    689   } else {
    690     Status = Ip6CleanProtocol (IpInstance);
    691 
    692     //
    693     // Don't change the state if it is DESTROY, consider the following
    694     // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
    695     // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
    696     // the unload fails miserably.
    697     //
    698     if (IpInstance->State == IP6_STATE_CONFIGED) {
    699       IpInstance->State = IP6_STATE_UNCONFIGED;
    700     }
    701   }
    702 
    703   //
    704   // Update the MNP's configure data. Ip6ServiceConfigMnp will check
    705   // whether it is necessary to reconfigure the MNP.
    706   //
    707   Ip6ServiceConfigMnp (IpInstance->Service, FALSE);
    708 
    709 Exit:
    710   gBS->RestoreTPL (OldTpl);
    711   return Status;
    712 }
    713 
    714 /**
    715   Joins and leaves multicast groups.
    716 
    717   The Groups() function is used to join and leave multicast group sessions. Joining a group will
    718   enable reception of matching multicast packets. Leaving a group will disable reception of matching
    719   multicast packets. Source-Specific Multicast isn't required to be supported.
    720 
    721   If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
    722 
    723   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
    724   @param[in]  JoinFlag           Set to TRUE to join the multicast group session, and FALSE to leave.
    725   @param[in]  GroupAddress       Pointer to the IPv6 multicast address.
    726                                  This is an optional parameter that may be NULL.
    727 
    728   @retval EFI_SUCCESS            The operation completed successfully.
    729   @retval EFI_INVALID_PARAMETER  One or more of the following is TRUE:
    730                                  - This is NULL.
    731                                  - JoinFlag is TRUE and GroupAddress is NULL.
    732                                  - GroupAddress is not NULL and *GroupAddress is
    733                                    not a multicast IPv6 address.
    734                                  - GroupAddress is not NULL and *GroupAddress is in the
    735                                    range of SSM destination address.
    736   @retval EFI_NOT_STARTED        This instance has not been started.
    737   @retval EFI_OUT_OF_RESOURCES   System resources could not be allocated.
    738   @retval EFI_UNSUPPORTED        This EFI IPv6 Protocol implementation does not support multicast groups.
    739   @retval EFI_ALREADY_STARTED    The group address is already in the group table (when
    740                                  JoinFlag is TRUE).
    741   @retval EFI_NOT_FOUND          The group address is not in the group table (when JoinFlag is FALSE).
    742   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
    743 
    744 **/
    745 EFI_STATUS
    746 EFIAPI
    747 EfiIp6Groups (
    748   IN EFI_IP6_PROTOCOL  *This,
    749   IN BOOLEAN           JoinFlag,
    750   IN EFI_IPv6_ADDRESS  *GroupAddress  OPTIONAL
    751   )
    752 {
    753   EFI_TPL                   OldTpl;
    754   EFI_STATUS                Status;
    755   IP6_PROTOCOL              *IpInstance;
    756   IP6_SERVICE               *IpSb;
    757 
    758   if ((This == NULL) || (JoinFlag && GroupAddress == NULL)) {
    759     return EFI_INVALID_PARAMETER;
    760   }
    761 
    762   if (GroupAddress != NULL && !IP6_IS_MULTICAST (GroupAddress)) {
    763     return EFI_INVALID_PARAMETER;
    764   }
    765 
    766   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
    767   IpSb       = IpInstance->Service;
    768 
    769   if (IpSb->LinkLocalDadFail) {
    770     return EFI_DEVICE_ERROR;
    771   }
    772 
    773   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
    774 
    775   if (IpInstance->State != IP6_STATE_CONFIGED) {
    776     Status = EFI_NOT_STARTED;
    777     goto ON_EXIT;
    778   }
    779 
    780   Status = Ip6Groups (IpInstance, JoinFlag, GroupAddress);
    781 
    782 ON_EXIT:
    783   gBS->RestoreTPL (OldTpl);
    784   return Status;
    785 }
    786 
    787 /**
    788   Adds and deletes routing table entries.
    789 
    790   The Routes() function adds a route to, or deletes a route from, the routing table.
    791 
    792   Routes are determined by comparing the leftmost PrefixLength bits of Destination with
    793   the destination IPv6 address arithmetically. The gateway address must be on the same subnet as the
    794   configured station address.
    795 
    796   The default route is added with Destination and PrefixLegth both set to all zeros. The
    797   default route matches all destination IPv6 addresses that do not match any other routes.
    798 
    799   All EFI IPv6 Protocol instances share a routing table.
    800 
    801   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
    802   @param[in]  DeleteRoute        Set to TRUE to delete this route from the routing table. Set to
    803                                  FALSE to add this route to the routing table. Destination,
    804                                  PrefixLength and Gateway are used as the key to each
    805                                  route entry.
    806   @param[in]  Destination        The address prefix of the subnet that needs to be routed.
    807                                  This is an optional parameter that may be NULL.
    808   @param[in]  PrefixLength       The prefix length of Destination. Ignored if Destination
    809                                  is NULL.
    810   @param[in]  GatewayAddress     The unicast gateway IPv6 address for this route.
    811                                  This is an optional parameter that may be NULL.
    812 
    813   @retval EFI_SUCCESS            The operation completed successfully.
    814   @retval EFI_NOT_STARTED        The driver instance has not been started.
    815   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
    816                                  - This is NULL.
    817                                  - When DeleteRoute is TRUE, both Destination and
    818                                    GatewayAddress are NULL.
    819                                  - When DeleteRoute is FALSE, either Destination or
    820                                    GatewayAddress is NULL.
    821                                  - *GatewayAddress is not a valid unicast IPv6 address.
    822                                  - *GatewayAddress is one of the local configured IPv6
    823                                    addresses.
    824   @retval EFI_OUT_OF_RESOURCES   Could not add the entry to the routing table.
    825   @retval EFI_NOT_FOUND          This route is not in the routing table (when DeleteRoute is TRUE).
    826   @retval EFI_ACCESS_DENIED      The route is already defined in the routing table (when
    827                                  DeleteRoute is FALSE).
    828 
    829 **/
    830 EFI_STATUS
    831 EFIAPI
    832 EfiIp6Routes (
    833   IN EFI_IP6_PROTOCOL    *This,
    834   IN BOOLEAN             DeleteRoute,
    835   IN EFI_IPv6_ADDRESS    *Destination    OPTIONAL,
    836   IN UINT8               PrefixLength,
    837   IN EFI_IPv6_ADDRESS    *GatewayAddress OPTIONAL
    838   )
    839 {
    840   IP6_PROTOCOL              *IpInstance;
    841   EFI_STATUS                Status;
    842   EFI_TPL                   OldTpl;
    843   IP6_SERVICE               *IpSb;
    844 
    845   if ((This == NULL) || (PrefixLength > IP6_PREFIX_MAX)) {
    846     return EFI_INVALID_PARAMETER;
    847   }
    848 
    849   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
    850   IpSb       = IpInstance->Service;
    851 
    852   if (IpSb->LinkLocalDadFail) {
    853     return EFI_DEVICE_ERROR;
    854   }
    855 
    856   if (IpInstance->State != IP6_STATE_CONFIGED) {
    857     return EFI_NOT_STARTED;
    858   }
    859 
    860   if (DeleteRoute && (Destination == NULL) && (GatewayAddress == NULL)) {
    861     return EFI_INVALID_PARAMETER;
    862   }
    863 
    864   if (!DeleteRoute && (Destination == NULL || GatewayAddress == NULL)) {
    865     return EFI_INVALID_PARAMETER;
    866   }
    867 
    868   if (GatewayAddress != NULL) {
    869     if (!Ip6IsValidAddress (IpSb, GatewayAddress, FALSE)) {
    870       return EFI_INVALID_PARAMETER;
    871     }
    872 
    873     if (!NetIp6IsUnspecifiedAddr (GatewayAddress) &&
    874         !NetIp6IsNetEqual (GatewayAddress, &IpInstance->ConfigData.StationAddress, PrefixLength)
    875           ) {
    876       return EFI_INVALID_PARAMETER;
    877     }
    878   }
    879 
    880   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    881 
    882   //
    883   // Update the route table
    884   //
    885   if (DeleteRoute) {
    886     Status = Ip6DelRoute (IpSb->RouteTable, Destination, PrefixLength, GatewayAddress);
    887   } else {
    888     Status = Ip6AddRoute (IpSb->RouteTable, Destination, PrefixLength, GatewayAddress);
    889   }
    890 
    891   gBS->RestoreTPL (OldTpl);
    892   return Status;
    893 }
    894 
    895 /**
    896   Add or delete Neighbor cache entries.
    897 
    898   The Neighbors() function is used to add, update, or delete an entry from neighbor cache.
    899   IPv6 neighbor cache entries are typically inserted and updated by the network protocol driver as
    900   network traffic is processed. Most neighbor cache entries will timeout and be deleted if the network
    901   traffic stops. Neighbor cache entries that were inserted by Neighbors() may be static (will not
    902   timeout) or dynamic (will timeout).
    903 
    904   The implementation should follow the neighbor cache timeout mechanism which is defined in
    905   RFC4861. The default neighbor cache timeout value should be tuned for the expected network
    906   environment
    907 
    908   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
    909   @param[in]  DeleteFlag         Set to TRUE to delete the specified cache entry, set to FALSE to
    910                                  add (or update, if it already exists and Override is TRUE) the
    911                                  specified cache entry. TargetIp6Address is used as the key
    912                                  to find the requested cache entry.
    913   @param[in]  TargetIp6Address   Pointer to the Target IPv6 address.
    914   @param[in]  TargetLinkAddress  Pointer to the link-layer address of the target. Ignored if NULL.
    915   @param[in]  Timeout            Time in 100-ns units that this entry will remain in the neighbor
    916                                  cache, it will be deleted after Timeout. A value of zero means that
    917                                  the entry is permanent. A non-zero value means that the entry is
    918                                  dynamic.
    919   @param[in]  Override           If TRUE, the cached link-layer address of the matching entry will
    920                                  be overridden and updated; if FALSE, EFI_ACCESS_DENIED
    921                                  will be returned if a corresponding cache entry already existed.
    922 
    923   @retval  EFI_SUCCESS           The data has been queued for transmission.
    924   @retval  EFI_NOT_STARTED       This instance has not been started.
    925   @retval  EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
    926                                  - This is NULL.
    927                                  - TargetIpAddress is NULL.
    928                                  - *TargetLinkAddress is invalid when not NULL.
    929                                  - *TargetIpAddress is not a valid unicast IPv6 address.
    930                                  - *TargetIpAddress is one of the local configured IPv6
    931                                    addresses.
    932   @retval  EFI_OUT_OF_RESOURCES  Could not add the entry to the neighbor cache.
    933   @retval  EFI_NOT_FOUND         This entry is not in the neighbor cache (when DeleteFlag  is
    934                                  TRUE or when DeleteFlag  is FALSE while
    935                                  TargetLinkAddress is NULL.).
    936   @retval  EFI_ACCESS_DENIED     The to-be-added entry is already defined in the neighbor cache,
    937                                  and that entry is tagged as un-overridden (when Override
    938                                  is FALSE).
    939 
    940 **/
    941 EFI_STATUS
    942 EFIAPI
    943 EfiIp6Neighbors (
    944   IN EFI_IP6_PROTOCOL          *This,
    945   IN BOOLEAN                   DeleteFlag,
    946   IN EFI_IPv6_ADDRESS          *TargetIp6Address,
    947   IN EFI_MAC_ADDRESS           *TargetLinkAddress OPTIONAL,
    948   IN UINT32                    Timeout,
    949   IN BOOLEAN                   Override
    950   )
    951 {
    952   EFI_TPL                   OldTpl;
    953   EFI_STATUS                Status;
    954   IP6_PROTOCOL              *IpInstance;
    955   IP6_SERVICE               *IpSb;
    956 
    957   if (This == NULL || TargetIp6Address == NULL) {
    958     return EFI_INVALID_PARAMETER;
    959   }
    960 
    961   if (NetIp6IsUnspecifiedAddr (TargetIp6Address)) {
    962     return EFI_INVALID_PARAMETER;
    963   }
    964 
    965   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
    966   IpSb       = IpInstance->Service;
    967 
    968   if (IpSb->LinkLocalDadFail) {
    969     return EFI_DEVICE_ERROR;
    970   }
    971 
    972   if (!Ip6IsValidAddress (IpSb, TargetIp6Address, FALSE)) {
    973     return EFI_INVALID_PARAMETER;
    974   }
    975 
    976   if (TargetLinkAddress != NULL) {
    977     if (!Ip6IsValidLinkAddress (IpSb, TargetLinkAddress)) {
    978       return EFI_INVALID_PARAMETER;
    979     }
    980   }
    981 
    982   if (Ip6IsOneOfSetAddress (IpSb, TargetIp6Address, NULL, NULL)) {
    983     return EFI_INVALID_PARAMETER;
    984   }
    985 
    986   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    987   if (IpInstance->State != IP6_STATE_CONFIGED) {
    988     Status = EFI_NOT_STARTED;
    989     goto Exit;
    990   }
    991 
    992   if (DeleteFlag) {
    993     Status = Ip6DelNeighbor (IpInstance->Service, TargetIp6Address, TargetLinkAddress, Timeout, Override);
    994   } else {
    995     Status = Ip6AddNeighbor (IpInstance->Service, TargetIp6Address, TargetLinkAddress, Timeout, Override);
    996   }
    997 
    998 Exit:
    999   gBS->RestoreTPL (OldTpl);
   1000   return Status;
   1001 }
   1002 
   1003 /**
   1004   Check whether the user's token or event has already
   1005   been enqueue on IP6's list.
   1006 
   1007   @param[in]  Map                The container of either user's transmit or receive
   1008                                  token.
   1009   @param[in]  Item               Current item to check against.
   1010   @param[in]  Context            The Token to check againist.
   1011 
   1012   @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP
   1013   @retval EFI_SUCCESS            The current item isn't the same token/event as the
   1014                                  context.
   1015 
   1016 **/
   1017 EFI_STATUS
   1018 EFIAPI
   1019 Ip6TokenExist (
   1020   IN NET_MAP                *Map,
   1021   IN NET_MAP_ITEM           *Item,
   1022   IN VOID                   *Context
   1023   )
   1024 {
   1025   EFI_IP6_COMPLETION_TOKEN  *Token;
   1026   EFI_IP6_COMPLETION_TOKEN  *TokenInItem;
   1027 
   1028   Token       = (EFI_IP6_COMPLETION_TOKEN *) Context;
   1029   TokenInItem = (EFI_IP6_COMPLETION_TOKEN *) Item->Key;
   1030 
   1031   if (Token == TokenInItem || Token->Event == TokenInItem->Event) {
   1032     return EFI_ACCESS_DENIED;
   1033   }
   1034 
   1035   return EFI_SUCCESS;
   1036 }
   1037 
   1038 /**
   1039   Validate the user's token against the current station address.
   1040 
   1041   @param[in]  Token              User's token to validate.
   1042 
   1043   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
   1044   @retval EFI_BAD_BUFFER_SIZE    The user's option/data is too long.
   1045   @retval EFI_SUCCESS            The token is OK.
   1046 
   1047 **/
   1048 EFI_STATUS
   1049 Ip6TxTokenValid (
   1050   IN EFI_IP6_COMPLETION_TOKEN   *Token
   1051   )
   1052 {
   1053   EFI_IP6_TRANSMIT_DATA     *TxData;
   1054   UINT32                    Index;
   1055   UINT32                    DataLength;
   1056 
   1057   if (Token == NULL || Token->Event == NULL) {
   1058     return EFI_INVALID_PARAMETER;
   1059   }
   1060 
   1061   TxData = Token->Packet.TxData;
   1062 
   1063   if (TxData == NULL || (TxData->ExtHdrsLength != 0 && TxData->ExtHdrs == NULL)) {
   1064     return EFI_INVALID_PARAMETER;
   1065   }
   1066 
   1067   if (TxData->FragmentCount == 0 || TxData->DataLength == 0) {
   1068     return EFI_INVALID_PARAMETER;
   1069   }
   1070 
   1071   for (DataLength = 0, Index = 0; Index < TxData->FragmentCount; Index++) {
   1072     if (TxData->FragmentTable[Index].FragmentLength == 0 || TxData->FragmentTable[Index].FragmentBuffer == NULL) {
   1073       return EFI_INVALID_PARAMETER;
   1074     }
   1075 
   1076     DataLength += TxData->FragmentTable[Index].FragmentLength;
   1077   }
   1078 
   1079   if (TxData->DataLength != DataLength) {
   1080     return EFI_INVALID_PARAMETER;
   1081   }
   1082 
   1083   //
   1084   // TODO: Token.Packet.TxData.DataLength is too short to transmit.
   1085   // return EFI_BUFFER_TOO_SMALL;
   1086   //
   1087 
   1088   //
   1089   // If Token.Packet.TxData.DataLength is beyond the maximum that which can be
   1090   // described through the Fragment Offset field in Fragment header when performing
   1091   // fragmentation.
   1092   //
   1093   if (TxData->DataLength > 64 * 1024) {
   1094     return EFI_BAD_BUFFER_SIZE;
   1095   }
   1096 
   1097   return EFI_SUCCESS;
   1098 }
   1099 
   1100 /**
   1101   The callback function for the net buffer which wraps the user's
   1102   transmit token. Although  this function seems simple, there
   1103   are some subtle aspects.
   1104   When user requests the IP to transmit a packet by passing it a
   1105   token, the token is wrapped in an IP6_TXTOKEN_WRAP and the data
   1106   is wrapped in an net buffer. The net buffer's Free function is
   1107   set to Ip6FreeTxToken. The Token and token wrap are added to the
   1108   IP child's TxToken map. Then the buffer is passed to Ip6Output for
   1109   transmission. If an error happened before that, the buffer
   1110   is freed, which in turn frees the token wrap. The wrap may
   1111   have been added to the TxToken map or not, and the user's event
   1112   shouldn't be fired because we are still in the EfiIp6Transmit. If
   1113   the buffer has been sent by Ip6Output, it should be removed from
   1114   the TxToken map and user's event signaled. The token wrap and buffer
   1115   are bound together. Check the comments in Ip6Output for information
   1116   about IP fragmentation.
   1117 
   1118   @param[in]  Context                The token's wrap.
   1119 
   1120 **/
   1121 VOID
   1122 EFIAPI
   1123 Ip6FreeTxToken (
   1124   IN VOID                   *Context
   1125   )
   1126 {
   1127   IP6_TXTOKEN_WRAP          *Wrap;
   1128   NET_MAP_ITEM              *Item;
   1129 
   1130   Wrap = (IP6_TXTOKEN_WRAP *) Context;
   1131 
   1132   //
   1133   // Signal IpSecRecycleEvent to inform IPsec free the memory
   1134   //
   1135   if (Wrap->IpSecRecycleSignal != NULL) {
   1136     gBS->SignalEvent (Wrap->IpSecRecycleSignal);
   1137   }
   1138 
   1139   //
   1140   // Find the token in the instance's map. EfiIp6Transmit put the
   1141   // token to the map. If that failed, NetMapFindKey will return NULL.
   1142   //
   1143   Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
   1144 
   1145   if (Item != NULL) {
   1146     NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
   1147   }
   1148 
   1149   if (Wrap->Sent) {
   1150     gBS->SignalEvent (Wrap->Token->Event);
   1151 
   1152     //
   1153     // Dispatch the DPC queued by the NotifyFunction of Token->Event.
   1154     //
   1155     DispatchDpc ();
   1156   }
   1157 
   1158   FreePool (Wrap);
   1159 }
   1160 
   1161 
   1162 /**
   1163   The callback function to Ip6Output to update the transmit status.
   1164 
   1165   @param[in]  Packet           The user's transmit packet.
   1166   @param[in]  IoStatus         The result of the transmission.
   1167   @param[in]  Flag             Not used during transmission.
   1168   @param[in]  Context          The token's wrap.
   1169 
   1170 **/
   1171 VOID
   1172 Ip6OnPacketSent (
   1173   IN NET_BUF                   *Packet,
   1174   IN EFI_STATUS                IoStatus,
   1175   IN UINT32                    Flag,
   1176   IN VOID                      *Context
   1177   )
   1178 {
   1179   IP6_TXTOKEN_WRAP             *Wrap;
   1180 
   1181   //
   1182   // This is the transmission request from upper layer,
   1183   // not the IP6 driver itself.
   1184   //
   1185   Wrap                = (IP6_TXTOKEN_WRAP *) Context;
   1186   Wrap->Token->Status = IoStatus;
   1187 
   1188   NetbufFree (Wrap->Packet);
   1189 }
   1190 
   1191 /**
   1192   Places outgoing data packets into the transmit queue.
   1193 
   1194   The Transmit() function places a sending request in the transmit queue of this
   1195   EFI IPv6 Protocol instance. Whenever the packet in the token is sent out or some
   1196   errors occur, the event in the token will be signaled, and the status is updated.
   1197 
   1198   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
   1199   @param[in]  Token              Pointer to the transmit token.
   1200 
   1201   @retval  EFI_SUCCESS           The data has been queued for transmission.
   1202   @retval  EFI_NOT_STARTED       This instance has not been started.
   1203   @retval  EFI_NO_MAPPING        The IPv6 driver was responsible for choosing
   1204                                  a source address for this transmission,
   1205                                  but no source address was available for use.
   1206   @retval  EFI_INVALID_PARAMETER One or more of the following is TRUE:
   1207                                  - This is NULL.
   1208                                  - Token is NULL.
   1209                                  - Token.Event is NULL.
   1210                                  - Token.Packet.TxData is NULL.
   1211                                  - Token.Packet.ExtHdrsLength is not zero and
   1212                                    Token.Packet.ExtHdrs is NULL.
   1213                                  - Token.Packet.FragmentCount is zero.
   1214                                  - One or more of the Token.Packet.TxData.
   1215                                    FragmentTable[].FragmentLength fields is zero.
   1216                                  - One or more of the Token.Packet.TxData.
   1217                                    FragmentTable[].FragmentBuffer fields is NULL.
   1218                                  - Token.Packet.TxData.DataLength is zero or not
   1219                                    equal to the sum of fragment lengths.
   1220                                  - Token.Packet.TxData.DestinationAddress is non
   1221                                    zero when DestinationAddress is configured as
   1222                                    non-zero when doing Configure() for this
   1223                                    EFI IPv6 protocol instance.
   1224                                  - Token.Packet.TxData.DestinationAddress is
   1225                                    unspecified when DestinationAddress is unspecified
   1226                                    when doing Configure() for this EFI IPv6 protocol
   1227                                    instance.
   1228   @retval  EFI_ACCESS_DENIED     The transmit completion token with the same Token.
   1229                                  Event was already in the transmit queue.
   1230   @retval  EFI_NOT_READY         The completion token could not be queued because
   1231                                  the transmit queue is full.
   1232   @retval  EFI_NOT_FOUND         Not route is found to destination address.
   1233   @retval  EFI_OUT_OF_RESOURCES  Could not queue the transmit data.
   1234   @retval  EFI_BUFFER_TOO_SMALL  Token.Packet.TxData.TotalDataLength is too
   1235                                  short to transmit.
   1236   @retval  EFI_BAD_BUFFER_SIZE   If Token.Packet.TxData.DataLength is beyond the
   1237                                  maximum that which can be described through the
   1238                                  Fragment Offset field in Fragment header when
   1239                                  performing fragmentation.
   1240   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
   1241 
   1242 **/
   1243 EFI_STATUS
   1244 EFIAPI
   1245 EfiIp6Transmit (
   1246   IN EFI_IP6_PROTOCOL          *This,
   1247   IN EFI_IP6_COMPLETION_TOKEN  *Token
   1248   )
   1249 {
   1250   IP6_SERVICE               *IpSb;
   1251   IP6_PROTOCOL              *IpInstance;
   1252   EFI_IP6_CONFIG_DATA       *Config;
   1253   EFI_STATUS                Status;
   1254   EFI_TPL                   OldTpl;
   1255   EFI_IP6_HEADER            Head;
   1256   EFI_IP6_TRANSMIT_DATA     *TxData;
   1257   EFI_IP6_OVERRIDE_DATA     *Override;
   1258   IP6_TXTOKEN_WRAP          *Wrap;
   1259   UINT8                     *ExtHdrs;
   1260 
   1261   //
   1262   // Check input parameters.
   1263   //
   1264   if (This == NULL) {
   1265     return EFI_INVALID_PARAMETER;
   1266   }
   1267 
   1268   ExtHdrs = NULL;
   1269 
   1270   Status = Ip6TxTokenValid (Token);
   1271   if (EFI_ERROR (Status)) {
   1272     return Status;
   1273   }
   1274 
   1275   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
   1276   IpSb       = IpInstance->Service;
   1277 
   1278   if (IpSb->LinkLocalDadFail) {
   1279     return EFI_DEVICE_ERROR;
   1280   }
   1281 
   1282   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
   1283 
   1284   if (IpInstance->State != IP6_STATE_CONFIGED) {
   1285     Status = EFI_NOT_STARTED;
   1286     goto Exit;
   1287   }
   1288 
   1289   Config = &IpInstance->ConfigData;
   1290 
   1291   //
   1292   // Check whether the token or signal already existed.
   1293   //
   1294   if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip6TokenExist, Token))) {
   1295     Status = EFI_ACCESS_DENIED;
   1296     goto Exit;
   1297   }
   1298 
   1299   //
   1300   // Build the IP header, fill in the information from ConfigData or OverrideData
   1301   //
   1302   ZeroMem (&Head, sizeof(EFI_IP6_HEADER));
   1303   TxData = Token->Packet.TxData;
   1304   IP6_COPY_ADDRESS (&Head.SourceAddress, &Config->StationAddress);
   1305   IP6_COPY_ADDRESS (&Head.DestinationAddress, &Config->DestinationAddress);
   1306 
   1307   Status = EFI_INVALID_PARAMETER;
   1308 
   1309   if (NetIp6IsUnspecifiedAddr (&TxData->DestinationAddress)) {
   1310     if (NetIp6IsUnspecifiedAddr (&Config->DestinationAddress)) {
   1311       goto Exit;
   1312     }
   1313 
   1314     ASSERT (!NetIp6IsUnspecifiedAddr (&Config->StationAddress));
   1315 
   1316   } else {
   1317     //
   1318     // StationAddress is unspecified only when ConfigData.Dest is unspecified.
   1319     // Use TxData.Dest to override the DestinationAddress.
   1320     //
   1321     if (!NetIp6IsUnspecifiedAddr (&Config->DestinationAddress)) {
   1322       goto Exit;
   1323     }
   1324 
   1325     if (NetIp6IsUnspecifiedAddr (&Config->StationAddress)) {
   1326       Status = Ip6SelectSourceAddress (
   1327                  IpSb,
   1328                  &TxData->DestinationAddress,
   1329                  &Head.SourceAddress
   1330                  );
   1331       if (EFI_ERROR (Status)) {
   1332         goto Exit;
   1333       }
   1334     }
   1335 
   1336     IP6_COPY_ADDRESS (&Head.DestinationAddress, &TxData->DestinationAddress);
   1337   }
   1338 
   1339   //
   1340   // Fill in Head infos.
   1341   //
   1342   Head.NextHeader = Config->DefaultProtocol;
   1343   if (TxData->ExtHdrsLength != 0) {
   1344     Head.NextHeader = TxData->NextHeader;
   1345   }
   1346 
   1347   if (TxData->OverrideData != NULL) {
   1348     Override        = TxData->OverrideData;
   1349     Head.NextHeader = Override->Protocol;
   1350     Head.HopLimit   = Override->HopLimit;
   1351     Head.FlowLabelL = HTONS ((UINT16) Override->FlowLabel);
   1352     Head.FlowLabelH = (UINT8) ((Override->FlowLabel >> 16) & 0x0F);
   1353   } else {
   1354     Head.HopLimit   = Config->HopLimit;
   1355     Head.FlowLabelL = HTONS ((UINT16) Config->FlowLabel);
   1356     Head.FlowLabelH = (UINT8) ((Config->FlowLabel >> 16) & 0x0F);
   1357   }
   1358 
   1359   Head.PayloadLength = HTONS ((UINT16) (TxData->ExtHdrsLength + TxData->DataLength));
   1360 
   1361   //
   1362   // OK, it survives all the validation check. Wrap the token in
   1363   // a IP6_TXTOKEN_WRAP and the data in a netbuf
   1364   //
   1365   Status = EFI_OUT_OF_RESOURCES;
   1366   Wrap   = AllocateZeroPool (sizeof (IP6_TXTOKEN_WRAP));
   1367   if (Wrap == NULL) {
   1368     goto Exit;
   1369   }
   1370 
   1371   Wrap->IpInstance  = IpInstance;
   1372   Wrap->Token       = Token;
   1373   Wrap->Sent        = FALSE;
   1374   Wrap->Life        = IP6_US_TO_SEC (Config->TransmitTimeout);
   1375   Wrap->Packet      = NetbufFromExt (
   1376                         (NET_FRAGMENT *) TxData->FragmentTable,
   1377                         TxData->FragmentCount,
   1378                         IP6_MAX_HEADLEN,
   1379                         0,
   1380                         Ip6FreeTxToken,
   1381                         Wrap
   1382                         );
   1383 
   1384   if (Wrap->Packet == NULL) {
   1385     FreePool (Wrap);
   1386     goto Exit;
   1387   }
   1388 
   1389   Token->Status = EFI_NOT_READY;
   1390 
   1391   Status = NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap);
   1392   if (EFI_ERROR (Status)) {
   1393     //
   1394     // NetbufFree will call Ip6FreeTxToken, which in turn will
   1395     // free the IP6_TXTOKEN_WRAP. Now, the token wrap hasn't been
   1396     // enqueued.
   1397     //
   1398     NetbufFree (Wrap->Packet);
   1399     goto Exit;
   1400   }
   1401 
   1402   //
   1403   // Allocate a new buffer to store IPv6 extension headers to avoid updating
   1404   // the original data in EFI_IP6_COMPLETION_TOKEN.
   1405   //
   1406   if (TxData->ExtHdrsLength != 0 && TxData->ExtHdrs != NULL) {
   1407     ExtHdrs = (UINT8 *) AllocateCopyPool (TxData->ExtHdrsLength, TxData->ExtHdrs);
   1408     if (ExtHdrs == NULL) {
   1409       Status = EFI_OUT_OF_RESOURCES;
   1410       goto Exit;
   1411     }
   1412   }
   1413 
   1414   //
   1415   // Mark the packet sent before output it. Mark it not sent again if the
   1416   // returned status is not EFI_SUCCESS;
   1417   //
   1418   Wrap->Sent = TRUE;
   1419 
   1420   Status = Ip6Output (
   1421              IpSb,
   1422              NULL,
   1423              IpInstance,
   1424              Wrap->Packet,
   1425              &Head,
   1426              ExtHdrs,
   1427              TxData->ExtHdrsLength,
   1428              Ip6OnPacketSent,
   1429              Wrap
   1430              );
   1431   if (EFI_ERROR (Status)) {
   1432     Wrap->Sent = FALSE;
   1433     NetbufFree (Wrap->Packet);
   1434   }
   1435 
   1436 Exit:
   1437   gBS->RestoreTPL (OldTpl);
   1438 
   1439   if (ExtHdrs != NULL) {
   1440     FreePool (ExtHdrs);
   1441   }
   1442 
   1443   return Status;
   1444 }
   1445 
   1446 /**
   1447   Places a receiving request into the receiving queue.
   1448 
   1449   The Receive() function places a completion token into the receive packet queue.
   1450   This function is always asynchronous.
   1451 
   1452   The Token.Event field in the completion token must be filled in by the caller
   1453   and cannot be NULL. When the receive operation completes, the EFI IPv6 Protocol
   1454   driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
   1455   is signaled.
   1456 
   1457   Current Udp implementation creates an IP child for each Udp child.
   1458   It initates a asynchronous receive immediately no matter whether
   1459   there is no mapping or not. Therefore, disable the returning EFI_NO_MAPPING for now.
   1460   To enable it, the following check must be performed:
   1461 
   1462   if (NetIp6IsUnspecifiedAddr (&Config->StationAddress) && IP6_NO_MAPPING (IpInstance)) {
   1463     Status = EFI_NO_MAPPING;
   1464     goto Exit;
   1465   }
   1466 
   1467   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
   1468   @param[in]  Token              Pointer to a token that is associated with the receive data descriptor.
   1469 
   1470   @retval EFI_SUCCESS            The receive completion token was cached.
   1471   @retval EFI_NOT_STARTED        This EFI IPv6 Protocol instance has not been started.
   1472   @retval EFI_NO_MAPPING         When IP6 driver responsible for binding source address to this instance,
   1473                                  while no source address is available for use.
   1474   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
   1475                                  - This is NULL.
   1476                                  - Token is NULL.
   1477                                  - Token.Event is NULL.
   1478   @retval EFI_OUT_OF_RESOURCES   The receive completion token could not be queued due to a lack of system
   1479                                  resources (usually memory).
   1480   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
   1481                                  The EFI IPv6 Protocol instance has been reset to startup defaults.
   1482   @retval EFI_ACCESS_DENIED      The receive completion token with the same Token.Event was already
   1483                                  in the receive queue.
   1484   @retval EFI_NOT_READY          The receive request could not be queued because the receive queue is full.
   1485 
   1486 **/
   1487 EFI_STATUS
   1488 EFIAPI
   1489 EfiIp6Receive (
   1490   IN EFI_IP6_PROTOCOL          *This,
   1491   IN EFI_IP6_COMPLETION_TOKEN  *Token
   1492   )
   1493 {
   1494   IP6_PROTOCOL              *IpInstance;
   1495   EFI_STATUS                Status;
   1496   EFI_TPL                   OldTpl;
   1497   IP6_SERVICE               *IpSb;
   1498 
   1499   if (This == NULL || Token == NULL || Token->Event == NULL) {
   1500     return EFI_INVALID_PARAMETER;
   1501   }
   1502 
   1503   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
   1504   IpSb       = IpInstance->Service;
   1505 
   1506   if (IpSb->LinkLocalDadFail) {
   1507     return EFI_DEVICE_ERROR;
   1508   }
   1509 
   1510   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1511 
   1512   if (IpInstance->State != IP6_STATE_CONFIGED) {
   1513     Status = EFI_NOT_STARTED;
   1514     goto Exit;
   1515   }
   1516 
   1517   //
   1518   // Check whether the toke is already on the receive queue.
   1519   //
   1520   Status = NetMapIterate (&IpInstance->RxTokens, Ip6TokenExist, Token);
   1521 
   1522   if (EFI_ERROR (Status)) {
   1523     Status = EFI_ACCESS_DENIED;
   1524     goto Exit;
   1525   }
   1526 
   1527   //
   1528   // Queue the token then check whether there is pending received packet.
   1529   //
   1530   Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
   1531 
   1532   if (EFI_ERROR (Status)) {
   1533     goto Exit;
   1534   }
   1535 
   1536   Status = Ip6InstanceDeliverPacket (IpInstance);
   1537 
   1538   //
   1539   // Dispatch the DPC queued by the NotifyFunction of this instane's receive
   1540   // event.
   1541   //
   1542   DispatchDpc ();
   1543 
   1544 Exit:
   1545   gBS->RestoreTPL (OldTpl);
   1546   return Status;
   1547 }
   1548 
   1549 
   1550 /**
   1551   Cancel the transmitted but not recycled packet. If a matching
   1552   token is found, it will call Ip6CancelPacket to cancel the
   1553   packet. Ip6CancelPacket cancels all the fragments of the
   1554   packet. When all the fragments are freed, the IP6_TXTOKEN_WRAP
   1555   is deleted from the Map, and user's event is signalled.
   1556   Because Ip6CancelPacket and other functions are all called in
   1557   line, after Ip6CancelPacket returns, the Item has been freed.
   1558 
   1559   @param[in]  Map                The IP6 child's transmit queue.
   1560   @param[in]  Item               The current transmitted packet to test.
   1561   @param[in]  Context            The user's token to cancel.
   1562 
   1563   @retval EFI_SUCCESS            Continue to check the next Item.
   1564   @retval EFI_ABORTED            The user's Token (Token != NULL) is cancelled.
   1565 
   1566 **/
   1567 EFI_STATUS
   1568 EFIAPI
   1569 Ip6CancelTxTokens (
   1570   IN NET_MAP                *Map,
   1571   IN NET_MAP_ITEM           *Item,
   1572   IN VOID                   *Context
   1573   )
   1574 {
   1575   EFI_IP6_COMPLETION_TOKEN  *Token;
   1576   IP6_TXTOKEN_WRAP          *Wrap;
   1577 
   1578   Token = (EFI_IP6_COMPLETION_TOKEN *) Context;
   1579 
   1580   //
   1581   // Return EFI_SUCCESS to check the next item in the map if
   1582   // this one doesn't match.
   1583   //
   1584   if ((Token != NULL) && (Token != Item->Key)) {
   1585     return EFI_SUCCESS;
   1586   }
   1587 
   1588   Wrap = (IP6_TXTOKEN_WRAP *) Item->Value;
   1589   ASSERT (Wrap != NULL);
   1590 
   1591   //
   1592   // Don't access the Item, Wrap and Token's members after this point.
   1593   // Item and wrap has been freed. And we no longer own the Token.
   1594   //
   1595   Ip6CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
   1596 
   1597   //
   1598   // If only one item is to be cancel, return EFI_ABORTED to stop
   1599   // iterating the map any more.
   1600   //
   1601   if (Token != NULL) {
   1602     return EFI_ABORTED;
   1603   }
   1604 
   1605   return EFI_SUCCESS;
   1606 }
   1607 
   1608 
   1609 /**
   1610   Cancel the receive request. This is simple, because
   1611   it is only enqueued in our local receive map.
   1612 
   1613   @param[in]  Map                The IP6 child's receive queue.
   1614   @param[in]  Item               Current receive request to cancel.
   1615   @param[in]  Context            The user's token to cancel.
   1616 
   1617 
   1618   @retval EFI_SUCCESS            Continue to check the next receive request on the
   1619                                  queue.
   1620   @retval EFI_ABORTED            The user's token (token != NULL) has been
   1621                                  cancelled.
   1622 
   1623 **/
   1624 EFI_STATUS
   1625 EFIAPI
   1626 Ip6CancelRxTokens (
   1627   IN NET_MAP                *Map,
   1628   IN NET_MAP_ITEM           *Item,
   1629   IN VOID                   *Context
   1630   )
   1631 {
   1632   EFI_IP6_COMPLETION_TOKEN  *Token;
   1633   EFI_IP6_COMPLETION_TOKEN  *This;
   1634 
   1635   Token = (EFI_IP6_COMPLETION_TOKEN *) Context;
   1636   This  = Item->Key;
   1637 
   1638   if ((Token != NULL) && (Token != This)) {
   1639     return EFI_SUCCESS;
   1640   }
   1641 
   1642   NetMapRemoveItem (Map, Item, NULL);
   1643 
   1644   This->Status        = EFI_ABORTED;
   1645   This->Packet.RxData = NULL;
   1646   gBS->SignalEvent (This->Event);
   1647 
   1648   if (Token != NULL) {
   1649     return EFI_ABORTED;
   1650   }
   1651 
   1652   return EFI_SUCCESS;
   1653 }
   1654 
   1655 /**
   1656   Cancel the user's receive/transmit request. It is the worker function of
   1657   EfiIp6Cancel API.
   1658 
   1659   @param[in]  IpInstance         The IP6 child.
   1660   @param[in]  Token              The token to cancel. If NULL, all token will be
   1661                                  cancelled.
   1662 
   1663   @retval EFI_SUCCESS            The token is cancelled.
   1664   @retval EFI_NOT_FOUND          The token isn't found on either the
   1665                                  transmit/receive queue.
   1666   @retval EFI_DEVICE_ERROR       Not all tokens are cancelled when Token is NULL.
   1667 
   1668 **/
   1669 EFI_STATUS
   1670 Ip6Cancel (
   1671   IN IP6_PROTOCOL             *IpInstance,
   1672   IN EFI_IP6_COMPLETION_TOKEN *Token          OPTIONAL
   1673   )
   1674 {
   1675   EFI_STATUS                Status;
   1676 
   1677   //
   1678   // First check the transmitted packet. Ip6CancelTxTokens returns
   1679   // EFI_ABORTED to mean that the token has been cancelled when
   1680   // token != NULL. So, return EFI_SUCCESS for this condition.
   1681   //
   1682   Status = NetMapIterate (&IpInstance->TxTokens, Ip6CancelTxTokens, Token);
   1683   if (EFI_ERROR (Status)) {
   1684     if ((Token != NULL) && (Status == EFI_ABORTED)) {
   1685       return EFI_SUCCESS;
   1686     }
   1687 
   1688     return Status;
   1689   }
   1690 
   1691   //
   1692   // Check the receive queue. Ip6CancelRxTokens also returns EFI_ABORT
   1693   // for Token!=NULL and it is cancelled.
   1694   //
   1695   Status = NetMapIterate (&IpInstance->RxTokens, Ip6CancelRxTokens, Token);
   1696   //
   1697   // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
   1698   // events.
   1699   //
   1700   DispatchDpc ();
   1701   if (EFI_ERROR (Status)) {
   1702     if ((Token != NULL) && (Status == EFI_ABORTED)) {
   1703       return EFI_SUCCESS;
   1704     }
   1705 
   1706     return Status;
   1707   }
   1708 
   1709   //
   1710   // OK, if the Token is found when Token != NULL, the NetMapIterate
   1711   // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
   1712   //
   1713   if (Token != NULL) {
   1714     return EFI_NOT_FOUND;
   1715   }
   1716 
   1717   //
   1718   // If Token == NULL, cancel all the tokens. return error if not
   1719   // all of them are cancelled.
   1720   //
   1721   if (!NetMapIsEmpty (&IpInstance->TxTokens) || !NetMapIsEmpty (&IpInstance->RxTokens)) {
   1722 
   1723     return EFI_DEVICE_ERROR;
   1724   }
   1725 
   1726   return EFI_SUCCESS;
   1727 }
   1728 
   1729 /**
   1730   Abort an asynchronous transmit or receive request.
   1731 
   1732   The Cancel() function is used to abort a pending transmit or receive request.
   1733   If the token is in the transmit or receive request queues, after calling this
   1734   function, Token->Status will be set to EFI_ABORTED, and then Token->Event will
   1735   be signaled. If the token is not in one of the queues, which usually means the
   1736   asynchronous operation has completed, this function will not signal the token,
   1737   and EFI_NOT_FOUND is returned.
   1738 
   1739   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
   1740   @param[in]  Token              Pointer to a token that has been issued by
   1741                                  EFI_IP6_PROTOCOL.Transmit() or
   1742                                  EFI_IP6_PROTOCOL.Receive(). If NULL, all pending
   1743                                  tokens are aborted. Type EFI_IP6_COMPLETION_TOKEN is
   1744                                  defined in EFI_IP6_PROTOCOL.Transmit().
   1745 
   1746   @retval EFI_SUCCESS            The asynchronous I/O request was aborted and
   1747                                  Token->Event was signaled. When Token is NULL, all
   1748                                  pending requests were aborted, and their events were signaled.
   1749   @retval EFI_INVALID_PARAMETER  This is NULL.
   1750   @retval EFI_NOT_STARTED        This instance has not been started.
   1751   @retval EFI_NOT_FOUND          When Token is not NULL, the asynchronous I/O request was
   1752                                  not found in the transmit or receive queue. It has either completed
   1753                                  or was not issued by Transmit() and Receive().
   1754   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
   1755 
   1756 **/
   1757 EFI_STATUS
   1758 EFIAPI
   1759 EfiIp6Cancel (
   1760   IN EFI_IP6_PROTOCOL          *This,
   1761   IN EFI_IP6_COMPLETION_TOKEN  *Token    OPTIONAL
   1762   )
   1763 {
   1764   IP6_PROTOCOL              *IpInstance;
   1765   EFI_STATUS                Status;
   1766   EFI_TPL                   OldTpl;
   1767 
   1768   if (This == NULL) {
   1769     return EFI_INVALID_PARAMETER;
   1770   }
   1771 
   1772   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
   1773 
   1774   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1775 
   1776   if (IpInstance->State != IP6_STATE_CONFIGED) {
   1777     Status = EFI_NOT_STARTED;
   1778     goto Exit;
   1779   }
   1780 
   1781   Status = Ip6Cancel (IpInstance, Token);
   1782 
   1783 Exit:
   1784   gBS->RestoreTPL (OldTpl);
   1785   return Status;
   1786 }
   1787 
   1788 /**
   1789   Polls for incoming data packets, and processes outgoing data packets.
   1790 
   1791   The Poll() function polls for incoming data packets and processes outgoing data
   1792   packets. Network drivers and applications can call the EFI_IP6_PROTOCOL.Poll()
   1793   function to increase the rate that data packets are moved between the communications
   1794   device and the transmit and receive queues.
   1795 
   1796   In some systems the periodic timer event may not poll the underlying communications
   1797   device fast enough to transmit and/or receive all data packets without missing
   1798   incoming packets or dropping outgoing packets. Drivers and applications that are
   1799   experiencing packet loss should try calling the EFI_IP6_PROTOCOL.Poll() function
   1800   more often.
   1801 
   1802   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
   1803 
   1804   @retval  EFI_SUCCESS           Incoming or outgoing data was processed.
   1805   @retval  EFI_NOT_STARTED       This EFI IPv6 Protocol instance has not been started.
   1806   @retval  EFI_INVALID_PARAMETER This is NULL.
   1807   @retval  EFI_DEVICE_ERROR      An unexpected system error or network error occurred.
   1808   @retval  EFI_NOT_READY         No incoming or outgoing data was processed.
   1809   @retval  EFI_TIMEOUT           Data was dropped out of the transmit and/or receive queue.
   1810                                  Consider increasing the polling rate.
   1811 
   1812 **/
   1813 EFI_STATUS
   1814 EFIAPI
   1815 EfiIp6Poll (
   1816   IN EFI_IP6_PROTOCOL          *This
   1817   )
   1818 {
   1819   IP6_PROTOCOL                  *IpInstance;
   1820   IP6_SERVICE                   *IpSb;
   1821   EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;
   1822 
   1823   if (This == NULL) {
   1824     return EFI_INVALID_PARAMETER;
   1825   }
   1826 
   1827   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
   1828   IpSb       = IpInstance->Service;
   1829 
   1830   if (IpSb->LinkLocalDadFail) {
   1831     return EFI_DEVICE_ERROR;
   1832   }
   1833 
   1834   if (IpInstance->State == IP6_STATE_UNCONFIGED) {
   1835     return EFI_NOT_STARTED;
   1836   }
   1837 
   1838   Mnp = IpInstance->Service->Mnp;
   1839 
   1840   //
   1841   // Don't lock the Poll function to enable the deliver of
   1842   // the packet polled up.
   1843   //
   1844   return Mnp->Poll (Mnp);
   1845 
   1846 }
   1847 
   1848