Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3492 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
vanjeff
2007-07-30 02:37:10 +00:00
parent eca7eaf49b
commit 772db4bb33
113 changed files with 42735 additions and 302 deletions

View File

@@ -0,0 +1,166 @@
/** @file
Copyright (c) 2005 - 2007, Intel Corporation
All rights reserved. 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.
Module Name:
ComponentName.c
Abstract:
**/
#include "Ip4Impl.h"
//
// EFI Component Name Functions
//
EFI_STATUS
EFIAPI
Ip4ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
EFI_STATUS
EFIAPI
Ip4ComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
//
// EFI Component Name Protocol
//
EFI_COMPONENT_NAME_PROTOCOL gIp4ComponentName = {
Ip4ComponentNameGetDriverName,
Ip4ComponentNameGetControllerName,
"eng"
};
static EFI_UNICODE_STRING_TABLE mIp4DriverNameTable[] = {
{
"eng",
L"IP4 Network Service Driver"
},
{
NULL,
NULL
}
};
EFI_STATUS
EFIAPI
Ip4ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable
name of the EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
Language - A pointer to a three character ISO 639-2 language
identifier. This is the language of the driver name
that that the caller is requesting, and it must match
one of the languages specified in SupportedLanguages.
The number of languages supported by a driver is up to
the driver writer.
DriverName - A pointer to the Unicode string to return. This Unicode
string is the name of the driver specified by This in the
language specified by Language.
Returns:
EFI_SUCCES - The Unicode string for the Driver specified by This
and the language specified by Language was returned
in DriverName.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - DriverName is NULL.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return LookupUnicodeString (
Language,
gIp4ComponentName.SupportedLanguages,
mIp4DriverNameTable,
DriverName
);
}
EFI_STATUS
EFIAPI
Ip4ComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of
the controller that is being managed by an EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
ControllerHandle - The handle of a controller that the driver specified by
This is managing. This handle specifies the controller
whose name is to be returned.
ChildHandle - The handle of the child controller to retrieve the name
of. This is an optional parameter that may be NULL. It
will be NULL for device drivers. It will also be NULL
for a bus drivers that wish to retrieve the name of the
bus controller. It will not be NULL for a bus driver
that wishes to retrieve the name of a child controller.
Language - A pointer to a three character ISO 639-2 language
identifier. This is the language of the controller name
that that the caller is requesting, and it must match one
of the languages specified in SupportedLanguages. The
number of languages supported by a driver is up to the
driver writer.
ControllerName - A pointer to the Unicode string to return. This Unicode
string is the name of the controller specified by
ControllerHandle and ChildHandle in the language
specified by Language from the point of view of the
driver specified by This.
Returns:
EFI_SUCCESS - The Unicode string for the user readable name in the
language specified by Language for the driver
specified by This was returned in DriverName.
EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not
a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - ControllerName is NULL.
EFI_UNSUPPORTED - The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return EFI_UNSUPPORTED;
}

View File

@@ -0,0 +1,421 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Common.c
Abstract:
**/
#include "Ip4Impl.h"
/**
Return the cast type (Unicast/Boradcast) specific to a
interface. All the addresses are host byte ordered.
@param IpAddr The IP address to classify in host byte order
@param IpIf The interface that IpAddr received from
@return The cast type of this IP address specific to the interface.
@retval IP4_LOCAL_HOST The IpAddr equals to the interface's address
@retval IP4_SUBNET_BROADCAST The IpAddr is a directed subnet boradcast to the
interface
@retval IP4_NET_BROADCAST The IpAddr is a network broadcast to the interface
**/
INTN
Ip4GetNetCast (
IN IP4_ADDR IpAddr,
IN IP4_INTERFACE *IpIf
)
{
if (IpAddr == IpIf->Ip) {
return IP4_LOCAL_HOST;
} else if (IpAddr == IpIf->SubnetBrdcast) {
return IP4_SUBNET_BROADCAST;
} else if (IpAddr == IpIf->NetBrdcast) {
return IP4_NET_BROADCAST;
}
return 0;
}
/**
Find the cast type of the packet related to the local host.
This isn't the same as link layer cast type. For example, DHCP
server may send local broadcast to the local unicast MAC.
@param IpSb The IP4 service binding instance that received the
packet
@param Dst The destination address in the packet (host byte
order)
@param Src The source address in the packet (host byte order)
@return The cast type for the Dst, it will return on the first non-promiscuous
@return cast type to a configured interface. If the packet doesn't match any of
@return the interface, multicast address and local broadcast address are checked.
**/
INTN
Ip4GetHostCast (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Dst,
IN IP4_ADDR Src
)
{
NET_LIST_ENTRY *Entry;
IP4_INTERFACE *IpIf;
INTN Type;
INTN Class;
Type = 0;
if (IpSb->MnpConfigData.EnablePromiscuousReceive) {
Type = IP4_PROMISCUOUS;
}
//
// Go through the interface list of the IP service, most likely.
//
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
//
// Skip the unconfigured interface and invalid source address:
// source address can't be broadcast.
//
if (!IpIf->Configured || IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
continue;
}
if ((Class = Ip4GetNetCast (Dst, IpIf)) > Type) {
return Class;
}
}
//
// If it is local broadcast address. The source address must
// be a unicast address on one of the direct connected network.
// If it is a multicast address, accept it only if we are in
// the group.
//
if (Dst == IP4_ALLONE_ADDRESS) {
IpIf = Ip4FindNet (IpSb, Src);
if (IpIf && !IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
return IP4_LOCAL_BROADCAST;
}
} else if (IP4_IS_MULTICAST (Dst) && Ip4FindGroup (&IpSb->IgmpCtrl, Dst)) {
return IP4_MULTICAST;
}
return Type;
}
/**
Find an interface whose configured IP address is Ip
@param IpSb The IP4 service binding instance
@param Ip The Ip address (host byte order) to find
@return The IP4_INTERFACE point if found, otherwise NULL
**/
IP4_INTERFACE *
Ip4FindInterface (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Ip
)
{
NET_LIST_ENTRY *Entry;
IP4_INTERFACE *IpIf;
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
if (IpIf->Configured && (IpIf->Ip == Ip)) {
return IpIf;
}
}
return NULL;
}
/**
Find an interface that Ip is on that connected network.
@param IpSb The IP4 service binding instance
@param Ip The Ip address (host byte order) to find
@return The IP4_INTERFACE point if found, otherwise NULL
**/
IP4_INTERFACE *
Ip4FindNet (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Ip
)
{
NET_LIST_ENTRY *Entry;
IP4_INTERFACE *IpIf;
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
if (IpIf->Configured && IP4_NET_EQUAL (Ip, IpIf->Ip, IpIf->SubnetMask)) {
return IpIf;
}
}
return NULL;
}
/**
Find an interface of the service with the same Ip/Netmask pair.
@param IpSb Ip4 service binding instance
@param Ip The Ip adress to find (host byte order)
@param Netmask The network to find (host byte order)
@return The IP4_INTERFACE point if found, otherwise NULL
**/
IP4_INTERFACE *
Ip4FindStationAddress (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Ip,
IN IP4_ADDR Netmask
)
{
NET_LIST_ENTRY *Entry;
IP4_INTERFACE *IpIf;
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
if (IpIf->Configured && (IpIf->Ip == Ip) && (IpIf->SubnetMask == Netmask)) {
return IpIf;
}
}
return NULL;
}
/**
Get the MAC address for a multicast IP address. Call
Mnp's McastIpToMac to find the MAC address in stead of
hard code the NIC to be Ethernet.
@param Mnp The Mnp instance to get the MAC address.
@param Multicast The multicast IP address to translate.
@param Mac The buffer to hold the translated address.
@return Returns EFI_SUCCESS if the multicast IP is successfully
@return translated to a multicast MAC address. Otherwise some error.
**/
EFI_STATUS
Ip4GetMulticastMac (
IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
IN IP4_ADDR Multicast,
OUT EFI_MAC_ADDRESS *Mac
)
{
EFI_IP_ADDRESS EfiIp;
EFI_IP4 (EfiIp.v4) = HTONL (Multicast);
return Mnp->McastIpToMac (Mnp, FALSE, &EfiIp, Mac);
}
/**
Convert the multibyte field in IP header's byter order.
In spite of its name, it can also be used to convert from
host to network byte order.
@param Head The IP head to convert
@return Point to the converted IP head
**/
IP4_HEAD *
Ip4NtohHead (
IN IP4_HEAD *Head
)
{
Head->TotalLen = NTOHS (Head->TotalLen);
Head->Id = NTOHS (Head->Id);
Head->Fragment = NTOHS (Head->Fragment);
Head->Src = NTOHL (Head->Src);
Head->Dst = NTOHL (Head->Dst);
return Head;
}
/**
Set the Ip4 variable data.
@param IpSb Ip4 service binding instance
@retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.
@retval other Set variable failed.
**/
EFI_STATUS
Ip4SetVariableData (
IN IP4_SERVICE *IpSb
)
{
UINT32 NumConfiguredInstance;
NET_LIST_ENTRY *Entry;
UINTN VariableDataSize;
EFI_IP4_VARIABLE_DATA *Ip4VariableData;
EFI_IP4_ADDRESS_PAIR *Ip4AddressPair;
IP4_PROTOCOL *IpInstance;
CHAR16 *NewMacString;
EFI_STATUS Status;
NumConfiguredInstance = 0;
//
// Go through the children list to count the configured children.
//
NET_LIST_FOR_EACH (Entry, &IpSb->Children) {
IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);
if (IpInstance->State == IP4_STATE_CONFIGED) {
NumConfiguredInstance++;
}
}
//
// Calculate the size of the Ip4VariableData. As there may be no IP child,
// we should add extra buffer for the address paris only if the number of configured
// children is more than 1.
//
VariableDataSize = sizeof (EFI_IP4_VARIABLE_DATA);
if (NumConfiguredInstance > 1) {
VariableDataSize += sizeof (EFI_IP4_ADDRESS_PAIR) * (NumConfiguredInstance - 1);
}
Ip4VariableData = NetAllocatePool (VariableDataSize);
if (Ip4VariableData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Ip4VariableData->DriverHandle = IpSb->Image;
Ip4VariableData->AddressCount = NumConfiguredInstance;
Ip4AddressPair = &Ip4VariableData->AddressPairs[0];
//
// Go through the children list to fill the configured children's address pairs.
//
NET_LIST_FOR_EACH (Entry, &IpSb->Children) {
IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);
if (IpInstance->State == IP4_STATE_CONFIGED) {
Ip4AddressPair->InstanceHandle = IpInstance->Handle;
EFI_IP4 (Ip4AddressPair->Ip4Address) = NTOHL (IpInstance->Interface->Ip);
EFI_IP4 (Ip4AddressPair->SubnetMask) = NTOHL (IpInstance->Interface->SubnetMask);
Ip4AddressPair++;
}
}
//
// Get the mac string.
//
Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &NewMacString);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
if (IpSb->MacString != NULL) {
//
// The variable is set already, we're going to update it.
//
if (StrCmp (IpSb->MacString, NewMacString) != 0) {
//
// The mac address is changed, delete the previous variable first.
//
gRT->SetVariable (
IpSb->MacString,
&gEfiIp4ServiceBindingProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
0,
NULL
);
}
NetFreePool (IpSb->MacString);
}
IpSb->MacString = NewMacString;
Status = gRT->SetVariable (
IpSb->MacString,
&gEfiIp4ServiceBindingProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
VariableDataSize,
(VOID *) Ip4VariableData
);
ON_ERROR:
NetFreePool (Ip4VariableData);
return Status;
}
/**
Clear the variable and free the resource.
@param IpSb Ip4 service binding instance
@return None.
**/
VOID
Ip4ClearVariableData (
IN IP4_SERVICE *IpSb
)
{
ASSERT (IpSb->MacString != NULL);
gRT->SetVariable (
IpSb->MacString,
&gEfiIp4ServiceBindingProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
0,
NULL
);
NetFreePool (IpSb->MacString);
IpSb->MacString = NULL;
}

View File

@@ -0,0 +1,143 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Common.h
Abstract:
Common definition for IP4.
**/
#ifndef __EFI_IP4_COMMON_H__
#define __EFI_IP4_COMMON_H__
typedef struct _IP4_INTERFACE IP4_INTERFACE;
typedef struct _IP4_PROTOCOL IP4_PROTOCOL;
typedef struct _IP4_SERVICE IP4_SERVICE;
enum {
IP4_ETHER_PROTO = 0x0800,
IP4_PROTO_ICMP = 0x01,
IP4_PROTO_IGMP = 0x02,
//
// The packet is received as link level broadcast/multicast/promiscuous.
//
IP4_LINK_BROADCAST = 0x00000001,
IP4_LINK_MULTICAST = 0x00000002,
IP4_LINK_PROMISC = 0x00000004,
//
// IP4 address cast type classfication. Keep it true that any
// type bigger than or equal to LOCAL_BROADCAST is broadcast.
//
IP4_PROMISCUOUS = 1,
IP4_LOCAL_HOST,
IP4_MULTICAST,
IP4_LOCAL_BROADCAST, // Destination is 255.255.255.255
IP4_SUBNET_BROADCAST,
IP4_NET_BROADCAST,
//
// IP4 header flags
//
IP4_HEAD_DF_MASK = 0x4000,
IP4_HEAD_MF_MASK = 0x2000,
IP4_HEAD_OFFSET_MASK = 0x1fff,
};
#define IP4_ALLZERO_ADDRESS 0x00000000u
#define IP4_ALLONE_ADDRESS 0xFFFFFFFFu
#define IP4_ALLSYSTEM_ADDRESS 0xE0000001u
#define IP4_ALLROUTER_ADDRESS 0xE0000002u
//
// Compose the fragment field to be used in the IP4 header.
//
#define IP4_HEAD_FRAGMENT_FIELD(Df, Mf, Offset) \
((UINT16)(((Df) ? 0x4000 : 0) | ((Mf) ? 0x2000 : 0) | (((Offset) >> 3) & 0x1fff)))
#define IP4_LAST_FRAGMENT(FragmentField) \
(((FragmentField) & IP4_HEAD_MF_MASK) == 0)
#define IP4_FIRST_FRAGMENT(FragmentField) \
((BOOLEAN)(((FragmentField) & IP4_HEAD_OFFSET_MASK) == 0))
#define IP4_IS_BROADCAST(CastType) ((CastType) >= IP4_LOCAL_BROADCAST)
//
// Conver the Microsecond to second. IP transmit/receive time is
// in the unit of microsecond. IP ticks once per second.
//
#define IP4_US_TO_SEC(Us) (((Us) + 999999) / 1000000)
INTN
Ip4GetNetCast (
IN IP4_ADDR IpAddr,
IN IP4_INTERFACE *IpIf
);
INTN
Ip4GetHostCast (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Dst,
IN IP4_ADDR Src
);
IP4_INTERFACE *
Ip4FindInterface (
IN IP4_SERVICE *IpService,
IN IP4_ADDR Addr
);
IP4_INTERFACE *
Ip4FindNet (
IN IP4_SERVICE *IpService,
IN IP4_ADDR Addr
);
IP4_INTERFACE *
Ip4FindStationAddress (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Ip,
IN IP4_ADDR Netmask
);
EFI_STATUS
Ip4GetMulticastMac (
IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
IN IP4_ADDR Multicast,
OUT EFI_MAC_ADDRESS *Mac
);
IP4_HEAD *
Ip4NtohHead (
IN IP4_HEAD *Head
);
EFI_STATUS
Ip4SetVariableData (
IN IP4_SERVICE *IpSb
);
VOID
Ip4ClearVariableData (
IN IP4_SERVICE *IpSb
);
#endif

