Home | History | Annotate | Download | only in Ip4Dxe
      1 /** @file
      2   Implement IP4 pesudo interface.
      3 
      4 Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "Ip4Impl.h"
     16 
     17 //
     18 // Mac address with all zero, used to determine whethter the ARP
     19 // resolve succeeded. Failed ARP requests zero the MAC address buffer.
     20 //
     21 EFI_MAC_ADDRESS  mZeroMacAddress;
     22 
     23 /**
     24   Callback funtion when frame transmission is finished. It will
     25   call the frame owner's callback function to tell it the result.
     26 
     27   @param[in]  Context            Context which is point to the token.
     28 
     29 **/
     30 VOID
     31 EFIAPI
     32 Ip4OnFrameSentDpc (
     33   IN VOID                    *Context
     34   );
     35 
     36 /**
     37   Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK.
     38 
     39   @param[in]  Event              The transmit token's event.
     40   @param[in]  Context            Context which is point to the token.
     41 
     42 **/
     43 VOID
     44 EFIAPI
     45 Ip4OnFrameSent (
     46   IN EFI_EVENT               Event,
     47   IN VOID                    *Context
     48   );
     49 
     50 /**
     51   Callback function when ARP request are finished. It will cancelled
     52   all the queued frame if the ARP requests failed. Or transmit them
     53   if the request succeed.
     54 
     55   @param[in]  Context           The context of the callback, a point to the ARP
     56                                 queue
     57 
     58 **/
     59 VOID
     60 EFIAPI
     61 Ip4OnArpResolvedDpc (
     62   IN VOID                   *Context
     63   );
     64 
     65 /**
     66   Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK.
     67 
     68   @param  Event             The Arp request event.
     69   @param  Context           The context of the callback, a point to the ARP
     70                             queue.
     71 
     72 **/
     73 VOID
     74 EFIAPI
     75 Ip4OnArpResolved (
     76   IN EFI_EVENT              Event,
     77   IN VOID                   *Context
     78   );
     79 
     80 /**
     81   Received a frame from MNP, wrap it in net buffer then deliver
     82   it to IP's input function. The ownship of the packet also
     83   transferred to IP. When Ip is finished with this packet, it
     84   will call NetbufFree to release the packet, NetbufFree will
     85   again call the Ip4RecycleFrame to signal MNP's event and free
     86   the token used.
     87 
     88   @param  Context               Context for the callback.
     89 
     90 **/
     91 VOID
     92 EFIAPI
     93 Ip4OnFrameReceivedDpc (
     94   IN VOID                     *Context
     95   );
     96 
     97 /**
     98   Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
     99 
    100   @param Event      The receive event delivered to MNP for receive.
    101   @param Context    Context for the callback.
    102 
    103 **/
    104 VOID
    105 EFIAPI
    106 Ip4OnFrameReceived (
    107   IN EFI_EVENT                Event,
    108   IN VOID                     *Context
    109   );
    110 
    111 /**
    112   Remove all the frames on the ARP queue that pass the FrameToCancel,
    113   that is, either FrameToCancel is NULL or it returns true for the frame.
    114 
    115   @param[in]  ArpQue            ARP frame to remove the frames from.
    116   @param[in]  IoStatus          The status returned to the cancelled frames'
    117                                 callback function.
    118   @param[in]  FrameToCancel     Function to select which frame to cancel.
    119   @param[in]  Context           Opaque parameter to the FrameToCancel.
    120 
    121 **/
    122 VOID
    123 Ip4CancelFrameArp (
    124   IN IP4_ARP_QUE            *ArpQue,
    125   IN EFI_STATUS             IoStatus,
    126   IN IP4_FRAME_TO_CANCEL    FrameToCancel  OPTIONAL,
    127   IN VOID                   *Context
    128   );
    129 
    130 
    131 /**
    132   Wrap a transmit request into a newly allocated IP4_LINK_TX_TOKEN.
    133 
    134   @param[in]  Interface         The interface to send out to.
    135   @param[in]  IpInstance        The IpInstance that transmit the packet.  NULL if
    136                                 the packet is sent by the IP4 driver itself.
    137   @param[in]  Packet            The packet to transmit
    138   @param[in]  CallBack          Call back function to execute if transmission
    139                                 finished.
    140   @param[in]  Context           Opaque parameter to the call back.
    141 
    142   @retval   Token               The wrapped token if succeed
    143   @retval   NULL                The wrapped token if NULL
    144 
    145 **/
    146 IP4_LINK_TX_TOKEN *
    147 Ip4WrapLinkTxToken (
    148   IN IP4_INTERFACE          *Interface,
    149   IN IP4_PROTOCOL           *IpInstance     OPTIONAL,
    150   IN NET_BUF                *Packet,
    151   IN IP4_FRAME_CALLBACK     CallBack,
    152   IN VOID                   *Context
    153   )
    154 {
    155   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
    156   EFI_MANAGED_NETWORK_TRANSMIT_DATA     *MnpTxData;
    157   IP4_LINK_TX_TOKEN                     *Token;
    158   EFI_STATUS                            Status;
    159   UINT32                                Count;
    160 
    161   Token = AllocatePool (sizeof (IP4_LINK_TX_TOKEN) + \
    162             (Packet->BlockOpNum - 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA));
    163 
    164   if (Token == NULL) {
    165     return NULL;
    166   }
    167 
    168   Token->Signature = IP4_FRAME_TX_SIGNATURE;
    169   InitializeListHead (&Token->Link);
    170 
    171   Token->Interface  = Interface;
    172   Token->IpInstance = IpInstance;
    173   Token->CallBack   = CallBack;
    174   Token->Packet     = Packet;
    175   Token->Context    = Context;
    176   CopyMem (&Token->DstMac, &mZeroMacAddress, sizeof (Token->DstMac));
    177   CopyMem (&Token->SrcMac, &Interface->Mac, sizeof (Token->SrcMac));
    178 
    179   MnpToken          = &(Token->MnpToken);
    180   MnpToken->Status  = EFI_NOT_READY;
    181 
    182   Status = gBS->CreateEvent (
    183                   EVT_NOTIFY_SIGNAL,
    184                   TPL_NOTIFY,
    185                   Ip4OnFrameSent,
    186                   Token,
    187                   &MnpToken->Event
    188                   );
    189 
    190   if (EFI_ERROR (Status)) {
    191     FreePool (Token);
    192     return NULL;
    193   }
    194 
    195   MnpTxData                     = &Token->MnpTxData;
    196   MnpToken->Packet.TxData       = MnpTxData;
    197 
    198   MnpTxData->DestinationAddress = &Token->DstMac;
    199   MnpTxData->SourceAddress      = &Token->SrcMac;
    200   MnpTxData->ProtocolType       = IP4_ETHER_PROTO;
    201   MnpTxData->DataLength         = Packet->TotalSize;
    202   MnpTxData->HeaderLength       = 0;
    203 
    204   Count                         = Packet->BlockOpNum;
    205 
    206   NetbufBuildExt (Packet, (NET_FRAGMENT *) MnpTxData->FragmentTable, &Count);
    207   MnpTxData->FragmentCount      = (UINT16)Count;
    208 
    209   return Token;
    210 }
    211 
    212 
    213 /**
    214   Free the link layer transmit token. It will close the event
    215   then free the memory used.
    216 
    217   @param[in]  Token                 Token to free
    218 
    219 **/
    220 VOID
    221 Ip4FreeLinkTxToken (
    222   IN IP4_LINK_TX_TOKEN      *Token
    223   )
    224 {
    225   NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
    226 
    227   gBS->CloseEvent (Token->MnpToken.Event);
    228   FreePool (Token);
    229 }
    230 
    231 
    232 /**
    233   Create an IP_ARP_QUE structure to request ARP service.
    234 
    235   @param[in]  Interface         The interface to send ARP from.
    236   @param[in]  DestIp            The destination IP (host byte order) to request MAC
    237                                 for
    238 
    239   @return Point to newly created IP4_ARP_QUE if succeed, otherwise NULL.
    240 
    241 **/
    242 IP4_ARP_QUE *
    243 Ip4CreateArpQue (
    244   IN IP4_INTERFACE          *Interface,
    245   IN IP4_ADDR               DestIp
    246   )
    247 {
    248   IP4_ARP_QUE               *ArpQue;
    249   EFI_STATUS                Status;
    250 
    251   ArpQue = AllocatePool (sizeof (IP4_ARP_QUE));
    252 
    253   if (ArpQue == NULL) {
    254     return NULL;
    255   }
    256 
    257   ArpQue->Signature = IP4_FRAME_ARP_SIGNATURE;
    258   InitializeListHead (&ArpQue->Link);
    259 
    260   InitializeListHead (&ArpQue->Frames);
    261   ArpQue->Interface = Interface;
    262 
    263   Status = gBS->CreateEvent (
    264                   EVT_NOTIFY_SIGNAL,
    265                   TPL_NOTIFY,
    266                   Ip4OnArpResolved,
    267                   ArpQue,
    268                   &ArpQue->OnResolved
    269                   );
    270 
    271   if (EFI_ERROR (Status)) {
    272     FreePool (ArpQue);
    273     return NULL;
    274   }
    275 
    276   ArpQue->Ip  = DestIp;
    277   CopyMem (&ArpQue->Mac, &mZeroMacAddress, sizeof (ArpQue->Mac));
    278 
    279   return ArpQue;
    280 }
    281 
    282 
    283 /**
    284   Remove all the transmit requests queued on the ARP queue, then free it.
    285 
    286   @param[in]  ArpQue            Arp queue to free
    287   @param[in]  IoStatus          The transmit status returned to transmit requests'
    288                                 callback.
    289 
    290 **/
    291 VOID
    292 Ip4FreeArpQue (
    293   IN IP4_ARP_QUE            *ArpQue,
    294   IN EFI_STATUS             IoStatus
    295   )
    296 {
    297   NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
    298 
    299   //
    300   // Remove all the frame waiting the ARP response
    301   //
    302   Ip4CancelFrameArp (ArpQue, IoStatus, NULL, NULL);
    303 
    304   gBS->CloseEvent (ArpQue->OnResolved);
    305   FreePool (ArpQue);
    306 }
    307 
    308 
    309 /**
    310   Create a link layer receive token to wrap the receive request
    311 
    312   @param[in]  Interface         The interface to receive from
    313   @param[in]  IpInstance        The instance that request the receive (NULL for IP4
    314                                 driver itself)
    315   @param[in]  CallBack          Call back function to execute when finished.
    316   @param[in]  Context           Opaque parameters to the callback
    317 
    318   @return Point to created IP4_LINK_RX_TOKEN if succeed, otherwise NULL.
    319 
    320 **/
    321 IP4_LINK_RX_TOKEN *
    322 Ip4CreateLinkRxToken (
    323   IN IP4_INTERFACE          *Interface,
    324   IN IP4_PROTOCOL           *IpInstance,
    325   IN IP4_FRAME_CALLBACK     CallBack,
    326   IN VOID                   *Context
    327   )
    328 {
    329   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
    330   IP4_LINK_RX_TOKEN                     *Token;
    331   EFI_STATUS                            Status;
    332 
    333   Token = AllocatePool (sizeof (IP4_LINK_RX_TOKEN));
    334   if (Token == NULL) {
    335     return NULL;
    336   }
    337 
    338   Token->Signature  = IP4_FRAME_RX_SIGNATURE;
    339   Token->Interface  = Interface;
    340   Token->IpInstance = IpInstance;
    341   Token->CallBack   = CallBack;
    342   Token->Context    = Context;
    343 
    344   MnpToken          = &Token->MnpToken;
    345   MnpToken->Status  = EFI_NOT_READY;
    346 
    347   Status = gBS->CreateEvent (
    348                   EVT_NOTIFY_SIGNAL,
    349                   TPL_NOTIFY,
    350                   Ip4OnFrameReceived,
    351                   Token,
    352                   &MnpToken->Event
    353                   );
    354 
    355   if (EFI_ERROR (Status)) {
    356     FreePool (Token);
    357     return NULL;
    358   }
    359 
    360   MnpToken->Packet.RxData = NULL;
    361   return Token;
    362 }
    363 
    364 
    365 /**
    366   Free the link layer request token. It will close the event
    367   then free the memory used.
    368 
    369   @param[in]  Token                 Request token to free.
    370 
    371 **/
    372 VOID
    373 Ip4FreeFrameRxToken (
    374   IN IP4_LINK_RX_TOKEN      *Token
    375   )
    376 {
    377 
    378   NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
    379 
    380   gBS->CloseEvent (Token->MnpToken.Event);
    381   FreePool (Token);
    382 }
    383 
    384 
    385 /**
    386   Remove all the frames on the ARP queue that pass the FrameToCancel,
    387   that is, either FrameToCancel is NULL or it returns true for the frame.
    388 
    389   @param[in]  ArpQue            ARP frame to remove the frames from.
    390   @param[in]  IoStatus          The status returned to the cancelled frames'
    391                                 callback function.
    392   @param[in]  FrameToCancel     Function to select which frame to cancel.
    393   @param[in]  Context           Opaque parameter to the FrameToCancel.
    394 
    395 **/
    396 VOID
    397 Ip4CancelFrameArp (
    398   IN IP4_ARP_QUE            *ArpQue,
    399   IN EFI_STATUS             IoStatus,
    400   IN IP4_FRAME_TO_CANCEL    FrameToCancel  OPTIONAL,
    401   IN VOID                   *Context
    402   )
    403 {
    404   LIST_ENTRY                *Entry;
    405   LIST_ENTRY                *Next;
    406   IP4_LINK_TX_TOKEN         *Token;
    407 
    408   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
    409     Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
    410 
    411     if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {
    412       RemoveEntryList (Entry);
    413 
    414       Token->CallBack (Token->IpInstance, Token->Packet, IoStatus, 0, Token->Context);
    415       Ip4FreeLinkTxToken (Token);
    416     }
    417   }
    418 }
    419 
    420 
    421 /**
    422   Remove all the frames on the interface that pass the FrameToCancel,
    423   either queued on ARP queues or that have already been delivered to
    424   MNP and not yet recycled.
    425 
    426   @param[in]  Interface         Interface to remove the frames from.
    427   @param[in]  IoStatus          The transmit status returned to the frames'
    428                                 callback.
    429   @param[in]  FrameToCancel     Function to select the frame to cancel, NULL to
    430                                 select all.
    431   @param[in]  Context           Opaque parameters passed to FrameToCancel.
    432 
    433 **/
    434 VOID
    435 Ip4CancelFrames (
    436   IN IP4_INTERFACE          *Interface,
    437   IN EFI_STATUS             IoStatus,
    438   IN IP4_FRAME_TO_CANCEL    FrameToCancel    OPTIONAL,
    439   IN VOID                   *Context
    440   )
    441 {
    442   LIST_ENTRY                *Entry;
    443   LIST_ENTRY                *Next;
    444   IP4_ARP_QUE               *ArpQue;
    445   IP4_LINK_TX_TOKEN         *Token;
    446 
    447   //
    448   // Cancel all the pending frames on ARP requests
    449   //
    450   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->ArpQues) {
    451     ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
    452 
    453     Ip4CancelFrameArp (ArpQue, IoStatus, FrameToCancel, Context);
    454 
    455     if (IsListEmpty (&ArpQue->Frames)) {
    456       Interface->Arp->Cancel (Interface->Arp, &ArpQue->Ip, ArpQue->OnResolved);
    457     }
    458   }
    459 
    460   //
    461   // Cancel all the frames that have been delivered to MNP
    462   // but not yet recycled.
    463   //
    464   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->SentFrames) {
    465     Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
    466 
    467     if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {
    468       Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
    469     }
    470   }
    471 }
    472 
    473 
    474 /**
    475   Create an IP4_INTERFACE. Delay the creation of ARP instance until
    476   the interface is configured.
    477 
    478   @param[in]  Mnp               The shared MNP child of this IP4 service binding
    479                                 instance.
    480   @param[in]  Controller        The controller this IP4 service binding instance
    481                                 is installed. Most like the UNDI handle.
    482   @param[in]  ImageHandle       This driver's image handle.
    483 
    484   @return Point to the created IP4_INTERFACE, otherwise NULL.
    485 
    486 **/
    487 IP4_INTERFACE *
    488 Ip4CreateInterface (
    489   IN  EFI_MANAGED_NETWORK_PROTOCOL  *Mnp,
    490   IN  EFI_HANDLE                    Controller,
    491   IN  EFI_HANDLE                    ImageHandle
    492   )
    493 {
    494   IP4_INTERFACE             *Interface;
    495   EFI_SIMPLE_NETWORK_MODE   SnpMode;
    496 
    497   Interface = AllocatePool (sizeof (IP4_INTERFACE));
    498 
    499   if ((Interface == NULL) || (Mnp == NULL)) {
    500     return NULL;
    501   }
    502 
    503   Interface->Signature = IP4_INTERFACE_SIGNATURE;
    504   InitializeListHead (&Interface->Link);
    505   Interface->RefCnt     = 1;
    506 
    507   Interface->Ip         = IP4_ALLZERO_ADDRESS;
    508   Interface->SubnetMask = IP4_ALLZERO_ADDRESS;
    509   Interface->Configured = FALSE;
    510 
    511   Interface->Controller = Controller;
    512   Interface->Image      = ImageHandle;
    513   Interface->Mnp        = Mnp;
    514   Interface->Arp        = NULL;
    515   Interface->ArpHandle  = NULL;
    516 
    517   InitializeListHead (&Interface->ArpQues);
    518   InitializeListHead (&Interface->SentFrames);
    519 
    520   Interface->RecvRequest = NULL;
    521 
    522   //
    523   // Get the interface's Mac address and broadcast mac address from SNP
    524   //
    525   if (EFI_ERROR (Mnp->GetModeData (Mnp, NULL, &SnpMode))) {
    526     FreePool (Interface);
    527     return NULL;
    528   }
    529 
    530   CopyMem (&Interface->Mac, &SnpMode.CurrentAddress, sizeof (Interface->Mac));
    531   CopyMem (&Interface->BroadcastMac, &SnpMode.BroadcastAddress, sizeof (Interface->BroadcastMac));
    532   Interface->HwaddrLen    = SnpMode.HwAddressSize;
    533 
    534   InitializeListHead (&Interface->IpInstances);
    535   Interface->PromiscRecv = FALSE;
    536 
    537   return Interface;
    538 }
    539 
    540 
    541 /**
    542   Set the interface's address, create and configure
    543   the ARP child if necessary.
    544 
    545   @param  Interface         The interface to set the address.
    546   @param  IpAddr            The interface's IP address.
    547   @param  SubnetMask        The interface's netmask.
    548 
    549   @retval EFI_SUCCESS           The interface is configured with Ip/netmask pair,
    550                                 and a ARP is created for it.
    551   @retval Others                Failed to set the interface's address.
    552 
    553 **/
    554 EFI_STATUS
    555 Ip4SetAddress (
    556   IN OUT IP4_INTERFACE      *Interface,
    557   IN     IP4_ADDR           IpAddr,
    558   IN     IP4_ADDR           SubnetMask
    559   )
    560 {
    561   EFI_ARP_CONFIG_DATA       ArpConfig;
    562   EFI_STATUS                Status;
    563   INTN                      Len;
    564 
    565   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
    566 
    567   Len = NetGetMaskLength (SubnetMask);
    568   if (Len == IP4_MASK_NUM) {
    569     return EFI_INVALID_PARAMETER;
    570   }
    571 
    572   //
    573   // Set the ip/netmask, then compute the subnet broadcast
    574   // and network broadcast for easy access. When computing
    575   // nework broadcast, the subnet mask is most like longer
    576   // than the default netmask (not subneted) as defined in
    577   // RFC793. If that isn't the case, we are aggregating the
    578   // networks, use the subnet's mask instead.
    579   //
    580   Interface->Ip             = IpAddr;
    581   Interface->SubnetMask     = SubnetMask;
    582   Interface->SubnetBrdcast  = (IpAddr | ~SubnetMask);
    583   Interface->NetBrdcast     = (IpAddr | ~SubnetMask);
    584 
    585   //
    586   // Do clean up for Arp child
    587   //
    588   if (Interface->ArpHandle != NULL) {
    589     if (Interface->Arp != NULL) {
    590       gBS->CloseProtocol (
    591              Interface->ArpHandle,
    592              &gEfiArpProtocolGuid,
    593              Interface->Image,
    594              Interface->Controller
    595              );
    596 
    597       Interface->Arp = NULL;
    598     }
    599 
    600     NetLibDestroyServiceChild (
    601       Interface->Controller,
    602       Interface->Image,
    603       &gEfiArpServiceBindingProtocolGuid,
    604       &Interface->ArpHandle
    605       );
    606 
    607     Interface->ArpHandle = NULL;
    608   }
    609 
    610   //
    611   // If the address is NOT all zero, create then configure an ARP child.
    612   // Pay attention: DHCP configures its station address as 0.0.0.0/0
    613   //
    614   if (IpAddr != IP4_ALLZERO_ADDRESS) {
    615     Status = NetLibCreateServiceChild (
    616                Interface->Controller,
    617                Interface->Image,
    618                &gEfiArpServiceBindingProtocolGuid,
    619                &Interface->ArpHandle
    620                );
    621 
    622     if (EFI_ERROR (Status)) {
    623       return Status;
    624     }
    625 
    626     Status = gBS->OpenProtocol (
    627                     Interface->ArpHandle,
    628                     &gEfiArpProtocolGuid,
    629                     (VOID **) &Interface->Arp,
    630                     Interface->Image,
    631                     Interface->Controller,
    632                     EFI_OPEN_PROTOCOL_BY_DRIVER
    633                     );
    634 
    635     if (EFI_ERROR (Status)) {
    636       goto ON_ERROR;
    637     }
    638 
    639     IpAddr                    = HTONL (IpAddr);
    640     ArpConfig.SwAddressType   = IP4_ETHER_PROTO;
    641     ArpConfig.SwAddressLength = 4;
    642     ArpConfig.StationAddress  = &IpAddr;
    643     ArpConfig.EntryTimeOut    = 0;
    644     ArpConfig.RetryCount      = 0;
    645     ArpConfig.RetryTimeOut    = 0;
    646 
    647     Status = Interface->Arp->Configure (Interface->Arp, &ArpConfig);
    648 
    649     if (EFI_ERROR (Status)) {
    650       gBS->CloseProtocol (
    651              Interface->ArpHandle,
    652              &gEfiArpProtocolGuid,
    653              Interface->Image,
    654              Interface->Controller
    655              );
    656 
    657       goto ON_ERROR;
    658     }
    659   }
    660 
    661   Interface->Configured = TRUE;
    662   return EFI_SUCCESS;
    663 
    664 ON_ERROR:
    665   NetLibDestroyServiceChild (
    666     Interface->Controller,
    667     Interface->Image,
    668     &gEfiArpServiceBindingProtocolGuid,
    669     &Interface->ArpHandle
    670     );
    671 
    672   return Status;
    673 }
    674 
    675 
    676 /**
    677   Filter function to cancel all the frame related to an IP instance.
    678 
    679   @param[in]  Frame             The transmit request to test whether to cancel
    680   @param[in]  Context           The context which is the Ip instance that issued
    681                                 the transmit.
    682 
    683   @retval TRUE                  The frame belongs to this instance and is to be
    684                                 removed
    685   @retval FALSE                 The frame doesn't belong to this instance.
    686 
    687 **/
    688 BOOLEAN
    689 Ip4CancelInstanceFrame (
    690   IN IP4_LINK_TX_TOKEN *Frame,
    691   IN VOID              *Context
    692   )
    693 {
    694   if (Frame->IpInstance == (IP4_PROTOCOL *) Context) {
    695     return TRUE;
    696   }
    697 
    698   return FALSE;
    699 }
    700 
    701 
    702 
    703 /**
    704   If there is a pending receive request, cancel it. Don't call
    705   the receive request's callback because this function can be only
    706   called if the instance or driver is tearing itself down. It
    707   doesn't make sense to call it back. But it is necessary to call
    708   the transmit token's callback to give it a chance to free the
    709   packet and update the upper layer's transmit request status, say
    710   that from the UDP.
    711 
    712   @param[in]  Interface         The interface used by the IpInstance
    713 
    714 **/
    715 VOID
    716 Ip4CancelReceive (
    717   IN IP4_INTERFACE          *Interface
    718   )
    719 {
    720   EFI_TPL                   OldTpl;
    721   IP4_LINK_RX_TOKEN         *Token;
    722 
    723   if ((Token = Interface->RecvRequest) != NULL) {
    724     OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    725 
    726     Interface->RecvRequest = NULL;
    727     Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
    728 
    729     gBS->RestoreTPL (OldTpl);
    730   }
    731 }
    732 
    733 
    734 /**
    735   Free the interface used by IpInstance. All the IP instance with
    736   the same Ip/Netmask pair share the same interface. It is reference
    737   counted. All the frames haven't been sent will be cancelled.
    738   Because the IpInstance is optional, the caller must remove
    739   IpInstance from the interface's instance list itself.
    740 
    741   @param[in]  Interface         The interface used by the IpInstance.
    742   @param[in]  IpInstance        The Ip instance that free the interface. NULL if
    743                                 the Ip driver is releasing the default interface.
    744 
    745   @retval EFI_SUCCESS           The interface use IpInstance is freed.
    746 
    747 **/
    748 EFI_STATUS
    749 Ip4FreeInterface (
    750   IN  IP4_INTERFACE         *Interface,
    751   IN  IP4_PROTOCOL          *IpInstance           OPTIONAL
    752   )
    753 {
    754   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
    755   ASSERT (Interface->RefCnt > 0);
    756 
    757   //
    758   // Remove all the pending transmit token related to this IP instance.
    759   //
    760   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);
    761 
    762   if (--Interface->RefCnt > 0) {
    763     return EFI_SUCCESS;
    764   }
    765 
    766   //
    767   // Destroy the interface if this is the last IP instance that
    768   // has the address. Remove all the system transmitted packets
    769   // from this interface, cancel the receive request if there is
    770   // one, and destroy the ARP requests.
    771   //
    772   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);
    773   Ip4CancelReceive (Interface);
    774 
    775   ASSERT (IsListEmpty (&Interface->IpInstances));
    776   ASSERT (IsListEmpty (&Interface->ArpQues));
    777   ASSERT (IsListEmpty (&Interface->SentFrames));
    778 
    779   if (Interface->Arp != NULL) {
    780     gBS->CloseProtocol (
    781           Interface->ArpHandle,
    782           &gEfiArpProtocolGuid,
    783           Interface->Image,
    784           Interface->Controller
    785           );
    786 
    787     NetLibDestroyServiceChild (
    788       Interface->Controller,
    789       Interface->Image,
    790       &gEfiArpServiceBindingProtocolGuid,
    791       Interface->ArpHandle
    792       );
    793   }
    794 
    795   RemoveEntryList (&Interface->Link);
    796   FreePool (Interface);
    797 
    798   return EFI_SUCCESS;
    799 }
    800 
    801 
    802 /**
    803   Callback function when ARP request are finished. It will cancelled
    804   all the queued frame if the ARP requests failed. Or transmit them
    805   if the request succeed.
    806 
    807   @param[in]  Context           The context of the callback, a point to the ARP
    808                                 queue
    809 
    810 **/
    811 VOID
    812 EFIAPI
    813 Ip4OnArpResolvedDpc (
    814   IN VOID                   *Context
    815   )
    816 {
    817   LIST_ENTRY                *Entry;
    818   LIST_ENTRY                *Next;
    819   IP4_ARP_QUE               *ArpQue;
    820   IP4_INTERFACE             *Interface;
    821   IP4_LINK_TX_TOKEN         *Token;
    822   EFI_STATUS                Status;
    823 
    824   ArpQue = (IP4_ARP_QUE *) Context;
    825   NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
    826 
    827   RemoveEntryList (&ArpQue->Link);
    828 
    829   //
    830   // ARP resolve failed for some reason. Release all the frame
    831   // and ARP queue itself. Ip4FreeArpQue will call the frame's
    832   // owner back.
    833   //
    834   if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {
    835     Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
    836 
    837     return ;
    838   }
    839 
    840   //
    841   // ARP resolve succeeded, Transmit all the frame. Release the ARP
    842   // queue. It isn't necessary for us to cache the ARP binding because
    843   // we always check the ARP cache first before transmit.
    844   //
    845   Interface = ArpQue->Interface;
    846 
    847   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
    848     RemoveEntryList (Entry);
    849 
    850     Token         = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
    851     CopyMem (&Token->DstMac, &ArpQue->Mac, sizeof (Token->DstMac));
    852 
    853     //
    854     // Insert the tx token before transmitting it via MNP as the FrameSentDpc
    855     // may be called before Mnp->Transmit returns which will remove this tx
    856     // token from the SentFrames list. Remove it from the list if the returned
    857     // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
    858     // FrameSentDpc won't be queued.
    859     //
    860     InsertTailList (&Interface->SentFrames, &Token->Link);
    861 
    862     Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
    863     if (EFI_ERROR (Status)) {
    864       RemoveEntryList (Entry);
    865       Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
    866 
    867       Ip4FreeLinkTxToken (Token);
    868       continue;
    869     }
    870   }
    871 
    872   Ip4FreeArpQue (ArpQue, EFI_SUCCESS);
    873 }
    874 
    875 /**
    876   Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK.
    877 
    878   @param  Event             The Arp request event.
    879   @param  Context           The context of the callback, a point to the ARP
    880                             queue.
    881 
    882 **/
    883 VOID
    884 EFIAPI
    885 Ip4OnArpResolved (
    886   IN EFI_EVENT              Event,
    887   IN VOID                   *Context
    888   )
    889 {
    890   //
    891   // Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK
    892   //
    893   QueueDpc (TPL_CALLBACK, Ip4OnArpResolvedDpc, Context);
    894 }
    895 
    896 
    897 
    898 /**
    899   Callback funtion when frame transmission is finished. It will
    900   call the frame owner's callback function to tell it the result.
    901 
    902   @param[in]  Context            Context which is point to the token.
    903 
    904 **/
    905 VOID
    906 EFIAPI
    907 Ip4OnFrameSentDpc (
    908   IN VOID                    *Context
    909   )
    910 {
    911   IP4_LINK_TX_TOKEN         *Token;
    912 
    913   Token = (IP4_LINK_TX_TOKEN *) Context;
    914   NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
    915 
    916   RemoveEntryList (&Token->Link);
    917 
    918   Token->CallBack (
    919           Token->IpInstance,
    920           Token->Packet,
    921           Token->MnpToken.Status,
    922           0,
    923           Token->Context
    924           );
    925 
    926   Ip4FreeLinkTxToken (Token);
    927 }
    928 
    929 /**
    930   Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK.
    931 
    932   @param[in]  Event              The transmit token's event.
    933   @param[in]  Context            Context which is point to the token.
    934 
    935 **/
    936 VOID
    937 EFIAPI
    938 Ip4OnFrameSent (
    939   IN EFI_EVENT               Event,
    940   IN VOID                    *Context
    941   )
    942 {
    943   //
    944   // Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK
    945   //
    946   QueueDpc (TPL_CALLBACK, Ip4OnFrameSentDpc, Context);
    947 }
    948 
    949 
    950 
    951 /**
    952   Send a frame from the interface. If the next hop is broadcast or
    953   multicast address, it is transmitted immediately. If the next hop
    954   is a unicast, it will consult ARP to resolve the NextHop's MAC.
    955   If some error happened, the CallBack won't be called. So, the caller
    956   must test the return value, and take action when there is an error.
    957 
    958   @param[in]  Interface         The interface to send the frame from
    959   @param[in]  IpInstance        The IP child that request the transmission.  NULL
    960                                 if it is the IP4 driver itself.
    961   @param[in]  Packet            The packet to transmit.
    962   @param[in]  NextHop           The immediate destination to transmit the packet
    963                                 to.
    964   @param[in]  CallBack          Function to call back when transmit finished.
    965   @param[in]  Context           Opaque parameter to the call back.
    966 
    967   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to send the frame
    968   @retval EFI_NO_MAPPING        Can't resolve the MAC for the nexthop
    969   @retval EFI_SUCCESS           The packet is successfully transmitted.
    970   @retval other                 Other error occurs.
    971 
    972 **/
    973 EFI_STATUS
    974 Ip4SendFrame (
    975   IN  IP4_INTERFACE         *Interface,
    976   IN  IP4_PROTOCOL          *IpInstance       OPTIONAL,
    977   IN  NET_BUF               *Packet,
    978   IN  IP4_ADDR              NextHop,
    979   IN  IP4_FRAME_CALLBACK    CallBack,
    980   IN  VOID                  *Context
    981   )
    982 {
    983   IP4_LINK_TX_TOKEN         *Token;
    984   LIST_ENTRY                *Entry;
    985   IP4_ARP_QUE               *ArpQue;
    986   EFI_ARP_PROTOCOL          *Arp;
    987   EFI_STATUS                Status;
    988 
    989   ASSERT (Interface->Configured);
    990 
    991   Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);
    992 
    993   if (Token == NULL) {
    994     return EFI_OUT_OF_RESOURCES;
    995   }
    996 
    997   //
    998   // Get the destination MAC address for multicast and broadcasts.
    999   // Don't depend on ARP to solve the address since there maybe no
   1000   // ARP at all. Ip4Output has set NextHop to 255.255.255.255 for
   1001   // all the broadcasts.
   1002   //
   1003   if (NextHop == IP4_ALLONE_ADDRESS) {
   1004     CopyMem (&Token->DstMac, &Interface->BroadcastMac, sizeof (Token->DstMac));
   1005     goto SEND_NOW;
   1006 
   1007   } else if (IP4_IS_MULTICAST (NextHop)) {
   1008 
   1009     Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);
   1010 
   1011     if (EFI_ERROR (Status)) {
   1012       goto ON_ERROR;
   1013     }
   1014 
   1015     goto SEND_NOW;
   1016   }
   1017 
   1018   //
   1019   // Can only send out multicast/broadcast if the IP address is zero
   1020   //
   1021   if ((Arp = Interface->Arp) == NULL) {
   1022     Status = EFI_NO_MAPPING;
   1023     goto ON_ERROR;
   1024   }
   1025 
   1026   //
   1027   // First check whether this binding is in the ARP cache.
   1028   //
   1029   NextHop = HTONL (NextHop);
   1030   Status  = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);
   1031 
   1032   if (Status == EFI_SUCCESS) {
   1033     goto SEND_NOW;
   1034 
   1035   } else if (Status != EFI_NOT_READY) {
   1036     goto ON_ERROR;
   1037   }
   1038 
   1039   //
   1040   // Have to do asynchronous ARP resolution. First check
   1041   // whether there is already a pending request.
   1042   //
   1043   ArpQue = NULL;
   1044 
   1045   NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {
   1046     ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
   1047 
   1048     if (ArpQue->Ip == NextHop) {
   1049       break;
   1050     }
   1051   }
   1052 
   1053   //
   1054   // Found a pending ARP request, enqueue the frame then return
   1055   //
   1056   if (Entry != &Interface->ArpQues) {
   1057     InsertTailList (&ArpQue->Frames, &Token->Link);
   1058     return EFI_SUCCESS;
   1059   }
   1060 
   1061   //
   1062   // First frame to NextHop, issue an asynchronous ARP requests
   1063   //
   1064   ArpQue = Ip4CreateArpQue (Interface, NextHop);
   1065 
   1066   if (ArpQue == NULL) {
   1067     Status = EFI_OUT_OF_RESOURCES;
   1068     goto ON_ERROR;
   1069   }
   1070 
   1071   Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);
   1072 
   1073   if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
   1074     Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
   1075     goto ON_ERROR;
   1076   }
   1077 
   1078   InsertHeadList (&ArpQue->Frames, &Token->Link);
   1079   InsertHeadList (&Interface->ArpQues, &ArpQue->Link);
   1080   return EFI_SUCCESS;
   1081 
   1082 SEND_NOW:
   1083   //
   1084   // Insert the tx token into the SentFrames list before calling Mnp->Transmit.
   1085   // Remove it if the returned status is not EFI_SUCCESS.
   1086   //
   1087   InsertTailList (&Interface->SentFrames, &Token->Link);
   1088   Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
   1089   if (EFI_ERROR (Status)) {
   1090     RemoveEntryList (&Interface->SentFrames);
   1091     goto ON_ERROR;
   1092   }
   1093 
   1094   return EFI_SUCCESS;
   1095 
   1096 ON_ERROR:
   1097   Ip4FreeLinkTxToken (Token);
   1098   return Status;
   1099 }
   1100 
   1101 
   1102 /**
   1103   Call back function when the received packet is freed.
   1104   Check Ip4OnFrameReceived for information.
   1105 
   1106   @param  Context          Context, which is the IP4_LINK_RX_TOKEN.
   1107 
   1108 **/
   1109 VOID
   1110 EFIAPI
   1111 Ip4RecycleFrame (
   1112   IN VOID                   *Context
   1113   )
   1114 {
   1115   IP4_LINK_RX_TOKEN         *Frame;
   1116 
   1117   Frame = (IP4_LINK_RX_TOKEN *) Context;
   1118   NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);
   1119 
   1120   gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);
   1121   Ip4FreeFrameRxToken (Frame);
   1122 }
   1123 
   1124 
   1125 /**
   1126   Received a frame from MNP, wrap it in net buffer then deliver
   1127   it to IP's input function. The ownship of the packet also
   1128   transferred to IP. When Ip is finished with this packet, it
   1129   will call NetbufFree to release the packet, NetbufFree will
   1130   again call the Ip4RecycleFrame to signal MNP's event and free
   1131   the token used.
   1132 
   1133   @param  Context               Context for the callback.
   1134 
   1135 **/
   1136 VOID
   1137 EFIAPI
   1138 Ip4OnFrameReceivedDpc (
   1139   IN VOID                     *Context
   1140   )
   1141 {
   1142   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
   1143   EFI_MANAGED_NETWORK_RECEIVE_DATA      *MnpRxData;
   1144   IP4_LINK_RX_TOKEN                     *Token;
   1145   NET_FRAGMENT                          Netfrag;
   1146   NET_BUF                               *Packet;
   1147   UINT32                                Flag;
   1148 
   1149   Token = (IP4_LINK_RX_TOKEN *) Context;
   1150   NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
   1151 
   1152   //
   1153   // First clear the interface's receive request in case the
   1154   // caller wants to call Ip4ReceiveFrame in the callback.
   1155   //
   1156   Token->Interface->RecvRequest = NULL;
   1157 
   1158   MnpToken  = &Token->MnpToken;
   1159   MnpRxData = MnpToken->Packet.RxData;
   1160 
   1161   if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {
   1162     Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);
   1163     Ip4FreeFrameRxToken (Token);
   1164 
   1165     return ;
   1166   }
   1167 
   1168   //
   1169   // Wrap the frame in a net buffer then deliever it to IP input.
   1170   // IP will reassemble the packet, and deliver it to upper layer
   1171   //
   1172   Netfrag.Len  = MnpRxData->DataLength;
   1173   Netfrag.Bulk = MnpRxData->PacketData;
   1174 
   1175   Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);
   1176 
   1177   if (Packet == NULL) {
   1178     gBS->SignalEvent (MnpRxData->RecycleEvent);
   1179 
   1180     Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);
   1181     Ip4FreeFrameRxToken (Token);
   1182 
   1183     return ;
   1184   }
   1185 
   1186   Flag  = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);
   1187   Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);
   1188   Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);
   1189 
   1190   Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);
   1191 }
   1192 
   1193 /**
   1194   Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
   1195 
   1196   @param Event      The receive event delivered to MNP for receive.
   1197   @param Context    Context for the callback.
   1198 
   1199 **/
   1200 VOID
   1201 EFIAPI
   1202 Ip4OnFrameReceived (
   1203   IN EFI_EVENT                Event,
   1204   IN VOID                     *Context
   1205   )
   1206 {
   1207   //
   1208   // Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK
   1209   //
   1210   QueueDpc (TPL_CALLBACK, Ip4OnFrameReceivedDpc, Context);
   1211 }
   1212 
   1213 
   1214 /**
   1215   Request to receive the packet from the interface.
   1216 
   1217   @param[in]  Interface         The interface to receive the frames from.
   1218   @param[in]  IpInstance        The instance that requests the receive. NULL for
   1219                                 the driver itself.
   1220   @param[in]  CallBack          Function to call when receive finished.
   1221   @param[in]  Context           Opaque parameter to the callback.
   1222 
   1223   @retval EFI_ALREADY_STARTED   There is already a pending receive request.
   1224   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to receive.
   1225   @retval EFI_SUCCESS           The recieve request has been started.
   1226   @retval other                 Other error occurs.
   1227 
   1228 **/
   1229 EFI_STATUS
   1230 Ip4ReceiveFrame (
   1231   IN  IP4_INTERFACE         *Interface,
   1232   IN  IP4_PROTOCOL          *IpInstance       OPTIONAL,
   1233   IN  IP4_FRAME_CALLBACK    CallBack,
   1234   IN  VOID                  *Context
   1235   )
   1236 {
   1237   IP4_LINK_RX_TOKEN *Token;
   1238   EFI_STATUS        Status;
   1239 
   1240   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
   1241 
   1242   if (Interface->RecvRequest != NULL) {
   1243     return EFI_ALREADY_STARTED;
   1244   }
   1245 
   1246   Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);
   1247 
   1248   if (Token == NULL) {
   1249     return EFI_OUT_OF_RESOURCES;
   1250   }
   1251 
   1252   Interface->RecvRequest = Token;
   1253   Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);
   1254   if (EFI_ERROR (Status)) {
   1255     Interface->RecvRequest = NULL;
   1256     Ip4FreeFrameRxToken (Token);
   1257     return Status;
   1258   }
   1259   return EFI_SUCCESS;
   1260 }
   1261