Home | History | Annotate | Download | only in Ip4Dxe
      1 /** @file
      2 
      3 Copyright (c) 2005 - 2015, 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   The event handle for IP4 auto reconfiguration. The original default
    568   interface and route table will be removed as the default.
    569 
    570   @param[in]  Context                The IP4 service binding instance.
    571 
    572 **/
    573 VOID
    574 EFIAPI
    575 Ip4AutoReconfigCallBackDpc (
    576   IN VOID                   *Context
    577   )
    578 {
    579   IP4_SERVICE               *IpSb;
    580 
    581   IpSb      = (IP4_SERVICE *) Context;
    582   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
    583 
    584   if (IpSb->State > IP4_SERVICE_UNSTARTED) {
    585     IpSb->State = IP4_SERVICE_UNSTARTED;
    586   }
    587 
    588   IpSb->Reconfig = TRUE;
    589 
    590   Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);
    591 
    592   return ;
    593 }
    594 
    595 
    596 /**
    597   Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK.
    598 
    599   @param Event     The event that is signalled.
    600   @param Context   The IP4 service binding instance.
    601 
    602 **/
    603 VOID
    604 EFIAPI
    605 Ip4AutoReconfigCallBack (
    606   IN EFI_EVENT              Event,
    607   IN VOID                   *Context
    608   )
    609 {
    610   //
    611   // Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK
    612   //
    613   QueueDpc (TPL_CALLBACK, Ip4AutoReconfigCallBackDpc, Context);
    614 }
    615 
    616 
    617 /**
    618   Configure the IP4 child. If the child is already configured,
    619   change the configuration parameter. Otherwise configure it
    620   for the first time. The caller should validate the configuration
    621   before deliver them to it. It also don't do configure NULL.
    622 
    623   @param[in, out]  IpInstance         The IP4 child to configure.
    624   @param[in]       Config             The configure data.
    625 
    626   @retval EFI_SUCCESS            The IP4 child is successfully configured.
    627   @retval EFI_DEVICE_ERROR       Failed to free the pending transive or to
    628                                  configure  underlying MNP or other errors.
    629   @retval EFI_NO_MAPPING         The IP4 child is configured to use default
    630                                  address, but the default address hasn't been
    631                                  configured. The IP4 child doesn't need to be
    632                                  reconfigured when default address is configured.
    633   @retval EFI_OUT_OF_RESOURCES   No more memory space is available.
    634   @retval other                  Other error occurs.
    635 
    636 **/
    637 EFI_STATUS
    638 Ip4ConfigProtocol (
    639   IN OUT IP4_PROTOCOL         *IpInstance,
    640   IN     EFI_IP4_CONFIG_DATA  *Config
    641   )
    642 {
    643   IP4_SERVICE               *IpSb;
    644   IP4_INTERFACE             *IpIf;
    645   EFI_STATUS                Status;
    646   IP4_ADDR                  Ip;
    647   IP4_ADDR                  Netmask;
    648   EFI_ARP_PROTOCOL          *Arp;
    649 
    650   IpSb = IpInstance->Service;
    651 
    652   //
    653   // User is changing packet filters. It must be stopped
    654   // before the station address can be changed.
    655   //
    656   if (IpInstance->State == IP4_STATE_CONFIGED) {
    657     //
    658     // Cancel all the pending transmit/receive from upper layer
    659     //
    660     Status = Ip4Cancel (IpInstance, NULL);
    661 
    662     if (EFI_ERROR (Status)) {
    663       return EFI_DEVICE_ERROR;
    664     }
    665 
    666     CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
    667     return EFI_SUCCESS;
    668   }
    669 
    670   //
    671   // Configure a fresh IP4 protocol instance. Create a route table.
    672   // Each IP child has its own route table, which may point to the
    673   // default table if it is using default address.
    674   //
    675   Status                 = EFI_OUT_OF_RESOURCES;
    676   IpInstance->RouteTable = Ip4CreateRouteTable ();
    677 
    678   if (IpInstance->RouteTable == NULL) {
    679     return Status;
    680   }
    681 
    682   //
    683   // Set up the interface.
    684   //
    685   CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));
    686   CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));
    687 
    688   Ip      = NTOHL (Ip);
    689   Netmask = NTOHL (Netmask);
    690 
    691   if (!Config->UseDefaultAddress) {
    692     //
    693     // Find whether there is already an interface with the same
    694     // station address. All the instances with the same station
    695     // address shares one interface.
    696     //
    697     IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);
    698 
    699     if (IpIf != NULL) {
    700       NET_GET_REF (IpIf);
    701 
    702     } else {
    703       IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
    704 
    705       if (IpIf == NULL) {
    706         goto ON_ERROR;
    707       }
    708 
    709       Status = Ip4SetAddress (IpIf, Ip, Netmask);
    710 
    711       if (EFI_ERROR (Status)) {
    712         Status = EFI_DEVICE_ERROR;
    713         Ip4FreeInterface (IpIf, IpInstance);
    714         goto ON_ERROR;
    715       }
    716 
    717       InsertTailList (&IpSb->Interfaces, &IpIf->Link);
    718     }
    719 
    720     //
    721     // Add a route to this connected network in the route table
    722     //
    723     Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);
    724 
    725   } else {
    726     //
    727     // Use the default address. If the default configuration hasn't
    728     // been started, start it.
    729     //
    730     if (IpSb->State == IP4_SERVICE_UNSTARTED) {
    731       //
    732       // Create the ReconfigEvent to start the new configuration.
    733       //
    734       if (IpSb->ReconfigEvent == NULL) {
    735         Status = gBS->CreateEvent (
    736                         EVT_NOTIFY_SIGNAL,
    737                         TPL_NOTIFY,
    738                         Ip4AutoReconfigCallBack,
    739                         IpSb,
    740                         &IpSb->ReconfigEvent
    741                         );
    742 
    743         if (EFI_ERROR (Status)) {
    744           goto ON_ERROR;
    745         }
    746       }
    747 
    748       Status = Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);
    749 
    750       if (EFI_ERROR (Status)) {
    751         goto CLOSE_RECONFIG_EVENT;
    752       }
    753     }
    754 
    755     IpIf = IpSb->DefaultInterface;
    756     NET_GET_REF (IpSb->DefaultInterface);
    757 
    758     //
    759     // If default address is used, so is the default route table.
    760     // Any route set by the instance has the precedence over the
    761     // routes in the default route table. Link the default table
    762     // after the instance's table. Routing will search the local
    763     // table first.
    764     //
    765     NET_GET_REF (IpSb->DefaultRouteTable);
    766     IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;
    767   }
    768 
    769   IpInstance->Interface = IpIf;
    770   if (IpIf->Arp != NULL) {
    771     Arp = NULL;
    772     Status = gBS->OpenProtocol (
    773                     IpIf->ArpHandle,
    774                     &gEfiArpProtocolGuid,
    775                     (VOID **) &Arp,
    776                     gIp4DriverBinding.DriverBindingHandle,
    777                     IpInstance->Handle,
    778                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    779                     );
    780     if (EFI_ERROR (Status)) {
    781       goto CLOSE_RECONFIG_EVENT;
    782     }
    783   }
    784   InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
    785 
    786   CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
    787   IpInstance->State       = IP4_STATE_CONFIGED;
    788 
    789   //
    790   // Although EFI_NO_MAPPING is an error code, the IP child has been
    791   // successfully configured and doesn't need reconfiguration when
    792   // default address is acquired.
    793   //
    794   if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
    795     return EFI_NO_MAPPING;
    796   }
    797 
    798   return EFI_SUCCESS;
    799 
    800 CLOSE_RECONFIG_EVENT:
    801   if (IpSb->ReconfigEvent != NULL) {
    802     gBS->CloseEvent (IpSb->ReconfigEvent);
    803     IpSb->ReconfigEvent = NULL;
    804   }
    805 
    806 ON_ERROR:
    807   Ip4FreeRouteTable (IpInstance->RouteTable);
    808   IpInstance->RouteTable = NULL;
    809   return Status;
    810 }
    811 
    812 
    813 /**
    814   Clean up the IP4 child, release all the resources used by it.
    815 
    816   @param[in]  IpInstance         The IP4 child to clean up.
    817 
    818   @retval EFI_SUCCESS            The IP4 child is cleaned up.
    819   @retval EFI_DEVICE_ERROR       Some resources failed to be released.
    820 
    821 **/
    822 EFI_STATUS
    823 Ip4CleanProtocol (
    824   IN  IP4_PROTOCOL          *IpInstance
    825   )
    826 {
    827   if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {
    828     return EFI_DEVICE_ERROR;
    829   }
    830 
    831   if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {
    832     return EFI_DEVICE_ERROR;
    833   }
    834 
    835   //
    836   // Some packets haven't been recycled. It is because either the
    837   // user forgets to recycle the packets, or because the callback
    838   // hasn't been called. Just leave it alone.
    839   //
    840   if (!IsListEmpty (&IpInstance->Delivered)) {
    841     ;
    842   }
    843 
    844   if (IpInstance->Interface != NULL) {
    845     RemoveEntryList (&IpInstance->AddrLink);
    846     if (IpInstance->Interface->Arp != NULL) {
    847       gBS->CloseProtocol (
    848              IpInstance->Interface->ArpHandle,
    849              &gEfiArpProtocolGuid,
    850              gIp4DriverBinding.DriverBindingHandle,
    851              IpInstance->Handle
    852              );
    853     }
    854     Ip4FreeInterface (IpInstance->Interface, IpInstance);
    855     IpInstance->Interface = NULL;
    856   }
    857 
    858   if (IpInstance->RouteTable != NULL) {
    859     if (IpInstance->RouteTable->Next != NULL) {
    860       Ip4FreeRouteTable (IpInstance->RouteTable->Next);
    861     }
    862 
    863     Ip4FreeRouteTable (IpInstance->RouteTable);
    864     IpInstance->RouteTable = NULL;
    865   }
    866 
    867   if (IpInstance->EfiRouteTable != NULL) {
    868     FreePool (IpInstance->EfiRouteTable);
    869     IpInstance->EfiRouteTable = NULL;
    870     IpInstance->EfiRouteCount = 0;
    871   }
    872 
    873   if (IpInstance->Groups != NULL) {
    874     FreePool (IpInstance->Groups);
    875     IpInstance->Groups      = NULL;
    876     IpInstance->GroupCount  = 0;
    877   }
    878 
    879   NetMapClean (&IpInstance->TxTokens);
    880 
    881   NetMapClean (&IpInstance->RxTokens);
    882 
    883   return EFI_SUCCESS;
    884 }
    885 
    886 
    887 /**
    888   Validate that Ip/Netmask pair is OK to be used as station
    889   address. Only continuous netmasks are supported. and check
    890   that StationAddress is a unicast address on the newtwork.
    891 
    892   @param[in]  Ip                 The IP address to validate.
    893   @param[in]  Netmask            The netmaks of the IP.
    894 
    895   @retval TRUE                   The Ip/Netmask pair is valid.
    896   @retval FALSE                  The Ip/Netmask pair is invalid.
    897 
    898 **/
    899 BOOLEAN
    900 Ip4StationAddressValid (
    901   IN IP4_ADDR               Ip,
    902   IN IP4_ADDR               Netmask
    903   )
    904 {
    905   IP4_ADDR                  NetBrdcastMask;
    906   INTN                      Len;
    907   INTN                      Type;
    908 
    909   //
    910   // Only support the station address with 0.0.0.0/0 to enable DHCP client.
    911   //
    912   if (Netmask == IP4_ALLZERO_ADDRESS) {
    913     return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);
    914   }
    915 
    916   //
    917   // Only support the continuous net masks
    918   //
    919   if ((Len = NetGetMaskLength (Netmask)) == IP4_MASK_NUM) {
    920     return FALSE;
    921   }
    922 
    923   //
    924   // Station address can't be class D or class E address
    925   //
    926   if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {
    927     return FALSE;
    928   }
    929 
    930   //
    931   // Station address can't be subnet broadcast/net broadcast address
    932   //
    933   if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {
    934     return FALSE;
    935   }
    936 
    937   NetBrdcastMask = gIp4AllMasks[MIN (Len, Type << 3)];
    938 
    939   if (Ip == (Ip | ~NetBrdcastMask)) {
    940     return FALSE;
    941   }
    942 
    943   return TRUE;
    944 }
    945 
    946 
    947 /**
    948   Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
    949 
    950   The Configure() function is used to set, change, or reset the operational
    951   parameters and filter settings for this EFI IPv4 Protocol instance. Until these
    952   parameters have been set, no network traffic can be sent or received by this
    953   instance. Once the parameters have been reset (by calling this function with
    954   IpConfigData set to NULL), no more traffic can be sent or received until these
    955   parameters have been set again. Each EFI IPv4 Protocol instance can be started
    956   and stopped independently of each other by enabling or disabling their receive
    957   filter settings with the Configure() function.
    958 
    959   When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
    960   be appended as an alias address into the addresses list in the EFI IPv4 Protocol
    961   driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
    962   to retrieve the default IPv4 address if it is not available yet. Clients could
    963   frequently call GetModeData() to check the status to ensure that the default IPv4
    964   address is ready.
    965 
    966   If operational parameters are reset or changed, any pending transmit and receive
    967   requests will be cancelled. Their completion token status will be set to EFI_ABORTED
    968   and their events will be signaled.
    969 
    970   @param[in]  This              Pointer to the EFI_IP4_PROTOCOL instance.
    971   @param[in]  IpConfigData      Pointer to the EFI IPv4 Protocol configuration data structure.
    972 
    973   @retval EFI_SUCCESS           The driver instance was successfully opened.
    974   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
    975                                 RARP, etc.) is not finished yet.
    976   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
    977   @retval EFI_UNSUPPORTED       One or more of the following conditions is TRUE:
    978                                 A configuration protocol (DHCP, BOOTP, RARP, etc.) could
    979                                 not be located when clients choose to use the default IPv4
    980                                 address. This EFI IPv4 Protocol implementation does not
    981                                 support this requested filter or timeout setting.
    982   @retval EFI_OUT_OF_RESOURCES  The EFI IPv4 Protocol driver instance data could not be allocated.
    983   @retval EFI_ALREADY_STARTED   The interface is already open and must be stopped before the
    984                                 IPv4 address or subnet mask can be changed. The interface must
    985                                 also be stopped when switching to/from raw packet mode.
    986   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred. The EFI IPv4
    987                                 Protocol driver instance is not opened.
    988 
    989 **/
    990 EFI_STATUS
    991 EFIAPI
    992 EfiIp4Configure (
    993   IN EFI_IP4_PROTOCOL       *This,
    994   IN EFI_IP4_CONFIG_DATA    *IpConfigData       OPTIONAL
    995   )
    996 {
    997   IP4_PROTOCOL              *IpInstance;
    998   EFI_IP4_CONFIG_DATA       *Current;
    999   EFI_TPL                   OldTpl;
   1000   EFI_STATUS                Status;
   1001   BOOLEAN                   AddrOk;
   1002   IP4_ADDR                  IpAddress;
   1003   IP4_ADDR                  SubnetMask;
   1004 
   1005   //
   1006   // First, validate the parameters
   1007   //
   1008   if (This == NULL) {
   1009     return EFI_INVALID_PARAMETER;
   1010   }
   1011 
   1012   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   1013   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
   1014 
   1015   //
   1016   // Validate the configuration first.
   1017   //
   1018   if (IpConfigData != NULL) {
   1019 
   1020     CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));
   1021     CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));
   1022 
   1023     IpAddress  = NTOHL (IpAddress);
   1024     SubnetMask = NTOHL (SubnetMask);
   1025 
   1026     //
   1027     // Check whether the station address is a valid unicast address
   1028     //
   1029     if (!IpConfigData->UseDefaultAddress) {
   1030       AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);
   1031 
   1032       if (!AddrOk) {
   1033         Status = EFI_INVALID_PARAMETER;
   1034         goto ON_EXIT;
   1035       }
   1036     }
   1037 
   1038     //
   1039     // User can only update packet filters when already configured.
   1040     // If it wants to change the station address, it must configure(NULL)
   1041     // the instance first.
   1042     //
   1043     if (IpInstance->State == IP4_STATE_CONFIGED) {
   1044       Current = &IpInstance->ConfigData;
   1045 
   1046       if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {
   1047         Status = EFI_ALREADY_STARTED;
   1048         goto ON_EXIT;
   1049       }
   1050 
   1051       if (!Current->UseDefaultAddress &&
   1052          (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||
   1053           !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {
   1054         Status = EFI_ALREADY_STARTED;
   1055         goto ON_EXIT;
   1056       }
   1057 
   1058       if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
   1059         Status = EFI_NO_MAPPING;
   1060         goto ON_EXIT;
   1061       }
   1062     }
   1063   }
   1064 
   1065   //
   1066   // Configure the instance or clean it up.
   1067   //
   1068   if (IpConfigData != NULL) {
   1069     Status = Ip4ConfigProtocol (IpInstance, IpConfigData);
   1070   } else {
   1071     Status = Ip4CleanProtocol (IpInstance);
   1072 
   1073     //
   1074     // Don't change the state if it is DESTROY, consider the following
   1075     // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
   1076     // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
   1077     // the unload fails miserably.
   1078     //
   1079     if (IpInstance->State == IP4_STATE_CONFIGED) {
   1080       IpInstance->State = IP4_STATE_UNCONFIGED;
   1081     }
   1082   }
   1083 
   1084   //
   1085   // Update the MNP's configure data. Ip4ServiceConfigMnp will check
   1086   // whether it is necessary to reconfigure the MNP.
   1087   //
   1088   Ip4ServiceConfigMnp (IpInstance->Service, FALSE);
   1089 
   1090 ON_EXIT:
   1091   gBS->RestoreTPL (OldTpl);
   1092   return Status;
   1093 
   1094 }
   1095 
   1096 
   1097 /**
   1098   Change the IP4 child's multicast setting. The caller
   1099   should make sure that the parameters is valid.
   1100 
   1101   @param[in]  IpInstance             The IP4 child to change the setting.
   1102   @param[in]  JoinFlag               TRUE to join the group, otherwise leave it.
   1103   @param[in]  GroupAddress           The target group address.
   1104 
   1105   @retval EFI_ALREADY_STARTED    Want to join the group, but already a member of it.
   1106   @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.
   1107   @retval EFI_DEVICE_ERROR       Failed to set the group configuraton.
   1108   @retval EFI_SUCCESS            Successfully updated the group setting.
   1109   @retval EFI_NOT_FOUND          Try to leave the group which it isn't a member.
   1110 
   1111 **/
   1112 EFI_STATUS
   1113 Ip4Groups (
   1114   IN IP4_PROTOCOL           *IpInstance,
   1115   IN BOOLEAN                JoinFlag,
   1116   IN EFI_IPv4_ADDRESS       *GroupAddress       OPTIONAL
   1117   )
   1118 {
   1119   IP4_ADDR                  *Members;
   1120   IP4_ADDR                  Group;
   1121   UINT32                    Index;
   1122 
   1123   //
   1124   // Add it to the instance's Groups, and join the group by IGMP.
   1125   // IpInstance->Groups is in network byte order. IGMP operates in
   1126   // host byte order
   1127   //
   1128   if (JoinFlag) {
   1129     //
   1130     // When JoinFlag is TRUE, GroupAddress shouldn't be NULL.
   1131     //
   1132     ASSERT (GroupAddress != NULL);
   1133     CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));
   1134 
   1135     for (Index = 0; Index < IpInstance->GroupCount; Index++) {
   1136       if (IpInstance->Groups[Index] == Group) {
   1137         return EFI_ALREADY_STARTED;
   1138       }
   1139     }
   1140 
   1141     Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);
   1142 
   1143     if (Members == NULL) {
   1144       return EFI_OUT_OF_RESOURCES;
   1145     }
   1146 
   1147     if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {
   1148       FreePool (Members);
   1149       return EFI_DEVICE_ERROR;
   1150     }
   1151 
   1152     if (IpInstance->Groups != NULL) {
   1153       FreePool (IpInstance->Groups);
   1154     }
   1155 
   1156     IpInstance->Groups = Members;
   1157     IpInstance->GroupCount++;
   1158 
   1159     return EFI_SUCCESS;
   1160   }
   1161 
   1162   //
   1163   // Leave the group. Leave all the groups if GroupAddress is NULL.
   1164   // Must iterate from the end to the beginning because the GroupCount
   1165   // is decreamented each time an address is removed..
   1166   //
   1167   for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {
   1168     Group = IpInstance->Groups[Index - 1];
   1169 
   1170     if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {
   1171       if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {
   1172         return EFI_DEVICE_ERROR;
   1173       }
   1174 
   1175       Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);
   1176       IpInstance->GroupCount--;
   1177 
   1178       if (IpInstance->GroupCount == 0) {
   1179         ASSERT (Index == 1);
   1180 
   1181         FreePool (IpInstance->Groups);
   1182         IpInstance->Groups = NULL;
   1183       }
   1184 
   1185       if (GroupAddress != NULL) {
   1186         return EFI_SUCCESS;
   1187       }
   1188     }
   1189   }
   1190 
   1191   return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);
   1192 }
   1193 
   1194 
   1195 /**
   1196   Joins and leaves multicast groups.
   1197 
   1198   The Groups() function is used to join and leave multicast group sessions. Joining
   1199   a group will enable reception of matching multicast packets. Leaving a group will
   1200   disable the multicast packet reception.
   1201 
   1202   If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
   1203 
   1204   @param[in]  This                  Pointer to the EFI_IP4_PROTOCOL instance.
   1205   @param[in]  JoinFlag              Set to TRUE to join the multicast group session and FALSE to leave.
   1206   @param[in]  GroupAddress          Pointer to the IPv4 multicast address.
   1207 
   1208   @retval EFI_SUCCESS           The operation completed successfully.
   1209   @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
   1210                                 - This is NULL.
   1211                                 - JoinFlag is TRUE and GroupAddress is NULL.
   1212                                 - GroupAddress is not NULL and *GroupAddress is
   1213                                 not a multicast IPv4 address.
   1214   @retval EFI_NOT_STARTED       This instance has not been started.
   1215   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
   1216                                 RARP, etc.) is not finished yet.
   1217   @retval EFI_OUT_OF_RESOURCES  System resources could not be allocated.
   1218   @retval EFI_UNSUPPORTED       This EFI IPv4 Protocol implementation does not support multicast groups.
   1219   @retval EFI_ALREADY_STARTED   The group address is already in the group table (when
   1220                                 JoinFlag is TRUE).
   1221   @retval EFI_NOT_FOUND         The group address is not in the group table (when JoinFlag is FALSE).
   1222   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
   1223 
   1224 **/
   1225 EFI_STATUS
   1226 EFIAPI
   1227 EfiIp4Groups (
   1228   IN EFI_IP4_PROTOCOL       *This,
   1229   IN BOOLEAN                JoinFlag,
   1230   IN EFI_IPv4_ADDRESS       *GroupAddress     OPTIONAL
   1231   )
   1232 {
   1233   IP4_PROTOCOL              *IpInstance;
   1234   EFI_STATUS                Status;
   1235   EFI_TPL                   OldTpl;
   1236   IP4_ADDR                  McastIp;
   1237 
   1238   if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {
   1239     return EFI_INVALID_PARAMETER;
   1240   }
   1241 
   1242   if (GroupAddress != NULL) {
   1243     CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));
   1244 
   1245     if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {
   1246       return EFI_INVALID_PARAMETER;
   1247     }
   1248   }
   1249 
   1250   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   1251   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
   1252 
   1253   if (IpInstance->State != IP4_STATE_CONFIGED) {
   1254     Status = EFI_NOT_STARTED;
   1255     goto ON_EXIT;
   1256   }
   1257 
   1258   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
   1259     Status = EFI_NO_MAPPING;
   1260     goto ON_EXIT;
   1261   }
   1262 
   1263   Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);
   1264 
   1265 ON_EXIT:
   1266   gBS->RestoreTPL (OldTpl);
   1267   return Status;
   1268 }
   1269 
   1270 
   1271 /**
   1272   Adds and deletes routing table entries.
   1273 
   1274   The Routes() function adds a route to or deletes a route from the routing table.
   1275 
   1276   Routes are determined by comparing the SubnetAddress with the destination IPv4
   1277   address arithmetically AND-ed with the SubnetMask. The gateway address must be
   1278   on the same subnet as the configured station address.
   1279 
   1280   The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
   1281   The default route matches all destination IPv4 addresses that do not match any
   1282   other routes.
   1283 
   1284   A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
   1285   IP address if it can be found in the ARP cache or on the local subnet. One automatic
   1286   nonroute entry will be inserted into the routing table for outgoing packets that
   1287   are addressed to a local subnet (gateway address of 0.0.0.0).
   1288 
   1289   Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
   1290   IPv4 Protocol instances that use the default IPv4 address will also have copies
   1291   of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
   1292   copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
   1293   instances. As a result, client modification to the routing table will be lost.
   1294 
   1295   @param[in]  This                   Pointer to the EFI_IP4_PROTOCOL instance.
   1296   @param[in]  DeleteRoute            Set to TRUE to delete this route from the routing table. Set to
   1297                                      FALSE to add this route to the routing table. SubnetAddress
   1298                                      and SubnetMask are used as the key to each route entry.
   1299   @param[in]  SubnetAddress          The address of the subnet that needs to be routed.
   1300   @param[in]  SubnetMask             The subnet mask of SubnetAddress.
   1301   @param[in]  GatewayAddress         The unicast gateway IPv4 address for this route.
   1302 
   1303   @retval EFI_SUCCESS            The operation completed successfully.
   1304   @retval EFI_NOT_STARTED        The driver instance has not been started.
   1305   @retval EFI_NO_MAPPING         When using the default address, configuration (DHCP, BOOTP,
   1306                                  RARP, etc.) is not finished yet.
   1307   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
   1308                                  - This is NULL.
   1309                                  - SubnetAddress is NULL.
   1310                                  - SubnetMask is NULL.
   1311                                  - GatewayAddress is NULL.
   1312                                  - *SubnetAddress is not a valid subnet address.
   1313                                  - *SubnetMask is not a valid subnet mask.
   1314                                  - *GatewayAddress is not a valid unicast IPv4 address.
   1315   @retval EFI_OUT_OF_RESOURCES   Could not add the entry to the routing table.
   1316   @retval EFI_NOT_FOUND          This route is not in the routing table (when DeleteRoute is TRUE).
   1317   @retval EFI_ACCESS_DENIED      The route is already defined in the routing table (when
   1318                                   DeleteRoute is FALSE).
   1319 
   1320 **/
   1321 EFI_STATUS
   1322 EFIAPI
   1323 EfiIp4Routes (
   1324   IN EFI_IP4_PROTOCOL       *This,
   1325   IN BOOLEAN                DeleteRoute,
   1326   IN EFI_IPv4_ADDRESS       *SubnetAddress,
   1327   IN EFI_IPv4_ADDRESS       *SubnetMask,
   1328   IN EFI_IPv4_ADDRESS       *GatewayAddress
   1329   )
   1330 {
   1331   IP4_PROTOCOL              *IpInstance;
   1332   IP4_INTERFACE             *IpIf;
   1333   IP4_ADDR                  Dest;
   1334   IP4_ADDR                  Netmask;
   1335   IP4_ADDR                  Nexthop;
   1336   EFI_STATUS                Status;
   1337   EFI_TPL                   OldTpl;
   1338 
   1339   //
   1340   // First, validate the parameters
   1341   //
   1342   if ((This == NULL) || (SubnetAddress == NULL) ||
   1343       (SubnetMask == NULL) || (GatewayAddress == NULL)) {
   1344     return EFI_INVALID_PARAMETER;
   1345   }
   1346 
   1347   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   1348   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
   1349 
   1350   if (IpInstance->State != IP4_STATE_CONFIGED) {
   1351     Status = EFI_NOT_STARTED;
   1352     goto ON_EXIT;
   1353   }
   1354 
   1355   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
   1356     Status = EFI_NO_MAPPING;
   1357     goto ON_EXIT;
   1358   }
   1359 
   1360   CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));
   1361   CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));
   1362   CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));
   1363 
   1364   Dest    = NTOHL (Dest);
   1365   Netmask = NTOHL (Netmask);
   1366   Nexthop = NTOHL (Nexthop);
   1367 
   1368   IpIf    = IpInstance->Interface;
   1369 
   1370   if (!IP4_IS_VALID_NETMASK (Netmask)) {
   1371     Status = EFI_INVALID_PARAMETER;
   1372     goto ON_EXIT;
   1373   }
   1374 
   1375   //
   1376   // the gateway address must be a unicast on the connected network if not zero.
   1377   //
   1378   if ((Nexthop != IP4_ALLZERO_ADDRESS) &&
   1379       (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||
   1380         IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {
   1381 
   1382     Status = EFI_INVALID_PARAMETER;
   1383     goto ON_EXIT;
   1384   }
   1385 
   1386   if (DeleteRoute) {
   1387     Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
   1388   } else {
   1389     Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
   1390   }
   1391 
   1392 ON_EXIT:
   1393   gBS->RestoreTPL (OldTpl);
   1394   return Status;
   1395 }
   1396 
   1397 
   1398 /**
   1399   Check whether the user's token or event has already
   1400   been enqueued on IP4's list.
   1401 
   1402   @param[in]  Map                    The container of either user's transmit or receive
   1403                                      token.
   1404   @param[in]  Item                   Current item to check against.
   1405   @param[in]  Context                The Token to check againist.
   1406 
   1407   @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP.
   1408   @retval EFI_SUCCESS            The current item isn't the same token/event as the
   1409                                  context.
   1410 
   1411 **/
   1412 EFI_STATUS
   1413 EFIAPI
   1414 Ip4TokenExist (
   1415   IN NET_MAP                *Map,
   1416   IN NET_MAP_ITEM           *Item,
   1417   IN VOID                   *Context
   1418   )
   1419 {
   1420   EFI_IP4_COMPLETION_TOKEN  *Token;
   1421   EFI_IP4_COMPLETION_TOKEN  *TokenInItem;
   1422 
   1423   Token       = (EFI_IP4_COMPLETION_TOKEN *) Context;
   1424   TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;
   1425 
   1426   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
   1427     return EFI_ACCESS_DENIED;
   1428   }
   1429 
   1430   return EFI_SUCCESS;
   1431 }
   1432 
   1433 /**
   1434   Validate the user's token against current station address.
   1435 
   1436   @param[in]  Token              User's token to validate.
   1437   @param[in]  IpIf               The IP4 child's interface.
   1438   @param[in]  RawData            Set to TRUE to send unformatted packets.
   1439 
   1440   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
   1441   @retval EFI_BAD_BUFFER_SIZE    The user's option/data is too long.
   1442   @retval EFI_SUCCESS            The token is valid.
   1443 
   1444 **/
   1445 EFI_STATUS
   1446 Ip4TxTokenValid (
   1447   IN EFI_IP4_COMPLETION_TOKEN   *Token,
   1448   IN IP4_INTERFACE              *IpIf,
   1449   IN BOOLEAN                    RawData
   1450   )
   1451 {
   1452   EFI_IP4_TRANSMIT_DATA     *TxData;
   1453   EFI_IP4_OVERRIDE_DATA     *Override;
   1454   IP4_ADDR                  Src;
   1455   IP4_ADDR                  Gateway;
   1456   UINT32                    Offset;
   1457   UINT32                    Index;
   1458   UINT32                    HeadLen;
   1459 
   1460   if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {
   1461     return EFI_INVALID_PARAMETER;
   1462   }
   1463 
   1464   TxData = Token->Packet.TxData;
   1465 
   1466   //
   1467   // Check the fragment table: no empty fragment, and length isn't bogus.
   1468   //
   1469   if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {
   1470     return EFI_INVALID_PARAMETER;
   1471   }
   1472 
   1473   Offset = TxData->TotalDataLength;
   1474 
   1475   if (Offset > IP4_MAX_PACKET_SIZE) {
   1476     return EFI_BAD_BUFFER_SIZE;
   1477   }
   1478 
   1479   for (Index = 0; Index < TxData->FragmentCount; Index++) {
   1480     if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
   1481         (TxData->FragmentTable[Index].FragmentLength == 0)) {
   1482 
   1483       return EFI_INVALID_PARAMETER;
   1484     }
   1485 
   1486     Offset -= TxData->FragmentTable[Index].FragmentLength;
   1487   }
   1488 
   1489   if (Offset != 0) {
   1490     return EFI_INVALID_PARAMETER;
   1491   }
   1492 
   1493   //
   1494   // NOTE that OptionsLength/OptionsBuffer/OverrideData are ignored if RawData
   1495   // is TRUE.
   1496   //
   1497   if (RawData) {
   1498     return EFI_SUCCESS;
   1499   }
   1500 
   1501   //
   1502   // Check the IP options: no more than 40 bytes and format is OK
   1503   //
   1504   if (TxData->OptionsLength != 0) {
   1505     if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {
   1506       return EFI_INVALID_PARAMETER;
   1507     }
   1508 
   1509     if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {
   1510       return EFI_INVALID_PARAMETER;
   1511     }
   1512   }
   1513 
   1514   //
   1515   // Check the source and gateway: they must be a valid unicast.
   1516   // Gateway must also be on the connected network.
   1517   //
   1518   if (TxData->OverrideData != NULL) {
   1519     Override = TxData->OverrideData;
   1520 
   1521     CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));
   1522     CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));
   1523 
   1524     Src     = NTOHL (Src);
   1525     Gateway = NTOHL (Gateway);
   1526 
   1527     if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||
   1528         (Src == IP4_ALLONE_ADDRESS) ||
   1529         IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
   1530 
   1531       return EFI_INVALID_PARAMETER;
   1532     }
   1533 
   1534     //
   1535     // If gateway isn't zero, it must be a unicast address, and
   1536     // on the connected network.
   1537     //
   1538     if ((Gateway != IP4_ALLZERO_ADDRESS) &&
   1539         ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||
   1540          !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||
   1541          IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {
   1542 
   1543       return EFI_INVALID_PARAMETER;
   1544     }
   1545   }
   1546 
   1547   //
   1548   // Check the packet length: Head length and packet length all has a limit
   1549   //
   1550   HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);
   1551 
   1552   if ((HeadLen > IP4_MAX_HEADLEN) ||
   1553       (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {
   1554 
   1555     return EFI_BAD_BUFFER_SIZE;
   1556   }
   1557 
   1558   return EFI_SUCCESS;
   1559 }
   1560 
   1561 
   1562 /**
   1563   The callback function for the net buffer which wraps the user's
   1564   transmit token. Although it seems this function is pretty simple,
   1565   there are some subtle things.
   1566   When user requests the IP to transmit a packet by passing it a
   1567   token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data
   1568   is wrapped in an net buffer. the net buffer's Free function is
   1569   set to Ip4FreeTxToken. The Token and token wrap are added to the
   1570   IP child's TxToken map. Then the buffer is passed to Ip4Output for
   1571   transmission. If something error happened before that, the buffer
   1572   is freed, which in turn will free the token wrap. The wrap may
   1573   have been added to the TxToken map or not, and the user's event
   1574   shouldn't be fired because we are still in the EfiIp4Transmit. If
   1575   the buffer has been sent by Ip4Output, it should be removed from
   1576   the TxToken map and user's event signaled. The token wrap and buffer
   1577   are bound together. Check the comments in Ip4Output for information
   1578   about IP fragmentation.
   1579 
   1580   @param[in]  Context                The token's wrap.
   1581 
   1582 **/
   1583 VOID
   1584 EFIAPI
   1585 Ip4FreeTxToken (
   1586   IN VOID                   *Context
   1587   )
   1588 {
   1589   IP4_TXTOKEN_WRAP          *Wrap;
   1590   NET_MAP_ITEM              *Item;
   1591 
   1592   Wrap = (IP4_TXTOKEN_WRAP *) Context;
   1593 
   1594   //
   1595   // Signal IpSecRecycleEvent to inform IPsec free the memory
   1596   //
   1597   if (Wrap->IpSecRecycleSignal != NULL) {
   1598     gBS->SignalEvent (Wrap->IpSecRecycleSignal);
   1599   }
   1600 
   1601   //
   1602   // Find the token in the instance's map. EfiIp4Transmit put the
   1603   // token to the map. If that failed, NetMapFindKey will return NULL.
   1604   //
   1605   Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
   1606 
   1607   if (Item != NULL) {
   1608     NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
   1609   }
   1610 
   1611   if (Wrap->Sent) {
   1612     gBS->SignalEvent (Wrap->Token->Event);
   1613 
   1614     //
   1615     // Dispatch the DPC queued by the NotifyFunction of Token->Event.
   1616     //
   1617     DispatchDpc ();
   1618   }
   1619 
   1620   FreePool (Wrap);
   1621 }
   1622 
   1623 
   1624 /**
   1625   The callback function to Ip4Output to update the transmit status.
   1626 
   1627   @param  Ip4Instance            The Ip4Instance that request the transmit.
   1628   @param  Packet                 The user's transmit request.
   1629   @param  IoStatus               The result of the transmission.
   1630   @param  Flag                   Not used during transmission.
   1631   @param  Context                The token's wrap.
   1632 
   1633 **/
   1634 VOID
   1635 Ip4OnPacketSent (
   1636   IP4_PROTOCOL              *Ip4Instance,
   1637   NET_BUF                   *Packet,
   1638   EFI_STATUS                IoStatus,
   1639   UINT32                    Flag,
   1640   VOID                      *Context
   1641   )
   1642 {
   1643   IP4_TXTOKEN_WRAP          *Wrap;
   1644 
   1645   //
   1646   // This is the transmission request from upper layer,
   1647   // not the IP4 driver itself.
   1648   //
   1649   ASSERT (Ip4Instance != NULL);
   1650 
   1651   //
   1652   // The first fragment of the packet has been sent. Update
   1653   // the token's status. That is, if fragmented, the transmit's
   1654   // status is the first fragment's status. The Wrap will be
   1655   // release when all the fragments are release. Check the comments
   1656   // in Ip4FreeTxToken and Ip4Output for information.
   1657   //
   1658   Wrap                = (IP4_TXTOKEN_WRAP *) Context;
   1659   Wrap->Token->Status = IoStatus;
   1660 
   1661   NetbufFree (Wrap->Packet);
   1662 }
   1663 
   1664 
   1665 /**
   1666   Places outgoing data packets into the transmit queue.
   1667 
   1668   The Transmit() function places a sending request in the transmit queue of this
   1669   EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
   1670   errors occur, the event in the token will be signaled and the status is updated.
   1671 
   1672   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
   1673   @param[in]  Token Pointer to the transmit token.
   1674 
   1675   @retval  EFI_SUCCESS           The data has been queued for transmission.
   1676   @retval  EFI_NOT_STARTED       This instance has not been started.
   1677   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
   1678                                  RARP, etc.) is not finished yet.
   1679   @retval  EFI_INVALID_PARAMETER One or more pameters are invalid.
   1680   @retval  EFI_ACCESS_DENIED     The transmit completion token with the same Token.Event
   1681                                  was already in the transmit queue.
   1682   @retval  EFI_NOT_READY         The completion token could not be queued because the transmit
   1683                                  queue is full.
   1684   @retval  EFI_NOT_FOUND         Not route is found to destination address.
   1685   @retval  EFI_OUT_OF_RESOURCES  Could not queue the transmit data.
   1686   @retval  EFI_BUFFER_TOO_SMALL  Token.Packet.TxData.TotalDataLength is too
   1687                                  short to transmit.
   1688   @retval  EFI_BAD_BUFFER_SIZE   The length of the IPv4 header + option length + total data length is
   1689                                  greater than MTU (or greater than the maximum packet size if
   1690                                  Token.Packet.TxData.OverrideData.
   1691                                  DoNotFragment is TRUE).
   1692 
   1693 **/
   1694 EFI_STATUS
   1695 EFIAPI
   1696 EfiIp4Transmit (
   1697   IN EFI_IP4_PROTOCOL         *This,
   1698   IN EFI_IP4_COMPLETION_TOKEN *Token
   1699   )
   1700 {
   1701   IP4_SERVICE               *IpSb;
   1702   IP4_PROTOCOL              *IpInstance;
   1703   IP4_INTERFACE             *IpIf;
   1704   IP4_TXTOKEN_WRAP          *Wrap;
   1705   EFI_IP4_TRANSMIT_DATA     *TxData;
   1706   EFI_IP4_CONFIG_DATA       *Config;
   1707   EFI_IP4_OVERRIDE_DATA     *Override;
   1708   IP4_HEAD                  Head;
   1709   IP4_ADDR                  GateWay;
   1710   EFI_STATUS                Status;
   1711   EFI_TPL                   OldTpl;
   1712   BOOLEAN                   DontFragment;
   1713   UINT32                    HeadLen;
   1714   UINT8                     RawHdrLen;
   1715   UINT32                    OptionsLength;
   1716   UINT8                     *OptionsBuffer;
   1717   VOID                      *FirstFragment;
   1718 
   1719   if (This == NULL) {
   1720     return EFI_INVALID_PARAMETER;
   1721   }
   1722 
   1723   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   1724 
   1725   if (IpInstance->State != IP4_STATE_CONFIGED) {
   1726     return EFI_NOT_STARTED;
   1727   }
   1728 
   1729   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
   1730 
   1731   IpSb    = IpInstance->Service;
   1732   IpIf    = IpInstance->Interface;
   1733   Config  = &IpInstance->ConfigData;
   1734 
   1735   if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
   1736     Status = EFI_NO_MAPPING;
   1737     goto ON_EXIT;
   1738   }
   1739 
   1740   //
   1741   // make sure that token is properly formated
   1742   //
   1743   Status = Ip4TxTokenValid (Token, IpIf, Config->RawData);
   1744 
   1745   if (EFI_ERROR (Status)) {
   1746     goto ON_EXIT;
   1747   }
   1748 
   1749   //
   1750   // Check whether the token or signal already existed.
   1751   //
   1752   if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {
   1753     Status = EFI_ACCESS_DENIED;
   1754     goto ON_EXIT;
   1755   }
   1756 
   1757   //
   1758   // Build the IP header, need to fill in the Tos, TotalLen, Id,
   1759   // fragment, Ttl, protocol, Src, and Dst.
   1760   //
   1761   TxData = Token->Packet.TxData;
   1762 
   1763   FirstFragment = NULL;
   1764 
   1765   if (Config->RawData) {
   1766     //
   1767     // When RawData is TRUE, first buffer in FragmentTable points to a raw
   1768     // IPv4 fragment including IPv4 header and options.
   1769     //
   1770     FirstFragment = TxData->FragmentTable[0].FragmentBuffer;
   1771     CopyMem (&RawHdrLen, FirstFragment, sizeof (UINT8));
   1772 
   1773     RawHdrLen = (UINT8) (RawHdrLen & 0x0f);
   1774     if (RawHdrLen < 5) {
   1775       Status = EFI_INVALID_PARAMETER;
   1776       goto ON_EXIT;
   1777     }
   1778 
   1779     RawHdrLen = (UINT8) (RawHdrLen << 2);
   1780 
   1781     CopyMem (&Head, FirstFragment, IP4_MIN_HEADLEN);
   1782 
   1783     Ip4NtohHead (&Head);
   1784     HeadLen      = 0;
   1785     DontFragment = IP4_DO_NOT_FRAGMENT (Head.Fragment);
   1786 
   1787     if (!DontFragment) {
   1788       Status = EFI_INVALID_PARAMETER;
   1789       goto ON_EXIT;
   1790     }
   1791 
   1792     GateWay = IP4_ALLZERO_ADDRESS;
   1793 
   1794     //
   1795     // Get IPv4 options from first fragment.
   1796     //
   1797     if (RawHdrLen == IP4_MIN_HEADLEN) {
   1798       OptionsLength = 0;
   1799       OptionsBuffer = NULL;
   1800     } else {
   1801       OptionsLength = RawHdrLen - IP4_MIN_HEADLEN;
   1802       OptionsBuffer = (UINT8 *) FirstFragment + IP4_MIN_HEADLEN;
   1803     }
   1804 
   1805     //
   1806     // Trim off IPv4 header and options from first fragment.
   1807     //
   1808     TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment + RawHdrLen;
   1809     TxData->FragmentTable[0].FragmentLength = TxData->FragmentTable[0].FragmentLength - RawHdrLen;
   1810   } else {
   1811     CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));
   1812     Head.Dst = NTOHL (Head.Dst);
   1813 
   1814     if (TxData->OverrideData != NULL) {
   1815       Override      = TxData->OverrideData;
   1816       Head.Protocol = Override->Protocol;
   1817       Head.Tos      = Override->TypeOfService;
   1818       Head.Ttl      = Override->TimeToLive;
   1819       DontFragment  = Override->DoNotFragment;
   1820 
   1821       CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));
   1822       CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));
   1823 
   1824       Head.Src = NTOHL (Head.Src);
   1825       GateWay  = NTOHL (GateWay);
   1826     } else {
   1827       Head.Src      = IpIf->Ip;
   1828       GateWay       = IP4_ALLZERO_ADDRESS;
   1829       Head.Protocol = Config->DefaultProtocol;
   1830       Head.Tos      = Config->TypeOfService;
   1831       Head.Ttl      = Config->TimeToLive;
   1832       DontFragment  = Config->DoNotFragment;
   1833     }
   1834 
   1835     Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);
   1836     HeadLen       = (TxData->OptionsLength + 3) & (~0x03);
   1837 
   1838     OptionsLength = TxData->OptionsLength;
   1839     OptionsBuffer = (UINT8 *) (TxData->OptionsBuffer);
   1840   }
   1841 
   1842   //
   1843   // If don't fragment and fragment needed, return error
   1844   //
   1845   if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->MaxPacketSize)) {
   1846     Status = EFI_BAD_BUFFER_SIZE;
   1847     goto ON_EXIT;
   1848   }
   1849 
   1850   //
   1851   // OK, it survives all the validation check. Wrap the token in
   1852   // a IP4_TXTOKEN_WRAP and the data in a netbuf
   1853   //
   1854   Status = EFI_OUT_OF_RESOURCES;
   1855   Wrap   = AllocateZeroPool (sizeof (IP4_TXTOKEN_WRAP));
   1856   if (Wrap == NULL) {
   1857     goto ON_EXIT;
   1858   }
   1859 
   1860   Wrap->IpInstance  = IpInstance;
   1861   Wrap->Token       = Token;
   1862   Wrap->Sent        = FALSE;
   1863   Wrap->Life        = IP4_US_TO_SEC (Config->TransmitTimeout);
   1864   Wrap->Packet      = NetbufFromExt (
   1865                         (NET_FRAGMENT *) TxData->FragmentTable,
   1866                         TxData->FragmentCount,
   1867                         IP4_MAX_HEADLEN,
   1868                         0,
   1869                         Ip4FreeTxToken,
   1870                         Wrap
   1871                         );
   1872 
   1873   if (Wrap->Packet == NULL) {
   1874     FreePool (Wrap);
   1875     goto ON_EXIT;
   1876   }
   1877 
   1878   Token->Status = EFI_NOT_READY;
   1879 
   1880   if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {
   1881     //
   1882     // NetbufFree will call Ip4FreeTxToken, which in turn will
   1883     // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been
   1884     // enqueued.
   1885     //
   1886     if (Config->RawData) {
   1887       //
   1888       // Restore pointer of first fragment in RawData mode.
   1889       //
   1890       TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
   1891     }
   1892 
   1893     NetbufFree (Wrap->Packet);
   1894     goto ON_EXIT;
   1895   }
   1896 
   1897   //
   1898   // Mark the packet sent before output it. Mark it not sent again if the
   1899   // returned status is not EFI_SUCCESS;
   1900   //
   1901   Wrap->Sent = TRUE;
   1902 
   1903   Status = Ip4Output (
   1904              IpSb,
   1905              IpInstance,
   1906              Wrap->Packet,
   1907              &Head,
   1908              OptionsBuffer,
   1909              OptionsLength,
   1910              GateWay,
   1911              Ip4OnPacketSent,
   1912              Wrap
   1913              );
   1914 
   1915   if (EFI_ERROR (Status)) {
   1916     Wrap->Sent = FALSE;
   1917 
   1918     if (Config->RawData) {
   1919       //
   1920       // Restore pointer of first fragment in RawData mode.
   1921       //
   1922       TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
   1923     }
   1924 
   1925     NetbufFree (Wrap->Packet);
   1926   }
   1927 
   1928   if (Config->RawData) {
   1929     //
   1930     // Restore pointer of first fragment in RawData mode.
   1931     //
   1932     TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
   1933   }
   1934 
   1935 ON_EXIT:
   1936   gBS->RestoreTPL (OldTpl);
   1937   return Status;
   1938 }
   1939 
   1940 
   1941 /**
   1942   Places a receiving request into the receiving queue.
   1943 
   1944   The Receive() function places a completion token into the receive packet queue.
   1945   This function is always asynchronous.
   1946 
   1947   The Token.Event field in the completion token must be filled in by the caller
   1948   and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
   1949   driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
   1950   is signaled.
   1951 
   1952   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
   1953   @param[in]  Token Pointer to a token that is associated with the receive data descriptor.
   1954 
   1955   @retval EFI_SUCCESS           The receive completion token was cached.
   1956   @retval EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.
   1957   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
   1958                                 is not finished yet.
   1959   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
   1960                                 - This is NULL.
   1961                                 - Token is NULL.
   1962                                 - Token.Event is NULL.
   1963   @retval EFI_OUT_OF_RESOURCES  The receive completion token could not be queued due to a lack of system
   1964                                 resources (usually memory).
   1965   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
   1966                                 The EFI IPv4 Protocol instance has been reset to startup defaults.
   1967                                 EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
   1968                                 in the receive queue.
   1969   @retval EFI_NOT_READY         The receive request could not be queued because the receive queue is full.
   1970   @retval EFI_ICMP_ERROR        An ICMP error packet was received.
   1971 
   1972 **/
   1973 EFI_STATUS
   1974 EFIAPI
   1975 EfiIp4Receive (
   1976   IN EFI_IP4_PROTOCOL         *This,
   1977   IN EFI_IP4_COMPLETION_TOKEN *Token
   1978   )
   1979 {
   1980   IP4_PROTOCOL              *IpInstance;
   1981   EFI_STATUS                Status;
   1982   EFI_TPL                   OldTpl;
   1983 
   1984   //
   1985   // First validate the parameters
   1986   //
   1987   if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
   1988     return EFI_INVALID_PARAMETER;
   1989   }
   1990 
   1991   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   1992 
   1993   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1994 
   1995   if (IpInstance->State != IP4_STATE_CONFIGED) {
   1996     Status = EFI_NOT_STARTED;
   1997     goto ON_EXIT;
   1998   }
   1999 
   2000   //
   2001   // Check whether the toke is already on the receive queue.
   2002   //
   2003   Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);
   2004 
   2005   if (EFI_ERROR (Status)) {
   2006     Status = EFI_ACCESS_DENIED;
   2007     goto ON_EXIT;
   2008   }
   2009 
   2010   //
   2011   // Queue the token then check whether there is pending received packet.
   2012   //
   2013   Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
   2014 
   2015   if (EFI_ERROR (Status)) {
   2016     goto ON_EXIT;
   2017   }
   2018 
   2019   Status = Ip4InstanceDeliverPacket (IpInstance);
   2020 
   2021   //
   2022   // Dispatch the DPC queued by the NotifyFunction of this instane's receive
   2023   // event.
   2024   //
   2025   DispatchDpc ();
   2026 
   2027 ON_EXIT:
   2028   gBS->RestoreTPL (OldTpl);
   2029   return Status;
   2030 }
   2031 
   2032 
   2033 /**
   2034   Cancel the transmitted but not recycled packet. If a matching
   2035   token is found, it will call Ip4CancelPacket to cancel the
   2036   packet. Ip4CancelPacket will cancel all the fragments of the
   2037   packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP
   2038   will be deleted from the Map, and user's event signalled.
   2039   Because Ip4CancelPacket and other functions are all called in
   2040   line, so, after Ip4CancelPacket returns, the Item has been freed.
   2041 
   2042   @param[in]  Map                The IP4 child's transmit queue.
   2043   @param[in]  Item               The current transmitted packet to test.
   2044   @param[in]  Context            The user's token to cancel.
   2045 
   2046   @retval EFI_SUCCESS            Continue to check the next Item.
   2047   @retval EFI_ABORTED            The user's Token (Token != NULL) is cancelled.
   2048 
   2049 **/
   2050 EFI_STATUS
   2051 EFIAPI
   2052 Ip4CancelTxTokens (
   2053   IN NET_MAP                *Map,
   2054   IN NET_MAP_ITEM           *Item,
   2055   IN VOID                   *Context
   2056   )
   2057 {
   2058   EFI_IP4_COMPLETION_TOKEN  *Token;
   2059   IP4_TXTOKEN_WRAP          *Wrap;
   2060 
   2061   Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
   2062 
   2063   //
   2064   // Return EFI_SUCCESS to check the next item in the map if
   2065   // this one doesn't match.
   2066   //
   2067   if ((Token != NULL) && (Token != Item->Key)) {
   2068     return EFI_SUCCESS;
   2069   }
   2070 
   2071   Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
   2072   ASSERT (Wrap != NULL);
   2073 
   2074   //
   2075   // Don't access the Item, Wrap and Token's members after this point.
   2076   // Item and wrap has been freed. And we no longer own the Token.
   2077   //
   2078   Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
   2079 
   2080   //
   2081   // If only one item is to be cancel, return EFI_ABORTED to stop
   2082   // iterating the map any more.
   2083   //
   2084   if (Token != NULL) {
   2085     return EFI_ABORTED;
   2086   }
   2087 
   2088   return EFI_SUCCESS;
   2089 }
   2090 
   2091 
   2092 /**
   2093   Cancel the receive request. This is quiet simple, because
   2094   it is only enqueued in our local receive map.
   2095 
   2096   @param[in]  Map                The IP4 child's receive queue.
   2097   @param[in]  Item               Current receive request to cancel.
   2098   @param[in]  Context            The user's token to cancel.
   2099 
   2100   @retval EFI_SUCCESS            Continue to check the next receive request on the
   2101                                  queue.
   2102   @retval EFI_ABORTED            The user's token (token != NULL) has been
   2103                                  cancelled.
   2104 
   2105 **/
   2106 EFI_STATUS
   2107 EFIAPI
   2108 Ip4CancelRxTokens (
   2109   IN NET_MAP                *Map,
   2110   IN NET_MAP_ITEM           *Item,
   2111   IN VOID                   *Context
   2112   )
   2113 {
   2114   EFI_IP4_COMPLETION_TOKEN  *Token;
   2115   EFI_IP4_COMPLETION_TOKEN  *This;
   2116 
   2117   Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
   2118   This  = Item->Key;
   2119 
   2120   if ((Token != NULL) && (Token != This)) {
   2121     return EFI_SUCCESS;
   2122   }
   2123 
   2124   NetMapRemoveItem (Map, Item, NULL);
   2125 
   2126   This->Status        = EFI_ABORTED;
   2127   This->Packet.RxData = NULL;
   2128   gBS->SignalEvent (This->Event);
   2129 
   2130   if (Token != NULL) {
   2131     return EFI_ABORTED;
   2132   }
   2133 
   2134   return EFI_SUCCESS;
   2135 }
   2136 
   2137 
   2138 /**
   2139   Cancel the user's receive/transmit request.
   2140 
   2141   @param[in]  IpInstance         The IP4 child.
   2142   @param[in]  Token              The token to cancel. If NULL, all token will be
   2143                                  cancelled.
   2144 
   2145   @retval EFI_SUCCESS            The token is cancelled.
   2146   @retval EFI_NOT_FOUND          The token isn't found on either the
   2147                                  transmit/receive queue.
   2148   @retval EFI_DEVICE_ERROR       Not all token is cancelled when Token is NULL.
   2149 
   2150 **/
   2151 EFI_STATUS
   2152 Ip4Cancel (
   2153   IN IP4_PROTOCOL             *IpInstance,
   2154   IN EFI_IP4_COMPLETION_TOKEN *Token          OPTIONAL
   2155   )
   2156 {
   2157   EFI_STATUS                Status;
   2158 
   2159   //
   2160   // First check the transmitted packet. Ip4CancelTxTokens returns
   2161   // EFI_ABORTED to mean that the token has been cancelled when
   2162   // token != NULL. So, return EFI_SUCCESS for this condition.
   2163   //
   2164   Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);
   2165 
   2166   if (EFI_ERROR (Status)) {
   2167     if ((Token != NULL) && (Status == EFI_ABORTED)) {
   2168       return EFI_SUCCESS;
   2169     }
   2170 
   2171     return Status;
   2172   }
   2173 
   2174   //
   2175   // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT
   2176   // for Token!=NULL and it is cancelled.
   2177   //
   2178   Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);
   2179   //
   2180   // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
   2181   // events.
   2182   //
   2183   DispatchDpc ();
   2184   if (EFI_ERROR (Status)) {
   2185     if ((Token != NULL) && (Status == EFI_ABORTED)) {
   2186       return EFI_SUCCESS;
   2187     }
   2188 
   2189     return Status;
   2190   }
   2191 
   2192   //
   2193   // OK, if the Token is found when Token != NULL, the NetMapIterate
   2194   // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
   2195   //
   2196   if (Token != NULL) {
   2197     return EFI_NOT_FOUND;
   2198   }
   2199 
   2200   //
   2201   // If Token == NULL, cancel all the tokens. return error if no
   2202   // all of them are cancelled.
   2203   //
   2204   if (!NetMapIsEmpty (&IpInstance->TxTokens) ||
   2205       !NetMapIsEmpty (&IpInstance->RxTokens)) {
   2206 
   2207     return EFI_DEVICE_ERROR;
   2208   }
   2209 
   2210   return EFI_SUCCESS;
   2211 }
   2212 
   2213 
   2214 /**
   2215   Abort an asynchronous transmit or receive request.
   2216 
   2217   The Cancel() function is used to abort a pending transmit or receive request.
   2218   If the token is in the transmit or receive request queues, after calling this
   2219   function, Token->Status will be set to EFI_ABORTED and then Token->Event will
   2220   be signaled. If the token is not in one of the queues, which usually means the
   2221   asynchronous operation has completed, this function will not signal the token
   2222   and EFI_NOT_FOUND is returned.
   2223 
   2224   @param[in]  This  Pointer to the EFI_IP4_PROTOCOL instance.
   2225   @param[in]  Token Pointer to a token that has been issued by
   2226                     EFI_IP4_PROTOCOL.Transmit() or
   2227                     EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
   2228                     tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
   2229                     defined in EFI_IP4_PROTOCOL.Transmit().
   2230 
   2231   @retval EFI_SUCCESS           The asynchronous I/O request was aborted and
   2232                                 Token.->Event was signaled. When Token is NULL, all
   2233                                 pending requests were aborted and their events were signaled.
   2234   @retval EFI_INVALID_PARAMETER This is NULL.
   2235   @retval EFI_NOT_STARTED       This instance has not been started.
   2236   @retval EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
   2237                                 RARP, etc.) is not finished yet.
   2238   @retval EFI_NOT_FOUND         When Token is not NULL, the asynchronous I/O request was
   2239                                 not found in the transmit or receive queue. It has either completed
   2240                                 or was not issued by Transmit() and Receive().
   2241 
   2242 **/
   2243 EFI_STATUS
   2244 EFIAPI
   2245 EfiIp4Cancel (
   2246   IN EFI_IP4_PROTOCOL         *This,
   2247   IN EFI_IP4_COMPLETION_TOKEN *Token    OPTIONAL
   2248   )
   2249 {
   2250   IP4_PROTOCOL              *IpInstance;
   2251   EFI_STATUS                Status;
   2252   EFI_TPL                   OldTpl;
   2253 
   2254   if (This == NULL) {
   2255     return EFI_INVALID_PARAMETER;
   2256   }
   2257 
   2258   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   2259 
   2260   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   2261 
   2262   if (IpInstance->State != IP4_STATE_CONFIGED) {
   2263     Status = EFI_NOT_STARTED;
   2264     goto ON_EXIT;
   2265   }
   2266 
   2267   if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
   2268     Status = EFI_NO_MAPPING;
   2269     goto ON_EXIT;
   2270   }
   2271 
   2272   Status = Ip4Cancel (IpInstance, Token);
   2273 
   2274 ON_EXIT:
   2275   gBS->RestoreTPL (OldTpl);
   2276   return Status;
   2277 }
   2278 
   2279 
   2280 /**
   2281   Polls for incoming data packets and processes outgoing data packets.
   2282 
   2283   The Poll() function polls for incoming data packets and processes outgoing data
   2284   packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
   2285   function to increase the rate that data packets are moved between the communications
   2286   device and the transmit and receive queues.
   2287 
   2288   In some systems the periodic timer event may not poll the underlying communications
   2289   device fast enough to transmit and/or receive all data packets without missing
   2290   incoming packets or dropping outgoing packets. Drivers and applications that are
   2291   experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
   2292   more often.
   2293 
   2294   @param[in]  This               Pointer to the EFI_IP4_PROTOCOL instance.
   2295 
   2296   @retval  EFI_SUCCESS           Incoming or outgoing data was processed.
   2297   @retval  EFI_NOT_STARTED       This EFI IPv4 Protocol instance has not been started.
   2298   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
   2299                                  RARP, etc.) is not finished yet.
   2300   @retval  EFI_INVALID_PARAMETER This is NULL.
   2301   @retval  EFI_DEVICE_ERROR      An unexpected system or network error occurred.
   2302   @retval  EFI_NOT_READY         No incoming or outgoing data is processed.
   2303   @retval  EFI_TIMEOUT           Data was dropped out of the transmit and/or receive queue.
   2304                                  Consider increasing the polling rate.
   2305 
   2306 **/
   2307 EFI_STATUS
   2308 EFIAPI
   2309 EfiIp4Poll (
   2310   IN EFI_IP4_PROTOCOL       *This
   2311   )
   2312 {
   2313   IP4_PROTOCOL                  *IpInstance;
   2314   EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;
   2315 
   2316   if (This == NULL) {
   2317     return EFI_INVALID_PARAMETER;
   2318   }
   2319 
   2320   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
   2321 
   2322   if (IpInstance->State == IP4_STATE_UNCONFIGED) {
   2323     return EFI_NOT_STARTED;
   2324   }
   2325 
   2326   Mnp = IpInstance->Service->Mnp;
   2327 
   2328   //
   2329   // Don't lock the Poll function to enable the deliver of
   2330   // the packet polled up.
   2331   //
   2332   return Mnp->Poll (Mnp);
   2333 }
   2334 
   2335 /**
   2336   Decrease the life of the transmitted packets. If it is
   2337   decreased to zero, cancel the packet. This function is
   2338   called by Ip4PacketTimerTicking which time out both the
   2339   received-but-not-delivered and transmitted-but-not-recycle
   2340   packets.
   2341 
   2342   @param[in]  Map                    The IP4 child's transmit map.
   2343   @param[in]  Item                   Current transmitted packet.
   2344   @param[in]  Context                Not used.
   2345 
   2346   @retval EFI_SUCCESS            Always returns EFI_SUCCESS.
   2347 
   2348 **/
   2349 EFI_STATUS
   2350 EFIAPI
   2351 Ip4SentPacketTicking (
   2352   IN NET_MAP                *Map,
   2353   IN NET_MAP_ITEM           *Item,
   2354   IN VOID                   *Context
   2355   )
   2356 {
   2357   IP4_TXTOKEN_WRAP          *Wrap;
   2358 
   2359   Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
   2360   ASSERT (Wrap != NULL);
   2361 
   2362   if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
   2363     Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
   2364   }
   2365 
   2366   return EFI_SUCCESS;
   2367 }
   2368 
   2369 
   2370 /**
   2371   There are two steps for this the heart beat timer of IP4 service instance.
   2372   First, it times out all of its IP4 children's received-but-not-delivered
   2373   and transmitted-but-not-recycle packets, and provides time input for its
   2374   IGMP protocol.
   2375   Second, a dedicated timer is used to poll underlying media status. In case
   2376   of cable swap, a new round auto configuration will be initiated. The timer
   2377   will signal the IP4 to run DHCP configuration again. IP4 driver will free
   2378   old IP address related resource, such as route table and Interface, then
   2379   initiate a DHCP process to acquire new IP, eventually create route table
   2380   for new IP address.
   2381 
   2382   @param[in]  Event                  The IP4 service instance's heart beat timer.
   2383   @param[in]  Context                The IP4 service instance.
   2384 
   2385 **/
   2386 VOID
   2387 EFIAPI
   2388 Ip4TimerTicking (
   2389   IN EFI_EVENT              Event,
   2390   IN VOID                   *Context
   2391   )
   2392 {
   2393   IP4_SERVICE               *IpSb;
   2394   BOOLEAN                   OldMediaPresent;
   2395   EFI_STATUS                Status;
   2396   EFI_SIMPLE_NETWORK_MODE   SnpModeData;
   2397 
   2398   IpSb = (IP4_SERVICE *) Context;
   2399   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
   2400 
   2401   OldMediaPresent = IpSb->MediaPresent;
   2402 
   2403   Ip4PacketTimerTicking (IpSb);
   2404   Ip4IgmpTicking (IpSb);
   2405 
   2406   //
   2407   // Get fresh mode data from MNP, since underlying media status may change.
   2408   // Here, it needs to mention that the MediaPresent can also be checked even if
   2409   // EFI_NOT_STARTED returned while this MNP child driver instance isn't configured.
   2410   //
   2411   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &SnpModeData);
   2412   if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
   2413     return;
   2414   }
   2415 
   2416   IpSb->MediaPresent = SnpModeData.MediaPresent;
   2417   //
   2418   // Media transimit Unpresent to Present means new link movement is detected.
   2419   //
   2420   if (!OldMediaPresent && IpSb->MediaPresent) {
   2421     //
   2422     // Signal the IP4 to run the dhcp configuration again. IP4 driver will free
   2423     // old IP address related resource, such as route table and Interface, then
   2424     // initiate a DHCP round to acquire new IP, eventually
   2425     // create route table for new IP address.
   2426     //
   2427     if (IpSb->ReconfigEvent != NULL) {
   2428       Status = gBS->SignalEvent (IpSb->ReconfigEvent);
   2429       DispatchDpc ();
   2430     }
   2431   }
   2432 }
   2433