View File

@@ -0,0 +1,932 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Driver.c
Abstract:
The driver binding and service binding protocol for IP4 driver.
**/
#include "Ip4Impl.h"
EFI_DRIVER_BINDING_PROTOCOL gIp4DriverBinding = {
Ip4DriverBindingSupported,
Ip4DriverBindingStart,
Ip4DriverBindingStop,
0xa,
NULL,
NULL
};
//@MT: EFI_DRIVER_ENTRY_POINT (Ip4DriverEntryPoint)
EFI_STATUS
EFIAPI
Ip4DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
The entry point for IP4 driver which install the driver
binding and component name protocol on its image.
Arguments:
ImageHandle - The image handle of the driver
SystemTable - The system table
Returns:
EFI_SUCCESS if the driver binding and component name protocols
are successfully installed, otherwise if failed.
--*/
{
return NetLibInstallAllDriverProtocols (
ImageHandle,
SystemTable,
&gIp4DriverBinding,
ImageHandle,
&gIp4ComponentName,
NULL,
NULL
);
}
/**
Test to see if this driver supports ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to test
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCES This driver supports this device
@retval EFI_ALREADY_STARTED This driver is already running on this device
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
Ip4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL * This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
//
// Test for the MNP service binding Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Test for the Arp service binding Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiArpServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
return Status;
}
STATIC
EFI_STATUS
Ip4CleanService (
IN IP4_SERVICE *IpSb
);
/**
Create a new IP4 driver service binding protocol
@param Controller The controller that has MNP service binding
installed
@param ImageHandle The IP4 driver's image handle
@param Service The variable to receive the newly created IP4
service.
@retval EFI_OUT_OF_RESOURCES Failed to allocate some resource
@retval EFI_SUCCESS A new IP4 service binding private is created.
**/
STATIC
EFI_STATUS
Ip4CreateService (
IN EFI_HANDLE Controller,
IN EFI_HANDLE ImageHandle,
OUT IP4_SERVICE **Service
)
{
IP4_SERVICE *IpSb;
EFI_STATUS Status;
ASSERT (Service != NULL);
*Service = NULL;
//
// allocate a service private data then initialize all the filed to
// empty resources, so if any thing goes wrong when allocating
// resources, Ip4CleanService can be called to clean it up.
//
IpSb = NetAllocatePool (sizeof (IP4_SERVICE));
if (IpSb == NULL) {
return EFI_OUT_OF_RESOURCES;
}
IpSb->Signature = IP4_SERVICE_SIGNATURE;
IpSb->ServiceBinding.CreateChild = Ip4ServiceBindingCreateChild;
IpSb->ServiceBinding.DestroyChild = Ip4ServiceBindingDestroyChild;
IpSb->State = IP4_SERVICE_UNSTARTED;
IpSb->InDestory = FALSE;
IpSb->NumChildren = 0;
NetListInit (&IpSb->Children);
NetListInit (&IpSb->Interfaces);
IpSb->DefaultInterface = NULL;
IpSb->DefaultRouteTable = NULL;
Ip4InitAssembleTable (&IpSb->Assemble);
IpSb->IgmpCtrl.Igmpv1QuerySeen = 0;
NetListInit (&IpSb->IgmpCtrl.Groups);
IpSb->Image = ImageHandle;
IpSb->Controller = Controller;
IpSb->MnpChildHandle = NULL;
IpSb->Mnp = NULL;
IpSb->MnpConfigData.ReceivedQueueTimeoutValue = 0;
IpSb->MnpConfigData.TransmitQueueTimeoutValue = 0;
IpSb->MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO;
IpSb->MnpConfigData.EnableUnicastReceive = TRUE;
IpSb->MnpConfigData.EnableMulticastReceive = TRUE;
IpSb->MnpConfigData.EnableBroadcastReceive = TRUE;
IpSb->MnpConfigData.EnablePromiscuousReceive = FALSE;
IpSb->MnpConfigData.FlushQueuesOnReset = TRUE;
IpSb->MnpConfigData.EnableReceiveTimestamps = FALSE;
IpSb->MnpConfigData.DisableBackgroundPolling = FALSE;
NetZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));
IpSb->Timer = NULL;
IpSb->Ip4Config = NULL;
IpSb->DoneEvent = NULL;
IpSb->ReconfigEvent = NULL;
//
// Create various resources. First create the route table, timer
// event and MNP child. IGMP, interface's initialization depend
// on the MNP child.
//
IpSb->DefaultRouteTable = Ip4CreateRouteTable ();
if (IpSb->DefaultRouteTable == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL | EVT_TIMER,
TPL_CALLBACK,
Ip4TimerTicking,
IpSb,
&IpSb->Timer
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = NetLibCreateServiceChild (
Controller,
ImageHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
&IpSb->MnpChildHandle
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = gBS->OpenProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
(VOID **) &IpSb->Mnp,
ImageHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip4ServiceConfigMnp (IpSb, TRUE);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip4InitIgmp (IpSb);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
IpSb->DefaultInterface = Ip4CreateInterface (IpSb->Mnp, Controller, ImageHandle);
if (IpSb->DefaultInterface == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
NetListInsertHead (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);
IpSb->MacString = NULL;
*Service = IpSb;
return EFI_SUCCESS;
ON_ERROR:
Ip4CleanService (IpSb);
NetFreePool (IpSb);
return Status;
}
/**
Clean up a IP4 service binding instance. It will release all
the resource allocated by the instance. The instance may be
partly initialized, or partly destoried. If a resource is
destoried, it is marked as that in case the destory failed and
being called again later.
@param IpSb The IP4 serviceing binding instance to clean up
@retval EFI_SUCCESS The resource used by the instance are cleaned up
@retval Others Failed to clean up some of the resources.
**/
EFI_STATUS
Ip4CleanService (
IN IP4_SERVICE *IpSb
)
{
EFI_STATUS Status;
if (IpSb->DefaultInterface != NULL) {
Status = Ip4FreeInterface (IpSb->DefaultInterface, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
IpSb->DefaultInterface = NULL;
}
if (IpSb->DefaultRouteTable != NULL) {
Ip4FreeRouteTable (IpSb->DefaultRouteTable);
IpSb->DefaultRouteTable = NULL;
}
Ip4CleanAssembleTable (&IpSb->Assemble);
if (IpSb->MnpChildHandle != NULL) {
if (IpSb->Mnp) {
gBS->CloseProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
IpSb->Image,
IpSb->Controller
);
IpSb->Mnp = NULL;
}
NetLibDestroyServiceChild (
IpSb->Controller,
IpSb->Image,
&gEfiManagedNetworkServiceBindingProtocolGuid,
IpSb->MnpChildHandle
);
IpSb->MnpChildHandle = NULL;
}
if (IpSb->Timer != NULL) {
gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
gBS->CloseEvent (IpSb->Timer);
IpSb->Timer = NULL;
}
if (IpSb->Ip4Config != NULL) {
IpSb->Ip4Config->Stop (IpSb->Ip4Config);
gBS->CloseProtocol (
IpSb->Controller,
&gEfiIp4ConfigProtocolGuid,
IpSb->Image,
IpSb->Controller
);
gBS->CloseEvent (IpSb->DoneEvent);
gBS->CloseEvent (IpSb->ReconfigEvent);
IpSb->Ip4Config = NULL;
}
return EFI_SUCCESS;
}
/**
Start this driver on ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to bind driver to
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCES This driver is added to ControllerHandle
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
Ip4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL * This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
)
{
IP4_SERVICE *IpSb;
EFI_STATUS Status;
//
// Test for the Ip4 service binding protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (Status == EFI_SUCCESS) {
return EFI_ALREADY_STARTED;
}
Status = Ip4CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Install the Ip4ServiceBinding Protocol onto ControlerHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
&IpSb->ServiceBinding,
NULL
);
if (EFI_ERROR (Status)) {
goto FREE_SERVICE;
}
//
// ready to go: start the receiving and timer
//
Status = Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);
if (EFI_ERROR (Status)) {
goto UNINSTALL_PROTOCOL;
}
Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
if (EFI_ERROR (Status)) {
goto UNINSTALL_PROTOCOL;
}
//
// Initialize the IP4 ID
//
mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());
Ip4SetVariableData (IpSb);
return Status;
UNINSTALL_PROTOCOL:
gBS->UninstallProtocolInterface (
ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
&IpSb->ServiceBinding
);
FREE_SERVICE:
Ip4CleanService (IpSb);
NetFreePool (IpSb);
return Status;
}
/**
Stop this driver on ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to stop driver on
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
of children is zero stop the entire bus driver.
@param ChildHandleBuffer List of Child Handles to Stop.
@retval EFI_SUCCES This driver is removed ControllerHandle
@retval other This driver was not removed from this device
**/
EFI_STATUS
EFIAPI
Ip4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
IP4_SERVICE *IpSb;
IP4_PROTOCOL *IpInstance;
EFI_HANDLE NicHandle;
EFI_STATUS Status;
EFI_TPL OldTpl;
INTN State;
//
// IP4 driver opens the MNP child, ARP children or the IP4_CONFIG protocol
// by driver. So the ControllerHandle may be the MNP child handle, ARP child
// handle, or the NIC (UNDI) handle because IP4_CONFIG protocol is installed
// in the NIC handle.
//
//
// First, check whether it is the IP4_CONFIG protocol being uninstalled.
// IP4_CONFIG protocol is installed on the NIC handle. It isn't necessary
// to clean up the default configuration if IP4_CONFIG is being stopped.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp4ConfigProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (Status == EFI_SUCCESS) {
//
// Retrieve the IP4 service binding protocol. If failed, it is
// likely that Ip4 ServiceBinding is uninstalled already. In this
// case, return immediately.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
(VOID **) &ServiceBinding,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
if (IpSb->Ip4Config && (IpSb->State != IP4_SERVICE_DESTORY)) {
IpSb->Ip4Config->Stop (IpSb->Ip4Config);
Status = gBS->CloseProtocol (
ControllerHandle,
&gEfiIp4ConfigProtocolGuid,
IpSb->Image,
ControllerHandle
);
if (EFI_ERROR (Status)) {
NET_RESTORE_TPL (OldTpl);
return Status;
}
//
// If the auto configure hasn't complete, mark it as not started.
//
if (IpSb->State == IP4_SERVICE_STARTED) {
IpSb->State = IP4_SERVICE_UNSTARTED;
}
IpSb->Ip4Config = NULL;
gBS->CloseEvent (IpSb->DoneEvent);
gBS->CloseEvent (IpSb->ReconfigEvent);
}
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
}
//
// Either MNP or ARP protocol is being uninstalled. The controller
// handle is either the MNP child or ARP child. But, the IP4's
// service binding is installed on the NIC handle. So, need to open
// the protocol info to find the NIC handle.
//
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
if (NicHandle == NULL) {
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
}
if (NicHandle == NULL) {
return EFI_SUCCESS;
}
//
// Retrieve the IP4 service binding protocol
//
Status = gBS->OpenProtocol (
NicHandle,
&gEfiIp4ServiceBindingProtocolGuid,
(VOID **) &ServiceBinding,
This->DriverBindingHandle,
NicHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
if (IpSb->InDestory) {
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
}
IpSb->InDestory = TRUE;
State = IpSb->State;
IpSb->State = IP4_SERVICE_DESTORY;
//
// Destory all the children first. If not all children are destoried,
// the IP driver can operate correctly, so restore it state. Don't
// use NET_LIST_FOR_EACH_SAFE here, because it will cache the next
// pointer, which may point to the child that has already been destoried.
// For example, if there are two child in the list, the first is UDP
// listen child, the send is the MTFTP's child. When Udp child is
// destoried, it will destory the MTFTP's child. Then Next point to
// a invalid child.
//
while (!NetListIsEmpty (&IpSb->Children)) {
IpInstance = NET_LIST_HEAD (&IpSb->Children, IP4_PROTOCOL, Link);
Ip4ServiceBindingDestroyChild (ServiceBinding, IpInstance->Handle);
}
if (IpSb->NumChildren != 0) {
IpSb->State = State;
Status = EFI_DEVICE_ERROR;
goto ON_ERROR;
}
//
// Clear the variable data.
//
Ip4ClearVariableData (IpSb);
//
// OK, clean other resources then uninstall the service binding protocol.
//
Status = Ip4CleanService (IpSb);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = gBS->UninstallProtocolInterface (
NicHandle,
&gEfiIp4ServiceBindingProtocolGuid,
ServiceBinding
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
NET_RESTORE_TPL (OldTpl);
NetFreePool (IpSb);
return EFI_SUCCESS;
ON_ERROR:
IpSb->InDestory = FALSE;
NET_RESTORE_TPL (OldTpl);
return Status;
}
/**
Creates a child handle with a set of I/O services.
@param This Protocol instance pointer.
@param ChildHandle Pointer to the handle of the child to create. If
it is NULL, then a new handle is created. If it
is not NULL, then the I/O services are added to
the existing child handle.
@retval EFI_SUCCES The child handle was created with the I/O services
@retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
the child
@retval other The child handle was not created
**/
EFI_STATUS
EFIAPI
Ip4ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
)
{
IP4_SERVICE *IpSb;
IP4_PROTOCOL *IpInstance;
EFI_TPL OldTpl;
EFI_STATUS Status;
VOID *Mnp;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
IpInstance = NetAllocatePool (sizeof (IP4_PROTOCOL));
if (IpInstance == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Ip4InitProtocol (IpSb, IpInstance);
//
// Install Ip4 onto ChildHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiIp4ProtocolGuid,
&IpInstance->Ip4Proto,
NULL
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
IpInstance->Handle = *ChildHandle;
//
// Open the Managed Network protocol BY_CHILD.
//
Status = gBS->OpenProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
(VOID **) &Mnp,
gIp4DriverBinding.DriverBindingHandle,
IpInstance->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
gBS->UninstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiIp4ProtocolGuid,
&IpInstance->Ip4Proto,
NULL
);
goto ON_ERROR;
}
//
// Insert it into the service binding instance.
//
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
NetListInsertTail (&IpSb->Children, &IpInstance->Link);
IpSb->NumChildren++;
NET_RESTORE_TPL (OldTpl);
ON_ERROR:
if (EFI_ERROR (Status)) {
Ip4CleanProtocol (IpInstance);
NetFreePool (IpInstance);
}
return Status;
}
/**
Destroys a child handle with a set of I/O services.
@param This Protocol instance pointer.
@param ChildHandle Handle of the child to destroy
@retval EFI_SUCCES The I/O services were removed from the child
handle
@retval EFI_UNSUPPORTED The child handle does not support the I/O services
that are being removed
@retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
@retval EFI_ACCESS_DENIED The child handle could not be destroyed because
its I/O services are being used.
@retval other The child handle was not destroyed
**/
EFI_STATUS
EFIAPI
Ip4ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
EFI_STATUS Status;
IP4_SERVICE *IpSb;
IP4_PROTOCOL *IpInstance;
EFI_IP4_PROTOCOL *Ip4;
EFI_TPL OldTpl;
INTN State;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Retrieve the private context data structures
//
IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiIp4ProtocolGuid,
(VOID **) &Ip4,
gIp4DriverBinding.DriverBindingHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);
if (IpInstance->Service != IpSb) {
return EFI_INVALID_PARAMETER;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
//
// A child can be destoried more than once. For example,
// Ip4DriverBindingStop will destory all of its children.
// when UDP driver is being stopped, it will destory all
// the IP child it opens.
//
if (IpInstance->State == IP4_STATE_DESTORY) {
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
}
State = IpInstance->State;
IpInstance->State = IP4_STATE_DESTORY;
//
// Close the Managed Network protocol.
//
gBS->CloseProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
gIp4DriverBinding.DriverBindingHandle,
ChildHandle
);
//
// Uninstall the IP4 protocol first. Many thing happens during
// this:
// 1. The consumer of the IP4 protocol will be stopped if it
// opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
// stopped, IP driver's stop function will be called, and uninstall
// EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
// makes it possible to create the network stack bottom up, and
// stop it top down.
// 2. the upper layer will recycle the received packet. The recycle
// event's TPL is higher than this function. The recycle events
// will be called back before preceeding. If any packets not recycled,
// that means there is a resource leak.
//
Status = gBS->UninstallProtocolInterface (
ChildHandle,
&gEfiIp4ProtocolGuid,
&IpInstance->Ip4Proto
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip4CleanProtocol (IpInstance);
Ip4SetVariableData (IpSb);
if (EFI_ERROR (Status)) {
gBS->InstallMultipleProtocolInterfaces (
&ChildHandle,
&gEfiIp4ProtocolGuid,
Ip4,
NULL
);
goto ON_ERROR;
}
NetListRemoveEntry (&IpInstance->Link);
IpSb->NumChildren--;
NET_RESTORE_TPL (OldTpl);
NetFreePool (IpInstance);
return EFI_SUCCESS;
ON_ERROR:
IpInstance->State = State;
NET_RESTORE_TPL (OldTpl);
return Status;
}

