Home | History | Annotate | Download | only in Udp6Dxe
      1 /** @file
      2   Udp6 driver's whole implementation.
      3 
      4   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "Udp6Impl.h"
     17 
     18 UINT16  mUdp6RandomPort;
     19 
     20 /**
     21   This function checks and timeouts the I/O datagrams holding by the corresponding
     22   service context.
     23 
     24   @param[in]  Event              The event this function is registered to.
     25   @param[in]  Context            The context data registered during the creation of
     26                                  the Event.
     27 
     28 **/
     29 VOID
     30 EFIAPI
     31 Udp6CheckTimeout (
     32   IN EFI_EVENT  Event,
     33   IN VOID       *Context
     34   );
     35 
     36 /**
     37   This function finds the udp instance by the specified <Address, Port> pair.
     38 
     39   @param[in]  InstanceList       Pointer to the head of the list linking the udp
     40                                  instances.
     41   @param[in]  Address            Pointer to the specified IPv6 address.
     42   @param[in]  Port               The udp port number.
     43 
     44   @retval TRUE     The specified <Address, Port> pair is found.
     45   @retval FALSE    Otherwise.
     46 
     47 **/
     48 BOOLEAN
     49 Udp6FindInstanceByPort (
     50   IN LIST_ENTRY        *InstanceList,
     51   IN EFI_IPv6_ADDRESS  *Address,
     52   IN UINT16            Port
     53   );
     54 
     55 /**
     56   This function is the packet transmitting notify function registered to the IpIo
     57   interface. It's called to signal the udp TxToken when the IpIo layer completes
     58   transmitting of the udp datagram.
     59 
     60   @param[in]  Status            The completion status of the output udp datagram.
     61   @param[in]  Context           Pointer to the context data.
     62   @param[in]  Sender            Specify a EFI_IP6_PROTOCOL for sending.
     63   @param[in]  NotifyData        Pointer to the notify data.
     64 
     65 **/
     66 VOID
     67 EFIAPI
     68 Udp6DgramSent (
     69   IN EFI_STATUS        Status,
     70   IN VOID              *Context,
     71   IN IP_IO_IP_PROTOCOL Sender,
     72   IN VOID              *NotifyData
     73   );
     74 
     75 /**
     76   This function processes the received datagram passed up by the IpIo layer.
     77 
     78   @param[in]  Status            The status of this udp datagram.
     79   @param[in]  IcmpError         The IcmpError code, only available when Status is
     80                                 EFI_ICMP_ERROR.
     81   @param[in]  NetSession        Pointer to the EFI_NET_SESSION_DATA.
     82   @param[in]  Packet            Pointer to the NET_BUF containing the received udp
     83                                 datagram.
     84   @param[in]  Context           Pointer to the context data.
     85 
     86 **/
     87 VOID
     88 EFIAPI
     89 Udp6DgramRcvd (
     90   IN EFI_STATUS            Status,
     91   IN UINT8                 IcmpError,
     92   IN EFI_NET_SESSION_DATA  *NetSession,
     93   IN NET_BUF               *Packet,
     94   IN VOID                  *Context
     95   );
     96 
     97 /**
     98   This function cancle the token specified by Arg in the Map.
     99 
    100   @param[in]  Map             Pointer to the NET_MAP.
    101   @param[in]  Item            Pointer to the NET_MAP_ITEM.
    102   @param[in]  Arg             Pointer to the token to be cancelled, if NULL, all
    103                               the tokens in this Map will be cancelled.
    104                               This parameter is optional and may be NULL.
    105 
    106   @retval EFI_SUCCESS         The token is cancelled if Arg is NULL or the token
    107                               is not the same as that in the Item if Arg is not
    108                               NULL.
    109   @retval EFI_ABORTED         Arg is not NULL, and the token specified by Arg is
    110                               cancelled.
    111 
    112 **/
    113 EFI_STATUS
    114 EFIAPI
    115 Udp6CancelTokens (
    116   IN NET_MAP       *Map,
    117   IN NET_MAP_ITEM  *Item,
    118   IN VOID          *Arg OPTIONAL
    119   );
    120 
    121 /**
    122   This function check if the received udp datagram matches with the Instance.
    123 
    124   @param[in]  Instance           Pointer to the udp instance context data.
    125   @param[in]  Udp6Session        Pointer to the EFI_UDP6_SESSION_DATA abstracted
    126                                  from the received udp datagram.
    127 
    128   @retval TRUE     The udp datagram matches the receiving requirements of the Instance.
    129   @retval FALSE    The udp datagram doe not match the receiving requirements of the Instance.
    130 
    131 **/
    132 BOOLEAN
    133 Udp6MatchDgram (
    134   IN UDP6_INSTANCE_DATA     *Instance,
    135   IN EFI_UDP6_SESSION_DATA  *Udp6Session
    136   );
    137 
    138 /**
    139   This function removes the Wrap specified by Context and releases relevant resources.
    140 
    141   @param[in]  Event                  The Event this notify function is registered to.
    142   @param[in]  Context                Pointer to the context data.
    143 
    144 **/
    145 VOID
    146 EFIAPI
    147 Udp6RecycleRxDataWrap (
    148   IN EFI_EVENT  Event,
    149   IN VOID       *Context
    150   );
    151 
    152 /**
    153   This function wraps the Packet into RxData.
    154 
    155   @param[in]  Instance           Pointer to the instance context data.
    156   @param[in]  Packet             Pointer to the buffer containing the received
    157                                  datagram.
    158   @param[in]  RxData             Pointer to the EFI_UDP6_RECEIVE_DATA of this
    159                                  datagram.
    160 
    161   @return Pointer to the structure wrapping the RxData and the Packet.
    162 
    163 **/
    164 UDP6_RXDATA_WRAP *
    165 Udp6WrapRxData (
    166   IN UDP6_INSTANCE_DATA     *Instance,
    167   IN NET_BUF                *Packet,
    168   IN EFI_UDP6_RECEIVE_DATA  *RxData
    169   );
    170 
    171 /**
    172   This function enqueues the received datagram into the instances' receiving queues.
    173 
    174   @param[in]  Udp6Service        Pointer to the udp service context data.
    175   @param[in]  Packet             Pointer to the buffer containing the received
    176                                  datagram.
    177   @param[in]  RxData             Pointer to the EFI_UDP6_RECEIVE_DATA of this
    178                                  datagram.
    179 
    180   @return The times this datagram is enqueued.
    181 
    182 **/
    183 UINTN
    184 Udp6EnqueueDgram (
    185   IN UDP6_SERVICE_DATA      *Udp6Service,
    186   IN NET_BUF                *Packet,
    187   IN EFI_UDP6_RECEIVE_DATA  *RxData
    188   );
    189 
    190 /**
    191   This function delivers the datagrams enqueued in the instances.
    192 
    193   @param[in]  Udp6Service            Pointer to the udp service context data.
    194 
    195 **/
    196 VOID
    197 Udp6DeliverDgram (
    198   IN UDP6_SERVICE_DATA  *Udp6Service
    199   );
    200 
    201 /**
    202   This function demultiplexes the received udp datagram to the appropriate instances.
    203 
    204   @param[in]  Udp6Service        Pointer to the udp service context data.
    205   @param[in]  NetSession         Pointer to the EFI_NET_SESSION_DATA abstracted from
    206                                  the received datagram.
    207   @param[in]  Packet             Pointer to the buffer containing the received udp
    208                                  datagram.
    209 
    210 **/
    211 VOID
    212 Udp6Demultiplex (
    213   IN UDP6_SERVICE_DATA     *Udp6Service,
    214   IN EFI_NET_SESSION_DATA  *NetSession,
    215   IN NET_BUF               *Packet
    216   );
    217 
    218 /**
    219   This function handles the received Icmp Error message and demultiplexes it to the
    220   instance.
    221 
    222   @param[in]       Udp6Service        Pointer to the udp service context data.
    223   @param[in]       IcmpError          The icmp error code.
    224   @param[in]       NetSession         Pointer to the EFI_NET_SESSION_DATA abstracted
    225                                       from the received Icmp Error packet.
    226   @param[in, out]  Packet             Pointer to the Icmp Error packet.
    227 
    228 **/
    229 VOID
    230 Udp6IcmpHandler (
    231   IN UDP6_SERVICE_DATA     *Udp6Service,
    232   IN UINT8                 IcmpError,
    233   IN EFI_NET_SESSION_DATA  *NetSession,
    234   IN OUT NET_BUF           *Packet
    235   );
    236 
    237 /**
    238   This function builds and sends out a icmp port unreachable message.
    239 
    240   @param[in]  IpIo               Pointer to the IP_IO instance.
    241   @param[in]  NetSession         Pointer to the EFI_NET_SESSION_DATA of the packet
    242                                  causes this icmp error message.
    243   @param[in]  Udp6Header         Pointer to the udp header of the datagram causes
    244                                  this icmp error message.
    245 
    246 **/
    247 VOID
    248 Udp6SendPortUnreach (
    249   IN IP_IO                 *IpIo,
    250   IN EFI_NET_SESSION_DATA  *NetSession,
    251   IN VOID                  *Udp6Header
    252   );
    253 
    254 /**
    255   Find the key in the netmap
    256 
    257   @param[in]  Map                    The netmap to search within.
    258   @param[in]  Key                    The key to search.
    259 
    260   @return The point to the item contains the Key, or NULL if Key isn't in the map.
    261 
    262 **/
    263 NET_MAP_ITEM *
    264 Udp6MapMultiCastAddr (
    265   IN  NET_MAP               *Map,
    266   IN  VOID                  *Key
    267   );
    268 
    269 /**
    270   Create the Udp service context data.
    271 
    272   @param[in]  Udp6Service        Pointer to the UDP6_SERVICE_DATA.
    273   @param[in]  ImageHandle        The image handle of this udp6 driver.
    274   @param[in]  ControllerHandle   The controller handle this udp6 driver binds on.
    275 
    276   @retval EFI_SUCCESS            The udp6 service context data was created and
    277                                  initialized.
    278   @retval EFI_OUT_OF_RESOURCES   Cannot allocate memory.
    279   @retval Others                 An error condition occurred.
    280 
    281 **/
    282 EFI_STATUS
    283 Udp6CreateService (
    284   IN UDP6_SERVICE_DATA  *Udp6Service,
    285   IN EFI_HANDLE         ImageHandle,
    286   IN EFI_HANDLE         ControllerHandle
    287   )
    288 {
    289   EFI_STATUS       Status;
    290   IP_IO_OPEN_DATA  OpenData;
    291 
    292   ZeroMem (Udp6Service, sizeof (UDP6_SERVICE_DATA));
    293 
    294   Udp6Service->Signature        = UDP6_SERVICE_DATA_SIGNATURE;
    295   Udp6Service->ServiceBinding   = mUdp6ServiceBinding;
    296   Udp6Service->ImageHandle      = ImageHandle;
    297   Udp6Service->ControllerHandle = ControllerHandle;
    298   Udp6Service->ChildrenNumber   = 0;
    299 
    300   InitializeListHead (&Udp6Service->ChildrenList);
    301 
    302   //
    303   // Create the IpIo for this service context.
    304   //
    305   Udp6Service->IpIo = IpIoCreate (ImageHandle, ControllerHandle, IP_VERSION_6);
    306   if (Udp6Service->IpIo == NULL) {
    307     return EFI_OUT_OF_RESOURCES;
    308   }
    309 
    310   //
    311   // Set the OpenData used to open the IpIo.
    312   //
    313   CopyMem (
    314     &OpenData.IpConfigData.Ip6CfgData,
    315     &mIp6IoDefaultIpConfigData,
    316     sizeof (EFI_IP6_CONFIG_DATA)
    317     );
    318   OpenData.RcvdContext           = (VOID *) Udp6Service;
    319   OpenData.SndContext            = NULL;
    320   OpenData.PktRcvdNotify         = Udp6DgramRcvd;
    321   OpenData.PktSentNotify         = Udp6DgramSent;
    322 
    323   //
    324   // Configure and start the IpIo.
    325   //
    326   Status = IpIoOpen (Udp6Service->IpIo, &OpenData);
    327   if (EFI_ERROR (Status)) {
    328     goto ON_ERROR;
    329   }
    330 
    331   //
    332   // Create the event for Udp timeout checking.
    333   //
    334   Status = gBS->CreateEvent (
    335                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
    336                   TPL_CALLBACK,
    337                   Udp6CheckTimeout,
    338                   Udp6Service,
    339                   &Udp6Service->TimeoutEvent
    340                   );
    341   if (EFI_ERROR (Status)) {
    342     goto ON_ERROR;
    343   }
    344 
    345   //
    346   // Start the timeout timer event.
    347   //
    348   Status = gBS->SetTimer (
    349                   Udp6Service->TimeoutEvent,
    350                   TimerPeriodic,
    351                   UDP6_TIMEOUT_INTERVAL
    352                   );
    353   if (EFI_ERROR (Status)) {
    354     goto ON_ERROR;
    355   }
    356 
    357   return EFI_SUCCESS;
    358 
    359 ON_ERROR:
    360 
    361   if (Udp6Service->TimeoutEvent != NULL) {
    362     gBS->CloseEvent (Udp6Service->TimeoutEvent);
    363   }
    364 
    365   IpIoDestroy (Udp6Service->IpIo);
    366   Udp6Service->IpIo = NULL;
    367 
    368   return Status;
    369 }
    370 
    371 
    372 /**
    373   Clean the Udp service context data.
    374 
    375   @param[in, out]  Udp6Service      Pointer to the UDP6_SERVICE_DATA.
    376 
    377 **/
    378 VOID
    379 Udp6CleanService (
    380   IN OUT UDP6_SERVICE_DATA  *Udp6Service
    381   )
    382 {
    383   //
    384   // Close the TimeoutEvent timer.
    385   //
    386   gBS->CloseEvent (Udp6Service->TimeoutEvent);
    387 
    388   //
    389   // Destroy the IpIo.
    390   //
    391   IpIoDestroy (Udp6Service->IpIo);
    392   Udp6Service->IpIo = NULL;
    393 
    394   ZeroMem (Udp6Service, sizeof (UDP6_SERVICE_DATA));
    395 }
    396 
    397 
    398 /**
    399   This function checks and times out the I/O datagrams listed in the
    400   UDP6_SERVICE_DATA which is specified by the input parameter Context.
    401 
    402 
    403   @param[in]  Event              The event this function registered to.
    404   @param[in]  Context            The context data registered during the creation of
    405                                  the Event.
    406 
    407 **/
    408 VOID
    409 EFIAPI
    410 Udp6CheckTimeout (
    411   IN EFI_EVENT  Event,
    412   IN VOID       *Context
    413   )
    414 {
    415   UDP6_SERVICE_DATA   *Udp6Service;
    416   LIST_ENTRY          *Entry;
    417   UDP6_INSTANCE_DATA  *Instance;
    418   LIST_ENTRY          *WrapEntry;
    419   LIST_ENTRY          *NextEntry;
    420   UDP6_RXDATA_WRAP    *Wrap;
    421 
    422   Udp6Service = (UDP6_SERVICE_DATA *) Context;
    423   NET_CHECK_SIGNATURE (Udp6Service, UDP6_SERVICE_DATA_SIGNATURE);
    424 
    425   NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) {
    426     //
    427     // Iterate all the instances belonging to this service context.
    428     //
    429     Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link);
    430     NET_CHECK_SIGNATURE (Instance, UDP6_INSTANCE_DATA_SIGNATURE);
    431 
    432     if (!Instance->Configured || (Instance->ConfigData.ReceiveTimeout == 0)) {
    433       //
    434       // Skip this instance if it's not configured or no receive timeout.
    435       //
    436       continue;
    437     }
    438 
    439     NET_LIST_FOR_EACH_SAFE (WrapEntry, NextEntry, &Instance->RcvdDgramQue) {
    440       //
    441       // Iterate all the rxdatas belonging to this udp instance.
    442       //
    443       Wrap = NET_LIST_USER_STRUCT (WrapEntry, UDP6_RXDATA_WRAP, Link);
    444 
    445       if (Wrap->TimeoutTick < UDP6_TIMEOUT_INTERVAL / 10) {
    446         //
    447         // Remove this RxData if it timeouts.
    448         //
    449         Udp6RecycleRxDataWrap (NULL, (VOID *) Wrap);
    450       } else {
    451         Wrap->TimeoutTick -= UDP6_TIMEOUT_INTERVAL / 10;
    452       }
    453     }
    454   }
    455 }
    456 
    457 
    458 /**
    459   This function intializes the new created udp instance.
    460 
    461   @param[in]       Udp6Service      Pointer to the UDP6_SERVICE_DATA.
    462   @param[in, out]  Instance         Pointer to the un-initialized UDP6_INSTANCE_DATA.
    463 
    464 **/
    465 VOID
    466 Udp6InitInstance (
    467   IN UDP6_SERVICE_DATA       *Udp6Service,
    468   IN OUT UDP6_INSTANCE_DATA  *Instance
    469   )
    470 {
    471   //
    472   // Set the signature.
    473   //
    474   Instance->Signature = UDP6_INSTANCE_DATA_SIGNATURE;
    475 
    476   //
    477   // Init the lists.
    478   //
    479   InitializeListHead (&Instance->Link);
    480   InitializeListHead (&Instance->RcvdDgramQue);
    481   InitializeListHead (&Instance->DeliveredDgramQue);
    482 
    483   //
    484   // Init the NET_MAPs.
    485   //
    486   NetMapInit (&Instance->TxTokens);
    487   NetMapInit (&Instance->RxTokens);
    488   NetMapInit (&Instance->McastIps);
    489 
    490   //
    491   // Save the pointer to the UDP6_SERVICE_DATA, and initialize other members.
    492   //
    493   Instance->Udp6Service = Udp6Service;
    494   CopyMem (&Instance->Udp6Proto, &mUdp6Protocol, sizeof (EFI_UDP6_PROTOCOL));
    495   Instance->IcmpError   = EFI_SUCCESS;
    496   Instance->Configured  = FALSE;
    497   Instance->IsNoMapping = FALSE;
    498   Instance->InDestroy   = FALSE;
    499 }
    500 
    501 
    502 /**
    503   This function cleans the udp instance.
    504 
    505   @param[in, out]  Instance       Pointer to the UDP6_INSTANCE_DATA to clean.
    506 
    507 **/
    508 VOID
    509 Udp6CleanInstance (
    510   IN OUT UDP6_INSTANCE_DATA  *Instance
    511   )
    512 {
    513   NetMapClean (&Instance->McastIps);
    514   NetMapClean (&Instance->RxTokens);
    515   NetMapClean (&Instance->TxTokens);
    516 }
    517 
    518 
    519 /**
    520   This function finds the udp instance by the specified <Address, Port> pair.
    521 
    522   @param[in]  InstanceList       Pointer to the head of the list linking the udp
    523                                  instances.
    524   @param[in]  Address            Pointer to the specified IPv6 address.
    525   @param[in]  Port               The udp port number.
    526 
    527   @retval TRUE     The specified <Address, Port> pair is found.
    528   @retval FALSE    Otherwise.
    529 
    530 **/
    531 BOOLEAN
    532 Udp6FindInstanceByPort (
    533   IN LIST_ENTRY        *InstanceList,
    534   IN EFI_IPv6_ADDRESS  *Address,
    535   IN UINT16            Port
    536   )
    537 {
    538   LIST_ENTRY            *Entry;
    539   UDP6_INSTANCE_DATA    *Instance;
    540   EFI_UDP6_CONFIG_DATA  *ConfigData;
    541 
    542   NET_LIST_FOR_EACH (Entry, InstanceList) {
    543     //
    544     // Iterate all the udp instances.
    545     //
    546     Instance   = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link);
    547     ConfigData = &Instance->ConfigData;
    548 
    549     if (!Instance->Configured || ConfigData->AcceptAnyPort) {
    550       //
    551       // If the instance is not configured, or the configdata of the instance indicates
    552       // this instance accepts any port, skip it.
    553       //
    554       continue;
    555     }
    556 
    557     if (EFI_IP6_EQUAL (&ConfigData->StationAddress, Address) &&
    558         (ConfigData->StationPort == Port)
    559         ) {
    560       //
    561       // If both the address and the port are the same, return TRUE.
    562       //
    563       return TRUE;
    564     }
    565   }
    566 
    567   //
    568   // Return FALSE when matching fails.
    569   //
    570   return FALSE;
    571 }
    572 
    573 
    574 /**
    575   This function tries to bind the udp instance according to the configured port
    576   allocation stragety.
    577 
    578   @param[in]  InstanceList       Pointer to the head of the list linking the udp
    579                                  instances.
    580   @param[in]  ConfigData         Pointer to the ConfigData of the instance to be
    581                                  bound.
    582 
    583   @retval EFI_SUCCESS            The bound operation completed successfully.
    584   @retval EFI_ACCESS_DENIED      The <Address, Port> specified by the ConfigData is
    585                                  already used by other instance.
    586   @retval EFI_OUT_OF_RESOURCES   No available port resources.
    587 
    588 **/
    589 EFI_STATUS
    590 Udp6Bind (
    591   IN LIST_ENTRY            *InstanceList,
    592   IN EFI_UDP6_CONFIG_DATA  *ConfigData
    593   )
    594 {
    595   EFI_IPv6_ADDRESS  *StationAddress;
    596   UINT16            StartPort;
    597 
    598   if (ConfigData->AcceptAnyPort) {
    599     return EFI_SUCCESS;
    600   }
    601 
    602   StationAddress = &ConfigData->StationAddress;
    603 
    604   if (ConfigData->StationPort != 0) {
    605 
    606     if (!ConfigData->AllowDuplicatePort &&
    607         Udp6FindInstanceByPort (InstanceList, StationAddress, ConfigData->StationPort)
    608         ) {
    609       //
    610       // Do not allow duplicate ports and the port is already used by other instance.
    611       //
    612       return EFI_ACCESS_DENIED;
    613     }
    614   } else {
    615     //
    616     // Select a random port for this instance.
    617     //
    618     if (ConfigData->AllowDuplicatePort) {
    619       //
    620       // Just pick up the random port if the instance allows duplicate port.
    621       //
    622       ConfigData->StationPort = mUdp6RandomPort;
    623     } else {
    624 
    625       StartPort = mUdp6RandomPort;
    626 
    627       while (Udp6FindInstanceByPort (InstanceList, StationAddress, mUdp6RandomPort)) {
    628 
    629         mUdp6RandomPort++;
    630         if (mUdp6RandomPort == 0) {
    631           mUdp6RandomPort = UDP6_PORT_KNOWN;
    632         }
    633 
    634         if (mUdp6RandomPort == StartPort) {
    635           //
    636           // No available port.
    637           //
    638           return EFI_OUT_OF_RESOURCES;
    639         }
    640       }
    641 
    642       ConfigData->StationPort = mUdp6RandomPort;
    643     }
    644 
    645     mUdp6RandomPort++;
    646     if (mUdp6RandomPort == 0) {
    647       mUdp6RandomPort = UDP6_PORT_KNOWN;
    648     }
    649   }
    650   return EFI_SUCCESS;
    651 }
    652 
    653 
    654 /**
    655   This function is used to check whether the NewConfigData has any un-reconfigurable
    656   parameters changed compared to the OldConfigData.
    657 
    658   @param[in]  OldConfigData    Pointer to the current ConfigData the udp instance
    659                                uses.
    660   @param[in]  NewConfigData    Pointer to the new ConfigData.
    661 
    662   @retval TRUE     The instance is reconfigurable according to the NewConfigData.
    663   @retval FALSE    Otherwise.
    664 
    665 **/
    666 BOOLEAN
    667 Udp6IsReconfigurable (
    668   IN EFI_UDP6_CONFIG_DATA  *OldConfigData,
    669   IN EFI_UDP6_CONFIG_DATA  *NewConfigData
    670   )
    671 {
    672   if ((NewConfigData->AcceptAnyPort != OldConfigData->AcceptAnyPort) ||
    673       (NewConfigData->AcceptPromiscuous != OldConfigData->AcceptPromiscuous) ||
    674       (NewConfigData->AllowDuplicatePort != OldConfigData->AllowDuplicatePort)
    675       ) {
    676     //
    677     // The receiving filter parameters cannot be changed.
    678     //
    679     return FALSE;
    680   }
    681 
    682   if ((!NewConfigData->AcceptAnyPort) &&
    683       (NewConfigData->StationPort != OldConfigData->StationPort)
    684       ) {
    685     //
    686     // The port is not changeable.
    687     //
    688     return FALSE;
    689   }
    690 
    691   if (!EFI_IP6_EQUAL (&NewConfigData->StationAddress, &OldConfigData->StationAddress)) {
    692     //
    693     //  The StationAddress is not the same.
    694     //
    695     return FALSE;
    696   }
    697 
    698 
    699   if (!EFI_IP6_EQUAL (&NewConfigData->RemoteAddress, &OldConfigData->RemoteAddress)) {
    700     //
    701     // The remoteaddress is not the same.
    702     //
    703     return FALSE;
    704   }
    705 
    706   if (!NetIp6IsUnspecifiedAddr (&NewConfigData->RemoteAddress) &&
    707       (NewConfigData->RemotePort != OldConfigData->RemotePort)
    708       ) {
    709     //
    710     // The RemotePort differs if it's designated in the configdata.
    711     //
    712     return FALSE;
    713   }
    714 
    715   //
    716   // All checks pass, return TRUE.
    717   //
    718   return TRUE;
    719 }
    720 
    721 
    722 /**
    723   This function builds the Ip6 configdata from the Udp6ConfigData.
    724 
    725   @param[in]       Udp6ConfigData         Pointer to the EFI_UDP6_CONFIG_DATA.
    726   @param[in, out]  Ip6ConfigData          Pointer to the EFI_IP6_CONFIG_DATA.
    727 
    728 **/
    729 VOID
    730 Udp6BuildIp6ConfigData (
    731   IN EFI_UDP6_CONFIG_DATA      *Udp6ConfigData,
    732   IN OUT EFI_IP6_CONFIG_DATA   *Ip6ConfigData
    733   )
    734 {
    735   CopyMem (
    736     Ip6ConfigData,
    737     &mIp6IoDefaultIpConfigData,
    738     sizeof (EFI_IP6_CONFIG_DATA)
    739     );
    740   Ip6ConfigData->DefaultProtocol      = EFI_IP_PROTO_UDP;
    741   Ip6ConfigData->AcceptPromiscuous    = Udp6ConfigData->AcceptPromiscuous;
    742   IP6_COPY_ADDRESS (&Ip6ConfigData->StationAddress, &Udp6ConfigData->StationAddress);
    743   IP6_COPY_ADDRESS (&Ip6ConfigData->DestinationAddress, &Udp6ConfigData->RemoteAddress);
    744   //
    745   // Use the -1 magic number to disable the receiving process of the ip instance.
    746   //
    747   Ip6ConfigData->ReceiveTimeout    = (UINT32) (-1);
    748 }
    749 
    750 
    751 /**
    752   This function validates the TxToken. It returns the error code according to the spec.
    753 
    754   @param[in]  Instance           Pointer to the udp instance context data.
    755   @param[in]  TxToken            Pointer to the token to be checked.
    756 
    757   @retval EFI_SUCCESS            The TxToken is valid.
    758   @retval EFI_INVALID_PARAMETER  One or more of the following are TRUE:
    759                                  Token.Event is NULL;
    760                                  Token.Packet.TxData is NULL;
    761                                  Token.Packet.TxData.FragmentCount is zero;
    762                                  Token.Packet.TxData.DataLength is not equal to the
    763                                  sum of fragment lengths;
    764                                  One or more of the
    765                                  Token.Packet.TxData.FragmentTable[].FragmentLength
    766                                  fields is zero;
    767                                  One or more of the
    768                                  Token.Packet.TxData.FragmentTable[].FragmentBuffer
    769                                  fields is NULL;
    770                                  UdpSessionData.DestinationAddress are not valid
    771                                  unicast IPv6 addresses if the UdpSessionData is
    772                                  not NULL;
    773                                  UdpSessionData.DestinationPort and
    774                                  ConfigData.RemotePort are all zero if the
    775                                  UdpSessionData is not NULL.
    776   @retval EFI_BAD_BUFFER_SIZE    The data length is greater than the maximum UDP
    777                                  packet size.
    778 
    779 **/
    780 EFI_STATUS
    781 Udp6ValidateTxToken (
    782   IN UDP6_INSTANCE_DATA         *Instance,
    783   IN EFI_UDP6_COMPLETION_TOKEN  *TxToken
    784   )
    785 {
    786   EFI_UDP6_TRANSMIT_DATA  *TxData;
    787   UINT32                  Index;
    788   UINT32                  TotalLen;
    789   EFI_UDP6_CONFIG_DATA    *ConfigData;
    790   EFI_UDP6_SESSION_DATA   *UdpSessionData;
    791 
    792 
    793   if (TxToken->Event == NULL) {
    794     return EFI_INVALID_PARAMETER;
    795   }
    796 
    797   TxData = TxToken->Packet.TxData;
    798 
    799   if ((TxData == NULL) || (TxData->FragmentCount == 0)) {
    800     return EFI_INVALID_PARAMETER;
    801   }
    802 
    803   TotalLen = 0;
    804   for (Index = 0; Index < TxData->FragmentCount; Index++) {
    805 
    806     if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
    807         (TxData->FragmentTable[Index].FragmentLength == 0)
    808         ) {
    809       //
    810       // If the FragmentBuffer is NULL, or the FragmentLeng is zero.
    811       //
    812       return EFI_INVALID_PARAMETER;
    813     }
    814 
    815     TotalLen += TxData->FragmentTable[Index].FragmentLength;
    816   }
    817 
    818   if (TotalLen != TxData->DataLength) {
    819     //
    820     // The TotalLen calculated by adding all the FragmentLeng doesn't equal to the
    821     // DataLength.
    822     //
    823     return EFI_INVALID_PARAMETER;
    824   }
    825 
    826   ConfigData     = &Instance->ConfigData;
    827   UdpSessionData = TxData->UdpSessionData;
    828 
    829   if (UdpSessionData != NULL) {
    830 
    831     if ((UdpSessionData->DestinationPort == 0) && (ConfigData->RemotePort == 0)) {
    832       //
    833       // Ambiguous; no avalaible DestinationPort for this token.
    834       //
    835       return EFI_INVALID_PARAMETER;
    836     }
    837 
    838     if (NetIp6IsUnspecifiedAddr (&UdpSessionData->DestinationAddress) &&
    839         NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress)
    840         ) {
    841       //
    842       // The DestinationAddress is not specificed.
    843       //
    844       return EFI_INVALID_PARAMETER;
    845     }
    846 
    847     if (!NetIp6IsUnspecifiedAddr (&UdpSessionData->DestinationAddress) &&
    848         !NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress)
    849         ) {
    850       //
    851       // The ConfigData.RemoteAddress is not zero and the UdpSessionData.DestinationAddress
    852       // is not zero too.
    853       //
    854       return EFI_INVALID_PARAMETER;
    855     }
    856   } else if (NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress)) {
    857     //
    858     // The configured RemoteAddress is all zero, and the user doesn't override the
    859     // destination address.
    860     //
    861     return EFI_INVALID_PARAMETER;
    862   }
    863 
    864   if (TxData->DataLength > UDP6_MAX_DATA_SIZE) {
    865     return EFI_BAD_BUFFER_SIZE;
    866   }
    867 
    868   return EFI_SUCCESS;
    869 }
    870 
    871 
    872 /**
    873   This function checks whether the specified Token duplicates the one in the Map.
    874 
    875   @param[in]  Map                Pointer to the NET_MAP.
    876   @param[in]  Item               Pointer to the NET_MAP_ITEM contain the pointer to
    877                                  the Token.
    878   @param[in]  Context            Pointer to the Token to be checked.
    879 
    880   @retval EFI_SUCCESS            The Token specified by Context differs from the
    881                                  one in the Item.
    882   @retval EFI_ACCESS_DENIED      The Token duplicates with the one in the Item.
    883 
    884 **/
    885 EFI_STATUS
    886 EFIAPI
    887 Udp6TokenExist (
    888   IN NET_MAP       *Map,
    889   IN NET_MAP_ITEM  *Item,
    890   IN VOID          *Context
    891   )
    892 {
    893   EFI_UDP6_COMPLETION_TOKEN  *Token;
    894   EFI_UDP6_COMPLETION_TOKEN  *TokenInItem;
    895 
    896   Token       = (EFI_UDP6_COMPLETION_TOKEN *) Context;
    897   TokenInItem = (EFI_UDP6_COMPLETION_TOKEN *) Item->Key;
    898 
    899   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
    900     //
    901     // The Token duplicates with the TokenInItem in case either the two pointers are the
    902     // same, or the Events of these two tokens are the same.
    903     //
    904     return EFI_ACCESS_DENIED;
    905   }
    906 
    907   return EFI_SUCCESS;
    908 }
    909 
    910 
    911 /**
    912   This function calculates the checksum for the Packet, utilizing the pre-calculated
    913   pseudo HeadSum to reduce some overhead.
    914 
    915   @param[in]  Packet           Pointer to the NET_BUF contains the udp datagram.
    916   @param[in]  HeadSum          Checksum of the pseudo header, execpt the length
    917                                field.
    918 
    919   @return The 16-bit checksum of this udp datagram.
    920 
    921 **/
    922 UINT16
    923 Udp6Checksum (
    924   IN NET_BUF *Packet,
    925   IN UINT16  HeadSum
    926   )
    927 {
    928   UINT16  Checksum;
    929 
    930   Checksum  = NetbufChecksum (Packet);
    931   Checksum  = NetAddChecksum (Checksum, HeadSum);
    932 
    933   Checksum  = NetAddChecksum (Checksum, HTONS ((UINT16) Packet->TotalSize));
    934   Checksum  = (UINT16) (~Checksum);
    935   return Checksum;
    936 }
    937 
    938 
    939 /**
    940   This function removes the specified Token from the TokenMap.
    941 
    942   @param[in]  TokenMap           Pointer to the NET_MAP containing the tokens.
    943   @param[in]  Token              Pointer to the Token to be removed.
    944 
    945   @retval EFI_SUCCESS            The specified Token is removed from the TokenMap.
    946   @retval EFI_NOT_FOUND          The specified Token is not found in the TokenMap.
    947 
    948 **/
    949 EFI_STATUS
    950 Udp6RemoveToken (
    951   IN NET_MAP                    *TokenMap,
    952   IN EFI_UDP6_COMPLETION_TOKEN  *Token
    953   )
    954 {
    955   NET_MAP_ITEM  *Item;
    956 
    957   //
    958   // Find the Token first.
    959   //
    960   Item = NetMapFindKey (TokenMap, (VOID *) Token);
    961 
    962   if (Item != NULL) {
    963     //
    964     // Remove the token if it's found in the map.
    965     //
    966     NetMapRemoveItem (TokenMap, Item, NULL);
    967 
    968     return EFI_SUCCESS;
    969   }
    970   return EFI_NOT_FOUND;
    971 }
    972 
    973 
    974 /**
    975   This function is the packet transmitting notify function registered to the IpIo
    976   interface. It's called to signal the udp TxToken when IpIo layer completes the
    977   transmitting of the udp datagram.
    978 
    979   @param[in]  Status            The completion status of the output udp datagram.
    980   @param[in]  Context           Pointer to the context data.
    981   @param[in]  Sender            Specify a EFI_IP6_PROTOCOL for sending.
    982   @param[in]  NotifyData        Pointer to the notify data.
    983 
    984 **/
    985 VOID
    986 EFIAPI
    987 Udp6DgramSent (
    988   IN EFI_STATUS        Status,
    989   IN VOID              *Context,
    990   IN IP_IO_IP_PROTOCOL Sender,
    991   IN VOID              *NotifyData
    992   )
    993 {
    994   UDP6_INSTANCE_DATA         *Instance;
    995   EFI_UDP6_COMPLETION_TOKEN  *Token;
    996 
    997   Instance = (UDP6_INSTANCE_DATA *) Context;
    998   Token    = (EFI_UDP6_COMPLETION_TOKEN *) NotifyData;
    999 
   1000   if (Udp6RemoveToken (&Instance->TxTokens, Token) == EFI_SUCCESS) {
   1001     //
   1002     // The token may be cancelled. Only signal it if the remove operation succeeds.
   1003     //
   1004     Token->Status = Status;
   1005     gBS->SignalEvent (Token->Event);
   1006     DispatchDpc ();
   1007   }
   1008 }
   1009 
   1010 
   1011 /**
   1012   This function processes the received datagram passed up by the IpIo layer.
   1013 
   1014   @param[in]  Status            The status of this udp datagram.
   1015   @param[in]  IcmpError         The IcmpError code, only available when Status is
   1016                                 EFI_ICMP_ERROR.
   1017   @param[in]  NetSession        Pointer to the EFI_NET_SESSION_DATA.
   1018   @param[in]  Packet            Pointer to the NET_BUF containing the received udp
   1019                                 datagram.
   1020   @param[in]  Context           Pointer to the context data.
   1021 
   1022 **/
   1023 VOID
   1024 EFIAPI
   1025 Udp6DgramRcvd (
   1026   IN EFI_STATUS            Status,
   1027   IN UINT8                 IcmpError,
   1028   IN EFI_NET_SESSION_DATA  *NetSession,
   1029   IN NET_BUF               *Packet,
   1030   IN VOID                  *Context
   1031   )
   1032 {
   1033   NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE);
   1034 
   1035   //
   1036   // IpIo only passes received packets with Status EFI_SUCCESS or EFI_ICMP_ERROR.
   1037   //
   1038   if (Status == EFI_SUCCESS) {
   1039 
   1040     //
   1041     // Demultiplex the received datagram.
   1042     //
   1043     Udp6Demultiplex ((UDP6_SERVICE_DATA *) Context, NetSession, Packet);
   1044   } else {
   1045     //
   1046     // Handle the ICMP6 Error packet.
   1047     //
   1048     Udp6IcmpHandler ((UDP6_SERVICE_DATA *) Context, IcmpError, NetSession, Packet);
   1049   }
   1050 
   1051   //
   1052   // Dispatch the DPC queued by the NotifyFunction of the rx token's events
   1053   // that are signaled with received data.
   1054   //
   1055   DispatchDpc ();
   1056 }
   1057 
   1058 
   1059 /**
   1060   This function removes the multicast group specified by Arg from the Map.
   1061 
   1062   @param[in]  Map                Pointer to the NET_MAP.
   1063   @param[in]  Item               Pointer to the NET_MAP_ITEM.
   1064   @param[in]  Arg                Pointer to the Arg, it's the pointer to a
   1065                                  multicast IPv6 Address. This parameter is
   1066                                  optional and may be NULL.
   1067 
   1068   @retval EFI_SUCCESS            The multicast address is removed.
   1069   @retval EFI_ABORTED            The specified multicast address is removed, and the
   1070                                  Arg is not NULL.
   1071 
   1072 **/
   1073 EFI_STATUS
   1074 EFIAPI
   1075 Udp6LeaveGroup (
   1076   IN NET_MAP       *Map,
   1077   IN NET_MAP_ITEM  *Item,
   1078   IN VOID          *Arg OPTIONAL
   1079   )
   1080 {
   1081   EFI_IPv6_ADDRESS  *McastIp;
   1082 
   1083   McastIp = Arg;
   1084 
   1085   if ((McastIp != NULL) &&
   1086       !EFI_IP6_EQUAL (McastIp, ((EFI_IPv6_ADDRESS *)Item->Key))
   1087       ) {
   1088     //
   1089     // McastIp is not NULL and the multicast address contained in the Item
   1090     // is not the same as McastIp.
   1091     //
   1092     return EFI_SUCCESS;
   1093   }
   1094 
   1095   FreePool (Item->Key);
   1096 
   1097   //
   1098   // Remove this Item.
   1099   //
   1100   NetMapRemoveItem (Map, Item, NULL);
   1101 
   1102   if (McastIp != NULL) {
   1103     //
   1104     // Return EFI_ABORTED in case McastIp is not NULL to terminate the iteration.
   1105     //
   1106     return EFI_ABORTED;
   1107   }
   1108 
   1109   return EFI_SUCCESS;
   1110 }
   1111 
   1112 
   1113 /**
   1114   This function cancle the token specified by Arg in the Map.
   1115 
   1116   @param[in]  Map             Pointer to the NET_MAP.
   1117   @param[in]  Item            Pointer to the NET_MAP_ITEM.
   1118   @param[in]  Arg             Pointer to the token to be cancelled. If NULL, all
   1119                               the tokens in this Map will be cancelled.
   1120                               This parameter is optional and may be NULL.
   1121 
   1122   @retval EFI_SUCCESS         The token is cancelled if Arg is NULL, or the token
   1123                               is not the same as that in the Item, if Arg is not
   1124                               NULL.
   1125   @retval EFI_ABORTED         Arg is not NULL, and the token specified by Arg is
   1126                               cancelled.
   1127 
   1128 **/
   1129 EFI_STATUS
   1130 EFIAPI
   1131 Udp6CancelTokens (
   1132   IN NET_MAP       *Map,
   1133   IN NET_MAP_ITEM  *Item,
   1134   IN VOID          *Arg OPTIONAL
   1135   )
   1136 {
   1137   EFI_UDP6_COMPLETION_TOKEN  *TokenToCancel;
   1138   NET_BUF                    *Packet;
   1139   IP_IO                      *IpIo;
   1140 
   1141   if ((Arg != NULL) && (Item->Key != Arg)) {
   1142     return EFI_SUCCESS;
   1143   }
   1144 
   1145   if (Item->Value != NULL) {
   1146     //
   1147     // If the token is a transmit token, the corresponding Packet is recorded in
   1148     // Item->Value, invoke IpIo to cancel this packet first. The IpIoCancelTxToken
   1149     // will invoke Udp6DgramSent, the token will be signaled and this Item will
   1150     // be removed from the Map there.
   1151     //
   1152     Packet  = (NET_BUF *) (Item->Value);
   1153     IpIo    = (IP_IO *) (*((UINTN *) &Packet->ProtoData[0]));
   1154 
   1155     IpIoCancelTxToken (IpIo, Packet);
   1156   } else {
   1157     //
   1158     // The token is a receive token. Abort it and remove it from the Map.
   1159     //
   1160     TokenToCancel = (EFI_UDP6_COMPLETION_TOKEN *) Item->Key;
   1161     NetMapRemoveItem (Map, Item, NULL);
   1162 
   1163     TokenToCancel->Status = EFI_ABORTED;
   1164     gBS->SignalEvent (TokenToCancel->Event);
   1165   }
   1166 
   1167   if (Arg != NULL) {
   1168     return EFI_ABORTED;
   1169   }
   1170 
   1171   return EFI_SUCCESS;
   1172 }
   1173 
   1174 
   1175 /**
   1176   This function removes all the Wrap datas in the RcvdDgramQue.
   1177 
   1178   @param[in]  Instance    Pointer to the Udp6 Instance.
   1179 
   1180 **/
   1181 VOID
   1182 Udp6FlushRcvdDgram (
   1183   IN UDP6_INSTANCE_DATA  *Instance
   1184   )
   1185 {
   1186   UDP6_RXDATA_WRAP  *Wrap;
   1187 
   1188   while (!IsListEmpty (&Instance->RcvdDgramQue)) {
   1189     //
   1190     // Iterate all the Wraps in the RcvdDgramQue.
   1191     //
   1192     Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP6_RXDATA_WRAP, Link);
   1193 
   1194     //
   1195     // The Wrap will be removed from the RcvdDgramQue by this function call.
   1196     //
   1197     Udp6RecycleRxDataWrap (NULL, (VOID *) Wrap);
   1198   }
   1199 }
   1200 
   1201 
   1202 
   1203 /**
   1204   Cancel Udp6 tokens from the Udp6 instance.
   1205 
   1206   @param[in]  Instance           Pointer to the udp instance context data.
   1207   @param[in]  Token              Pointer to the token to be canceled. If NULL, all
   1208                                  tokens in this instance will be cancelled.
   1209                                  This parameter is optional and may be NULL.
   1210 
   1211   @retval EFI_SUCCESS            The Token is cancelled.
   1212   @retval EFI_NOT_FOUND          The Token is not found.
   1213 
   1214 **/
   1215 EFI_STATUS
   1216 Udp6InstanceCancelToken (
   1217   IN UDP6_INSTANCE_DATA         *Instance,
   1218   IN EFI_UDP6_COMPLETION_TOKEN  *Token OPTIONAL
   1219   )
   1220 {
   1221   EFI_STATUS  Status;
   1222 
   1223   //
   1224   // Cancel this token from the TxTokens map.
   1225   //
   1226   Status = NetMapIterate (&Instance->TxTokens, Udp6CancelTokens, Token);
   1227 
   1228   if ((Token != NULL) && (Status == EFI_ABORTED)) {
   1229     //
   1230     // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from
   1231     // the TxTokens and returns success.
   1232     //
   1233     return EFI_SUCCESS;
   1234   }
   1235 
   1236   //
   1237   // Try to cancel this token from the RxTokens map in condition either the Token
   1238   // is NULL or the specified Token is not in TxTokens.
   1239   //
   1240   Status = NetMapIterate (&Instance->RxTokens, Udp6CancelTokens, Token);
   1241 
   1242   if ((Token != NULL) && (Status == EFI_SUCCESS)) {
   1243     //
   1244     // If Token isn't NULL and Status is EFI_SUCCESS, the token is neither in the
   1245     // TxTokens nor the RxTokens, or say, it's not found.
   1246     //
   1247     return EFI_NOT_FOUND;
   1248   }
   1249 
   1250   ASSERT ((Token != NULL) ||
   1251           ((0 == NetMapGetCount (&Instance->TxTokens)) &&
   1252           (0 == NetMapGetCount (&Instance->RxTokens)))
   1253           );
   1254 
   1255   return EFI_SUCCESS;
   1256 }
   1257 
   1258 
   1259 /**
   1260   This function checks if the received udp datagram matches with the Instance.
   1261 
   1262   @param[in]  Instance           Pointer to the udp instance context data.
   1263   @param[in]  Udp6Session        Pointer to the EFI_UDP6_SESSION_DATA abstracted
   1264                                  from the received udp datagram.
   1265 
   1266   @retval TRUE     The udp datagram matches the receiving requirements of the Instance.
   1267   @retval FALSE    The udp datagram does not matche the receiving requirements of the Instance.
   1268 
   1269 **/
   1270 BOOLEAN
   1271 Udp6MatchDgram (
   1272   IN UDP6_INSTANCE_DATA     *Instance,
   1273   IN EFI_UDP6_SESSION_DATA  *Udp6Session
   1274   )
   1275 {
   1276   EFI_UDP6_CONFIG_DATA  *ConfigData;
   1277   EFI_IPv6_ADDRESS      Destination;
   1278 
   1279   ConfigData = &Instance->ConfigData;
   1280 
   1281   if (ConfigData->AcceptPromiscuous) {
   1282     //
   1283     // Always matches if this instance is in the promiscuous state.
   1284     //
   1285     return TRUE;
   1286   }
   1287 
   1288   if ((!ConfigData->AcceptAnyPort && (Udp6Session->DestinationPort != ConfigData->StationPort)) ||
   1289       ((ConfigData->RemotePort != 0) && (Udp6Session->SourcePort != ConfigData->RemotePort))
   1290       ) {
   1291     //
   1292     // The local port or the remote port doesn't match.
   1293     //
   1294     return FALSE;
   1295   }
   1296 
   1297   if (!NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress) &&
   1298       !EFI_IP6_EQUAL (&ConfigData->RemoteAddress, &Udp6Session->SourceAddress)
   1299       ) {
   1300     //
   1301     // This datagram doesn't come from the instance's specified sender.
   1302     //
   1303     return FALSE;
   1304   }
   1305 
   1306   if (NetIp6IsUnspecifiedAddr (&ConfigData->StationAddress) ||
   1307       EFI_IP6_EQUAL (&Udp6Session->DestinationAddress, &ConfigData->StationAddress)
   1308       ) {
   1309     //
   1310     // The instance is configured to receive datagrams destinated to any station IP or
   1311     // the destination address of this datagram matches the configured station IP.
   1312     //
   1313     return TRUE;
   1314   }
   1315 
   1316   IP6_COPY_ADDRESS (&Destination, &Udp6Session->DestinationAddress);
   1317 
   1318   if (IP6_IS_MULTICAST (&Destination) &&
   1319       (NULL != Udp6MapMultiCastAddr (&Instance->McastIps, &Destination))
   1320       ) {
   1321     //
   1322     // It's a multicast packet and the multicast address is accepted by this instance.
   1323     //
   1324     return TRUE;
   1325   }
   1326 
   1327   return FALSE;
   1328 }
   1329 
   1330 
   1331 /**
   1332   This function removes the Wrap specified by Context and release relevant resources.
   1333 
   1334   @param[in]  Event                  The Event this notify function registered to.
   1335   @param[in]  Context                Pointer to the context data.
   1336 
   1337 **/
   1338 VOID
   1339 EFIAPI
   1340 Udp6RecycleRxDataWrap (
   1341   IN EFI_EVENT  Event,
   1342   IN VOID       *Context
   1343   )
   1344 {
   1345   UDP6_RXDATA_WRAP  *Wrap;
   1346 
   1347   Wrap = (UDP6_RXDATA_WRAP *) Context;
   1348 
   1349   //
   1350   // Remove the Wrap from the list it belongs to.
   1351   //
   1352   RemoveEntryList (&Wrap->Link);
   1353 
   1354   //
   1355   // Free the Packet associated with this Wrap.
   1356   //
   1357   NetbufFree (Wrap->Packet);
   1358 
   1359   //
   1360   // Close the event.
   1361   //
   1362   gBS->CloseEvent (Wrap->RxData.RecycleSignal);
   1363 
   1364   FreePool (Wrap);
   1365 }
   1366 
   1367 
   1368 /**
   1369   This function wraps the Packet into RxData.
   1370 
   1371   @param[in]  Instance           Pointer to the instance context data.
   1372   @param[in]  Packet             Pointer to the buffer containing the received
   1373                                  datagram.
   1374   @param[in]  RxData             Pointer to the EFI_UDP6_RECEIVE_DATA of this
   1375                                  datagram.
   1376 
   1377   @return Pointer to the structure wrapping the RxData and the Packet.
   1378 
   1379 **/
   1380 UDP6_RXDATA_WRAP *
   1381 Udp6WrapRxData (
   1382   IN UDP6_INSTANCE_DATA     *Instance,
   1383   IN NET_BUF                *Packet,
   1384   IN EFI_UDP6_RECEIVE_DATA  *RxData
   1385   )
   1386 {
   1387   EFI_STATUS            Status;
   1388   UDP6_RXDATA_WRAP      *Wrap;
   1389 
   1390   //
   1391   // Allocate buffer for the Wrap.
   1392   //
   1393   Wrap = AllocateZeroPool (sizeof (UDP6_RXDATA_WRAP) +
   1394          (Packet->BlockOpNum - 1) * sizeof (EFI_UDP6_FRAGMENT_DATA));
   1395   if (Wrap == NULL) {
   1396     return NULL;
   1397   }
   1398 
   1399   InitializeListHead (&Wrap->Link);
   1400 
   1401   CopyMem (&Wrap->RxData, RxData, sizeof(EFI_UDP6_RECEIVE_DATA));
   1402   //
   1403   // Create the Recycle event.
   1404   //
   1405   Status = gBS->CreateEvent (
   1406                   EVT_NOTIFY_SIGNAL,
   1407                   TPL_NOTIFY,
   1408                   Udp6RecycleRxDataWrap,
   1409                   Wrap,
   1410                   &Wrap->RxData.RecycleSignal
   1411                   );
   1412   if (EFI_ERROR (Status)) {
   1413     FreePool (Wrap);
   1414     return NULL;
   1415   }
   1416 
   1417   Wrap->Packet      = Packet;
   1418   Wrap->TimeoutTick = Instance->ConfigData.ReceiveTimeout;
   1419 
   1420   return Wrap;
   1421 }
   1422 
   1423 
   1424 /**
   1425   This function enqueues the received datagram into the instances' receiving queues.
   1426 
   1427   @param[in]  Udp6Service        Pointer to the udp service context data.
   1428   @param[in]  Packet             Pointer to the buffer containing the received
   1429                                  datagram.
   1430   @param[in]  RxData             Pointer to the EFI_UDP6_RECEIVE_DATA of this
   1431                                  datagram.
   1432 
   1433   @return The times this datagram is enqueued.
   1434 
   1435 **/
   1436 UINTN
   1437 Udp6EnqueueDgram (
   1438   IN UDP6_SERVICE_DATA      *Udp6Service,
   1439   IN NET_BUF                *Packet,
   1440   IN EFI_UDP6_RECEIVE_DATA  *RxData
   1441   )
   1442 {
   1443   LIST_ENTRY          *Entry;
   1444   UDP6_INSTANCE_DATA  *Instance;
   1445   UDP6_RXDATA_WRAP    *Wrap;
   1446   UINTN               Enqueued;
   1447 
   1448   Enqueued = 0;
   1449 
   1450   NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) {
   1451     //
   1452     // Iterate the instances.
   1453     //
   1454     Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link);
   1455 
   1456     if (!Instance->Configured) {
   1457       continue;
   1458     }
   1459 
   1460     if (Udp6MatchDgram (Instance, &RxData->UdpSession)) {
   1461       //
   1462       // Wrap the RxData and put this Wrap into the instances RcvdDgramQue.
   1463       //
   1464       Wrap = Udp6WrapRxData (Instance, Packet, RxData);
   1465       if (Wrap == NULL) {
   1466         continue;
   1467       }
   1468 
   1469       NET_GET_REF (Packet);
   1470 
   1471       InsertTailList (&Instance->RcvdDgramQue, &Wrap->Link);
   1472 
   1473       Enqueued++;
   1474     }
   1475   }
   1476 
   1477   return Enqueued;
   1478 }
   1479 
   1480 
   1481 /**
   1482   This function delivers the received datagrams to the specified instance.
   1483 
   1484   @param[in]  Instance               Pointer to the instance context data.
   1485 
   1486 **/
   1487 VOID
   1488 Udp6InstanceDeliverDgram (
   1489   IN UDP6_INSTANCE_DATA  *Instance
   1490   )
   1491 {
   1492   UDP6_RXDATA_WRAP           *Wrap;
   1493   EFI_UDP6_COMPLETION_TOKEN  *Token;
   1494   NET_BUF                    *Dup;
   1495   EFI_UDP6_RECEIVE_DATA      *RxData;
   1496   EFI_TPL                    OldTpl;
   1497 
   1498   if (!IsListEmpty (&Instance->RcvdDgramQue) &&
   1499       !NetMapIsEmpty (&Instance->RxTokens)
   1500       ) {
   1501 
   1502     Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP6_RXDATA_WRAP, Link);
   1503 
   1504     if (NET_BUF_SHARED (Wrap->Packet)) {
   1505       //
   1506       // Duplicate the Packet if it is shared between instances.
   1507       //
   1508       Dup = NetbufDuplicate (Wrap->Packet, NULL, 0);
   1509       if (Dup == NULL) {
   1510         return;
   1511       }
   1512 
   1513       NetbufFree (Wrap->Packet);
   1514 
   1515       Wrap->Packet = Dup;
   1516     }
   1517 
   1518     NetListRemoveHead (&Instance->RcvdDgramQue);
   1519 
   1520     Token = (EFI_UDP6_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);
   1521 
   1522     //
   1523     // Build the FragmentTable and set the FragmentCount in RxData.
   1524     //
   1525     RxData                = &Wrap->RxData;
   1526     RxData->FragmentCount = Wrap->Packet->BlockOpNum;
   1527 
   1528     NetbufBuildExt (
   1529       Wrap->Packet,
   1530       (NET_FRAGMENT *) RxData->FragmentTable,
   1531       &RxData->FragmentCount
   1532       );
   1533 
   1534     Token->Status        = EFI_SUCCESS;
   1535     Token->Packet.RxData = &Wrap->RxData;
   1536 
   1537     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   1538     InsertTailList (&Instance->DeliveredDgramQue, &Wrap->Link);
   1539     gBS->RestoreTPL (OldTpl);
   1540 
   1541     gBS->SignalEvent (Token->Event);
   1542   }
   1543 }
   1544 
   1545 
   1546 /**
   1547   This function delivers the datagrams enqueued in the instances.
   1548 
   1549   @param[in]  Udp6Service            Pointer to the udp service context data.
   1550 
   1551 **/
   1552 VOID
   1553 Udp6DeliverDgram (
   1554   IN UDP6_SERVICE_DATA  *Udp6Service
   1555   )
   1556 {
   1557   LIST_ENTRY          *Entry;
   1558   UDP6_INSTANCE_DATA  *Instance;
   1559 
   1560   NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) {
   1561     //
   1562     // Iterate the instances.
   1563     //
   1564     Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link);
   1565 
   1566     if (!Instance->Configured) {
   1567       continue;
   1568     }
   1569 
   1570     //
   1571     // Deliver the datagrams of this instance.
   1572     //
   1573     Udp6InstanceDeliverDgram (Instance);
   1574   }
   1575 }
   1576 
   1577 
   1578 /**
   1579   This function demultiplexes the received udp datagram to the appropriate instances.
   1580 
   1581   @param[in]  Udp6Service        Pointer to the udp service context data.
   1582   @param[in]  NetSession         Pointer to the EFI_NET_SESSION_DATA abstracted from
   1583                                  the received datagram.
   1584   @param[in]  Packet             Pointer to the buffer containing the received udp
   1585                                  datagram.
   1586 
   1587 **/
   1588 VOID
   1589 Udp6Demultiplex (
   1590   IN UDP6_SERVICE_DATA     *Udp6Service,
   1591   IN EFI_NET_SESSION_DATA  *NetSession,
   1592   IN NET_BUF               *Packet
   1593   )
   1594 {
   1595   EFI_UDP_HEADER        *Udp6Header;
   1596   UINT16                 HeadSum;
   1597   EFI_UDP6_RECEIVE_DATA  RxData;
   1598   EFI_UDP6_SESSION_DATA  *Udp6Session;
   1599   UINTN                  Enqueued;
   1600 
   1601   if (Packet->TotalSize < sizeof (EFI_UDP_HEADER)) {
   1602     NetbufFree (Packet);
   1603     return;
   1604   }
   1605 
   1606   //
   1607   // Get the datagram header from the packet buffer.
   1608   //
   1609   Udp6Header = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL);
   1610   ASSERT (Udp6Header != NULL);
   1611 
   1612   if (Udp6Header->Checksum != 0) {
   1613     //
   1614     // check the checksum.
   1615     //
   1616     HeadSum = NetIp6PseudoHeadChecksum (
   1617                 &NetSession->Source.v6,
   1618                 &NetSession->Dest.v6,
   1619                 EFI_IP_PROTO_UDP,
   1620                 0
   1621                 );
   1622 
   1623     if (Udp6Checksum (Packet, HeadSum) != 0) {
   1624       //
   1625       // Wrong checksum.
   1626       //
   1627       NetbufFree (Packet);
   1628       return;
   1629     }
   1630   }
   1631 
   1632   Udp6Session                  = &RxData.UdpSession;
   1633   Udp6Session->SourcePort      = NTOHS (Udp6Header->SrcPort);
   1634   Udp6Session->DestinationPort = NTOHS (Udp6Header->DstPort);
   1635 
   1636   IP6_COPY_ADDRESS (&Udp6Session->SourceAddress, &NetSession->Source);
   1637   IP6_COPY_ADDRESS (&Udp6Session->DestinationAddress, &NetSession->Dest);
   1638 
   1639   //
   1640   // Trim the UDP header.
   1641   //
   1642   NetbufTrim (Packet, UDP6_HEADER_SIZE, TRUE);
   1643 
   1644   RxData.DataLength = (UINT32) Packet->TotalSize;
   1645 
   1646   //
   1647   // Try to enqueue this datagram into the instances.
   1648   //
   1649   Enqueued = Udp6EnqueueDgram (Udp6Service, Packet, &RxData);
   1650 
   1651   if (Enqueued == 0) {
   1652     //
   1653     // Send the port unreachable ICMP packet before we free this NET_BUF
   1654     //
   1655     Udp6SendPortUnreach (Udp6Service->IpIo, NetSession, Udp6Header);
   1656   }
   1657 
   1658   //
   1659   // Try to free the packet before deliver it.
   1660   //
   1661   NetbufFree (Packet);
   1662 
   1663   if (Enqueued > 0) {
   1664     //
   1665     // Deliver the datagram.
   1666     //
   1667     Udp6DeliverDgram (Udp6Service);
   1668   }
   1669 }
   1670 
   1671 
   1672 /**
   1673   This function builds and sends out a icmp port unreachable message.
   1674 
   1675   @param[in]  IpIo               Pointer to the IP_IO instance.
   1676   @param[in]  NetSession         Pointer to the EFI_NET_SESSION_DATA of the packet
   1677                                  causes this icmp error message.
   1678   @param[in]  Udp6Header         Pointer to the udp header of the datagram causes
   1679                                  this icmp error message.
   1680 
   1681 **/
   1682 VOID
   1683 Udp6SendPortUnreach (
   1684   IN IP_IO                 *IpIo,
   1685   IN EFI_NET_SESSION_DATA  *NetSession,
   1686   IN VOID                  *Udp6Header
   1687   )
   1688 {
   1689   NET_BUF              *Packet;
   1690   UINT32               Len;
   1691   IP6_ICMP_ERROR_HEAD  *IcmpErrHdr;
   1692   UINT8                *Ptr;
   1693   IP_IO_OVERRIDE       Override;
   1694   IP_IO_IP_INFO        *IpSender;
   1695   EFI_IP6_MODE_DATA    *Ip6ModeData;
   1696   EFI_STATUS           Status;
   1697   EFI_IP6_PROTOCOL     *Ip6Protocol;
   1698 
   1699   Ip6ModeData = NULL;
   1700 
   1701   //
   1702   // An ICMPv6 error message MUST NOT be originated as A packet destined to
   1703   // 1) an IPv6 multicast address 2) The IPv6 Unspecified Address
   1704   //
   1705   if (NetSession->IpVersion == IP_VERSION_6) {
   1706     if (NetIp6IsUnspecifiedAddr (&NetSession->Dest.v6) ||
   1707       IP6_IS_MULTICAST (&NetSession->Dest.v6)
   1708       ) {
   1709       goto EXIT;
   1710     }
   1711   }
   1712 
   1713 
   1714   IpSender    = IpIoFindSender (&IpIo, NetSession->IpVersion, &NetSession->Dest);
   1715 
   1716   //
   1717   // Get the Ipv6 Mode Data.
   1718   //
   1719   Ip6ModeData = AllocateZeroPool (sizeof (EFI_IP6_MODE_DATA));
   1720   ASSERT (Ip6ModeData != NULL);
   1721 
   1722   //
   1723   // If not finding the related IpSender use the default IpIo to send out
   1724   // the port unreachable ICMP message.
   1725   //
   1726   if (IpSender == NULL) {
   1727     Ip6Protocol = IpIo->Ip.Ip6;
   1728   } else {
   1729     Ip6Protocol = IpSender->Ip.Ip6;
   1730   }
   1731 
   1732   Status = Ip6Protocol->GetModeData (
   1733                           Ip6Protocol,
   1734                           Ip6ModeData,
   1735                           NULL,
   1736                           NULL
   1737                           );
   1738 
   1739   if (EFI_ERROR (Status)) {
   1740     goto EXIT;
   1741   }
   1742   //
   1743   // The ICMP6 packet length, includes whole invoking packet and ICMP6 error header.
   1744   //
   1745   Len = NetSession->IpHdrLen +
   1746         NTOHS(((EFI_UDP_HEADER *) Udp6Header)->Length) +
   1747         sizeof (IP6_ICMP_ERROR_HEAD);
   1748 
   1749   //
   1750   // If the ICMP6 packet length larger than IP MTU, adjust its length to MTU.
   1751   //
   1752   if (Ip6ModeData->MaxPacketSize < Len) {
   1753     Len = Ip6ModeData->MaxPacketSize;
   1754   }
   1755 
   1756   //
   1757   // Allocate buffer for the icmp error message.
   1758   //
   1759   Packet = NetbufAlloc (Len);
   1760   if (Packet == NULL) {
   1761     goto EXIT;
   1762   }
   1763 
   1764   //
   1765   // Allocate space for the IP6_ICMP_ERROR_HEAD.
   1766   //
   1767   IcmpErrHdr = (IP6_ICMP_ERROR_HEAD *) NetbufAllocSpace (Packet, Len, FALSE);
   1768   ASSERT (IcmpErrHdr != NULL);
   1769 
   1770   //
   1771   // Set the required fields for the icmp port unreachable message.
   1772   //
   1773   IcmpErrHdr->Head.Type     = ICMP_V6_DEST_UNREACHABLE;
   1774   IcmpErrHdr->Head.Code     = ICMP_V6_PORT_UNREACHABLE;
   1775   IcmpErrHdr->Head.Checksum = 0;
   1776   IcmpErrHdr->Fourth        = 0;
   1777 
   1778   //
   1779   // Copy as much of invoking Packet as possible without the ICMPv6 packet
   1780   // exceeding the minimum Ipv6 MTU. The length of IP6_ICMP_ERROR_HEAD contains
   1781   // the length of EFI_IP6_HEADER, so when using the length of IP6_ICMP_ERROR_HEAD
   1782   // for pointer movement that fact should be considered.
   1783   //
   1784   Ptr = (VOID *) &IcmpErrHdr->Head;
   1785   Ptr = (UINT8 *) (UINTN) ((UINTN) Ptr + sizeof (IP6_ICMP_ERROR_HEAD) - sizeof (EFI_IP6_HEADER));
   1786   CopyMem (Ptr, NetSession->IpHdr.Ip6Hdr, NetSession->IpHdrLen);
   1787   CopyMem (
   1788     Ptr + NetSession->IpHdrLen,
   1789     Udp6Header,
   1790     Len - NetSession->IpHdrLen - sizeof (IP6_ICMP_ERROR_HEAD) + sizeof (EFI_IP6_HEADER)
   1791     );
   1792 
   1793   //
   1794   // Set the checksum as zero, and IP6 driver will calcuate it with pseudo header.
   1795   //
   1796   IcmpErrHdr->Head.Checksum = 0;
   1797 
   1798   //
   1799   // Fill the override data.
   1800   //
   1801   Override.Ip6OverrideData.FlowLabel     = 0;
   1802   Override.Ip6OverrideData.HopLimit      = 255;
   1803   Override.Ip6OverrideData.Protocol      = IP6_ICMP;
   1804 
   1805   //
   1806   // Send out this icmp packet.
   1807   //
   1808   IpIoSend (IpIo, Packet, IpSender, NULL, NULL, &NetSession->Source, &Override);
   1809 
   1810   NetbufFree (Packet);
   1811 
   1812 EXIT:
   1813   if (Ip6ModeData != NULL) {
   1814     FreePool (Ip6ModeData);
   1815   }
   1816 }
   1817 
   1818 
   1819 /**
   1820   This function handles the received Icmp Error message and de-multiplexes it to the
   1821   instance.
   1822 
   1823   @param[in]       Udp6Service        Pointer to the udp service context data.
   1824   @param[in]       IcmpError          The icmp error code.
   1825   @param[in]       NetSession         Pointer to the EFI_NET_SESSION_DATA abstracted
   1826                                       from the received Icmp Error packet.
   1827   @param[in, out]  Packet             Pointer to the Icmp Error packet.
   1828 
   1829 **/
   1830 VOID
   1831 Udp6IcmpHandler (
   1832   IN UDP6_SERVICE_DATA     *Udp6Service,
   1833   IN UINT8                 IcmpError,
   1834   IN EFI_NET_SESSION_DATA  *NetSession,
   1835   IN OUT NET_BUF           *Packet
   1836   )
   1837 {
   1838   EFI_UDP_HEADER         *Udp6Header;
   1839   EFI_UDP6_SESSION_DATA  Udp6Session;
   1840   LIST_ENTRY             *Entry;
   1841   UDP6_INSTANCE_DATA     *Instance;
   1842 
   1843   if (Packet->TotalSize < sizeof (EFI_UDP_HEADER)) {
   1844     NetbufFree (Packet);
   1845     return;
   1846   }
   1847 
   1848   Udp6Header = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL);
   1849   ASSERT (Udp6Header != NULL);
   1850 
   1851   IP6_COPY_ADDRESS (&Udp6Session.SourceAddress, &NetSession->Source);
   1852   IP6_COPY_ADDRESS (&Udp6Session.DestinationAddress, &NetSession->Dest);
   1853 
   1854   Udp6Session.SourcePort      = NTOHS (Udp6Header->DstPort);
   1855   Udp6Session.DestinationPort = NTOHS (Udp6Header->SrcPort);
   1856 
   1857   NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) {
   1858     //
   1859     // Iterate all the instances.
   1860     //
   1861     Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link);
   1862 
   1863     if (!Instance->Configured) {
   1864       continue;
   1865     }
   1866 
   1867     if (Udp6MatchDgram (Instance, &Udp6Session)) {
   1868       //
   1869       // Translate the Icmp Error code according to the udp spec.
   1870       //
   1871       Instance->IcmpError = IpIoGetIcmpErrStatus (IcmpError, IP_VERSION_6, NULL, NULL);
   1872 
   1873       if (IcmpError > ICMP_ERR_UNREACH_PORT) {
   1874         Instance->IcmpError = EFI_ICMP_ERROR;
   1875       }
   1876 
   1877       //
   1878       // Notify the instance with the received Icmp Error.
   1879       //
   1880       Udp6ReportIcmpError (Instance);
   1881 
   1882       break;
   1883     }
   1884   }
   1885 
   1886   NetbufFree (Packet);
   1887 }
   1888 
   1889 
   1890 /**
   1891   This function reports the received ICMP error.
   1892 
   1893   @param[in]  Instance          Pointer to the udp instance context data.
   1894 
   1895 **/
   1896 VOID
   1897 Udp6ReportIcmpError (
   1898   IN UDP6_INSTANCE_DATA  *Instance
   1899   )
   1900 {
   1901   EFI_UDP6_COMPLETION_TOKEN  *Token;
   1902 
   1903   if (NetMapIsEmpty (&Instance->RxTokens)) {
   1904     //
   1905     // There are no receive tokens to deliver the ICMP error.
   1906     //
   1907     return;
   1908   }
   1909 
   1910   if (EFI_ERROR (Instance->IcmpError)) {
   1911     //
   1912     // Try to get a RxToken from the RxTokens map.
   1913     //
   1914     Token = (EFI_UDP6_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);
   1915 
   1916     if (Token != NULL) {
   1917       //
   1918       // Report the error through the Token.
   1919       //
   1920       Token->Status = Instance->IcmpError;
   1921       gBS->SignalEvent (Token->Event);
   1922 
   1923       //
   1924       // Clear the IcmpError.
   1925       //
   1926       Instance->IcmpError = EFI_SUCCESS;
   1927     }
   1928   }
   1929 }
   1930 
   1931 
   1932 /**
   1933   This function is a dummy ext-free function for the NET_BUF created for the output
   1934   udp datagram.
   1935 
   1936   @param[in]  Context                Pointer to the context data.
   1937 
   1938 **/
   1939 VOID
   1940 EFIAPI
   1941 Udp6NetVectorExtFree (
   1942   IN VOID  *Context
   1943   )
   1944 {
   1945 }
   1946 
   1947 /**
   1948   Find the key in the netmap.
   1949 
   1950   @param[in]  Map                    The netmap to search within.
   1951   @param[in]  Key                    The key to search.
   1952 
   1953   @return The point to the item contains the Key, or NULL, if Key isn't in the map.
   1954 
   1955 **/
   1956 NET_MAP_ITEM *
   1957 Udp6MapMultiCastAddr (
   1958   IN  NET_MAP               *Map,
   1959   IN  VOID                  *Key
   1960   )
   1961 {
   1962   LIST_ENTRY        *Entry;
   1963   NET_MAP_ITEM      *Item;
   1964   EFI_IPv6_ADDRESS  *Addr;
   1965 
   1966   ASSERT (Map != NULL);
   1967   NET_LIST_FOR_EACH (Entry, &Map->Used) {
   1968     Item  = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1969     Addr  = (EFI_IPv6_ADDRESS *) Item->Key;
   1970     if (EFI_IP6_EQUAL (Addr, Key)) {
   1971       return Item;
   1972     }
   1973   }
   1974   return NULL;
   1975 }
   1976 
   1977