summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
diff options
context:
space:
mode:
authorFathi Boudra <fathi.boudra@linaro.org>2013-02-05 14:07:53 +0200
committerFathi Boudra <fathi.boudra@linaro.org>2013-03-30 21:30:39 +0200
commit3ecb0687d28957a309ad40f47469ddd2e0ab5836 (patch)
treed586ad3f179b48d21e04932dcc96e7efba1dcab0 /MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
parentbbbc819a23d706083a1ccbfc6e7a3784dc724ffb (diff)
parent0016e32cf6e4fe0dfb0885f3394df70be2f63bb2 (diff)
Imported Debian patch 1:0.1+git10+20130125+212a710-0linaro2debian/1%0.1+git10+20130125+212a710-0linaro2
Diffstat (limited to 'MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c')
-rw-r--r--MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c5090
1 files changed, 2597 insertions, 2493 deletions
diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
index 33c9bc36..74bf7f76 100644
--- a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
+++ b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c
@@ -1,2493 +1,2597 @@
-/** @file
-
-Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution. The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "Ip4Impl.h"
-
-EFI_IPSEC2_PROTOCOL *mIpSec = NULL;
-
-/**
- Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.
-
- The GetModeData() function returns the current operational mode data for this
- driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This
- function is used optionally to retrieve the operational mode data of underlying
- networks or drivers.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[out] Ip4ModeData Pointer to the EFI IPv4 Protocol mode data structure.
- @param[out] MnpConfigData Pointer to the managed network configuration data structure.
- @param[out] SnpModeData Pointer to the simple network mode data structure.
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_INVALID_PARAMETER This is NULL.
- @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4GetModeData (
- IN CONST EFI_IP4_PROTOCOL *This,
- OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL,
- OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
- OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
- );
-
-/**
- Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
-
- The Configure() function is used to set, change, or reset the operational
- parameters and filter settings for this EFI IPv4 Protocol instance. Until these
- parameters have been set, no network traffic can be sent or received by this
- instance. Once the parameters have been reset (by calling this function with
- IpConfigData set to NULL), no more traffic can be sent or received until these
- parameters have been set again. Each EFI IPv4 Protocol instance can be started
- and stopped independently of each other by enabling or disabling their receive
- filter settings with the Configure() function.
-
- When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
- be appended as an alias address into the addresses list in the EFI IPv4 Protocol
- driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
- to retrieve the default IPv4 address if it is not available yet. Clients could
- frequently call GetModeData() to check the status to ensure that the default IPv4
- address is ready.
-
- If operational parameters are reset or changed, any pending transmit and receive
- requests will be cancelled. Their completion token status will be set to EFI_ABORTED
- and their events will be signaled.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] IpConfigData Pointer to the EFI IPv4 Protocol configuration data structure.
-
- @retval EFI_SUCCESS The driver instance was successfully opened.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- @retval EFI_UNSUPPORTED One or more of the following conditions is TRUE:
- A configuration protocol (DHCP, BOOTP, RARP, etc.) could
- not be located when clients choose to use the default IPv4
- address. This EFI IPv4 Protocol implementation does not
- support this requested filter or timeout setting.
- @retval EFI_OUT_OF_RESOURCES The EFI IPv4 Protocol driver instance data could not be allocated.
- @retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the
- IPv4 address or subnet mask can be changed. The interface must
- also be stopped when switching to/from raw packet mode.
- @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv4
- Protocol driver instance is not opened.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Configure (
- IN EFI_IP4_PROTOCOL *This,
- IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL
- );
-
-/**
- Joins and leaves multicast groups.
-
- The Groups() function is used to join and leave multicast group sessions. Joining
- a group will enable reception of matching multicast packets. Leaving a group will
- disable the multicast packet reception.
-
- If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] JoinFlag Set to TRUE to join the multicast group session and FALSE to leave.
- @param[in] GroupAddress Pointer to the IPv4 multicast address.
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
- - This is NULL.
- - JoinFlag is TRUE and GroupAddress is NULL.
- - GroupAddress is not NULL and *GroupAddress is
- not a multicast IPv4 address.
- @retval EFI_NOT_STARTED This instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_OUT_OF_RESOURCES System resources could not be allocated.
- @retval EFI_UNSUPPORTED This EFI IPv4 Protocol implementation does not support multicast groups.
- @retval EFI_ALREADY_STARTED The group address is already in the group table (when
- JoinFlag is TRUE).
- @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE).
- @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Groups (
- IN EFI_IP4_PROTOCOL *This,
- IN BOOLEAN JoinFlag,
- IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
- );
-
-/**
- Adds and deletes routing table entries.
-
- The Routes() function adds a route to or deletes a route from the routing table.
-
- Routes are determined by comparing the SubnetAddress with the destination IPv4
- address arithmetically AND-ed with the SubnetMask. The gateway address must be
- on the same subnet as the configured station address.
-
- The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
- The default route matches all destination IPv4 addresses that do not match any
- other routes.
-
- A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
- IP address if it can be found in the ARP cache or on the local subnet. One automatic
- nonroute entry will be inserted into the routing table for outgoing packets that
- are addressed to a local subnet (gateway address of 0.0.0.0).
-
- Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
- IPv4 Protocol instances that use the default IPv4 address will also have copies
- of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
- copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
- instances. As a result, client modification to the routing table will be lost.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. Set to
- FALSE to add this route to the routing table. SubnetAddress
- and SubnetMask are used as the key to each route entry.
- @param[in] SubnetAddress The address of the subnet that needs to be routed.
- @param[in] SubnetMask The subnet mask of SubnetAddress.
- @param[in] GatewayAddress The unicast gateway IPv4 address for this route.
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_NOT_STARTED The driver instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- - This is NULL.
- - SubnetAddress is NULL.
- - SubnetMask is NULL.
- - GatewayAddress is NULL.
- - *SubnetAddress is not a valid subnet address.
- - *SubnetMask is not a valid subnet mask.
- - *GatewayAddress is not a valid unicast IPv4 address.
- @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
- @retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE).
- @retval EFI_ACCESS_DENIED The route is already defined in the routing table (when
- DeleteRoute is FALSE).
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Routes (
- IN EFI_IP4_PROTOCOL *This,
- IN BOOLEAN DeleteRoute,
- IN EFI_IPv4_ADDRESS *SubnetAddress,
- IN EFI_IPv4_ADDRESS *SubnetMask,
- IN EFI_IPv4_ADDRESS *GatewayAddress
- );
-
-/**
- Places outgoing data packets into the transmit queue.
-
- The Transmit() function places a sending request in the transmit queue of this
- EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
- errors occur, the event in the token will be signaled and the status is updated.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] Token Pointer to the transmit token.
-
- @retval EFI_SUCCESS The data has been queued for transmission.
- @retval EFI_NOT_STARTED This instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_INVALID_PARAMETER One or more pameters are invalid.
- @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.Event
- was already in the transmit queue.
- @retval EFI_NOT_READY The completion token could not be queued because the transmit
- queue is full.
- @retval EFI_NOT_FOUND Not route is found to destination address.
- @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.
- @retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too
- short to transmit.
- @retval EFI_BAD_BUFFER_SIZE The length of the IPv4 header + option length + total data length is
- greater than MTU (or greater than the maximum packet size if
- Token.Packet.TxData.OverrideData.
- DoNotFragment is TRUE.)
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Transmit (
- IN EFI_IP4_PROTOCOL *This,
- IN EFI_IP4_COMPLETION_TOKEN *Token
- );
-
-/**
- Places a receiving request into the receiving queue.
-
- The Receive() function places a completion token into the receive packet queue.
- This function is always asynchronous.
-
- The Token.Event field in the completion token must be filled in by the caller
- and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
- driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
- is signaled.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] Token Pointer to a token that is associated with the receive data descriptor.
-
- @retval EFI_SUCCESS The receive completion token was cached.
- @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
- is not finished yet.
- @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- - This is NULL.
- - Token is NULL.
- - Token.Event is NULL.
- @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system
- resources (usually memory).
- @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
- The EFI IPv4 Protocol instance has been reset to startup defaults.
- EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
- in the receive queue.
- @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full.
- @retval EFI_ICMP_ERROR An ICMP error packet was received.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Receive (
- IN EFI_IP4_PROTOCOL *This,
- IN EFI_IP4_COMPLETION_TOKEN *Token
- );
-
-/**
- Abort an asynchronous transmit or receive request.
-
- The Cancel() function is used to abort a pending transmit or receive request.
- If the token is in the transmit or receive request queues, after calling this
- function, Token->Status will be set to EFI_ABORTED and then Token->Event will
- be signaled. If the token is not in one of the queues, which usually means the
- asynchronous operation has completed, this function will not signal the token
- and EFI_NOT_FOUND is returned.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] Token Pointer to a token that has been issued by
- EFI_IP4_PROTOCOL.Transmit() or
- EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
- tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
- defined in EFI_IP4_PROTOCOL.Transmit().
-
- @retval EFI_SUCCESS The asynchronous I/O request was aborted and
- Token.->Event was signaled. When Token is NULL, all
- pending requests were aborted and their events were signaled.
- @retval EFI_INVALID_PARAMETER This is NULL.
- @retval EFI_NOT_STARTED This instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was
- not found in the transmit or receive queue. It has either completed
- or was not issued by Transmit() and Receive().
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Cancel (
- IN EFI_IP4_PROTOCOL *This,
- IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
- );
-
-/**
- Polls for incoming data packets and processes outgoing data packets.
-
- The Poll() function polls for incoming data packets and processes outgoing data
- packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
- function to increase the rate that data packets are moved between the communications
- device and the transmit and receive queues.
-
- In some systems the periodic timer event may not poll the underlying communications
- device fast enough to transmit and/or receive all data packets without missing
- incoming packets or dropping outgoing packets. Drivers and applications that are
- experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
- more often.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
-
- @retval EFI_SUCCESS Incoming or outgoing data was processed.
- @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_INVALID_PARAMETER This is NULL.
- @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
- @retval EFI_NOT_READY No incoming or outgoing data is processed.
- @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue.
- Consider increasing the polling rate.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Poll (
- IN EFI_IP4_PROTOCOL *This
- );
-
-EFI_IP4_PROTOCOL
-mEfiIp4ProtocolTemplete = {
- EfiIp4GetModeData,
- EfiIp4Configure,
- EfiIp4Groups,
- EfiIp4Routes,
- EfiIp4Transmit,
- EfiIp4Receive,
- EfiIp4Cancel,
- EfiIp4Poll
-};
-
-/**
- Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.
-
- The GetModeData() function returns the current operational mode data for this
- driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This
- function is used optionally to retrieve the operational mode data of underlying
- networks or drivers.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[out] Ip4ModeData Pointer to the EFI IPv4 Protocol mode data structure.
- @param[out] MnpConfigData Pointer to the managed network configuration data structure.
- @param[out] SnpModeData Pointer to the simple network mode data structure.
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_INVALID_PARAMETER This is NULL.
- @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4GetModeData (
- IN CONST EFI_IP4_PROTOCOL *This,
- OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL,
- OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
- OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
- )
-{
- IP4_PROTOCOL *IpInstance;
- IP4_SERVICE *IpSb;
- EFI_IP4_CONFIG_DATA *Config;
- EFI_STATUS Status;
- EFI_TPL OldTpl;
- IP4_ADDR Ip;
-
- if (This == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
- IpSb = IpInstance->Service;
-
- if (Ip4ModeData != NULL) {
- //
- // IsStarted is "whether the EfiIp4Configure has been called".
- // IsConfigured is "whether the station address has been configured"
- //
- Ip4ModeData->IsStarted = (BOOLEAN)(IpInstance->State == IP4_STATE_CONFIGED);
- CopyMem (&Ip4ModeData->ConfigData, &IpInstance->ConfigData, sizeof (Ip4ModeData->ConfigData));
- Ip4ModeData->IsConfigured = FALSE;
-
- Ip4ModeData->GroupCount = IpInstance->GroupCount;
- Ip4ModeData->GroupTable = (EFI_IPv4_ADDRESS *) IpInstance->Groups;
-
- Ip4ModeData->IcmpTypeCount = 23;
- Ip4ModeData->IcmpTypeList = mIp4SupportedIcmp;
-
- Ip4ModeData->RouteTable = NULL;
- Ip4ModeData->RouteCount = 0;
-
- Ip4ModeData->MaxPacketSize = IpSb->MaxPacketSize;
-
- //
- // return the current station address for this IP child. So,
- // the user can get the default address through this. Some
- // application wants to know it station address even it is
- // using the default one, such as a ftp server.
- //
- if (Ip4ModeData->IsStarted) {
- Config = &Ip4ModeData->ConfigData;
-
- Ip = HTONL (IpInstance->Interface->Ip);
- CopyMem (&Config->StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
-
- Ip = HTONL (IpInstance->Interface->SubnetMask);
- CopyMem (&Config->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));
-
- Ip4ModeData->IsConfigured = IpInstance->Interface->Configured;
-
- //
- // Build a EFI route table for user from the internal route table.
- //
- Status = Ip4BuildEfiRouteTable (IpInstance);
-
- if (EFI_ERROR (Status)) {
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
-
- Ip4ModeData->RouteTable = IpInstance->EfiRouteTable;
- Ip4ModeData->RouteCount = IpInstance->EfiRouteCount;
- }
- }
-
- //
- // Get fresh mode data from MNP, since underlying media status may change
- //
- Status = IpSb->Mnp->GetModeData (IpSb->Mnp, MnpConfigData, SnpModeData);
-
- gBS->RestoreTPL (OldTpl);
- return Status;
-}
-
-
-/**
- Config the MNP parameter used by IP. The IP driver use one MNP
- child to transmit/receive frames. By default, it configures MNP
- to receive unicast/multicast/broadcast. And it will enable/disable
- the promiscous receive according to whether there is IP child
- enable that or not. If Force is FALSE, it will iterate through
- all the IP children to check whether the promiscuous receive
- setting has been changed. If it hasn't been changed, it won't
- reconfigure the MNP. If Force is TRUE, the MNP is configured no
- matter whether that is changed or not.
-
- @param[in] IpSb The IP4 service instance that is to be changed.
- @param[in] Force Force the configuration or not.
-
- @retval EFI_SUCCESS The MNP is successfully configured/reconfigured.
- @retval Others Configuration failed.
-
-**/
-EFI_STATUS
-Ip4ServiceConfigMnp (
- IN IP4_SERVICE *IpSb,
- IN BOOLEAN Force
- )
-{
- LIST_ENTRY *Entry;
- LIST_ENTRY *ProtoEntry;
- IP4_INTERFACE *IpIf;
- IP4_PROTOCOL *IpInstance;
- BOOLEAN Reconfig;
- BOOLEAN PromiscReceive;
- EFI_STATUS Status;
-
- Reconfig = FALSE;
- PromiscReceive = FALSE;
-
- if (!Force) {
- //
- // Iterate through the IP children to check whether promiscuous
- // receive setting has been changed. Update the interface's receive
- // filter also.
- //
- NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
-
- IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
- IpIf->PromiscRecv = FALSE;
-
- NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {
- IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP4_PROTOCOL, AddrLink);
-
- if (IpInstance->ConfigData.AcceptPromiscuous) {
- IpIf->PromiscRecv = TRUE;
- PromiscReceive = TRUE;
- }
- }
- }
-
- //
- // If promiscuous receive isn't changed, it isn't necessary to reconfigure.
- //
- if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {
- return EFI_SUCCESS;
- }
-
- Reconfig = TRUE;
- IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;
- }
-
- Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);
-
- //
- // recover the original configuration if failed to set the configure.
- //
- if (EFI_ERROR (Status) && Reconfig) {
- IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;
- }
-
- return Status;
-}
-
-
-/**
- The event handle for IP4 auto configuration. If IP is asked
- to reconfigure the default address. The original default
- interface and route table are removed as the default. If there
- is active IP children using the default address, the interface
- will remain valid until all the children have freed their
- references. If IP is signalled when auto configuration is done,
- it will configure the default interface and default route table
- with the configuration information retrieved by IP4_CONFIGURE.
-
- @param[in] Context The IP4 service binding instance.
-
-**/
-VOID
-EFIAPI
-Ip4AutoConfigCallBackDpc (
- IN VOID *Context
- )
-{
- EFI_IP4_CONFIG_PROTOCOL *Ip4Config;
- EFI_IP4_IPCONFIG_DATA *Data;
- EFI_IP4_ROUTE_TABLE *RouteEntry;
- IP4_SERVICE *IpSb;
- IP4_ROUTE_TABLE *RouteTable;
- IP4_INTERFACE *IpIf;
- EFI_STATUS Status;
- UINTN Len;
- UINT32 Index;
- IP4_ADDR StationAddress;
- IP4_ADDR SubnetMask;
- IP4_ADDR SubnetAddress;
- IP4_ADDR GatewayAddress;
-
- IpSb = (IP4_SERVICE *) Context;
- NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
-
- Ip4Config = IpSb->Ip4Config;
-
- //
- // IP is asked to do the reconfiguration. If the default interface
- // has been configured, release the default interface and route
- // table, then create a new one. If there are some IP children
- // using it, the interface won't be physically freed until all the
- // children have released their reference to it. Also remember to
- // restart the receive on the default address. IP4 driver only receive
- // frames on the default address, and when the default interface is
- // freed, Ip4AcceptFrame won't be informed.
- //
- if (IpSb->ActiveEvent == IpSb->ReconfigEvent) {
-
- if (IpSb->DefaultInterface->Configured) {
- IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
-
- if (IpIf == NULL) {
- return;
- }
-
- RouteTable = Ip4CreateRouteTable ();
-
- if (RouteTable == NULL) {
- Ip4FreeInterface (IpIf, NULL);
- return;
- }
-
- Ip4CancelReceive (IpSb->DefaultInterface);
- Ip4FreeInterface (IpSb->DefaultInterface, NULL);
- Ip4FreeRouteTable (IpSb->DefaultRouteTable);
-
- IpSb->DefaultInterface = IpIf;
- InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
-
- IpSb->DefaultRouteTable = RouteTable;
- Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
- }
-
- Ip4Config->Stop (Ip4Config);
- Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);
- return ;
- }
-
- //
- // Get the configure data in two steps: get the length then the data.
- //
- Len = 0;
-
- if (Ip4Config->GetData (Ip4Config, &Len, NULL) != EFI_BUFFER_TOO_SMALL) {
- return ;
- }
-
- Data = AllocatePool (Len);
-
- if (Data == NULL) {
- return ;
- }
-
- Status = Ip4Config->GetData (Ip4Config, &Len, Data);
-
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
-
- IpIf = IpSb->DefaultInterface;
-
- //
- // If the default address has been configured don't change it.
- // This is unlikely to happen if EFI_IP4_CONFIG protocol has
- // informed us to reconfigure each time it wants to change the
- // configuration parameters.
- //
- if (IpIf->Configured) {
- goto ON_EXIT;
- }
-
- //
- // Set the default interface's address, then add a directed
- // route for it, that is, the route whose nexthop is zero.
- //
- StationAddress = EFI_NTOHL (Data->StationAddress);
- SubnetMask = EFI_NTOHL (Data->SubnetMask);
- Status = Ip4SetAddress (IpIf, StationAddress, SubnetMask);
-
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
-
- Ip4AddRoute (
- IpSb->DefaultRouteTable,
- StationAddress,
- SubnetMask,
- IP4_ALLZERO_ADDRESS
- );
-
- //
- // Add routes returned by EFI_IP4_CONFIG protocol.
- //
- for (Index = 0; Index < Data->RouteTableSize; Index++) {
- RouteEntry = &Data->RouteTable[Index];
-
- SubnetAddress = EFI_NTOHL (RouteEntry->SubnetAddress);
- SubnetMask = EFI_NTOHL (RouteEntry->SubnetMask);
- GatewayAddress = EFI_NTOHL (RouteEntry->GatewayAddress);
- Ip4AddRoute (IpSb->DefaultRouteTable, SubnetAddress, SubnetMask, GatewayAddress);
- }
-
- IpSb->State = IP4_SERVICE_CONFIGED;
-
- Ip4SetVariableData (IpSb);
-
-ON_EXIT:
- FreePool (Data);
-}
-
-/**
- Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK.
-
- @param Event The event that is signalled.
- @param Context The IP4 service binding instance.
-
-**/
-VOID
-EFIAPI
-Ip4AutoConfigCallBack (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- IP4_SERVICE *IpSb;
-
- IpSb = (IP4_SERVICE *) Context;
- IpSb->ActiveEvent = Event;
-
- //
- // Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK
- //
- QueueDpc (TPL_CALLBACK, Ip4AutoConfigCallBackDpc, Context);
-}
-
-
-/**
- Start the auto configuration for this IP service instance.
- It will locates the EFI_IP4_CONFIG_PROTOCOL, then start the
- auto configuration.
-
- @param[in] IpSb The IP4 service instance to configure
-
- @retval EFI_SUCCESS The auto configuration is successfull started
- @retval Others Failed to start auto configuration.
-
-**/
-EFI_STATUS
-Ip4StartAutoConfig (
- IN IP4_SERVICE *IpSb
- )
-{
- EFI_IP4_CONFIG_PROTOCOL *Ip4Config;
- EFI_STATUS Status;
-
- if (IpSb->State > IP4_SERVICE_UNSTARTED) {
- return EFI_SUCCESS;
- }
-
- //
- // Create the DoneEvent and ReconfigEvent to call EFI_IP4_CONFIG
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- Ip4AutoConfigCallBack,
- IpSb,
- &IpSb->DoneEvent
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- Ip4AutoConfigCallBack,
- IpSb,
- &IpSb->ReconfigEvent
- );
-
- if (EFI_ERROR (Status)) {
- goto CLOSE_DONE_EVENT;
- }
-
- //
- // Open the EFI_IP4_CONFIG protocol then start auto configure
- //
- Status = gBS->OpenProtocol (
- IpSb->Controller,
- &gEfiIp4ConfigProtocolGuid,
- (VOID **) &Ip4Config,
- IpSb->Image,
- IpSb->Controller,
- EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
- );
-
- if (EFI_ERROR (Status)) {
- Status = EFI_UNSUPPORTED;
- goto CLOSE_RECONFIG_EVENT;
- }
-
- Status = Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);
-
- if (EFI_ERROR (Status)) {
- gBS->CloseProtocol (
- IpSb->Controller,
- &gEfiIp4ConfigProtocolGuid,
- IpSb->Image,
- IpSb->Controller
- );
-
- goto CLOSE_RECONFIG_EVENT;
- }
-
- IpSb->Ip4Config = Ip4Config;
- IpSb->State = IP4_SERVICE_STARTED;
- return Status;
-
-CLOSE_RECONFIG_EVENT:
- gBS->CloseEvent (IpSb->ReconfigEvent);
- IpSb->ReconfigEvent = NULL;
-
-CLOSE_DONE_EVENT:
- gBS->CloseEvent (IpSb->DoneEvent);
- IpSb->DoneEvent = NULL;
-
- return Status;
-}
-
-
-/**
- Intiialize the IP4_PROTOCOL structure to the unconfigured states.
-
- @param IpSb The IP4 service instance.
- @param IpInstance The IP4 child instance.
-
-**/
-VOID
-Ip4InitProtocol (
- IN IP4_SERVICE *IpSb,
- IN OUT IP4_PROTOCOL *IpInstance
- )
-{
- ASSERT ((IpSb != NULL) && (IpInstance != NULL));
-
- ZeroMem (IpInstance, sizeof (IP4_PROTOCOL));
-
- IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;
- CopyMem (&IpInstance->Ip4Proto, &mEfiIp4ProtocolTemplete, sizeof (IpInstance->Ip4Proto));
- IpInstance->State = IP4_STATE_UNCONFIGED;
- IpInstance->Service = IpSb;
-
- InitializeListHead (&IpInstance->Link);
- NetMapInit (&IpInstance->RxTokens);
- NetMapInit (&IpInstance->TxTokens);
- InitializeListHead (&IpInstance->Received);
- InitializeListHead (&IpInstance->Delivered);
- InitializeListHead (&IpInstance->AddrLink);
-
- EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);
-}
-
-
-/**
- Configure the IP4 child. If the child is already configured,
- change the configuration parameter. Otherwise configure it
- for the first time. The caller should validate the configuration
- before deliver them to it. It also don't do configure NULL.
-
- @param[in, out] IpInstance The IP4 child to configure.
- @param[in] Config The configure data.
-
- @retval EFI_SUCCESS The IP4 child is successfully configured.
- @retval EFI_DEVICE_ERROR Failed to free the pending transive or to
- configure underlying MNP or other errors.
- @retval EFI_NO_MAPPING The IP4 child is configured to use default
- address, but the default address hasn't been
- configured. The IP4 child doesn't need to be
- reconfigured when default address is configured.
- @retval EFI_OUT_OF_RESOURCES No more memory space is available.
- @retval other Other error occurs.
-
-**/
-EFI_STATUS
-Ip4ConfigProtocol (
- IN OUT IP4_PROTOCOL *IpInstance,
- IN EFI_IP4_CONFIG_DATA *Config
- )
-{
- IP4_SERVICE *IpSb;
- IP4_INTERFACE *IpIf;
- EFI_STATUS Status;
- IP4_ADDR Ip;
- IP4_ADDR Netmask;
-
- IpSb = IpInstance->Service;
-
- //
- // User is changing packet filters. It must be stopped
- // before the station address can be changed.
- //
- if (IpInstance->State == IP4_STATE_CONFIGED) {
- //
- // Cancel all the pending transmit/receive from upper layer
- //
- Status = Ip4Cancel (IpInstance, NULL);
-
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
-
- CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
- return EFI_SUCCESS;
- }
-
- //
- // Configure a fresh IP4 protocol instance. Create a route table.
- // Each IP child has its own route table, which may point to the
- // default table if it is using default address.
- //
- Status = EFI_OUT_OF_RESOURCES;
- IpInstance->RouteTable = Ip4CreateRouteTable ();
-
- if (IpInstance->RouteTable == NULL) {
- return Status;
- }
-
- //
- // Set up the interface.
- //
- CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));
- CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));
-
- Ip = NTOHL (Ip);
- Netmask = NTOHL (Netmask);
-
- if (!Config->UseDefaultAddress) {
- //
- // Find whether there is already an interface with the same
- // station address. All the instances with the same station
- // address shares one interface.
- //
- IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);
-
- if (IpIf != NULL) {
- NET_GET_REF (IpIf);
-
- } else {
- IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
-
- if (IpIf == NULL) {
- goto ON_ERROR;
- }
-
- Status = Ip4SetAddress (IpIf, Ip, Netmask);
-
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- Ip4FreeInterface (IpIf, IpInstance);
- goto ON_ERROR;
- }
-
- InsertTailList (&IpSb->Interfaces, &IpIf->Link);
- }
-
- //
- // Add a route to this connected network in the route table
- //
- Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);
-
- } else {
- //
- // Use the default address. If the default configuration hasn't
- // been started, start it.
- //
- if (IpSb->State == IP4_SERVICE_UNSTARTED) {
- Status = Ip4StartAutoConfig (IpSb);
-
- if (EFI_ERROR (Status)) {
- goto ON_ERROR;
- }
- }
-
- IpIf = IpSb->DefaultInterface;
- NET_GET_REF (IpSb->DefaultInterface);
-
- //
- // If default address is used, so is the default route table.
- // Any route set by the instance has the precedence over the
- // routes in the default route table. Link the default table
- // after the instance's table. Routing will search the local
- // table first.
- //
- NET_GET_REF (IpSb->DefaultRouteTable);
- IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;
- }
-
- IpInstance->Interface = IpIf;
- InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
-
- CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
- IpInstance->State = IP4_STATE_CONFIGED;
-
- //
- // Although EFI_NO_MAPPING is an error code, the IP child has been
- // successfully configured and doesn't need reconfiguration when
- // default address is acquired.
- //
- if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
- return EFI_NO_MAPPING;
- }
-
- return EFI_SUCCESS;
-
-ON_ERROR:
- Ip4FreeRouteTable (IpInstance->RouteTable);
- IpInstance->RouteTable = NULL;
- return Status;
-}
-
-
-/**
- Clean up the IP4 child, release all the resources used by it.
-
- @param[in] IpInstance The IP4 child to clean up.
-
- @retval EFI_SUCCESS The IP4 child is cleaned up
- @retval EFI_DEVICE_ERROR Some resources failed to be released
-
-**/
-EFI_STATUS
-Ip4CleanProtocol (
- IN IP4_PROTOCOL *IpInstance
- )
-{
- if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {
- return EFI_DEVICE_ERROR;
- }
-
- if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {
- return EFI_DEVICE_ERROR;
- }
-
- //
- // Some packets haven't been recycled. It is because either the
- // user forgets to recycle the packets, or because the callback
- // hasn't been called. Just leave it alone.
- //
- if (!IsListEmpty (&IpInstance->Delivered)) {
- ;
- }
-
- if (IpInstance->Interface != NULL) {
- RemoveEntryList (&IpInstance->AddrLink);
- Ip4FreeInterface (IpInstance->Interface, IpInstance);
- IpInstance->Interface = NULL;
- }
-
- if (IpInstance->RouteTable != NULL) {
- if (IpInstance->RouteTable->Next != NULL) {
- Ip4FreeRouteTable (IpInstance->RouteTable->Next);
- }
-
- Ip4FreeRouteTable (IpInstance->RouteTable);
- IpInstance->RouteTable = NULL;
- }
-
- if (IpInstance->EfiRouteTable != NULL) {
- FreePool (IpInstance->EfiRouteTable);
- IpInstance->EfiRouteTable = NULL;
- IpInstance->EfiRouteCount = 0;
- }
-
- if (IpInstance->Groups != NULL) {
- FreePool (IpInstance->Groups);
- IpInstance->Groups = NULL;
- IpInstance->GroupCount = 0;
- }
-
- NetMapClean (&IpInstance->TxTokens);
-
- NetMapClean (&IpInstance->RxTokens);
-
- return EFI_SUCCESS;
-}
-
-
-/**
- Validate that Ip/Netmask pair is OK to be used as station
- address. Only continuous netmasks are supported. and check
- that StationAddress is a unicast address on the newtwork.
-
- @param[in] Ip The IP address to validate
- @param[in] Netmask The netmaks of the IP
-
- @retval TRUE The Ip/Netmask pair is valid
- @retval FALSE The Ip/Netmask pair is invalid
-
-**/
-BOOLEAN
-Ip4StationAddressValid (
- IN IP4_ADDR Ip,
- IN IP4_ADDR Netmask
- )
-{
- IP4_ADDR NetBrdcastMask;
- INTN Len;
- INTN Type;
-
- //
- // Only support the station address with 0.0.0.0/0 to enable DHCP client.
- //
- if (Netmask == IP4_ALLZERO_ADDRESS) {
- return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);
- }
-
- //
- // Only support the continuous net masks
- //
- if ((Len = NetGetMaskLength (Netmask)) == IP4_MASK_NUM) {
- return FALSE;
- }
-
- //
- // Station address can't be class D or class E address
- //
- if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {
- return FALSE;
- }
-
- //
- // Station address can't be subnet broadcast/net broadcast address
- //
- if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {
- return FALSE;
- }
-
- NetBrdcastMask = gIp4AllMasks[MIN (Len, Type << 3)];
-
- if (Ip == (Ip | ~NetBrdcastMask)) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/**
- Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
-
- The Configure() function is used to set, change, or reset the operational
- parameters and filter settings for this EFI IPv4 Protocol instance. Until these
- parameters have been set, no network traffic can be sent or received by this
- instance. Once the parameters have been reset (by calling this function with
- IpConfigData set to NULL), no more traffic can be sent or received until these
- parameters have been set again. Each EFI IPv4 Protocol instance can be started
- and stopped independently of each other by enabling or disabling their receive
- filter settings with the Configure() function.
-
- When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
- be appended as an alias address into the addresses list in the EFI IPv4 Protocol
- driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
- to retrieve the default IPv4 address if it is not available yet. Clients could
- frequently call GetModeData() to check the status to ensure that the default IPv4
- address is ready.
-
- If operational parameters are reset or changed, any pending transmit and receive
- requests will be cancelled. Their completion token status will be set to EFI_ABORTED
- and their events will be signaled.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] IpConfigData Pointer to the EFI IPv4 Protocol configuration data structure.
-
- @retval EFI_SUCCESS The driver instance was successfully opened.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- @retval EFI_UNSUPPORTED One or more of the following conditions is TRUE:
- A configuration protocol (DHCP, BOOTP, RARP, etc.) could
- not be located when clients choose to use the default IPv4
- address. This EFI IPv4 Protocol implementation does not
- support this requested filter or timeout setting.
- @retval EFI_OUT_OF_RESOURCES The EFI IPv4 Protocol driver instance data could not be allocated.
- @retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the
- IPv4 address or subnet mask can be changed. The interface must
- also be stopped when switching to/from raw packet mode.
- @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv4
- Protocol driver instance is not opened.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Configure (
- IN EFI_IP4_PROTOCOL *This,
- IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL
- )
-{
- IP4_PROTOCOL *IpInstance;
- EFI_IP4_CONFIG_DATA *Current;
- EFI_TPL OldTpl;
- EFI_STATUS Status;
- BOOLEAN AddrOk;
- IP4_ADDR IpAddress;
- IP4_ADDR SubnetMask;
-
- //
- // First, validate the parameters
- //
- if (This == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
-
- //
- // Validate the configuration first.
- //
- if (IpConfigData != NULL) {
- //
- // This implementation doesn't support RawData
- //
- if (IpConfigData->RawData) {
- Status = EFI_UNSUPPORTED;
- goto ON_EXIT;
- }
-
-
- CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));
- CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));
-
- IpAddress = NTOHL (IpAddress);
- SubnetMask = NTOHL (SubnetMask);
-
- //
- // Check whether the station address is a valid unicast address
- //
- if (!IpConfigData->UseDefaultAddress) {
- AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);
-
- if (!AddrOk) {
- Status = EFI_INVALID_PARAMETER;
- goto ON_EXIT;
- }
- }
-
- //
- // User can only update packet filters when already configured.
- // If it wants to change the station address, it must configure(NULL)
- // the instance first.
- //
- if (IpInstance->State == IP4_STATE_CONFIGED) {
- Current = &IpInstance->ConfigData;
-
- if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {
- Status = EFI_ALREADY_STARTED;
- goto ON_EXIT;
- }
-
- if (!Current->UseDefaultAddress &&
- (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||
- !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {
- Status = EFI_ALREADY_STARTED;
- goto ON_EXIT;
- }
-
- if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
- Status = EFI_NO_MAPPING;
- goto ON_EXIT;
- }
- }
- }
-
- //
- // Configure the instance or clean it up.
- //
- if (IpConfigData != NULL) {
- Status = Ip4ConfigProtocol (IpInstance, IpConfigData);
- } else {
- Status = Ip4CleanProtocol (IpInstance);
-
- //
- // Don't change the state if it is DESTROY, consider the following
- // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
- // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
- // the unload fails miserably.
- //
- if (IpInstance->State == IP4_STATE_CONFIGED) {
- IpInstance->State = IP4_STATE_UNCONFIGED;
- }
- }
-
- //
- // Update the MNP's configure data. Ip4ServiceConfigMnp will check
- // whether it is necessary to reconfigure the MNP.
- //
- Ip4ServiceConfigMnp (IpInstance->Service, FALSE);
-
- //
- // Update the variable data.
- //
- Ip4SetVariableData (IpInstance->Service);
-
-ON_EXIT:
- gBS->RestoreTPL (OldTpl);
- return Status;
-
-}
-
-
-/**
- Change the IP4 child's multicast setting. The caller
- should make sure that the parameters is valid.
-
- @param[in] IpInstance The IP4 child to change the setting.
- @param[in] JoinFlag TRUE to join the group, otherwise leave it
- @param[in] GroupAddress The target group address
-
- @retval EFI_ALREADY_STARTED Want to join the group, but already a member of it
- @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
- @retval EFI_DEVICE_ERROR Failed to set the group configuraton
- @retval EFI_SUCCESS Successfully updated the group setting.
- @retval EFI_NOT_FOUND Try to leave the group which it isn't a member.
-
-**/
-EFI_STATUS
-Ip4Groups (
- IN IP4_PROTOCOL *IpInstance,
- IN BOOLEAN JoinFlag,
- IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
- )
-{
- IP4_ADDR *Members;
- IP4_ADDR Group;
- UINT32 Index;
-
- //
- // Add it to the instance's Groups, and join the group by IGMP.
- // IpInstance->Groups is in network byte order. IGMP operates in
- // host byte order
- //
- if (JoinFlag) {
- //
- // When JoinFlag is TRUE, GroupAddress shouldn't be NULL.
- //
- ASSERT (GroupAddress != NULL);
- CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));
-
- for (Index = 0; Index < IpInstance->GroupCount; Index++) {
- if (IpInstance->Groups[Index] == Group) {
- return EFI_ALREADY_STARTED;
- }
- }
-
- Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);
-
- if (Members == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {
- FreePool (Members);
- return EFI_DEVICE_ERROR;
- }
-
- if (IpInstance->Groups != NULL) {
- FreePool (IpInstance->Groups);
- }
-
- IpInstance->Groups = Members;
- IpInstance->GroupCount++;
-
- return EFI_SUCCESS;
- }
-
- //
- // Leave the group. Leave all the groups if GroupAddress is NULL.
- // Must iterate from the end to the beginning because the GroupCount
- // is decreamented each time an address is removed..
- //
- for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {
- Group = IpInstance->Groups[Index - 1];
-
- if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {
- if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {
- return EFI_DEVICE_ERROR;
- }
-
- Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);
- IpInstance->GroupCount--;
-
- if (IpInstance->GroupCount == 0) {
- ASSERT (Index == 1);
-
- FreePool (IpInstance->Groups);
- IpInstance->Groups = NULL;
- }
-
- if (GroupAddress != NULL) {
- return EFI_SUCCESS;
- }
- }
- }
-
- return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);
-}
-
-
-/**
- Joins and leaves multicast groups.
-
- The Groups() function is used to join and leave multicast group sessions. Joining
- a group will enable reception of matching multicast packets. Leaving a group will
- disable the multicast packet reception.
-
- If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] JoinFlag Set to TRUE to join the multicast group session and FALSE to leave.
- @param[in] GroupAddress Pointer to the IPv4 multicast address.
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
- - This is NULL.
- - JoinFlag is TRUE and GroupAddress is NULL.
- - GroupAddress is not NULL and *GroupAddress is
- not a multicast IPv4 address.
- @retval EFI_NOT_STARTED This instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_OUT_OF_RESOURCES System resources could not be allocated.
- @retval EFI_UNSUPPORTED This EFI IPv4 Protocol implementation does not support multicast groups.
- @retval EFI_ALREADY_STARTED The group address is already in the group table (when
- JoinFlag is TRUE).
- @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE).
- @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Groups (
- IN EFI_IP4_PROTOCOL *This,
- IN BOOLEAN JoinFlag,
- IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
- )
-{
- IP4_PROTOCOL *IpInstance;
- EFI_STATUS Status;
- EFI_TPL OldTpl;
- IP4_ADDR McastIp;
-
- if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (GroupAddress != NULL) {
- CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));
-
- if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {
- return EFI_INVALID_PARAMETER;
- }
- }
-
- IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
-
- if (IpInstance->State != IP4_STATE_CONFIGED) {
- Status = EFI_NOT_STARTED;
- goto ON_EXIT;
- }
-
- if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
- Status = EFI_NO_MAPPING;
- goto ON_EXIT;
- }
-
- Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);
-
-ON_EXIT:
- gBS->RestoreTPL (OldTpl);
- return Status;
-}
-
-
-/**
- Adds and deletes routing table entries.
-
- The Routes() function adds a route to or deletes a route from the routing table.
-
- Routes are determined by comparing the SubnetAddress with the destination IPv4
- address arithmetically AND-ed with the SubnetMask. The gateway address must be
- on the same subnet as the configured station address.
-
- The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
- The default route matches all destination IPv4 addresses that do not match any
- other routes.
-
- A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
- IP address if it can be found in the ARP cache or on the local subnet. One automatic
- nonroute entry will be inserted into the routing table for outgoing packets that
- are addressed to a local subnet (gateway address of 0.0.0.0).
-
- Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
- IPv4 Protocol instances that use the default IPv4 address will also have copies
- of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
- copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
- instances. As a result, client modification to the routing table will be lost.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. Set to
- FALSE to add this route to the routing table. SubnetAddress
- and SubnetMask are used as the key to each route entry.
- @param[in] SubnetAddress The address of the subnet that needs to be routed.
- @param[in] SubnetMask The subnet mask of SubnetAddress.
- @param[in] GatewayAddress The unicast gateway IPv4 address for this route.
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_NOT_STARTED The driver instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- - This is NULL.
- - SubnetAddress is NULL.
- - SubnetMask is NULL.
- - GatewayAddress is NULL.
- - *SubnetAddress is not a valid subnet address.
- - *SubnetMask is not a valid subnet mask.
- - *GatewayAddress is not a valid unicast IPv4 address.
- @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
- @retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE).
- @retval EFI_ACCESS_DENIED The route is already defined in the routing table (when
- DeleteRoute is FALSE).
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Routes (
- IN EFI_IP4_PROTOCOL *This,
- IN BOOLEAN DeleteRoute,
- IN EFI_IPv4_ADDRESS *SubnetAddress,
- IN EFI_IPv4_ADDRESS *SubnetMask,
- IN EFI_IPv4_ADDRESS *GatewayAddress
- )
-{
- IP4_PROTOCOL *IpInstance;
- IP4_INTERFACE *IpIf;
- IP4_ADDR Dest;
- IP4_ADDR Netmask;
- IP4_ADDR Nexthop;
- EFI_STATUS Status;
- EFI_TPL OldTpl;
-
- //
- // First, validate the parameters
- //
- if ((This == NULL) || (SubnetAddress == NULL) ||
- (SubnetMask == NULL) || (GatewayAddress == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
-
- if (IpInstance->State != IP4_STATE_CONFIGED) {
- Status = EFI_NOT_STARTED;
- goto ON_EXIT;
- }
-
- if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
- Status = EFI_NO_MAPPING;
- goto ON_EXIT;
- }
-
- CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));
- CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));
- CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));
-
- Dest = NTOHL (Dest);
- Netmask = NTOHL (Netmask);
- Nexthop = NTOHL (Nexthop);
-
- IpIf = IpInstance->Interface;
-
- if (!IP4_IS_VALID_NETMASK (Netmask)) {
- Status = EFI_INVALID_PARAMETER;
- goto ON_EXIT;
- }
-
- //
- // the gateway address must be a unicast on the connected network if not zero.
- //
- if ((Nexthop != IP4_ALLZERO_ADDRESS) &&
- (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||
- IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {
-
- Status = EFI_INVALID_PARAMETER;
- goto ON_EXIT;
- }
-
- if (DeleteRoute) {
- Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
- } else {
- Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
- }
-
-ON_EXIT:
- gBS->RestoreTPL (OldTpl);
- return Status;
-}
-
-
-/**
- Check whether the user's token or event has already
- been enqueued on IP4's list.
-
- @param[in] Map The container of either user's transmit or receive
- token.
- @param[in] Item Current item to check against
- @param[in] Context The Token to check againist.
-
- @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
- @retval EFI_SUCCESS The current item isn't the same token/event as the
- context.
-
-**/
-EFI_STATUS
-EFIAPI
-Ip4TokenExist (
- IN NET_MAP *Map,
- IN NET_MAP_ITEM *Item,
- IN VOID *Context
- )
-{
- EFI_IP4_COMPLETION_TOKEN *Token;
- EFI_IP4_COMPLETION_TOKEN *TokenInItem;
-
- Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
- TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;
-
- if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
- return EFI_ACCESS_DENIED;
- }
-
- return EFI_SUCCESS;
-}
-
-
-/**
- Validate the user's token against current station address.
-
- @param[in] Token User's token to validate
- @param[in] IpIf The IP4 child's interface.
-
- @retval EFI_INVALID_PARAMETER Some parameters are invalid
- @retval EFI_BAD_BUFFER_SIZE The user's option/data is too long.
- @retval EFI_SUCCESS The token is OK
-
-**/
-EFI_STATUS
-Ip4TxTokenValid (
- IN EFI_IP4_COMPLETION_TOKEN *Token,
- IN IP4_INTERFACE *IpIf
- )
-{
- EFI_IP4_TRANSMIT_DATA *TxData;
- EFI_IP4_OVERRIDE_DATA *Override;
- IP4_ADDR Src;
- IP4_ADDR Gateway;
- UINT32 Offset;
- UINT32 Index;
- UINT32 HeadLen;
-
- if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- TxData = Token->Packet.TxData;
-
- //
- // Check the IP options: no more than 40 bytes and format is OK
- //
- if (TxData->OptionsLength != 0) {
- if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {
- return EFI_INVALID_PARAMETER;
- }
- }
-
- //
- // Check the fragment table: no empty fragment, and length isn't bogus
- //
- if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Offset = TxData->TotalDataLength;
-
- for (Index = 0; Index < TxData->FragmentCount; Index++) {
- if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
- (TxData->FragmentTable[Index].FragmentLength == 0)) {
-
- return EFI_INVALID_PARAMETER;
- }
-
- Offset -= TxData->FragmentTable[Index].FragmentLength;
- }
-
- if (Offset != 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Check the source and gateway: they must be a valid unicast.
- // Gateway must also be on the connected network.
- //
- if (TxData->OverrideData != NULL) {
- Override = TxData->OverrideData;
-
- CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));
- CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));
-
- Src = NTOHL (Src);
- Gateway = NTOHL (Gateway);
-
- if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||
- (Src == IP4_ALLONE_ADDRESS) ||
- IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
-
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // If gateway isn't zero, it must be a unicast address, and
- // on the connected network.
- //
- if ((Gateway != IP4_ALLZERO_ADDRESS) &&
- ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||
- !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||
- IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {
-
- return EFI_INVALID_PARAMETER;
- }
- }
-
- //
- // Check the packet length: Head length and packet length all has a limit
- //
- HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);
-
- if ((HeadLen > IP4_MAX_HEADLEN) ||
- (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {
-
- return EFI_BAD_BUFFER_SIZE;
- }
-
- return EFI_SUCCESS;
-}
-
-
-/**
- The callback function for the net buffer which wraps the user's
- transmit token. Although it seems this function is pretty simple,
- there are some subtle things.
- When user requests the IP to transmit a packet by passing it a
- token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data
- is wrapped in an net buffer. the net buffer's Free function is
- set to Ip4FreeTxToken. The Token and token wrap are added to the
- IP child's TxToken map. Then the buffer is passed to Ip4Output for
- transmission. If something error happened before that, the buffer
- is freed, which in turn will free the token wrap. The wrap may
- have been added to the TxToken map or not, and the user's event
- shouldn't be fired because we are still in the EfiIp4Transmit. If
- the buffer has been sent by Ip4Output, it should be removed from
- the TxToken map and user's event signaled. The token wrap and buffer
- are bound together. Check the comments in Ip4Output for information
- about IP fragmentation.
-
- @param[in] Context The token's wrap
-
-**/
-VOID
-EFIAPI
-Ip4FreeTxToken (
- IN VOID *Context
- )
-{
- IP4_TXTOKEN_WRAP *Wrap;
- NET_MAP_ITEM *Item;
-
- Wrap = (IP4_TXTOKEN_WRAP *) Context;
-
- //
- // Signal IpSecRecycleEvent to inform IPsec free the memory
- //
- if (Wrap->IpSecRecycleSignal != NULL) {
- gBS->SignalEvent (Wrap->IpSecRecycleSignal);
- }
-
- //
- // Find the token in the instance's map. EfiIp4Transmit put the
- // token to the map. If that failed, NetMapFindKey will return NULL.
- //
- Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
-
- if (Item != NULL) {
- NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
- }
-
- if (Wrap->Sent) {
- gBS->SignalEvent (Wrap->Token->Event);
-
- //
- // Dispatch the DPC queued by the NotifyFunction of Token->Event.
- //
- DispatchDpc ();
- }
-
- FreePool (Wrap);
-}
-
-
-/**
- The callback function to Ip4Output to update the transmit status.
-
- @param Ip4Instance The Ip4Instance that request the transmit.
- @param Packet The user's transmit request
- @param IoStatus The result of the transmission
- @param Flag Not used during transmission
- @param Context The token's wrap.
-
-**/
-VOID
-Ip4OnPacketSent (
- IP4_PROTOCOL *Ip4Instance,
- NET_BUF *Packet,
- EFI_STATUS IoStatus,
- UINT32 Flag,
- VOID *Context
- )
-{
- IP4_TXTOKEN_WRAP *Wrap;
-
- //
- // This is the transmission request from upper layer,
- // not the IP4 driver itself.
- //
- ASSERT (Ip4Instance != NULL);
-
- //
- // The first fragment of the packet has been sent. Update
- // the token's status. That is, if fragmented, the transmit's
- // status is the first fragment's status. The Wrap will be
- // release when all the fragments are release. Check the comments
- // in Ip4FreeTxToken and Ip4Output for information.
- //
- Wrap = (IP4_TXTOKEN_WRAP *) Context;
- Wrap->Token->Status = IoStatus;
-
- NetbufFree (Wrap->Packet);
-}
-
-
-/**
- Places outgoing data packets into the transmit queue.
-
- The Transmit() function places a sending request in the transmit queue of this
- EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
- errors occur, the event in the token will be signaled and the status is updated.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] Token Pointer to the transmit token.
-
- @retval EFI_SUCCESS The data has been queued for transmission.
- @retval EFI_NOT_STARTED This instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_INVALID_PARAMETER One or more pameters are invalid.
- @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.Event
- was already in the transmit queue.
- @retval EFI_NOT_READY The completion token could not be queued because the transmit
- queue is full.
- @retval EFI_NOT_FOUND Not route is found to destination address.
- @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.
- @retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too
- short to transmit.
- @retval EFI_BAD_BUFFER_SIZE The length of the IPv4 header + option length + total data length is
- greater than MTU (or greater than the maximum packet size if
- Token.Packet.TxData.OverrideData.
- DoNotFragment is TRUE.)
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Transmit (
- IN EFI_IP4_PROTOCOL *This,
- IN EFI_IP4_COMPLETION_TOKEN *Token
- )
-{
- IP4_SERVICE *IpSb;
- IP4_PROTOCOL *IpInstance;
- IP4_INTERFACE *IpIf;
- IP4_TXTOKEN_WRAP *Wrap;
- EFI_IP4_TRANSMIT_DATA *TxData;
- EFI_IP4_CONFIG_DATA *Config;
- EFI_IP4_OVERRIDE_DATA *Override;
- IP4_HEAD Head;
- IP4_ADDR GateWay;
- EFI_STATUS Status;
- EFI_TPL OldTpl;
- BOOLEAN DontFragment;
- UINT32 HeadLen;
-
- if (This == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
-
- if (IpInstance->State != IP4_STATE_CONFIGED) {
- return EFI_NOT_STARTED;
- }
-
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
-
- IpSb = IpInstance->Service;
- IpIf = IpInstance->Interface;
- Config = &IpInstance->ConfigData;
-
- if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
- Status = EFI_NO_MAPPING;
- goto ON_EXIT;
- }
-
- //
- // make sure that token is properly formated
- //
- Status = Ip4TxTokenValid (Token, IpIf);
-
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
-
- //
- // Check whether the token or signal already existed.
- //
- if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {
- Status = EFI_ACCESS_DENIED;
- goto ON_EXIT;
- }
-
- //
- // Build the IP header, need to fill in the Tos, TotalLen, Id,
- // fragment, Ttl, protocol, Src, and Dst.
- //
- TxData = Token->Packet.TxData;
-
- CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));
- Head.Dst = NTOHL (Head.Dst);
-
- if (TxData->OverrideData != NULL) {
- Override = TxData->OverrideData;
- Head.Protocol = Override->Protocol;
- Head.Tos = Override->TypeOfService;
- Head.Ttl = Override->TimeToLive;
- DontFragment = Override->DoNotFragment;
-
- CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));
- CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));
-
- Head.Src = NTOHL (Head.Src);
- GateWay = NTOHL (GateWay);
- } else {
- Head.Src = IpIf->Ip;
- GateWay = IP4_ALLZERO_ADDRESS;
- Head.Protocol = Config->DefaultProtocol;
- Head.Tos = Config->TypeOfService;
- Head.Ttl = Config->TimeToLive;
- DontFragment = Config->DoNotFragment;
- }
-
- Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);
- HeadLen = (TxData->OptionsLength + 3) & (~0x03);
-
- //
- // If don't fragment and fragment needed, return error
- //
- if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->MaxPacketSize)) {
- Status = EFI_BAD_BUFFER_SIZE;
- goto ON_EXIT;
- }
-
- //
- // OK, it survives all the validation check. Wrap the token in
- // a IP4_TXTOKEN_WRAP and the data in a netbuf
- //
- Status = EFI_OUT_OF_RESOURCES;
- Wrap = AllocateZeroPool (sizeof (IP4_TXTOKEN_WRAP));
- if (Wrap == NULL) {
- goto ON_EXIT;
- }
-
- Wrap->IpInstance = IpInstance;
- Wrap->Token = Token;
- Wrap->Sent = FALSE;
- Wrap->Life = IP4_US_TO_SEC (Config->TransmitTimeout);
- Wrap->Packet = NetbufFromExt (
- (NET_FRAGMENT *) TxData->FragmentTable,
- TxData->FragmentCount,
- IP4_MAX_HEADLEN,
- 0,
- Ip4FreeTxToken,
- Wrap
- );
-
- if (Wrap->Packet == NULL) {
- FreePool (Wrap);
- goto ON_EXIT;
- }
-
- Token->Status = EFI_NOT_READY;
-
- if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {
- //
- // NetbufFree will call Ip4FreeTxToken, which in turn will
- // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been
- // enqueued.
- //
- NetbufFree (Wrap->Packet);
- goto ON_EXIT;
- }
-
- //
- // Mark the packet sent before output it. Mark it not sent again if the
- // returned status is not EFI_SUCCESS;
- //
- Wrap->Sent = TRUE;
-
- Status = Ip4Output (
- IpSb,
- IpInstance,
- Wrap->Packet,
- &Head,
- TxData->OptionsBuffer,
- TxData->OptionsLength,
- GateWay,
- Ip4OnPacketSent,
- Wrap
- );
-
- if (EFI_ERROR (Status)) {
- Wrap->Sent = FALSE;
- NetbufFree (Wrap->Packet);
- }
-
-ON_EXIT:
- gBS->RestoreTPL (OldTpl);
- return Status;
-}
-
-
-/**
- Places a receiving request into the receiving queue.
-
- The Receive() function places a completion token into the receive packet queue.
- This function is always asynchronous.
-
- The Token.Event field in the completion token must be filled in by the caller
- and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
- driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
- is signaled.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] Token Pointer to a token that is associated with the receive data descriptor.
-
- @retval EFI_SUCCESS The receive completion token was cached.
- @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
- is not finished yet.
- @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- - This is NULL.
- - Token is NULL.
- - Token.Event is NULL.
- @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system
- resources (usually memory).
- @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
- The EFI IPv4 Protocol instance has been reset to startup defaults.
- EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
- in the receive queue.
- @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full.
- @retval EFI_ICMP_ERROR An ICMP error packet was received.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Receive (
- IN EFI_IP4_PROTOCOL *This,
- IN EFI_IP4_COMPLETION_TOKEN *Token
- )
-{
- IP4_PROTOCOL *IpInstance;
- EFI_STATUS Status;
- EFI_TPL OldTpl;
-
- //
- // First validate the parameters
- //
- if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
-
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
-
- if (IpInstance->State != IP4_STATE_CONFIGED) {
- Status = EFI_NOT_STARTED;
- goto ON_EXIT;
- }
-
- //
- // Check whether the toke is already on the receive queue.
- //
- Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);
-
- if (EFI_ERROR (Status)) {
- Status = EFI_ACCESS_DENIED;
- goto ON_EXIT;
- }
-
- //
- // Queue the token then check whether there is pending received packet.
- //
- Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
-
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
-
- Status = Ip4InstanceDeliverPacket (IpInstance);
-
- //
- // Dispatch the DPC queued by the NotifyFunction of this instane's receive
- // event.
- //
- DispatchDpc ();
-
-ON_EXIT:
- gBS->RestoreTPL (OldTpl);
- return Status;
-}
-
-
-/**
- Cancel the transmitted but not recycled packet. If a matching
- token is found, it will call Ip4CancelPacket to cancel the
- packet. Ip4CancelPacket will cancel all the fragments of the
- packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP
- will be deleted from the Map, and user's event signalled.
- Because Ip4CancelPacket and other functions are all called in
- line, so, after Ip4CancelPacket returns, the Item has been freed.
-
- @param[in] Map The IP4 child's transmit queue
- @param[in] Item The current transmitted packet to test.
- @param[in] Context The user's token to cancel.
-
- @retval EFI_SUCCESS Continue to check the next Item.
- @retval EFI_ABORTED The user's Token (Token != NULL) is cancelled.
-
-**/
-EFI_STATUS
-EFIAPI
-Ip4CancelTxTokens (
- IN NET_MAP *Map,
- IN NET_MAP_ITEM *Item,
- IN VOID *Context
- )
-{
- EFI_IP4_COMPLETION_TOKEN *Token;
- IP4_TXTOKEN_WRAP *Wrap;
-
- Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
-
- //
- // Return EFI_SUCCESS to check the next item in the map if
- // this one doesn't match.
- //
- if ((Token != NULL) && (Token != Item->Key)) {
- return EFI_SUCCESS;
- }
-
- Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
- ASSERT (Wrap != NULL);
-
- //
- // Don't access the Item, Wrap and Token's members after this point.
- // Item and wrap has been freed. And we no longer own the Token.
- //
- Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
-
- //
- // If only one item is to be cancel, return EFI_ABORTED to stop
- // iterating the map any more.
- //
- if (Token != NULL) {
- return EFI_ABORTED;
- }
-
- return EFI_SUCCESS;
-}
-
-
-/**
- Cancel the receive request. This is quiet simple, because
- it is only enqueued in our local receive map.
-
- @param[in] Map The IP4 child's receive queue
- @param[in] Item Current receive request to cancel.
- @param[in] Context The user's token to cancel
-
- @retval EFI_SUCCESS Continue to check the next receive request on the
- queue.
- @retval EFI_ABORTED The user's token (token != NULL) has been
- cancelled.
-
-**/
-EFI_STATUS
-EFIAPI
-Ip4CancelRxTokens (
- IN NET_MAP *Map,
- IN NET_MAP_ITEM *Item,
- IN VOID *Context
- )
-{
- EFI_IP4_COMPLETION_TOKEN *Token;
- EFI_IP4_COMPLETION_TOKEN *This;
-
- Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
- This = Item->Key;
-
- if ((Token != NULL) && (Token != This)) {
- return EFI_SUCCESS;
- }
-
- NetMapRemoveItem (Map, Item, NULL);
-
- This->Status = EFI_ABORTED;
- This->Packet.RxData = NULL;
- gBS->SignalEvent (This->Event);
-
- if (Token != NULL) {
- return EFI_ABORTED;
- }
-
- return EFI_SUCCESS;
-}
-
-
-/**
- Cancel the user's receive/transmit request.
-
- @param[in] IpInstance The IP4 child
- @param[in] Token The token to cancel. If NULL, all token will be
- cancelled.
-
- @retval EFI_SUCCESS The token is cancelled
- @retval EFI_NOT_FOUND The token isn't found on either the
- transmit/receive queue
- @retval EFI_DEVICE_ERROR Not all token is cancelled when Token is NULL.
-
-**/
-EFI_STATUS
-Ip4Cancel (
- IN IP4_PROTOCOL *IpInstance,
- IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
- )
-{
- EFI_STATUS Status;
-
- //
- // First check the transmitted packet. Ip4CancelTxTokens returns
- // EFI_ABORTED to mean that the token has been cancelled when
- // token != NULL. So, return EFI_SUCCESS for this condition.
- //
- Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);
-
- if (EFI_ERROR (Status)) {
- if ((Token != NULL) && (Status == EFI_ABORTED)) {
- return EFI_SUCCESS;
- }
-
- return Status;
- }
-
- //
- // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT
- // for Token!=NULL and it is cancelled.
- //
- Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);
- //
- // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
- // events.
- //
- DispatchDpc ();
- if (EFI_ERROR (Status)) {
- if ((Token != NULL) && (Status == EFI_ABORTED)) {
- return EFI_SUCCESS;
- }
-
- return Status;
- }
-
- //
- // OK, if the Token is found when Token != NULL, the NetMapIterate
- // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
- //
- if (Token != NULL) {
- return EFI_NOT_FOUND;
- }
-
- //
- // If Token == NULL, cancel all the tokens. return error if no
- // all of them are cancelled.
- //
- if (!NetMapIsEmpty (&IpInstance->TxTokens) ||
- !NetMapIsEmpty (&IpInstance->RxTokens)) {
-
- return EFI_DEVICE_ERROR;
- }
-
- return EFI_SUCCESS;
-}
-
-
-/**
- Abort an asynchronous transmit or receive request.
-
- The Cancel() function is used to abort a pending transmit or receive request.
- If the token is in the transmit or receive request queues, after calling this
- function, Token->Status will be set to EFI_ABORTED and then Token->Event will
- be signaled. If the token is not in one of the queues, which usually means the
- asynchronous operation has completed, this function will not signal the token
- and EFI_NOT_FOUND is returned.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
- @param[in] Token Pointer to a token that has been issued by
- EFI_IP4_PROTOCOL.Transmit() or
- EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
- tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
- defined in EFI_IP4_PROTOCOL.Transmit().
-
- @retval EFI_SUCCESS The asynchronous I/O request was aborted and
- Token.->Event was signaled. When Token is NULL, all
- pending requests were aborted and their events were signaled.
- @retval EFI_INVALID_PARAMETER This is NULL.
- @retval EFI_NOT_STARTED This instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was
- not found in the transmit or receive queue. It has either completed
- or was not issued by Transmit() and Receive().
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Cancel (
- IN EFI_IP4_PROTOCOL *This,
- IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
- )
-{
- IP4_PROTOCOL *IpInstance;
- EFI_STATUS Status;
- EFI_TPL OldTpl;
-
- if (This == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
-
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
-
- if (IpInstance->State != IP4_STATE_CONFIGED) {
- Status = EFI_NOT_STARTED;
- goto ON_EXIT;
- }
-
- if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
- Status = EFI_NO_MAPPING;
- goto ON_EXIT;
- }
-
- Status = Ip4Cancel (IpInstance, Token);
-
-ON_EXIT:
- gBS->RestoreTPL (OldTpl);
- return Status;
-}
-
-
-/**
- Polls for incoming data packets and processes outgoing data packets.
-
- The Poll() function polls for incoming data packets and processes outgoing data
- packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
- function to increase the rate that data packets are moved between the communications
- device and the transmit and receive queues.
-
- In some systems the periodic timer event may not poll the underlying communications
- device fast enough to transmit and/or receive all data packets without missing
- incoming packets or dropping outgoing packets. Drivers and applications that are
- experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
- more often.
-
- @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
-
- @retval EFI_SUCCESS Incoming or outgoing data was processed.
- @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
- @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
- RARP, etc.) is not finished yet.
- @retval EFI_INVALID_PARAMETER This is NULL.
- @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
- @retval EFI_NOT_READY No incoming or outgoing data is processed.
- @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue.
- Consider increasing the polling rate.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiIp4Poll (
- IN EFI_IP4_PROTOCOL *This
- )
-{
- IP4_PROTOCOL *IpInstance;
- EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
-
- if (This == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
-
- if (IpInstance->State == IP4_STATE_UNCONFIGED) {
- return EFI_NOT_STARTED;
- }
-
- Mnp = IpInstance->Service->Mnp;
-
- //
- // Don't lock the Poll function to enable the deliver of
- // the packet polled up.
- //
- return Mnp->Poll (Mnp);
-}
-
-/**
- Decrease the life of the transmitted packets. If it is
- decreased to zero, cancel the packet. This function is
- called by Ip4PacketTimerTicking which time out both the
- received-but-not-delivered and transmitted-but-not-recycle
- packets.
-
- @param[in] Map The IP4 child's transmit map.
- @param[in] Item Current transmitted packet
- @param[in] Context Not used.
-
- @retval EFI_SUCCESS Always returns EFI_SUCCESS
-
-**/
-EFI_STATUS
-EFIAPI
-Ip4SentPacketTicking (
- IN NET_MAP *Map,
- IN NET_MAP_ITEM *Item,
- IN VOID *Context
- )
-{
- IP4_TXTOKEN_WRAP *Wrap;
-
- Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
- ASSERT (Wrap != NULL);
-
- if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
- Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
- }
-
- return EFI_SUCCESS;
-}
-
-
-/**
- The heart beat timer of IP4 service instance. It times out
- all of its IP4 children's received-but-not-delivered and
- transmitted-but-not-recycle packets, and provides time input
- for its IGMP protocol.
-
- @param[in] Event The IP4 service instance's heart beat timer.
- @param[in] Context The IP4 service instance.
-
-**/
-VOID
-EFIAPI
-Ip4TimerTicking (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- IP4_SERVICE *IpSb;
-
- IpSb = (IP4_SERVICE *) Context;
- NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
-
- Ip4PacketTimerTicking (IpSb);
- Ip4IgmpTicking (IpSb);
-}
+/** @file
+
+Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Ip4Impl.h"
+
+EFI_IPSEC2_PROTOCOL *mIpSec = NULL;
+
+/**
+ Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.
+
+ The GetModeData() function returns the current operational mode data for this
+ driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This
+ function is used optionally to retrieve the operational mode data of underlying
+ networks or drivers.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[out] Ip4ModeData Pointer to the EFI IPv4 Protocol mode data structure.
+ @param[out] MnpConfigData Pointer to the managed network configuration data structure.
+ @param[out] SnpModeData Pointer to the simple network mode data structure.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4GetModeData (
+ IN CONST EFI_IP4_PROTOCOL *This,
+ OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL,
+ OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
+ OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
+ );
+
+/**
+ Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
+
+ The Configure() function is used to set, change, or reset the operational
+ parameters and filter settings for this EFI IPv4 Protocol instance. Until these
+ parameters have been set, no network traffic can be sent or received by this
+ instance. Once the parameters have been reset (by calling this function with
+ IpConfigData set to NULL), no more traffic can be sent or received until these
+ parameters have been set again. Each EFI IPv4 Protocol instance can be started
+ and stopped independently of each other by enabling or disabling their receive
+ filter settings with the Configure() function.
+
+ When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
+ be appended as an alias address into the addresses list in the EFI IPv4 Protocol
+ driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
+ to retrieve the default IPv4 address if it is not available yet. Clients could
+ frequently call GetModeData() to check the status to ensure that the default IPv4
+ address is ready.
+
+ If operational parameters are reset or changed, any pending transmit and receive
+ requests will be cancelled. Their completion token status will be set to EFI_ABORTED
+ and their events will be signaled.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] IpConfigData Pointer to the EFI IPv4 Protocol configuration data structure.
+
+ @retval EFI_SUCCESS The driver instance was successfully opened.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ @retval EFI_UNSUPPORTED One or more of the following conditions is TRUE:
+ A configuration protocol (DHCP, BOOTP, RARP, etc.) could
+ not be located when clients choose to use the default IPv4
+ address. This EFI IPv4 Protocol implementation does not
+ support this requested filter or timeout setting.
+ @retval EFI_OUT_OF_RESOURCES The EFI IPv4 Protocol driver instance data could not be allocated.
+ @retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the
+ IPv4 address or subnet mask can be changed. The interface must
+ also be stopped when switching to/from raw packet mode.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv4
+ Protocol driver instance is not opened.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Configure (
+ IN EFI_IP4_PROTOCOL *This,
+ IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL
+ );
+
+/**
+ Joins and leaves multicast groups.
+
+ The Groups() function is used to join and leave multicast group sessions. Joining
+ a group will enable reception of matching multicast packets. Leaving a group will
+ disable the multicast packet reception.
+
+ If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] JoinFlag Set to TRUE to join the multicast group session and FALSE to leave.
+ @param[in] GroupAddress Pointer to the IPv4 multicast address.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
+ - This is NULL.
+ - JoinFlag is TRUE and GroupAddress is NULL.
+ - GroupAddress is not NULL and *GroupAddress is
+ not a multicast IPv4 address.
+ @retval EFI_NOT_STARTED This instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_OUT_OF_RESOURCES System resources could not be allocated.
+ @retval EFI_UNSUPPORTED This EFI IPv4 Protocol implementation does not support multicast groups.
+ @retval EFI_ALREADY_STARTED The group address is already in the group table (when
+ JoinFlag is TRUE).
+ @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE).
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Groups (
+ IN EFI_IP4_PROTOCOL *This,
+ IN BOOLEAN JoinFlag,
+ IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
+ );
+
+/**
+ Adds and deletes routing table entries.
+
+ The Routes() function adds a route to or deletes a route from the routing table.
+
+ Routes are determined by comparing the SubnetAddress with the destination IPv4
+ address arithmetically AND-ed with the SubnetMask. The gateway address must be
+ on the same subnet as the configured station address.
+
+ The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
+ The default route matches all destination IPv4 addresses that do not match any
+ other routes.
+
+ A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
+ IP address if it can be found in the ARP cache or on the local subnet. One automatic
+ nonroute entry will be inserted into the routing table for outgoing packets that
+ are addressed to a local subnet (gateway address of 0.0.0.0).
+
+ Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
+ IPv4 Protocol instances that use the default IPv4 address will also have copies
+ of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
+ copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
+ instances. As a result, client modification to the routing table will be lost.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. Set to
+ FALSE to add this route to the routing table. SubnetAddress
+ and SubnetMask are used as the key to each route entry.
+ @param[in] SubnetAddress The address of the subnet that needs to be routed.
+ @param[in] SubnetMask The subnet mask of SubnetAddress.
+ @param[in] GatewayAddress The unicast gateway IPv4 address for this route.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_NOT_STARTED The driver instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - This is NULL.
+ - SubnetAddress is NULL.
+ - SubnetMask is NULL.
+ - GatewayAddress is NULL.
+ - *SubnetAddress is not a valid subnet address.
+ - *SubnetMask is not a valid subnet mask.
+ - *GatewayAddress is not a valid unicast IPv4 address.
+ @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
+ @retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE).
+ @retval EFI_ACCESS_DENIED The route is already defined in the routing table (when
+ DeleteRoute is FALSE).
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Routes (
+ IN EFI_IP4_PROTOCOL *This,
+ IN BOOLEAN DeleteRoute,
+ IN EFI_IPv4_ADDRESS *SubnetAddress,
+ IN EFI_IPv4_ADDRESS *SubnetMask,
+ IN EFI_IPv4_ADDRESS *GatewayAddress
+ );
+
+/**
+ Places outgoing data packets into the transmit queue.
+
+ The Transmit() function places a sending request in the transmit queue of this
+ EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
+ errors occur, the event in the token will be signaled and the status is updated.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] Token Pointer to the transmit token.
+
+ @retval EFI_SUCCESS The data has been queued for transmission.
+ @retval EFI_NOT_STARTED This instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_INVALID_PARAMETER One or more pameters are invalid.
+ @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.Event
+ was already in the transmit queue.
+ @retval EFI_NOT_READY The completion token could not be queued because the transmit
+ queue is full.
+ @retval EFI_NOT_FOUND Not route is found to destination address.
+ @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.
+ @retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too
+ short to transmit.
+ @retval EFI_BAD_BUFFER_SIZE The length of the IPv4 header + option length + total data length is
+ greater than MTU (or greater than the maximum packet size if
+ Token.Packet.TxData.OverrideData.
+ DoNotFragment is TRUE.)
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Transmit (
+ IN EFI_IP4_PROTOCOL *This,
+ IN EFI_IP4_COMPLETION_TOKEN *Token
+ );
+
+/**
+ Places a receiving request into the receiving queue.
+
+ The Receive() function places a completion token into the receive packet queue.
+ This function is always asynchronous.
+
+ The Token.Event field in the completion token must be filled in by the caller
+ and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
+ driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
+ is signaled.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] Token Pointer to a token that is associated with the receive data descriptor.
+
+ @retval EFI_SUCCESS The receive completion token was cached.
+ @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
+ is not finished yet.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - This is NULL.
+ - Token is NULL.
+ - Token.Event is NULL.
+ @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system
+ resources (usually memory).
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ The EFI IPv4 Protocol instance has been reset to startup defaults.
+ EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
+ in the receive queue.
+ @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full.
+ @retval EFI_ICMP_ERROR An ICMP error packet was received.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Receive (
+ IN EFI_IP4_PROTOCOL *This,
+ IN EFI_IP4_COMPLETION_TOKEN *Token
+ );
+
+/**
+ Abort an asynchronous transmit or receive request.
+
+ The Cancel() function is used to abort a pending transmit or receive request.
+ If the token is in the transmit or receive request queues, after calling this
+ function, Token->Status will be set to EFI_ABORTED and then Token->Event will
+ be signaled. If the token is not in one of the queues, which usually means the
+ asynchronous operation has completed, this function will not signal the token
+ and EFI_NOT_FOUND is returned.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] Token Pointer to a token that has been issued by
+ EFI_IP4_PROTOCOL.Transmit() or
+ EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
+ tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
+ defined in EFI_IP4_PROTOCOL.Transmit().
+
+ @retval EFI_SUCCESS The asynchronous I/O request was aborted and
+ Token.->Event was signaled. When Token is NULL, all
+ pending requests were aborted and their events were signaled.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_NOT_STARTED This instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was
+ not found in the transmit or receive queue. It has either completed
+ or was not issued by Transmit() and Receive().
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Cancel (
+ IN EFI_IP4_PROTOCOL *This,
+ IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
+ );
+
+/**
+ Polls for incoming data packets and processes outgoing data packets.
+
+ The Poll() function polls for incoming data packets and processes outgoing data
+ packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
+ function to increase the rate that data packets are moved between the communications
+ device and the transmit and receive queues.
+
+ In some systems the periodic timer event may not poll the underlying communications
+ device fast enough to transmit and/or receive all data packets without missing
+ incoming packets or dropping outgoing packets. Drivers and applications that are
+ experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
+ more often.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Incoming or outgoing data was processed.
+ @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval EFI_NOT_READY No incoming or outgoing data is processed.
+ @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue.
+ Consider increasing the polling rate.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Poll (
+ IN EFI_IP4_PROTOCOL *This
+ );
+
+EFI_IP4_PROTOCOL
+mEfiIp4ProtocolTemplete = {
+ EfiIp4GetModeData,
+ EfiIp4Configure,
+ EfiIp4Groups,
+ EfiIp4Routes,
+ EfiIp4Transmit,
+ EfiIp4Receive,
+ EfiIp4Cancel,
+ EfiIp4Poll
+};
+
+/**
+ Gets the current operational settings for this instance of the EFI IPv4 Protocol driver.
+
+ The GetModeData() function returns the current operational mode data for this
+ driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This
+ function is used optionally to retrieve the operational mode data of underlying
+ networks or drivers.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[out] Ip4ModeData Pointer to the EFI IPv4 Protocol mode data structure.
+ @param[out] MnpConfigData Pointer to the managed network configuration data structure.
+ @param[out] SnpModeData Pointer to the simple network mode data structure.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4GetModeData (
+ IN CONST EFI_IP4_PROTOCOL *This,
+ OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL,
+ OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
+ OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
+ )
+{
+ IP4_PROTOCOL *IpInstance;
+ IP4_SERVICE *IpSb;
+ EFI_IP4_CONFIG_DATA *Config;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ IP4_ADDR Ip;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
+ IpSb = IpInstance->Service;
+
+ if (Ip4ModeData != NULL) {
+ //
+ // IsStarted is "whether the EfiIp4Configure has been called".
+ // IsConfigured is "whether the station address has been configured"
+ //
+ Ip4ModeData->IsStarted = (BOOLEAN)(IpInstance->State == IP4_STATE_CONFIGED);
+ CopyMem (&Ip4ModeData->ConfigData, &IpInstance->ConfigData, sizeof (Ip4ModeData->ConfigData));
+ Ip4ModeData->IsConfigured = FALSE;
+
+ Ip4ModeData->GroupCount = IpInstance->GroupCount;
+ Ip4ModeData->GroupTable = (EFI_IPv4_ADDRESS *) IpInstance->Groups;
+
+ Ip4ModeData->IcmpTypeCount = 23;
+ Ip4ModeData->IcmpTypeList = mIp4SupportedIcmp;
+
+ Ip4ModeData->RouteTable = NULL;
+ Ip4ModeData->RouteCount = 0;
+
+ Ip4ModeData->MaxPacketSize = IpSb->MaxPacketSize;
+
+ //
+ // return the current station address for this IP child. So,
+ // the user can get the default address through this. Some
+ // application wants to know it station address even it is
+ // using the default one, such as a ftp server.
+ //
+ if (Ip4ModeData->IsStarted) {
+ Config = &Ip4ModeData->ConfigData;
+
+ Ip = HTONL (IpInstance->Interface->Ip);
+ CopyMem (&Config->StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
+
+ Ip = HTONL (IpInstance->Interface->SubnetMask);
+ CopyMem (&Config->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));
+
+ Ip4ModeData->IsConfigured = IpInstance->Interface->Configured;
+
+ //
+ // Build a EFI route table for user from the internal route table.
+ //
+ Status = Ip4BuildEfiRouteTable (IpInstance);
+
+ if (EFI_ERROR (Status)) {
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+ }
+
+ Ip4ModeData->RouteTable = IpInstance->EfiRouteTable;
+ Ip4ModeData->RouteCount = IpInstance->EfiRouteCount;
+ }
+ }
+
+ //
+ // Get fresh mode data from MNP, since underlying media status may change
+ //
+ Status = IpSb->Mnp->GetModeData (IpSb->Mnp, MnpConfigData, SnpModeData);
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Config the MNP parameter used by IP. The IP driver use one MNP
+ child to transmit/receive frames. By default, it configures MNP
+ to receive unicast/multicast/broadcast. And it will enable/disable
+ the promiscous receive according to whether there is IP child
+ enable that or not. If Force is FALSE, it will iterate through
+ all the IP children to check whether the promiscuous receive
+ setting has been changed. If it hasn't been changed, it won't
+ reconfigure the MNP. If Force is TRUE, the MNP is configured no
+ matter whether that is changed or not.
+
+ @param[in] IpSb The IP4 service instance that is to be changed.
+ @param[in] Force Force the configuration or not.
+
+ @retval EFI_SUCCESS The MNP is successfully configured/reconfigured.
+ @retval Others Configuration failed.
+
+**/
+EFI_STATUS
+Ip4ServiceConfigMnp (
+ IN IP4_SERVICE *IpSb,
+ IN BOOLEAN Force
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *ProtoEntry;
+ IP4_INTERFACE *IpIf;
+ IP4_PROTOCOL *IpInstance;
+ BOOLEAN Reconfig;
+ BOOLEAN PromiscReceive;
+ EFI_STATUS Status;
+
+ Reconfig = FALSE;
+ PromiscReceive = FALSE;
+
+ if (!Force) {
+ //
+ // Iterate through the IP children to check whether promiscuous
+ // receive setting has been changed. Update the interface's receive
+ // filter also.
+ //
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
+
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
+ IpIf->PromiscRecv = FALSE;
+
+ NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {
+ IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP4_PROTOCOL, AddrLink);
+
+ if (IpInstance->ConfigData.AcceptPromiscuous) {
+ IpIf->PromiscRecv = TRUE;
+ PromiscReceive = TRUE;
+ }
+ }
+ }
+
+ //
+ // If promiscuous receive isn't changed, it isn't necessary to reconfigure.
+ //
+ if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {
+ return EFI_SUCCESS;
+ }
+
+ Reconfig = TRUE;
+ IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;
+ }
+
+ Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);
+
+ //
+ // recover the original configuration if failed to set the configure.
+ //
+ if (EFI_ERROR (Status) && Reconfig) {
+ IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;
+ }
+
+ return Status;
+}
+
+
+/**
+ The event handle for IP4 auto configuration. If IP is asked
+ to reconfigure the default address. The original default
+ interface and route table are removed as the default. If there
+ is active IP children using the default address, the interface
+ will remain valid until all the children have freed their
+ references. If IP is signalled when auto configuration is done,
+ it will configure the default interface and default route table
+ with the configuration information retrieved by IP4_CONFIGURE.
+
+ @param[in] Context The IP4 service binding instance.
+
+**/
+VOID
+EFIAPI
+Ip4AutoConfigCallBackDpc (
+ IN VOID *Context
+ )
+{
+ EFI_IP4_CONFIG_PROTOCOL *Ip4Config;
+ EFI_IP4_IPCONFIG_DATA *Data;
+ EFI_IP4_ROUTE_TABLE *RouteEntry;
+ IP4_SERVICE *IpSb;
+ IP4_ROUTE_TABLE *RouteTable;
+ IP4_INTERFACE *IpIf;
+ EFI_STATUS Status;
+ UINTN Len;
+ UINT32 Index;
+ IP4_ADDR StationAddress;
+ IP4_ADDR SubnetMask;
+ IP4_ADDR SubnetAddress;
+ IP4_ADDR GatewayAddress;
+
+ IpSb = (IP4_SERVICE *) Context;
+ NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
+
+ Ip4Config = IpSb->Ip4Config;
+
+ //
+ // IP is asked to do the reconfiguration. If the default interface
+ // has been configured, release the default interface and route
+ // table, then create a new one. If there are some IP children
+ // using it, the interface won't be physically freed until all the
+ // children have released their reference to it. Also remember to
+ // restart the receive on the default address. IP4 driver only receive
+ // frames on the default address, and when the default interface is
+ // freed, Ip4AcceptFrame won't be informed.
+ //
+ if (IpSb->ActiveEvent == IpSb->ReconfigEvent) {
+
+ if (IpSb->DefaultInterface->Configured) {
+ IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
+
+ if (IpIf == NULL) {
+ return;
+ }
+
+ RouteTable = Ip4CreateRouteTable ();
+
+ if (RouteTable == NULL) {
+ Ip4FreeInterface (IpIf, NULL);
+ return;
+ }
+
+ Ip4CancelReceive (IpSb->DefaultInterface);
+ Ip4FreeInterface (IpSb->DefaultInterface, NULL);
+ Ip4FreeRouteTable (IpSb->DefaultRouteTable);
+
+ IpSb->DefaultInterface = IpIf;
+ InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
+
+ IpSb->DefaultRouteTable = RouteTable;
+ Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
+ }
+
+ Ip4Config->Stop (Ip4Config);
+ Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);
+ return ;
+ }
+
+ //
+ // Get the configure data in two steps: get the length then the data.
+ //
+ Len = 0;
+
+ if (Ip4Config->GetData (Ip4Config, &Len, NULL) != EFI_BUFFER_TOO_SMALL) {
+ return ;
+ }
+
+ Data = AllocatePool (Len);
+
+ if (Data == NULL) {
+ return ;
+ }
+
+ Status = Ip4Config->GetData (Ip4Config, &Len, Data);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ IpIf = IpSb->DefaultInterface;
+
+ //
+ // If the default address has been configured don't change it.
+ // This is unlikely to happen if EFI_IP4_CONFIG protocol has
+ // informed us to reconfigure each time it wants to change the
+ // configuration parameters.
+ //
+ if (IpIf->Configured) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Set the default interface's address, then add a directed
+ // route for it, that is, the route whose nexthop is zero.
+ //
+ StationAddress = EFI_NTOHL (Data->StationAddress);
+ SubnetMask = EFI_NTOHL (Data->SubnetMask);
+ Status = Ip4SetAddress (IpIf, StationAddress, SubnetMask);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Ip4AddRoute (
+ IpSb->DefaultRouteTable,
+ StationAddress,
+ SubnetMask,
+ IP4_ALLZERO_ADDRESS
+ );
+
+ //
+ // Add routes returned by EFI_IP4_CONFIG protocol.
+ //
+ for (Index = 0; Index < Data->RouteTableSize; Index++) {
+ RouteEntry = &Data->RouteTable[Index];
+
+ SubnetAddress = EFI_NTOHL (RouteEntry->SubnetAddress);
+ SubnetMask = EFI_NTOHL (RouteEntry->SubnetMask);
+ GatewayAddress = EFI_NTOHL (RouteEntry->GatewayAddress);
+ Ip4AddRoute (IpSb->DefaultRouteTable, SubnetAddress, SubnetMask, GatewayAddress);
+ }
+
+ IpSb->State = IP4_SERVICE_CONFIGED;
+
+ Ip4SetVariableData (IpSb);
+
+ON_EXIT:
+ FreePool (Data);
+}
+
+/**
+ Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK.
+
+ @param Event The event that is signalled.
+ @param Context The IP4 service binding instance.
+
+**/
+VOID
+EFIAPI
+Ip4AutoConfigCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ IP4_SERVICE *IpSb;
+
+ IpSb = (IP4_SERVICE *) Context;
+ IpSb->ActiveEvent = Event;
+
+ //
+ // Request Ip4AutoConfigCallBackDpc as a DPC at TPL_CALLBACK
+ //
+ QueueDpc (TPL_CALLBACK, Ip4AutoConfigCallBackDpc, Context);
+}
+
+
+/**
+ Start the auto configuration for this IP service instance.
+ It will locates the EFI_IP4_CONFIG_PROTOCOL, then start the
+ auto configuration.
+
+ @param[in] IpSb The IP4 service instance to configure
+
+ @retval EFI_SUCCESS The auto configuration is successfull started
+ @retval Others Failed to start auto configuration.
+
+**/
+EFI_STATUS
+Ip4StartAutoConfig (
+ IN IP4_SERVICE *IpSb
+ )
+{
+ EFI_IP4_CONFIG_PROTOCOL *Ip4Config;
+ EFI_STATUS Status;
+
+ if (IpSb->State > IP4_SERVICE_UNSTARTED) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Create the DoneEvent and ReconfigEvent to call EFI_IP4_CONFIG
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ Ip4AutoConfigCallBack,
+ IpSb,
+ &IpSb->DoneEvent
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ Ip4AutoConfigCallBack,
+ IpSb,
+ &IpSb->ReconfigEvent
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_DONE_EVENT;
+ }
+
+ //
+ // Open the EFI_IP4_CONFIG protocol then start auto configure
+ //
+ Status = gBS->OpenProtocol (
+ IpSb->Controller,
+ &gEfiIp4ConfigProtocolGuid,
+ (VOID **) &Ip4Config,
+ IpSb->Image,
+ IpSb->Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto CLOSE_RECONFIG_EVENT;
+ }
+
+ Status = Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ IpSb->Controller,
+ &gEfiIp4ConfigProtocolGuid,
+ IpSb->Image,
+ IpSb->Controller
+ );
+
+ goto CLOSE_RECONFIG_EVENT;
+ }
+
+ IpSb->Ip4Config = Ip4Config;
+ IpSb->State = IP4_SERVICE_STARTED;
+ return Status;
+
+CLOSE_RECONFIG_EVENT:
+ gBS->CloseEvent (IpSb->ReconfigEvent);
+ IpSb->ReconfigEvent = NULL;
+
+CLOSE_DONE_EVENT:
+ gBS->CloseEvent (IpSb->DoneEvent);
+ IpSb->DoneEvent = NULL;
+
+ return Status;
+}
+
+
+/**
+ Intiialize the IP4_PROTOCOL structure to the unconfigured states.
+
+ @param IpSb The IP4 service instance.
+ @param IpInstance The IP4 child instance.
+
+**/
+VOID
+Ip4InitProtocol (
+ IN IP4_SERVICE *IpSb,
+ IN OUT IP4_PROTOCOL *IpInstance
+ )
+{
+ ASSERT ((IpSb != NULL) && (IpInstance != NULL));
+
+ ZeroMem (IpInstance, sizeof (IP4_PROTOCOL));
+
+ IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;
+ CopyMem (&IpInstance->Ip4Proto, &mEfiIp4ProtocolTemplete, sizeof (IpInstance->Ip4Proto));
+ IpInstance->State = IP4_STATE_UNCONFIGED;
+ IpInstance->Service = IpSb;
+
+ InitializeListHead (&IpInstance->Link);
+ NetMapInit (&IpInstance->RxTokens);
+ NetMapInit (&IpInstance->TxTokens);
+ InitializeListHead (&IpInstance->Received);
+ InitializeListHead (&IpInstance->Delivered);
+ InitializeListHead (&IpInstance->AddrLink);
+
+ EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);
+}
+
+
+/**
+ Configure the IP4 child. If the child is already configured,
+ change the configuration parameter. Otherwise configure it
+ for the first time. The caller should validate the configuration
+ before deliver them to it. It also don't do configure NULL.
+
+ @param[in, out] IpInstance The IP4 child to configure.
+ @param[in] Config The configure data.
+
+ @retval EFI_SUCCESS The IP4 child is successfully configured.
+ @retval EFI_DEVICE_ERROR Failed to free the pending transive or to
+ configure underlying MNP or other errors.
+ @retval EFI_NO_MAPPING The IP4 child is configured to use default
+ address, but the default address hasn't been
+ configured. The IP4 child doesn't need to be
+ reconfigured when default address is configured.
+ @retval EFI_OUT_OF_RESOURCES No more memory space is available.
+ @retval other Other error occurs.
+
+**/
+EFI_STATUS
+Ip4ConfigProtocol (
+ IN OUT IP4_PROTOCOL *IpInstance,
+ IN EFI_IP4_CONFIG_DATA *Config
+ )
+{
+ IP4_SERVICE *IpSb;
+ IP4_INTERFACE *IpIf;
+ EFI_STATUS Status;
+ IP4_ADDR Ip;
+ IP4_ADDR Netmask;
+ EFI_ARP_PROTOCOL *Arp;
+
+ IpSb = IpInstance->Service;
+
+ //
+ // User is changing packet filters. It must be stopped
+ // before the station address can be changed.
+ //
+ if (IpInstance->State == IP4_STATE_CONFIGED) {
+ //
+ // Cancel all the pending transmit/receive from upper layer
+ //
+ Status = Ip4Cancel (IpInstance, NULL);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Configure a fresh IP4 protocol instance. Create a route table.
+ // Each IP child has its own route table, which may point to the
+ // default table if it is using default address.
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ IpInstance->RouteTable = Ip4CreateRouteTable ();
+
+ if (IpInstance->RouteTable == NULL) {
+ return Status;
+ }
+
+ //
+ // Set up the interface.
+ //
+ CopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));
+ CopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));
+
+ Ip = NTOHL (Ip);
+ Netmask = NTOHL (Netmask);
+
+ if (!Config->UseDefaultAddress) {
+ //
+ // Find whether there is already an interface with the same
+ // station address. All the instances with the same station
+ // address shares one interface.
+ //
+ IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);
+
+ if (IpIf != NULL) {
+ NET_GET_REF (IpIf);
+
+ } else {
+ IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
+
+ if (IpIf == NULL) {
+ goto ON_ERROR;
+ }
+
+ Status = Ip4SetAddress (IpIf, Ip, Netmask);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ Ip4FreeInterface (IpIf, IpInstance);
+ goto ON_ERROR;
+ }
+
+ InsertTailList (&IpSb->Interfaces, &IpIf->Link);
+ }
+
+ //
+ // Add a route to this connected network in the route table
+ //
+ Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);
+
+ } else {
+ //
+ // Use the default address. If the default configuration hasn't
+ // been started, start it.
+ //
+ if (IpSb->State == IP4_SERVICE_UNSTARTED) {
+ Status = Ip4StartAutoConfig (IpSb);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+
+ IpIf = IpSb->DefaultInterface;
+ NET_GET_REF (IpSb->DefaultInterface);
+
+ //
+ // If default address is used, so is the default route table.
+ // Any route set by the instance has the precedence over the
+ // routes in the default route table. Link the default table
+ // after the instance's table. Routing will search the local
+ // table first.
+ //
+ NET_GET_REF (IpSb->DefaultRouteTable);
+ IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;
+ }
+
+ IpInstance->Interface = IpIf;
+ if (IpIf->Arp != NULL) {
+ Arp = NULL;
+ Status = gBS->OpenProtocol (
+ IpIf->ArpHandle,
+ &gEfiArpProtocolGuid,
+ (VOID **) &Arp,
+ gIp4DriverBinding.DriverBindingHandle,
+ IpInstance->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+ InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
+
+ CopyMem (&IpInstance->ConfigData, Config, sizeof (IpInstance->ConfigData));
+ IpInstance->State = IP4_STATE_CONFIGED;
+
+ //
+ // Although EFI_NO_MAPPING is an error code, the IP child has been
+ // successfully configured and doesn't need reconfiguration when
+ // default address is acquired.
+ //
+ if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
+ return EFI_NO_MAPPING;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ Ip4FreeRouteTable (IpInstance->RouteTable);
+ IpInstance->RouteTable = NULL;
+ return Status;
+}
+
+
+/**
+ Clean up the IP4 child, release all the resources used by it.
+
+ @param[in] IpInstance The IP4 child to clean up.
+
+ @retval EFI_SUCCESS The IP4 child is cleaned up
+ @retval EFI_DEVICE_ERROR Some resources failed to be released
+
+**/
+EFI_STATUS
+Ip4CleanProtocol (
+ IN IP4_PROTOCOL *IpInstance
+ )
+{
+ if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Some packets haven't been recycled. It is because either the
+ // user forgets to recycle the packets, or because the callback
+ // hasn't been called. Just leave it alone.
+ //
+ if (!IsListEmpty (&IpInstance->Delivered)) {
+ ;
+ }
+
+ if (IpInstance->Interface != NULL) {
+ RemoveEntryList (&IpInstance->AddrLink);
+ if (IpInstance->Interface->Arp != NULL) {
+ gBS->CloseProtocol (
+ IpInstance->Interface->ArpHandle,
+ &gEfiArpProtocolGuid,
+ gIp4DriverBinding.DriverBindingHandle,
+ IpInstance->Handle
+ );
+ }
+ Ip4FreeInterface (IpInstance->Interface, IpInstance);
+ IpInstance->Interface = NULL;
+ }
+
+ if (IpInstance->RouteTable != NULL) {
+ if (IpInstance->RouteTable->Next != NULL) {
+ Ip4FreeRouteTable (IpInstance->RouteTable->Next);
+ }
+
+ Ip4FreeRouteTable (IpInstance->RouteTable);
+ IpInstance->RouteTable = NULL;
+ }
+
+ if (IpInstance->EfiRouteTable != NULL) {
+ FreePool (IpInstance->EfiRouteTable);
+ IpInstance->EfiRouteTable = NULL;
+ IpInstance->EfiRouteCount = 0;
+ }
+
+ if (IpInstance->Groups != NULL) {
+ FreePool (IpInstance->Groups);
+ IpInstance->Groups = NULL;
+ IpInstance->GroupCount = 0;
+ }
+
+ NetMapClean (&IpInstance->TxTokens);
+
+ NetMapClean (&IpInstance->RxTokens);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Validate that Ip/Netmask pair is OK to be used as station
+ address. Only continuous netmasks are supported. and check
+ that StationAddress is a unicast address on the newtwork.
+
+ @param[in] Ip The IP address to validate
+ @param[in] Netmask The netmaks of the IP
+
+ @retval TRUE The Ip/Netmask pair is valid
+ @retval FALSE The Ip/Netmask pair is invalid
+
+**/
+BOOLEAN
+Ip4StationAddressValid (
+ IN IP4_ADDR Ip,
+ IN IP4_ADDR Netmask
+ )
+{
+ IP4_ADDR NetBrdcastMask;
+ INTN Len;
+ INTN Type;
+
+ //
+ // Only support the station address with 0.0.0.0/0 to enable DHCP client.
+ //
+ if (Netmask == IP4_ALLZERO_ADDRESS) {
+ return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);
+ }
+
+ //
+ // Only support the continuous net masks
+ //
+ if ((Len = NetGetMaskLength (Netmask)) == IP4_MASK_NUM) {
+ return FALSE;
+ }
+
+ //
+ // Station address can't be class D or class E address
+ //
+ if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {
+ return FALSE;
+ }
+
+ //
+ // Station address can't be subnet broadcast/net broadcast address
+ //
+ if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {
+ return FALSE;
+ }
+
+ NetBrdcastMask = gIp4AllMasks[MIN (Len, Type << 3)];
+
+ if (Ip == (Ip | ~NetBrdcastMask)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance.
+
+ The Configure() function is used to set, change, or reset the operational
+ parameters and filter settings for this EFI IPv4 Protocol instance. Until these
+ parameters have been set, no network traffic can be sent or received by this
+ instance. Once the parameters have been reset (by calling this function with
+ IpConfigData set to NULL), no more traffic can be sent or received until these
+ parameters have been set again. Each EFI IPv4 Protocol instance can be started
+ and stopped independently of each other by enabling or disabling their receive
+ filter settings with the Configure() function.
+
+ When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will
+ be appended as an alias address into the addresses list in the EFI IPv4 Protocol
+ driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL
+ to retrieve the default IPv4 address if it is not available yet. Clients could
+ frequently call GetModeData() to check the status to ensure that the default IPv4
+ address is ready.
+
+ If operational parameters are reset or changed, any pending transmit and receive
+ requests will be cancelled. Their completion token status will be set to EFI_ABORTED
+ and their events will be signaled.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] IpConfigData Pointer to the EFI IPv4 Protocol configuration data structure.
+
+ @retval EFI_SUCCESS The driver instance was successfully opened.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ @retval EFI_UNSUPPORTED One or more of the following conditions is TRUE:
+ A configuration protocol (DHCP, BOOTP, RARP, etc.) could
+ not be located when clients choose to use the default IPv4
+ address. This EFI IPv4 Protocol implementation does not
+ support this requested filter or timeout setting.
+ @retval EFI_OUT_OF_RESOURCES The EFI IPv4 Protocol driver instance data could not be allocated.
+ @retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the
+ IPv4 address or subnet mask can be changed. The interface must
+ also be stopped when switching to/from raw packet mode.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv4
+ Protocol driver instance is not opened.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Configure (
+ IN EFI_IP4_PROTOCOL *This,
+ IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL
+ )
+{
+ IP4_PROTOCOL *IpInstance;
+ EFI_IP4_CONFIG_DATA *Current;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ BOOLEAN AddrOk;
+ IP4_ADDR IpAddress;
+ IP4_ADDR SubnetMask;
+
+ //
+ // First, validate the parameters
+ //
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Validate the configuration first.
+ //
+ if (IpConfigData != NULL) {
+
+ CopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));
+ CopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));
+
+ IpAddress = NTOHL (IpAddress);
+ SubnetMask = NTOHL (SubnetMask);
+
+ //
+ // Check whether the station address is a valid unicast address
+ //
+ if (!IpConfigData->UseDefaultAddress) {
+ AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);
+
+ if (!AddrOk) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // User can only update packet filters when already configured.
+ // If it wants to change the station address, it must configure(NULL)
+ // the instance first.
+ //
+ if (IpInstance->State == IP4_STATE_CONFIGED) {
+ Current = &IpInstance->ConfigData;
+
+ if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {
+ Status = EFI_ALREADY_STARTED;
+ goto ON_EXIT;
+ }
+
+ if (!Current->UseDefaultAddress &&
+ (!EFI_IP4_EQUAL (&Current->StationAddress, &IpConfigData->StationAddress) ||
+ !EFI_IP4_EQUAL (&Current->SubnetMask, &IpConfigData->SubnetMask))) {
+ Status = EFI_ALREADY_STARTED;
+ goto ON_EXIT;
+ }
+
+ if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
+ Status = EFI_NO_MAPPING;
+ goto ON_EXIT;
+ }
+ }
+ }
+
+ //
+ // Configure the instance or clean it up.
+ //
+ if (IpConfigData != NULL) {
+ Status = Ip4ConfigProtocol (IpInstance, IpConfigData);
+ } else {
+ Status = Ip4CleanProtocol (IpInstance);
+
+ //
+ // Don't change the state if it is DESTROY, consider the following
+ // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
+ // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
+ // the unload fails miserably.
+ //
+ if (IpInstance->State == IP4_STATE_CONFIGED) {
+ IpInstance->State = IP4_STATE_UNCONFIGED;
+ }
+ }
+
+ //
+ // Update the MNP's configure data. Ip4ServiceConfigMnp will check
+ // whether it is necessary to reconfigure the MNP.
+ //
+ Ip4ServiceConfigMnp (IpInstance->Service, FALSE);
+
+ //
+ // Update the variable data.
+ //
+ Ip4SetVariableData (IpInstance->Service);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+
+}
+
+
+/**
+ Change the IP4 child's multicast setting. The caller
+ should make sure that the parameters is valid.
+
+ @param[in] IpInstance The IP4 child to change the setting.
+ @param[in] JoinFlag TRUE to join the group, otherwise leave it
+ @param[in] GroupAddress The target group address
+
+ @retval EFI_ALREADY_STARTED Want to join the group, but already a member of it
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
+ @retval EFI_DEVICE_ERROR Failed to set the group configuraton
+ @retval EFI_SUCCESS Successfully updated the group setting.
+ @retval EFI_NOT_FOUND Try to leave the group which it isn't a member.
+
+**/
+EFI_STATUS
+Ip4Groups (
+ IN IP4_PROTOCOL *IpInstance,
+ IN BOOLEAN JoinFlag,
+ IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
+ )
+{
+ IP4_ADDR *Members;
+ IP4_ADDR Group;
+ UINT32 Index;
+
+ //
+ // Add it to the instance's Groups, and join the group by IGMP.
+ // IpInstance->Groups is in network byte order. IGMP operates in
+ // host byte order
+ //
+ if (JoinFlag) {
+ //
+ // When JoinFlag is TRUE, GroupAddress shouldn't be NULL.
+ //
+ ASSERT (GroupAddress != NULL);
+ CopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));
+
+ for (Index = 0; Index < IpInstance->GroupCount; Index++) {
+ if (IpInstance->Groups[Index] == Group) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);
+
+ if (Members == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {
+ FreePool (Members);
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (IpInstance->Groups != NULL) {
+ FreePool (IpInstance->Groups);
+ }
+
+ IpInstance->Groups = Members;
+ IpInstance->GroupCount++;
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Leave the group. Leave all the groups if GroupAddress is NULL.
+ // Must iterate from the end to the beginning because the GroupCount
+ // is decreamented each time an address is removed..
+ //
+ for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {
+ Group = IpInstance->Groups[Index - 1];
+
+ if ((GroupAddress == NULL) || EFI_IP4_EQUAL (&Group, GroupAddress)) {
+ if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);
+ IpInstance->GroupCount--;
+
+ if (IpInstance->GroupCount == 0) {
+ ASSERT (Index == 1);
+
+ FreePool (IpInstance->Groups);
+ IpInstance->Groups = NULL;
+ }
+
+ if (GroupAddress != NULL) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);
+}
+
+
+/**
+ Joins and leaves multicast groups.
+
+ The Groups() function is used to join and leave multicast group sessions. Joining
+ a group will enable reception of matching multicast packets. Leaving a group will
+ disable the multicast packet reception.
+
+ If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] JoinFlag Set to TRUE to join the multicast group session and FALSE to leave.
+ @param[in] GroupAddress Pointer to the IPv4 multicast address.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
+ - This is NULL.
+ - JoinFlag is TRUE and GroupAddress is NULL.
+ - GroupAddress is not NULL and *GroupAddress is
+ not a multicast IPv4 address.
+ @retval EFI_NOT_STARTED This instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_OUT_OF_RESOURCES System resources could not be allocated.
+ @retval EFI_UNSUPPORTED This EFI IPv4 Protocol implementation does not support multicast groups.
+ @retval EFI_ALREADY_STARTED The group address is already in the group table (when
+ JoinFlag is TRUE).
+ @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE).
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Groups (
+ IN EFI_IP4_PROTOCOL *This,
+ IN BOOLEAN JoinFlag,
+ IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
+ )
+{
+ IP4_PROTOCOL *IpInstance;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ IP4_ADDR McastIp;
+
+ if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GroupAddress != NULL) {
+ CopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));
+
+ if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (IpInstance->State != IP4_STATE_CONFIGED) {
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+ }
+
+ if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
+ Status = EFI_NO_MAPPING;
+ goto ON_EXIT;
+ }
+
+ Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Adds and deletes routing table entries.
+
+ The Routes() function adds a route to or deletes a route from the routing table.
+
+ Routes are determined by comparing the SubnetAddress with the destination IPv4
+ address arithmetically AND-ed with the SubnetMask. The gateway address must be
+ on the same subnet as the configured station address.
+
+ The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
+ The default route matches all destination IPv4 addresses that do not match any
+ other routes.
+
+ A GatewayAddress that is zero is a nonroute. Packets are sent to the destination
+ IP address if it can be found in the ARP cache or on the local subnet. One automatic
+ nonroute entry will be inserted into the routing table for outgoing packets that
+ are addressed to a local subnet (gateway address of 0.0.0.0).
+
+ Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI
+ IPv4 Protocol instances that use the default IPv4 address will also have copies
+ of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these
+ copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its
+ instances. As a result, client modification to the routing table will be lost.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. Set to
+ FALSE to add this route to the routing table. SubnetAddress
+ and SubnetMask are used as the key to each route entry.
+ @param[in] SubnetAddress The address of the subnet that needs to be routed.
+ @param[in] SubnetMask The subnet mask of SubnetAddress.
+ @param[in] GatewayAddress The unicast gateway IPv4 address for this route.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_NOT_STARTED The driver instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - This is NULL.
+ - SubnetAddress is NULL.
+ - SubnetMask is NULL.
+ - GatewayAddress is NULL.
+ - *SubnetAddress is not a valid subnet address.
+ - *SubnetMask is not a valid subnet mask.
+ - *GatewayAddress is not a valid unicast IPv4 address.
+ @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
+ @retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE).
+ @retval EFI_ACCESS_DENIED The route is already defined in the routing table (when
+ DeleteRoute is FALSE).
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Routes (
+ IN EFI_IP4_PROTOCOL *This,
+ IN BOOLEAN DeleteRoute,
+ IN EFI_IPv4_ADDRESS *SubnetAddress,
+ IN EFI_IPv4_ADDRESS *SubnetMask,
+ IN EFI_IPv4_ADDRESS *GatewayAddress
+ )
+{
+ IP4_PROTOCOL *IpInstance;
+ IP4_INTERFACE *IpIf;
+ IP4_ADDR Dest;
+ IP4_ADDR Netmask;
+ IP4_ADDR Nexthop;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // First, validate the parameters
+ //
+ if ((This == NULL) || (SubnetAddress == NULL) ||
+ (SubnetMask == NULL) || (GatewayAddress == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (IpInstance->State != IP4_STATE_CONFIGED) {
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+ }
+
+ if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
+ Status = EFI_NO_MAPPING;
+ goto ON_EXIT;
+ }
+
+ CopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));
+ CopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));
+ CopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));
+
+ Dest = NTOHL (Dest);
+ Netmask = NTOHL (Netmask);
+ Nexthop = NTOHL (Nexthop);
+
+ IpIf = IpInstance->Interface;
+
+ if (!IP4_IS_VALID_NETMASK (Netmask)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ //
+ // the gateway address must be a unicast on the connected network if not zero.
+ //
+ if ((Nexthop != IP4_ALLZERO_ADDRESS) &&
+ (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||
+ IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {
+
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (DeleteRoute) {
+ Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
+ } else {
+ Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Check whether the user's token or event has already
+ been enqueued on IP4's list.
+
+ @param[in] Map The container of either user's transmit or receive
+ token.
+ @param[in] Item Current item to check against
+ @param[in] Context The Token to check againist.
+
+ @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP
+ @retval EFI_SUCCESS The current item isn't the same token/event as the
+ context.
+
+**/
+EFI_STATUS
+EFIAPI
+Ip4TokenExist (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ )
+{
+ EFI_IP4_COMPLETION_TOKEN *Token;
+ EFI_IP4_COMPLETION_TOKEN *TokenInItem;
+
+ Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
+ TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;
+
+ if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Validate the user's token against current station address.
+
+ @param[in] Token User's token to validate.
+ @param[in] IpIf The IP4 child's interface.
+ @param[in] RawData Set to TRUE to send unformatted packets.
+
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.
+ @retval EFI_BAD_BUFFER_SIZE The user's option/data is too long.
+ @retval EFI_SUCCESS The token is valid.
+
+**/
+EFI_STATUS
+Ip4TxTokenValid (
+ IN EFI_IP4_COMPLETION_TOKEN *Token,
+ IN IP4_INTERFACE *IpIf,
+ IN BOOLEAN RawData
+ )
+{
+ EFI_IP4_TRANSMIT_DATA *TxData;
+ EFI_IP4_OVERRIDE_DATA *Override;
+ IP4_ADDR Src;
+ IP4_ADDR Gateway;
+ UINT32 Offset;
+ UINT32 Index;
+ UINT32 HeadLen;
+
+ if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TxData = Token->Packet.TxData;
+
+ //
+ // Check the fragment table: no empty fragment, and length isn't bogus.
+ //
+ if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Offset = TxData->TotalDataLength;
+
+ if (Offset > IP4_MAX_PACKET_SIZE) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ for (Index = 0; Index < TxData->FragmentCount; Index++) {
+ if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
+ (TxData->FragmentTable[Index].FragmentLength == 0)) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Offset -= TxData->FragmentTable[Index].FragmentLength;
+ }
+
+ if (Offset != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // NOTE that OptionsLength/OptionsBuffer/OverrideData are ignored if RawData
+ // is TRUE.
+ //
+ if (RawData) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check the IP options: no more than 40 bytes and format is OK
+ //
+ if (TxData->OptionsLength != 0) {
+ if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Check the source and gateway: they must be a valid unicast.
+ // Gateway must also be on the connected network.
+ //
+ if (TxData->OverrideData != NULL) {
+ Override = TxData->OverrideData;
+
+ CopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));
+ CopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));
+
+ Src = NTOHL (Src);
+ Gateway = NTOHL (Gateway);
+
+ if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||
+ (Src == IP4_ALLONE_ADDRESS) ||
+ IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If gateway isn't zero, it must be a unicast address, and
+ // on the connected network.
+ //
+ if ((Gateway != IP4_ALLZERO_ADDRESS) &&
+ ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||
+ !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||
+ IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Check the packet length: Head length and packet length all has a limit
+ //
+ HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);
+
+ if ((HeadLen > IP4_MAX_HEADLEN) ||
+ (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {
+
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The callback function for the net buffer which wraps the user's
+ transmit token. Although it seems this function is pretty simple,
+ there are some subtle things.
+ When user requests the IP to transmit a packet by passing it a
+ token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data
+ is wrapped in an net buffer. the net buffer's Free function is
+ set to Ip4FreeTxToken. The Token and token wrap are added to the
+ IP child's TxToken map. Then the buffer is passed to Ip4Output for
+ transmission. If something error happened before that, the buffer
+ is freed, which in turn will free the token wrap. The wrap may
+ have been added to the TxToken map or not, and the user's event
+ shouldn't be fired because we are still in the EfiIp4Transmit. If
+ the buffer has been sent by Ip4Output, it should be removed from
+ the TxToken map and user's event signaled. The token wrap and buffer
+ are bound together. Check the comments in Ip4Output for information
+ about IP fragmentation.
+
+ @param[in] Context The token's wrap
+
+**/
+VOID
+EFIAPI
+Ip4FreeTxToken (
+ IN VOID *Context
+ )
+{
+ IP4_TXTOKEN_WRAP *Wrap;
+ NET_MAP_ITEM *Item;
+
+ Wrap = (IP4_TXTOKEN_WRAP *) Context;
+
+ //
+ // Signal IpSecRecycleEvent to inform IPsec free the memory
+ //
+ if (Wrap->IpSecRecycleSignal != NULL) {
+ gBS->SignalEvent (Wrap->IpSecRecycleSignal);
+ }
+
+ //
+ // Find the token in the instance's map. EfiIp4Transmit put the
+ // token to the map. If that failed, NetMapFindKey will return NULL.
+ //
+ Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
+
+ if (Item != NULL) {
+ NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
+ }
+
+ if (Wrap->Sent) {
+ gBS->SignalEvent (Wrap->Token->Event);
+
+ //
+ // Dispatch the DPC queued by the NotifyFunction of Token->Event.
+ //
+ DispatchDpc ();
+ }
+
+ FreePool (Wrap);
+}
+
+
+/**
+ The callback function to Ip4Output to update the transmit status.
+
+ @param Ip4Instance The Ip4Instance that request the transmit.
+ @param Packet The user's transmit request
+ @param IoStatus The result of the transmission
+ @param Flag Not used during transmission
+ @param Context The token's wrap.
+
+**/
+VOID
+Ip4OnPacketSent (
+ IP4_PROTOCOL *Ip4Instance,
+ NET_BUF *Packet,
+ EFI_STATUS IoStatus,
+ UINT32 Flag,
+ VOID *Context
+ )
+{
+ IP4_TXTOKEN_WRAP *Wrap;
+
+ //
+ // This is the transmission request from upper layer,
+ // not the IP4 driver itself.
+ //
+ ASSERT (Ip4Instance != NULL);
+
+ //
+ // The first fragment of the packet has been sent. Update
+ // the token's status. That is, if fragmented, the transmit's
+ // status is the first fragment's status. The Wrap will be
+ // release when all the fragments are release. Check the comments
+ // in Ip4FreeTxToken and Ip4Output for information.
+ //
+ Wrap = (IP4_TXTOKEN_WRAP *) Context;
+ Wrap->Token->Status = IoStatus;
+
+ NetbufFree (Wrap->Packet);
+}
+
+
+/**
+ Places outgoing data packets into the transmit queue.
+
+ The Transmit() function places a sending request in the transmit queue of this
+ EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
+ errors occur, the event in the token will be signaled and the status is updated.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] Token Pointer to the transmit token.
+
+ @retval EFI_SUCCESS The data has been queued for transmission.
+ @retval EFI_NOT_STARTED This instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_INVALID_PARAMETER One or more pameters are invalid.
+ @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.Event
+ was already in the transmit queue.
+ @retval EFI_NOT_READY The completion token could not be queued because the transmit
+ queue is full.
+ @retval EFI_NOT_FOUND Not route is found to destination address.
+ @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.
+ @retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too
+ short to transmit.
+ @retval EFI_BAD_BUFFER_SIZE The length of the IPv4 header + option length + total data length is
+ greater than MTU (or greater than the maximum packet size if
+ Token.Packet.TxData.OverrideData.
+ DoNotFragment is TRUE.)
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Transmit (
+ IN EFI_IP4_PROTOCOL *This,
+ IN EFI_IP4_COMPLETION_TOKEN *Token
+ )
+{
+ IP4_SERVICE *IpSb;
+ IP4_PROTOCOL *IpInstance;
+ IP4_INTERFACE *IpIf;
+ IP4_TXTOKEN_WRAP *Wrap;
+ EFI_IP4_TRANSMIT_DATA *TxData;
+ EFI_IP4_CONFIG_DATA *Config;
+ EFI_IP4_OVERRIDE_DATA *Override;
+ IP4_HEAD Head;
+ IP4_ADDR GateWay;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ BOOLEAN DontFragment;
+ UINT32 HeadLen;
+ UINT8 RawHdrLen;
+ UINT32 OptionsLength;
+ UINT8 *OptionsBuffer;
+ VOID *FirstFragment;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
+
+ if (IpInstance->State != IP4_STATE_CONFIGED) {
+ return EFI_NOT_STARTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ IpSb = IpInstance->Service;
+ IpIf = IpInstance->Interface;
+ Config = &IpInstance->ConfigData;
+
+ if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
+ Status = EFI_NO_MAPPING;
+ goto ON_EXIT;
+ }
+
+ //
+ // make sure that token is properly formated
+ //
+ Status = Ip4TxTokenValid (Token, IpIf, Config->RawData);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Check whether the token or signal already existed.
+ //
+ if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {
+ Status = EFI_ACCESS_DENIED;
+ goto ON_EXIT;
+ }
+
+ //
+ // Build the IP header, need to fill in the Tos, TotalLen, Id,
+ // fragment, Ttl, protocol, Src, and Dst.
+ //
+ TxData = Token->Packet.TxData;
+
+ FirstFragment = NULL;
+
+ if (Config->RawData) {
+ //
+ // When RawData is TRUE, first buffer in FragmentTable points to a raw
+ // IPv4 fragment including IPv4 header and options.
+ //
+ FirstFragment = TxData->FragmentTable[0].FragmentBuffer;
+ CopyMem (&RawHdrLen, FirstFragment, sizeof (UINT8));
+
+ RawHdrLen = (UINT8) (RawHdrLen & 0x0f);
+ if (RawHdrLen < 5) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RawHdrLen = (UINT8) (RawHdrLen << 2);
+
+ CopyMem (&Head, FirstFragment, IP4_MIN_HEADLEN);
+
+ Ip4NtohHead (&Head);
+ HeadLen = 0;
+ DontFragment = IP4_DO_NOT_FRAGMENT (Head.Fragment);
+
+ if (!DontFragment) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GateWay = IP4_ALLZERO_ADDRESS;
+
+ //
+ // Get IPv4 options from first fragment.
+ //
+ if (RawHdrLen == IP4_MIN_HEADLEN) {
+ OptionsLength = 0;
+ OptionsBuffer = NULL;
+ } else {
+ OptionsLength = RawHdrLen - IP4_MIN_HEADLEN;
+ OptionsBuffer = (UINT8 *) FirstFragment + IP4_MIN_HEADLEN;
+ }
+
+ //
+ // Trim off IPv4 header and options from first fragment.
+ //
+ TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment + RawHdrLen;
+ TxData->FragmentTable[0].FragmentLength = TxData->FragmentTable[0].FragmentLength - RawHdrLen;
+ } else {
+ CopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));
+ Head.Dst = NTOHL (Head.Dst);
+
+ if (TxData->OverrideData != NULL) {
+ Override = TxData->OverrideData;
+ Head.Protocol = Override->Protocol;
+ Head.Tos = Override->TypeOfService;
+ Head.Ttl = Override->TimeToLive;
+ DontFragment = Override->DoNotFragment;
+
+ CopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));
+ CopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));
+
+ Head.Src = NTOHL (Head.Src);
+ GateWay = NTOHL (GateWay);
+ } else {
+ Head.Src = IpIf->Ip;
+ GateWay = IP4_ALLZERO_ADDRESS;
+ Head.Protocol = Config->DefaultProtocol;
+ Head.Tos = Config->TypeOfService;
+ Head.Ttl = Config->TimeToLive;
+ DontFragment = Config->DoNotFragment;
+ }
+
+ Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);
+ HeadLen = (TxData->OptionsLength + 3) & (~0x03);
+
+ OptionsLength = TxData->OptionsLength;
+ OptionsBuffer = (UINT8 *) (TxData->OptionsBuffer);
+ }
+
+ //
+ // If don't fragment and fragment needed, return error
+ //
+ if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->MaxPacketSize)) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto ON_EXIT;
+ }
+
+ //
+ // OK, it survives all the validation check. Wrap the token in
+ // a IP4_TXTOKEN_WRAP and the data in a netbuf
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ Wrap = AllocateZeroPool (sizeof (IP4_TXTOKEN_WRAP));
+ if (Wrap == NULL) {
+ goto ON_EXIT;
+ }
+
+ Wrap->IpInstance = IpInstance;
+ Wrap->Token = Token;
+ Wrap->Sent = FALSE;
+ Wrap->Life = IP4_US_TO_SEC (Config->TransmitTimeout);
+ Wrap->Packet = NetbufFromExt (
+ (NET_FRAGMENT *) TxData->FragmentTable,
+ TxData->FragmentCount,
+ IP4_MAX_HEADLEN,
+ 0,
+ Ip4FreeTxToken,
+ Wrap
+ );
+
+ if (Wrap->Packet == NULL) {
+ FreePool (Wrap);
+ goto ON_EXIT;
+ }
+
+ Token->Status = EFI_NOT_READY;
+
+ if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {
+ //
+ // NetbufFree will call Ip4FreeTxToken, which in turn will
+ // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been
+ // enqueued.
+ //
+ if (Config->RawData) {
+ //
+ // Restore pointer of first fragment in RawData mode.
+ //
+ TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
+ }
+
+ NetbufFree (Wrap->Packet);
+ goto ON_EXIT;
+ }
+
+ //
+ // Mark the packet sent before output it. Mark it not sent again if the
+ // returned status is not EFI_SUCCESS;
+ //
+ Wrap->Sent = TRUE;
+
+ Status = Ip4Output (
+ IpSb,
+ IpInstance,
+ Wrap->Packet,
+ &Head,
+ OptionsBuffer,
+ OptionsLength,
+ GateWay,
+ Ip4OnPacketSent,
+ Wrap
+ );
+
+ if (EFI_ERROR (Status)) {
+ Wrap->Sent = FALSE;
+
+ if (Config->RawData) {
+ //
+ // Restore pointer of first fragment in RawData mode.
+ //
+ TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
+ }
+
+ NetbufFree (Wrap->Packet);
+ }
+
+ if (Config->RawData) {
+ //
+ // Restore pointer of first fragment in RawData mode.
+ //
+ TxData->FragmentTable[0].FragmentBuffer = (UINT8 *) FirstFragment;
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Places a receiving request into the receiving queue.
+
+ The Receive() function places a completion token into the receive packet queue.
+ This function is always asynchronous.
+
+ The Token.Event field in the completion token must be filled in by the caller
+ and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol
+ driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
+ is signaled.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] Token Pointer to a token that is associated with the receive data descriptor.
+
+ @retval EFI_SUCCESS The receive completion token was cached.
+ @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, RARP, etc.)
+ is not finished yet.
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
+ - This is NULL.
+ - Token is NULL.
+ - Token.Event is NULL.
+ @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system
+ resources (usually memory).
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ The EFI IPv4 Protocol instance has been reset to startup defaults.
+ EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
+ in the receive queue.
+ @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full.
+ @retval EFI_ICMP_ERROR An ICMP error packet was received.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Receive (
+ IN EFI_IP4_PROTOCOL *This,
+ IN EFI_IP4_COMPLETION_TOKEN *Token
+ )
+{
+ IP4_PROTOCOL *IpInstance;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // First validate the parameters
+ //
+ if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (IpInstance->State != IP4_STATE_CONFIGED) {
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+ }
+
+ //
+ // Check whether the toke is already on the receive queue.
+ //
+ Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_ACCESS_DENIED;
+ goto ON_EXIT;
+ }
+
+ //
+ // Queue the token then check whether there is pending received packet.
+ //
+ Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = Ip4InstanceDeliverPacket (IpInstance);
+
+ //
+ // Dispatch the DPC queued by the NotifyFunction of this instane's receive
+ // event.
+ //
+ DispatchDpc ();
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Cancel the transmitted but not recycled packet. If a matching
+ token is found, it will call Ip4CancelPacket to cancel the
+ packet. Ip4CancelPacket will cancel all the fragments of the
+ packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP
+ will be deleted from the Map, and user's event signalled.
+ Because Ip4CancelPacket and other functions are all called in
+ line, so, after Ip4CancelPacket returns, the Item has been freed.
+
+ @param[in] Map The IP4 child's transmit queue
+ @param[in] Item The current transmitted packet to test.
+ @param[in] Context The user's token to cancel.
+
+ @retval EFI_SUCCESS Continue to check the next Item.
+ @retval EFI_ABORTED The user's Token (Token != NULL) is cancelled.
+
+**/
+EFI_STATUS
+EFIAPI
+Ip4CancelTxTokens (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ )
+{
+ EFI_IP4_COMPLETION_TOKEN *Token;
+ IP4_TXTOKEN_WRAP *Wrap;
+
+ Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
+
+ //
+ // Return EFI_SUCCESS to check the next item in the map if
+ // this one doesn't match.
+ //
+ if ((Token != NULL) && (Token != Item->Key)) {
+ return EFI_SUCCESS;
+ }
+
+ Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
+ ASSERT (Wrap != NULL);
+
+ //
+ // Don't access the Item, Wrap and Token's members after this point.
+ // Item and wrap has been freed. And we no longer own the Token.
+ //
+ Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
+
+ //
+ // If only one item is to be cancel, return EFI_ABORTED to stop
+ // iterating the map any more.
+ //
+ if (Token != NULL) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Cancel the receive request. This is quiet simple, because
+ it is only enqueued in our local receive map.
+
+ @param[in] Map The IP4 child's receive queue
+ @param[in] Item Current receive request to cancel.
+ @param[in] Context The user's token to cancel
+
+ @retval EFI_SUCCESS Continue to check the next receive request on the
+ queue.
+ @retval EFI_ABORTED The user's token (token != NULL) has been
+ cancelled.
+
+**/
+EFI_STATUS
+EFIAPI
+Ip4CancelRxTokens (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ )
+{
+ EFI_IP4_COMPLETION_TOKEN *Token;
+ EFI_IP4_COMPLETION_TOKEN *This;
+
+ Token = (EFI_IP4_COMPLETION_TOKEN *) Context;
+ This = Item->Key;
+
+ if ((Token != NULL) && (Token != This)) {
+ return EFI_SUCCESS;
+ }
+
+ NetMapRemoveItem (Map, Item, NULL);
+
+ This->Status = EFI_ABORTED;
+ This->Packet.RxData = NULL;
+ gBS->SignalEvent (This->Event);
+
+ if (Token != NULL) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Cancel the user's receive/transmit request.
+
+ @param[in] IpInstance The IP4 child
+ @param[in] Token The token to cancel. If NULL, all token will be
+ cancelled.
+
+ @retval EFI_SUCCESS The token is cancelled
+ @retval EFI_NOT_FOUND The token isn't found on either the
+ transmit/receive queue
+ @retval EFI_DEVICE_ERROR Not all token is cancelled when Token is NULL.
+
+**/
+EFI_STATUS
+Ip4Cancel (
+ IN IP4_PROTOCOL *IpInstance,
+ IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // First check the transmitted packet. Ip4CancelTxTokens returns
+ // EFI_ABORTED to mean that the token has been cancelled when
+ // token != NULL. So, return EFI_SUCCESS for this condition.
+ //
+ Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);
+
+ if (EFI_ERROR (Status)) {
+ if ((Token != NULL) && (Status == EFI_ABORTED)) {
+ return EFI_SUCCESS;
+ }
+
+ return Status;
+ }
+
+ //
+ // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT
+ // for Token!=NULL and it is cancelled.
+ //
+ Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);
+ //
+ // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
+ // events.
+ //
+ DispatchDpc ();
+ if (EFI_ERROR (Status)) {
+ if ((Token != NULL) && (Status == EFI_ABORTED)) {
+ return EFI_SUCCESS;
+ }
+
+ return Status;
+ }
+
+ //
+ // OK, if the Token is found when Token != NULL, the NetMapIterate
+ // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
+ //
+ if (Token != NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If Token == NULL, cancel all the tokens. return error if no
+ // all of them are cancelled.
+ //
+ if (!NetMapIsEmpty (&IpInstance->TxTokens) ||
+ !NetMapIsEmpty (&IpInstance->RxTokens)) {
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Abort an asynchronous transmit or receive request.
+
+ The Cancel() function is used to abort a pending transmit or receive request.
+ If the token is in the transmit or receive request queues, after calling this
+ function, Token->Status will be set to EFI_ABORTED and then Token->Event will
+ be signaled. If the token is not in one of the queues, which usually means the
+ asynchronous operation has completed, this function will not signal the token
+ and EFI_NOT_FOUND is returned.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+ @param[in] Token Pointer to a token that has been issued by
+ EFI_IP4_PROTOCOL.Transmit() or
+ EFI_IP4_PROTOCOL.Receive(). If NULL, all pending
+ tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is
+ defined in EFI_IP4_PROTOCOL.Transmit().
+
+ @retval EFI_SUCCESS The asynchronous I/O request was aborted and
+ Token.->Event was signaled. When Token is NULL, all
+ pending requests were aborted and their events were signaled.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_NOT_STARTED This instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was
+ not found in the transmit or receive queue. It has either completed
+ or was not issued by Transmit() and Receive().
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Cancel (
+ IN EFI_IP4_PROTOCOL *This,
+ IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
+ )
+{
+ IP4_PROTOCOL *IpInstance;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (IpInstance->State != IP4_STATE_CONFIGED) {
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+ }
+
+ if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
+ Status = EFI_NO_MAPPING;
+ goto ON_EXIT;
+ }
+
+ Status = Ip4Cancel (IpInstance, Token);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Polls for incoming data packets and processes outgoing data packets.
+
+ The Poll() function polls for incoming data packets and processes outgoing data
+ packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll()
+ function to increase the rate that data packets are moved between the communications
+ device and the transmit and receive queues.
+
+ In some systems the periodic timer event may not poll the underlying communications
+ device fast enough to transmit and/or receive all data packets without missing
+ incoming packets or dropping outgoing packets. Drivers and applications that are
+ experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function
+ more often.
+
+ @param[in] This Pointer to the EFI_IP4_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Incoming or outgoing data was processed.
+ @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started.
+ @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP,
+ RARP, etc.) is not finished yet.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval EFI_NOT_READY No incoming or outgoing data is processed.
+ @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue.
+ Consider increasing the polling rate.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIp4Poll (
+ IN EFI_IP4_PROTOCOL *This
+ )
+{
+ IP4_PROTOCOL *IpInstance;
+ EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
+
+ if (IpInstance->State == IP4_STATE_UNCONFIGED) {
+ return EFI_NOT_STARTED;
+ }
+
+ Mnp = IpInstance->Service->Mnp;
+
+ //
+ // Don't lock the Poll function to enable the deliver of
+ // the packet polled up.
+ //
+ return Mnp->Poll (Mnp);
+}
+
+/**
+ Decrease the life of the transmitted packets. If it is
+ decreased to zero, cancel the packet. This function is
+ called by Ip4PacketTimerTicking which time out both the
+ received-but-not-delivered and transmitted-but-not-recycle
+ packets.
+
+ @param[in] Map The IP4 child's transmit map.
+ @param[in] Item Current transmitted packet
+ @param[in] Context Not used.
+
+ @retval EFI_SUCCESS Always returns EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+Ip4SentPacketTicking (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ )
+{
+ IP4_TXTOKEN_WRAP *Wrap;
+
+ Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;
+ ASSERT (Wrap != NULL);
+
+ if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
+ Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The heart beat timer of IP4 service instance. It times out
+ all of its IP4 children's received-but-not-delivered and
+ transmitted-but-not-recycle packets, and provides time input
+ for its IGMP protocol.
+
+ @param[in] Event The IP4 service instance's heart beat timer.
+ @param[in] Context The IP4 service instance.
+
+**/
+VOID
+EFIAPI
+Ip4TimerTicking (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ IP4_SERVICE *IpSb;
+
+ IpSb = (IP4_SERVICE *) Context;
+ NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
+
+ Ip4PacketTimerTicking (IpSb);
+ Ip4IgmpTicking (IpSb);
+}