View File

@@ -0,0 +1,84 @@
/** @file
Copyright (c) 2005 - 2007, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Driver.h
Abstract:
**/
#ifndef __EFI_IP4_DRIVER_H__
#define __EFI_IP4_DRIVER_H__
#include <Protocol/ServiceBinding.h>
extern EFI_DRIVER_BINDING_PROTOCOL gIp4DriverBinding;
extern EFI_COMPONENT_NAME_PROTOCOL gIp4ComponentName;
//
// Function prototype for the driver's entry point
//
EFI_STATUS
EFIAPI
Ip4DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
//
// Function prototypes for the Drivr Binding Protocol
//
EFI_STATUS
EFIAPI
Ip4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
EFI_STATUS
EFIAPI
Ip4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
EFI_STATUS
EFIAPI
Ip4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
);
//
// Function ptototypes for the ServiceBinding Prococol
//
EFI_STATUS
EFIAPI
Ip4ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
);
EFI_STATUS
EFIAPI
Ip4ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
);
#endif

View File

@@ -0,0 +1,81 @@
#/** @file
# Component name for module Ip4
#
# Copyright (c) 2007, Intel Corporation
#
# All rights reserved. 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.
#
#
#**/
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Ip4Dxe
FILE_GUID = 9FB1A1F3-3B71-4324-B39A-745CBB015FFF
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = Ip4DriverEntryPoint
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources.common]
Ip4Driver.c
Ip4Option.h
Ip4Route.h
Ip4If.c
Ip4Igmp.h
Ip4Output.c
Ip4Icmp.c
Ip4Igmp.c
Ip4Impl.c
Ip4Common.h
Ip4Impl.h
Ip4Driver.h
Ip4Common.c
Ip4If.h
Ip4Option.c
Ip4Output.h
ComponentName.c
Ip4Input.h
Ip4Route.c
Ip4Icmp.h
Ip4Input.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiLib
BaseLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
DebugLib
NetLib
[Protocols]
gEfiIp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiManagedNetworkServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiIp4ConfigProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiArpServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiIp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiManagedNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiArpProtocolGuid # PROTOCOL ALWAYS_CONSUMED

View File

@@ -0,0 +1,101 @@
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>Ip4Dxe</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>9FB1A1F3-3B71-4324-B39A-745CBB015FFF</GuidValue>
<Version>1.0</Version>
<Abstract>Component name for module Ip4</Abstract>
<Description>FIX ME!</Description>
<Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
<License>All rights reserved. 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.</License>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>Ip4Dxe</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiRuntimeServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>Ip4Input.c</Filename>
<Filename>Ip4Icmp.h</Filename>
<Filename>Ip4Route.c</Filename>
<Filename>Ip4Input.h</Filename>
<Filename>ComponentName.c</Filename>
<Filename>Ip4Output.h</Filename>
<Filename>Ip4Option.c</Filename>
<Filename>Ip4If.h</Filename>
<Filename>Ip4Common.c</Filename>
<Filename>Ip4Driver.h</Filename>
<Filename>Ip4Impl.h</Filename>
<Filename>Ip4Common.h</Filename>
<Filename>Ip4Impl.c</Filename>
<Filename>Ip4Igmp.c</Filename>
<Filename>Ip4Icmp.c</Filename>
<Filename>Ip4Output.c</Filename>
<Filename>Ip4Igmp.h</Filename>
<Filename>Ip4If.c</Filename>
<Filename>Ip4Route.h</Filename>
<Filename>Ip4Option.h</Filename>
<Filename>Ip4Driver.c</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiArpProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiManagedNetworkProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiIp4ServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiArpServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiIp4ConfigProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiManagedNetworkServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiIp4ProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>Ip4DriverEntryPoint</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

View File

