Home | History | Annotate | Download | only in Ip4Dxe
      1 /** @file
      2 
      3 Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 **/
     13 
     14 #include "Ip4Impl.h"
     15 
     16 EFI_IPSEC2_PROTOCOL    *mIpSec = NULL;
     17 
     18 /**
     19   Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.
     20 
     21   The GetModeData() function returns the current operational mode data for this
     22   driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This
     23   function is used optionally to retrieve the operational mode data of underlying
     24   networks or drivers.
     25 
     26   @param[in]   This          Pointer to the EFI_IP4_PROTOCOL instance.
     27   @param[out]  Ip4ModeData   Pointer to the EFI IPv4 Protocol mode data structure.
     28   @param[out]  MnpConfigData Pointer to the managed network configuration data structure.
     29   @param[out]  SnpModeData   Pointer to the simple network mode data structure.
     30 
     31   @retval EFI_SUCCESS           The operation completed successfully.
     32   @retval EFI_INVALID_PARAMETER This is NULL.
     33   @retval EFI_OUT_OF_RESOURCES  The required mode data could not be allocated.
     34 
     35 **/
     36 EFI_STATUS
     37 EFIAPI
     38 EfiIp4GetModeData (
     39   IN  CONST EFI_IP4_PROTOCOL                *This,
     40   OUT       EFI_IP4_MODE_DATA               *Ip4ModeData     OPTIONAL,
     41   OUT       EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData   OPTIONAL,
     42   OUT       EFI_SIMPLE_NETWORK_MODE         *SnpModeData     OPTIONAL
     43   );
     44 
     45 /**
     46   Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
     47 
     48   The Configure() function is used to set, change, or reset the operational
     49   parameters and filter settings for this EFI IPv4 Protocol instance. Until these
     50   parameters have been set, no network traffic can be sent or received by this
     51   instance. Once the parameters have been reset (by calling this function with
     52   IpConfigData set to NULL), no more traffic can be sent or received until these
     53   parameters have been set again. Each EFI IPv4 Protocol instance can be started
     54   and stopped independently of each other by enabling or disabling their receive
     55   filter settings with the Configure() function.
     56 
     57   When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
     58   be appended as an alias address into the addresses list in the EFI IPv4 Protocol
     59   driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
     60   to retrieve the default IPv4 address if it is not available yet. Clients could
     61   frequently call GetModeData() to check the status to ensure that the default IPv4
     62   address is ready.
     63 
     64   If operational parameters are reset or changed, any pending transmit and receive
     65   requests will be cancelled. Their completion token status will be set to EFI_ABORTED
     66   and their events will be signaled.
     67 
     68   @param[in]  This              Pointer to the EFI_IP4_PROTOCOL instance.
     69   @param[in]  IpConfigData      Pointer to the EFI IPv4 Protocol configuration data structure.
     70 
     71   @retval EFI_SUCCESS           The driver instance was successfully opened.
     72   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
     73                                 RARP, etc.) is not finished yet.
     74   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
     75   @retval EFI_UNSUPPORTED       One or more of the following conditions is TRUE:
     76                                 A configuration protocol (DHCP, BOOTP, RARP, etc.) could
     77                                 not be located when clients choose to use the default IPv4
     78                                 address. This EFI IPv4 Protocol implementation does not
     79                                 support this requested filter or timeout setting.
     80   @retval EFI_OUT_OF_RESOURCES  The EFI IPv4 Protocol driver instance data could not be allocated.
     81   @retval EFI_ALREADY_STARTED   The interface is already open and must be stopped before the
     82                                 IPv4 address or subnet mask can be changed. The interface must
     83                                 also be stopped when switching to/from raw packet mode.
     84   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred. The EFI IPv4
     85                                 Protocol driver instance is not opened.
     86 
     87 **/
     88 EFI_STATUS
     89 EFIAPI
     90 EfiIp4Configure (
     91   IN EFI_IP4_PROTOCOL       *This,
     92   IN EFI_IP4_CONFIG_DATA    *IpConfigData       OPTIONAL
     93   );
     94 
     95 /**
     96   Joins and leaves multicast groups.
     97 
     98   The Groups() function is used to join and leave multicast group sessions. Joining
     99   a group will enable reception of matching multicast packets. Leaving a group will
    100   disable the multicast packet reception.
    101 
    102   If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
    103 
    104   @param[in]  This                  Pointer to the EFI_IP4_PROTOCOL instance.
    105   @param[in]  JoinFlag              Set to TRUE to join the multicast group session and FALSE to leave.
    106   @param[in]  GroupAddress          Pointer to the IPv4 multicast address.
    107 
    108   @retval EFI_SUCCESS           The operation completed successfully.
    109   @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
    110                                 - This is NULL.
    111                                 - JoinFlag is TRUE and GroupAddress is NULL.
    112                                 - GroupAddress is not NULL and *GroupAddress is
    113                                 not a multicast IPv4 address.
    114   @retval EFI_NOT_STARTED       This instance has not been started.
    115   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
    116                                 RARP, etc.) is not finished yet.
    117   @retval EFI_OUT_OF_RESOURCES  System resources could not be allocated.
    118   @retval EFI_UNSUPPORTED       This EFI IPv4 Protocol implementation does not support multicast groups.
    119   @retval EFI_ALREADY_STARTED   The group address is already in the group table (when
    120                                 JoinFlag is TRUE).
    121   @retval EFI_NOT_FOUND         The group address is not in the group table (when JoinFlag is FALSE).
    122   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
    123 
    124 **/
    125 EFI_STATUS
    126 EFIAPI
    127 EfiIp4Groups (
    128   IN EFI_IP4_PROTOCOL       *This,
    129   IN BOOLEAN                JoinFlag,
    130   IN EFI_IPv4_ADDRESS       *GroupAddress     OPTIONAL
    131   );
    132 
    133 /**
    134   Adds and deletes routing table entries.
    135 
    136   The Routes() function adds a route to or deletes a route from the routing table.
    137 
    138   Routes are determined by comparing the SubnetAddress with the destination IPv4
    139   address arithmetically AND-ed with the SubnetMask. The gateway address must be
    140   on the same subnet as the configured station address.
    141 
    142   The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
    143   The default route matches all destination IPv4 addresses that do not match any
    144   other routes.
    145 
    146   A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
    147   IP address if it can be found in the ARP cache or on the local subnet. One automatic
    148   nonroute entry will be inserted into the routing table for outgoing packets that
    149   are addressed to a local subnet (gateway address of 0.0.0.0).
    150 
    151   Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
    152   IPv4 Protocol instances that use the default IPv4 address will also have copies
    153   of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
    154   copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
    155   instances. As a result, client modification to the routing table will be lost.
    156 
    157   @param[in]  This                   Pointer to the EFI_IP4_PROTOCOL instance.
    158   @param[in]  DeleteRoute            Set to TRUE to delete this route from the routing table. Set to
    159                                      FALSE to add this route to the routing table. SubnetAddress
    160                                      and SubnetMask are used as the key to each route entry.
    161   @param[in]  SubnetAddress          The address of the subnet that needs to be routed.
    162   @param[in]  SubnetMask             The subnet mask of SubnetAddress.
    163   @param[in]  GatewayAddress         The unicast gateway IPv4 address for this route.
    164 
    165   @retval EFI_SUCCESS            The operation completed successfully.
    166   @retval EFI_NOT_STARTED        The driver instance has not been started.
    167   @retval EFI_NO_MAPPING         When using the default address, configuration (DHCP, BOOTP,
    168                                  RARP, etc.) is not finished yet.
    169   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
    170                                  - This is NULL.
    171                                  - SubnetAddress is NULL.
    172                                  - SubnetMask is NULL.
    173                                  - GatewayAddress is NULL.
    174                                  - *SubnetAddress is not a valid subnet address.
    175                                  - *SubnetMask is not a valid subnet mask.
    176                                  - *GatewayAddress is not a valid unicast IPv4 address.
    177   @retval EFI_OUT_OF_RESOURCES   Could not add the entry to the routing table.
    178   @retval EFI_NOT_FOUND          This route is not in the routing table (when DeleteRoute is TRUE).
    179   @retval EFI_ACCESS_DENIED      The route is already defined in the routing table (when
    180                                   DeleteRoute is FALSE).
    181 
    182 **/
    183 EFI_STATUS
    184 EFIAPI
    185 EfiIp4Routes (
    186   IN EFI_IP4_PROTOCOL       *This,
    187   IN BOOLEAN                DeleteRoute,
    188   IN EFI_IPv4_ADDRESS       *SubnetAddress,
    189   IN EFI_IPv4_ADDRESS       *SubnetMask,
    190   IN EFI_IPv4_ADDRESS       *GatewayAddress
    191   );
    192 
    193 /**
    194   Places outgoing data packets into the transmit queue.
    195 
    196   The Transmit() function places a sending request in the transmit queue of this
    197   EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
    198   errors occur, the event in the token will be signaled and the status is updated.
    199 
    200   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
    201   @param[in]  Token Pointer to the transmit token.
    202 
    203   @retval  EFI_SUCCESS           The data has been queued for transmission.
    204   @retval  EFI_NOT_STARTED       This instance has not been started.
    205   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
    206                                  RARP, etc.) is not finished yet.
    207   @retval  EFI_INVALID_PARAMETER One or more pameters are invalid.
    208   @retval  EFI_ACCESS_DENIED     The transmit completion token with the same Token.Event
    209                                  was already in the transmit queue.
    210   @retval  EFI_NOT_READY         The completion token could not be queued because the transmit
    211                                  queue is full.
    212   @retval  EFI_NOT_FOUND         Not route is found to destination address.
    213   @retval  EFI_OUT_OF_RESOURCES  Could not queue the transmit data.
    214   @retval  EFI_BUFFER_TOO_SMALL  Token.Packet.TxData.TotalDataLength is too
    215                                  short to transmit.
    216   @retval  EFI_BAD_BUFFER_SIZE   The length of the IPv4 header + option length + total data length is
    217                                  greater than MTU (or greater than the maximum packet size if
    218                                  Token.Packet.TxData.OverrideData.
    219                                  DoNotFragment is TRUE.)
    220 
    221 **/
    222 EFI_STATUS
    223 EFIAPI
    224 EfiIp4Transmit (
    225   IN EFI_IP4_PROTOCOL         *This,
    226   IN EFI_IP4_COMPLETION_TOKEN *Token
    227   );
    228 
    229 /**
    230   Places a receiving request into the receiving queue.
    231 
    232   The Receive() function places a completion token into the receive packet queue.
    233   This function is always asynchronous.
    234 
    235   The Token.Event field in the completion token must be filled in by the caller
    236   and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
    237   driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
    238   is signaled.
    239 
    240   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
    241   @param[in]  Token Pointer to a token that is associated with the receive data descriptor.
    242 
    243   @retval EFI_SUCCESS           The receive completion token was cached.
    244   @retval EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.
    245   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
    246                                 is not finished yet.
    247   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
    248                                 - This is NULL.
    249                                 - Token is NULL.
    250                                 - Token.Event is NULL.
    251   @retval EFI_OUT_OF_RESOURCES  The receive completion token could not be queued due to a lack of system
    252                                 resources (usually memory).
    253   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
    254                                 The EFI IPv4 Protocol instance has been reset to startup defaults.
    255                                 EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
    256                                 in the receive queue.
    257   @retval EFI_NOT_READY         The receive request could not be queued because the receive queue is full.
    258   @retval EFI_ICMP_ERROR        An ICMP error packet was received.
    259 
    260 **/
    261 EFI_STATUS
    262 EFIAPI
    263 EfiIp4Receive (
    264   IN EFI_IP4_PROTOCOL         *This,
    265   IN EFI_IP4_COMPLETION_TOKEN *Token
    266   );
    267 
    268 /**
    269   Abort an asynchronous transmit or receive request.
    270 
    271   The Cancel() function is used to abort a pending transmit or receive request.
    272   If the token is in the transmit or receive request queues, after calling this
    273   function, Token->Status will be set to EFI_ABORTED and then Token->Event will
    274   be signaled. If the token is not in one of the queues, which usually means the
    275   asynchronous operation has completed, this function will not signal the token
    276   and EFI_NOT_FOUND is returned.
    277 
    278   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
    279   @param[in]  Token Pointer to a token that has been issued by
    280                     EFI_IP4_PROTOCOL.Transmit() or
    281                     EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
    282                     tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
    283                     defined in EFI_IP4_PROTOCOL.Transmit().
    284 
    285   @retval EFI_SUCCESS           The asynchronous I/O request was aborted and
    286                                 Token.->Event was signaled. When Token is NULL, all
    287                                 pending requests were aborted and their events were signaled.
    288   @retval EFI_INVALID_PARAMETER This is NULL.
    289   @retval EFI_NOT_STARTED       This instance has not been started.
    290   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
    291                                 RARP, etc.) is not finished yet.
    292   @retval EFI_NOT_FOUND         When Token is not NULL, the asynchronous I/O request was
    293                                 not found in the transmit or receive queue. It has either completed
    294                                 or was not issued by Transmit() and Receive().
    295 
    296 **/
    297 EFI_STATUS
    298 EFIAPI
    299 EfiIp4Cancel (
    300   IN EFI_IP4_PROTOCOL         *This,
    301   IN EFI_IP4_COMPLETION_TOKEN *Token    OPTIONAL
    302   );
    303 
    304 /**
    305   Polls for incoming data packets and processes outgoing data packets.
    306 
    307   The Poll() function polls for incoming data packets and processes outgoing data
    308   packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
    309   function to increase the rate that data packets are moved between the communications
    310   device and the transmit and receive queues.
    311 
    312   In some systems the periodic timer event may not poll the underlying communications
    313   device fast enough to transmit and/or receive all data packets without missing
    314   incoming packets or dropping outgoing packets. Drivers and applications that are
    315   experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
    316   more often.
    317 
    318   @param[in]  This               Pointer to the EFI_IP4_PROTOCOL instance.
    319 
    320   @retval  EFI_SUCCESS           Incoming or outgoing data was processed.
    321   @retval  EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.
    322   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
    323                                  RARP, etc.) is not finished yet.
    324   @retval  EFI_INVALID_PARAMETER This is NULL.
    325   @retval  EFI_DEVICE_ERROR      An unexpected system or network error occurred.
    326   @retval  EFI_NOT_READY         No incoming or outgoing data is processed.
    327   @retval  EFI_TIMEOUT           Data was dropped out of the transmit and/or receive queue.
    328                                  Consider increasing the polling rate.
    329 
    330 **/
    331 EFI_STATUS
    332 EFIAPI
    333 EfiIp4Poll (
    334   IN EFI_IP4_PROTOCOL       *This
    335   );
    336 
    337 EFI_IP4_PROTOCOL
    338 mEfiIp4ProtocolTemplete = {
    339   EfiIp4GetModeData,
    340   EfiIp4Configure,
    341   EfiIp4Groups,
    342   EfiIp4Routes,
    343   EfiIp4Transmit,
    344   EfiIp4Receive,
    345   EfiIp4Cancel,
    346   EfiIp4Poll
    347 };
    348 
    349 /**
    350   Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.
    351 
    352   The GetModeData() function returns the current operational mode data for this
    353   driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This
    354   function is used optionally to retrieve the operational mode data of underlying
    355   networks or drivers.
    356 
    357   @param[in]   This          Pointer to the EFI_IP4_PROTOCOL instance.
    358   @param[out]  Ip4ModeData   Pointer to the EFI IPv4 Protocol mode data structure.
    359   @param[out]  MnpConfigData Pointer to the managed network configuration data structure.
    360   @param[out]  SnpModeData   Pointer to the simple network mode data structure.
    361 
    362   @retval EFI_SUCCESS           The operation completed successfully.
    363   @retval EFI_INVALID_PARAMETER This is NULL.
    364   @retval EFI_OUT_OF_RESOURCES  The required mode data could not be allocated.
    365 
    366 **/
    367 EFI_STATUS
    368 EFIAPI
    369 EfiIp4GetModeData (
    370   IN  CONST EFI_IP4_PROTOCOL                *This,
    371   OUT       EFI_IP4_MODE_DATA               *Ip4ModeData     OPTIONAL,
    372   OUT       EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData   OPTIONAL,
    373   OUT       EFI_SIMPLE_NETWORK_MODE         *SnpModeData     OPTIONAL
    374   )
    375 {
    376   IP4_PROTOCOL              *IpInstance;
    377   IP4_SERVICE               *IpSb;
    378   EFI_IP4_CONFIG_DATA       *Config;
    379   EFI_STATUS                Status;
    380   EFI_TPL                   OldTpl;
    381   IP4_ADDR                  Ip;
    382 
    383   if (This == NULL) {
    384     return EFI_INVALID_PARAMETER;
    385   }
    386 
    387   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
    388   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
    389   IpSb       = IpInstance->Service;
    390 
    391   if (Ip4ModeData != NULL) {
    392     //
    393     // IsStarted is "whether the EfiIp4Configure has been called".
    394     // IsConfigured is "whether the station address has been configured"
    395     //
    396     Ip4ModeData->IsStarted     = (BOOLEAN)(IpInstance->State == IP4_STATE_CONFIGED);
    397     CopyMem (&Ip4ModeData->ConfigData, &IpInstance->ConfigData, sizeof (Ip4ModeData->ConfigData));
    398     Ip4ModeData->IsConfigured  = FALSE;
    399 
    400     Ip4ModeData->GroupCount    = IpInstance->GroupCount;
    401     Ip4ModeData->GroupTable    = (EFI_IPv4_ADDRESS *) IpInstance->Groups;
    402 
    403     Ip4ModeData->IcmpTypeCount = 23;
    404     Ip4ModeData->IcmpTypeList  = mIp4SupportedIcmp;
    405 
    406     Ip4ModeData->RouteTable    = NULL;
    407     Ip4ModeData->RouteCount    = 0;
    408 
    409     Ip4ModeData->MaxPacketSize = IpSb->MaxPacketSize;
    410 
    411     //
    412     // return the current station address for this IP child. So,
    413     // the user can get the default address through this. Some
    414     // application wants to know it station address even it is
    415     // using the default one, such as a ftp server.
    416     //
    417     if (Ip4ModeData->IsStarted) {
    418       Config  = &Ip4ModeData->ConfigData;
    419 
    420       Ip = HTONL (IpInstance->Interface->Ip);
    421       CopyMem (&Config->StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
    422 
    423       Ip = HTONL (IpInstance->Interface->SubnetMask);
    424       CopyMem (&Config->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));
    425 
    426       Ip4ModeData->IsConfigured = IpInstance->Interface->Configured;
    427 
    428       //
    429       // Build a EFI route table for user from the internal route table.
    430       //
    431       Status = Ip4BuildEfiRouteTable (IpInstance);
    432 
    433       if (EFI_ERROR (Status)) {
    434         gBS->RestoreTPL (OldTpl);
    435         return Status;
    436       }
    437 
    438       Ip4ModeData->RouteTable = IpInstance->EfiRouteTable;
    439       Ip4ModeData->RouteCount = IpInstance->EfiRouteCount;
    440     }
    441   }
    442 
    443   //
    444   // Get fresh mode data from MNP, since underlying media status may change
    445   //
    446   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, MnpConfigData, SnpModeData);
    447 
    448   gBS->RestoreTPL (OldTpl);
    449   return Status;
    450 }
    451 
    452 
    453 /**
    454   Config the MNP parameter used by IP. The IP driver use one MNP
    455   child to transmit/receive frames. By default, it configures MNP
    456   to receive unicast/multicast/broadcast. And it will enable/disable
    457   the promiscous receive according to whether there is IP child
    458   enable that or not. If Force is FALSE, it will iterate through
    459   all the IP children to check whether the promiscuous receive
    460   setting has been changed. If it hasn't been changed, it won't
    461   reconfigure the MNP. If Force is TRUE, the MNP is configured no
    462   matter whether that is changed or not.
    463 
    464   @param[in]  IpSb               The IP4 service instance that is to be changed.
    465   @param[in]  Force              Force the configuration or not.
    466 
    467   @retval EFI_SUCCESS            The MNP is successfully configured/reconfigured.
    468   @retval Others                 Configuration failed.
    469 
    470 **/
    471 EFI_STATUS
    472 Ip4ServiceConfigMnp (
    473   IN IP4_SERVICE            *IpSb,
    474   IN BOOLEAN                Force
    475   )
    476 {
    477   LIST_ENTRY                *Entry;
    478   LIST_ENTRY                *ProtoEntry;
    479   IP4_INTERFACE             *IpIf;
    480   IP4_PROTOCOL              *IpInstance;
    481   BOOLEAN                   Reconfig;
    482   BOOLEAN                   PromiscReceive;
    483   EFI_STATUS                Status;
    484 
    485   Reconfig       = FALSE;
    486   PromiscReceive = FALSE;
    487 
    488   if (!Force) {
    489     //
    490     // Iterate through the IP children to check whether promiscuous
    491     // receive setting has been changed. Update the interface's receive
    492     // filter also.
    493     //
    494     NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
    495 
    496       IpIf              = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
    497       IpIf->PromiscRecv = FALSE;
    498 
    499       NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {
    500         IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP4_PROTOCOL, AddrLink);
    501 
    502         if (IpInstance->ConfigData.AcceptPromiscuous) {
    503           IpIf->PromiscRecv = TRUE;
    504           PromiscReceive    = TRUE;
    505         }
    506       }
    507     }
    508 
    509     //
    510     // If promiscuous receive isn't changed, it isn't necessary to reconfigure.
    511     //
    512     if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {
    513       return EFI_SUCCESS;
    514     }
    515 
    516     Reconfig  = TRUE;
    517     IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;
    518   }
    519 
    520   Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);
    521 
    522   //
    523   // recover the original configuration if failed to set the configure.
    524   //
    525   if (EFI_ERROR (Status) && Reconfig) {
    526     IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;
    527   }
    528 
    529   return Status;
    530 }
    531 
    532 
    533 /**
    534   Intiialize the IP4_PROTOCOL structure to the unconfigured states.
    535 
    536   @param  IpSb                   The IP4 service instance.
    537   @param  IpInstance             The IP4 child instance.
    538 
    539 **/
    540 VOID
    541 Ip4InitProtocol (
    542   IN     IP4_SERVICE            *IpSb,
    543   IN OUT IP4_PROTOCOL           *IpInstance
    544   )
    545 {
    546   ASSERT ((IpSb != NULL) && (IpInstance != NULL));
    547 
    548   ZeroMem (IpInstance, sizeof (IP4_PROTOCOL));
    549 
    550   IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;
    551   CopyMem (&IpInstance->Ip4Proto, &mEfiIp4ProtocolTemplete, sizeof (IpInstance->Ip4Proto));
    552   IpInstance->State     = IP4_STATE_UNCONFIGED;
    553   IpInstance->Service   = IpSb;
    554 
    555   InitializeListHead (&IpInstance->Link);
    556   NetMapInit  (&IpInstance->RxTokens);
    557   NetMapInit  (&IpInstance->TxTokens);
    558   InitializeListHead (&IpInstance->Received);
    559   InitializeListHead (&IpInstance->Delivered);
    560   InitializeListHead (&IpInstance->AddrLink);
    561 
    562   EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);
    563 }
    564 
    565 
    566 /**
    567   Configure the IP4 child. If the child is already configured,
    568   change the configuration parameter. Otherwise configure it
    569   for the first time. The caller should validate the configuration
    570   before deliver them to it. It also don't do configure NULL.
    571 
    572   @param[in, out]  IpInstance         The IP4 child to configure.
    573   @param[in]       Config             The configure data.
    574 
    575   @retval EFI_SUCCESS            The IP4 child is successfully configured.
    576   @retval EFI_DEVICE_ERROR       Failed to free the pending transive or to
    577                                  configure  underlying MNP or other errors.
    578   @retval EFI_NO_MAPPING         The IP4 child is configured to use default
    579                                  address, but the default address hasn't been
    580                                  configured. The IP4 child doesn't need to be
    581                                  reconfigured when default address is configured.
    582   @retval EFI_OUT_OF_RESOURCES   No more memory space is available.
    583   @retval other                  Other error occurs.
    584 
    585 **/
    586 EFI_STATUS
    587 Ip4ConfigProtocol (
    588   IN OUT IP4_PROTOCOL         *IpInstance,
    589   IN     EFI_IP4_CONFIG_DATA  *Config
    590   )
    591 {
    592   IP4_SERVICE               *IpSb;
    593   IP4_INTERFACE             *IpIf;
    594   EFI_STATUS                Status;
    595   IP4_ADDR                  Ip;
    596   IP4_ADDR                  Netmask;
    597   EFI_ARP_PROTOCOL          *Arp;
    598 
    599   IpSb = IpInstance->Service;
    600 
    601   //
    602   // User is changing packet filters. It must be stopped
    603   // before the station address can be changed.
    604   //
    605   if (IpInstance->State == IP4_STATE_CONFIGED) {
    606     //
    607     // Cancel all the pending transmit/receive from upper layer
    608     //
    609     Status = Ip4Cancel (IpInstance, NULL);
    610 
    611     if (EFI_ERROR (Status)) {
    612       return EFI_DEVICE_ERROR;
    613     }
    614 
    615     CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
    616     return EFI_SUCCESS;
    617   }
    618 
    619   //
    620   // Configure a fresh IP4 protocol instance. Create a route table.
    621   // Each IP child has its own route table, which may point to the
    622   // default table if it is using default address.
    623   //
    624   Status                 = EFI_OUT_OF_RESOURCES;
    625   IpInstance->RouteTable = Ip4CreateRouteTable ();
    626 
    627   if (IpInstance->RouteTable == NULL) {
    628     return Status;
    629   }
    630 
    631   //
    632   // Set up the interface.
    633   //
    634   CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));
    635   CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));
    636 
    637   Ip      = NTOHL (Ip);
    638   Netmask = NTOHL (Netmask);
    639 
    640   if (!Config->UseDefaultAddress) {
    641     //
    642     // Find whether there is already an interface with the same
    643     // station address. All the instances with the same station
    644     // address shares one interface.
    645     //
    646     IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);
    647 
    648     if (IpIf != NULL) {
    649       NET_GET_REF (IpIf);
    650 
    651     } else {
    652       IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
    653 
    654       if (IpIf == NULL) {
    655         goto ON_ERROR;
    656       }
    657 
    658       Status = Ip4SetAddress (IpIf, Ip, Netmask);
    659 
    660       if (EFI_ERROR (Status)) {
    661         Status = EFI_DEVICE_ERROR;
    662         Ip4FreeInterface (IpIf, IpInstance);
    663         goto ON_ERROR;
    664       }
    665 
    666       InsertTailList (&IpSb->Interfaces, &IpIf->Link);
    667     }
    668 
    669     //
    670     // Add a route to this connected network in the route table
    671     //
    672     Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);
    673 
    674   } else {
    675     //
    676     // Use the default address. Check the state.
    677     //
    678     if (IpSb->State == IP4_SERVICE_UNSTARTED) {
    679       Status = Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);
    680 
    681       if (EFI_ERROR (Status)) {
    682         goto ON_ERROR;
    683       }
    684     }
    685 
    686     IpIf = IpSb->DefaultInterface;
    687     NET_GET_REF (IpSb->DefaultInterface);
    688 
    689     //
    690     // If default address is used, so is the default route table.
    691     // Any route set by the instance has the precedence over the
    692     // routes in the default route table. Link the default table
    693     // after the instance's table. Routing will search the local
    694     // table first.
    695     //
    696     NET_GET_REF (IpSb->DefaultRouteTable);
    697     IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;
    698   }
    699 
    700   IpInstance->Interface = IpIf;
    701   if (IpIf->Arp != NULL) {
    702     Arp = NULL;
    703     Status = gBS->OpenProtocol (
    704                     IpIf->ArpHandle,
    705                     &gEfiArpProtocolGuid,
    706                     (VOID **) &Arp,
    707                     gIp4DriverBinding.DriverBindingHandle,
    708                     IpInstance->Handle,
    709                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    710                     );
    711     if (EFI_ERROR (Status)) {
    712       goto ON_ERROR;
    713     }
    714   }
    715   InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
    716 
    717   CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
    718   IpInstance->State       = IP4_STATE_CONFIGED;
    719 
    720   //
    721   // Although EFI_NO_MAPPING is an error code, the IP child has been
    722   // successfully configured and doesn't need reconfiguration when
    723   // default address is acquired.
    724   //
    725   if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
    726     return EFI_NO_MAPPING;
    727   }
    728 
    729   return EFI_SUCCESS;
    730 
    731 ON_ERROR:
    732   Ip4FreeRouteTable (IpInstance->RouteTable);
    733   IpInstance->RouteTable = NULL;
    734   return Status;
    735 }
    736 
    737 
    738 /**
    739   Clean up the IP4 child, release all the resources used by it.
    740 
    741   @param[in]  IpInstance         The IP4 child to clean up.
    742 
    743   @retval EFI_SUCCESS            The IP4 child is cleaned up.
    744   @retval EFI_DEVICE_ERROR       Some resources failed to be released.
    745 
    746 **/
    747 EFI_STATUS
    748 Ip4CleanProtocol (
    749   IN  IP4_PROTOCOL          *IpInstance
    750   )
    751 {
    752   if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {
    753     return EFI_DEVICE_ERROR;
    754   }
    755 
    756   if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {
    757     return EFI_DEVICE_ERROR;
    758   }
    759 
    760   //
    761   // Some packets haven't been recycled. It is because either the
    762   // user forgets to recycle the packets, or because the callback
    763   // hasn't been called. Just leave it alone.
    764   //
    765   if (!IsListEmpty (&IpInstance->Delivered)) {
    766     ;
    767   }
    768 
    769   if (IpInstance->Interface != NULL) {
    770     RemoveEntryList (&IpInstance->AddrLink);
    771     if (IpInstance->Interface->Arp != NULL) {
    772       gBS->CloseProtocol (
    773              IpInstance->Interface->ArpHandle,
    774              &gEfiArpProtocolGuid,
    775              gIp4DriverBinding.DriverBindingHandle,
    776              IpInstance->Handle
    777              );
    778     }
    779     Ip4FreeInterface (IpInstance->Interface, IpInstance);
    780     IpInstance->Interface = NULL;
    781   }
    782 
    783   if (IpInstance->RouteTable != NULL) {
    784     if (IpInstance->RouteTable->Next != NULL) {
    785       Ip4FreeRouteTable (IpInstance->RouteTable->Next);
    786     }
    787 
    788     Ip4FreeRouteTable (IpInstance->RouteTable);
    789     IpInstance->RouteTable = NULL;
    790   }
    791 
    792   if (IpInstance->EfiRouteTable != NULL) {
    793     FreePool (IpInstance->EfiRouteTable);
    794     IpInstance->EfiRouteTable = NULL;
    795     IpInstance->EfiRouteCount = 0;
    796   }
    797 
    798   if (IpInstance->Groups != NULL) {
    799     FreePool (IpInstance->Groups);
    800     IpInstance->Groups      = NULL;
    801     IpInstance->GroupCount  = 0;
    802   }
    803 
    804   NetMapClean (&IpInstance->TxTokens);
    805 
    806   NetMapClean (&IpInstance->RxTokens);
    807 
    808   return EFI_SUCCESS;
    809 }
    810 
    811 
    812 /**
    813   Validate that Ip/Netmask pair is OK to be used as station
    814   address. Only continuous netmasks are supported. and check
    815   that StationAddress is a unicast address on the newtwork.
    816 
    817   @param[in]  Ip                 The IP address to validate.
    818   @param[in]  Netmask            The netmaks of the IP.
    819 
    820   @retval TRUE                   The Ip/Netmask pair is valid.
    821   @retval FALSE                  The Ip/Netmask pair is invalid.
    822 
    823 **/
    824 BOOLEAN
    825 Ip4StationAddressValid (
    826   IN IP4_ADDR               Ip,
    827   IN IP4_ADDR               Netmask
    828   )
    829 {
    830   IP4_ADDR                  NetBrdcastMask;
    831   INTN                      Len;
    832   INTN                      Type;
    833 
    834   //
    835   // Only support the station address with 0.0.0.0/0 to enable DHCP client.
    836   //
    837   if (Netmask == IP4_ALLZERO_ADDRESS) {
    838     return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);
    839   }
    840 
    841   //
    842   // Only support the continuous net masks
    843   //
    844   if ((Len = NetGetMaskLength (Netmask)) == (IP4_MASK_MAX + 1)) {
    845     return FALSE;
    846   }
    847 
    848   //
    849   // Station address can't be class D or class E address
    850   //
    851   if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {
    852     return FALSE;
    853   }
    854 
    855   //
    856   // Station address can't be subnet broadcast/net broadcast address
    857   //
    858   if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {
    859     return FALSE;
    860   }
    861 
    862   NetBrdcastMask = gIp4AllMasks[MIN (Len, Type << 3)];
    863 
    864   if (Ip == (Ip | ~NetBrdcastMask)) {
    865     return FALSE;
    866   }
    867 
    868   return TRUE;
    869 }
    870 
    871 
    872 /**
    873   Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
    874 
    875   The Configure() function is used to set, change, or reset the operational
    876   parameters and filter settings for this EFI IPv4 Protocol instance. Until these
    877   parameters have been set, no network traffic can be sent or received by this
    878   instance. Once the parameters have been reset (by calling this function with
    879   IpConfigData set to NULL), no more traffic can be sent or received until these
    880   parameters have been set again. Each EFI IPv4 Protocol instance can be started
    881   and stopped independently of each other by enabling or disabling their receive
    882   filter settings with the Configure() function.
    883 
    884   When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
    885   be appended as an alias address into the addresses list in the EFI IPv4 Protocol
    886   driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
    887   to retrieve the default IPv4 address if it is not available yet. Clients could
    888   frequently call GetModeData() to check the status to ensure that the default IPv4
    889   address is ready.
    890 
    891   If operational parameters are reset or changed, any pending transmit and receive
    892   requests will be cancelled. Their completion token status will be set to EFI_ABORTED
    893   and their events will be signaled.
    894 
    895   @param[in]  This              Pointer to the EFI_IP4_PROTOCOL instance.
    896   @param[in]  IpConfigData      Pointer to the EFI IPv4 Protocol configuration data structure.
    897 
    898   @retval EFI_SUCCESS           The driver instance was successfully opened.
    899   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
    900                                 RARP, etc.) is not finished yet.
    901   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
    902   @retval EFI_UNSUPPORTED       One or more of the following conditions is TRUE:
    903                                 A configuration protocol (DHCP, BOOTP, RARP, etc.) could
    904                                 not be located when clients choose to use the default IPv4
    905                                 address. This EFI IPv4 Protocol implementation does not
    906                                 support this requested filter or timeout setting.
    907   @retval EFI_OUT_OF_RESOURCES  The EFI IPv4 Protocol driver instance data could not be allocated.
    908   @retval EFI_ALREADY_STARTED   The interface is already open and must be stopped before the
    909                                 IPv4 address or subnet mask can be changed. The interface must
    910                                 also be stopped when switching to/from raw packet mode.
    911   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred. The EFI IPv4
    912                                 Protocol driver instance is not opened.
    913 
    914 **/
    915 EFI_STATUS
    916 EFIAPI
    917 EfiIp4Configure (
    918   IN EFI_IP4_PROTOCOL       *This,
    919   IN EFI_IP4_CONFIG_DATA    *IpConfigData       OPTIONAL
    920   )
    921 {
    922   IP4_PROTOCOL              *IpInstance;
    923   EFI_IP4_CONFIG_DATA       *Current;
    924   EFI_TPL                   OldTpl;
    925   EFI_STATUS                Status;
    926   BOOLEAN                   AddrOk;
    927   IP4_ADDR                  IpAddress;
    928   IP4_ADDR                  SubnetMask;
    929 
    930   //
    931   // First, validate the parameters
    932   //
    933   if (This == NULL) {
    934     return EFI_INVALID_PARAMETER;
    935   }
    936 
    937   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
    938   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
    939 
    940   //
    941   // Validate the configuration first.
    942   //
    943   if (IpConfigData != NULL) {
    944 
    945     CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));
    946     CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));
    947 
    948     IpAddress  = NTOHL (IpAddress);
    949     SubnetMask = NTOHL (SubnetMask);
    950 
    951     //
    952     // Check whether the station address is a valid unicast address
    953     //
    954     if (!IpConfigData->UseDefaultAddress) {
    955       AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);
    956 
    957       if (!AddrOk) {
    958         Status = EFI_INVALID_PARAMETER;
    959         goto ON_EXIT;
    960       }
    961     }
    962 
    963     //
    964     // User can only update packet filters when already configured.
    965     // If it wants to change the station address, it must configure(NULL)
    966     // the instance first.
    967     //
    968     if (IpInstance->State == IP4_STATE_CONFIGED) {
    969       Current = &IpInstance->ConfigData;
    970 
    971       if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {
    972         Status = EFI_ALREADY_STARTED;
    973         goto ON_EXIT;
    974       }
    975 
    976       if (!Current->UseDefaultAddress &&
    977          (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||
    978           !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {
    979         Status = EFI_ALREADY_STARTED;
    980         goto ON_EXIT;
    981       }
    982 
    983       if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
    984         Status = EFI_NO_MAPPING;
    985         goto ON_EXIT;
    986       }
    987     }
    988   }
    989 
    990   //
    991   // Configure the instance or clean it up.
    992   //
    993   if (IpConfigData != NULL) {
    994     Status = Ip4ConfigProtocol (IpInstance, IpConfigData);
    995   } else {
    996     Status = Ip4CleanProtocol (IpInstance);
    997 
    998     //
    999     // Don't change the state if it is DESTROY, consider the following
   1000     // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
   1001     // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
   1002     // the unload fails miserably.
   1003     //
   1004     if (IpInstance->State == IP4_STATE_CONFIGED) {
   1005       IpInstance->State = IP4_STATE_UNCONFIGED;
   1006     }
   1007   }
   1008 
   1009   //
   1010   // Update the MNP's configure data. Ip4ServiceConfigMnp will check
   1011   // whether it is necessary to reconfigure the MNP.
   1012   //
   1013   Ip4ServiceConfigMnp (IpInstance->Service, FALSE);
   1014 
   1015 ON_EXIT:
   1016   gBS->RestoreTPL (OldTpl);
   1017   return Status;
   1018 
   1019 }
   1020 
   1021 
   1022 /**
   1023   Change the IP4 child's multicast setting. The caller
   1024   should make sure that the parameters is valid.
   1025 
   1026   @param[in]  IpInstance             The IP4 child to change the setting.
   1027   @param[in]  JoinFlag               TRUE to join the group, otherwise leave it.
   1028   @param[in]  GroupAddress           The target group address.
   1029 
   1030   @retval EFI_ALREADY_STARTED    Want to join the group, but already a member of it.
   1031   @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.
   1032   @retval EFI_DEVICE_ERROR       Failed to set the group configuraton.
   1033   @retval EFI_SUCCESS            Successfully updated the group setting.
   1034   @retval EFI_NOT_FOUND          Try to leave the group which it isn't a member.
   1035 
   1036 **/
   1037 EFI_STATUS
   1038 Ip4Groups (
   1039   IN IP4_PROTOCOL           *IpInstance,
   1040   IN BOOLEAN                JoinFlag,
   1041   IN EFI_IPv4_ADDRESS       *GroupAddress       OPTIONAL
   1042   )
   1043 {
   1044   IP4_ADDR                  *Members;
   1045   IP4_ADDR                  Group;
   1046   UINT32                    Index;
   1047 
   1048   //
   1049   // Add it to the instance's Groups, and join the group by IGMP.
   1050   // IpInstance->Groups is in network byte order. IGMP operates in
   1051   // host byte order
   1052   //
   1053   if (JoinFlag) {
   1054     //
   1055     // When JoinFlag is TRUE, GroupAddress shouldn't be NULL.
   1056     //
   1057     ASSERT (GroupAddress != NULL);
   1058     CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));
   1059 
   1060     for (Index = 0; Index < IpInstance->GroupCount; Index++) {
   1061       if (IpInstance->Groups[Index] == Group) {
   1062         return EFI_ALREADY_STARTED;
   1063       }
   1064     }
   1065 
   1066     Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);
   1067 
   1068     if (Members == NULL) {
   1069       return EFI_OUT_OF_RESOURCES;
   1070     }
   1071 
   1072     if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {
   1073       FreePool (Members);
   1074       return EFI_DEVICE_ERROR;
   1075     }
   1076 
   1077     if (IpInstance->Groups != NULL) {
   1078       FreePool (IpInstance->Groups);
   1079     }
   1080 
   1081     IpInstance->Groups = Members;
   1082     IpInstance->GroupCount++;
   1083 
   1084     return EFI_SUCCESS;
   1085   }
   1086 
   1087   //
   1088   // Leave the group. Leave all the groups if GroupAddress is NULL.
   1089   // Must iterate from the end to the beginning because the GroupCount
   1090   // is decreamented each time an address is removed..
   1091   //
   1092   for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {
   1093     Group = IpInstance->Groups[Index - 1];
   1094 
   1095     if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {
   1096       if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {
   1097         return EFI_DEVICE_ERROR;
   1098       }
   1099 
   1100       Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);
   1101       IpInstance->GroupCount--;
   1102 
   1103       if (IpInstance->GroupCount == 0) {
   1104         ASSERT (Index == 1);
   1105 
   1106         FreePool (IpInstance->Groups);
   1107         IpInstance->Groups = NULL;
   1108       }
   1109 
   1110       if (GroupAddress != NULL) {
   1111         return EFI_SUCCESS;
   1112       }
   1113     }
   1114   }
   1115 
   1116   return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);
   1117 }
   1118 
   1119 
   1120 /**
   1121   Joins and leaves multicast groups.
   1122 
   1123   The Groups() function is used to join and leave multicast group sessions. Joining
   1124   a group will enable reception of matching multicast packets. Leaving a group will
   1125   disable the multicast packet reception.
   1126 
   1127   If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
   1128 
   1129   @param[in]  This                  Pointer to the EFI_IP4_PROTOCOL instance.
   1130   @param[in]  JoinFlag              Set to TRUE to join the multicast group session and FALSE to leave.
   1131   @param[in]  GroupAddress          Pointer to the IPv4 multicast address.
   1132 
   1133   @retval EFI_SUCCESS           The operation completed successfully.
   1134   @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
   1135                                 - This is NULL.
   1136                                 - JoinFlag is TRUE and GroupAddress is NULL.
   1137                                 - GroupAddress is not NULL and *GroupAddress is
   1138                                 not a multicast IPv4 address.
   1139   @retval EFI_NOT_STARTED       This instance has not been started.
   1140   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
   1141                                 RARP, etc.) is not finished yet.
   1142   @retval EFI_OUT_OF_RESOURCES  System resources could not be allocated.
   1143   @retval EFI_UNSUPPORTED       This EFI IPv4 Protocol implementation does not support multicast groups.
   1144   @retval EFI_ALREADY_STARTED   The group address is already in the group table (when
   1145                                 JoinFlag is TRUE).
   1146   @retval EFI_NOT_FOUND         The group address is not in the group table (when JoinFlag is FALSE).
   1147   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
   1148 
   1149 **/
   1150 EFI_STATUS
   1151 EFIAPI
   1152 EfiIp4Groups (
   1153   IN EFI_IP4_PROTOCOL       *This,
   1154   IN BOOLEAN                JoinFlag,
   1155   IN EFI_IPv4_ADDRESS       *GroupAddress     OPTIONAL
   1156   )
   1157 {
   1158   IP4_PROTOCOL              *IpInstance;
   1159   EFI_STATUS                Status;
   1160   EFI_TPL                   OldTpl;
   1161   IP4_ADDR                  McastIp;
   1162 
   1163   if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {
   1164     return EFI_INVALID_PARAMETER;
   1165   }
   1166 
   1167   if (GroupAddress != NULL) {
   1168     CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));
   1169 
   1170     if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {
   1171       return EFI_INVALID_PARAMETER;
   1172     }
   1173   }
   1174 
   1175   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   1176   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
   1177 
   1178   if (IpInstance->State != IP4_STATE_CONFIGED) {
   1179     Status = EFI_NOT_STARTED;
   1180     goto ON_EXIT;
   1181   }
   1182 
   1183   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
   1184     Status = EFI_NO_MAPPING;
   1185     goto ON_EXIT;
   1186   }
   1187 
   1188   Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);
   1189 
   1190 ON_EXIT:
   1191   gBS->RestoreTPL (OldTpl);
   1192   return Status;
   1193 }
   1194 
   1195 
   1196 /**
   1197   Adds and deletes routing table entries.
   1198 
   1199   The Routes() function adds a route to or deletes a route from the routing table.
   1200 
   1201   Routes are determined by comparing the SubnetAddress with the destination IPv4
   1202   address arithmetically AND-ed with the SubnetMask. The gateway address must be
   1203   on the same subnet as the configured station address.
   1204 
   1205   The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
   1206   The default route matches all destination IPv4 addresses that do not match any
   1207   other routes.
   1208 
   1209   A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
   1210   IP address if it can be found in the ARP cache or on the local subnet. One automatic
   1211   nonroute entry will be inserted into the routing table for outgoing packets that
   1212   are addressed to a local subnet (gateway address of 0.0.0.0).
   1213 
   1214   Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
   1215   IPv4 Protocol instances that use the default IPv4 address will also have copies
   1216   of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
   1217   copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
   1218   instances. As a result, client modification to the routing table will be lost.
   1219 
   1220   @param[in]  This                   Pointer to the EFI_IP4_PROTOCOL instance.
   1221   @param[in]  DeleteRoute            Set to TRUE to delete this route from the routing table. Set to
   1222                                      FALSE to add this route to the routing table. SubnetAddress
   1223                                      and SubnetMask are used as the key to each route entry.
   1224   @param[in]  SubnetAddress          The address of the subnet that needs to be routed.
   1225   @param[in]  SubnetMask             The subnet mask of SubnetAddress.
   1226   @param[in]  GatewayAddress         The unicast gateway IPv4 address for this route.
   1227 
   1228   @retval EFI_SUCCESS            The operation completed successfully.
   1229   @retval EFI_NOT_STARTED        The driver instance has not been started.
   1230   @retval EFI_NO_MAPPING         When using the default address, configuration (DHCP, BOOTP,
   1231                                  RARP, etc.) is not finished yet.
   1232   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
   1233                                  - This is NULL.
   1234                                  - SubnetAddress is NULL.
   1235                                  - SubnetMask is NULL.
   1236                                  - GatewayAddress is NULL.
   1237                                  - *SubnetAddress is not a valid subnet address.
   1238                                  - *SubnetMask is not a valid subnet mask.
   1239                                  - *GatewayAddress is not a valid unicast IPv4 address.
   1240   @retval EFI_OUT_OF_RESOURCES   Could not add the entry to the routing table.
   1241   @retval EFI_NOT_FOUND          This route is not in the routing table (when DeleteRoute is TRUE).
   1242   @retval EFI_ACCESS_DENIED      The route is already defined in the routing table (when
   1243                                   DeleteRoute is FALSE).
   1244 
   1245 **/
   1246 EFI_STATUS
   1247 EFIAPI
   1248 EfiIp4Routes (
   1249   IN EFI_IP4_PROTOCOL       *This,
   1250   IN BOOLEAN                DeleteRoute,
   1251   IN EFI_IPv4_ADDRESS       *SubnetAddress,
   1252   IN EFI_IPv4_ADDRESS       *SubnetMask,
   1253   IN EFI_IPv4_ADDRESS       *GatewayAddress
   1254   )
   1255 {
   1256   IP4_PROTOCOL              *IpInstance;
   1257   IP4_INTERFACE             *IpIf;
   1258   IP4_ADDR                  Dest;
   1259   IP4_ADDR                  Netmask;
   1260   IP4_ADDR                  Nexthop;
   1261   EFI_STATUS                Status;
   1262   EFI_TPL                   OldTpl;
   1263 
   1264   //
   1265   // First, validate the parameters
   1266   //
   1267   if ((This == NULL) || (SubnetAddress == NULL) ||
   1268       (SubnetMask == NULL) || (GatewayAddress == NULL)) {
   1269     return EFI_INVALID_PARAMETER;
   1270   }
   1271 
   1272   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   1273   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
   1274 
   1275   if (IpInstance->State != IP4_STATE_CONFIGED) {
   1276     Status = EFI_NOT_STARTED;
   1277     goto ON_EXIT;
   1278   }
   1279 
   1280   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
   1281     Status = EFI_NO_MAPPING;
   1282     goto ON_EXIT;
   1283   }
   1284 
   1285   CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));
   1286   CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));
   1287   CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));
   1288 
   1289   Dest    = NTOHL (Dest);
   1290   Netmask = NTOHL (Netmask);
   1291   Nexthop = NTOHL (Nexthop);
   1292 
   1293   IpIf    = IpInstance->Interface;
   1294 
   1295   if (!IP4_IS_VALID_NETMASK (Netmask)) {
   1296     Status = EFI_INVALID_PARAMETER;
   1297     goto ON_EXIT;
   1298   }
   1299 
   1300   //
   1301   // the gateway address must be a unicast on the connected network if not zero.
   1302   //
   1303   if ((Nexthop != IP4_ALLZERO_ADDRESS) &&
   1304       (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||
   1305         IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {
   1306 
   1307     Status = EFI_INVALID_PARAMETER;
   1308     goto ON_EXIT;
   1309   }
   1310 
   1311   if (DeleteRoute) {
   1312     Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
   1313   } else {
   1314     Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
   1315   }
   1316 
   1317 ON_EXIT:
   1318   gBS->RestoreTPL (OldTpl);
   1319   return Status;
   1320 }
   1321 
   1322 
   1323 /**
   1324   Check whether the user's token or event has already
   1325   been enqueued on IP4's list.
   1326 
   1327   @param[in]  Map                    The container of either user's transmit or receive
   1328                                      token.
   1329   @param[in]  Item                   Current item to check against.
   1330   @param[in]  Context                The Token to check againist.
   1331 
   1332   @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP.
   1333   @retval EFI_SUCCESS            The current item isn't the same token/event as the
   1334                                  context.
   1335 
   1336 **/
   1337 EFI_STATUS
   1338 EFIAPI
   1339 Ip4TokenExist (
   1340   IN NET_MAP                *Map,
   1341   IN NET_MAP_ITEM           *Item,
   1342   IN VOID                   *Context
   1343   )
   1344 {
   1345   EFI_IP4_COMPLETION_TOKEN  *Token;
   1346   EFI_IP4_COMPLETION_TOKEN  *TokenInItem;
   1347 
   1348   Token       = (EFI_IP4_COMPLETION_TOKEN *) Context;
   1349   TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;
   1350 
   1351   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
   1352     return EFI_ACCESS_DENIED;
   1353   }
   1354 
   1355   return EFI_SUCCESS;
   1356 }
   1357 
   1358 /**
   1359   Validate the user's token against current station address.
   1360 
   1361   @param[in]  Token              User's token to validate.
   1362   @param[in]  IpIf               The IP4 child's interface.
   1363   @param[in]  RawData            Set to TRUE to send unformatted packets.
   1364 
   1365   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
   1366   @retval EFI_BAD_BUFFER_SIZE    The user's option/data is too long.
   1367   @retval EFI_SUCCESS            The token is valid.
   1368 
   1369 **/
   1370 EFI_STATUS
   1371 Ip4TxTokenValid (
   1372   IN EFI_IP4_COMPLETION_TOKEN   *Token,
   1373   IN IP4_INTERFACE              *IpIf,
   1374   IN BOOLEAN                    RawData
   1375   )
   1376 {
   1377   EFI_IP4_TRANSMIT_DATA     *TxData;
   1378   EFI_IP4_OVERRIDE_DATA     *Override;
   1379   IP4_ADDR                  Src;
   1380   IP4_ADDR                  Gateway;
   1381   UINT32                    Offset;
   1382   UINT32                    Index;
   1383   UINT32                    HeadLen;
   1384 
   1385   if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {
   1386     return EFI_INVALID_PARAMETER;
   1387   }
   1388 
   1389   TxData = Token->Packet.TxData;
   1390 
   1391   //
   1392   // Check the fragment table: no empty fragment, and length isn't bogus.
   1393   //
   1394   if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {
   1395     return EFI_INVALID_PARAMETER;
   1396   }
   1397 
   1398   Offset = TxData->TotalDataLength;
   1399 
   1400   if (Offset > IP4_MAX_PACKET_SIZE) {
   1401     return EFI_BAD_BUFFER_SIZE;
   1402   }
   1403 
   1404   for (Index = 0; Index < TxData->FragmentCount; Index++) {
   1405     if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
   1406         (TxData->FragmentTable[Index].FragmentLength == 0)) {
   1407 
   1408       return EFI_INVALID_PARAMETER;
   1409     }
   1410 
   1411     Offset -= TxData->FragmentTable[Index].FragmentLength;
   1412   }
   1413 
   1414   if (Offset != 0) {
   1415     return EFI_INVALID_PARAMETER;
   1416   }
   1417 
   1418   //
   1419   // NOTE that OptionsLength/OptionsBuffer/OverrideData are ignored if RawData
   1420   // is TRUE.
   1421   //
   1422   if (RawData) {
   1423     return EFI_SUCCESS;
   1424   }
   1425 
   1426   //
   1427   // Check the IP options: no more than 40 bytes and format is OK
   1428   //
   1429   if (TxData->OptionsLength != 0) {
   1430     if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {
   1431       return EFI_INVALID_PARAMETER;
   1432     }
   1433 
   1434     if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {
   1435       return EFI_INVALID_PARAMETER;
   1436     }
   1437   }
   1438 
   1439   //
   1440   // Check the source and gateway: they must be a valid unicast.
   1441   // Gateway must also be on the connected network.
   1442   //
   1443   if (TxData->OverrideData != NULL) {
   1444     Override = TxData->OverrideData;
   1445 
   1446     CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));
   1447     CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));
   1448 
   1449     Src     = NTOHL (Src);
   1450     Gateway = NTOHL (Gateway);
   1451 
   1452     if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||
   1453         (Src == IP4_ALLONE_ADDRESS) ||
   1454         IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
   1455 
   1456       return EFI_INVALID_PARAMETER;
   1457     }
   1458 
   1459     //
   1460     // If gateway isn't zero, it must be a unicast address, and
   1461     // on the connected network.
   1462     //
   1463     if ((Gateway != IP4_ALLZERO_ADDRESS) &&
   1464         ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||
   1465          !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||
   1466          IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {
   1467 
   1468       return EFI_INVALID_PARAMETER;
   1469     }
   1470   }
   1471 
   1472   //
   1473   // Check the packet length: Head length and packet length all has a limit
   1474   //
   1475   HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);
   1476 
   1477   if ((HeadLen > IP4_MAX_HEADLEN) ||
   1478       (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {
   1479 
   1480     return EFI_BAD_BUFFER_SIZE;
   1481   }
   1482 
   1483   return EFI_SUCCESS;
   1484 }
   1485 
   1486 
   1487 /**
   1488   The callback function for the net buffer which wraps the user's
   1489   transmit token. Although it seems this function is pretty simple,
   1490   there are some subtle things.
   1491   When user requests the IP to transmit a packet by passing it a
   1492   token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data
   1493   is wrapped in an net buffer. the net buffer's Free function is
   1494   set to Ip4FreeTxToken. The Token and token wrap are added to the
   1495   IP child's TxToken map. Then the buffer is passed to Ip4Output for
   1496   transmission. If something error happened before that, the buffer
   1497   is freed, which in turn will free the token wrap. The wrap may
   1498   have been added to the TxToken map or not, and the user's event
   1499   shouldn't be fired because we are still in the EfiIp4Transmit. If
   1500   the buffer has been sent by Ip4Output, it should be removed from
   1501   the TxToken map and user's event signaled. The token wrap and buffer
   1502   are bound together. Check the comments in Ip4Output for information
   1503   about IP fragmentation.
   1504 
   1505   @param[in]  Context                The token's wrap.
   1506 
   1507 **/
   1508 VOID
   1509 EFIAPI
   1510 Ip4FreeTxToken (
   1511   IN VOID                   *Context
   1512   )
   1513 {
   1514   IP4_TXTOKEN_WRAP          *Wrap;
   1515   NET_MAP_ITEM              *Item;
   1516 
   1517   Wrap = (IP4_TXTOKEN_WRAP *) Context;
   1518 
   1519   //
   1520   // Signal IpSecRecycleEvent to inform IPsec free the memory
   1521   //
   1522   if (Wrap->IpSecRecycleSignal != NULL) {
   1523     gBS->SignalEvent (Wrap->IpSecRecycleSignal);
   1524   }
   1525 
   1526   //
   1527   // Find the token in the instance's map. EfiIp4Transmit put the
   1528   // token to the map. If that failed, NetMapFindKey will return NULL.
   1529   //
   1530   Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
   1531 
   1532   if (Item != NULL) {
   1533     NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
   1534   }
   1535 
   1536   if (Wrap->Sent) {
   1537     gBS->SignalEvent (Wrap->Token->Event);
   1538 
   1539     //
   1540     // Dispatch the DPC queued by the NotifyFunction of Token->Event.
   1541     //
   1542     DispatchDpc ();
   1543   }
   1544 
   1545   FreePool (Wrap);
   1546 }
   1547 
   1548 
   1549 /**
   1550   The callback function to Ip4Output to update the transmit status.
   1551 
   1552   @param  Ip4Instance            The Ip4Instance that request the transmit.
   1553   @param  Packet                 The user's transmit request.
   1554   @param  IoStatus               The result of the transmission.
   1555   @param  Flag                   Not used during transmission.
   1556   @param  Context                The token's wrap.
   1557 
   1558 **/
   1559 VOID
   1560 Ip4OnPacketSent (
   1561   IP4_PROTOCOL              *Ip4Instance,
   1562   NET_BUF                   *Packet,
   1563   EFI_STATUS                IoStatus,
   1564   UINT32                    Flag,
   1565   VOID                      *Context
   1566   )
   1567 {
   1568   IP4_TXTOKEN_WRAP          *Wrap;
   1569 
   1570   //
   1571   // This is the transmission request from upper layer,
   1572   // not the IP4 driver itself.
   1573   //
   1574   ASSERT (Ip4Instance != NULL);
   1575 
   1576   //
   1577   // The first fragment of the packet has been sent. Update
   1578   // the token's status. That is, if fragmented, the transmit's
   1579   // status is the first fragment's status. The Wrap will be
   1580   // release when all the fragments are release. Check the comments
   1581   // in Ip4FreeTxToken and Ip4Output for information.
   1582   //
   1583   Wrap                = (IP4_TXTOKEN_WRAP *) Context;
   1584   Wrap->Token->Status = IoStatus;
   1585 
   1586   NetbufFree (Wrap->Packet);
   1587 }
   1588 
   1589 
   1590 /**
   1591   Places outgoing data packets into the transmit queue.
   1592 
   1593   The Transmit() function places a sending request in the transmit queue of this
   1594   EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
   1595   errors occur, the event in the token will be signaled and the status is updated.
   1596 
   1597   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
   1598   @param[in]  Token Pointer to the transmit token.
   1599 
   1600   @retval  EFI_SUCCESS           The data has been queued for transmission.
   1601   @retval  EFI_NOT_STARTED       This instance has not been started.
   1602   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
   1603                                  RARP, etc.) is not finished yet.
   1604   @retval  EFI_INVALID_PARAMETER One or more pameters are invalid.
   1605   @retval  EFI_ACCESS_DENIED     The transmit completion token with the same Token.Event
   1606                                  was already in the transmit queue.
   1607   @retval  EFI_NOT_READY         The completion token could not be queued because the transmit
   1608                                  queue is full.
   1609   @retval  EFI_NOT_FOUND         Not route is found to destination address.
   1610   @retval  EFI_OUT_OF_RESOURCES  Could not queue the transmit data.
   1611   @retval  EFI_BUFFER_TOO_SMALL  Token.Packet.TxData.TotalDataLength is too
   1612                                  short to transmit.
   1613   @retval  EFI_BAD_BUFFER_SIZE   The length of the IPv4 header + option length + total data length is
   1614                                  greater than MTU (or greater than the maximum packet size if
   1615                                  Token.Packet.TxData.OverrideData.
   1616                                  DoNotFragment is TRUE).
   1617 
   1618 **/
   1619 EFI_STATUS
   1620 EFIAPI
   1621 EfiIp4Transmit (
   1622   IN EFI_IP4_PROTOCOL         *This,
   1623   IN EFI_IP4_COMPLETION_TOKEN *Token
   1624   )
   1625 {
   1626   IP4_SERVICE               *IpSb;
   1627   IP4_PROTOCOL              *IpInstance;
   1628   IP4_INTERFACE             *IpIf;
   1629   IP4_TXTOKEN_WRAP          *Wrap;
   1630   EFI_IP4_TRANSMIT_DATA     *TxData;
   1631   EFI_IP4_CONFIG_DATA       *Config;
   1632   EFI_IP4_OVERRIDE_DATA     *Override;
   1633   IP4_HEAD                  Head;
   1634   IP4_ADDR                  GateWay;
   1635   EFI_STATUS                Status;
   1636   EFI_TPL                   OldTpl;
   1637   BOOLEAN                   DontFragment;
   1638   UINT32                    HeadLen;
   1639   UINT8                     RawHdrLen;
   1640   UINT32                    OptionsLength;
   1641   UINT8                     *OptionsBuffer;
   1642   VOID                      *FirstFragment;
   1643 
   1644   if (This == NULL) {
   1645     return EFI_INVALID_PARAMETER;
   1646   }
   1647 
   1648   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   1649 
   1650   if (IpInstance->State != IP4_STATE_CONFIGED) {
   1651     return EFI_NOT_STARTED;
   1652   }
   1653 
   1654   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
   1655 
   1656   IpSb    = IpInstance->Service;
   1657   IpIf    = IpInstance->Interface;
   1658   Config  = &IpInstance->ConfigData;
   1659 
   1660   if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
   1661     Status = EFI_NO_MAPPING;
   1662     goto ON_EXIT;
   1663   }
   1664 
   1665   //
   1666   // make sure that token is properly formated
   1667   //
   1668   Status = Ip4TxTokenValid (Token, IpIf, Config->RawData);
   1669 
   1670   if (EFI_ERROR (Status)) {
   1671     goto ON_EXIT;
   1672   }
   1673 
   1674   //
   1675   // Check whether the token or signal already existed.
   1676   //
   1677   if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {
   1678     Status = EFI_ACCESS_DENIED;
   1679     goto ON_EXIT;
   1680   }
   1681 
   1682   //
   1683   // Build the IP header, need to fill in the Tos, TotalLen, Id,
   1684   // fragment, Ttl, protocol, Src, and Dst.
   1685   //
   1686   TxData = Token->Packet.TxData;
   1687 
   1688   FirstFragment = NULL;
   1689 
   1690   if (Config->RawData) {
   1691     //
   1692     // When RawData is TRUE, first buffer in FragmentTable points to a raw
   1693     // IPv4 fragment including IPv4 header and options.
   1694     //
   1695     FirstFragment = TxData->FragmentTable[0].FragmentBuffer;
   1696     CopyMem (&RawHdrLen, FirstFragment, sizeof (UINT8));
   1697 
   1698     RawHdrLen = (UINT8) (RawHdrLen & 0x0f);
   1699     if (RawHdrLen < 5) {
   1700       Status = EFI_INVALID_PARAMETER;
   1701       goto ON_EXIT;
   1702     }
   1703 
   1704     RawHdrLen = (UINT8) (RawHdrLen << 2);
   1705 
   1706     CopyMem (&Head, FirstFragment, IP4_MIN_HEADLEN);
   1707 
   1708     Ip4NtohHead (&Head);
   1709     HeadLen      = 0;
   1710     DontFragment = IP4_DO_NOT_FRAGMENT (Head.Fragment);
   1711 
   1712     if (!DontFragment) {
   1713       Status = EFI_INVALID_PARAMETER;
   1714       goto ON_EXIT;
   1715     }
   1716 
   1717     GateWay = IP4_ALLZERO_ADDRESS;
   1718 
   1719     //
   1720     // Get IPv4 options from first fragment.
   1721     //
   1722     if (RawHdrLen == IP4_MIN_HEADLEN) {
   1723       OptionsLength = 0;
   1724       OptionsBuffer = NULL;
   1725     } else {
   1726       OptionsLength = RawHdrLen - IP4_MIN_HEADLEN;
   1727       OptionsBuffer = (UINT8 *) FirstFragment + IP4_MIN_HEADLEN;
   1728     }
   1729 
   1730     //
   1731     // Trim off IPv4 header and options from first fragment.
   1732     //
   1733     TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment + RawHdrLen;
   1734     TxData->FragmentTable[0].FragmentLength = TxData->FragmentTable[0].FragmentLength - RawHdrLen;
   1735   } else {
   1736     CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));
   1737     Head.Dst = NTOHL (Head.Dst);
   1738 
   1739     if (TxData->OverrideData != NULL) {
   1740       Override      = TxData->OverrideData;
   1741       Head.Protocol = Override->Protocol;
   1742       Head.Tos      = Override->TypeOfService;
   1743       Head.Ttl      = Override->TimeToLive;
   1744       DontFragment  = Override->DoNotFragment;
   1745 
   1746       CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));
   1747       CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));
   1748 
   1749       Head.Src = NTOHL (Head.Src);
   1750       GateWay  = NTOHL (GateWay);
   1751     } else {
   1752       Head.Src      = IpIf->Ip;
   1753       GateWay       = IP4_ALLZERO_ADDRESS;
   1754       Head.Protocol = Config->DefaultProtocol;
   1755       Head.Tos      = Config->TypeOfService;
   1756       Head.Ttl      = Config->TimeToLive;
   1757       DontFragment  = Config->DoNotFragment;
   1758     }
   1759 
   1760     Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);
   1761     HeadLen       = (TxData->OptionsLength + 3) & (~0x03);
   1762 
   1763     OptionsLength = TxData->OptionsLength;
   1764     OptionsBuffer = (UINT8 *) (TxData->OptionsBuffer);
   1765   }
   1766 
   1767   //
   1768   // If don't fragment and fragment needed, return error
   1769   //
   1770   if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->MaxPacketSize)) {
   1771     Status = EFI_BAD_BUFFER_SIZE;
   1772     goto ON_EXIT;
   1773   }
   1774 
   1775   //
   1776   // OK, it survives all the validation check. Wrap the token in
   1777   // a IP4_TXTOKEN_WRAP and the data in a netbuf
   1778   //
   1779   Status = EFI_OUT_OF_RESOURCES;
   1780   Wrap   = AllocateZeroPool (sizeof (IP4_TXTOKEN_WRAP));
   1781   if (Wrap == NULL) {
   1782     goto ON_EXIT;
   1783   }
   1784 
   1785   Wrap->IpInstance  = IpInstance;
   1786   Wrap->Token       = Token;
   1787   Wrap->Sent        = FALSE;
   1788   Wrap->Life        = IP4_US_TO_SEC (Config->TransmitTimeout);
   1789   Wrap->Packet      = NetbufFromExt (
   1790                         (NET_FRAGMENT *) TxData->FragmentTable,
   1791                         TxData->FragmentCount,
   1792                         IP4_MAX_HEADLEN,
   1793                         0,
   1794                         Ip4FreeTxToken,
   1795                         Wrap
   1796                         );
   1797 
   1798   if (Wrap->Packet == NULL) {
   1799     FreePool (Wrap);
   1800     goto ON_EXIT;
   1801   }
   1802 
   1803   Token->Status = EFI_NOT_READY;
   1804 
   1805   if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {
   1806     //
   1807     // NetbufFree will call Ip4FreeTxToken, which in turn will
   1808     // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been
   1809     // enqueued.
   1810     //
   1811     if (Config->RawData) {
   1812       //
   1813       // Restore pointer of first fragment in RawData mode.
   1814       //
   1815       TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
   1816     }
   1817 
   1818     NetbufFree (Wrap->Packet);
   1819     goto ON_EXIT;
   1820   }
   1821 
   1822   //
   1823   // Mark the packet sent before output it. Mark it not sent again if the
   1824   // returned status is not EFI_SUCCESS;
   1825   //
   1826   Wrap->Sent = TRUE;
   1827 
   1828   Status = Ip4Output (
   1829              IpSb,
   1830              IpInstance,
   1831              Wrap->Packet,
   1832              &Head,
   1833              OptionsBuffer,
   1834              OptionsLength,
   1835              GateWay,
   1836              Ip4OnPacketSent,
   1837              Wrap
   1838              );
   1839 
   1840   if (EFI_ERROR (Status)) {
   1841     Wrap->Sent = FALSE;
   1842 
   1843     if (Config->RawData) {
   1844       //
   1845       // Restore pointer of first fragment in RawData mode.
   1846       //
   1847       TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
   1848     }
   1849 
   1850     NetbufFree (Wrap->Packet);
   1851   }
   1852 
   1853   if (Config->RawData) {
   1854     //
   1855     // Restore pointer of first fragment in RawData mode.
   1856     //
   1857     TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
   1858   }
   1859 
   1860 ON_EXIT:
   1861   gBS->RestoreTPL (OldTpl);
   1862   return Status;
   1863 }
   1864 
   1865 
   1866 /**
   1867   Places a receiving request into the receiving queue.
   1868 
   1869   The Receive() function places a completion token into the receive packet queue.
   1870   This function is always asynchronous.
   1871 
   1872   The Token.Event field in the completion token must be filled in by the caller
   1873   and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
   1874   driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
   1875   is signaled.
   1876 
   1877   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
   1878   @param[in]  Token Pointer to a token that is associated with the receive data descriptor.
   1879 
   1880   @retval EFI_SUCCESS           The receive completion token was cached.
   1881   @retval EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.
   1882   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
   1883                                 is not finished yet.
   1884   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
   1885                                 - This is NULL.
   1886                                 - Token is NULL.
   1887                                 - Token.Event is NULL.
   1888   @retval EFI_OUT_OF_RESOURCES  The receive completion token could not be queued due to a lack of system
   1889                                 resources (usually memory).
   1890   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
   1891                                 The EFI IPv4 Protocol instance has been reset to startup defaults.
   1892                                 EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
   1893                                 in the receive queue.
   1894   @retval EFI_NOT_READY         The receive request could not be queued because the receive queue is full.
   1895   @retval EFI_ICMP_ERROR        An ICMP error packet was received.
   1896 
   1897 **/
   1898 EFI_STATUS
   1899 EFIAPI
   1900 EfiIp4Receive (
   1901   IN EFI_IP4_PROTOCOL         *This,
   1902   IN EFI_IP4_COMPLETION_TOKEN *Token
   1903   )
   1904 {
   1905   IP4_PROTOCOL              *IpInstance;
   1906   EFI_STATUS                Status;
   1907   EFI_TPL                   OldTpl;
   1908 
   1909   //
   1910   // First validate the parameters
   1911   //
   1912   if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
   1913     return EFI_INVALID_PARAMETER;
   1914   }
   1915 
   1916   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   1917 
   1918   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1919 
   1920   if (IpInstance->State != IP4_STATE_CONFIGED) {
   1921     Status = EFI_NOT_STARTED;
   1922     goto ON_EXIT;
   1923   }
   1924 
   1925   //
   1926   // Check whether the toke is already on the receive queue.
   1927   //
   1928   Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);
   1929 
   1930   if (EFI_ERROR (Status)) {
   1931     Status = EFI_ACCESS_DENIED;
   1932     goto ON_EXIT;
   1933   }
   1934 
   1935   //
   1936   // Queue the token then check whether there is pending received packet.
   1937   //
   1938   Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
   1939 
   1940   if (EFI_ERROR (Status)) {
   1941     goto ON_EXIT;
   1942   }
   1943 
   1944   Status = Ip4InstanceDeliverPacket (IpInstance);
   1945 
   1946   //
   1947   // Dispatch the DPC queued by the NotifyFunction of this instane's receive
   1948   // event.
   1949   //
   1950   DispatchDpc ();
   1951 
   1952 ON_EXIT:
   1953   gBS->RestoreTPL (OldTpl);
   1954   return Status;
   1955 }
   1956 
   1957 
   1958 /**
   1959   Cancel the transmitted but not recycled packet. If a matching
   1960   token is found, it will call Ip4CancelPacket to cancel the
   1961   packet. Ip4CancelPacket will cancel all the fragments of the
   1962   packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP
   1963   will be deleted from the Map, and user's event signalled.
   1964   Because Ip4CancelPacket and other functions are all called in
   1965   line, so, after Ip4CancelPacket returns, the Item has been freed.
   1966 
   1967   @param[in]  Map                The IP4 child's transmit queue.
   1968   @param[in]  Item               The current transmitted packet to test.
   1969   @param[in]  Context            The user's token to cancel.
   1970 
   1971   @retval EFI_SUCCESS            Continue to check the next Item.
   1972   @retval EFI_ABORTED            The user's Token (Token != NULL) is cancelled.
   1973 
   1974 **/
   1975 EFI_STATUS
   1976 EFIAPI
   1977 Ip4CancelTxTokens (
   1978   IN NET_MAP                *Map,
   1979   IN NET_MAP_ITEM           *Item,
   1980   IN VOID                   *Context
   1981   )
   1982 {
   1983   EFI_IP4_COMPLETION_TOKEN  *Token;
   1984   IP4_TXTOKEN_WRAP          *Wrap;
   1985 
   1986   Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
   1987 
   1988   //
   1989   // Return EFI_SUCCESS to check the next item in the map if
   1990   // this one doesn't match.
   1991   //
   1992   if ((Token != NULL) && (Token != Item->Key)) {
   1993     return EFI_SUCCESS;
   1994   }
   1995 
   1996   Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
   1997   ASSERT (Wrap != NULL);
   1998 
   1999   //
   2000   // Don't access the Item, Wrap and Token's members after this point.
   2001   // Item and wrap has been freed. And we no longer own the Token.
   2002   //
   2003   Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
   2004 
   2005   //
   2006   // If only one item is to be cancel, return EFI_ABORTED to stop
   2007   // iterating the map any more.
   2008   //
   2009   if (Token != NULL) {
   2010     return EFI_ABORTED;
   2011   }
   2012 
   2013   return EFI_SUCCESS;
   2014 }
   2015 
   2016 
   2017 /**
   2018   Cancel the receive request. This is quiet simple, because
   2019   it is only enqueued in our local receive map.
   2020 
   2021   @param[in]  Map                The IP4 child's receive queue.
   2022   @param[in]  Item               Current receive request to cancel.
   2023   @param[in]  Context            The user's token to cancel.
   2024 
   2025   @retval EFI_SUCCESS            Continue to check the next receive request on the
   2026                                  queue.
   2027   @retval EFI_ABORTED            The user's token (token != NULL) has been
   2028                                  cancelled.
   2029 
   2030 **/
   2031 EFI_STATUS
   2032 EFIAPI
   2033 Ip4CancelRxTokens (
   2034   IN NET_MAP                *Map,
   2035   IN NET_MAP_ITEM           *Item,
   2036   IN VOID                   *Context
   2037   )
   2038 {
   2039   EFI_IP4_COMPLETION_TOKEN  *Token;
   2040   EFI_IP4_COMPLETION_TOKEN  *This;
   2041 
   2042   Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
   2043   This  = Item->Key;
   2044 
   2045   if ((Token != NULL) && (Token != This)) {
   2046     return EFI_SUCCESS;
   2047   }
   2048 
   2049   NetMapRemoveItem (Map, Item, NULL);
   2050 
   2051   This->Status        = EFI_ABORTED;
   2052   This->Packet.RxData = NULL;
   2053   gBS->SignalEvent (This->Event);
   2054 
   2055   if (Token != NULL) {
   2056     return EFI_ABORTED;
   2057   }
   2058 
   2059   return EFI_SUCCESS;
   2060 }
   2061 
   2062 
   2063 /**
   2064   Cancel the user's receive/transmit request.
   2065 
   2066   @param[in]  IpInstance         The IP4 child.
   2067   @param[in]  Token              The token to cancel. If NULL, all token will be
   2068                                  cancelled.
   2069 
   2070   @retval EFI_SUCCESS            The token is cancelled.
   2071   @retval EFI_NOT_FOUND          The token isn't found on either the
   2072                                  transmit/receive queue.
   2073   @retval EFI_DEVICE_ERROR       Not all token is cancelled when Token is NULL.
   2074 
   2075 **/
   2076 EFI_STATUS
   2077 Ip4Cancel (
   2078   IN IP4_PROTOCOL             *IpInstance,
   2079   IN EFI_IP4_COMPLETION_TOKEN *Token          OPTIONAL
   2080   )
   2081 {
   2082   EFI_STATUS                Status;
   2083 
   2084   //
   2085   // First check the transmitted packet. Ip4CancelTxTokens returns
   2086   // EFI_ABORTED to mean that the token has been cancelled when
   2087   // token != NULL. So, return EFI_SUCCESS for this condition.
   2088   //
   2089   Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);
   2090 
   2091   if (EFI_ERROR (Status)) {
   2092     if ((Token != NULL) && (Status == EFI_ABORTED)) {
   2093       return EFI_SUCCESS;
   2094     }
   2095 
   2096     return Status;
   2097   }
   2098 
   2099   //
   2100   // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT
   2101   // for Token!=NULL and it is cancelled.
   2102   //
   2103   Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);
   2104   //
   2105   // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
   2106   // events.
   2107   //
   2108   DispatchDpc ();
   2109   if (EFI_ERROR (Status)) {
   2110     if ((Token != NULL) && (Status == EFI_ABORTED)) {
   2111       return EFI_SUCCESS;
   2112     }
   2113 
   2114     return Status;
   2115   }
   2116 
   2117   //
   2118   // OK, if the Token is found when Token != NULL, the NetMapIterate
   2119   // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
   2120   //
   2121   if (Token != NULL) {
   2122     return EFI_NOT_FOUND;
   2123   }
   2124 
   2125   //
   2126   // If Token == NULL, cancel all the tokens. return error if no
   2127   // all of them are cancelled.
   2128   //
   2129   if (!NetMapIsEmpty (&IpInstance->TxTokens) ||
   2130       !NetMapIsEmpty (&IpInstance->RxTokens)) {
   2131 
   2132     return EFI_DEVICE_ERROR;
   2133   }
   2134 
   2135   return EFI_SUCCESS;
   2136 }
   2137 
   2138 
   2139 /**
   2140   Abort an asynchronous transmit or receive request.
   2141 
   2142   The Cancel() function is used to abort a pending transmit or receive request.
   2143   If the token is in the transmit or receive request queues, after calling this
   2144   function, Token->Status will be set to EFI_ABORTED and then Token->Event will
   2145   be signaled. If the token is not in one of the queues, which usually means the
   2146   asynchronous operation has completed, this function will not signal the token
   2147   and EFI_NOT_FOUND is returned.
   2148 
   2149   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
   2150   @param[in]  Token Pointer to a token that has been issued by
   2151                     EFI_IP4_PROTOCOL.Transmit() or
   2152                     EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
   2153                     tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
   2154                     defined in EFI_IP4_PROTOCOL.Transmit().
   2155 
   2156   @retval EFI_SUCCESS           The asynchronous I/O request was aborted and
   2157                                 Token.->Event was signaled. When Token is NULL, all
   2158                                 pending requests were aborted and their events were signaled.
   2159   @retval EFI_INVALID_PARAMETER This is NULL.
   2160   @retval EFI_NOT_STARTED       This instance has not been started.
   2161   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
   2162                                 RARP, etc.) is not finished yet.
   2163   @retval EFI_NOT_FOUND         When Token is not NULL, the asynchronous I/O request was
   2164                                 not found in the transmit or receive queue. It has either completed
   2165                                 or was not issued by Transmit() and Receive().
   2166 
   2167 **/
   2168 EFI_STATUS
   2169 EFIAPI
   2170 EfiIp4Cancel (
   2171   IN EFI_IP4_PROTOCOL         *This,
   2172   IN EFI_IP4_COMPLETION_TOKEN *Token    OPTIONAL
   2173   )
   2174 {
   2175   IP4_PROTOCOL              *IpInstance;
   2176   EFI_STATUS                Status;
   2177   EFI_TPL                   OldTpl;
   2178 
   2179   if (This == NULL) {
   2180     return EFI_INVALID_PARAMETER;
   2181   }
   2182 
   2183   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   2184 
   2185   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   2186 
   2187   if (IpInstance->State != IP4_STATE_CONFIGED) {
   2188     Status = EFI_NOT_STARTED;
   2189     goto ON_EXIT;
   2190   }
   2191 
   2192   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
   2193     Status = EFI_NO_MAPPING;
   2194     goto ON_EXIT;
   2195   }
   2196 
   2197   Status = Ip4Cancel (IpInstance, Token);
   2198 
   2199 ON_EXIT:
   2200   gBS->RestoreTPL (OldTpl);
   2201   return Status;
   2202 }
   2203 
   2204 
   2205 /**
   2206   Polls for incoming data packets and processes outgoing data packets.
   2207 
   2208   The Poll() function polls for incoming data packets and processes outgoing data
   2209   packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
   2210   function to increase the rate that data packets are moved between the communications
   2211   device and the transmit and receive queues.
   2212 
   2213   In some systems the periodic timer event may not poll the underlying communications
   2214   device fast enough to transmit and/or receive all data packets without missing
   2215   incoming packets or dropping outgoing packets. Drivers and applications that are
   2216   experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
   2217   more often.
   2218 
   2219   @param[in]  This               Pointer to the EFI_IP4_PROTOCOL instance.
   2220 
   2221   @retval  EFI_SUCCESS           Incoming or outgoing data was processed.
   2222   @retval  EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.
   2223   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
   2224                                  RARP, etc.) is not finished yet.
   2225   @retval  EFI_INVALID_PARAMETER This is NULL.
   2226   @retval  EFI_DEVICE_ERROR      An unexpected system or network error occurred.
   2227   @retval  EFI_NOT_READY         No incoming or outgoing data is processed.
   2228   @retval  EFI_TIMEOUT           Data was dropped out of the transmit and/or receive queue.
   2229                                  Consider increasing the polling rate.
   2230 
   2231 **/
   2232 EFI_STATUS
   2233 EFIAPI
   2234 EfiIp4Poll (
   2235   IN EFI_IP4_PROTOCOL       *This
   2236   )
   2237 {
   2238   IP4_PROTOCOL                  *IpInstance;
   2239   EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;
   2240 
   2241   if (This == NULL) {
   2242     return EFI_INVALID_PARAMETER;
   2243   }
   2244 
   2245   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   2246 
   2247   if (IpInstance->State == IP4_STATE_UNCONFIGED) {
   2248     return EFI_NOT_STARTED;
   2249   }
   2250 
   2251   Mnp = IpInstance->Service->Mnp;
   2252 
   2253   //
   2254   // Don't lock the Poll function to enable the deliver of
   2255   // the packet polled up.
   2256   //
   2257   return Mnp->Poll (Mnp);
   2258 }
   2259 
   2260 /**
   2261   Decrease the life of the transmitted packets. If it is
   2262   decreased to zero, cancel the packet. This function is
   2263   called by Ip4PacketTimerTicking which time out both the
   2264   received-but-not-delivered and transmitted-but-not-recycle
   2265   packets.
   2266 
   2267   @param[in]  Map                    The IP4 child's transmit map.
   2268   @param[in]  Item                   Current transmitted packet.
   2269   @param[in]  Context                Not used.
   2270 
   2271   @retval EFI_SUCCESS            Always returns EFI_SUCCESS.
   2272 
   2273 **/
   2274 EFI_STATUS
   2275 EFIAPI
   2276 Ip4SentPacketTicking (
   2277   IN NET_MAP                *Map,
   2278   IN NET_MAP_ITEM           *Item,
   2279   IN VOID                   *Context
   2280   )
   2281 {
   2282   IP4_TXTOKEN_WRAP          *Wrap;
   2283 
   2284   Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
   2285   ASSERT (Wrap != NULL);
   2286 
   2287   if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
   2288     Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
   2289   }
   2290 
   2291   return EFI_SUCCESS;
   2292 }
   2293 
   2294 
   2295 /**
   2296   There are two steps for this the heart beat timer of IP4 service instance.
   2297   First, it times out all of its IP4 children's received-but-not-delivered
   2298   and transmitted-but-not-recycle packets, and provides time input for its
   2299   IGMP protocol.
   2300   Second, a dedicated timer is used to poll underlying media status. In case
   2301   of cable swap, a new round auto configuration will be initiated. The timer
   2302   will signal the IP4 to run DHCP configuration again. IP4 driver will free
   2303   old IP address related resource, such as route table and Interface, then
   2304   initiate a DHCP process to acquire new IP, eventually create route table
   2305   for new IP address.
   2306 
   2307   @param[in]  Event                  The IP4 service instance's heart beat timer.
   2308   @param[in]  Context                The IP4 service instance.
   2309 
   2310 **/
   2311 VOID
   2312 EFIAPI
   2313 Ip4TimerTicking (
   2314   IN EFI_EVENT              Event,
   2315   IN VOID                   *Context
   2316   )
   2317 {
   2318   IP4_SERVICE               *IpSb;
   2319   BOOLEAN                   OldMediaPresent;
   2320   EFI_STATUS                Status;
   2321   EFI_SIMPLE_NETWORK_MODE   SnpModeData;
   2322 
   2323   IpSb = (IP4_SERVICE *) Context;
   2324   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
   2325 
   2326   OldMediaPresent = IpSb->MediaPresent;
   2327 
   2328   Ip4PacketTimerTicking (IpSb);
   2329   Ip4IgmpTicking (IpSb);
   2330 
   2331   //
   2332   // Get fresh mode data from MNP, since underlying media status may change.
   2333   // Here, it needs to mention that the MediaPresent can also be checked even if
   2334   // EFI_NOT_STARTED returned while this MNP child driver instance isn't configured.
   2335   //
   2336   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &SnpModeData);
   2337   if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
   2338     return;
   2339   }
   2340 
   2341   IpSb->MediaPresent = SnpModeData.MediaPresent;
   2342   //
   2343   // Media transimit Unpresent to Present means new link movement is detected.
   2344   //
   2345   if (!OldMediaPresent && IpSb->MediaPresent && (IpSb->Ip4Config2Instance.Policy == Ip4Config2PolicyDhcp)) {
   2346     //
   2347     // Signal the IP4 to run the dhcp configuration again. IP4 driver will free
   2348     // old IP address related resource, such as route table and Interface, then
   2349     // initiate a DHCP round to acquire new IP, eventually
   2350     // create route table for new IP address.
   2351     //
   2352     if (IpSb->ReconfigEvent != NULL) {
   2353       Status = gBS->SignalEvent (IpSb->ReconfigEvent);
   2354       DispatchDpc ();
   2355     }
   2356   }
   2357 }
   2358