Home | History | Annotate | Download | only in DxeIpIoLib
      1 /** @file
      2   IpIo Library.
      3 
      4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
      5 Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
      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 #include <Uefi.h>
     16 
     17 #include <Protocol/Udp4.h>
     18 
     19 #include <Library/IpIoLib.h>
     20 #include <Library/BaseLib.h>
     21 #include <Library/DebugLib.h>
     22 #include <Library/BaseMemoryLib.h>
     23 #include <Library/UefiBootServicesTableLib.h>
     24 #include <Library/MemoryAllocationLib.h>
     25 #include <Library/DpcLib.h>
     26 
     27 
     28 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY  mActiveIpIoList = {
     29   &mActiveIpIoList,
     30   &mActiveIpIoList
     31 };
     32 
     33 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA  mIp4IoDefaultIpConfigData = {
     34   EFI_IP_PROTO_UDP,
     35   FALSE,
     36   TRUE,
     37   FALSE,
     38   FALSE,
     39   FALSE,
     40   {{0, 0, 0, 0}},
     41   {{0, 0, 0, 0}},
     42   0,
     43   255,
     44   FALSE,
     45   FALSE,
     46   0,
     47   0
     48 };
     49 
     50 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA  mIp6IoDefaultIpConfigData = {
     51   EFI_IP_PROTO_UDP,
     52   FALSE,
     53   TRUE,
     54   FALSE,
     55   {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
     56   {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
     57   0,
     58   255,
     59   0,
     60   0,
     61   0
     62 };
     63 
     64 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO  mIcmpErrMap[10] = {
     65   {FALSE, TRUE }, // ICMP_ERR_UNREACH_NET
     66   {FALSE, TRUE }, // ICMP_ERR_UNREACH_HOST
     67   {TRUE,  TRUE }, // ICMP_ERR_UNREACH_PROTOCOL
     68   {TRUE,  TRUE }, // ICMP_ERR_UNREACH_PORT
     69   {TRUE,  TRUE }, // ICMP_ERR_MSGSIZE
     70   {FALSE, TRUE }, // ICMP_ERR_UNREACH_SRCFAIL
     71   {FALSE, TRUE }, // ICMP_ERR_TIMXCEED_INTRANS
     72   {FALSE, TRUE }, // ICMP_ERR_TIMEXCEED_REASS
     73   {FALSE, FALSE}, // ICMP_ERR_QUENCH
     74   {FALSE, TRUE }  // ICMP_ERR_PARAMPROB
     75 };
     76 
     77 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO  mIcmp6ErrMap[10] = {
     78   {FALSE, TRUE}, // ICMP6_ERR_UNREACH_NET
     79   {FALSE, TRUE}, // ICMP6_ERR_UNREACH_HOST
     80   {TRUE,  TRUE}, // ICMP6_ERR_UNREACH_PROTOCOL
     81   {TRUE,  TRUE}, // ICMP6_ERR_UNREACH_PORT
     82   {TRUE,  TRUE}, // ICMP6_ERR_PACKAGE_TOOBIG
     83   {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_HOPLIMIT
     84   {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_REASS
     85   {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_HEADER
     86   {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_NEXHEADER
     87   {FALSE, TRUE}  // ICMP6_ERR_PARAMPROB_IPV6OPTION
     88 };
     89 
     90 
     91 /**
     92   Notify function for IP transmit token.
     93 
     94   @param[in]  Context               The context passed in by the event notifier.
     95 
     96 **/
     97 VOID
     98 EFIAPI
     99 IpIoTransmitHandlerDpc (
    100   IN VOID      *Context
    101   );
    102 
    103 
    104 /**
    105   Notify function for IP transmit token.
    106 
    107   @param[in]  Event                 The event signaled.
    108   @param[in]  Context               The context passed in by the event notifier.
    109 
    110 **/
    111 VOID
    112 EFIAPI
    113 IpIoTransmitHandler (
    114   IN EFI_EVENT Event,
    115   IN VOID      *Context
    116   );
    117 
    118 
    119 /**
    120   This function create an IP child ,open the IP protocol, and return the opened
    121   IP protocol as Interface.
    122 
    123   @param[in]    ControllerHandle   The controller handle.
    124   @param[in]    ImageHandle        The image handle.
    125   @param[in]    ChildHandle        Pointer to the buffer to save the IP child handle.
    126   @param[in]    IpVersion          The version of the IP protocol to use, either
    127                                    IPv4 or IPv6.
    128   @param[out]   Interface          Pointer used to get the IP protocol interface.
    129 
    130   @retval       EFI_SUCCESS        The IP child is created and the IP protocol
    131                                    interface is retrieved.
    132   @retval       Others             The required operation failed.
    133 
    134 **/
    135 EFI_STATUS
    136 IpIoCreateIpChildOpenProtocol (
    137   IN  EFI_HANDLE  ControllerHandle,
    138   IN  EFI_HANDLE  ImageHandle,
    139   IN  EFI_HANDLE  *ChildHandle,
    140   IN  UINT8       IpVersion,
    141   OUT VOID        **Interface
    142   )
    143 {
    144   EFI_STATUS  Status;
    145   EFI_GUID    *ServiceBindingGuid;
    146   EFI_GUID    *IpProtocolGuid;
    147 
    148   if (IpVersion == IP_VERSION_4) {
    149     ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;
    150     IpProtocolGuid     = &gEfiIp4ProtocolGuid;
    151   } else if (IpVersion == IP_VERSION_6){
    152     ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;
    153     IpProtocolGuid     = &gEfiIp6ProtocolGuid;
    154   } else {
    155     return EFI_UNSUPPORTED;
    156   }
    157 
    158   //
    159   // Create an IP child.
    160   //
    161   Status = NetLibCreateServiceChild (
    162              ControllerHandle,
    163              ImageHandle,
    164              ServiceBindingGuid,
    165              ChildHandle
    166              );
    167   if (EFI_ERROR (Status)) {
    168     return Status;
    169   }
    170 
    171   //
    172   // Open the IP protocol installed on the *ChildHandle.
    173   //
    174   Status = gBS->OpenProtocol (
    175                   *ChildHandle,
    176                   IpProtocolGuid,
    177                   Interface,
    178                   ImageHandle,
    179                   ControllerHandle,
    180                   EFI_OPEN_PROTOCOL_BY_DRIVER
    181                   );
    182   if (EFI_ERROR (Status)) {
    183     //
    184     // On failure, destroy the IP child.
    185     //
    186     NetLibDestroyServiceChild (
    187       ControllerHandle,
    188       ImageHandle,
    189       ServiceBindingGuid,
    190       *ChildHandle
    191       );
    192   }
    193 
    194   return Status;
    195 }
    196 
    197 
    198 /**
    199   This function close the previously openned IP protocol and destroy the IP child.
    200 
    201   @param[in]  ControllerHandle    The controller handle.
    202   @param[in]  ImageHandle         The image handle.
    203   @param[in]  ChildHandle         The child handle of the IP child.
    204   @param[in]  IpVersion           The version of the IP protocol to use, either
    205                                   IPv4 or IPv6.
    206 
    207   @retval     EFI_SUCCESS         The IP protocol is closed and the relevant IP child
    208                                   is destroyed.
    209   @retval     Others              The required operation failed.
    210 
    211 **/
    212 EFI_STATUS
    213 IpIoCloseProtocolDestroyIpChild (
    214   IN EFI_HANDLE  ControllerHandle,
    215   IN EFI_HANDLE  ImageHandle,
    216   IN EFI_HANDLE  ChildHandle,
    217   IN UINT8       IpVersion
    218   )
    219 {
    220   EFI_STATUS  Status;
    221   EFI_GUID    *ServiceBindingGuid;
    222   EFI_GUID    *IpProtocolGuid;
    223 
    224   if (IpVersion == IP_VERSION_4) {
    225     ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;
    226     IpProtocolGuid     = &gEfiIp4ProtocolGuid;
    227   } else if (IpVersion == IP_VERSION_6) {
    228     ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;
    229     IpProtocolGuid     = &gEfiIp6ProtocolGuid;
    230   } else {
    231     return EFI_UNSUPPORTED;
    232   }
    233 
    234   //
    235   // Close the previously openned IP protocol.
    236   //
    237   gBS->CloseProtocol (
    238          ChildHandle,
    239          IpProtocolGuid,
    240          ImageHandle,
    241          ControllerHandle
    242          );
    243 
    244   //
    245   // Destroy the IP child.
    246   //
    247   Status = NetLibDestroyServiceChild (
    248              ControllerHandle,
    249              ImageHandle,
    250              ServiceBindingGuid,
    251              ChildHandle
    252              );
    253 
    254   return Status;
    255 }
    256 
    257 /**
    258   This function handles ICMPv4 packets. It is the worker function of
    259   IpIoIcmpHandler.
    260 
    261   @param[in]       IpIo            Pointer to the IP_IO instance.
    262   @param[in, out]  Pkt             Pointer to the ICMPv4 packet.
    263   @param[in]       Session         Pointer to the net session of this ICMPv4 packet.
    264 
    265   @retval          EFI_SUCCESS     The ICMPv4 packet is handled successfully.
    266   @retval          EFI_ABORTED     This type of ICMPv4 packet is not supported.
    267 
    268 **/
    269 EFI_STATUS
    270 IpIoIcmpv4Handler (
    271   IN     IP_IO                *IpIo,
    272   IN OUT NET_BUF              *Pkt,
    273   IN     EFI_NET_SESSION_DATA *Session
    274   )
    275 {
    276   IP4_ICMP_ERROR_HEAD  *IcmpHdr;
    277   EFI_IP4_HEADER       *IpHdr;
    278   UINT8                IcmpErr;
    279   UINT8                *PayLoadHdr;
    280   UINT8                Type;
    281   UINT8                Code;
    282   UINT32               TrimBytes;
    283 
    284   ASSERT (IpIo->IpVersion == IP_VERSION_4);
    285 
    286   IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);
    287   IpHdr   = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);
    288 
    289   //
    290   // Check the ICMP packet length.
    291   //
    292   if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) {
    293 
    294     return EFI_ABORTED;
    295   }
    296 
    297   Type = IcmpHdr->Head.Type;
    298   Code = IcmpHdr->Head.Code;
    299 
    300   //
    301   // Analyze the ICMP Error in this ICMP pkt
    302   //
    303   switch (Type) {
    304   case ICMP_TYPE_UNREACH:
    305     switch (Code) {
    306     case ICMP_CODE_UNREACH_NET:
    307     case ICMP_CODE_UNREACH_HOST:
    308     case ICMP_CODE_UNREACH_PROTOCOL:
    309     case ICMP_CODE_UNREACH_PORT:
    310     case ICMP_CODE_UNREACH_SRCFAIL:
    311       IcmpErr = (UINT8) (ICMP_ERR_UNREACH_NET + Code);
    312 
    313       break;
    314 
    315     case ICMP_CODE_UNREACH_NEEDFRAG:
    316       IcmpErr = ICMP_ERR_MSGSIZE;
    317 
    318       break;
    319 
    320     case ICMP_CODE_UNREACH_NET_UNKNOWN:
    321     case ICMP_CODE_UNREACH_NET_PROHIB:
    322     case ICMP_CODE_UNREACH_TOSNET:
    323       IcmpErr = ICMP_ERR_UNREACH_NET;
    324 
    325       break;
    326 
    327     case ICMP_CODE_UNREACH_HOST_UNKNOWN:
    328     case ICMP_CODE_UNREACH_ISOLATED:
    329     case ICMP_CODE_UNREACH_HOST_PROHIB:
    330     case ICMP_CODE_UNREACH_TOSHOST:
    331       IcmpErr = ICMP_ERR_UNREACH_HOST;
    332 
    333       break;
    334 
    335     default:
    336       return EFI_ABORTED;
    337     }
    338 
    339     break;
    340 
    341   case ICMP_TYPE_TIMXCEED:
    342     if (Code > 1) {
    343       return EFI_ABORTED;
    344     }
    345 
    346     IcmpErr = (UINT8) (Code + ICMP_ERR_TIMXCEED_INTRANS);
    347 
    348     break;
    349 
    350   case ICMP_TYPE_PARAMPROB:
    351     if (Code > 1) {
    352       return EFI_ABORTED;
    353     }
    354 
    355     IcmpErr = ICMP_ERR_PARAMPROB;
    356 
    357     break;
    358 
    359   case ICMP_TYPE_SOURCEQUENCH:
    360     if (Code != 0) {
    361       return EFI_ABORTED;
    362     }
    363 
    364     IcmpErr = ICMP_ERR_QUENCH;
    365 
    366     break;
    367 
    368   default:
    369     return EFI_ABORTED;
    370   }
    371 
    372   //
    373   // Notify user the ICMP pkt only containing payload except
    374   // IP and ICMP header
    375   //
    376   PayLoadHdr = (UINT8 *) ((UINT8 *) IpHdr + EFI_IP4_HEADER_LEN (IpHdr));
    377   TrimBytes  = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
    378 
    379   NetbufTrim (Pkt, TrimBytes, TRUE);
    380 
    381   IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
    382 
    383   return EFI_SUCCESS;
    384 }
    385 
    386 /**
    387   This function handles ICMPv6 packets. It is the worker function of
    388   IpIoIcmpHandler.
    389 
    390   @param[in]       IpIo            Pointer to the IP_IO instance.
    391   @param[in, out]  Pkt             Pointer to the ICMPv6 packet.
    392   @param[in]       Session         Pointer to the net session of this ICMPv6 packet.
    393 
    394   @retval          EFI_SUCCESS     The ICMPv6 packet is handled successfully.
    395   @retval          EFI_ABORTED     This type of ICMPv6 packet is not supported.
    396 
    397 **/
    398 EFI_STATUS
    399 IpIoIcmpv6Handler (
    400   IN     IP_IO                *IpIo,
    401   IN OUT NET_BUF              *Pkt,
    402   IN     EFI_NET_SESSION_DATA *Session
    403   )
    404 {
    405   IP6_ICMP_ERROR_HEAD  *IcmpHdr;
    406   EFI_IP6_HEADER       *IpHdr;
    407   UINT8                IcmpErr;
    408   UINT8                *PayLoadHdr;
    409   UINT8                Type;
    410   UINT8                Code;
    411   UINT8                NextHeader;
    412   UINT32               TrimBytes;
    413   BOOLEAN              Flag;
    414 
    415   ASSERT (IpIo->IpVersion == IP_VERSION_6);
    416 
    417   //
    418   // Check the ICMPv6 packet length.
    419   //
    420   if (Pkt->TotalSize < sizeof (IP6_ICMP_ERROR_HEAD)) {
    421 
    422     return EFI_ABORTED;
    423   }
    424 
    425   IcmpHdr = NET_PROTO_HDR (Pkt, IP6_ICMP_ERROR_HEAD);
    426   Type    = IcmpHdr->Head.Type;
    427   Code    = IcmpHdr->Head.Code;
    428 
    429   //
    430   // Analyze the ICMPv6 Error in this ICMPv6 packet
    431   //
    432   switch (Type) {
    433   case ICMP_V6_DEST_UNREACHABLE:
    434     switch (Code) {
    435     case ICMP_V6_NO_ROUTE_TO_DEST:
    436     case ICMP_V6_BEYOND_SCOPE:
    437     case ICMP_V6_ROUTE_REJECTED:
    438       IcmpErr = ICMP6_ERR_UNREACH_NET;
    439 
    440       break;
    441 
    442     case ICMP_V6_COMM_PROHIBITED:
    443     case ICMP_V6_ADDR_UNREACHABLE:
    444     case ICMP_V6_SOURCE_ADDR_FAILED:
    445       IcmpErr = ICMP6_ERR_UNREACH_HOST;
    446 
    447       break;
    448 
    449     case ICMP_V6_PORT_UNREACHABLE:
    450       IcmpErr = ICMP6_ERR_UNREACH_PORT;
    451 
    452       break;
    453 
    454      default:
    455       return EFI_ABORTED;
    456     }
    457 
    458     break;
    459 
    460   case ICMP_V6_PACKET_TOO_BIG:
    461     if (Code >= 1) {
    462       return EFI_ABORTED;
    463     }
    464 
    465     IcmpErr = ICMP6_ERR_PACKAGE_TOOBIG;
    466 
    467     break;
    468 
    469   case ICMP_V6_TIME_EXCEEDED:
    470     if (Code > 1) {
    471       return EFI_ABORTED;
    472     }
    473 
    474     IcmpErr = (UINT8) (ICMP6_ERR_TIMXCEED_HOPLIMIT + Code);
    475 
    476     break;
    477 
    478   case ICMP_V6_PARAMETER_PROBLEM:
    479     if (Code > 3) {
    480       return EFI_ABORTED;
    481     }
    482 
    483     IcmpErr = (UINT8) (ICMP6_ERR_PARAMPROB_HEADER + Code);
    484 
    485     break;
    486 
    487    default:
    488 
    489      return EFI_ABORTED;
    490    }
    491 
    492   //
    493   // Notify user the ICMPv6 packet only containing payload except
    494   // IPv6 basic header, extension header and ICMP header
    495   //
    496 
    497   IpHdr      = (EFI_IP6_HEADER *) (&IcmpHdr->IpHead);
    498   NextHeader = IpHdr->NextHeader;
    499   PayLoadHdr = (UINT8 *) ((UINT8 *) IcmpHdr + sizeof (IP6_ICMP_ERROR_HEAD));
    500   Flag       = TRUE;
    501 
    502   do {
    503     switch (NextHeader) {
    504     case EFI_IP_PROTO_UDP:
    505     case EFI_IP_PROTO_TCP:
    506     case EFI_IP_PROTO_ICMP:
    507     case IP6_NO_NEXT_HEADER:
    508       Flag = FALSE;
    509 
    510       break;
    511 
    512     case IP6_HOP_BY_HOP:
    513     case IP6_DESTINATION:
    514       //
    515       // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including
    516       // the first 8 octets.
    517       //
    518       NextHeader = *(PayLoadHdr);
    519       PayLoadHdr = (UINT8 *) (PayLoadHdr + (*(PayLoadHdr + 1) + 1) * 8);
    520 
    521       break;
    522 
    523     case IP6_FRAGMENT:
    524       //
    525       // The Fragment Header Length is 8 octets.
    526       //
    527       NextHeader = *(PayLoadHdr);
    528       PayLoadHdr = (UINT8 *) (PayLoadHdr + 8);
    529 
    530       break;
    531 
    532     default:
    533 
    534       return EFI_ABORTED;
    535     }
    536   } while (Flag);
    537 
    538   TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
    539 
    540   NetbufTrim (Pkt, TrimBytes, TRUE);
    541 
    542   IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
    543 
    544   return EFI_SUCCESS;
    545 }
    546 
    547 /**
    548   This function handles ICMP packets.
    549 
    550   @param[in]       IpIo            Pointer to the IP_IO instance.
    551   @param[in, out]  Pkt             Pointer to the ICMP packet.
    552   @param[in]       Session         Pointer to the net session of this ICMP packet.
    553 
    554   @retval          EFI_SUCCESS     The ICMP packet is handled successfully.
    555   @retval          EFI_ABORTED     This type of ICMP packet is not supported.
    556   @retval          EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported.
    557 
    558 **/
    559 EFI_STATUS
    560 IpIoIcmpHandler (
    561   IN     IP_IO                *IpIo,
    562   IN OUT NET_BUF              *Pkt,
    563   IN     EFI_NET_SESSION_DATA *Session
    564   )
    565 {
    566 
    567   if (IpIo->IpVersion == IP_VERSION_4) {
    568 
    569     return IpIoIcmpv4Handler (IpIo, Pkt, Session);
    570 
    571   } else if (IpIo->IpVersion == IP_VERSION_6) {
    572 
    573     return IpIoIcmpv6Handler (IpIo, Pkt, Session);
    574 
    575   } else {
    576 
    577     return EFI_UNSUPPORTED;
    578   }
    579 }
    580 
    581 
    582 /**
    583   Free function for receive token of IP_IO. It is used to
    584   signal the recycle event to notify IP to recycle the
    585   data buffer.
    586 
    587   @param[in]  Event                 The event to be signaled.
    588 
    589 **/
    590 VOID
    591 EFIAPI
    592 IpIoExtFree (
    593   IN VOID  *Event
    594   )
    595 {
    596   gBS->SignalEvent ((EFI_EVENT) Event);
    597 }
    598 
    599 
    600 /**
    601   Create a send entry to wrap a packet before sending
    602   out it through IP.
    603 
    604   @param[in, out]  IpIo                 Pointer to the IP_IO instance.
    605   @param[in, out]  Pkt                  Pointer to the packet.
    606   @param[in]       Sender               Pointer to the IP sender.
    607   @param[in]       Context              Pointer to the context.
    608   @param[in]       NotifyData           Pointer to the notify data.
    609   @param[in]       Dest                 Pointer to the destination IP address.
    610   @param[in]       Override             Pointer to the overriden IP_IO data.
    611 
    612   @return Pointer to the data structure created to wrap the packet. If NULL,
    613   @return resource limit occurred.
    614 
    615 **/
    616 IP_IO_SEND_ENTRY *
    617 IpIoCreateSndEntry (
    618   IN OUT IP_IO             *IpIo,
    619   IN OUT NET_BUF           *Pkt,
    620   IN     IP_IO_IP_PROTOCOL Sender,
    621   IN     VOID              *Context    OPTIONAL,
    622   IN     VOID              *NotifyData OPTIONAL,
    623   IN     EFI_IP_ADDRESS    *Dest       OPTIONAL,
    624   IN     IP_IO_OVERRIDE    *Override
    625   )
    626 {
    627   IP_IO_SEND_ENTRY          *SndEntry;
    628   EFI_EVENT                 Event;
    629   EFI_STATUS                Status;
    630   NET_FRAGMENT              *ExtFragment;
    631   UINT32                    FragmentCount;
    632   IP_IO_OVERRIDE            *OverrideData;
    633   IP_IO_IP_TX_DATA          *TxData;
    634   EFI_IP4_TRANSMIT_DATA     *Ip4TxData;
    635   EFI_IP6_TRANSMIT_DATA     *Ip6TxData;
    636 
    637   if ((IpIo->IpVersion != IP_VERSION_4) && (IpIo->IpVersion != IP_VERSION_6)) {
    638     return NULL;
    639   }
    640 
    641   Event        = NULL;
    642   TxData       = NULL;
    643   OverrideData = NULL;
    644 
    645   //
    646   // Allocate resource for SndEntry
    647   //
    648   SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));
    649   if (NULL == SndEntry) {
    650     return NULL;
    651   }
    652 
    653   Status = gBS->CreateEvent (
    654                   EVT_NOTIFY_SIGNAL,
    655                   TPL_NOTIFY,
    656                   IpIoTransmitHandler,
    657                   SndEntry,
    658                   &Event
    659                   );
    660   if (EFI_ERROR (Status)) {
    661     goto ON_ERROR;
    662   }
    663 
    664   FragmentCount = Pkt->BlockOpNum;
    665 
    666   //
    667   // Allocate resource for TxData
    668   //
    669   TxData = (IP_IO_IP_TX_DATA *) AllocatePool (
    670     sizeof (IP_IO_IP_TX_DATA) + sizeof (NET_FRAGMENT) * (FragmentCount - 1)
    671     );
    672 
    673   if (NULL == TxData) {
    674     goto ON_ERROR;
    675   }
    676 
    677   //
    678   // Build a fragment table to contain the fragments in the packet.
    679   //
    680   if (IpIo->IpVersion == IP_VERSION_4) {
    681     ExtFragment = (NET_FRAGMENT *) TxData->Ip4TxData.FragmentTable;
    682   } else {
    683     ExtFragment = (NET_FRAGMENT *) TxData->Ip6TxData.FragmentTable;
    684   }
    685 
    686   NetbufBuildExt (Pkt, ExtFragment, &FragmentCount);
    687 
    688 
    689   //
    690   // Allocate resource for OverrideData if needed
    691   //
    692   if (NULL != Override) {
    693 
    694     OverrideData = AllocateCopyPool (sizeof (IP_IO_OVERRIDE), Override);
    695     if (NULL == OverrideData) {
    696       goto ON_ERROR;
    697     }
    698   }
    699 
    700   //
    701   // Set other fields of TxData except the fragment table
    702   //
    703   if (IpIo->IpVersion == IP_VERSION_4) {
    704 
    705     Ip4TxData = &TxData->Ip4TxData;
    706 
    707     IP4_COPY_ADDRESS (&Ip4TxData->DestinationAddress, Dest);
    708 
    709     Ip4TxData->OverrideData    = &OverrideData->Ip4OverrideData;
    710     Ip4TxData->OptionsLength   = 0;
    711     Ip4TxData->OptionsBuffer   = NULL;
    712     Ip4TxData->TotalDataLength = Pkt->TotalSize;
    713     Ip4TxData->FragmentCount   = FragmentCount;
    714 
    715     //
    716     // Set the fields of SndToken
    717     //
    718     SndEntry->SndToken.Ip4Token.Event         = Event;
    719     SndEntry->SndToken.Ip4Token.Packet.TxData = Ip4TxData;
    720   } else {
    721 
    722     Ip6TxData = &TxData->Ip6TxData;
    723 
    724     if (Dest != NULL) {
    725       CopyMem (&Ip6TxData->DestinationAddress, Dest, sizeof (EFI_IPv6_ADDRESS));
    726     } else {
    727       ZeroMem (&Ip6TxData->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));
    728     }
    729 
    730     Ip6TxData->OverrideData  = &OverrideData->Ip6OverrideData;
    731     Ip6TxData->DataLength    = Pkt->TotalSize;
    732     Ip6TxData->FragmentCount = FragmentCount;
    733     Ip6TxData->ExtHdrsLength = 0;
    734     Ip6TxData->ExtHdrs       = NULL;
    735 
    736     //
    737     // Set the fields of SndToken
    738     //
    739     SndEntry->SndToken.Ip6Token.Event         = Event;
    740     SndEntry->SndToken.Ip6Token.Packet.TxData = Ip6TxData;
    741   }
    742 
    743   //
    744   // Set the fields of SndEntry
    745   //
    746   SndEntry->IpIo        = IpIo;
    747   SndEntry->Ip          = Sender;
    748   SndEntry->Context     = Context;
    749   SndEntry->NotifyData  = NotifyData;
    750 
    751   SndEntry->Pkt         = Pkt;
    752   NET_GET_REF (Pkt);
    753 
    754   InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);
    755 
    756   return SndEntry;
    757 
    758 ON_ERROR:
    759 
    760   if (OverrideData != NULL) {
    761     FreePool (OverrideData);
    762   }
    763 
    764   if (TxData != NULL) {
    765     FreePool (TxData);
    766   }
    767 
    768   if (SndEntry != NULL) {
    769     FreePool (SndEntry);
    770   }
    771 
    772   if (Event != NULL) {
    773     gBS->CloseEvent (Event);
    774   }
    775 
    776   return NULL;
    777 }
    778 
    779 
    780 /**
    781   Destroy the SndEntry.
    782 
    783   This function pairs with IpIoCreateSndEntry().
    784 
    785   @param[in]  SndEntry              Pointer to the send entry to be destroyed.
    786 
    787 **/
    788 VOID
    789 IpIoDestroySndEntry (
    790   IN IP_IO_SEND_ENTRY  *SndEntry
    791   )
    792 {
    793   EFI_EVENT         Event;
    794   IP_IO_IP_TX_DATA  *TxData;
    795   IP_IO_OVERRIDE    *Override;
    796 
    797   if (SndEntry->IpIo->IpVersion == IP_VERSION_4) {
    798     Event              = SndEntry->SndToken.Ip4Token.Event;
    799     TxData             = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip4Token.Packet.TxData;
    800     Override           = (IP_IO_OVERRIDE *) TxData->Ip4TxData.OverrideData;
    801   } else if (SndEntry->IpIo->IpVersion == IP_VERSION_6) {
    802     Event              = SndEntry->SndToken.Ip6Token.Event;
    803     TxData             = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip6Token.Packet.TxData;
    804     Override           = (IP_IO_OVERRIDE *) TxData->Ip6TxData.OverrideData;
    805   } else {
    806     return ;
    807   }
    808 
    809   gBS->CloseEvent (Event);
    810 
    811   FreePool (TxData);
    812 
    813   if (NULL != Override) {
    814     FreePool (Override);
    815   }
    816 
    817   NetbufFree (SndEntry->Pkt);
    818 
    819   RemoveEntryList (&SndEntry->Entry);
    820 
    821   FreePool (SndEntry);
    822 }
    823 
    824 
    825 /**
    826   Notify function for IP transmit token.
    827 
    828   @param[in]  Context               The context passed in by the event notifier.
    829 
    830 **/
    831 VOID
    832 EFIAPI
    833 IpIoTransmitHandlerDpc (
    834   IN VOID      *Context
    835   )
    836 {
    837   IP_IO             *IpIo;
    838   IP_IO_SEND_ENTRY  *SndEntry;
    839   EFI_STATUS        Status;
    840 
    841   SndEntry  = (IP_IO_SEND_ENTRY *) Context;
    842 
    843   IpIo      = SndEntry->IpIo;
    844 
    845   if (IpIo->IpVersion == IP_VERSION_4) {
    846     Status = SndEntry->SndToken.Ip4Token.Status;
    847   } else if (IpIo->IpVersion == IP_VERSION_6){
    848     Status = SndEntry->SndToken.Ip6Token.Status;
    849   } else {
    850     return ;
    851   }
    852 
    853   if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) {
    854     IpIo->PktSentNotify (
    855             Status,
    856             SndEntry->Context,
    857             SndEntry->Ip,
    858             SndEntry->NotifyData
    859             );
    860   }
    861 
    862   IpIoDestroySndEntry (SndEntry);
    863 }
    864 
    865 
    866 /**
    867   Notify function for IP transmit token.
    868 
    869   @param[in]  Event                 The event signaled.
    870   @param[in]  Context               The context passed in by the event notifier.
    871 
    872 **/
    873 VOID
    874 EFIAPI
    875 IpIoTransmitHandler (
    876   IN EFI_EVENT Event,
    877   IN VOID      *Context
    878   )
    879 {
    880   //
    881   // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
    882   //
    883   QueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);
    884 }
    885 
    886 
    887 /**
    888   The dummy handler for the dummy IP receive token.
    889 
    890   @param[in]  Context               The context passed in by the event notifier.
    891 
    892 **/
    893 VOID
    894 EFIAPI
    895 IpIoDummyHandlerDpc (
    896   IN VOID      *Context
    897   )
    898 {
    899   IP_IO_IP_INFO             *IpInfo;
    900   EFI_STATUS                 Status;
    901   EFI_EVENT                  RecycleEvent;
    902 
    903   IpInfo      = (IP_IO_IP_INFO *) Context;
    904 
    905   if ((IpInfo->IpVersion != IP_VERSION_4) && (IpInfo->IpVersion != IP_VERSION_6)) {
    906     return ;
    907   }
    908 
    909   RecycleEvent = NULL;
    910 
    911   if (IpInfo->IpVersion == IP_VERSION_4) {
    912     Status = IpInfo->DummyRcvToken.Ip4Token.Status;
    913 
    914     if (IpInfo->DummyRcvToken.Ip4Token.Packet.RxData != NULL) {
    915       RecycleEvent = IpInfo->DummyRcvToken.Ip4Token.Packet.RxData->RecycleSignal;
    916     }
    917   } else {
    918     Status = IpInfo->DummyRcvToken.Ip6Token.Status;
    919 
    920     if (IpInfo->DummyRcvToken.Ip6Token.Packet.RxData != NULL) {
    921       RecycleEvent = IpInfo->DummyRcvToken.Ip6Token.Packet.RxData->RecycleSignal;
    922     }
    923   }
    924 
    925 
    926 
    927   if (EFI_ABORTED == Status) {
    928     //
    929     // The reception is actively aborted by the consumer, directly return.
    930     //
    931     return;
    932   } else if (EFI_SUCCESS == Status) {
    933     //
    934     // Recycle the RxData.
    935     //
    936     ASSERT (RecycleEvent != NULL);
    937 
    938     gBS->SignalEvent (RecycleEvent);
    939   }
    940 
    941   //
    942   // Continue the receive.
    943   //
    944   if (IpInfo->IpVersion == IP_VERSION_4) {
    945     IpInfo->Ip.Ip4->Receive (
    946                       IpInfo->Ip.Ip4,
    947                       &IpInfo->DummyRcvToken.Ip4Token
    948                       );
    949   } else {
    950     IpInfo->Ip.Ip6->Receive (
    951                       IpInfo->Ip.Ip6,
    952                       &IpInfo->DummyRcvToken.Ip6Token
    953                       );
    954   }
    955 }
    956 
    957 
    958 /**
    959   This function add IpIoDummyHandlerDpc to the end of the DPC queue.
    960 
    961   @param[in]  Event                 The event signaled.
    962   @param[in]  Context               The context passed in by the event notifier.
    963 
    964 **/
    965 VOID
    966 EFIAPI
    967 IpIoDummyHandler (
    968   IN EFI_EVENT Event,
    969   IN VOID      *Context
    970   )
    971 {
    972   //
    973   // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
    974   //
    975   QueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);
    976 }
    977 
    978 
    979 /**
    980   Notify function for the IP receive token, used to process
    981   the received IP packets.
    982 
    983   @param[in]  Context               The context passed in by the event notifier.
    984 
    985 **/
    986 VOID
    987 EFIAPI
    988 IpIoListenHandlerDpc (
    989   IN VOID      *Context
    990   )
    991 {
    992   IP_IO                 *IpIo;
    993   EFI_STATUS            Status;
    994   IP_IO_IP_RX_DATA      *RxData;
    995   EFI_NET_SESSION_DATA  Session;
    996   NET_BUF               *Pkt;
    997 
    998   IpIo = (IP_IO *) Context;
    999 
   1000   if (IpIo->IpVersion == IP_VERSION_4) {
   1001     Status = IpIo->RcvToken.Ip4Token.Status;
   1002     RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip4Token.Packet.RxData;
   1003   } else if (IpIo->IpVersion == IP_VERSION_6) {
   1004     Status = IpIo->RcvToken.Ip6Token.Status;
   1005     RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip6Token.Packet.RxData;
   1006   } else {
   1007     return;
   1008   }
   1009 
   1010   if (EFI_ABORTED == Status) {
   1011     //
   1012     // The reception is actively aborted by the consumer, directly return.
   1013     //
   1014     return;
   1015   }
   1016 
   1017   if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {
   1018     //
   1019     // @bug Only process the normal packets and the icmp error packets, if RxData is NULL
   1020     // @bug with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although
   1021     // @bug this should be a bug of the low layer (IP).
   1022     //
   1023     goto Resume;
   1024   }
   1025 
   1026   if (NULL == IpIo->PktRcvdNotify) {
   1027     goto CleanUp;
   1028   }
   1029 
   1030   if (IpIo->IpVersion == IP_VERSION_4) {
   1031     if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) &&
   1032         (IpIo->SubnetMask != 0) &&
   1033         IP4_NET_EQUAL (IpIo->StationIp, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask) &&
   1034         !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask)) {
   1035       //
   1036       // The source address is not zero and it's not a unicast IP address, discard it.
   1037       //
   1038       goto CleanUp;
   1039     }
   1040 
   1041     if (RxData->Ip4RxData.DataLength == 0) {
   1042       //
   1043       // Discard zero length data payload packet.
   1044       //
   1045       goto CleanUp;
   1046     }
   1047 
   1048     //
   1049     // Create a netbuffer representing IPv4 packet
   1050     //
   1051     Pkt = NetbufFromExt (
   1052             (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,
   1053             RxData->Ip4RxData.FragmentCount,
   1054             0,
   1055             0,
   1056             IpIoExtFree,
   1057             RxData->Ip4RxData.RecycleSignal
   1058             );
   1059     if (NULL == Pkt) {
   1060       goto CleanUp;
   1061     }
   1062 
   1063     //
   1064     // Create a net session
   1065     //
   1066     Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress);
   1067     Session.Dest.Addr[0]   = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress);
   1068     Session.IpHdr.Ip4Hdr   = RxData->Ip4RxData.Header;
   1069     Session.IpHdrLen       = RxData->Ip4RxData.HeaderLength;
   1070     Session.IpVersion      = IP_VERSION_4;
   1071   } else {
   1072 
   1073     if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {
   1074       goto CleanUp;
   1075     }
   1076 
   1077     if (RxData->Ip6RxData.DataLength == 0) {
   1078       //
   1079       // Discard zero length data payload packet.
   1080       //
   1081       goto CleanUp;
   1082     }
   1083 
   1084     //
   1085     // Create a netbuffer representing IPv6 packet
   1086     //
   1087     Pkt = NetbufFromExt (
   1088             (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,
   1089             RxData->Ip6RxData.FragmentCount,
   1090             0,
   1091             0,
   1092             IpIoExtFree,
   1093             RxData->Ip6RxData.RecycleSignal
   1094             );
   1095     if (NULL == Pkt) {
   1096       goto CleanUp;
   1097     }
   1098 
   1099     //
   1100     // Create a net session
   1101     //
   1102     CopyMem (
   1103       &Session.Source,
   1104       &RxData->Ip6RxData.Header->SourceAddress,
   1105       sizeof(EFI_IPv6_ADDRESS)
   1106       );
   1107     CopyMem (
   1108       &Session.Dest,
   1109       &RxData->Ip6RxData.Header->DestinationAddress,
   1110       sizeof(EFI_IPv6_ADDRESS)
   1111       );
   1112     Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;
   1113     Session.IpHdrLen     = RxData->Ip6RxData.HeaderLength;
   1114     Session.IpVersion    = IP_VERSION_6;
   1115   }
   1116 
   1117   if (EFI_SUCCESS == Status) {
   1118 
   1119     IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);
   1120   } else {
   1121     //
   1122     // Status is EFI_ICMP_ERROR
   1123     //
   1124     Status = IpIoIcmpHandler (IpIo, Pkt, &Session);
   1125     if (EFI_ERROR (Status)) {
   1126       NetbufFree (Pkt);
   1127     }
   1128   }
   1129 
   1130   goto Resume;
   1131 
   1132 CleanUp:
   1133 
   1134   if (IpIo->IpVersion == IP_VERSION_4){
   1135     gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);
   1136   } else {
   1137     gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal);
   1138   }
   1139 
   1140 Resume:
   1141 
   1142   if (IpIo->IpVersion == IP_VERSION_4){
   1143     IpIo->Ip.Ip4->Receive (IpIo->Ip.Ip4, &(IpIo->RcvToken.Ip4Token));
   1144   } else {
   1145     IpIo->Ip.Ip6->Receive (IpIo->Ip.Ip6, &(IpIo->RcvToken.Ip6Token));
   1146   }
   1147 }
   1148 
   1149 /**
   1150   This function add IpIoListenHandlerDpc to the end of the DPC queue.
   1151 
   1152   @param[in]  Event                The event signaled.
   1153   @param[in]  Context              The context passed in by the event notifier.
   1154 
   1155 **/
   1156 VOID
   1157 EFIAPI
   1158 IpIoListenHandler (
   1159   IN EFI_EVENT Event,
   1160   IN VOID      *Context
   1161   )
   1162 {
   1163   //
   1164   // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
   1165   //
   1166   QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);
   1167 }
   1168 
   1169 
   1170 /**
   1171   Create a new IP_IO instance.
   1172 
   1173   This function uses IP4/IP6 service binding protocol in Controller to create
   1174   an IP4/IP6 child (aka IP4/IP6 instance).
   1175 
   1176   @param[in]  Image             The image handle of the driver or application that
   1177                                 consumes IP_IO.
   1178   @param[in]  Controller        The controller handle that has IP4 or IP6 service
   1179                                 binding protocol installed.
   1180   @param[in]  IpVersion         The version of the IP protocol to use, either
   1181                                 IPv4 or IPv6.
   1182 
   1183   @return Pointer to a newly created IP_IO instance, or NULL if failed.
   1184 
   1185 **/
   1186 IP_IO *
   1187 EFIAPI
   1188 IpIoCreate (
   1189   IN EFI_HANDLE Image,
   1190   IN EFI_HANDLE Controller,
   1191   IN UINT8      IpVersion
   1192   )
   1193 {
   1194   EFI_STATUS  Status;
   1195   IP_IO       *IpIo;
   1196   EFI_EVENT   Event;
   1197 
   1198   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
   1199 
   1200   IpIo = AllocateZeroPool (sizeof (IP_IO));
   1201   if (NULL == IpIo) {
   1202     return NULL;
   1203   }
   1204 
   1205   InitializeListHead (&(IpIo->PendingSndList));
   1206   InitializeListHead (&(IpIo->IpList));
   1207   IpIo->Controller  = Controller;
   1208   IpIo->Image       = Image;
   1209   IpIo->IpVersion   = IpVersion;
   1210   Event             = NULL;
   1211 
   1212   Status = gBS->CreateEvent (
   1213                   EVT_NOTIFY_SIGNAL,
   1214                   TPL_NOTIFY,
   1215                   IpIoListenHandler,
   1216                   IpIo,
   1217                   &Event
   1218                   );
   1219   if (EFI_ERROR (Status)) {
   1220     goto ReleaseIpIo;
   1221   }
   1222 
   1223   if (IpVersion == IP_VERSION_4) {
   1224     IpIo->RcvToken.Ip4Token.Event = Event;
   1225   } else {
   1226     IpIo->RcvToken.Ip6Token.Event = Event;
   1227   }
   1228 
   1229   //
   1230   // Create an IP child and open IP protocol
   1231   //
   1232   Status = IpIoCreateIpChildOpenProtocol (
   1233              Controller,
   1234              Image,
   1235              &IpIo->ChildHandle,
   1236              IpVersion,
   1237              (VOID **)&(IpIo->Ip)
   1238              );
   1239   if (EFI_ERROR (Status)) {
   1240     goto ReleaseIpIo;
   1241   }
   1242 
   1243   return IpIo;
   1244 
   1245 ReleaseIpIo:
   1246 
   1247   if (Event != NULL) {
   1248     gBS->CloseEvent (Event);
   1249   }
   1250 
   1251   gBS->FreePool (IpIo);
   1252 
   1253   return NULL;
   1254 }
   1255 
   1256 
   1257 /**
   1258   Open an IP_IO instance for use.
   1259 
   1260   This function is called after IpIoCreate(). It is used for configuring the IP
   1261   instance and register the callbacks and their context data for sending and
   1262   receiving IP packets.
   1263 
   1264   @param[in, out]  IpIo               Pointer to an IP_IO instance that needs
   1265                                       to open.
   1266   @param[in]       OpenData           The configuration data and callbacks for
   1267                                       the IP_IO instance.
   1268 
   1269   @retval          EFI_SUCCESS        The IP_IO instance opened with OpenData
   1270                                       successfully.
   1271   @retval          EFI_ACCESS_DENIED  The IP_IO instance is configured, avoid to
   1272                                       reopen it.
   1273   @retval          Others             Error condition occurred.
   1274 
   1275 **/
   1276 EFI_STATUS
   1277 EFIAPI
   1278 IpIoOpen (
   1279   IN OUT IP_IO           *IpIo,
   1280   IN     IP_IO_OPEN_DATA *OpenData
   1281   )
   1282 {
   1283   EFI_STATUS        Status;
   1284   UINT8             IpVersion;
   1285 
   1286   if (IpIo->IsConfigured) {
   1287     return EFI_ACCESS_DENIED;
   1288   }
   1289 
   1290   IpVersion = IpIo->IpVersion;
   1291 
   1292   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
   1293 
   1294   //
   1295   // configure ip
   1296   //
   1297   if (IpVersion == IP_VERSION_4){
   1298     //
   1299     // RawData mode is no supported.
   1300     //
   1301     ASSERT (!OpenData->IpConfigData.Ip4CfgData.RawData);
   1302     if (OpenData->IpConfigData.Ip4CfgData.RawData) {
   1303       return EFI_UNSUPPORTED;
   1304     }
   1305 
   1306     if (!OpenData->IpConfigData.Ip4CfgData.UseDefaultAddress) {
   1307       IpIo->StationIp = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.StationAddress);
   1308       IpIo->SubnetMask = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.SubnetMask);
   1309     }
   1310 
   1311     Status = IpIo->Ip.Ip4->Configure (
   1312                              IpIo->Ip.Ip4,
   1313                              &OpenData->IpConfigData.Ip4CfgData
   1314                              );
   1315   } else {
   1316 
   1317     Status = IpIo->Ip.Ip6->Configure (
   1318                              IpIo->Ip.Ip6,
   1319                              &OpenData->IpConfigData.Ip6CfgData
   1320                              );
   1321   }
   1322 
   1323   if (EFI_ERROR (Status)) {
   1324     return Status;
   1325   }
   1326 
   1327   //
   1328   // @bug To delete the default route entry in this Ip, if it is:
   1329   // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
   1330   // @bug its code
   1331   //
   1332   if (IpVersion == IP_VERSION_4){
   1333     Status = IpIo->Ip.Ip4->Routes (
   1334                              IpIo->Ip.Ip4,
   1335                              TRUE,
   1336                              &mZeroIp4Addr,
   1337                              &mZeroIp4Addr,
   1338                              &mZeroIp4Addr
   1339                              );
   1340 
   1341     if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {
   1342       return Status;
   1343     }
   1344   }
   1345 
   1346   IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;
   1347   IpIo->PktSentNotify = OpenData->PktSentNotify;
   1348 
   1349   IpIo->RcvdContext   = OpenData->RcvdContext;
   1350   IpIo->SndContext    = OpenData->SndContext;
   1351 
   1352   if (IpVersion == IP_VERSION_4){
   1353     IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;
   1354 
   1355     //
   1356     // start to listen incoming packet
   1357     //
   1358     Status = IpIo->Ip.Ip4->Receive (
   1359                              IpIo->Ip.Ip4,
   1360                              &(IpIo->RcvToken.Ip4Token)
   1361                              );
   1362     if (EFI_ERROR (Status)) {
   1363       IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
   1364       goto ErrorExit;
   1365     }
   1366 
   1367   } else {
   1368 
   1369     IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;
   1370     Status = IpIo->Ip.Ip6->Receive (
   1371                              IpIo->Ip.Ip6,
   1372                              &(IpIo->RcvToken.Ip6Token)
   1373                              );
   1374     if (EFI_ERROR (Status)) {
   1375       IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
   1376       goto ErrorExit;
   1377     }
   1378   }
   1379 
   1380   IpIo->IsConfigured = TRUE;
   1381   InsertTailList (&mActiveIpIoList, &IpIo->Entry);
   1382 
   1383 ErrorExit:
   1384 
   1385   return Status;
   1386 }
   1387 
   1388 
   1389 /**
   1390   Stop an IP_IO instance.
   1391 
   1392   This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
   1393   the pending send/receive tokens will be canceled.
   1394 
   1395   @param[in, out]  IpIo            Pointer to the IP_IO instance that needs to stop.
   1396 
   1397   @retval          EFI_SUCCESS     The IP_IO instance stopped successfully.
   1398   @retval          Others          Error condition occurred.
   1399 
   1400 **/
   1401 EFI_STATUS
   1402 EFIAPI
   1403 IpIoStop (
   1404   IN OUT IP_IO *IpIo
   1405   )
   1406 {
   1407   EFI_STATUS        Status;
   1408   IP_IO_IP_INFO     *IpInfo;
   1409   UINT8             IpVersion;
   1410 
   1411   if (!IpIo->IsConfigured) {
   1412     return EFI_SUCCESS;
   1413   }
   1414 
   1415   IpVersion = IpIo->IpVersion;
   1416 
   1417   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
   1418 
   1419   //
   1420   // Remove the IpIo from the active IpIo list.
   1421   //
   1422   RemoveEntryList (&IpIo->Entry);
   1423 
   1424   //
   1425   // Configure NULL Ip
   1426   //
   1427   if (IpVersion == IP_VERSION_4) {
   1428     Status = IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
   1429   } else {
   1430     Status = IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
   1431   }
   1432   if (EFI_ERROR (Status)) {
   1433     return Status;
   1434   }
   1435 
   1436   IpIo->IsConfigured = FALSE;
   1437 
   1438   //
   1439   // Detroy the Ip List used by IpIo
   1440   //
   1441 
   1442   while (!IsListEmpty (&(IpIo->IpList))) {
   1443     IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);
   1444 
   1445     IpIoRemoveIp (IpIo, IpInfo);
   1446   }
   1447 
   1448   //
   1449   // All pending send tokens should be flushed by resetting the IP instances.
   1450   //
   1451   ASSERT (IsListEmpty (&IpIo->PendingSndList));
   1452 
   1453   //
   1454   // Close the receive event.
   1455   //
   1456   if (IpVersion == IP_VERSION_4){
   1457     gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);
   1458   } else {
   1459     gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);
   1460   }
   1461 
   1462   return EFI_SUCCESS;
   1463 }
   1464 
   1465 
   1466 /**
   1467   Destroy an IP_IO instance.
   1468 
   1469   This function is paired with IpIoCreate(). The IP_IO will be closed first.
   1470   Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
   1471 
   1472   @param[in, out]  IpIo         Pointer to the IP_IO instance that needs to be
   1473                                 destroyed.
   1474 
   1475   @retval          EFI_SUCCESS  The IP_IO instance destroyed successfully.
   1476   @retval          Others       Error condition occurred.
   1477 
   1478 **/
   1479 EFI_STATUS
   1480 EFIAPI
   1481 IpIoDestroy (
   1482   IN OUT IP_IO *IpIo
   1483   )
   1484 {
   1485   //
   1486   // Stop the IpIo.
   1487   //
   1488   IpIoStop (IpIo);
   1489 
   1490   //
   1491   // Close the IP protocol and destroy the child.
   1492   //
   1493   IpIoCloseProtocolDestroyIpChild (
   1494     IpIo->Controller,
   1495     IpIo->Image,
   1496     IpIo->ChildHandle,
   1497     IpIo->IpVersion
   1498     );
   1499 
   1500   gBS->FreePool (IpIo);
   1501 
   1502   return EFI_SUCCESS;
   1503 }
   1504 
   1505 
   1506 /**
   1507   Send out an IP packet.
   1508 
   1509   This function is called after IpIoOpen(). The data to be sent are wrapped in
   1510   Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
   1511   overriden by Sender. Other sending configs, like source address and gateway
   1512   address etc., are specified in OverrideData.
   1513 
   1514   @param[in, out]  IpIo                  Pointer to an IP_IO instance used for sending IP
   1515                                          packet.
   1516   @param[in, out]  Pkt                   Pointer to the IP packet to be sent.
   1517   @param[in]       Sender                The IP protocol instance used for sending.
   1518   @param[in]       Context               Optional context data.
   1519   @param[in]       NotifyData            Optional notify data.
   1520   @param[in]       Dest                  The destination IP address to send this packet to.
   1521   @param[in]       OverrideData          The data to override some configuration of the IP
   1522                                          instance used for sending.
   1523 
   1524   @retval          EFI_SUCCESS           The operation is completed successfully.
   1525   @retval          EFI_NOT_STARTED       The IpIo is not configured.
   1526   @retval          EFI_OUT_OF_RESOURCES  Failed due to resource limit.
   1527 
   1528 **/
   1529 EFI_STATUS
   1530 EFIAPI
   1531 IpIoSend (
   1532   IN OUT IP_IO          *IpIo,
   1533   IN OUT NET_BUF        *Pkt,
   1534   IN     IP_IO_IP_INFO  *Sender        OPTIONAL,
   1535   IN     VOID           *Context       OPTIONAL,
   1536   IN     VOID           *NotifyData    OPTIONAL,
   1537   IN     EFI_IP_ADDRESS *Dest,
   1538   IN     IP_IO_OVERRIDE *OverrideData  OPTIONAL
   1539   )
   1540 {
   1541   EFI_STATUS        Status;
   1542   IP_IO_IP_PROTOCOL Ip;
   1543   IP_IO_SEND_ENTRY  *SndEntry;
   1544 
   1545   ASSERT ((IpIo->IpVersion != IP_VERSION_4) || (Dest != NULL));
   1546 
   1547   if (!IpIo->IsConfigured) {
   1548     return EFI_NOT_STARTED;
   1549   }
   1550 
   1551   Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;
   1552 
   1553   //
   1554   // create a new SndEntry
   1555   //
   1556   SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);
   1557   if (NULL == SndEntry) {
   1558     return EFI_OUT_OF_RESOURCES;
   1559   }
   1560 
   1561   //
   1562   // Send this Packet
   1563   //
   1564   if (IpIo->IpVersion == IP_VERSION_4){
   1565     Status = Ip.Ip4->Transmit (
   1566                        Ip.Ip4,
   1567                        &SndEntry->SndToken.Ip4Token
   1568                        );
   1569   } else {
   1570     Status = Ip.Ip6->Transmit (
   1571                        Ip.Ip6,
   1572                        &SndEntry->SndToken.Ip6Token
   1573                        );
   1574   }
   1575 
   1576   if (EFI_ERROR (Status)) {
   1577     IpIoDestroySndEntry (SndEntry);
   1578   }
   1579 
   1580   return Status;
   1581 }
   1582 
   1583 
   1584 /**
   1585   Cancel the IP transmit token which wraps this Packet.
   1586 
   1587   @param[in]  IpIo                  Pointer to the IP_IO instance.
   1588   @param[in]  Packet                Pointer to the packet of NET_BUF to cancel.
   1589 
   1590 **/
   1591 VOID
   1592 EFIAPI
   1593 IpIoCancelTxToken (
   1594   IN IP_IO  *IpIo,
   1595   IN VOID   *Packet
   1596   )
   1597 {
   1598   LIST_ENTRY        *Node;
   1599   IP_IO_SEND_ENTRY  *SndEntry;
   1600   IP_IO_IP_PROTOCOL Ip;
   1601 
   1602   ASSERT ((IpIo != NULL) && (Packet != NULL));
   1603 
   1604   NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {
   1605 
   1606     SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);
   1607 
   1608     if (SndEntry->Pkt == Packet) {
   1609 
   1610       Ip = SndEntry->Ip;
   1611 
   1612       if (IpIo->IpVersion == IP_VERSION_4) {
   1613         Ip.Ip4->Cancel (
   1614                   Ip.Ip4,
   1615                   &SndEntry->SndToken.Ip4Token
   1616                   );
   1617       } else {
   1618         Ip.Ip6->Cancel (
   1619                   Ip.Ip6,
   1620                   &SndEntry->SndToken.Ip6Token
   1621                   );
   1622       }
   1623 
   1624       break;
   1625     }
   1626   }
   1627 
   1628 }
   1629 
   1630 
   1631 /**
   1632   Add a new IP instance for sending data.
   1633 
   1634   The function is used to add the IP_IO to the IP_IO sending list. The caller
   1635   can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
   1636   data.
   1637 
   1638   @param[in, out]  IpIo               Pointer to a IP_IO instance to add a new IP
   1639                                       instance for sending purpose.
   1640 
   1641   @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
   1642 
   1643 **/
   1644 IP_IO_IP_INFO *
   1645 EFIAPI
   1646 IpIoAddIp (
   1647   IN OUT IP_IO  *IpIo
   1648   )
   1649 {
   1650   EFI_STATUS     Status;
   1651   IP_IO_IP_INFO  *IpInfo;
   1652   EFI_EVENT      Event;
   1653 
   1654   ASSERT (IpIo != NULL);
   1655 
   1656   IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));
   1657   if (IpInfo == NULL) {
   1658     return NULL;
   1659   }
   1660 
   1661   //
   1662   // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
   1663   // instance.
   1664   //
   1665   InitializeListHead (&IpInfo->Entry);
   1666   IpInfo->ChildHandle = NULL;
   1667   ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
   1668   ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
   1669 
   1670   IpInfo->RefCnt    = 1;
   1671   IpInfo->IpVersion = IpIo->IpVersion;
   1672 
   1673   //
   1674   // Create the IP instance and open the IP protocol.
   1675   //
   1676   Status = IpIoCreateIpChildOpenProtocol (
   1677              IpIo->Controller,
   1678              IpIo->Image,
   1679              &IpInfo->ChildHandle,
   1680              IpInfo->IpVersion,
   1681              (VOID **) &IpInfo->Ip
   1682              );
   1683   if (EFI_ERROR (Status)) {
   1684     goto ReleaseIpInfo;
   1685   }
   1686 
   1687   //
   1688   // Create the event for the DummyRcvToken.
   1689   //
   1690   Status = gBS->CreateEvent (
   1691                   EVT_NOTIFY_SIGNAL,
   1692                   TPL_NOTIFY,
   1693                   IpIoDummyHandler,
   1694                   IpInfo,
   1695                   &Event
   1696                   );
   1697   if (EFI_ERROR (Status)) {
   1698     goto ReleaseIpChild;
   1699   }
   1700 
   1701   if (IpInfo->IpVersion == IP_VERSION_4) {
   1702     IpInfo->DummyRcvToken.Ip4Token.Event = Event;
   1703   } else {
   1704     IpInfo->DummyRcvToken.Ip6Token.Event = Event;
   1705   }
   1706 
   1707   //
   1708   // Link this IpInfo into the IpIo.
   1709   //
   1710   InsertTailList (&IpIo->IpList, &IpInfo->Entry);
   1711 
   1712   return IpInfo;
   1713 
   1714 ReleaseIpChild:
   1715 
   1716   IpIoCloseProtocolDestroyIpChild (
   1717     IpIo->Controller,
   1718     IpIo->Image,
   1719     IpInfo->ChildHandle,
   1720     IpInfo->IpVersion
   1721     );
   1722 
   1723 ReleaseIpInfo:
   1724 
   1725   gBS->FreePool (IpInfo);
   1726 
   1727   return NULL;
   1728 }
   1729 
   1730 
   1731 /**
   1732   Configure the IP instance of this IpInfo and start the receiving if IpConfigData
   1733   is not NULL.
   1734 
   1735   @param[in, out]  IpInfo          Pointer to the IP_IO_IP_INFO instance.
   1736   @param[in, out]  IpConfigData    The IP configure data used to configure the IP
   1737                                    instance, if NULL the IP instance is reset. If
   1738                                    UseDefaultAddress is set to TRUE, and the configure
   1739                                    operation succeeds, the default address information
   1740                                    is written back in this IpConfigData.
   1741 
   1742   @retval          EFI_SUCCESS     The IP instance of this IpInfo is configured successfully
   1743                                    or no need to reconfigure it.
   1744   @retval          Others          Configuration fails.
   1745 
   1746 **/
   1747 EFI_STATUS
   1748 EFIAPI
   1749 IpIoConfigIp (
   1750   IN OUT IP_IO_IP_INFO        *IpInfo,
   1751   IN OUT VOID                 *IpConfigData OPTIONAL
   1752   )
   1753 {
   1754   EFI_STATUS         Status;
   1755   IP_IO_IP_PROTOCOL  Ip;
   1756   UINT8              IpVersion;
   1757   EFI_IP4_MODE_DATA  Ip4ModeData;
   1758   EFI_IP6_MODE_DATA  Ip6ModeData;
   1759 
   1760   ASSERT (IpInfo != NULL);
   1761 
   1762   if (IpInfo->RefCnt > 1) {
   1763     //
   1764     // This IP instance is shared, don't reconfigure it until it has only one
   1765     // consumer. Currently, only the tcp children cloned from their passive parent
   1766     // will share the same IP. So this cases only happens while IpConfigData is NULL,
   1767     // let the last consumer clean the IP instance.
   1768     //
   1769     return EFI_SUCCESS;
   1770   }
   1771 
   1772   IpVersion = IpInfo->IpVersion;
   1773   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
   1774 
   1775   Ip = IpInfo->Ip;
   1776 
   1777   if (IpInfo->IpVersion == IP_VERSION_4) {
   1778     Status = Ip.Ip4->Configure (Ip.Ip4, IpConfigData);
   1779   } else {
   1780     Status = Ip.Ip6->Configure (Ip.Ip6, IpConfigData);
   1781   }
   1782 
   1783   if (EFI_ERROR (Status)) {
   1784     goto OnExit;
   1785   }
   1786 
   1787   if (IpConfigData != NULL) {
   1788     if (IpInfo->IpVersion == IP_VERSION_4){
   1789 
   1790       if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {
   1791         Ip.Ip4->GetModeData (
   1792                   Ip.Ip4,
   1793                   &Ip4ModeData,
   1794                   NULL,
   1795                   NULL
   1796                   );
   1797 
   1798         IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress, &Ip4ModeData.ConfigData.StationAddress);
   1799         IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask, &Ip4ModeData.ConfigData.SubnetMask);
   1800     }
   1801 
   1802       CopyMem (
   1803         &IpInfo->Addr.Addr,
   1804         &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress,
   1805         sizeof (IP4_ADDR)
   1806         );
   1807       CopyMem (
   1808         &IpInfo->PreMask.SubnetMask,
   1809         &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,
   1810         sizeof (IP4_ADDR)
   1811         );
   1812 
   1813       Status = Ip.Ip4->Receive (
   1814                          Ip.Ip4,
   1815                          &IpInfo->DummyRcvToken.Ip4Token
   1816                          );
   1817     if (EFI_ERROR (Status)) {
   1818       Ip.Ip4->Configure (Ip.Ip4, NULL);
   1819     }
   1820   } else {
   1821     Ip.Ip6->GetModeData (
   1822               Ip.Ip6,
   1823               &Ip6ModeData,
   1824               NULL,
   1825               NULL
   1826               );
   1827 
   1828       if (Ip6ModeData.IsConfigured) {
   1829         CopyMem (
   1830           &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,
   1831           &Ip6ModeData.ConfigData.StationAddress,
   1832           sizeof (EFI_IPv6_ADDRESS)
   1833           );
   1834 
   1835         if (Ip6ModeData.AddressList != NULL) {
   1836           FreePool (Ip6ModeData.AddressList);
   1837         }
   1838 
   1839         if (Ip6ModeData.GroupTable != NULL) {
   1840           FreePool (Ip6ModeData.GroupTable);
   1841         }
   1842 
   1843         if (Ip6ModeData.RouteTable != NULL) {
   1844           FreePool (Ip6ModeData.RouteTable);
   1845         }
   1846 
   1847         if (Ip6ModeData.NeighborCache != NULL) {
   1848           FreePool (Ip6ModeData.NeighborCache);
   1849         }
   1850 
   1851         if (Ip6ModeData.PrefixTable != NULL) {
   1852           FreePool (Ip6ModeData.PrefixTable);
   1853         }
   1854 
   1855         if (Ip6ModeData.IcmpTypeList != NULL) {
   1856           FreePool (Ip6ModeData.IcmpTypeList);
   1857         }
   1858 
   1859       } else {
   1860         Status = EFI_NO_MAPPING;
   1861         goto OnExit;
   1862       }
   1863 
   1864       CopyMem (
   1865         &IpInfo->Addr,
   1866         &Ip6ModeData.ConfigData.StationAddress,
   1867         sizeof (EFI_IPv6_ADDRESS)
   1868         );
   1869 
   1870       Status = Ip.Ip6->Receive (
   1871                          Ip.Ip6,
   1872                          &IpInfo->DummyRcvToken.Ip6Token
   1873                          );
   1874       if (EFI_ERROR (Status)) {
   1875         Ip.Ip6->Configure (Ip.Ip6, NULL);
   1876       }
   1877     }
   1878   } else {
   1879     //
   1880     // The IP instance is reset, set the stored Addr and SubnetMask to zero.
   1881     //
   1882     ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
   1883     ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
   1884   }
   1885 
   1886 OnExit:
   1887 
   1888   return Status;
   1889 }
   1890 
   1891 
   1892 /**
   1893   Destroy an IP instance maintained in IpIo->IpList for
   1894   sending purpose.
   1895 
   1896   This function pairs with IpIoAddIp(). The IpInfo is previously created by
   1897   IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
   1898   will be dstroyed if the RefCnt is zero.
   1899 
   1900   @param[in]  IpIo                  Pointer to the IP_IO instance.
   1901   @param[in]  IpInfo                Pointer to the IpInfo to be removed.
   1902 
   1903 **/
   1904 VOID
   1905 EFIAPI
   1906 IpIoRemoveIp (
   1907   IN IP_IO            *IpIo,
   1908   IN IP_IO_IP_INFO    *IpInfo
   1909   )
   1910 {
   1911 
   1912   UINT8               IpVersion;
   1913 
   1914   ASSERT (IpInfo->RefCnt > 0);
   1915 
   1916   NET_PUT_REF (IpInfo);
   1917 
   1918   if (IpInfo->RefCnt > 0) {
   1919 
   1920     return;
   1921   }
   1922 
   1923   IpVersion = IpIo->IpVersion;
   1924 
   1925   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
   1926 
   1927   RemoveEntryList (&IpInfo->Entry);
   1928 
   1929   if (IpVersion == IP_VERSION_4){
   1930     IpInfo->Ip.Ip4->Configure (
   1931                       IpInfo->Ip.Ip4,
   1932                       NULL
   1933                       );
   1934     IpIoCloseProtocolDestroyIpChild (
   1935       IpIo->Controller,
   1936       IpIo->Image,
   1937       IpInfo->ChildHandle,
   1938       IP_VERSION_4
   1939       );
   1940 
   1941     gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);
   1942 
   1943   } else {
   1944 
   1945     IpInfo->Ip.Ip6->Configure (
   1946                       IpInfo->Ip.Ip6,
   1947                       NULL
   1948                       );
   1949 
   1950     IpIoCloseProtocolDestroyIpChild (
   1951       IpIo->Controller,
   1952       IpIo->Image,
   1953       IpInfo->ChildHandle,
   1954       IP_VERSION_6
   1955       );
   1956 
   1957     gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);
   1958   }
   1959 
   1960   FreePool (IpInfo);
   1961 }
   1962 
   1963 
   1964 /**
   1965   Find the first IP protocol maintained in IpIo whose local
   1966   address is the same as Src.
   1967 
   1968   This function is called when the caller needs the IpIo to send data to the
   1969   specified Src. The IpIo was added previously by IpIoAddIp().
   1970 
   1971   @param[in, out]  IpIo              Pointer to the pointer of the IP_IO instance.
   1972   @param[in]       IpVersion         The version of the IP protocol to use, either
   1973                                      IPv4 or IPv6.
   1974   @param[in]       Src               The local IP address.
   1975 
   1976   @return Pointer to the IP protocol can be used for sending purpose and its local
   1977           address is the same with Src.
   1978 
   1979 **/
   1980 IP_IO_IP_INFO *
   1981 EFIAPI
   1982 IpIoFindSender (
   1983   IN OUT IP_IO           **IpIo,
   1984   IN     UINT8           IpVersion,
   1985   IN     EFI_IP_ADDRESS  *Src
   1986   )
   1987 {
   1988   LIST_ENTRY      *IpIoEntry;
   1989   IP_IO           *IpIoPtr;
   1990   LIST_ENTRY      *IpInfoEntry;
   1991   IP_IO_IP_INFO   *IpInfo;
   1992 
   1993   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
   1994 
   1995   NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {
   1996     IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);
   1997 
   1998     if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {
   1999       continue;
   2000     }
   2001 
   2002     NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {
   2003       IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);
   2004       if (IpInfo->IpVersion == IP_VERSION_4){
   2005 
   2006         if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {
   2007           *IpIo = IpIoPtr;
   2008           return IpInfo;
   2009         }
   2010 
   2011       } else {
   2012 
   2013         if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {
   2014           *IpIo = IpIoPtr;
   2015           return IpInfo;
   2016         }
   2017       }
   2018 
   2019     }
   2020   }
   2021 
   2022   //
   2023   // No match.
   2024   //
   2025   return NULL;
   2026 }
   2027 
   2028 
   2029 /**
   2030   Get the ICMP error map information.
   2031 
   2032   The ErrorStatus will be returned. The IsHard and Notify are optional. If they
   2033   are not NULL, this routine will fill them.
   2034 
   2035   @param[in]   IcmpError             IcmpError Type.
   2036   @param[in]   IpVersion             The version of the IP protocol to use,
   2037                                      either IPv4 or IPv6.
   2038   @param[out]  IsHard                If TRUE, indicates that it is a hard error.
   2039   @param[out]  Notify                If TRUE, SockError needs to be notified.
   2040 
   2041   @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
   2042 
   2043 **/
   2044 EFI_STATUS
   2045 EFIAPI
   2046 IpIoGetIcmpErrStatus (
   2047   IN  UINT8       IcmpError,
   2048   IN  UINT8       IpVersion,
   2049   OUT BOOLEAN     *IsHard  OPTIONAL,
   2050   OUT BOOLEAN     *Notify  OPTIONAL
   2051   )
   2052 {
   2053   if (IpVersion == IP_VERSION_4 ) {
   2054     ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);
   2055 
   2056     if (IsHard != NULL) {
   2057       *IsHard = mIcmpErrMap[IcmpError].IsHard;
   2058     }
   2059 
   2060     if (Notify != NULL) {
   2061       *Notify = mIcmpErrMap[IcmpError].Notify;
   2062     }
   2063 
   2064     switch (IcmpError) {
   2065     case ICMP_ERR_UNREACH_NET:
   2066       return  EFI_NETWORK_UNREACHABLE;
   2067 
   2068     case ICMP_ERR_TIMXCEED_INTRANS:
   2069     case ICMP_ERR_TIMXCEED_REASS:
   2070     case ICMP_ERR_UNREACH_HOST:
   2071       return  EFI_HOST_UNREACHABLE;
   2072 
   2073     case ICMP_ERR_UNREACH_PROTOCOL:
   2074       return  EFI_PROTOCOL_UNREACHABLE;
   2075 
   2076     case ICMP_ERR_UNREACH_PORT:
   2077       return  EFI_PORT_UNREACHABLE;
   2078 
   2079     case ICMP_ERR_MSGSIZE:
   2080     case ICMP_ERR_UNREACH_SRCFAIL:
   2081     case ICMP_ERR_QUENCH:
   2082     case ICMP_ERR_PARAMPROB:
   2083       return  EFI_ICMP_ERROR;
   2084 
   2085     default:
   2086       ASSERT (FALSE);
   2087       return EFI_UNSUPPORTED;
   2088     }
   2089 
   2090   } else if (IpVersion == IP_VERSION_6) {
   2091 
   2092     ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);
   2093 
   2094     if (IsHard != NULL) {
   2095       *IsHard = mIcmp6ErrMap[IcmpError].IsHard;
   2096     }
   2097 
   2098     if (Notify != NULL) {
   2099       *Notify = mIcmp6ErrMap[IcmpError].Notify;
   2100     }
   2101 
   2102     switch (IcmpError) {
   2103     case ICMP6_ERR_UNREACH_NET:
   2104       return EFI_NETWORK_UNREACHABLE;
   2105 
   2106     case ICMP6_ERR_UNREACH_HOST:
   2107     case ICMP6_ERR_TIMXCEED_HOPLIMIT:
   2108     case ICMP6_ERR_TIMXCEED_REASS:
   2109       return EFI_HOST_UNREACHABLE;
   2110 
   2111     case ICMP6_ERR_UNREACH_PROTOCOL:
   2112       return EFI_PROTOCOL_UNREACHABLE;
   2113 
   2114     case ICMP6_ERR_UNREACH_PORT:
   2115       return EFI_PORT_UNREACHABLE;
   2116 
   2117     case ICMP6_ERR_PACKAGE_TOOBIG:
   2118     case ICMP6_ERR_PARAMPROB_HEADER:
   2119     case ICMP6_ERR_PARAMPROB_NEXHEADER:
   2120     case ICMP6_ERR_PARAMPROB_IPV6OPTION:
   2121       return EFI_ICMP_ERROR;
   2122 
   2123     default:
   2124       ASSERT (FALSE);
   2125       return EFI_UNSUPPORTED;
   2126     }
   2127 
   2128   } else {
   2129     //
   2130     // Should never be here
   2131     //
   2132     ASSERT (FALSE);
   2133     return EFI_UNSUPPORTED;
   2134   }
   2135 }
   2136 
   2137 
   2138 /**
   2139   Refresh the remote peer's Neighbor Cache entries.
   2140 
   2141   This function is called when the caller needs the IpIo to refresh the existing
   2142   IPv6 neighbor cache entries since the neighbor is considered reachable by the
   2143   node has recently received a confirmation that packets sent recently to the
   2144   neighbor were received by its IP layer.
   2145 
   2146   @param[in]   IpIo                  Pointer to an IP_IO instance
   2147   @param[in]   Neighbor              The IP address of the neighbor
   2148   @param[in]   Timeout               Time in 100-ns units that this entry will
   2149                                      remain in the neighbor cache. A value of
   2150                                      zero means that the entry is permanent.
   2151                                      A value of non-zero means that the entry is
   2152                                      dynamic and will be deleted after Timeout.
   2153 
   2154   @retval      EFI_SUCCESS           The operation is completed successfully.
   2155   @retval      EFI_NOT_STARTED       The IpIo is not configured.
   2156   @retval      EFI_INVALID_PARAMETER Neighbor Address is invalid.
   2157   @retval      EFI_NOT_FOUND         The neighbor cache entry is not in the
   2158                                      neighbor table.
   2159   @retval      EFI_OUT_OF_RESOURCES  Failed due to resource limit.
   2160 
   2161 **/
   2162 EFI_STATUS
   2163 IpIoRefreshNeighbor (
   2164   IN IP_IO           *IpIo,
   2165   IN EFI_IP_ADDRESS  *Neighbor,
   2166   IN UINT32          Timeout
   2167   )
   2168 {
   2169   EFI_IP6_PROTOCOL  *Ip;
   2170 
   2171   if (!IpIo->IsConfigured || IpIo->IpVersion != IP_VERSION_6) {
   2172     return EFI_NOT_STARTED;
   2173   }
   2174 
   2175   Ip = IpIo->Ip.Ip6;
   2176 
   2177   return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);
   2178 }
   2179 
   2180