@@ -0,0 +1,372 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Icmp.c
Abstract:
**/
#include "Ip4Impl.h"
IP4_ICMP_CLASS
mIcmpClass[] = {
{ICMP_ECHO_REPLY, ICMP_QUERY_MESSAGE },
{1, ICMP_INVALID_MESSAGE},
{2, ICMP_INVALID_MESSAGE},
{ICMP_DEST_UNREACHABLE, ICMP_ERROR_MESSAGE },
{ICMP_SOURCE_QUENCH, ICMP_ERROR_MESSAGE },
{ICMP_REDIRECT, ICMP_ERROR_MESSAGE },
{6, ICMP_INVALID_MESSAGE},
{7, ICMP_INVALID_MESSAGE},
{ICMP_ECHO_REQUEST, ICMP_QUERY_MESSAGE },
{9, ICMP_INVALID_MESSAGE},
{10, ICMP_INVALID_MESSAGE},
{ICMP_TIME_EXCEEDED, ICMP_ERROR_MESSAGE },
{ICMP_PARAMETER_PROBLEM, ICMP_ERROR_MESSAGE },
{ICMP_TIMESTAMP , ICMP_QUERY_MESSAGE },
{14, ICMP_INVALID_MESSAGE},
{ICMP_INFO_REQUEST , ICMP_QUERY_MESSAGE },
{ICMP_INFO_REPLY , ICMP_QUERY_MESSAGE },
};
EFI_IP4_ICMP_TYPE
mIp4SupportedIcmp [23] = {
{ICMP_ECHO_REPLY, ICMP_DEFAULT_CODE },
{ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE },
{ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE },
{ICMP_DEST_UNREACHABLE, ICMP_PROTO_UNREACHABLE },
{ICMP_DEST_UNREACHABLE, ICMP_PORT_UNREACHABLE },
{ICMP_DEST_UNREACHABLE, ICMP_FRAGMENT_FAILED },
{ICMP_DEST_UNREACHABLE, ICMP_SOURCEROUTE_FAILED},
{ICMP_DEST_UNREACHABLE, ICMP_NET_UNKNOWN },
{ICMP_DEST_UNREACHABLE, ICMP_HOST_UNKNOWN },
{ICMP_DEST_UNREACHABLE, ICMP_SOURCE_ISOLATED },
{ICMP_DEST_UNREACHABLE, ICMP_NET_PROHIBITED },
{ICMP_DEST_UNREACHABLE, ICMP_HOST_PROHIBITED },
{ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE_TOS },
{ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE_TOS},
{ICMP_SOURCE_QUENCH, ICMP_DEFAULT_CODE },
{ICMP_REDIRECT, ICMP_NET_REDIRECT },
{ICMP_REDIRECT, ICMP_HOST_REDIRECT },
{ICMP_REDIRECT, ICMP_NET_TOS_REDIRECT },
{ICMP_REDIRECT, ICMP_HOST_TOS_REDIRECT },
{ICMP_ECHO_REQUEST, ICMP_DEFAULT_CODE },
{ICMP_TIME_EXCEEDED, ICMP_TIMEOUT_IN_TRANSIT},
{ICMP_TIME_EXCEEDED, ICMp_TIMEOUT_REASSEMBLE},
{ICMP_PARAMETER_PROBLEM, ICMP_DEFAULT_CODE },
};
/**
Process the ICMP redirect. Find the instance then update
its route cache.
All kinds of redirect is treated as host redirect as
specified by RFC1122 3.3.1.2:
"Since the subnet mask appropriate to the destination
address is generally not known, a Network Redirect
message SHOULD be treated identically to a Host Redirect
message;"
@param IpSb The IP4 service binding instance that received the
packet
@param Head The IP head of the received ICMPpacket.
@param Packet The content of the ICMP redirect packet with IP
head removed.
@param Icmp The buffer to store the ICMP error message if
something is wrong.
@retval EFI_INVALID_PARAMETER The parameter is invalid
@retval EFI_SUCCESS Successfully updated the route caches
**/
STATIC
EFI_STATUS
Ip4ProcessIcmpRedirect (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet,
IN IP4_ICMP_ERROR_HEAD *Icmp
)
{
NET_LIST_ENTRY *Entry;
IP4_PROTOCOL *Ip4Instance;
IP4_ROUTE_CACHE_ENTRY *CacheEntry;
IP4_INTERFACE *IpIf;
IP4_ADDR Gateway;
//
// Find the interface whose IP address is the source of the
// orgianl IP packet.
//
IpIf = Ip4FindInterface (IpSb, NTOHL (Icmp->IpHead.Src));
Gateway = NTOHL (Icmp->Fourth);
//
// discard the packet if the new gateway address it specifies
// is not on the same connected net through which the Redirect
// arrived. (RFC1122 3.2.2.2).
//
if ((IpIf == NULL) || !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask)) {
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}
//
// Update each IP child's route cache on the interface.
//
NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);
if (Ip4Instance->RouteTable == NULL) {
continue;
}
CacheEntry = Ip4FindRouteCache (
Ip4Instance->RouteTable,
NTOHL (Icmp->IpHead.Dst),
NTOHL (Icmp->IpHead.Src)
);
//
// Only update the route cache's gateway if the source of the
// Redirect is the current first-hop gateway
//
if ((CacheEntry != NULL) && (NTOHL (Head->Src) == CacheEntry->NextHop)) {
CacheEntry->NextHop = Gateway;
}
}
NetbufFree (Packet);
return EFI_SUCCESS;
}
/**
Process the ICMP error packet. If it is an ICMP redirect packet,
update call Ip4ProcessIcmpRedirect to update the IP instance's
route cache, otherwise, deliver the packet to upper layer.
@param IpSb The IP service that received the packet.
@param Head The IP head of the ICMP error packet
@param Packet The content of the ICMP error with IP head
removed.
@retval EFI_INVALID_PARAMETER The packet is invalid
@retval Others Failed to process the packet.
@retval EFI_SUCCESS The ICMP error is processed successfully.
**/
STATIC
EFI_STATUS
Ip4ProcessIcmpError (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
{
IP4_ICMP_ERROR_HEAD Icmp;
if (Packet->TotalSize < sizeof (Icmp)) {
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}
NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
//
// If it is an ICMP redirect error, update the route cache
// as RFC1122. Otherwise, demultiplex it to IP instances.
//
if (Icmp.Head.Type == ICMP_REDIRECT) {
return Ip4ProcessIcmpRedirect (IpSb, Head, Packet, &Icmp);
}
IP4_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;
return Ip4Demultiplex (IpSb, Head, Packet);
}
/**
Replay an ICMP echo request.
@param IpSb The IP service that receivd the packet
@param Head The IP head of the ICMP error packet
@param Packet The content of the ICMP error with IP head
removed.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
@retval EFI_SUCCESS The ICMP Echo request is successfully answered.
@retval Others Failed to answer the ICMP echo request.
**/
EFI_STATUS
Ip4IcmpReplyEcho (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
{
IP4_ICMP_QUERY_HEAD *Icmp;
NET_BUF *Data;
EFI_STATUS Status;
IP4_HEAD ReplyHead;
//
// make a copy the packet, it is really a bad idea to
// send the MNP's buffer back to MNP.
//
Data = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN);
if (Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT;
}
//
// Change the ICMP type to echo reply, exchange the source
// and destination, then send it. The source is updated to
// use specific destination. See RFC1122. SRR/RR option
// update is omitted.
//
Icmp = (IP4_ICMP_QUERY_HEAD *) NetbufGetByte (Data, 0, NULL);
Icmp->Head.Type = ICMP_ECHO_REPLY;
Icmp->Head.Checksum = 0;
Icmp->Head.Checksum = ~NetblockChecksum ((UINT8 *) Icmp, Data->TotalSize);
ReplyHead.Tos = 0;
ReplyHead.Fragment = 0;
ReplyHead.Ttl = 64;
ReplyHead.Protocol = IP4_PROTO_ICMP;
ReplyHead.Src = 0;
//
// Ip4Output will select a source for us
//
ReplyHead.Dst = Head->Src;
Status = Ip4Output (
IpSb,
NULL,
Data,
&ReplyHead,
NULL,
0,
IP4_ALLZERO_ADDRESS,
Ip4SysPacketSent,
NULL
);
ON_EXIT:
NetbufFree (Packet);
return Status;
}
/**
Process the ICMP query message. If it is an ICMP echo
request, answer it. Otherwise deliver it to upper layer.
@param IpSb The IP service that receivd the packet
@param Head The IP head of the ICMP query packet
@param Packet The content of the ICMP query with IP head
removed.
@retval EFI_INVALID_PARAMETER The packet is invalid
@retval EFI_SUCCESS The ICMP query message is processed
**/
EFI_STATUS
Ip4ProcessIcmpQuery (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
{
IP4_ICMP_QUERY_HEAD Icmp;
if (Packet->TotalSize < sizeof (Icmp)) {
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}
NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
if (Icmp.Head.Type == ICMP_ECHO_REQUEST) {
return Ip4IcmpReplyEcho (IpSb, Head, Packet);
}
return Ip4Demultiplex (IpSb, Head, Packet);
}
/**
Handle the ICMP packet. First validate the message format,
then according to the message types, process it as query or
error packet.
@param IpSb The IP service that receivd the packet
@param Head The IP head of the ICMP query packet
@param Packet The content of the ICMP query with IP head
removed.
@retval EFI_INVALID_PARAMETER The packet is malformated.
@retval EFI_SUCCESS The ICMP message is successfully processed.
**/
EFI_STATUS
Ip4IcmpHandle (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
{
IP4_ICMP_HEAD Icmp;
UINT16 Checksum;
if (Packet->TotalSize < sizeof (Icmp)) {
goto DROP;
}
NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
if (Icmp.Type > ICMP_TYPE_MAX) {
goto DROP;
}
Checksum = ~NetbufChecksum (Packet);
if ((Icmp.Checksum != 0) && (Checksum != 0)) {
goto DROP;
}
if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_ERROR_MESSAGE) {
return Ip4ProcessIcmpError (IpSb, Head, Packet);
} else if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_QUERY_MESSAGE) {
return Ip4ProcessIcmpQuery (IpSb, Head, Packet);
}
DROP:
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}

View File

@@ -0,0 +1,99 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Icmp.h
Abstract:
Header file for ICMP protocol.
**/
#ifndef __EFI_IP4_ICMP_H__
#define __EFI_IP4_ICMP_H__
enum {
//
// ICMP type definations
//
ICMP_ECHO_REPLY = 0,
ICMP_DEST_UNREACHABLE = 3,
ICMP_SOURCE_QUENCH = 4,
ICMP_REDIRECT = 5,
ICMP_ECHO_REQUEST = 8,
ICMP_TIME_EXCEEDED = 11,
ICMP_PARAMETER_PROBLEM = 12,
ICMP_TIMESTAMP = 13,
ICMP_INFO_REQUEST = 15,
ICMP_INFO_REPLY = 16,
ICMP_TYPE_MAX = ICMP_INFO_REPLY,
ICMP_DEFAULT_CODE = 0,
//
// ICMP code definations for ICMP_DEST_UNREACHABLE
//
ICMP_NET_UNREACHABLE = 0,
ICMP_HOST_UNREACHABLE = 1,
ICMP_PROTO_UNREACHABLE = 2, // Host may generate
ICMP_PORT_UNREACHABLE = 3, // Host may generate
ICMP_FRAGMENT_FAILED = 4,
ICMP_SOURCEROUTE_FAILED = 5, // Host may generate
ICMP_NET_UNKNOWN = 6,
ICMP_HOST_UNKNOWN = 7,
ICMP_SOURCE_ISOLATED = 8,
ICMP_NET_PROHIBITED = 9,
ICMP_HOST_PROHIBITED = 10,
ICMP_NET_UNREACHABLE_TOS = 11,
ICMP_HOST_UNREACHABLE_TOS = 12,
//
// ICMP code definations for ICMP_TIME_EXCEEDED
//
ICMP_TIMEOUT_IN_TRANSIT = 0,
ICMp_TIMEOUT_REASSEMBLE = 1, // Host may generate
//
// ICMP code definations for ICMP_TIME_EXCEEDED
//
ICMP_NET_REDIRECT = 0,
ICMP_HOST_REDIRECT = 1,
ICMP_NET_TOS_REDIRECT = 2,
ICMP_HOST_TOS_REDIRECT = 3,
//
// ICMP message classes, each class of ICMP message shares
// a common message format. INVALID_MESSAGE is only a flag.
//
ICMP_INVALID_MESSAGE = 0,
ICMP_ERROR_MESSAGE = 1,
ICMP_QUERY_MESSAGE = 2,
};
typedef struct {
UINT8 IcmpType;
UINT8 IcmpClass;
} IP4_ICMP_CLASS;
extern IP4_ICMP_CLASS mIcmpClass[];
extern EFI_IP4_ICMP_TYPE mIp4SupportedIcmp[];
EFI_STATUS
Ip4IcmpHandle (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Header,
IN NET_BUF *Packet
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,238 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4If.h
Abstract:
Definition for IP4 pesudo interface structure.
**/
#ifndef __EFI_IP4_IF_H__
#define __EFI_IP4_IF_H__
enum {
IP4_FRAME_RX_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', 'F', 'R'),
IP4_FRAME_TX_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', 'F', 'T'),
IP4_FRAME_ARP_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', 'F', 'A'),
IP4_INTERFACE_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', 'I', 'F'),
};
//
// This prototype is used by both receive and transmission.
// When receiving Netbuf is allocated by IP4_INTERFACE, and
// released by IP4. Flag shows whether the frame is received
// as link broadcast/multicast...
//
// When transmitting, the Netbuf is from IP4, and provided
// to the callback as a reference. Flag isn't used.
//
// IpInstance can be NULL which means that it is the IP4 driver
// itself sending the packets. IP4 driver may send packets that
// don't belong to any instance, such as ICMP errors, ICMP echo
// responses, or IGMP packets. IpInstance is used as a tag in
// this module.
//
typedef
VOID
(*IP4_FRAME_CALLBACK) (
IP4_PROTOCOL *IpInstance, OPTIONAL
NET_BUF *Packet,
EFI_STATUS IoStatus,
UINT32 LinkFlag,
VOID *Context
);
//
// Each receive request is wrapped in an IP4_LINK_RX_TOKEN.
// Upon completion, the Callback will be called. Only one
// receive request is send to MNP. IpInstance is always NULL.
// Reference MNP's spec for information.
//
typedef struct {
UINT32 Signature;
IP4_INTERFACE *Interface;
IP4_PROTOCOL *IpInstance;
IP4_FRAME_CALLBACK CallBack;
VOID *Context;
EFI_MANAGED_NETWORK_COMPLETION_TOKEN MnpToken;
} IP4_LINK_RX_TOKEN;
//
// Each transmit request is wrapped in an IP4_LINK_TX_TOKEN.
// Upon completion, the Callback will be called.
//
typedef struct {
UINT32 Signature;
NET_LIST_ENTRY Link;
IP4_INTERFACE *Interface;
IP4_PROTOCOL *IpInstance;
IP4_FRAME_CALLBACK CallBack;
NET_BUF *Packet;
VOID *Context;
EFI_MAC_ADDRESS DstMac;
EFI_MAC_ADDRESS SrcMac;
EFI_MANAGED_NETWORK_COMPLETION_TOKEN MnpToken;
EFI_MANAGED_NETWORK_TRANSMIT_DATA MnpTxData;
} IP4_LINK_TX_TOKEN;
//
// Only one ARP request is requested for all the frames in
// a time. It is started for the first frames to the Ip. Any
// subsequent transmission frame will be linked to Frames, and
// be sent all at once the ARP requests succeed.
//
typedef struct {
UINT32 Signature;
NET_LIST_ENTRY Link;
NET_LIST_ENTRY Frames;
IP4_INTERFACE *Interface;
//
// ARP requesting staffs
//
EFI_EVENT OnResolved;
IP4_ADDR Ip;
EFI_MAC_ADDRESS Mac;
} IP4_ARP_QUE;
//
// Callback to select which frame to cancel. Caller can cancel a
// single frame, or all the frame from an IP instance.
//
typedef
BOOLEAN
(*IP4_FRAME_TO_CANCEL) (
IP4_LINK_TX_TOKEN *Frame,
VOID *Context
);
//
// Each IP4 instance has its own station address. All the instances
// with the same station address share a single interface structure.
// Each interface has its own ARP child, and shares one MNP child.
// Notice the special cases that DHCP can configure the interface
// with 0.0.0.0/0.0.0.0.
//
typedef struct _IP4_INTERFACE {
UINT32 Signature;
NET_LIST_ENTRY Link;
INTN RefCnt;
//
// IP address and subnet mask of the interface. It also contains
// the subnet/net broadcast address for quick access. The fileds
// are invalid if (Configured == FALSE)
//
IP4_ADDR Ip;
IP4_ADDR SubnetMask;
IP4_ADDR SubnetBrdcast;
IP4_ADDR NetBrdcast;
BOOLEAN Configured;
//
// Handle used to create/destory ARP child. All the IP children
// share one MNP which is owned by IP service binding.
//
EFI_HANDLE Controller;
EFI_HANDLE Image;
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
EFI_ARP_PROTOCOL *Arp;
EFI_HANDLE ArpHandle;
//
// Queues to keep the frames sent and waiting ARP request.
//
NET_LIST_ENTRY ArpQues;
NET_LIST_ENTRY SentFrames;
IP4_LINK_RX_TOKEN *RecvRequest;
//
// The interface's MAC and broadcast MAC address.
//
EFI_MAC_ADDRESS Mac;
EFI_MAC_ADDRESS BroadcastMac;
UINT32 HwaddrLen;
//
// All the IP instances that have the same IP/SubnetMask are linked
// together through IpInstances. If any of the instance enables
// promiscuous receive, PromiscRecv is true.
//
NET_LIST_ENTRY IpInstances;
BOOLEAN PromiscRecv;
} IP4_INTERFACE;
IP4_INTERFACE *
Ip4CreateInterface (
IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
IN EFI_HANDLE Controller,
IN EFI_HANDLE ImageHandle
);
EFI_STATUS
Ip4SetAddress (
IN IP4_INTERFACE *Interface,
IN IP4_ADDR IpAddr,
IN IP4_ADDR SubnetMask
);
EFI_STATUS
Ip4FreeInterface (
IN IP4_INTERFACE *Interface,
IN IP4_PROTOCOL *IpInstance OPTIONAL
);
EFI_STATUS
Ip4SendFrame (
IN IP4_INTERFACE *Interface,
IN IP4_PROTOCOL *IpInstance, OPTIONAL
IN NET_BUF *Packet,
IN IP4_ADDR NextHop,
IN IP4_FRAME_CALLBACK CallBack,
IN VOID *Context
);
VOID
Ip4CancelFrames (
IN IP4_INTERFACE *Interface,
IN EFI_STATUS IoStatus,
IN IP4_FRAME_TO_CANCEL FrameToCancel, OPTIONAL
IN VOID *Context
);
VOID
Ip4CancelReceive (
IN IP4_INTERFACE *Interface
);
EFI_STATUS
Ip4ReceiveFrame (
IN IP4_INTERFACE *Interface,
IN IP4_PROTOCOL *IpInstance, OPTIONAL
IN IP4_FRAME_CALLBACK CallBack,
IN VOID *Context
);
#endif

View File

@@ -0,0 +1,629 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Igmp.c
Abstract:
This file implements the RFC2236: IGMP v2
**/
#include "Ip4Impl.h"
//
// Route Alert option in IGMP report to direct routers to
// examine the packet more closely.
//
UINT32 mRouteAlertOption = 0x00000494;
/**
Init the IGMP control data of the IP4 service instance, configure
MNP to receive ALL SYSTEM multicast.
@param IpSb The IP4 service whose IGMP is to be initialized.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to initialize IGMP.
@retval Others Failed to initialize the IGMP of IpSb.
@retval EFI_SUCCESS IGMP of the IpSb is successfully initialized.
**/
EFI_STATUS
Ip4InitIgmp (
IN IP4_SERVICE *IpSb
)
{
IGMP_SERVICE_DATA *IgmpCtrl;
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
IGMP_GROUP *Group;
EFI_STATUS Status;
IgmpCtrl = &IpSb->IgmpCtrl;
//
// Configure MNP to receive ALL_SYSTEM multicast
//
Group = NetAllocatePool (sizeof (IGMP_GROUP));
if (Group == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Mnp = IpSb->Mnp;
Group->Address = IP4_ALLSYSTEM_ADDRESS;
Group->RefCnt = 1;
Group->DelayTime = 0;
Group->ReportByUs = FALSE;
Status = Ip4GetMulticastMac (Mnp, IP4_ALLSYSTEM_ADDRESS, &Group->Mac);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Mnp->Groups (Mnp, TRUE, &Group->Mac);
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
goto ON_ERROR;
}
NetListInsertHead (&IgmpCtrl->Groups, &Group->Link);
return EFI_SUCCESS;
ON_ERROR:
NetFreePool (Group);
return Status;
}
/**
Find the IGMP_GROUP structure which contains the status of multicast
group Address in this IGMP control block
@param IgmpCtrl The IGMP control block to search from
@param Address The multicast address to search
@return NULL if the multicast address isn't in the IGMP control block. Otherwise
@return the point to the IGMP_GROUP which contains the status of multicast group
@return for Address.
**/
IGMP_GROUP *
Ip4FindGroup (
IN IGMP_SERVICE_DATA *IgmpCtrl,
IN IP4_ADDR Address
)
{
NET_LIST_ENTRY *Entry;
IGMP_GROUP *Group;
NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);
if (Group->Address == Address) {
return Group;
}
}
return NULL;
}
/**
Count the number of IP4 multicast groups that are mapped to the
same MAC address. Several IP4 multicast address may be mapped to
the same MAC address.
@param IgmpCtrl The IGMP control block to search in
@param Mac The MAC address to search
@return The number of the IP4 multicast group that mapped to the same
@return multicast group Mac.
**/
INTN
Ip4FindMac (
IN IGMP_SERVICE_DATA *IgmpCtrl,
IN EFI_MAC_ADDRESS *Mac
)
{
NET_LIST_ENTRY *Entry;
IGMP_GROUP *Group;
INTN Count;
Count = 0;
NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);
if (NET_MAC_EQUAL (&Group->Mac, Mac, sizeof (EFI_MAC_ADDRESS))) {
Count++;
}
}
return Count;
}
/**
Send an IGMP protocol message to the Dst, such as IGMP v1 membership report.
@param IpSb The IP4 service instance that requests the
transmission
@param Dst The destinaton to send to
@param Type The IGMP message type, such as IGMP v2 membership
report
@param Group The group address in the IGMP message head.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory to build the message
@retval EFI_SUCCESS The IGMP message is successfully send
@retval Others Failed to send the IGMP message.
**/
EFI_STATUS
Ip4SendIgmpMessage (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Dst,
IN UINT8 Type,
IN IP4_ADDR Group
)
{
IP4_HEAD Head;
NET_BUF *Packet;
IGMP_HEAD *Igmp;
//
// Allocate a net buffer to hold the message
//
Packet = NetbufAlloc (IP4_MAX_HEADLEN + sizeof (IGMP_HEAD));
if (Packet == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Fill in the IGMP and IP header, then transmit the message
//
NetbufReserve (Packet, IP4_MAX_HEADLEN);
Igmp = (IGMP_HEAD *) NetbufAllocSpace (Packet, sizeof (IGMP_HEAD), FALSE);
Igmp->Type = Type;
Igmp->MaxRespTime = 0;
Igmp->Checksum = 0;
Igmp->Group = HTONL (Group);
Igmp->Checksum = ~NetblockChecksum ((UINT8 *) Igmp, sizeof (IGMP_HEAD));
Head.Tos = 0;
Head.Protocol = IP4_PROTO_IGMP;
Head.Ttl = 1;
Head.Fragment = 0;
Head.Dst = Dst;
Head.Src = IP4_ALLZERO_ADDRESS;
return Ip4Output (
IpSb,
NULL,
Packet,
&Head,
(UINT8 *) &mRouteAlertOption,
sizeof (UINT32),
IP4_ALLZERO_ADDRESS,
Ip4SysPacketSent,
NULL
);
}
/**
Send an IGMP membership report. Depends on whether the server is
v1 or v2, it will send either a V1 or V2 membership report.
@param IpSb The IP4 service instance that requests the
transmission.
@param Group The group address to report
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory to build the message
@retval EFI_SUCCESS The IGMP report message is successfully send
@retval Others Failed to send the report.
**/
EFI_STATUS
Ip4SendIgmpReport (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Group
)
{
if (IpSb->IgmpCtrl.Igmpv1QuerySeen != 0) {
return Ip4SendIgmpMessage (IpSb, Group, IGMP_V1_MEMBERSHIP_REPORT, Group);
} else {
return Ip4SendIgmpMessage (IpSb, Group, IGMP_V2_MEMBERSHIP_REPORT, Group);
}
}
/**
Join the multicast group on behavior of this IP4 child
@param IpInstance The IP4 child that wants to join the group
@param Address The group to join
@retval EFI_SUCCESS Successfully join the multicast group
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources
@retval Others Failed to join the multicast group.
**/
EFI_STATUS
Ip4JoinGroup (
IN IP4_PROTOCOL *IpInstance,
IN IP4_ADDR Address
)
{
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
IP4_SERVICE *IpSb;
IGMP_SERVICE_DATA *IgmpCtrl;
IGMP_GROUP *Group;
EFI_STATUS Status;
IpSb = IpInstance->Service;
IgmpCtrl = &IpSb->IgmpCtrl;
Mnp = IpSb->Mnp;
//
// If the IP service already is a member in the group, just
// increase the refernce count and return.
//
Group = Ip4FindGroup (IgmpCtrl, Address);
if (Group != NULL) {
Group->RefCnt++;
return EFI_SUCCESS;
}
//
// Otherwise, create a new IGMP_GROUP, Get the multicast's MAC address,
// send a report, then direct MNP to receive the multicast.
//
Group = NetAllocatePool (sizeof (IGMP_GROUP));
if (Group == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Group->Address = Address;
Group->RefCnt = 1;
Group->DelayTime = IGMP_UNSOLICIATED_REPORT;
Group->ReportByUs = TRUE;
Status = Ip4GetMulticastMac (Mnp, Address, &Group->Mac);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip4SendIgmpReport (IpSb, Address);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Mnp->Groups (Mnp, TRUE, &Group->Mac);
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
goto ON_ERROR;
}
NetListInsertHead (&IgmpCtrl->Groups, &Group->Link);
return EFI_SUCCESS;
ON_ERROR:
NetFreePool (Group);
return Status;
}
/**
Leave the IP4 multicast group on behavior of IpInstance.
@param IpInstance The IP4 child that wants to leave the group
address
@param Address The group address to leave
@retval EFI_NOT_FOUND The IP4 service instance isn't in the group
@retval EFI_SUCCESS Successfully leave the multicast group.
@retval Others Failed to leave the multicast group.
**/
EFI_STATUS
Ip4LeaveGroup (
IN IP4_PROTOCOL *IpInstance,
IN IP4_ADDR Address
)
{
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
IP4_SERVICE *IpSb;
IGMP_SERVICE_DATA *IgmpCtrl;
IGMP_GROUP *Group;
EFI_STATUS Status;
IpSb = IpInstance->Service;
IgmpCtrl = &IpSb->IgmpCtrl;
Mnp = IpSb->Mnp;
Group = Ip4FindGroup (IgmpCtrl, Address);
if (Group == NULL) {
return EFI_NOT_FOUND;
}
//
// If more than one instance is in the group, decrease
// the RefCnt then return.
//
if (--Group->RefCnt > 0) {
return EFI_SUCCESS;
}
//
// If multiple IP4 group addresses are mapped to the same
// multicast MAC address, don't configure the MNP to leave
// the MAC.
//
if (Ip4FindMac (IgmpCtrl, &Group->Mac) == 1) {
Status = Mnp->Groups (Mnp, FALSE, &Group->Mac);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
return Status;
}
}
//
// Send a leave report if the membership is reported by us
// and we are talking IGMPv2.
//
if (Group->ReportByUs && !IgmpCtrl->Igmpv1QuerySeen) {
Ip4SendIgmpMessage (IpSb, IP4_ALLROUTER_ADDRESS, IGMP_LEAVE_GROUP, Group->Address);
}
NetListRemoveEntry (&Group->Link);
NetFreePool (Group);
return EFI_SUCCESS;
}
/**
Handle the received IGMP message for the IP4 service instance.
@param IpSb The IP4 service instance that received the message
@param Head The IP4 header of the received message
@param Packet The IGMP message, without IP4 header
@retval EFI_INVALID_PARAMETER The IGMP message is malformated.
@retval EFI_SUCCESS The IGMP message is successfully processed.
**/
EFI_STATUS
Ip4IgmpHandle (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
{
IGMP_SERVICE_DATA *IgmpCtrl;
IGMP_HEAD Igmp;
IGMP_GROUP *Group;
IP4_ADDR Address;
NET_LIST_ENTRY *Entry;
IgmpCtrl = &IpSb->IgmpCtrl;
//
// Must checksum over the whole packet, later IGMP version
// may employ message longer than 8 bytes. IP's header has
// already been trimmed off.
//
if ((Packet->TotalSize < sizeof (Igmp)) || (NetbufChecksum (Packet) != 0)) {
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}
//
// Copy the packet in case it is fragmented
//
NetbufCopy (Packet, 0, sizeof (IGMP_HEAD), (UINT8 *)&Igmp);
switch (Igmp.Type) {
case IGMP_MEMBERSHIP_QUERY:
//
// If MaxRespTIme is zero, it is most likely that we are
// talking to a V1 router
//
if (Igmp.MaxRespTime == 0) {
IgmpCtrl->Igmpv1QuerySeen = IGMP_V1ROUTER_PRESENT;
Igmp.MaxRespTime = 100;
}
//
// Igmp is ticking once per second but MaxRespTime is in
// the unit of 100ms.
//
Igmp.MaxRespTime /= 10;
Address = NTOHL (Igmp.Group);
if (Address == IP4_ALLSYSTEM_ADDRESS) {
break;
}
NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);
//
// If address is all zero, all the memberships will be reported.
// otherwise only one is reported.
//
if ((Address == IP4_ALLZERO_ADDRESS) || (Address == Group->Address)) {
//
// If the timer is pending, only update it if the time left
// is longer than the MaxRespTime. TODO: randomize the DelayTime.
//
if ((Group->DelayTime == 0) || (Group->DelayTime > Igmp.MaxRespTime)) {
Group->DelayTime = NET_MAX (1, Igmp.MaxRespTime);
}
}
}
break;
case IGMP_V1_MEMBERSHIP_REPORT:
case IGMP_V2_MEMBERSHIP_REPORT:
Address = NTOHL (Igmp.Group);
Group = Ip4FindGroup (IgmpCtrl, Address);
if ((Group != NULL) && (Group->DelayTime > 0)) {
Group->DelayTime = 0;
Group->ReportByUs = FALSE;
}
break;
}
NetbufFree (Packet);
return EFI_SUCCESS;
}
/**
The periodical timer function for IGMP. It does the following
things:
1. Decrease the Igmpv1QuerySeen to make it possible to refresh
the IGMP server type.
2. Decrease the report timer for each IGMP group in "delaying
member" state.
@param IpSb The IP4 service instance that is ticking
@return None
**/
VOID
Ip4IgmpTicking (
IN IP4_SERVICE *IpSb
)
{
IGMP_SERVICE_DATA *IgmpCtrl;
NET_LIST_ENTRY *Entry;
IGMP_GROUP *Group;
IgmpCtrl = &IpSb->IgmpCtrl;
if (IgmpCtrl->Igmpv1QuerySeen > 0) {
IgmpCtrl->Igmpv1QuerySeen--;
}
//
// Decrease the report timer for each IGMP group in "delaying member"
//
NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);
ASSERT (Group->DelayTime >= 0);
if (Group->DelayTime > 0) {
Group->DelayTime--;
if (Group->DelayTime == 0) {
Ip4SendIgmpReport (IpSb, Group->Address);
Group->ReportByUs = TRUE;
}
}
}
}
/**
Add a group address to the array of group addresses.
The caller should make sure that no duplicated address
existed in the array. Although the function doesn't
assume the byte order of the both Source and Addr, the
network byte order is used by the caller.
@param Source The array of group addresses to add to
@param Count The number of group addresses in the Source
@param Addr The IP4 multicast address to add
@return NULL if failed to allocate memory for the new groups,
@return otherwise the new combined group addresses.
**/
IP4_ADDR *
Ip4CombineGroups (
IN IP4_ADDR *Source,
IN UINT32 Count,
IN IP4_ADDR Addr
)
{
IP4_ADDR *Groups;
Groups = NetAllocatePool (sizeof (IP4_ADDR) * (Count + 1));
if (Groups == NULL) {
return NULL;
}
NetCopyMem (Groups, Source, Count * sizeof (IP4_ADDR));
Groups[Count] = Addr;
return Groups;
}
/**
Remove a group address frome the array of group addresses.
Although the function doesn't assume the byte order of the
both Groups and Addr, the network byte order is used by
the caller.
@param Groups The array of group addresses to remove from
@param Count The number of group addresses in the Groups
@param Addr The IP4 multicast address to remove
@return The nubmer of group addresses in the Groups after remove.
@return It is Count if the Addr isn't in the Groups.
**/
INTN
Ip4RemoveGroupAddr (
IN IP4_ADDR *Groups,
IN UINT32 Count,
IN IP4_ADDR Addr
)
{
UINT32 Index;
for (Index = 0; Index < Count; Index++) {
if (Groups[Index] == Addr) {
break;
}
}
while (Index < Count - 1) {
Groups[Index] = Groups[Index + 1];
Index++;
}
return Index;
}

