Home | History | Annotate | Download | only in Ip4Dxe
      1 /** @file
      2   Implement IP4 pesudo interface.
      3 
      4 Copyright (c) 2005 - 2015, 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                      Type;
    564   INTN                      Len;
    565   IP4_ADDR                  Netmask;
    566 
    567   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
    568 
    569   //
    570   // Set the ip/netmask, then compute the subnet broadcast
    571   // and network broadcast for easy access. When computing
    572   // nework broadcast, the subnet mask is most like longer
    573   // than the default netmask (not subneted) as defined in
    574   // RFC793. If that isn't the case, we are aggregating the
    575   // networks, use the subnet's mask instead.
    576   //
    577   Interface->Ip             = IpAddr;
    578   Interface->SubnetMask     = SubnetMask;
    579   Interface->SubnetBrdcast  = (IpAddr | ~SubnetMask);
    580 
    581   Type                      = NetGetIpClass (IpAddr);
    582   ASSERT (Type <= IP4_ADDR_CLASSC);
    583   Len                       = NetGetMaskLength (SubnetMask);
    584   ASSERT (Len < IP4_MASK_NUM);
    585   Netmask                   = gIp4AllMasks[MIN (Len, Type << 3)];
    586   Interface->NetBrdcast     = (IpAddr | ~Netmask);
    587 
    588   //
    589   // Do clean up for Arp child
    590   //
    591   if (Interface->ArpHandle != NULL) {
    592     if (Interface->Arp != NULL) {
    593       gBS->CloseProtocol (
    594              Interface->ArpHandle,
    595              &gEfiArpProtocolGuid,
    596              Interface->Image,
    597              Interface->Controller
    598              );
    599 
    600       Interface->Arp = NULL;
    601     }
    602 
    603     NetLibDestroyServiceChild (
    604       Interface->Controller,
    605       Interface->Image,
    606       &gEfiArpServiceBindingProtocolGuid,
    607       &Interface->ArpHandle
    608       );
    609 
    610     Interface->ArpHandle = NULL;
    611   }
    612 
    613   //
    614   // If the address is NOT all zero, create then configure an ARP child.
    615   // Pay attention: DHCP configures its station address as 0.0.0.0/0
    616   //
    617   if (IpAddr != IP4_ALLZERO_ADDRESS) {
    618     Status = NetLibCreateServiceChild (
    619                Interface->Controller,
    620                Interface->Image,
    621                &gEfiArpServiceBindingProtocolGuid,
    622                &Interface->ArpHandle
    623                );
    624 
    625     if (EFI_ERROR (Status)) {
    626       return Status;
    627     }
    628 
    629     Status = gBS->OpenProtocol (
    630                     Interface->ArpHandle,
    631                     &gEfiArpProtocolGuid,
    632                     (VOID **) &Interface->Arp,
    633                     Interface->Image,
    634                     Interface->Controller,
    635                     EFI_OPEN_PROTOCOL_BY_DRIVER
    636                     );
    637 
    638     if (EFI_ERROR (Status)) {
    639       goto ON_ERROR;
    640     }
    641 
    642     IpAddr                    = HTONL (IpAddr);
    643     ArpConfig.SwAddressType   = IP4_ETHER_PROTO;
    644     ArpConfig.SwAddressLength = 4;
    645     ArpConfig.StationAddress  = &IpAddr;
    646     ArpConfig.EntryTimeOut    = 0;
    647     ArpConfig.RetryCount      = 0;
    648     ArpConfig.RetryTimeOut    = 0;
    649 
    650     Status = Interface->Arp->Configure (Interface->Arp, &ArpConfig);
    651 
    652     if (EFI_ERROR (Status)) {
    653       gBS->CloseProtocol (
    654              Interface->ArpHandle,
    655              &gEfiArpProtocolGuid,
    656              Interface->Image,
    657              Interface->Controller
    658              );
    659 
    660       goto ON_ERROR;
    661     }
    662   }
    663 
    664   Interface->Configured = TRUE;
    665   return EFI_SUCCESS;
    666 
    667 ON_ERROR:
    668   NetLibDestroyServiceChild (
    669     Interface->Controller,
    670     Interface->Image,
    671     &gEfiArpServiceBindingProtocolGuid,
    672     &Interface->ArpHandle
    673     );
    674 
    675   return Status;
    676 }
    677 
    678 
    679 /**
    680   Filter function to cancel all the frame related to an IP instance.
    681 
    682   @param[in]  Frame             The transmit request to test whether to cancel
    683   @param[in]  Context           The context which is the Ip instance that issued
    684                                 the transmit.
    685 
    686   @retval TRUE                  The frame belongs to this instance and is to be
    687                                 removed
    688   @retval FALSE                 The frame doesn't belong to this instance.
    689 
    690 **/
    691 BOOLEAN
    692 Ip4CancelInstanceFrame (
    693   IN IP4_LINK_TX_TOKEN *Frame,
    694   IN VOID              *Context
    695   )
    696 {
    697   if (Frame->IpInstance == (IP4_PROTOCOL *) Context) {
    698     return TRUE;
    699   }
    700 
    701   return FALSE;
    702 }
    703 
    704 
    705 
    706 /**
    707   If there is a pending receive request, cancel it. Don't call
    708   the receive request's callback because this function can be only
    709   called if the instance or driver is tearing itself down. It
    710   doesn't make sense to call it back. But it is necessary to call
    711   the transmit token's callback to give it a chance to free the
    712   packet and update the upper layer's transmit request status, say
    713   that from the UDP.
    714 
    715   @param[in]  Interface         The interface used by the IpInstance
    716 
    717 **/
    718 VOID
    719 Ip4CancelReceive (
    720   IN IP4_INTERFACE          *Interface
    721   )
    722 {
    723   EFI_TPL                   OldTpl;
    724   IP4_LINK_RX_TOKEN         *Token;
    725 
    726   if ((Token = Interface->RecvRequest) != NULL) {
    727     OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    728 
    729     Interface->RecvRequest = NULL;
    730     Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
    731 
    732     gBS->RestoreTPL (OldTpl);
    733   }
    734 }
    735 
    736 
    737 /**
    738   Free the interface used by IpInstance. All the IP instance with
    739   the same Ip/Netmask pair share the same interface. It is reference
    740   counted. All the frames haven't been sent will be cancelled.
    741   Because the IpInstance is optional, the caller must remove
    742   IpInstance from the interface's instance list itself.
    743 
    744   @param[in]  Interface         The interface used by the IpInstance.
    745   @param[in]  IpInstance        The Ip instance that free the interface. NULL if
    746                                 the Ip driver is releasing the default interface.
    747 
    748   @retval EFI_SUCCESS           The interface use IpInstance is freed.
    749 
    750 **/
    751 EFI_STATUS
    752 Ip4FreeInterface (
    753   IN  IP4_INTERFACE         *Interface,
    754   IN  IP4_PROTOCOL          *IpInstance           OPTIONAL
    755   )
    756 {
    757   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
    758   ASSERT (Interface->RefCnt > 0);
    759 
    760   //
    761   // Remove all the pending transmit token related to this IP instance.
    762   //
    763   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);
    764 
    765   if (--Interface->RefCnt > 0) {
    766     return EFI_SUCCESS;
    767   }
    768 
    769   //
    770   // Destroy the interface if this is the last IP instance that
    771   // has the address. Remove all the system transmitted packets
    772   // from this interface, cancel the receive request if there is
    773   // one, and destroy the ARP requests.
    774   //
    775   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);
    776   Ip4CancelReceive (Interface);
    777 
    778   ASSERT (IsListEmpty (&Interface->IpInstances));
    779   ASSERT (IsListEmpty (&Interface->ArpQues));
    780   ASSERT (IsListEmpty (&Interface->SentFrames));
    781 
    782   if (Interface->Arp != NULL) {
    783     gBS->CloseProtocol (
    784           Interface->ArpHandle,
    785           &gEfiArpProtocolGuid,
    786           Interface->Image,
    787           Interface->Controller
    788           );
    789 
    790     NetLibDestroyServiceChild (
    791       Interface->Controller,
    792       Interface->Image,
    793       &gEfiArpServiceBindingProtocolGuid,
    794       Interface->ArpHandle
    795       );
    796   }
    797 
    798   RemoveEntryList (&Interface->Link);
    799   FreePool (Interface);
    800 
    801   return EFI_SUCCESS;
    802 }
    803 
    804 
    805 /**
    806   Callback function when ARP request are finished. It will cancelled
    807   all the queued frame if the ARP requests failed. Or transmit them
    808   if the request succeed.
    809 
    810   @param[in]  Context           The context of the callback, a point to the ARP
    811                                 queue
    812 
    813 **/
    814 VOID
    815 EFIAPI
    816 Ip4OnArpResolvedDpc (
    817   IN VOID                   *Context
    818   )
    819 {
    820   LIST_ENTRY                *Entry;
    821   LIST_ENTRY                *Next;
    822   IP4_ARP_QUE               *ArpQue;
    823   IP4_INTERFACE             *Interface;
    824   IP4_LINK_TX_TOKEN         *Token;
    825   EFI_STATUS                Status;
    826 
    827   ArpQue = (IP4_ARP_QUE *) Context;
    828   NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
    829 
    830   RemoveEntryList (&ArpQue->Link);
    831 
    832   //
    833   // ARP resolve failed for some reason. Release all the frame
    834   // and ARP queue itself. Ip4FreeArpQue will call the frame's
    835   // owner back.
    836   //
    837   if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {
    838     Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
    839 
    840     return ;
    841   }
    842 
    843   //
    844   // ARP resolve succeeded, Transmit all the frame. Release the ARP
    845   // queue. It isn't necessary for us to cache the ARP binding because
    846   // we always check the ARP cache first before transmit.
    847   //
    848   Interface = ArpQue->Interface;
    849 
    850   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
    851     RemoveEntryList (Entry);
    852 
    853     Token         = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
    854     CopyMem (&Token->DstMac, &ArpQue->Mac, sizeof (Token->DstMac));
    855 
    856     //
    857     // Insert the tx token before transmitting it via MNP as the FrameSentDpc
    858     // may be called before Mnp->Transmit returns which will remove this tx
    859     // token from the SentFrames list. Remove it from the list if the returned
    860     // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
    861     // FrameSentDpc won't be queued.
    862     //
    863     InsertTailList (&Interface->SentFrames, &Token->Link);
    864 
    865     Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
    866     if (EFI_ERROR (Status)) {
    867       RemoveEntryList (Entry);
    868       Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
    869 
    870       Ip4FreeLinkTxToken (Token);
    871       continue;
    872     }
    873   }
    874 
    875   Ip4FreeArpQue (ArpQue, EFI_SUCCESS);
    876 }
    877 
    878 /**
    879   Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK.
    880 
    881   @param  Event             The Arp request event.
    882   @param  Context           The context of the callback, a point to the ARP
    883                             queue.
    884 
    885 **/
    886 VOID
    887 EFIAPI
    888 Ip4OnArpResolved (
    889   IN EFI_EVENT              Event,
    890   IN VOID                   *Context
    891   )
    892 {
    893   //
    894   // Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK
    895   //
    896   QueueDpc (TPL_CALLBACK, Ip4OnArpResolvedDpc, Context);
    897 }
    898 
    899 
    900 
    901 /**
    902   Callback funtion when frame transmission is finished. It will
    903   call the frame owner's callback function to tell it the result.
    904 
    905   @param[in]  Context            Context which is point to the token.
    906 
    907 **/
    908 VOID
    909 EFIAPI
    910 Ip4OnFrameSentDpc (
    911   IN VOID                    *Context
    912   )
    913 {
    914   IP4_LINK_TX_TOKEN         *Token;
    915 
    916   Token = (IP4_LINK_TX_TOKEN *) Context;
    917   NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
    918 
    919   RemoveEntryList (&Token->Link);
    920 
    921   Token->CallBack (
    922           Token->IpInstance,
    923           Token->Packet,
    924           Token->MnpToken.Status,
    925           0,
    926           Token->Context
    927           );
    928 
    929   Ip4FreeLinkTxToken (Token);
    930 }
    931 
    932 /**
    933   Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK.
    934 
    935   @param[in]  Event              The transmit token's event.
    936   @param[in]  Context            Context which is point to the token.
    937 
    938 **/
    939 VOID
    940 EFIAPI
    941 Ip4OnFrameSent (
    942   IN EFI_EVENT               Event,
    943   IN VOID                    *Context
    944   )
    945 {
    946   //
    947   // Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK
    948   //
    949   QueueDpc (TPL_CALLBACK, Ip4OnFrameSentDpc, Context);
    950 }
    951 
    952 
    953 
    954 /**
    955   Send a frame from the interface. If the next hop is broadcast or
    956   multicast address, it is transmitted immediately. If the next hop
    957   is a unicast, it will consult ARP to resolve the NextHop's MAC.
    958   If some error happened, the CallBack won't be called. So, the caller
    959   must test the return value, and take action when there is an error.
    960 
    961   @param[in]  Interface         The interface to send the frame from
    962   @param[in]  IpInstance        The IP child that request the transmission.  NULL
    963                                 if it is the IP4 driver itself.
    964   @param[in]  Packet            The packet to transmit.
    965   @param[in]  NextHop           The immediate destination to transmit the packet
    966                                 to.
    967   @param[in]  CallBack          Function to call back when transmit finished.
    968   @param[in]  Context           Opaque parameter to the call back.
    969 
    970   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to send the frame
    971   @retval EFI_NO_MAPPING        Can't resolve the MAC for the nexthop
    972   @retval EFI_SUCCESS           The packet is successfully transmitted.
    973   @retval other                 Other error occurs.
    974 
    975 **/
    976 EFI_STATUS
    977 Ip4SendFrame (
    978   IN  IP4_INTERFACE         *Interface,
    979   IN  IP4_PROTOCOL          *IpInstance       OPTIONAL,
    980   IN  NET_BUF               *Packet,
    981   IN  IP4_ADDR              NextHop,
    982   IN  IP4_FRAME_CALLBACK    CallBack,
    983   IN  VOID                  *Context
    984   )
    985 {
    986   IP4_LINK_TX_TOKEN         *Token;
    987   LIST_ENTRY                *Entry;
    988   IP4_ARP_QUE               *ArpQue;
    989   EFI_ARP_PROTOCOL          *Arp;
    990   EFI_STATUS                Status;
    991 
    992   ASSERT (Interface->Configured);
    993 
    994   Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);
    995 
    996   if (Token == NULL) {
    997     return EFI_OUT_OF_RESOURCES;
    998   }
    999 
   1000   //
   1001   // Get the destination MAC address for multicast and broadcasts.
   1002   // Don't depend on ARP to solve the address since there maybe no
   1003   // ARP at all. Ip4Output has set NextHop to 255.255.255.255 for
   1004   // all the broadcasts.
   1005   //
   1006   if (NextHop == IP4_ALLONE_ADDRESS) {
   1007     CopyMem (&Token->DstMac, &Interface->BroadcastMac, sizeof (Token->DstMac));
   1008     goto SEND_NOW;
   1009 
   1010   } else if (IP4_IS_MULTICAST (NextHop)) {
   1011 
   1012     Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);
   1013 
   1014     if (EFI_ERROR (Status)) {
   1015       goto ON_ERROR;
   1016     }
   1017 
   1018     goto SEND_NOW;
   1019   }
   1020 
   1021   //
   1022   // Can only send out multicast/broadcast if the IP address is zero
   1023   //
   1024   if ((Arp = Interface->Arp) == NULL) {
   1025     Status = EFI_NO_MAPPING;
   1026     goto ON_ERROR;
   1027   }
   1028 
   1029   //
   1030   // First check whether this binding is in the ARP cache.
   1031   //
   1032   NextHop = HTONL (NextHop);
   1033   Status  = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);
   1034 
   1035   if (Status == EFI_SUCCESS) {
   1036     goto SEND_NOW;
   1037 
   1038   } else if (Status != EFI_NOT_READY) {
   1039     goto ON_ERROR;
   1040   }
   1041 
   1042   //
   1043   // Have to do asynchronous ARP resolution. First check
   1044   // whether there is already a pending request.
   1045   //
   1046   ArpQue = NULL;
   1047 
   1048   NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {
   1049     ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
   1050 
   1051     if (ArpQue->Ip == NextHop) {
   1052       break;
   1053     }
   1054   }
   1055 
   1056   //
   1057   // Found a pending ARP request, enqueue the frame then return
   1058   //
   1059   if (Entry != &Interface->ArpQues) {
   1060     InsertTailList (&ArpQue->Frames, &Token->Link);
   1061     return EFI_SUCCESS;
   1062   }
   1063 
   1064   //
   1065   // First frame to NextHop, issue an asynchronous ARP requests
   1066   //
   1067   ArpQue = Ip4CreateArpQue (Interface, NextHop);
   1068 
   1069   if (ArpQue == NULL) {
   1070     Status = EFI_OUT_OF_RESOURCES;
   1071     goto ON_ERROR;
   1072   }
   1073 
   1074   Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);
   1075 
   1076   if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
   1077     Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
   1078     goto ON_ERROR;
   1079   }
   1080 
   1081   InsertHeadList (&ArpQue->Frames, &Token->Link);
   1082   InsertHeadList (&Interface->ArpQues, &ArpQue->Link);
   1083   return EFI_SUCCESS;
   1084 
   1085 SEND_NOW:
   1086   //
   1087   // Insert the tx token into the SentFrames list before calling Mnp->Transmit.
   1088   // Remove it if the returned status is not EFI_SUCCESS.
   1089   //
   1090   InsertTailList (&Interface->SentFrames, &Token->Link);
   1091   Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
   1092   if (EFI_ERROR (Status)) {
   1093     RemoveEntryList (&Interface->SentFrames);
   1094     goto ON_ERROR;
   1095   }
   1096 
   1097   return EFI_SUCCESS;
   1098 
   1099 ON_ERROR:
   1100   Ip4FreeLinkTxToken (Token);
   1101   return Status;
   1102 }
   1103 
   1104 
   1105 /**
   1106   Call back function when the received packet is freed.
   1107   Check Ip4OnFrameReceived for information.
   1108 
   1109   @param  Context          Context, which is the IP4_LINK_RX_TOKEN.
   1110 
   1111 **/
   1112 VOID
   1113 EFIAPI
   1114 Ip4RecycleFrame (
   1115   IN VOID                   *Context
   1116   )
   1117 {
   1118   IP4_LINK_RX_TOKEN         *Frame;
   1119 
   1120   Frame = (IP4_LINK_RX_TOKEN *) Context;
   1121   NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);
   1122 
   1123   gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);
   1124   Ip4FreeFrameRxToken (Frame);
   1125 }
   1126 
   1127 
   1128 /**
   1129   Received a frame from MNP, wrap it in net buffer then deliver
   1130   it to IP's input function. The ownship of the packet also
   1131   transferred to IP. When Ip is finished with this packet, it
   1132   will call NetbufFree to release the packet, NetbufFree will
   1133   again call the Ip4RecycleFrame to signal MNP's event and free
   1134   the token used.
   1135 
   1136   @param  Context               Context for the callback.
   1137 
   1138 **/
   1139 VOID
   1140 EFIAPI
   1141 Ip4OnFrameReceivedDpc (
   1142   IN VOID                     *Context
   1143   )
   1144 {
   1145   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
   1146   EFI_MANAGED_NETWORK_RECEIVE_DATA      *MnpRxData;
   1147   IP4_LINK_RX_TOKEN                     *Token;
   1148   NET_FRAGMENT                          Netfrag;
   1149   NET_BUF                               *Packet;
   1150   UINT32                                Flag;
   1151 
   1152   Token = (IP4_LINK_RX_TOKEN *) Context;
   1153   NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
   1154 
   1155   //
   1156   // First clear the interface's receive request in case the
   1157   // caller wants to call Ip4ReceiveFrame in the callback.
   1158   //
   1159   Token->Interface->RecvRequest = NULL;
   1160 
   1161   MnpToken  = &Token->MnpToken;
   1162   MnpRxData = MnpToken->Packet.RxData;
   1163 
   1164   if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {
   1165     Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);
   1166     Ip4FreeFrameRxToken (Token);
   1167 
   1168     return ;
   1169   }
   1170 
   1171   //
   1172   // Wrap the frame in a net buffer then deliever it to IP input.
   1173   // IP will reassemble the packet, and deliver it to upper layer
   1174   //
   1175   Netfrag.Len  = MnpRxData->DataLength;
   1176   Netfrag.Bulk = MnpRxData->PacketData;
   1177 
   1178   Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);
   1179 
   1180   if (Packet == NULL) {
   1181     gBS->SignalEvent (MnpRxData->RecycleEvent);
   1182 
   1183     Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);
   1184     Ip4FreeFrameRxToken (Token);
   1185 
   1186     return ;
   1187   }
   1188 
   1189   Flag  = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);
   1190   Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);
   1191   Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);
   1192 
   1193   Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);
   1194 }
   1195 
   1196 /**
   1197   Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
   1198 
   1199   @param Event      The receive event delivered to MNP for receive.
   1200   @param Context    Context for the callback.
   1201 
   1202 **/
   1203 VOID
   1204 EFIAPI
   1205 Ip4OnFrameReceived (
   1206   IN EFI_EVENT                Event,
   1207   IN VOID                     *Context
   1208   )
   1209 {
   1210   //
   1211   // Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK
   1212   //
   1213   QueueDpc (TPL_CALLBACK, Ip4OnFrameReceivedDpc, Context);
   1214 }
   1215 
   1216 
   1217 /**
   1218   Request to receive the packet from the interface.
   1219 
   1220   @param[in]  Interface         The interface to receive the frames from.
   1221   @param[in]  IpInstance        The instance that requests the receive. NULL for
   1222                                 the driver itself.
   1223   @param[in]  CallBack          Function to call when receive finished.
   1224   @param[in]  Context           Opaque parameter to the callback.
   1225 
   1226   @retval EFI_ALREADY_STARTED   There is already a pending receive request.
   1227   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to receive.
   1228   @retval EFI_SUCCESS           The recieve request has been started.
   1229   @retval other                 Other error occurs.
   1230 
   1231 **/
   1232 EFI_STATUS
   1233 Ip4ReceiveFrame (
   1234   IN  IP4_INTERFACE         *Interface,
   1235   IN  IP4_PROTOCOL          *IpInstance       OPTIONAL,
   1236   IN  IP4_FRAME_CALLBACK    CallBack,
   1237   IN  VOID                  *Context
   1238   )
   1239 {
   1240   IP4_LINK_RX_TOKEN *Token;
   1241   EFI_STATUS        Status;
   1242 
   1243   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
   1244 
   1245   if (Interface->RecvRequest != NULL) {
   1246     return EFI_ALREADY_STARTED;
   1247   }
   1248 
   1249   Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);
   1250 
   1251   if (Token == NULL) {
   1252     return EFI_OUT_OF_RESOURCES;
   1253   }
   1254 
   1255   Interface->RecvRequest = Token;
   1256   Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);
   1257   if (EFI_ERROR (Status)) {
   1258     Interface->RecvRequest = NULL;
   1259     Ip4FreeFrameRxToken (Token);
   1260     return Status;
   1261   }
   1262   return EFI_SUCCESS;
   1263 }
   1264