Home | History | Annotate | Download | only in Ip6Dxe
      1 /** @file
      2   Implement IP6 pesudo interface.
      3 
      4   Copyright (c) 2009 - 2012, 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 "Ip6Impl.h"
     17 
     18 /**
     19   Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK.
     20 
     21   @param[in]  Event              The transmit token's event.
     22   @param[in]  Context            The Context which is pointed to the token.
     23 
     24 **/
     25 VOID
     26 EFIAPI
     27 Ip6OnFrameSent (
     28   IN EFI_EVENT               Event,
     29   IN VOID                    *Context
     30   );
     31 
     32 /**
     33   Fileter function to cancel all the frame related to an IP instance.
     34 
     35   @param[in]  Frame             The transmit request to test whether to cancel.
     36   @param[in]  Context           The context which is the Ip instance that issued
     37                                 the transmit.
     38 
     39   @retval TRUE                  The frame belongs to this instance and is to be
     40                                 removed.
     41   @retval FALSE                 The frame doesn't belong to this instance.
     42 
     43 **/
     44 BOOLEAN
     45 Ip6CancelInstanceFrame (
     46   IN IP6_LINK_TX_TOKEN *Frame,
     47   IN VOID              *Context
     48   )
     49 {
     50   if (Frame->IpInstance == (IP6_PROTOCOL *) Context) {
     51     return TRUE;
     52   }
     53 
     54   return FALSE;
     55 }
     56 
     57 /**
     58   Set the interface's address. This will trigger the DAD process for the
     59   address to set. To set an already set address, the lifetimes wil be
     60   updated to the new value passed in.
     61 
     62   @param[in]  Interface             The interface to set the address.
     63   @param[in]  Ip6Addr               The interface's to be assigned IPv6 address.
     64   @param[in]  IsAnycast             If TRUE, the unicast IPv6 address is anycast.
     65                                     Otherwise, it is not anycast.
     66   @param[in]  PrefixLength          The prefix length of the Ip6Addr.
     67   @param[in]  ValidLifetime         The valid lifetime for this address.
     68   @param[in]  PreferredLifetime     The preferred lifetime for this address.
     69   @param[in]  DadCallback           The caller's callback to trigger when DAD finishes.
     70                                     This is an optional parameter that may be NULL.
     71   @param[in]  Context               The context that will be passed to DadCallback.
     72                                     This is an optional parameter that may be NULL.
     73 
     74   @retval EFI_SUCCESS               The interface is scheduled to be configured with
     75                                     the specified address.
     76   @retval EFI_OUT_OF_RESOURCES      Failed to set the interface's address due to
     77                                     lack of resources.
     78 
     79 **/
     80 EFI_STATUS
     81 Ip6SetAddress (
     82   IN IP6_INTERFACE          *Interface,
     83   IN EFI_IPv6_ADDRESS       *Ip6Addr,
     84   IN BOOLEAN                IsAnycast,
     85   IN UINT8                  PrefixLength,
     86   IN UINT32                 ValidLifetime,
     87   IN UINT32                 PreferredLifetime,
     88   IN IP6_DAD_CALLBACK       DadCallback  OPTIONAL,
     89   IN VOID                   *Context     OPTIONAL
     90   )
     91 {
     92   IP6_SERVICE            *IpSb;
     93   IP6_ADDRESS_INFO       *AddressInfo;
     94   LIST_ENTRY             *Entry;
     95   IP6_PREFIX_LIST_ENTRY  *PrefixEntry;
     96   UINT64                 Delay;
     97   IP6_DELAY_JOIN_LIST    *DelayNode;
     98 
     99   NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE);
    100 
    101   IpSb = Interface->Service;
    102 
    103   if (Ip6IsOneOfSetAddress (IpSb, Ip6Addr, NULL, &AddressInfo)) {
    104     ASSERT (AddressInfo != NULL);
    105     //
    106     // Update the lifetime.
    107     //
    108     AddressInfo->ValidLifetime     = ValidLifetime;
    109     AddressInfo->PreferredLifetime = PreferredLifetime;
    110 
    111     if (DadCallback != NULL) {
    112       DadCallback (TRUE, Ip6Addr, Context);
    113     }
    114 
    115     return EFI_SUCCESS;
    116   }
    117 
    118   AddressInfo = (IP6_ADDRESS_INFO *) AllocatePool (sizeof (IP6_ADDRESS_INFO));
    119   if (AddressInfo == NULL) {
    120     return EFI_OUT_OF_RESOURCES;
    121   }
    122 
    123   AddressInfo->Signature         = IP6_ADDR_INFO_SIGNATURE;
    124   IP6_COPY_ADDRESS (&AddressInfo->Address, Ip6Addr);
    125   AddressInfo->IsAnycast         = IsAnycast;
    126   AddressInfo->PrefixLength      = PrefixLength;
    127   AddressInfo->ValidLifetime     = ValidLifetime;
    128   AddressInfo->PreferredLifetime = PreferredLifetime;
    129 
    130   if (AddressInfo->PrefixLength == 0) {
    131     //
    132     // Find an appropriate prefix from on-link prefixes and update the prefixlength.
    133     // Longest prefix match is used here.
    134     //
    135     NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
    136       PrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
    137 
    138       if (NetIp6IsNetEqual (&PrefixEntry->Prefix, &AddressInfo->Address, PrefixEntry->PrefixLength)) {
    139         AddressInfo->PrefixLength = PrefixEntry->PrefixLength;
    140         break;
    141       }
    142     }
    143   }
    144 
    145   if (AddressInfo->PrefixLength == 0) {
    146     //
    147     // If the prefix length is still zero, try the autonomous prefixes.
    148     // Longest prefix match is used here.
    149     //
    150     NET_LIST_FOR_EACH (Entry, &IpSb->AutonomousPrefix) {
    151       PrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
    152 
    153       if (NetIp6IsNetEqual (&PrefixEntry->Prefix, &AddressInfo->Address, PrefixEntry->PrefixLength)) {
    154         AddressInfo->PrefixLength = PrefixEntry->PrefixLength;
    155         break;
    156       }
    157     }
    158   }
    159 
    160   if (AddressInfo->PrefixLength == 0) {
    161     //
    162     // BUGBUG: Stil fail, use 64 as the default prefix length.
    163     //
    164     AddressInfo->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;
    165   }
    166 
    167 
    168   //
    169   // Node should delay joining the solicited-node mulitcast address by a random delay
    170   // between 0 and MAX_RTR_SOLICITATION_DELAY (1 second).
    171   // Thus queue the address to be processed in Duplicate Address Detection module
    172   // after the delay time (in milliseconds).
    173   //
    174   Delay = (UINT64) NET_RANDOM (NetRandomInitSeed ());
    175   Delay = MultU64x32 (Delay, IP6_ONE_SECOND_IN_MS);
    176   Delay = RShiftU64 (Delay, 32);
    177 
    178   DelayNode = (IP6_DELAY_JOIN_LIST *) AllocatePool (sizeof (IP6_DELAY_JOIN_LIST));
    179   if (DelayNode == NULL) {
    180     FreePool (AddressInfo);
    181     return EFI_OUT_OF_RESOURCES;
    182   }
    183 
    184   DelayNode->DelayTime   = (UINT32) (DivU64x32 (Delay, IP6_TIMER_INTERVAL_IN_MS));
    185   DelayNode->Interface   = Interface;
    186   DelayNode->AddressInfo = AddressInfo;
    187   DelayNode->DadCallback = DadCallback;
    188   DelayNode->Context     = Context;
    189 
    190   InsertTailList (&Interface->DelayJoinList, &DelayNode->Link);
    191   return EFI_SUCCESS;
    192 }
    193 
    194 /**
    195   Create an IP6_INTERFACE.
    196 
    197   @param[in]  IpSb                  The IP6 service binding instance.
    198   @param[in]  LinkLocal             If TRUE, the instance is created for link-local address.
    199                                     Otherwise, it is not for a link-local address.
    200 
    201   @return Point to the created IP6_INTERFACE, otherwise NULL.
    202 
    203 **/
    204 IP6_INTERFACE *
    205 Ip6CreateInterface (
    206   IN IP6_SERVICE            *IpSb,
    207   IN BOOLEAN                LinkLocal
    208   )
    209 {
    210   EFI_STATUS                Status;
    211   IP6_INTERFACE             *Interface;
    212   EFI_IPv6_ADDRESS          *Ip6Addr;
    213 
    214   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    215 
    216   Interface = AllocatePool (sizeof (IP6_INTERFACE));
    217   if (Interface == NULL) {
    218     return NULL;
    219   }
    220 
    221   Interface->Signature        = IP6_INTERFACE_SIGNATURE;
    222   Interface->RefCnt           = 1;
    223 
    224   InitializeListHead (&Interface->AddressList);
    225   Interface->AddressCount     = 0;
    226   Interface->Configured       = FALSE;
    227 
    228   Interface->Service          = IpSb;
    229   Interface->Controller       = IpSb->Controller;
    230   Interface->Image            = IpSb->Image;
    231 
    232   InitializeListHead (&Interface->ArpQues);
    233   InitializeListHead (&Interface->SentFrames);
    234 
    235   Interface->DupAddrDetect    = IpSb->Ip6ConfigInstance.DadXmits.DupAddrDetectTransmits;
    236   InitializeListHead (&Interface->DupAddrDetectList);
    237 
    238   InitializeListHead (&Interface->DelayJoinList);
    239 
    240   InitializeListHead (&Interface->IpInstances);
    241   Interface->PromiscRecv      = FALSE;
    242 
    243   if (!LinkLocal) {
    244     return Interface;
    245   }
    246 
    247   //
    248   // Get the link local addr
    249   //
    250   Ip6Addr = Ip6CreateLinkLocalAddr (IpSb);
    251   if (Ip6Addr == NULL) {
    252     goto ON_ERROR;
    253   }
    254 
    255   //
    256   // Perform DAD - Duplicate Address Detection.
    257   //
    258   Status = Ip6SetAddress (
    259              Interface,
    260              Ip6Addr,
    261              FALSE,
    262              IP6_LINK_LOCAL_PREFIX_LENGTH,
    263              (UINT32) IP6_INFINIT_LIFETIME,
    264              (UINT32) IP6_INFINIT_LIFETIME,
    265              NULL,
    266              NULL
    267              );
    268 
    269   FreePool (Ip6Addr);
    270 
    271   if (EFI_ERROR (Status)) {
    272     goto ON_ERROR;
    273   }
    274 
    275   return Interface;
    276 
    277 ON_ERROR:
    278 
    279   FreePool (Interface);
    280   return NULL;
    281 }
    282 
    283 /**
    284   Free the interface used by IpInstance. All the IP instance with
    285   the same Ip/prefix pair share the same interface. It is reference
    286   counted. All the frames that haven't been sent will be cancelled.
    287   Because the IpInstance is optional, the caller must remove
    288   IpInstance from the interface's instance list.
    289 
    290   @param[in]  Interface         The interface used by the IpInstance.
    291   @param[in]  IpInstance        The IP instance that free the interface. NULL if
    292                                 the IP driver is releasing the default interface.
    293 
    294 **/
    295 VOID
    296 Ip6CleanInterface (
    297   IN  IP6_INTERFACE         *Interface,
    298   IN  IP6_PROTOCOL          *IpInstance           OPTIONAL
    299   )
    300 {
    301   IP6_DAD_ENTRY             *Duplicate;
    302   IP6_DELAY_JOIN_LIST       *Delay;
    303 
    304   NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE);
    305   ASSERT (Interface->RefCnt > 0);
    306 
    307   //
    308   // Remove all the pending transmit token related to this IP instance.
    309   //
    310   Ip6CancelFrames (Interface, EFI_ABORTED, Ip6CancelInstanceFrame, IpInstance);
    311 
    312   if (--Interface->RefCnt > 0) {
    313     return;
    314   }
    315 
    316   //
    317   // Destroy the interface if this is the last IP instance.
    318   // Remove all the system transmitted packets
    319   // from this interface, cancel the receive request if exists.
    320   //
    321   Ip6CancelFrames (Interface, EFI_ABORTED, Ip6CancelInstanceFrame, NULL);
    322 
    323   ASSERT (IsListEmpty (&Interface->IpInstances));
    324   ASSERT (IsListEmpty (&Interface->ArpQues));
    325   ASSERT (IsListEmpty (&Interface->SentFrames));
    326 
    327   while (!IsListEmpty (&Interface->DupAddrDetectList)) {
    328     Duplicate = NET_LIST_HEAD (&Interface->DupAddrDetectList, IP6_DAD_ENTRY, Link);
    329     NetListRemoveHead (&Interface->DupAddrDetectList);
    330     FreePool (Duplicate);
    331   }
    332 
    333   while (!IsListEmpty (&Interface->DelayJoinList)) {
    334     Delay = NET_LIST_HEAD (&Interface->DelayJoinList, IP6_DELAY_JOIN_LIST, Link);
    335     NetListRemoveHead (&Interface->DelayJoinList);
    336     FreePool (Delay);
    337   }
    338 
    339   Ip6RemoveAddr (Interface->Service, &Interface->AddressList, &Interface->AddressCount, NULL, 0);
    340 
    341   RemoveEntryList (&Interface->Link);
    342   FreePool (Interface);
    343 }
    344 
    345 /**
    346   Create and wrap a transmit request into a newly allocated IP6_LINK_TX_TOKEN.
    347 
    348   @param[in]  Interface         The interface to send out from.
    349   @param[in]  IpInstance        The IpInstance that transmit the packet.  NULL if
    350                                 the packet is sent by the IP6 driver itself.
    351   @param[in]  Packet            The packet to transmit
    352   @param[in]  CallBack          Call back function to execute if transmission
    353                                 finished.
    354   @param[in]  Context           Opaque parameter to the callback.
    355 
    356   @return The wrapped token if succeed or NULL.
    357 
    358 **/
    359 IP6_LINK_TX_TOKEN *
    360 Ip6CreateLinkTxToken (
    361   IN IP6_INTERFACE          *Interface,
    362   IN IP6_PROTOCOL           *IpInstance    OPTIONAL,
    363   IN NET_BUF                *Packet,
    364   IN IP6_FRAME_CALLBACK     CallBack,
    365   IN VOID                   *Context
    366   )
    367 {
    368   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
    369   EFI_MANAGED_NETWORK_TRANSMIT_DATA     *MnpTxData;
    370   IP6_LINK_TX_TOKEN                     *Token;
    371   EFI_STATUS                            Status;
    372   UINT32                                Count;
    373 
    374   Token = AllocatePool (sizeof (IP6_LINK_TX_TOKEN) + (Packet->BlockOpNum - 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA));
    375 
    376   if (Token == NULL) {
    377     return NULL;
    378   }
    379 
    380   Token->Signature = IP6_LINK_TX_SIGNATURE;
    381   InitializeListHead (&Token->Link);
    382 
    383   Token->IpInstance = IpInstance;
    384   Token->CallBack   = CallBack;
    385   Token->Packet     = Packet;
    386   Token->Context    = Context;
    387   ZeroMem (&Token->DstMac, sizeof (EFI_MAC_ADDRESS));
    388   IP6_COPY_LINK_ADDRESS (&Token->SrcMac, &Interface->Service->SnpMode.CurrentAddress);
    389 
    390   MnpToken          = &(Token->MnpToken);
    391   MnpToken->Status  = EFI_NOT_READY;
    392 
    393   Status = gBS->CreateEvent (
    394                   EVT_NOTIFY_SIGNAL,
    395                   TPL_NOTIFY,
    396                   Ip6OnFrameSent,
    397                   Token,
    398                   &MnpToken->Event
    399                   );
    400 
    401   if (EFI_ERROR (Status)) {
    402     FreePool (Token);
    403     return NULL;
    404   }
    405 
    406   MnpTxData                     = &Token->MnpTxData;
    407   MnpToken->Packet.TxData       = MnpTxData;
    408 
    409   MnpTxData->DestinationAddress = &Token->DstMac;
    410   MnpTxData->SourceAddress      = &Token->SrcMac;
    411   MnpTxData->ProtocolType       = IP6_ETHER_PROTO;
    412   MnpTxData->DataLength         = Packet->TotalSize;
    413   MnpTxData->HeaderLength       = 0;
    414 
    415   Count                         = Packet->BlockOpNum;
    416 
    417   NetbufBuildExt (Packet, (NET_FRAGMENT *) MnpTxData->FragmentTable, &Count);
    418   MnpTxData->FragmentCount      = (UINT16)Count;
    419 
    420   return Token;
    421 }
    422 
    423 /**
    424   Free the link layer transmit token. It will close the event,
    425   then free the memory used.
    426 
    427   @param[in]  Token                 Token to free.
    428 
    429 **/
    430 VOID
    431 Ip6FreeLinkTxToken (
    432   IN IP6_LINK_TX_TOKEN      *Token
    433   )
    434 {
    435   NET_CHECK_SIGNATURE (Token, IP6_LINK_TX_SIGNATURE);
    436 
    437   gBS->CloseEvent (Token->MnpToken.Event);
    438   FreePool (Token);
    439 }
    440 
    441 /**
    442   Callback function when the received packet is freed.
    443   Check Ip6OnFrameReceived for information.
    444 
    445   @param[in]  Context       Points to EFI_MANAGED_NETWORK_RECEIVE_DATA.
    446 
    447 **/
    448 VOID
    449 EFIAPI
    450 Ip6RecycleFrame (
    451   IN VOID                   *Context
    452   )
    453 {
    454   EFI_MANAGED_NETWORK_RECEIVE_DATA  *RxData;
    455 
    456   RxData = (EFI_MANAGED_NETWORK_RECEIVE_DATA *) Context;
    457 
    458   gBS->SignalEvent (RxData->RecycleEvent);
    459 }
    460 
    461 /**
    462   Received a frame from MNP. Wrap it in net buffer then deliver
    463   it to IP's input function. The ownship of the packet also
    464   is transferred to IP. When Ip is finished with this packet, it
    465   will call NetbufFree to release the packet, NetbufFree will
    466   again call the Ip6RecycleFrame to signal MNP's event and free
    467   the token used.
    468 
    469   @param[in]  Context         Context for the callback.
    470 
    471 **/
    472 VOID
    473 EFIAPI
    474 Ip6OnFrameReceivedDpc (
    475   IN VOID                     *Context
    476   )
    477 {
    478   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
    479   EFI_MANAGED_NETWORK_RECEIVE_DATA      *MnpRxData;
    480   IP6_LINK_RX_TOKEN                     *Token;
    481   NET_FRAGMENT                          Netfrag;
    482   NET_BUF                               *Packet;
    483   UINT32                                Flag;
    484   IP6_SERVICE                           *IpSb;
    485 
    486   Token = (IP6_LINK_RX_TOKEN *) Context;
    487   NET_CHECK_SIGNATURE (Token, IP6_LINK_RX_SIGNATURE);
    488 
    489   //
    490   // First clear the interface's receive request in case the
    491   // caller wants to call Ip6ReceiveFrame in the callback.
    492   //
    493   IpSb = (IP6_SERVICE *) Token->Context;
    494   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    495 
    496 
    497   MnpToken  = &Token->MnpToken;
    498   MnpRxData = MnpToken->Packet.RxData;
    499 
    500   if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {
    501     Token->CallBack (NULL, MnpToken->Status, 0, Token->Context);
    502     return ;
    503   }
    504 
    505   //
    506   // Wrap the frame in a net buffer then deliever it to IP input.
    507   // IP will reassemble the packet, and deliver it to upper layer
    508   //
    509   Netfrag.Len  = MnpRxData->DataLength;
    510   Netfrag.Bulk = MnpRxData->PacketData;
    511 
    512   Packet = NetbufFromExt (&Netfrag, 1, IP6_MAX_HEADLEN, 0, Ip6RecycleFrame, Token->MnpToken.Packet.RxData);
    513 
    514   if (Packet == NULL) {
    515     gBS->SignalEvent (MnpRxData->RecycleEvent);
    516 
    517     Token->CallBack (NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);
    518 
    519     return ;
    520   }
    521 
    522   Flag  = (MnpRxData->BroadcastFlag ? IP6_LINK_BROADCAST : 0);
    523   Flag |= (MnpRxData->MulticastFlag ? IP6_LINK_MULTICAST : 0);
    524   Flag |= (MnpRxData->PromiscuousFlag ? IP6_LINK_PROMISC : 0);
    525 
    526   Token->CallBack (Packet, EFI_SUCCESS, Flag, Token->Context);
    527 }
    528 
    529 /**
    530   Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
    531 
    532   @param  Event                 The receive event delivered to MNP for receive.
    533   @param  Context               Context for the callback.
    534 
    535 **/
    536 VOID
    537 EFIAPI
    538 Ip6OnFrameReceived (
    539   IN EFI_EVENT                Event,
    540   IN VOID                     *Context
    541   )
    542 {
    543   //
    544   // Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK
    545   //
    546   QueueDpc (TPL_CALLBACK, Ip6OnFrameReceivedDpc, Context);
    547 }
    548 
    549 /**
    550   Request to receive the packet from the interface.
    551 
    552   @param[in]  CallBack          Function to call when receive finished.
    553   @param[in]  IpSb              Points to IP6 service binding instance.
    554 
    555   @retval EFI_ALREADY_STARTED   There is already a pending receive request.
    556   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to receive.
    557   @retval EFI_SUCCESS           The recieve request has been started.
    558 
    559 **/
    560 EFI_STATUS
    561 Ip6ReceiveFrame (
    562   IN  IP6_FRAME_CALLBACK    CallBack,
    563   IN  IP6_SERVICE           *IpSb
    564   )
    565 {
    566   EFI_STATUS                Status;
    567   IP6_LINK_RX_TOKEN         *Token;
    568 
    569   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    570 
    571   Token           = &IpSb->RecvRequest;
    572   Token->CallBack = CallBack;
    573   Token->Context  = (VOID *) IpSb;
    574 
    575   Status = IpSb->Mnp->Receive (IpSb->Mnp, &Token->MnpToken);
    576   if (EFI_ERROR (Status)) {
    577     return Status;
    578   }
    579 
    580   return EFI_SUCCESS;
    581 }
    582 
    583 /**
    584   Callback funtion when frame transmission is finished. It will
    585   call the frame owner's callback function to tell it the result.
    586 
    587   @param[in]  Context        Context which points to the token.
    588 
    589 **/
    590 VOID
    591 EFIAPI
    592 Ip6OnFrameSentDpc (
    593   IN VOID                    *Context
    594   )
    595 {
    596   IP6_LINK_TX_TOKEN         *Token;
    597 
    598   Token = (IP6_LINK_TX_TOKEN *) Context;
    599   NET_CHECK_SIGNATURE (Token, IP6_LINK_TX_SIGNATURE);
    600 
    601   RemoveEntryList (&Token->Link);
    602 
    603   Token->CallBack (
    604           Token->Packet,
    605           Token->MnpToken.Status,
    606           0,
    607           Token->Context
    608           );
    609 
    610   Ip6FreeLinkTxToken (Token);
    611 }
    612 
    613 /**
    614   Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK.
    615 
    616   @param[in]  Event                 The transmit token's event.
    617   @param[in]  Context               Context which points to the token.
    618 
    619 **/
    620 VOID
    621 EFIAPI
    622 Ip6OnFrameSent (
    623   IN EFI_EVENT               Event,
    624   IN VOID                    *Context
    625   )
    626 {
    627   //
    628   // Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK
    629   //
    630   QueueDpc (TPL_CALLBACK, Ip6OnFrameSentDpc, Context);
    631 }
    632 
    633 /**
    634   Send a frame from the interface. If the next hop is a multicast address,
    635   it is transmitted immediately. If the next hop is a unicast,
    636   and the NextHop's MAC is not known, it will perform address resolution.
    637   If an error occurred, the CallBack won't be called. So, the caller
    638   must test the return value, and take action when there is an error.
    639 
    640   @param[in]  Interface         The interface to send the frame from
    641   @param[in]  IpInstance        The IP child that request the transmission.
    642                                 NULL if it is the IP6 driver itself.
    643   @param[in]  Packet            The packet to transmit.
    644   @param[in]  NextHop           The immediate destination to transmit the packet to.
    645   @param[in]  CallBack          Function to call back when transmit finished.
    646   @param[in]  Context           Opaque parameter to the callback.
    647 
    648   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to send the frame.
    649   @retval EFI_NO_MAPPING        Can't resolve the MAC for the nexthop.
    650   @retval EFI_SUCCESS           The packet successfully transmitted.
    651 
    652 **/
    653 EFI_STATUS
    654 Ip6SendFrame (
    655   IN  IP6_INTERFACE         *Interface,
    656   IN  IP6_PROTOCOL          *IpInstance      OPTIONAL,
    657   IN  NET_BUF               *Packet,
    658   IN  EFI_IPv6_ADDRESS      *NextHop,
    659   IN  IP6_FRAME_CALLBACK    CallBack,
    660   IN  VOID                  *Context
    661   )
    662 {
    663   IP6_SERVICE               *IpSb;
    664   IP6_LINK_TX_TOKEN         *Token;
    665   EFI_STATUS                Status;
    666   IP6_NEIGHBOR_ENTRY        *NeighborCache;
    667   LIST_ENTRY                *Entry;
    668   IP6_NEIGHBOR_ENTRY        *ArpQue;
    669 
    670   IpSb = Interface->Service;
    671   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    672 
    673   //
    674   // Only when link local address is performing DAD, the interface could be used in unconfigured.
    675   //
    676   if (IpSb->LinkLocalOk) {
    677     ASSERT (Interface->Configured);
    678   }
    679 
    680   Token = Ip6CreateLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);
    681 
    682   if (Token == NULL) {
    683     return EFI_OUT_OF_RESOURCES;
    684   }
    685 
    686   if (IP6_IS_MULTICAST (NextHop)) {
    687     Status = Ip6GetMulticastMac (IpSb->Mnp, NextHop, &Token->DstMac);
    688     if (EFI_ERROR (Status)) {
    689       goto Error;
    690     }
    691 
    692     goto SendNow;
    693   }
    694 
    695   //
    696   // If send to itself, directly send out
    697   //
    698   if (EFI_IP6_EQUAL (&Packet->Ip.Ip6->DestinationAddress, &Packet->Ip.Ip6->SourceAddress)) {
    699     IP6_COPY_LINK_ADDRESS (&Token->DstMac, &IpSb->SnpMode.CurrentAddress);
    700     goto SendNow;
    701   }
    702 
    703   //
    704   // If unicast, check the neighbor state.
    705   //
    706 
    707   NeighborCache = Ip6FindNeighborEntry (IpSb, NextHop);
    708   ASSERT (NeighborCache != NULL);
    709 
    710   if (NeighborCache->Interface == NULL) {
    711     NeighborCache->Interface = Interface;
    712   }
    713 
    714   switch (NeighborCache->State) {
    715   case EfiNeighborStale:
    716     NeighborCache->State = EfiNeighborDelay;
    717     NeighborCache->Ticks = (UINT32) IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME);
    718     //
    719     // Fall through
    720     //
    721   case EfiNeighborReachable:
    722   case EfiNeighborDelay:
    723   case EfiNeighborProbe:
    724     IP6_COPY_LINK_ADDRESS (&Token->DstMac, &NeighborCache->LinkAddress);
    725     goto SendNow;
    726     break;
    727 
    728   default:
    729     break;
    730   }
    731 
    732   //
    733   // Have to do asynchronous ARP resolution. First check whether there is
    734   // already a pending request.
    735   //
    736   NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {
    737     ArpQue = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, ArpList);
    738     if (ArpQue == NeighborCache) {
    739       InsertTailList (&NeighborCache->Frames, &Token->Link);
    740       NeighborCache->ArpFree = TRUE;
    741       return EFI_SUCCESS;
    742     }
    743   }
    744 
    745   //
    746   // First frame requires ARP.
    747   //
    748   InsertTailList (&NeighborCache->Frames, &Token->Link);
    749   InsertTailList (&Interface->ArpQues, &NeighborCache->ArpList);
    750 
    751   NeighborCache->ArpFree = TRUE;
    752 
    753   return EFI_SUCCESS;
    754 
    755 SendNow:
    756  //
    757   // Insert the tx token into the SentFrames list before calling Mnp->Transmit.
    758   // Remove it if the returned status is not EFI_SUCCESS.
    759   //
    760   InsertTailList (&Interface->SentFrames, &Token->Link);
    761   Status = IpSb->Mnp->Transmit (IpSb->Mnp, &Token->MnpToken);
    762   if (EFI_ERROR (Status)) {
    763     RemoveEntryList (&Token->Link);
    764     goto Error;
    765   }
    766 
    767   return EFI_SUCCESS;
    768 
    769 Error:
    770   Ip6FreeLinkTxToken (Token);
    771   return Status;
    772 }
    773 
    774 /**
    775   The heartbeat timer of IP6 service instance. It times out
    776   all of its IP6 children's received-but-not-delivered and
    777   transmitted-but-not-recycle packets.
    778 
    779   @param[in]  Event                 The IP6 service instance's heartbeat timer.
    780   @param[in]  Context               The IP6 service instance.
    781 
    782 **/
    783 VOID
    784 EFIAPI
    785 Ip6TimerTicking (
    786   IN EFI_EVENT              Event,
    787   IN VOID                   *Context
    788   )
    789 {
    790   IP6_SERVICE               *IpSb;
    791 
    792   IpSb = (IP6_SERVICE *) Context;
    793   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    794 
    795   Ip6PacketTimerTicking (IpSb);
    796   Ip6NdTimerTicking (IpSb);
    797   Ip6MldTimerTicking (IpSb);
    798 }
    799