View File

@@ -0,0 +1,120 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Igmp.h
Abstract:
**/
#ifndef __EFI_IP4_IGMP_H__
#define __EFI_IP4_IGMP_H__
#pragma pack(1)
typedef struct {
UINT8 Type;
UINT8 MaxRespTime;
UINT16 Checksum;
IP4_ADDR Group;
} IGMP_HEAD;
#pragma pack()
//
// The status of multicast group. It isn't necessary to maintain
// explicit state of host state diagram. A group with non-zero
// DelayTime is in "delaying member" state. otherwise, it is in
// "idle member" state.
//
typedef struct {
NET_LIST_ENTRY Link;
INTN RefCnt;
IP4_ADDR Address;
INTN DelayTime;
BOOLEAN ReportByUs;
EFI_MAC_ADDRESS Mac;
} IGMP_GROUP;
//
// The IGMP status. Each IP4 service instance has a IGMP_SERVICE_DATA
// attached. The Igmpv1QuerySeen remember whether the server on this
// connected network is v1 or v2.
//
typedef struct {
INTN Igmpv1QuerySeen;
NET_LIST_ENTRY Groups;
} IGMP_SERVICE_DATA;
enum {
//
// IGMP message type
//
IGMP_MEMBERSHIP_QUERY = 0x11,
IGMP_V1_MEMBERSHIP_REPORT = 0x12,
IGMP_V2_MEMBERSHIP_REPORT = 0x16,
IGMP_LEAVE_GROUP = 0x17,
IGMP_V1ROUTER_PRESENT = 400,
IGMP_UNSOLICIATED_REPORT = 10,
};
EFI_STATUS
Ip4InitIgmp (
IN IP4_SERVICE *IpService
);
EFI_STATUS
Ip4JoinGroup (
IN IP4_PROTOCOL *IpInstance,
IN IP4_ADDR Address
);
EFI_STATUS
Ip4LeaveGroup (
IN IP4_PROTOCOL *IpInstance,
IN IP4_ADDR Address
);
EFI_STATUS
Ip4IgmpHandle (
IN IP4_SERVICE *IpService,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
);
VOID
Ip4IgmpTicking (
IN IP4_SERVICE *IpService
);
IP4_ADDR *
Ip4CombineGroups (
IN IP4_ADDR *SourceGroups,
IN UINT32 Count,
IN IP4_ADDR Addr
);
INTN
Ip4RemoveGroupAddr (
IN IP4_ADDR *Group,
IN UINT32 GroupCnt,
IN IP4_ADDR Addr
);
IGMP_GROUP *
Ip4FindGroup (
IN IGMP_SERVICE_DATA *IgmpCtrl,
IN IP4_ADDR Address
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,258 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Impl.h
Abstract:
Ip4 internal functions and type defintions.
**/
#ifndef __EFI_IP4_IMPL_H__
#define __EFI_IP4_IMPL_H__
#include <PiDxe.h>
#include <Protocol/IP4.h>
#include <Protocol/IP4Config.h>
#include <Protocol/Arp.h>
#include <Protocol/ManagedNetwork.h>
#include <Library/DebugLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseLib.h>
#include <Library/UefiLib.h>
#include <Library/NetLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include "IP4Common.h"
#include "IP4Driver.h"
#include "IP4If.h"
#include "Ip4Icmp.h"
#include "IP4Option.h"
#include "Ip4Igmp.h"
#include "IP4Route.h"
#include "IP4Input.h"
#include "IP4Output.h"
enum {
IP4_PROTOCOL_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', '4', 'P'),
IP4_SERVICE_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', '4', 'S'),
//
// The state of IP4 protocol. It starts from UNCONFIGED. if it is
// successfully configured, it goes to CONFIGED. if configure NULL
// is called, it becomes UNCONFIGED again. If (partly) destoried, it
// becomes DESTORY.
//
IP4_STATE_UNCONFIGED = 0,
IP4_STATE_CONFIGED,
IP4_STATE_DESTORY,
//
// The state of IP4 service. It starts from UNSTARTED. It transits
// to STARTED if autoconfigure is started. If default address is
// configured, it becomes CONFIGED. and if partly destoried, it goes
// to DESTORY.
//
IP4_SERVICE_UNSTARTED = 0,
IP4_SERVICE_STARTED,
IP4_SERVICE_CONFIGED,
IP4_SERVICE_DESTORY,
};
//
// IP4_TXTOKEN_WRAP wraps the upper layer's transmit token.
// The user's data is kept in the Packet. When fragment is
// needed, each fragment of the Packet has a reference to the
// Packet, no data is actually copied. The Packet will be
// released when all the fragments of it have been recycled by
// MNP. Upon then, the IP4_TXTOKEN_WRAP will be released, and
// user's event signalled.
//
typedef struct {
IP4_PROTOCOL *IpInstance;
EFI_IP4_COMPLETION_TOKEN *Token;
NET_BUF *Packet;
BOOLEAN Sent;
INTN Life;
} IP4_TXTOKEN_WRAP;
//
// IP4_RXDATA_WRAP wraps the data IP4 child delivers to the
// upper layers. The received packet is kept in the Packet.
// The Packet itself may be constructured from some fragments.
// All the fragments of the Packet is organized by a
// IP4_ASSEMBLE_ENTRY structure. If the Packet is recycled by
// the upper layer, the assemble entry and its associated
// fragments will be freed at last.
//
typedef struct {
NET_LIST_ENTRY Link;
IP4_PROTOCOL *IpInstance;
NET_BUF *Packet;
EFI_IP4_RECEIVE_DATA RxData;
} IP4_RXDATA_WRAP;
typedef struct _IP4_PROTOCOL {
UINT32 Signature;
EFI_IP4_PROTOCOL Ip4Proto;
EFI_HANDLE Handle;
INTN State;
IP4_SERVICE *Service;
NET_LIST_ENTRY Link; // Link to all the IP protocol from the service
//
// User's transmit/receive tokens, and received/deliverd packets
//
NET_MAP RxTokens;
NET_MAP TxTokens; // map between (User's Token, IP4_TXTOKE_WRAP)
NET_LIST_ENTRY Received; // Received but not delivered packet
NET_LIST_ENTRY Delivered; // Delivered and to be recycled packets
EFI_LOCK RecycleLock;
//
// Instance's address and route tables. There are two route tables.
// RouteTable is used by the IP4 driver to route packet. EfiRouteTable
// is used to communicate the current route info to the upper layer.
//
IP4_INTERFACE *Interface;
NET_LIST_ENTRY AddrLink; // Ip instances with the same IP address.
IP4_ROUTE_TABLE *RouteTable;
EFI_IP4_ROUTE_TABLE *EfiRouteTable;
UINT32 EfiRouteCount;
//
// IGMP data for this instance
//
IP4_ADDR *Groups; // stored in network byte order
UINT32 GroupCount;
EFI_IP4_CONFIG_DATA ConfigData;
} IP4_PROTOCOL;
typedef struct _IP4_SERVICE {
UINT32 Signature;
EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
INTN State;
BOOLEAN InDestory;
//
// List of all the IP instances and interfaces, and default
// interface and route table and caches.
//
UINTN NumChildren;
NET_LIST_ENTRY Children;
NET_LIST_ENTRY Interfaces;
IP4_INTERFACE *DefaultInterface;
IP4_ROUTE_TABLE *DefaultRouteTable;
//
// Ip reassemble utilities, and IGMP data
//
IP4_ASSEMBLE_TABLE Assemble;
IGMP_SERVICE_DATA IgmpCtrl;
//
// Low level protocol used by this service instance
//
EFI_HANDLE Image;
EFI_HANDLE Controller;
EFI_HANDLE MnpChildHandle;
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
EFI_MANAGED_NETWORK_CONFIG_DATA MnpConfigData;
EFI_SIMPLE_NETWORK_MODE SnpMode;
EFI_EVENT Timer;
//
// Auto configure staff
//
EFI_IP4_CONFIG_PROTOCOL *Ip4Config;
EFI_EVENT DoneEvent;
EFI_EVENT ReconfigEvent;
//
// The string representation of the current mac address of the
// NIC this IP4_SERVICE works on.
//
CHAR16 *MacString;
} IP4_SERVICE;
#define IP4_INSTANCE_FROM_PROTOCOL(Ip4) \
CR ((Ip4), IP4_PROTOCOL, Ip4Proto, IP4_PROTOCOL_SIGNATURE)
#define IP4_SERVICE_FROM_PROTOCOL(Sb) \
CR ((Sb), IP4_SERVICE, ServiceBinding, IP4_SERVICE_SIGNATURE)
#define IP4_NO_MAPPING(IpInstance) (!(IpInstance)->Interface->Configured)
extern EFI_IP4_PROTOCOL mEfiIp4ProtocolTemplete;
EFI_STATUS
Ip4ServiceConfigMnp (
IN IP4_SERVICE *IpSb,
IN BOOLEAN Force
);
VOID
Ip4InitProtocol (
IN IP4_SERVICE *IpSb,
IN IP4_PROTOCOL *IpInstance
);
EFI_STATUS
Ip4CleanProtocol (
IN IP4_PROTOCOL *IpInstance
);
EFI_STATUS
Ip4Cancel (
IN IP4_PROTOCOL *IpInstance,
IN EFI_IP4_COMPLETION_TOKEN *Token
);
EFI_STATUS
Ip4Groups (
IN IP4_PROTOCOL *IpInstance,
IN BOOLEAN JoinFlag,
IN EFI_IPv4_ADDRESS *GroupAddress
);
VOID
EFIAPI
Ip4TimerTicking (
IN EFI_EVENT Event,
IN VOID *Context
);
EFI_STATUS
Ip4SentPacketTicking (
IN NET_MAP *Map,
IN NET_MAP_ITEM *Item,
IN VOID *Context
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,138 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Input.h
Abstract:
**/
#ifndef __EFI_IP4_INPUT_H__
#define __EFI_IP4_INPUT_H__
enum {
IP4_MIN_HEADLEN = 20,
IP4_MAX_HEADLEN = 60,
IP4_ASSEMLE_HASH_SIZE = 31,
IP4_FRAGMENT_LIFE = 120,
IP4_MAX_PACKET_SIZE = 65535,
};
//
// Per packet information for input process. LinkFlag specifies whether
// the packet is received as Link layer unicast, multicast or broadcast.
// The CastType is the IP layer cast type, such as IP multicast or unicast.
// Start, End and Length are staffs used to assemble the packets. Start
// is the sequence number of the first byte of data in the packet. Length
// is the number of bytes of data. End = Start + Length, that is, the
// sequence number of last byte + 1. Each assembled packet has a count down
// life. If it isn't consumed before Life reaches zero, the packet is released.
//
typedef struct {
UINTN LinkFlag;
INTN CastType;
INTN Start;
INTN End;
INTN Length;
UINT32 Life;
EFI_STATUS Status;
} IP4_CLIP_INFO;
//
// Structure used to assemble IP packets.
//
typedef struct {
NET_LIST_ENTRY Link;
//
// Identity of one IP4 packet. Each fragment of a packet has
// the same (Dst, Src, Id, Protocol).
//
IP4_ADDR Dst;
IP4_ADDR Src;
UINT16 Id;
UINT8 Protocol;
INTN TotalLen;
INTN CurLen;
NET_LIST_ENTRY Fragments; // List of all the fragments of this packet
IP4_HEAD *Head; // IP head of the first fragment
IP4_CLIP_INFO *Info; // Per packet info of the first fragment
INTN Life; // Count down life for the packet.
} IP4_ASSEMBLE_ENTRY;
//
// Each Ip service instance has an assemble table to reassemble
// the packets before delivery to its children. It is organized
// as hash table.
//
typedef struct {
NET_LIST_ENTRY Bucket[IP4_ASSEMLE_HASH_SIZE];
} IP4_ASSEMBLE_TABLE;
#define IP4_GET_CLIP_INFO(Packet) ((IP4_CLIP_INFO *) ((Packet)->ProtoData))
#define IP4_ASSEMBLE_HASH(Dst, Src, Id, Proto) \
(((Dst) + (Src) + ((Id) << 16) + (Proto)) % IP4_ASSEMLE_HASH_SIZE)
#define IP4_RXDATA_WRAP_SIZE(NumFrag) \
(sizeof (IP4_RXDATA_WRAP) + sizeof (EFI_IP4_FRAGMENT_DATA) * ((NumFrag) - 1))
VOID
Ip4InitAssembleTable (
IN IP4_ASSEMBLE_TABLE *Table
);
VOID
Ip4CleanAssembleTable (
IN IP4_ASSEMBLE_TABLE *Table
);
VOID
Ip4AccpetFrame (
IN IP4_PROTOCOL *Ip4Instance,
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus,
IN UINT32 Flag,
IN VOID *Context
);
EFI_STATUS
Ip4Demultiplex (
IN IP4_SERVICE *SbInstance,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
);
INTN
Ip4InterfaceEnquePacket (
IN IP4_SERVICE *SbInstance,
IN IP4_HEAD *Head,
IN NET_BUF *Packet,
IN IP4_INTERFACE *Interface
);
EFI_STATUS
Ip4InstanceDeliverPacket (
IN IP4_PROTOCOL *Ip4Instance
);
VOID
Ip4PacketTimerTicking (
IN IP4_SERVICE *IpSb
);
#endif

View File

@@ -0,0 +1,231 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Option.c
Abstract:
IP4 option support functions
**/
#include "Ip4Impl.h"
/**
Validate the IP4 option format for both the packets we received
and will transmit. It will compute the ICMP error message fields
if the option is mal-formated. But this information isn't used.
@param Option The first byte of the option
@param OptionLen The length of the whole option
@param Rcvd The option is from the packet we received if TRUE,
otherwise the option we wants to transmit.
@return TRUE: The option is properly formated
@return FALSE: The option is mal-formated
**/
BOOLEAN
Ip4OptionIsValid (
IN UINT8 *Option,
IN UINT32 OptionLen,
IN BOOLEAN Rcvd
)
{
UINT32 Cur;
UINT32 Len;
UINT32 Point;
UINT8 IcmpType;
UINT8 IcmpCode;
UINT32 IcmpPoint;
IcmpType = ICMP_PARAMETER_PROBLEM;
IcmpCode = 0;
IcmpPoint = 0;
Cur = 0;
while (Cur < OptionLen) {
switch (Option[Cur]) {
case IP4_OPTION_NOP:
Cur++;
break;
case IP4_OPTION_EOP:
Cur = OptionLen;
break;
case IP4_OPTION_LSRR:
case IP4_OPTION_SSRR:
case IP4_OPTION_RR:
Len = Option[Cur + 1];
Point = Option[Cur + 2];
//
// SRR/RR options are formated as |Type|Len|Point|Ip1|Ip2|...
//
if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) {
IcmpPoint = Cur + 1;
return FALSE;
}
if ((Point > Len + 1) || (Point % 4 != 0)) {
IcmpPoint = Cur + 2;
return FALSE;
}
//
// The Point must point pass the last entry if the packet is received
// by us. It must point to 4 if the packet is to be sent by us for
// source route option.
//
if ((Option[Cur] != IP4_OPTION_RR) &&
((Rcvd && (Point != Len + 1)) || (!Rcvd && (Point != 4)))) {
IcmpType = ICMP_DEST_UNREACHABLE;
IcmpCode = ICMP_SOURCEROUTE_FAILED;
return FALSE;
}
Cur += Len;
break;
default:
Len = Option[Cur + 1];
if ((OptionLen - Cur < Len) || (Len < 2)) {
IcmpPoint = Cur + 1;
return FALSE;
}
Cur = Cur + Len;
break;
}
}
return TRUE;
}
/**
Copy the option from the original option to buffer. It
handles the details such as:
1. whether copy the single IP4 option to the first/non-first
fragments.
2. Pad the options copied over to aligened to 4 bytes.
@param Option The original option to copy from
@param OptionLen The length of the original option
@param FirstFragment Whether it is the first fragment
@param Buf The buffer to copy options to
@param BufLen The length of the buffer
@retval EFI_SUCCESS The options are copied over
@retval EFI_BUFFER_TOO_SMALL The buffer caller provided is too small.
**/
EFI_STATUS
Ip4CopyOption (
IN UINT8 *Option,
IN UINT32 OptionLen,
IN BOOLEAN FirstFragment,
IN UINT8 *Buf, OPTIONAL
IN OUT UINT32 *BufLen
)
{
UINT8 OptBuf[40];
UINT32 Cur;
UINT32 Next;
UINT8 Type;
UINT32 Len;
ASSERT ((BufLen != NULL) && (OptionLen <= 40));
Cur = 0;
Next = 0;
while (Cur < OptionLen) {
Type = Option[Cur];
Len = Option[Cur + 1];
if (Type == IP4_OPTION_NOP) {
//
// Keep the padding, in case that the sender wants to align
// the option, say, to 4 bytes
//
OptBuf[Next] = IP4_OPTION_NOP;
Next++;
Cur++;
} else if (Type == IP4_OPTION_EOP) {
//
// Don't append the EOP to avoid including only a EOP option
//
break;
} else {
//
// don't copy options that is only valid for the first fragment
//
if (FirstFragment || (Type & IP4_OPTION_COPY_MASK)) {
NetCopyMem (OptBuf + Next, Option + Cur, Len);
Next += Len;
}
Cur += Len;
}
}
//
// Don't append an EOP only option.
//
if (Next == 0) {
*BufLen = 0;
return EFI_SUCCESS;
}
//
// Append an EOP if the end of option doesn't coincide with the
// end of the IP header, that is, isn't aligned to 4 bytes..
//
if ((Next % 4) != 0) {
OptBuf[Next] = IP4_OPTION_EOP;
Next++;
}
//
// Head length is in the unit of 4 bytes. Now, Len is the
// acutal option length to appear in the IP header.
//
Len = ((Next + 3) &~0x03);
//
// If the buffer is too small, set the BufLen then return
//
if ((Buf == NULL) || (*BufLen < Len)) {
*BufLen = Len;
return EFI_BUFFER_TOO_SMALL;
}
//
// Copy the option to the Buf, zero the buffer first to pad
// the options with NOP to align to 4 bytes.
//
NetZeroMem (Buf, Len);
NetCopyMem (Buf, OptBuf, Next);
*BufLen = Len;
return EFI_SUCCESS;
}

View File

@@ -0,0 +1,52 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Option.h
Abstract:
IP4 option support routines.
**/
#ifndef __EFI_IP4_OPTION_H__
#define __EFI_IP4_OPTION_H__
enum {
IP4_OPTION_EOP = 0,
IP4_OPTION_NOP = 1,
IP4_OPTION_LSRR = 131, // Loss source and record routing, 10000011
IP4_OPTION_SSRR = 137, // Strict source and record routing, 10001001
IP4_OPTION_RR = 7, // Record routing, 00000111
IP4_OPTION_COPY_MASK = 0x80,
};
BOOLEAN
Ip4OptionIsValid (
IN UINT8 *Option,
IN UINT32 OptLen,
IN BOOLEAN Rcvd
);
EFI_STATUS
Ip4CopyOption (
IN UINT8 *Option,
IN UINT32 OptLen,
IN BOOLEAN Fragment,
IN UINT8 *Buf, OPTIONAL
IN OUT UINT32 *BufLen
);
#endif

View File

@@ -0,0 +1,457 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Output.c
Abstract:
Transmit the IP4 packet
**/
#include "Ip4Impl.h"
UINT16 mIp4Id;
/**
Prepend an IP4 head to the Packet. It will copy the options and
build the IP4 header fields. Used for IP4 fragmentation.
@param Packet The packet to prepend IP4 header to
@param Head The caller supplied header. The caller should set
the following header fields: Tos, TotalLen, Id,
Fragment, Ttl, Protocol, Src and Dst. All the fields
are in host byte order. This function will fill in
the Ver, HeadLen, and checksum.
@param Option The orginal IP4 option to copy from
@param OptLen The length of the IP4 option
@retval EFI_BAD_BUFFER_SIZE There is no enought room in the head space of
Packet.
@retval EFI_SUCCESS The IP4 header is successfully added to the packet.
**/
EFI_STATUS
Ip4PrependHead (
IN NET_BUF *Packet,
IN IP4_HEAD *Head,
IN UINT8 *Option,
IN UINT32 OptLen
)
{
UINT32 HeadLen;
UINT32 Len;
IP4_HEAD *PacketHead;
BOOLEAN FirstFragment;
//
// Prepend the options: first get the option length, then copy it over.
//
HeadLen = 0;
FirstFragment = IP4_FIRST_FRAGMENT (Head->Fragment);
Ip4CopyOption (Option, OptLen, FirstFragment, NULL, &Len);
HeadLen = IP4_MIN_HEADLEN + Len;
ASSERT (((Len %4) == 0) && (HeadLen <= IP4_MAX_HEADLEN));
PacketHead = (IP4_HEAD *) NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);
if (PacketHead == NULL) {
return EFI_BAD_BUFFER_SIZE;
}
Ip4CopyOption (Option, OptLen, FirstFragment, (UINT8 *) (PacketHead + 1), &Len);
//
// Set the head up, convert the host byte order to network byte order
//
PacketHead->Ver = 4;
PacketHead->HeadLen = (UINT8) (HeadLen >> 2);
PacketHead->Tos = Head->Tos;
PacketHead->TotalLen = HTONS (Packet->TotalSize);
PacketHead->Id = HTONS (Head->Id);
PacketHead->Fragment = HTONS (Head->Fragment);
PacketHead->Checksum = 0;
PacketHead->Ttl = Head->Ttl;
PacketHead->Protocol = Head->Protocol;
PacketHead->Src = HTONL (Head->Src);
PacketHead->Dst = HTONL (Head->Dst);
PacketHead->Checksum = ~NetblockChecksum ((UINT8 *) PacketHead, HeadLen);
Packet->Ip = PacketHead;
return EFI_SUCCESS;
}
/**
Select an interface to send the packet generated in the IP4 driver
itself, that is, not by the requests of IP4 child's consumer. Such
packets include the ICMP echo replies, and other ICMP error packets.
@param IpSb The IP4 service that wants to send the packets.
@param Dst The destination of the packet
@param Src The source of the packet
@return NULL if no proper interface is found, otherwise the interface that
@return can be used to send the system packet from.
**/
IP4_INTERFACE *
Ip4SelectInterface (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Dst,
IN IP4_ADDR Src
)
{
IP4_INTERFACE *IpIf;
IP4_INTERFACE *Selected;
NET_LIST_ENTRY *Entry;
//
// Select the interface the Dst is on if one of the connected
// network. Some IP instance may be configured with 0.0.0.0/0,
// don't select that interface now.
//
IpIf = Ip4FindNet (IpSb, Dst);
if ((IpIf != NULL) && (IpIf->Ip != IP4_ALLZERO_ADDRESS)) {
return IpIf;
}
//
// If source is one of the interface address, select it.
//
IpIf = Ip4FindInterface (IpSb, Src);
if ((IpIf != NULL) && (IpIf->Ip != IP4_ALLZERO_ADDRESS)) {
return IpIf;
}
//
// Select a configured interface as the fall back. Always prefer
// an interface with non-zero address.
//
Selected = NULL;
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
if (IpIf->Configured && ((Selected == NULL) || (Selected->Ip == 0))) {
Selected = IpIf;
}
}
return Selected;
}
/**
The default callback function for system generated packet.
It will free the packet.
@param Ip4Instance The IP4 child that issued the transmission. It most
like is NULL.
@param Packet The packet that transmitted.
@param IoStatus The result of the transmission, succeeded or failed.
@param LinkFlag Not used when transmission. check IP4_FRAME_CALLBACK
for reference.
@param Context The context provided by us
@return None
**/
VOID
Ip4SysPacketSent (
IP4_PROTOCOL *Ip4Instance,
NET_BUF *Packet,
EFI_STATUS IoStatus,
UINT32 LinkFlag,
VOID *Context
)
{
NetbufFree (Packet);
}
/**
Transmit an IP4 packet. The packet comes either from the IP4
child's consumer (IpInstance != NULL) or the IP4 driver itself
(IpInstance == NULL). It will route the packet, fragment it,
then transmit all the fragments through some interface.
@param IpSb The IP4 service instance to transmit the packet
@param IpInstance The IP4 child that issues the transmission. It is
NULL if the packet is from the system.
@param Packet The user data to send, excluding the IP header.
@param Head The caller supplied header. The caller should set
the following header fields: Tos, TotalLen, Id, tl,
Fragment, Protocol, Src and Dst. All the fields are
in host byte order. This function will fill in the
Ver, HeadLen, Fragment, and checksum. The Fragment
only need to include the DF flag. Ip4Output will
compute the MF and offset for you.
@param Option The original option to append to the IP headers
@param OptLen The length of the option
@param GateWay The next hop address to transmit packet to.
255.255.255.255 means broadcast.
@param Callback The callback function to issue when transmission
completed.
@param Context The opaque context for the callback
@retval EFI_NO_MAPPING There is no interface to the destination.
@retval EFI_NOT_FOUND There is no route to the destination
@retval EFI_SUCCESS The packet is successfully transmitted.
@retval Others Failed to transmit the packet.
**/
EFI_STATUS
Ip4Output (
IN IP4_SERVICE *IpSb,
IN IP4_PROTOCOL *IpInstance, OPTIONAL
IN NET_BUF *Packet,
IN IP4_HEAD *Head,
IN UINT8 *Option,
IN UINT32 OptLen,
IN IP4_ADDR GateWay,
IN IP4_FRAME_CALLBACK Callback,
IN VOID *Context
)
{
IP4_INTERFACE *IpIf;
IP4_ROUTE_CACHE_ENTRY *CacheEntry;
IP4_ADDR Dest;
EFI_STATUS Status;
NET_BUF *Fragment;
UINT32 Index;
UINT32 HeadLen;
UINT32 PacketLen;
UINT32 Offset;
UINT32 Mtu;
UINT32 Num;
//
// Select an interface/source for system packet, application
// should select them itself.
//
if (IpInstance == NULL) {
IpIf = Ip4SelectInterface (IpSb, Head->Dst, Head->Src);
} else {
IpIf = IpInstance->Interface;
}
if (IpIf == NULL) {
return EFI_NO_MAPPING;
}
if ((Head->Src == IP4_ALLZERO_ADDRESS) && (IpInstance == NULL)) {
Head->Src = IpIf->Ip;
}
//
// Route the packet unless overrided, that is, GateWay isn't zero.
//
if (GateWay == IP4_ALLZERO_ADDRESS) {
Dest = Head->Dst;
if (IP4_IS_BROADCAST (Ip4GetNetCast (Dest, IpIf)) || (Dest == IP4_ALLONE_ADDRESS)) {
//
// Set the gateway to local broadcast if the Dest is
// is the broadcast address for the connected network
// or it is local broadcast.
//
GateWay = IP4_ALLONE_ADDRESS;
} else if (IP4_IS_MULTICAST (Dest)) {
//
// Set the gateway to the destination if it is an multicast
// address. The IP4_INTERFACE won't consult ARP to send local
// broadcast and multicast.
//
GateWay = Head->Dst;
} else {
//
// Consult the route table to route the packet
//
if (IpInstance == NULL) {
CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src);
} else {
CacheEntry = Ip4Route (IpInstance->RouteTable, Head->Dst, Head->Src);
}
if (CacheEntry == NULL) {
return EFI_NOT_FOUND;
}
GateWay = CacheEntry->NextHop;
Ip4FreeRouteCacheEntry (CacheEntry);
}
}
//
// OK, selected the source and route, fragment the packet then send
// them. Tag each fragment other than the first one as spawn from it.
//
Mtu = IpSb->SnpMode.MaxPacketSize;
HeadLen = sizeof (IP4_HEAD) + (OptLen + 3) &~0x03;
Head->Id = mIp4Id++;
if (Packet->TotalSize + HeadLen > Mtu) {
//
// Packet is fragmented from the tail to the head, that is, the
// first frame sent is the last fragment of the packet. The first
// fragment is NOT sent in this loop. First compute how many
// fragments there are.
//
Mtu = (Mtu - HeadLen) & (~0x07);
Num = (Packet->TotalSize + Mtu - 1) / Mtu;
//
// Initialize the packet length and Offset. Other than the last
// fragment, the packet length equals to MTU. The offset is always
// aligned to MTU.
//
PacketLen = Packet->TotalSize - (Num - 1) * Mtu;
Offset = Mtu * (Num - 1);
for (Index = 0; Index < Num - 1; Index++, Offset -= Mtu) {
Fragment = NetbufGetFragment (Packet, Offset, PacketLen, IP4_MAX_HEADLEN);
if (Fragment == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
//
// Update the header's fragment. The caller fills the IP4 header
// fields that are required by Ip4PrependHead except the fragment.
//
Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, (Index != 0), Offset);
Ip4PrependHead (Fragment, Head, Option, OptLen);
//
// Transmit the fragments, pass the Packet address as the context.
// So, we can find all the fragments spawned from the Packet by
// compare the NetBuf and Context to the Packet.
//
Status = Ip4SendFrame (
IpIf,
IpInstance,
Fragment,
GateWay,
Ip4SysPacketSent,
Packet
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
PacketLen = Mtu;
}
//
// Trim the already sent data, then adjust the head's fragment field.
//
NetbufTrim (Packet, Packet->TotalSize - Mtu, FALSE);
Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, TRUE, 0);
}
//
// Send the first fragment, it is either the orginal packet, or the
// first fragment of a fragmented packet. It seems that there is a subtle
// bug here: what if the caller free the packet in Callback and IpIf (or
// MNP child used by that interface) still holds the fragments and try
// to access the data? The caller can free the packet if it recycles the
// consumer's (such as UDP) data in the Callback. But this can't happen.
// The detailed sequence is:
// 1. for the packets generated by IP4 driver itself:
// The Callback is Ip4SysPacketSent, which is the same as the
// fragments' callback. Ip4SysPacketSent simply calls NetbufFree
// to release its reference to the packet. So, no problem for
// system packets.
//
// 2. for the upper layer's packets (use UDP as an example):
// UDP requests the IP layer to transmit some data which is
// wrapped in an asynchronous token, the token is wrapped
// in IP4_TXTOKEN_WRAP by IP4. IP4 also wrap the user's data
// in a net buffer, which is Packet we get here. IP4_TXTOKEN_WRAP
// is bound with the Packet. It will only be freed when all
// the references to Packet have been released. Upon then, the
// Packet's OnFree callback will release the IP4_TXTOKEN_WRAP,
// and singal the user's recycle event. So, also no problem for
// upper layer's packets.
//
Ip4PrependHead (Packet, Head, Option, OptLen);
Status = Ip4SendFrame (IpIf, IpInstance, Packet, GateWay, Callback, Context);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
return EFI_SUCCESS;
ON_ERROR:
Ip4CancelPacket (IpIf, Packet, Status);
return Status;
}
/**
The filter function to find a packet and all its fragments.
The packet's fragments have their Context set to the packet.
@param Frame The frames hold by the low level interface
@param Context Context to the function, which is the packet.
@retval TRUE This is the packet to cancel or its fragments.
@retval FALSE This is unrelated packet.
**/
STATIC
BOOLEAN
Ip4CancelPacketFragments (
IP4_LINK_TX_TOKEN *Frame,
VOID *Context
)
{
if ((Frame->Packet == (NET_BUF *) Context) || (Frame->Context == Context)) {
return TRUE;
}
return FALSE;
}
/**
Cancel the Packet and all its fragments.
@param IpIf The interface from which the Packet is sent
@param Packet The Packet to cancel
@param IoStatus The status returns to the sender.
@return None
**/
VOID
Ip4CancelPacket (
IN IP4_INTERFACE *IpIf,
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus
)
{
Ip4CancelFrames (IpIf, IoStatus, Ip4CancelPacketFragments, Packet);
}

View File

@@ -0,0 +1,54 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Output.h
Abstract:
**/
#ifndef __EFI_IP4_OUTPUT_H__
#define __EFI_IP4_OUTPUT_H__
VOID
Ip4SysPacketSent (
IP4_PROTOCOL *Ip4Instance,
NET_BUF *Packet,
EFI_STATUS IoStatus,
UINT32 Flag,
VOID *Context
);
EFI_STATUS
Ip4Output (
IN IP4_SERVICE *IpSb,
IN IP4_PROTOCOL *IpInstance, OPTIONAL
IN NET_BUF *Data,
IN IP4_HEAD *Head,
IN UINT8 *Option,
IN UINT32 OptLen,
IN IP4_ADDR GateWay,
IN IP4_FRAME_CALLBACK Callback,
IN VOID *Context
);
VOID
Ip4CancelPacket (
IN IP4_INTERFACE *IpIf,
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus
);
extern UINT16 mIp4Id;
#endif

View File

@@ -0,0 +1,690 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Route.c
Abstract:
**/
#include "Ip4Impl.h"
/**
Allocate a route entry then initialize it with the Dest/Netmaks
and Gateway.
@param Dest The destination network
@param Netmask The destination network mask
@param GateWay The nexthop address
@return NULL if failed to allocate memeory, otherwise the newly created
@return route entry.
**/
STATIC
IP4_ROUTE_ENTRY *
Ip4CreateRouteEntry (
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR GateWay
)
{
IP4_ROUTE_ENTRY *RtEntry;
RtEntry = NetAllocatePool (sizeof (IP4_ROUTE_ENTRY));
if (RtEntry == NULL) {
return NULL;
}
NetListInit (&RtEntry->Link);
RtEntry->RefCnt = 1;
RtEntry->Dest = Dest;
RtEntry->Netmask = Netmask;
RtEntry->NextHop = GateWay;
RtEntry->Flag = 0;
return RtEntry;
}
/**
Free the route table entry. It is reference counted.
@param RtEntry The route entry to free.
@return NONE
**/
STATIC
VOID
Ip4FreeRouteEntry (
IN IP4_ROUTE_ENTRY *RtEntry
)
{
ASSERT (RtEntry->RefCnt > 0);
if (--RtEntry->RefCnt == 0) {
NetFreePool (RtEntry);
}
}
/**
Allocate and initialize a IP4 route cache entry.
@param Dst The destination address
@param Src The source address
@param GateWay The next hop address
@param Tag The tag from the caller. This marks all the cache
entries spawned from one route table entry.
@return NULL if failed to allocate memory for the cache, other point
@return to the created route cache entry.
**/
STATIC
IP4_ROUTE_CACHE_ENTRY *
Ip4CreateRouteCacheEntry (
IN IP4_ADDR Dst,
IN IP4_ADDR Src,
IN IP4_ADDR GateWay,
IN UINTN Tag
)
{
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
RtCacheEntry = NetAllocatePool (sizeof (IP4_ROUTE_CACHE_ENTRY));
if (RtCacheEntry == NULL) {
return NULL;
}
NetListInit (&RtCacheEntry->Link);
RtCacheEntry->RefCnt = 1;
RtCacheEntry->Dest = Dst;
RtCacheEntry->Src = Src;
RtCacheEntry->NextHop = GateWay;
RtCacheEntry->Tag = Tag;
return RtCacheEntry;
}
/**
Free the route cache entry. It is reference counted.
@param RtCacheEntry The route cache entry to free.
@return None
**/
VOID
Ip4FreeRouteCacheEntry (
IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry
)
{
ASSERT (RtCacheEntry->RefCnt > 0);
if (--RtCacheEntry->RefCnt == 0) {
NetFreePool (RtCacheEntry);
}
}
/**
Initialize an empty route cache table.
@param RtCache The rotue cache table to initialize.
@return NONE
**/
VOID
Ip4InitRouteCache (
IN IP4_ROUTE_CACHE *RtCache
)
{
UINT32 Index;
for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {
NetListInit (&(RtCache->CacheBucket[Index]));
}
}
/**
Clean up a route cache, that is free all the route cache
entries enqueued in the cache.
@param RtCache The route cache table to clean up
@return None
**/
VOID
Ip4CleanRouteCache (
IN IP4_ROUTE_CACHE *RtCache
)
{
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
UINT32 Index;
for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtCache->CacheBucket[Index])) {
RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
NetListRemoveEntry (Entry);
Ip4FreeRouteCacheEntry (RtCacheEntry);
}
}
}
/**
Create an empty route table, includes its internal route cache
None
@return NULL if failed to allocate memory for the route table, otherwise
@return the point to newly created route table.
**/
IP4_ROUTE_TABLE *
Ip4CreateRouteTable (
VOID
)
{
IP4_ROUTE_TABLE *RtTable;
UINT32 Index;
RtTable = NetAllocatePool (sizeof (IP4_ROUTE_TABLE));
if (RtTable == NULL) {
return NULL;
}
RtTable->RefCnt = 1;
RtTable->TotalNum = 0;
for (Index = 0; Index < IP4_MASK_NUM; Index++) {
NetListInit (&(RtTable->RouteArea[Index]));
}
RtTable->Next = NULL;
Ip4InitRouteCache (&RtTable->Cache);
return RtTable;
}
/**
Free the route table and its associated route cache. Route
table is reference counted.
@param RtTable The route table to free.
@return None
**/
VOID
Ip4FreeRouteTable (
IN IP4_ROUTE_TABLE *RtTable
)
{
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_ROUTE_ENTRY *RtEntry;
UINT32 Index;
ASSERT (RtTable->RefCnt > 0);
if (--RtTable->RefCnt > 0) {
return ;
}
//
// Free all the route table entry and its route cache.
//
for (Index = 0; Index < IP4_MASK_NUM; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtTable->RouteArea[Index])) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
NetListRemoveEntry (Entry);
Ip4FreeRouteEntry (RtEntry);
}
}
Ip4CleanRouteCache (&RtTable->Cache);
NetFreePool (RtTable);
}
/**
Remove all the cache entries bearing the Tag. When a route cache
entry is created, it is tagged with the address of route entry
from which it is spawned. When a route entry is deleted, the cache
entries spawned from it are also deleted.
@param RtCache Route cache to remove the entries from
@param Tag The Tag of the entries to remove
@return None
**/
STATIC
VOID
Ip4PurgeRouteCache (
IN IP4_ROUTE_CACHE *RtCache,
IN UINTN Tag
)
{
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
UINT32 Index;
for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtCache->CacheBucket[Index]) {
RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
if (RtCacheEntry->Tag == Tag) {
NetListRemoveEntry (Entry);
Ip4FreeRouteCacheEntry (RtCacheEntry);
}
}
}
}
/**
Add a route entry to the route table. All the IP4_ADDRs are in
host byte order.
@param RtTable Route table to add route to
@param Dest The destination of the network
@param Netmask The netmask of the destination
@param Gateway The next hop address
@retval EFI_ACCESS_DENIED The same route already exists
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the entry
@retval EFI_SUCCESS The route is added successfully.
**/
EFI_STATUS
Ip4AddRoute (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR Gateway
)
{
NET_LIST_ENTRY *Head;
NET_LIST_ENTRY *Entry;
IP4_ROUTE_ENTRY *RtEntry;
//
// All the route entries with the same netmask length are
// linke to the same route area
//
Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);
//
// First check whether the route exists
//
NET_LIST_FOR_EACH (Entry, Head) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {
return EFI_ACCESS_DENIED;
}
}
//
// Create a route entry and insert it to the route area.
//
RtEntry = Ip4CreateRouteEntry (Dest, Netmask, Gateway);
if (RtEntry == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (Gateway == IP4_ALLZERO_ADDRESS) {
RtEntry->Flag = IP4_DIRECT_ROUTE;
}
NetListInsertHead (Head, &RtEntry->Link);
RtTable->TotalNum++;
return EFI_SUCCESS;
}
/**
Remove a route entry and all the route caches spawn from it.
@param RtTable The route table to remove the route from
@param Dest The destination network
@param Netmask The netmask of the Dest
@param Gateway The next hop address
@retval EFI_SUCCESS The route entry is successfully removed
@retval EFI_NOT_FOUND There is no route entry in the table with that
properity.
**/
EFI_STATUS
Ip4DelRoute (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR Gateway
)
{
NET_LIST_ENTRY *Head;
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_ROUTE_ENTRY *RtEntry;
Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);
NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {
Ip4PurgeRouteCache (&RtTable->Cache, (UINTN) RtEntry);
NetListRemoveEntry (Entry);
Ip4FreeRouteEntry (RtEntry);
RtTable->TotalNum--;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
Find a route cache with the dst and src. This is used by ICMP
redirect messasge process. All kinds of redirect is treated as
host redirect according to RFC1122. So, only route cache entries
are modified according to the ICMP redirect message.
@param RtTable The route table to search the cache for
@param Dest The destination address
@param Src The source address
@return NULL if no route entry to the (Dest, Src). Otherwise the point
@return to the correct route cache entry.
**/
IP4_ROUTE_CACHE_ENTRY *
Ip4FindRouteCache (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Src
)
{
NET_LIST_ENTRY *Entry;
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
UINT32 Index;
Index = IP4_ROUTE_CACHE_HASH (Dest, Src);
NET_LIST_FOR_EACH (Entry, &RtTable->Cache.CacheBucket[Index]) {
RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
if ((RtCacheEntry->Dest == Dest) && (RtCacheEntry->Src == Src)) {
NET_GET_REF (RtCacheEntry);
return RtCacheEntry;
}
}
return NULL;
}
/**
Search the route table for a most specific match to the Dst. It searches
from the longest route area (mask length == 32) to the shortest route area (
default routes). In each route area, it will first search the instance's
route table, then the default route table. This is required by the following
requirements:
1. IP search the route table for a most specific match
2. The local route entries have precedence over the default route entry.
@param RtTable The route table to search from
@param Dst The destionation address to search
@return NULL if no route matches the Dst, otherwise the point to the
@return most specific route to the Dst.
**/
STATIC
IP4_ROUTE_ENTRY *
Ip4FindRouteEntry (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dst
)
{
NET_LIST_ENTRY *Entry;
IP4_ROUTE_ENTRY *RtEntry;
IP4_ROUTE_TABLE *Table;
INTN Index;
RtEntry = NULL;
for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {
for (Table = RtTable; Table != NULL; Table = Table->Next) {
NET_LIST_FOR_EACH (Entry, &Table->RouteArea[Index]) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
if (IP4_NET_EQUAL (RtEntry->Dest, Dst, RtEntry->Netmask)) {
NET_GET_REF (RtEntry);
return RtEntry;
}
}
}
}
return NULL;
}
/**
Search the route table to route the packet. Return/creat a route
cache if there is a route to the destination.
@param RtTable The route table to search from
@param Dest The destination address to search for
@param Src The source address to search for
@return NULL if failed to route packet, otherwise a route cache
@return entry that can be used to route packet.
**/
IP4_ROUTE_CACHE_ENTRY *
Ip4Route (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Src
)
{
NET_LIST_ENTRY *Head;
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
IP4_ROUTE_CACHE_ENTRY *Cache;
IP4_ROUTE_ENTRY *RtEntry;
IP4_ADDR NextHop;
UINT32 Count;
ASSERT (RtTable != NULL);
Head = &RtTable->Cache.CacheBucket[IP4_ROUTE_CACHE_HASH (Dest, Src)];
RtCacheEntry = Ip4FindRouteCache (RtTable, Dest, Src);
//
// If found, promote the cache entry to the head of the hash bucket. LRU
//
if (RtCacheEntry != NULL) {
NetListRemoveEntry (&RtCacheEntry->Link);
NetListInsertHead (Head, &RtCacheEntry->Link);
return RtCacheEntry;
}
//
// Search the route table for the most specific route
//
RtEntry = Ip4FindRouteEntry (RtTable, Dest);
if (RtEntry == NULL) {
return NULL;
}
//
// Found a route to the Dest, if it is a direct route, the packet
// will be send directly to the destination, such as for connected
// network. Otherwise, it is an indirect route, the packet will be
// send the next hop router.
//
if (RtEntry->Flag & IP4_DIRECT_ROUTE) {
NextHop = Dest;
} else {
NextHop = RtEntry->NextHop;
}
Ip4FreeRouteEntry (RtEntry);
//
// Create a route cache entry, and tag it as spawned from this route entry
//
RtCacheEntry = Ip4CreateRouteCacheEntry (Dest, Src, NextHop, (UINTN) RtEntry);
if (RtCacheEntry == NULL) {
return NULL;
}
NetListInsertHead (Head, &RtCacheEntry->Link);
NET_GET_REF (RtCacheEntry);
//
// Each bucket of route cache can contain at most 64 entries.
// Remove the entries at the tail of the bucket. These entries
// are likely to be used least.
//
Count = 0;
NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
if (++Count < IP4_ROUTE_CACHE_MAX) {
continue;
}
Cache = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
NetListRemoveEntry (Entry);
Ip4FreeRouteCacheEntry (Cache);
}
return RtCacheEntry;
}
/**
Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of
GetModeData. The EFI_IP4_ROUTE_TABLE is clumsy to use in the
internal operation of the IP4 driver.
@param IpInstance The IP4 child that requests the route table.
@retval EFI_SUCCESS The route table is successfully build
@retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the rotue table.
**/
EFI_STATUS
Ip4BuildEfiRouteTable (
IN IP4_PROTOCOL *IpInstance
)
{
IP4_SERVICE *IpSb;
NET_LIST_ENTRY *Entry;
IP4_ROUTE_TABLE *RtTable;
IP4_ROUTE_ENTRY *RtEntry;
EFI_IP4_ROUTE_TABLE *Table;
UINT32 Count;
INT32 Index;
IpSb = IpInstance->Service;
RtTable = IpInstance->RouteTable;
if (IpInstance->EfiRouteTable != NULL) {
NetFreePool (IpInstance->EfiRouteTable);
IpInstance->EfiRouteTable = NULL;
IpInstance->EfiRouteCount = 0;
}
Count = RtTable->TotalNum;
if (RtTable->Next != NULL) {
Count += RtTable->Next->TotalNum;
}
if (Count == 0) {
return EFI_SUCCESS;
}
Table = NetAllocatePool (sizeof (EFI_IP4_ROUTE_TABLE) * Count);
if (Table == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Copy the route entry to EFI route table. Keep the order of
// route entry copied from most specific to default route. That
// is, interlevel the route entry from the instance's route area
// and those from the default route table's route area.
//
Count = 0;
for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {
for (RtTable = IpInstance->RouteTable; RtTable != NULL; RtTable = RtTable->Next) {
NET_LIST_FOR_EACH (Entry, &(RtTable->RouteArea[Index])) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
EFI_IP4 (Table[Count].SubnetAddress) = HTONL (RtEntry->Dest & RtEntry->Netmask);
EFI_IP4 (Table[Count].SubnetMask) = HTONL (RtEntry->Netmask);
EFI_IP4 (Table[Count].GatewayAddress) = HTONL (RtEntry->NextHop);
Count++;
}
}
}
IpInstance->EfiRouteTable = Table;
IpInstance->EfiRouteCount = Count;
return EFI_SUCCESS;
}

View File

@@ -0,0 +1,151 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation
All rights reserved. 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.
Module Name:
Ip4Route.h
Abstract:
EFI IP4 route table and route cache table defintions.
**/
#ifndef __EFI_IP4_ROUTE_H__
#define __EFI_IP4_ROUTE_H__
#include "IP4Common.h"
enum {
IP4_DIRECT_ROUTE = 0x00000001,
IP4_ROUTE_CACHE_HASH = 31,
IP4_ROUTE_CACHE_MAX = 64, // Max NO. of cache entry per hash bucket
};
#define IP4_ROUTE_CACHE_HASH(Dst, Src) (((Dst) ^ (Src)) % IP4_ROUTE_CACHE_HASH)
//
// The route entry in the route table. Dest/Netmask is the destion
// network. The nexthop is the gateway to send the packet to in
// order to reach the Dest/Netmask. If the Flag has IP4_DIRECT_ROUTE
// on, the gateway is the destination of the IP packet itself. Route
// enties of the connected network have the flag on.
//
typedef struct {
NET_LIST_ENTRY Link;
INTN RefCnt;
IP4_ADDR Dest;
IP4_ADDR Netmask;
IP4_ADDR NextHop;
UINT32 Flag;
} IP4_ROUTE_ENTRY;
//
// The route cache entry. The route cache entry is optional.
// But it is necessary to support the ICMP redirect message.
// Check Ip4ProcessIcmpRedirect for information.
//
// The cache entry field Tag is used to tag all the route
// cache entry spawned from a route table entry. This makes
// it simple to delete all the route cache entries from a
// to-be-deleted route entry.
//
typedef struct {
NET_LIST_ENTRY Link;
INTN RefCnt;
IP4_ADDR Dest;
IP4_ADDR Src;
IP4_ADDR NextHop;
UINTN Tag;
} IP4_ROUTE_CACHE_ENTRY;
//
// The route cache table is organized as a hash table. Each
// IP4 route table has a embedded route cache. For now the
// route cache and route table are binded togehter. But keep
// the route cache a seperated structure in case we want to
// detach them later.
//
typedef struct {
NET_LIST_ENTRY CacheBucket[IP4_ROUTE_CACHE_HASH];
} IP4_ROUTE_CACHE;
//
// Each IP4 instance has its own route table. Each ServiceBinding
// instance has a default route table and default address.
//
// All the route table entries with the same mask are linked
// together in one route area. For example, RouteArea[0] contains
// the default routes. A route table also contains a route cache.
//
typedef struct _IP4_ROUTE_TABLE IP4_ROUTE_TABLE;
typedef struct _IP4_ROUTE_TABLE {
INTN RefCnt;
UINT32 TotalNum;
NET_LIST_ENTRY RouteArea[IP4_MASK_NUM];
IP4_ROUTE_TABLE *Next;
IP4_ROUTE_CACHE Cache;
};
IP4_ROUTE_TABLE*
Ip4CreateRouteTable (
VOID
);
VOID
Ip4FreeRouteTable (
IN IP4_ROUTE_TABLE *RouteTable
);
EFI_STATUS
Ip4AddRoute (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR Gateway
);
EFI_STATUS
Ip4DelRoute (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR Gateway
);
IP4_ROUTE_CACHE_ENTRY *
Ip4FindRouteCache (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Src
);
VOID
Ip4FreeRouteCacheEntry (
IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry
);
IP4_ROUTE_CACHE_ENTRY *
Ip4Route (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Src
);
EFI_STATUS
Ip4BuildEfiRouteTable (
IN IP4_PROTOCOL *IpInstance
);
#endif