NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg

Signed-off-by: Liming Gao <liming.gao@intel.com>
Cc: Siyuan Fu <siyuan.fu@intel.com>
Cc: Jiaxin Wu <jiaxin.wu@intel.com>
Reviewed-by: Jiaxin Wu <jiaxin.wu@intel.com>
Reviewed-by: Siyuan Fu <siyuan.fu@intel.com>
This commit is contained in:
Liming Gao
2019-05-15 20:02:18 +08:00
parent c0fd7f734e
commit 4542f8b813
147 changed files with 24 additions and 24 deletions

View File

@@ -0,0 +1,428 @@
/** @file
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Ip4Impl.h"
//
// EFI Component Name Functions
//
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name 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. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param[out] 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.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
Ip4ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] 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.
@param[in] 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.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name 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. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param[out] 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.
@retval 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.
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
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
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gIp4ComponentName = {
Ip4ComponentNameGetDriverName,
Ip4ComponentNameGetControllerName,
"eng"
};
//
// EFI Component Name 2 Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIp4ComponentName2 = {
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) Ip4ComponentNameGetDriverName,
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) Ip4ComponentNameGetControllerName,
"en"
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIp4DriverNameTable[] = {
{
"eng;en",
L"IP4 Network Service Driver"
},
{
NULL,
NULL
}
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gIp4ControllerNameTable = NULL;
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name 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. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param[out] 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.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
Ip4ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mIp4DriverNameTable,
DriverName,
(BOOLEAN)(This == &gIp4ComponentName)
);
}
/**
Update the component name for the IP4 child handle.
@param Ip4[in] A pointer to the EFI_IP4_PROTOCOL.
@retval EFI_SUCCESS Update the ControllerNameTable of this instance successfully.
@retval EFI_INVALID_PARAMETER The input parameter is invalid.
**/
EFI_STATUS
UpdateName (
IN EFI_IP4_PROTOCOL *Ip4
)
{
EFI_STATUS Status;
CHAR16 HandleName[80];
EFI_IP4_MODE_DATA Ip4ModeData;
if (Ip4 == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Format the child name into the string buffer as:
// IPv4 (SrcIP=127.0.0.1, DestIP=127.0.0.1)
//
Status = Ip4->GetModeData (Ip4, &Ip4ModeData, NULL, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
if (!Ip4ModeData.IsStarted || !Ip4ModeData.IsConfigured) {
UnicodeSPrint (HandleName, sizeof (HandleName), L"IPv4 (Not started)");
} else {
UnicodeSPrint (HandleName, sizeof (HandleName),
L"IPv4 (SrcIP=%d.%d.%d.%d)",
Ip4ModeData.ConfigData.StationAddress.Addr[0],
Ip4ModeData.ConfigData.StationAddress.Addr[1],
Ip4ModeData.ConfigData.StationAddress.Addr[2],
Ip4ModeData.ConfigData.StationAddress.Addr[3]
);
}
if (gIp4ControllerNameTable != NULL) {
FreeUnicodeStringTable (gIp4ControllerNameTable);
gIp4ControllerNameTable = NULL;
}
Status = AddUnicodeString2 (
"eng",
gIp4ComponentName.SupportedLanguages,
&gIp4ControllerNameTable,
HandleName,
TRUE
);
if (EFI_ERROR (Status)) {
return Status;
}
return AddUnicodeString2 (
"en",
gIp4ComponentName2.SupportedLanguages,
&gIp4ControllerNameTable,
HandleName,
FALSE
);
}
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] 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.
@param[in] 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.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name 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. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param[out] 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.
@retval 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.
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
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_STATUS Status;
EFI_IP4_PROTOCOL *Ip4;
//
// Only provide names for child handles.
//
if (ChildHandle == NULL) {
return EFI_UNSUPPORTED;
}
//
// Make sure this driver produced ChildHandle
//
Status = EfiTestChildHandle (
ControllerHandle,
ChildHandle,
&gEfiManagedNetworkProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Retrieve an instance of a produced protocol from ChildHandle
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiIp4ProtocolGuid,
(VOID **)&Ip4,
NULL,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Update the component name for this child handle.
//
Status = UpdateName (Ip4);
if (EFI_ERROR (Status)) {
return Status;
}
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
gIp4ControllerNameTable,
ControllerName,
(BOOLEAN)(This == &gIp4ComponentName)
);
}

View File

@@ -0,0 +1,306 @@
/** @file
Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Ip4Impl.h"
/**
Return the cast type (Unicast/Boradcast) specific to an
interface. All the addresses are host byte ordered.
@param[in] IpAddr The IP address to classify in host byte order
@param[in] 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
@retval 0 Otherwise.
**/
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[in] IpSb The IP4 service binding instance that received the
packet
@param[in] Dst The destination address in the packet (host byte
order)
@param[in] 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
cast type to a configured interface. If the packet doesn't match any of
the interface, multicast address and local broadcast address are checked.
**/
INTN
Ip4GetHostCast (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Dst,
IN IP4_ADDR Src
)
{
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 != NULL && !IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
return IP4_LOCAL_BROADCAST;
}
} else if (IP4_IS_MULTICAST (Dst) && Ip4FindGroup (&IpSb->IgmpCtrl, Dst) != NULL) {
return IP4_MULTICAST;
}
return Type;
}
/**
Find an interface whose configured IP address is Ip.
@param[in] IpSb The IP4 service binding instance
@param[in] 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
)
{
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[in] IpSb The IP4 service binding instance
@param[in] 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
)
{
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[in] IpSb Ip4 service binding instance
@param[in] Ip The Ip adress to find (host byte order)
@param[in] 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
)
{
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[in] Mnp The Mnp instance to get the MAC address.
@param[in] Multicast The multicast IP address to translate.
@param[out] Mac The buffer to hold the translated address.
@retval EFI_SUCCESS if the multicast IP is successfully translated to a
multicast MAC address.
@retval other 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[in] 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;
}
/**
Validate that Ip/Netmask pair is OK to be used as station
address. Only continuous netmasks are supported. and check
that StationAddress is a unicast address on the newtwork.
@param[in] Ip The IP address to validate.
@param[in] Netmask The netmaks of the IP.
@retval TRUE The Ip/Netmask pair is valid.
@retval FALSE The Ip/Netmask pair is invalid.
**/
BOOLEAN
Ip4StationAddressValid (
IN IP4_ADDR Ip,
IN IP4_ADDR Netmask
)
{
//
// Only support the station address with 0.0.0.0/0 to enable DHCP client.
//
if (Netmask == IP4_ALLZERO_ADDRESS) {
return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);
}
//
// Only support the continuous net masks
//
if (NetGetMaskLength (Netmask) == (IP4_MASK_MAX + 1)) {
return FALSE;
}
//
// Station address can't be class D or class E address
//
if (NetGetIpClass (Ip) > IP4_ADDR_CLASSC) {
return FALSE;
}
return NetIp4IsUnicast (Ip, Netmask);
}

View File

@@ -0,0 +1,217 @@
/** @file
Common definition for IP4.
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#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;
#define IP4_ETHER_PROTO 0x0800
//
// The packet is received as link level broadcast/multicast/promiscuous.
//
#define IP4_LINK_BROADCAST 0x00000001
#define IP4_LINK_MULTICAST 0x00000002
#define IP4_LINK_PROMISC 0x00000004
//
// IP4 address cast type classfication. Keep it true that any
// type bigger than or equal to LOCAL_BROADCAST is broadcast.
//
#define IP4_PROMISCUOUS 1
#define IP4_LOCAL_HOST 2
#define IP4_MULTICAST 3
#define IP4_LOCAL_BROADCAST 4 // Destination is 255.255.255.255
#define IP4_SUBNET_BROADCAST 5
#define IP4_NET_BROADCAST 6
//
// IP4 header flags
//
#define IP4_HEAD_DF_MASK 0x4000
#define IP4_HEAD_MF_MASK 0x2000
#define 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) ? IP4_HEAD_DF_MASK : 0) | ((Mf) ? IP4_HEAD_MF_MASK : 0) | (((Offset) >> 3) & IP4_HEAD_OFFSET_MASK)))
#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_DO_NOT_FRAGMENT(FragmentField) \
((BOOLEAN)(((FragmentField) & IP4_HEAD_DF_MASK) == IP4_HEAD_DF_MASK))
#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)
/**
Return the cast type (Unicast/Boradcast) specific to an
interface. All the addresses are host byte ordered.
@param[in] IpAddr The IP address to classify in host byte order
@param[in] 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
@retval 0 Otherwise.
**/
INTN
Ip4GetNetCast (
IN IP4_ADDR IpAddr,
IN IP4_INTERFACE *IpIf
);
/**
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[in] IpSb The IP4 service binding instance that received the
packet
@param[in] Dst The destination address in the packet (host byte
order)
@param[in] 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
cast type to a configured interface. If the packet doesn't match any of
the interface, multicast address and local broadcast address are checked.
**/
INTN
Ip4GetHostCast (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Dst,
IN IP4_ADDR Src
);
/**
Find an interface whose configured IP address is Ip.
@param[in] IpSb The IP4 service binding instance
@param[in] 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
);
/**
Find an interface that Ip is on that connected network.
@param[in] IpSb The IP4 service binding instance
@param[in] 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
);
/**
Find an interface of the service with the same Ip/Netmask pair.
@param[in] IpSb Ip4 service binding instance
@param[in] Ip The Ip adress to find (host byte order)
@param[in] 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
);
/**
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[in] Mnp The Mnp instance to get the MAC address.
@param[in] Multicast The multicast IP address to translate.
@param[out] Mac The buffer to hold the translated address.
@retval EFI_SUCCESS if the multicast IP is successfully translated to a
multicast MAC address.
@retval other Otherwise some error.
**/
EFI_STATUS
Ip4GetMulticastMac (
IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
IN IP4_ADDR Multicast,
OUT EFI_MAC_ADDRESS *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[in] Head The IP head to convert
@return Point to the converted IP head
**/
IP4_HEAD *
Ip4NtohHead (
IN IP4_HEAD *Head
);
/**
Validate that Ip/Netmask pair is OK to be used as station
address. Only continuous netmasks are supported. and check
that StationAddress is a unicast address on the newtwork.
@param[in] Ip The IP address to validate.
@param[in] Netmask The netmaks of the IP.
@retval TRUE The Ip/Netmask pair is valid.
@retval FALSE The Ip/Netmask pair is invalid.
**/
BOOLEAN
Ip4StationAddressValid (
IN IP4_ADDR Ip,
IN IP4_ADDR Netmask
);
#endif

View File

@@ -0,0 +1,94 @@
/** @file
Vfr file for IP4Dxe.
Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Ip4NvData.h"
#define EFI_NETWORK_DEVICE_CLASS 0x04
formset
guid = IP4_CONFIG2_NVDATA_GUID,
title = STRING_TOKEN(STR_IP4_CONFIG2_FORM_TITLE),
help = STRING_TOKEN(STR_IP4_CONFIG2_FORM_HELP),
class = EFI_NETWORK_DEVICE_CLASS,
subclass = 0x03,
varstore IP4_CONFIG2_IFR_NVDATA,
name = IP4_CONFIG2_IFR_NVDATA,
guid = IP4_CONFIG2_NVDATA_GUID;
form formid = FORMID_MAIN_FORM,
title = STRING_TOKEN(STR_IP4_DEVICE_FORM_TITLE);
checkbox varid = IP4_CONFIG2_IFR_NVDATA.Configure,
prompt = STRING_TOKEN(STR_IP4_CONFIGURE),
help = STRING_TOKEN(STR_IP4_CONFIGURE_HELP),
flags = INTERACTIVE,
key = KEY_ENABLE,
endcheckbox;
suppressif ideqval IP4_CONFIG2_IFR_NVDATA.Configure == 0x00;
checkbox varid = IP4_CONFIG2_IFR_NVDATA.DhcpEnable,
prompt = STRING_TOKEN(STR_IP4_ENABLE_DHCP),
help = STRING_TOKEN(STR_IP4_ENABLE_DHCP),
flags = INTERACTIVE,
key = KEY_DHCP_ENABLE,
endcheckbox;
endif;
suppressif ideqval IP4_CONFIG2_IFR_NVDATA.DhcpEnable == 0x01 OR ideqval IP4_CONFIG2_IFR_NVDATA.Configure == 0x00;
string varid = IP4_CONFIG2_IFR_NVDATA.StationAddress,
prompt = STRING_TOKEN(STR_IP4_LOCAL_IP_ADDRESS),
help = STRING_TOKEN(STR_IP4_IP_ADDRESS_HELP),
flags = INTERACTIVE,
key = KEY_LOCAL_IP,
minsize = IP_MIN_SIZE,
maxsize = IP_MAX_SIZE,
endstring;
string varid = IP4_CONFIG2_IFR_NVDATA.SubnetMask,
prompt = STRING_TOKEN(STR_IP4_LOCAL_MASK),
help = STRING_TOKEN(STR_IP4_MASK_HELP),
flags = INTERACTIVE,
key = KEY_SUBNET_MASK,
minsize = IP_MIN_SIZE,
maxsize = IP_MAX_SIZE,
endstring;
string varid = IP4_CONFIG2_IFR_NVDATA.GatewayAddress,
prompt = STRING_TOKEN(STR_IP4_LOCAL_GATEWAY),
help = STRING_TOKEN(STR_IP4_GATEWAY_HELP),
flags = INTERACTIVE,
key = KEY_GATE_WAY,
minsize = IP_MIN_SIZE,
maxsize = IP_MAX_SIZE,
endstring;
string varid = IP4_CONFIG2_IFR_NVDATA.DnsAddress,
prompt = STRING_TOKEN(STR_IP4_LOCAL_DNS),
help = STRING_TOKEN(STR_IP4_DNS_HELP),
flags = INTERACTIVE,
key = KEY_DNS,
minsize = IP_MIN_SIZE,
maxsize = ADDRESS_STR_MAX_SIZE,
endstring;
endif;
subtitle text = STRING_TOKEN(STR_NULL);
text
help = STRING_TOKEN(STR_SAVE_CHANGES),
text = STRING_TOKEN(STR_SAVE_CHANGES),
flags = INTERACTIVE,
key = KEY_SAVE_CHANGES;
endform;
endformset;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,294 @@
/** @file
Definitions for EFI IPv4 Configuration II Protocol implementation.
Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __IP4_CONFIG2_IMPL_H__
#define __IP4_CONFIG2_IMPL_H__
#define IP4_CONFIG2_INSTANCE_SIGNATURE SIGNATURE_32 ('I', 'P', 'C', '2')
#define IP4_FORM_CALLBACK_INFO_SIGNATURE SIGNATURE_32 ('I', 'F', 'C', 'I')
#define IP4_CONFIG2_VARIABLE_ATTRIBUTE (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)
#define DATA_ATTRIB_SIZE_FIXED 0x1
#define DATA_ATTRIB_VOLATILE 0x2
#define DATA_ATTRIB_SET(Attrib, Bits) (BOOLEAN)((Attrib) & (Bits))
#define SET_DATA_ATTRIB(Attrib, Bits) ((Attrib) |= (Bits))
#define REMOVE_DATA_ATTRIB(Attrib, Bits) ((Attrib) &= (~Bits))
typedef struct _IP4_CONFIG2_INSTANCE IP4_CONFIG2_INSTANCE;
#define IP4_CONFIG2_INSTANCE_FROM_PROTOCOL(Proto) \
CR ((Proto), \
IP4_CONFIG2_INSTANCE, \
Ip4Config2, \
IP4_CONFIG2_INSTANCE_SIGNATURE \
)
#define IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE(Instance) \
CR ((Instance), \
IP4_SERVICE, \
Ip4Config2Instance, \
IP4_SERVICE_SIGNATURE \
)
#define IP4_CONFIG2_INSTANCE_FROM_FORM_CALLBACK(Callback) \
CR ((Callback), \
IP4_CONFIG2_INSTANCE, \
CallbackInfo, \
IP4_CONFIG2_INSTANCE_SIGNATURE \
)
#define IP4_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS(ConfigAccess) \
CR ((ConfigAccess), \
IP4_FORM_CALLBACK_INFO, \
HiiConfigAccessProtocol, \
IP4_FORM_CALLBACK_INFO_SIGNATURE \
)
/**
The prototype of work function for EfiIp4Config2SetData().
@param[in] Instance The pointer to the IP4 config2 instance data.
@param[in] DataSize In bytes, the size of the buffer pointed to by Data.
@param[in] Data The data buffer to set.
@retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type,
8 bytes.
@retval EFI_SUCCESS The specified configuration data for the EFI IPv4
network stack was set successfully.
**/
typedef
EFI_STATUS
(*IP4_CONFIG2_SET_DATA) (
IN IP4_CONFIG2_INSTANCE *Instance,
IN UINTN DataSize,
IN VOID *Data
);
/**
The prototype of work function for EfiIp4Config2GetData().
@param[in] Instance The pointer to the IP4 config2 instance data.
@param[in, out] DataSize On input, in bytes, the size of Data. On output, in
bytes, the size of buffer required to store the specified
configuration data.
@param[in] Data The data buffer in which the configuration data is returned.
Ignored if DataSize is ZERO.
@retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified
configuration data, and the required size is
returned in DataSize.
@retval EFI_SUCCESS The specified configuration data was obtained successfully.
**/
typedef
EFI_STATUS
(*IP4_CONFIG2_GET_DATA) (
IN IP4_CONFIG2_INSTANCE *Instance,
IN OUT UINTN *DataSize,
IN VOID *Data OPTIONAL
);
typedef union {
VOID *Ptr;
EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo;
EFI_IP4_CONFIG2_POLICY *Policy;
EFI_IP4_CONFIG2_MANUAL_ADDRESS *ManualAddress;
EFI_IPv4_ADDRESS *Gateway;
EFI_IPv4_ADDRESS *DnsServers;
} IP4_CONFIG2_DATA;
typedef struct {
IP4_CONFIG2_SET_DATA SetData;
IP4_CONFIG2_GET_DATA GetData;
EFI_STATUS Status;
UINT8 Attribute;
NET_MAP EventMap;
IP4_CONFIG2_DATA Data;
UINTN DataSize;
} IP4_CONFIG2_DATA_ITEM;
typedef struct {
UINT16 Offset;
UINT32 DataSize;
EFI_IP4_CONFIG2_DATA_TYPE DataType;
} IP4_CONFIG2_DATA_RECORD;
#pragma pack(1)
//
// heap data that contains the data for each data record.
//
// EFI_IP4_CONFIG2_POLICY Policy;
// UINT32 ManualaddressCount;
// UINT32 GatewayCount;
// UINT32 DnsServersCount;
// EFI_IP4_CONFIG2_MANUAL_ADDRESS ManualAddress[];
// EFI_IPv4_ADDRESS Gateway[];
// EFI_IPv4_ADDRESS DnsServers[];
//
typedef struct {
UINT16 Checksum;
UINT16 DataRecordCount;
IP4_CONFIG2_DATA_RECORD DataRecord[1];
} IP4_CONFIG2_VARIABLE;
#pragma pack()
typedef struct {
EFI_IP4_CONFIG2_POLICY Policy; ///< manual or automatic
EFI_IP4_CONFIG2_MANUAL_ADDRESS *ManualAddress; ///< IP addresses
UINT32 ManualAddressCount; ///< IP addresses count
EFI_IPv4_ADDRESS *GatewayAddress; ///< Gateway address
UINT32 GatewayAddressCount; ///< Gateway address count
EFI_IPv4_ADDRESS *DnsAddress; ///< DNS server address
UINT32 DnsAddressCount; ///< DNS server address count
} IP4_CONFIG2_NVDATA;
typedef struct _IP4_FORM_CALLBACK_INFO {
UINT32 Signature;
EFI_HANDLE ChildHandle;
EFI_HII_CONFIG_ACCESS_PROTOCOL HiiConfigAccessProtocol;
EFI_DEVICE_PATH_PROTOCOL *HiiVendorDevicePath;
EFI_HII_HANDLE RegisteredHandle;
} IP4_FORM_CALLBACK_INFO;
struct _IP4_CONFIG2_INSTANCE {
UINT32 Signature;
BOOLEAN Configured;
LIST_ENTRY Link;
UINT16 IfIndex;
EFI_IP4_CONFIG2_PROTOCOL Ip4Config2;
EFI_IP4_CONFIG2_INTERFACE_INFO InterfaceInfo;
EFI_IP4_CONFIG2_POLICY Policy;
IP4_CONFIG2_DATA_ITEM DataItem[Ip4Config2DataTypeMaximum];
EFI_EVENT Dhcp4SbNotifyEvent;
VOID *Registration;
EFI_HANDLE Dhcp4Handle;
EFI_DHCP4_PROTOCOL *Dhcp4;
BOOLEAN DhcpSuccess;
BOOLEAN OtherInfoOnly;
EFI_EVENT Dhcp4Event;
UINT32 FailedIaAddressCount;
EFI_IPv4_ADDRESS *DeclineAddress;
UINT32 DeclineAddressCount;
IP4_FORM_CALLBACK_INFO CallbackInfo;
IP4_CONFIG2_NVDATA Ip4NvData;
};
//
// Configure the DHCP to request the routers and netmask
// from server. The DHCP4_TAG_NETMASK is included in Head.
//
#pragma pack(1)
typedef struct {
EFI_DHCP4_PACKET_OPTION Head;
UINT8 Route;
UINT8 Dns;
} IP4_CONFIG2_DHCP4_OPTION;
#pragma pack()
/**
Read the configuration data from variable storage according to the VarName and
gEfiIp4Config2ProtocolGuid. It checks the integrity of variable data. If the
data is corrupted, it clears the variable data to ZERO. Othewise, it outputs the
configuration data to IP4_CONFIG2_INSTANCE.
@param[in] VarName The pointer to the variable name
@param[in, out] Instance The pointer to the IP4 config2 instance data.
@retval EFI_NOT_FOUND The variable can not be found or already corrupted.
@retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.
@retval EFI_SUCCESS The configuration data was retrieved successfully.
**/
EFI_STATUS
Ip4Config2ReadConfigData (
IN CHAR16 *VarName,
IN OUT IP4_CONFIG2_INSTANCE *Instance
);
/**
Start the DHCP configuration for this IP service instance.
It will locates the EFI_IP4_CONFIG2_PROTOCOL, then start the
DHCP configuration.
@param[in] Instance The IP4 config2 instance to configure.
@retval EFI_SUCCESS The auto configuration is successfully started.
@retval Others Failed to start auto configuration.
**/
EFI_STATUS
Ip4StartAutoConfig (
IN IP4_CONFIG2_INSTANCE *Instance
);
/**
Initialize an IP4_CONFIG2_INSTANCE.
@param[out] Instance The buffer of IP4_CONFIG2_INSTANCE to be initialized.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
@retval EFI_SUCCESS The IP4_CONFIG2_INSTANCE initialized successfully.
**/
EFI_STATUS
Ip4Config2InitInstance (
OUT IP4_CONFIG2_INSTANCE *Instance
);
/**
Release an IP4_CONFIG2_INSTANCE.
@param[in, out] Instance The buffer of IP4_CONFIG2_INSTANCE to be freed.
**/
VOID
Ip4Config2CleanInstance (
IN OUT IP4_CONFIG2_INSTANCE *Instance
);
/**
Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK.
@param Event The event that is signalled.
@param Context The IP4 service binding instance.
**/
VOID
EFIAPI
Ip4AutoReconfigCallBack (
IN EFI_EVENT Event,
IN VOID *Context
);
/**
Destroy the Dhcp4 child in IP4_CONFIG2_INSTANCE and release the resources.
@param[in, out] Instance The buffer of IP4 config2 instance to be freed.
@retval EFI_SUCCESS The child was successfully destroyed.
@retval Others Failed to destroy the child.
**/
EFI_STATUS
Ip4Config2DestroyDhcp4 (
IN OUT IP4_CONFIG2_INSTANCE *Instance
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
/** @file
The header file of IP4Config2Nv.c
Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef _IP4_CONFIG2NV_H_
#define _IP4_CONFIG2NV_H_
#include "Ip4Impl.h"
extern UINT8 Ip4Config2Bin[];
extern UINT8 Ip4DxeStrings[];
#define NIC_ITEM_CONFIG_SIZE (sizeof (IP4_CONFIG2_INSTANCE) + (sizeof (EFI_IPv4_ADDRESS) * MAX_IP4_CONFIG_DNS))
/**
Install HII Config Access protocol for network device and allocate resource.
@param[in, out] Instance The IP4 config2 Instance.
@retval EFI_SUCCESS The HII Config Access protocol is installed.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
@retval Others Other errors as indicated.
**/
EFI_STATUS
Ip4Config2FormInit (
IN OUT IP4_CONFIG2_INSTANCE *Instance
);
/**
Uninstall the HII Config Access protocol for network devices and free up the resources.
@param[in, out] Instance The IP4 config2 instance to unload a form.
**/
VOID
Ip4Config2FormUnload (
IN OUT IP4_CONFIG2_INSTANCE *Instance
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
/** @file
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#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;
extern EFI_COMPONENT_NAME2_PROTOCOL gIp4ComponentName2;
extern EFI_UNICODE_STRING_TABLE *gIp4ControllerNameTable;
typedef struct {
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
UINTN NumberOfChildren;
EFI_HANDLE *ChildHandleBuffer;
} IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT;
//
// Function prototype for the driver's entry point
//
/**
This is the declaration of an EFI image entry point. This entry point is
the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
both device drivers and bus drivers.
The entry point for IP4 driver which install the driver
binding and component name protocol on its image.
@param[in] ImageHandle The firmware allocated handle for the UEFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
**/
EFI_STATUS
EFIAPI
Ip4DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
//
// Function prototypes for the Drivr Binding Protocol
//
/**
Test to see if this driver supports ControllerHandle. This service
is called by the EFI boot service ConnectController(). In
order to make drivers as small as possible, there are a few calling
restrictions for this service. ConnectController() must
follow these calling restrictions. If any other agent wishes to call
Supported() it must also follow these calling restrictions.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to test
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS 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
);
/**
Start this driver on ControllerHandle. This service is called by the
EFI boot service ConnectController(). In order to make
drivers as small as possible, there are a few calling restrictions for
this service. ConnectController() must follow these
calling restrictions. If any other agent wishes to call Start() it
must also follow these calling restrictions.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to bind driver to
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS 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
);
/**
Stop this driver on ControllerHandle. This service is called by the
EFI boot service DisconnectController(). In order to
make drivers as small as possible, there are a few calling
restrictions for this service. DisconnectController()
must follow these calling restrictions. If any other agent wishes
to call Stop() it must also follow these calling restrictions.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to stop driver on
@param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number
of children is zero stop the entire bus driver.
@param[in] ChildHandleBuffer List of Child Handles to Stop.
@retval EFI_SUCCESS 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
);
//
// Function prototypes for the ServiceBinding Protocol
//
/**
Creates a child handle and installs a protocol.
The CreateChild() function installs a protocol on ChildHandle.
If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
@param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
@param ChildHandle Pointer to the handle of the child to create. If it is NULL,
then a new handle is created. If it is a pointer to an existing UEFI handle,
then the protocol is added to the existing UEFI handle.
@retval EFI_SUCCES The protocol was added to ChildHandle.
@retval EFI_INVALID_PARAMETER ChildHandle is NULL.
@retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
the child
@retval other The child handle was not created
**/
EFI_STATUS
EFIAPI
Ip4ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN OUT EFI_HANDLE *ChildHandle
);
/**
Destroys a child handle with a protocol installed on it.
The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
that was installed by CreateChild() from ChildHandle. If the removed protocol is the
last protocol on ChildHandle, then ChildHandle is destroyed.
@param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
@param ChildHandle Handle of the child to destroy
@retval EFI_SUCCES The protocol was removed from ChildHandle.
@retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
@retval EFI_INVALID_PARAMETER Child handle is NULL.
@retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
because its 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
);
#endif

View File

@@ -0,0 +1,109 @@
## @file
# This module produces EFI IPv4 Protocol and EFI IPv4 Service Binding Protocol.
#
# This module produces EFI IPv4 Protocol upon EFI MNP Protocol and EFI ARP Protocol,
# to provide basic network IPv4 packet I/O services, which includes support for a
# subset of the Internet Control Message Protocol (ICMP) and may include support for
# the Internet Group Management Protocol (IGMP).
#
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Ip4Dxe
MODULE_UNI_FILE = Ip4Dxe.uni
FILE_GUID = 9FB1A1F3-3B71-4324-B39A-745CBB015FFF
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = Ip4DriverEntryPoint
UNLOAD_IMAGE = NetLibDefaultUnload
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 EBC
#
# DRIVER_BINDING = gIp4DriverBinding
# COMPONENT_NAME = gIp4ComponentName
# COMPONENT_NAME2 = gIp4ComponentName2
#
[Sources]
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
Ip4Config2Impl.c
Ip4Config2Impl.h
Ip4Config2.vfr
Ip4DxeStrings.uni
Ip4NvData.h
Ip4Config2Nv.h
Ip4Config2Nv.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiLib
BaseLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
DebugLib
NetLib
DpcLib
HiiLib
PrintLib
DevicePathLib
UefiHiiServicesLib
[Protocols]
## BY_START
## UNDEFINED # variable
gEfiIp4ServiceBindingProtocolGuid
gEfiIp4ProtocolGuid ## BY_START
gEfiManagedNetworkServiceBindingProtocolGuid ## TO_START
gEfiManagedNetworkProtocolGuid ## TO_START
gEfiArpServiceBindingProtocolGuid ## TO_START
gEfiIp4Config2ProtocolGuid ## BY_START
gEfiArpProtocolGuid ## TO_START
gEfiDhcp4ServiceBindingProtocolGuid ## TO_START
gEfiDhcp4ProtocolGuid ## TO_START
gEfiIpSec2ProtocolGuid ## SOMETIMES_CONSUMES
gEfiHiiConfigAccessProtocolGuid ## BY_START
gEfiDevicePathProtocolGuid ## TO_START
[Guids]
## SOMETIMES_CONSUMES ## GUID # HiiIsConfigHdrMatch EFI_NIC_IP4_CONFIG_VARIABLE
## SOMETIMES_PRODUCES ## GUID # HiiConstructConfigHdr EFI_NIC_IP4_CONFIG_VARIABLE
## SOMETIMES_PRODUCES ## GUID # HiiGetBrowserData EFI_NIC_IP4_CONFIG_VARIABLE
## SOMETIMES_CONSUMES ## HII
gIp4Config2NvDataGuid
[UserExtensions.TianoCore."ExtraFiles"]
Ip4DxeExtra.uni

View File

@@ -0,0 +1,19 @@
// /** @file
// This module produces EFI IPv4 Protocol and EFI IPv4 Service Binding Protocol.
//
// This module produces EFI IPv4 Protocol upon EFI MNP Protocol and EFI ARP Protocol,
// to provide basic network IPv4 packet I/O services, which includes support for a
// subset of the Internet Control Message Protocol (ICMP) and may include support for
// the Internet Group Management Protocol (IGMP).
//
// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "Produces EFI IPv4 Protocol and EFI IPv4 Service Binding Protocol"
#string STR_MODULE_DESCRIPTION #language en-US "This module produces EFI IPv4 Protocol upon EFI MNP Protocol and EFI ARP Protocol to provide basic network IPv4 packet I/O services, which includes support for a subset of the Internet Control Message Protocol (ICMP), and may include support for the Internet Group Management Protocol (IGMP)."

View File

@@ -0,0 +1,14 @@
// /** @file
// Ip4Dxe Localized Strings and Content
//
// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_PROPERTIES_MODULE_NAME
#language en-US
"IP v4 DXE Driver"

View File

@@ -0,0 +1,30 @@
// /** @file
// String definitions for Ip4Config2 formset
// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
//**/
/=#
#langdef en-US "English"
#string STR_IP4_CONFIG2_FORM_TITLE #language en-US "IPv4 Network Configuration"
#string STR_IP4_CONFIG2_FORM_HELP #language en-US "Configure network parameters."
#string STR_IP4_DEVICE_FORM_TITLE #language en-US ""
#string STR_IP4_DEVICE_FORM_HELP #language en-US ""
#string STR_IP4_CONFIGURE #language en-US "Configured"
#string STR_IP4_CONFIGURE_HELP #language en-US "Indicate whether network address configured successfully or not."
#string STR_IP4_ENABLE_DHCP #language en-US "Enable DHCP"
#string STR_IP4_LOCAL_IP_ADDRESS #language en-US "Local IP Address"
#string STR_IP4_IP_ADDRESS_HELP #language en-US "Enter IP address in dotted-decimal notation. Example: 192.168.10.12\r\n"
#string STR_IP4_LOCAL_MASK #language en-US "Local NetMask"
#string STR_IP4_MASK_HELP #language en-US "Enter NetMask in dotted-decimal notation. Example: 255.255.255.0\r\n"
#string STR_IP4_LOCAL_GATEWAY #language en-US "Local Gateway"
#string STR_IP4_GATEWAY_HELP #language en-US "Enter Gateway in dotted-decimal notation. Example: 192.168.10.1\r\n"
#string STR_IP4_LOCAL_DNS #language en-US "Local DNS Servers"
#string STR_IP4_DNS_HELP #language en-US "Enter DNS Servers in dotted-decimal notation. Example: 192.168.10.8 192.168.10.9\r\n"
#string STR_SAVE_CHANGES #language en-US "Save Changes and Exit"
#string STR_NULL #language en-US ""

363
NetworkPkg/Ip4Dxe/Ip4Icmp.c Normal file
View File

@@ -0,0 +1,363 @@
/** @file
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#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[in] IpSb The IP4 service binding instance that received
the packet.
@param[in] Head The IP head of the received ICMPpacket.
@param[in] Packet The content of the ICMP redirect packet with IP
head removed.
@param[in] 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
**/
EFI_STATUS
Ip4ProcessIcmpRedirect (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet,
IN IP4_ICMP_ERROR_HEAD *Icmp
)
{
LIST_ENTRY *Entry;
IP4_PROTOCOL *Ip4Instance;
IP4_ROUTE_CACHE_ENTRY *CacheEntry;
IP4_INTERFACE *IpIf;
IP4_ADDR Gateway;
IP4_ADDR Src;
IP4_ADDR Dst;
//
// 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;
}
Dst = NTOHL (Icmp->IpHead.Dst);
Src = NTOHL (Icmp->IpHead.Src);
CacheEntry = Ip4FindRouteCache (Ip4Instance->RouteTable, Dst, 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[in] IpSb The IP4 service that received the packet.
@param[in] Head The IP4 head of the ICMP error packet
@param[in] Packet The content of the ICMP error with IP4 head
removed.
@retval EFI_SUCCESS The ICMP error is processed successfully.
@retval EFI_INVALID_PARAMETER The packet is invalid
@retval Others Failed to process the packet.
**/
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, NULL, 0);
}
/**
Replay an ICMP echo request.
@param[in] IpSb The IP4 service that receivd the packet
@param[in] Head The IP4 head of the ICMP error packet
@param[in] Packet The content of the ICMP error with IP4 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);
ASSERT (Icmp != NULL);
Icmp->Head.Type = ICMP_ECHO_REPLY;
Icmp->Head.Checksum = 0;
Icmp->Head.Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Icmp, Data->TotalSize));
ReplyHead.Tos = 0;
ReplyHead.Fragment = 0;
ReplyHead.Ttl = 64;
ReplyHead.Protocol = EFI_IP_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
);
if (EFI_ERROR (Status)) {
NetbufFree (Data);
}
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[in] IpSb The IP4 service that receivd the packet
@param[in] Head The IP4 head of the ICMP query packet
@param[in] Packet The content of the ICMP query with IP4 head
removed.
@retval EFI_INVALID_PARAMETER The packet is invalid
@retval EFI_SUCCESS The ICMP query message is processed
@retval Others Failed to process ICMP query.
**/
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, NULL, 0);
}
/**
Handle the ICMP packet. First validate the message format,
then according to the message types, process it as query or
error packet.
@param[in] IpSb The IP4 service that receivd the packet.
@param[in] Head The IP4 head of the ICMP query packet.
@param[in] Packet The content of the ICMP query with IP4 head
removed.
@retval EFI_INVALID_PARAMETER The packet is malformated.
@retval EFI_SUCCESS The ICMP message is successfully processed.
@retval Others Failed to handle ICMP packet.
**/
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 = (UINT16) (~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,97 @@
/** @file
Header file for ICMP protocol.
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_IP4_ICMP_H__
#define __EFI_IP4_ICMP_H__
//
// ICMP type definations
//
#define ICMP_ECHO_REPLY 0
#define ICMP_DEST_UNREACHABLE 3
#define ICMP_SOURCE_QUENCH 4
#define ICMP_REDIRECT 5
#define ICMP_ECHO_REQUEST 8
#define ICMP_TIME_EXCEEDED 11
#define ICMP_PARAMETER_PROBLEM 12
#define ICMP_TIMESTAMP 13
#define ICMP_INFO_REQUEST 15
#define ICMP_INFO_REPLY 16
#define ICMP_TYPE_MAX ICMP_INFO_REPLY
#define ICMP_DEFAULT_CODE 0
//
// ICMP code definations for ICMP_DEST_UNREACHABLE
//
#define ICMP_NET_UNREACHABLE 0
#define ICMP_HOST_UNREACHABLE 1
#define ICMP_PROTO_UNREACHABLE 2 // Host may generate
#define ICMP_PORT_UNREACHABLE 3 // Host may generate
#define ICMP_FRAGMENT_FAILED 4
#define ICMP_SOURCEROUTE_FAILED 5 // Host may generate
#define ICMP_NET_UNKNOWN 6
#define ICMP_HOST_UNKNOWN 7
#define ICMP_SOURCE_ISOLATED 8
#define ICMP_NET_PROHIBITED 9
#define ICMP_HOST_PROHIBITED 10
#define ICMP_NET_UNREACHABLE_TOS 11
#define ICMP_HOST_UNREACHABLE_TOS 12
//
// ICMP code definations for ICMP_TIME_EXCEEDED
//
#define ICMP_TIMEOUT_IN_TRANSIT 0
#define ICMP_TIMEOUT_REASSEMBLE 1 // Host may generate
//
// ICMP code definations for ICMP_TIME_EXCEEDED
//
#define ICMP_NET_REDIRECT 0
#define ICMP_HOST_REDIRECT 1
#define ICMP_NET_TOS_REDIRECT 2
#define ICMP_HOST_TOS_REDIRECT 3
//
// ICMP message classes, each class of ICMP message shares
// a common message format. INVALID_MESSAGE is only a flag.
//
#define ICMP_INVALID_MESSAGE 0
#define ICMP_ERROR_MESSAGE 1
#define ICMP_QUERY_MESSAGE 2
typedef struct {
UINT8 IcmpType;
UINT8 IcmpClass;
} IP4_ICMP_CLASS;
extern IP4_ICMP_CLASS mIcmpClass[];
extern EFI_IP4_ICMP_TYPE mIp4SupportedIcmp[];
/**
Handle the ICMP packet. First validate the message format,
then according to the message types, process it as query or
error packet.
@param[in] IpSb The IP4 service that receivd the packet.
@param[in] Head The IP4 head of the ICMP query packet.
@param[in] Packet The content of the ICMP query with IP4 head
removed.
@retval EFI_INVALID_PARAMETER The packet is malformated.
@retval EFI_SUCCESS The ICMP message is successfully processed.
@retval Others Failed to handle ICMP packet.
**/
EFI_STATUS
Ip4IcmpHandle (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
);
#endif

1345
NetworkPkg/Ip4Dxe/Ip4If.c Normal file

File diff suppressed because it is too large Load Diff

340
NetworkPkg/Ip4Dxe/Ip4If.h Normal file
View File

@@ -0,0 +1,340 @@
/** @file
Definition for IP4 pesudo interface structure.
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_IP4_IF_H__
#define __EFI_IP4_IF_H__
#define IP4_FRAME_RX_SIGNATURE SIGNATURE_32 ('I', 'P', 'F', 'R')
#define IP4_FRAME_TX_SIGNATURE SIGNATURE_32 ('I', 'P', 'F', 'T')
#define IP4_FRAME_ARP_SIGNATURE SIGNATURE_32 ('I', 'P', 'F', 'A')
#define IP4_INTERFACE_SIGNATURE 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.
@param[in] IpInstance The instance that sent or received the packet.
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.
@param[in] Packet The sent or received packet.
@param[in] IoStatus Status of sending or receiving.
@param[in] LinkFlag Indicate if the frame is received as link broadcast/multicast.
When transmitting, it is not used.
@param[in] Context Additional data for callback.
@retval None.
**/
typedef
VOID
(*IP4_FRAME_CALLBACK)(
IN IP4_PROTOCOL *IpInstance OPTIONAL,
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus,
IN UINT32 LinkFlag,
IN 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;
LIST_ENTRY Link;
IP4_INTERFACE *Interface;
IP4_SERVICE *IpSb;
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;
LIST_ENTRY Link;
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.
@param Frame The sending frame to check for cancellation.
@param Context Additional data for callback.
@retval TRUE The sending of the frame should be cancelled.
@retval FALSE Do not cancel the frame sending.
**/
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.
//
struct _IP4_INTERFACE {
UINT32 Signature;
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 fields
// are invalid if (Configured == FALSE)
//
IP4_ADDR Ip;
IP4_ADDR SubnetMask;
IP4_ADDR SubnetBrdcast;
IP4_ADDR NetBrdcast;
BOOLEAN Configured;
//
// Handle used to create/destroy 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.
//
LIST_ENTRY ArpQues;
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.
//
LIST_ENTRY IpInstances;
BOOLEAN PromiscRecv;
};
/**
Create an IP4_INTERFACE. Delay the creation of ARP instance until
the interface is configured.
@param[in] Mnp The shared MNP child of this IP4 service binding
instance.
@param[in] Controller The controller this IP4 service binding instance
is installed. Most like the UNDI handle.
@param[in] ImageHandle This driver's image handle.
@return Point to the created IP4_INTERFACE, otherwise NULL.
**/
IP4_INTERFACE *
Ip4CreateInterface (
IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
IN EFI_HANDLE Controller,
IN EFI_HANDLE ImageHandle
);
/**
Set the interface's address, create and configure
the ARP child if necessary.
@param Interface The interface to set the address.
@param IpAddr The interface's IP address.
@param SubnetMask The interface's netmask.
@retval EFI_SUCCESS The interface is configured with Ip/netmask pair,
and a ARP is created for it.
@retval Others Failed to set the interface's address.
**/
EFI_STATUS
Ip4SetAddress (
IN OUT IP4_INTERFACE *Interface,
IN IP4_ADDR IpAddr,
IN IP4_ADDR SubnetMask
);
/**
Free the interface used by IpInstance. All the IP instance with
the same Ip/Netmask pair share the same interface. It is reference
counted. All the frames haven't been sent will be cancelled.
Because the IpInstance is optional, the caller must remove
IpInstance from the interface's instance list itself.
@param[in] Interface The interface used by the IpInstance.
@param[in] IpInstance The Ip instance that free the interface. NULL if
the Ip driver is releasing the default interface.
@retval EFI_SUCCESS The interface use IpInstance is freed.
**/
EFI_STATUS
Ip4FreeInterface (
IN IP4_INTERFACE *Interface,
IN IP4_PROTOCOL *IpInstance OPTIONAL
);
/**
Send a frame from the interface. If the next hop is broadcast or
multicast address, it is transmitted immediately. If the next hop
is a unicast, it will consult ARP to resolve the NextHop's MAC.
If some error happened, the CallBack won't be called. So, the caller
must test the return value, and take action when there is an error.
@param[in] Interface The interface to send the frame from
@param[in] IpInstance The IP child that request the transmission. NULL
if it is the IP4 driver itself.
@param[in] Packet The packet to transmit.
@param[in] NextHop The immediate destination to transmit the packet
to.
@param[in] CallBack Function to call back when transmit finished.
@param[in] Context Opaque parameter to the call back.
@param[in] IpSb The pointer to the IP4 service binding instance.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame
@retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop
@retval EFI_SUCCESS The packet is successfully transmitted.
@retval other Other error occurs.
**/
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,
IN IP4_SERVICE *IpSb
);
/**
Remove all the frames on the interface that pass the FrameToCancel,
either queued on ARP queues or that have already been delivered to
MNP and not yet recycled.
@param[in] Interface Interface to remove the frames from.
@param[in] IoStatus The transmit status returned to the frames'
callback.
@param[in] FrameToCancel Function to select the frame to cancel, NULL to
select all.
@param[in] Context Opaque parameters passed to FrameToCancel.
**/
VOID
Ip4CancelFrames (
IN IP4_INTERFACE *Interface,
IN EFI_STATUS IoStatus,
IN IP4_FRAME_TO_CANCEL FrameToCancel OPTIONAL,
IN VOID *Context
);
/**
If there is a pending receive request, cancel it. Don't call
the receive request's callback because this function can be only
called if the instance or driver is tearing itself down. It
doesn't make sense to call it back. But it is necessary to call
the transmit token's callback to give it a chance to free the
packet and update the upper layer's transmit request status, say
that from the UDP.
@param[in] Interface The interface used by the IpInstance
**/
VOID
Ip4CancelReceive (
IN IP4_INTERFACE *Interface
);
/**
Request to receive the packet from the interface.
@param[in] Interface The interface to receive the frames from.
@param[in] IpInstance The instance that requests the receive. NULL for
the driver itself.
@param[in] CallBack Function to call when receive finished.
@param[in] Context Opaque parameter to the callback.
@retval EFI_ALREADY_STARTED There is already a pending receive request.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to receive.
@retval EFI_SUCCESS The recieve request has been started.
@retval other Other error occurs.
**/
EFI_STATUS
Ip4ReceiveFrame (
IN IP4_INTERFACE *Interface,
IN IP4_PROTOCOL *IpInstance OPTIONAL,
IN IP4_FRAME_CALLBACK CallBack,
IN VOID *Context
);
#endif

615
NetworkPkg/Ip4Dxe/Ip4Igmp.c Normal file
View File

@@ -0,0 +1,615 @@
/** @file
This file implements the RFC2236: IGMP v2.
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#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[in, out] IpSb The IP4 service whose IGMP is to be initialized.
@retval EFI_SUCCESS IGMP of the IpSb is successfully initialized.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to initialize IGMP.
@retval Others Failed to initialize the IGMP of IpSb.
**/
EFI_STATUS
Ip4InitIgmp (
IN OUT 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 = AllocatePool (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;
}
InsertHeadList (&IgmpCtrl->Groups, &Group->Link);
return EFI_SUCCESS;
ON_ERROR:
FreePool (Group);
return Status;
}
/**
Find the IGMP_GROUP structure which contains the status of multicast
group Address in this IGMP control block
@param[in] IgmpCtrl The IGMP control block to search from.
@param[in] Address The multicast address to search.
@return NULL if the multicast address isn't in the IGMP control block. Otherwise
the point to the IGMP_GROUP which contains the status of multicast group
for Address.
**/
IGMP_GROUP *
Ip4FindGroup (
IN IGMP_SERVICE_DATA *IgmpCtrl,
IN IP4_ADDR Address
)
{
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[in] IgmpCtrl The IGMP control block to search in.
@param[in] Mac The MAC address to search.
@return The number of the IP4 multicast group that mapped to the same
multicast group Mac.
**/
INTN
Ip4FindMac (
IN IGMP_SERVICE_DATA *IgmpCtrl,
IN EFI_MAC_ADDRESS *Mac
)
{
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[in] IpSb The IP4 service instance that requests the
transmission.
@param[in] Dst The destinaton to send to.
@param[in] Type The IGMP message type, such as IGMP v1 membership
report.
@param[in] 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);
if (Igmp == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Igmp->Type = Type;
Igmp->MaxRespTime = 0;
Igmp->Checksum = 0;
Igmp->Group = HTONL (Group);
Igmp->Checksum = (UINT16) (~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[in] IpSb The IP4 service instance that requests the
transmission.
@param[in] 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 behalf of this IP4 child
@param[in] IpInstance The IP4 child that wants to join the group.
@param[in] 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 = AllocatePool (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;
}
InsertHeadList (&IgmpCtrl->Groups, &Group->Link);
return EFI_SUCCESS;
ON_ERROR:
FreePool (Group);
return Status;
}
/**
Leave the IP4 multicast group on behalf of IpInstance.
@param[in] IpInstance The IP4 child that wants to leave the group
address.
@param[in] 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 == 0) {
Ip4SendIgmpMessage (IpSb, IP4_ALLROUTER_ADDRESS, IGMP_LEAVE_GROUP, Group->Address);
}
RemoveEntryList (&Group->Link);
FreePool (Group);
return EFI_SUCCESS;
}
/**
Handle the received IGMP message for the IP4 service instance.
@param[in] IpSb The IP4 service instance that received the message.
@param[in] Head The IP4 header of the received message.
@param[in] 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;
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 = 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[in] IpSb The IP4 service instance that is ticking.
**/
VOID
Ip4IgmpTicking (
IN IP4_SERVICE *IpSb
)
{
IGMP_SERVICE_DATA *IgmpCtrl;
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[in] Source The array of group addresses to add to.
@param[in] Count The number of group addresses in the Source.
@param[in] Addr The IP4 multicast address to add.
@return NULL if failed to allocate memory for the new groups,
otherwise the new combined group addresses.
**/
IP4_ADDR *
Ip4CombineGroups (
IN IP4_ADDR *Source,
IN UINT32 Count,
IN IP4_ADDR Addr
)
{
IP4_ADDR *Groups;
Groups = AllocatePool (sizeof (IP4_ADDR) * (Count + 1));
if (Groups == NULL) {
return NULL;
}
CopyMem (Groups, Source, Count * sizeof (IP4_ADDR));
Groups[Count] = Addr;
return Groups;
}
/**
Remove a group address from 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.
It is Count if the Addr isn't in the Groups.
**/
INTN
Ip4RemoveGroupAddr (
IN OUT 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;
}

201
NetworkPkg/Ip4Dxe/Ip4Igmp.h Normal file
View File

@@ -0,0 +1,201 @@
/** @file
Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_IP4_IGMP_H__
#define __EFI_IP4_IGMP_H__
//
// IGMP message type
//
#define IGMP_MEMBERSHIP_QUERY 0x11
#define IGMP_V1_MEMBERSHIP_REPORT 0x12
#define IGMP_V2_MEMBERSHIP_REPORT 0x16
#define IGMP_LEAVE_GROUP 0x17
#define IGMP_V1ROUTER_PRESENT 400
#define IGMP_UNSOLICIATED_REPORT 10
#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 {
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;
LIST_ENTRY Groups;
} IGMP_SERVICE_DATA;
/**
Init the IGMP control data of the IP4 service instance, configure
MNP to receive ALL SYSTEM multicast.
@param[in, out] IpSb The IP4 service whose IGMP is to be initialized.
@retval EFI_SUCCESS IGMP of the IpSb is successfully initialized.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to initialize IGMP.
@retval Others Failed to initialize the IGMP of IpSb.
**/
EFI_STATUS
Ip4InitIgmp (
IN OUT IP4_SERVICE *IpSb
);
/**
Join the multicast group on behalf of this IP4 child
@param[in] IpInstance The IP4 child that wants to join the group.
@param[in] 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
);
/**
Leave the IP4 multicast group on behalf of IpInstance.
@param[in] IpInstance The IP4 child that wants to leave the group
address.
@param[in] 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
);
/**
Handle the received IGMP message for the IP4 service instance.
@param[in] IpSb The IP4 service instance that received the message.
@param[in] Head The IP4 header of the received message.
@param[in] 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
);
/**
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[in] IpSb The IP4 service instance that is ticking.
**/
VOID
Ip4IgmpTicking (
IN IP4_SERVICE *IpSb
);
/**
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[in] Source The array of group addresses to add to.
@param[in] Count The number of group addresses in the Source.
@param[in] Addr The IP4 multicast address to add.
@return NULL if failed to allocate memory for the new groups,
otherwise the new combined group addresses.
**/
IP4_ADDR *
Ip4CombineGroups (
IN IP4_ADDR *Source,
IN UINT32 Count,
IN IP4_ADDR Addr
);
/**
Remove a group address from 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.
It is Count if the Addr isn't in the Groups.
**/
INTN
Ip4RemoveGroupAddr (
IN OUT IP4_ADDR *Groups,
IN UINT32 Count,
IN IP4_ADDR Addr
);
/**
Find the IGMP_GROUP structure which contains the status of multicast
group Address in this IGMP control block
@param[in] IgmpCtrl The IGMP control block to search from.
@param[in] Address The multicast address to search.
@return NULL if the multicast address isn't in the IGMP control block. Otherwise
the point to the IGMP_GROUP which contains the status of multicast group
for Address.
**/
IGMP_GROUP *
Ip4FindGroup (
IN IGMP_SERVICE_DATA *IgmpCtrl,
IN IP4_ADDR Address
);
#endif

2330
NetworkPkg/Ip4Dxe/Ip4Impl.c Normal file

File diff suppressed because it is too large Load Diff

417
NetworkPkg/Ip4Dxe/Ip4Impl.h Normal file
View File

@@ -0,0 +1,417 @@
/** @file
Ip4 internal functions and type defintions.
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_IP4_IMPL_H__
#define __EFI_IP4_IMPL_H__
#include <Uefi.h>
#include <Protocol/IpSec.h>
#include <Protocol/Ip4.h>
#include <Protocol/Ip4Config2.h>
#include <Protocol/Arp.h>
#include <Protocol/ManagedNetwork.h>
#include <Protocol/Dhcp4.h>
#include <Protocol/HiiConfigRouting.h>
#include <Protocol/HiiConfigAccess.h>
#include <IndustryStandard/Dhcp.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 <Library/DpcLib.h>
#include <Library/PrintLib.h>
#include <Library/DevicePathLib.h>
#include <Library/HiiLib.h>
#include <Library/UefiHiiServicesLib.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"
#include "Ip4Config2Impl.h"
#include "Ip4Config2Nv.h"
#include "Ip4NvData.h"
#define IP4_PROTOCOL_SIGNATURE SIGNATURE_32 ('I', 'P', '4', 'P')
#define IP4_SERVICE_SIGNATURE 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.
//
#define IP4_STATE_UNCONFIGED 0
#define IP4_STATE_CONFIGED 1
//
// 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 destroyed, it goes
// to DESTROY.
//
#define IP4_SERVICE_UNSTARTED 0
#define IP4_SERVICE_STARTED 1
#define IP4_SERVICE_CONFIGED 2
#define IP4_SERVICE_DESTROY 3
///
/// 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;
EFI_EVENT IpSecRecycleSignal;
NET_BUF *Packet;
BOOLEAN Sent;
INTN Life;
} IP4_TXTOKEN_WRAP;
///
/// IP4_IPSEC_WRAP wraps the packet received from MNP layer. The packet
/// will be released after it has been processed by the receiver. Upon then,
/// the IP4_IPSEC_WRAP will be released, and the IpSecRecycleSignal will be signaled
/// to notice IPsec to free the resources.
///
typedef struct {
EFI_EVENT IpSecRecycleSignal;
NET_BUF *Packet;
} IP4_IPSEC_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 {
LIST_ENTRY Link;
IP4_PROTOCOL *IpInstance;
NET_BUF *Packet;
EFI_IP4_RECEIVE_DATA RxData;
} IP4_RXDATA_WRAP;
struct _IP4_PROTOCOL {
UINT32 Signature;
EFI_IP4_PROTOCOL Ip4Proto;
EFI_HANDLE Handle;
INTN State;
BOOLEAN InDestroy;
IP4_SERVICE *Service;
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)
LIST_ENTRY Received; // Received but not delivered packet
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;
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;
};
struct _IP4_SERVICE {
UINT32 Signature;
EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
INTN State;
//
// List of all the IP instances and interfaces, and default
// interface and route table and caches.
//
UINTN NumChildren;
LIST_ENTRY Children;
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;
EFI_EVENT ReconfigCheckTimer;
EFI_EVENT ReconfigEvent;
BOOLEAN Reconfig;
//
// Underlying media present status.
//
BOOLEAN MediaPresent;
//
// IPv4 Configuration II Protocol instance
//
IP4_CONFIG2_INSTANCE Ip4Config2Instance;
CHAR16 *MacString;
UINT32 MaxPacketSize;
UINT32 OldMaxPacketSize; ///< The MTU before IPsec enable.
};
#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_SERVICE_FROM_CONFIG2_INSTANCE(This) \
CR (This, IP4_SERVICE, Ip4Config2Instance, IP4_SERVICE_SIGNATURE)
#define IP4_NO_MAPPING(IpInstance) (!(IpInstance)->Interface->Configured)
extern EFI_IP4_PROTOCOL mEfiIp4ProtocolTemplete;
/**
Config the MNP parameter used by IP. The IP driver use one MNP
child to transmit/receive frames. By default, it configures MNP
to receive unicast/multicast/broadcast. And it will enable/disable
the promiscous receive according to whether there is IP child
enable that or not. If Force is FALSE, it will iterate through
all the IP children to check whether the promiscuous receive
setting has been changed. If it hasn't been changed, it won't
reconfigure the MNP. If Force is TRUE, the MNP is configured no
matter whether that is changed or not.
@param[in] IpSb The IP4 service instance that is to be changed.
@param[in] Force Force the configuration or not.
@retval EFI_SUCCESS The MNP is successfully configured/reconfigured.
@retval Others Configuration failed.
**/
EFI_STATUS
Ip4ServiceConfigMnp (
IN IP4_SERVICE *IpSb,
IN BOOLEAN Force
);
/**
Intiialize the IP4_PROTOCOL structure to the unconfigured states.
@param IpSb The IP4 service instance.
@param IpInstance The IP4 child instance.
**/
VOID
Ip4InitProtocol (
IN IP4_SERVICE *IpSb,
IN OUT IP4_PROTOCOL *IpInstance
);
/**
Clean up the IP4 child, release all the resources used by it.
@param[in] IpInstance The IP4 child to clean up.
@retval EFI_SUCCESS The IP4 child is cleaned up.
@retval EFI_DEVICE_ERROR Some resources failed to be released.
**/
EFI_STATUS
Ip4CleanProtocol (
IN IP4_PROTOCOL *IpInstance
);
/**
Cancel the user's receive/transmit request.
@param[in] IpInstance The IP4 child.
@param[in] Token The token to cancel. If NULL, all token will be
cancelled.
@retval EFI_SUCCESS The token is cancelled.
@retval EFI_NOT_FOUND The token isn't found on either the
transmit/receive queue.
@retval EFI_DEVICE_ERROR Not all token is cancelled when Token is NULL.
**/
EFI_STATUS
Ip4Cancel (
IN IP4_PROTOCOL *IpInstance,
IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL
);
/**
Change the IP4 child's multicast setting. The caller
should make sure that the parameters is valid.
@param[in] IpInstance The IP4 child to change the setting.
@param[in] JoinFlag TRUE to join the group, otherwise leave it
@param[in] GroupAddress The target group address
@retval EFI_ALREADY_STARTED Want to join the group, but already a member of it
@retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
@retval EFI_DEVICE_ERROR Failed to set the group configuraton
@retval EFI_SUCCESS Successfully updated the group setting.
@retval EFI_NOT_FOUND Try to leave the group which it isn't a member.
**/
EFI_STATUS
Ip4Groups (
IN IP4_PROTOCOL *IpInstance,
IN BOOLEAN JoinFlag,
IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
);
/**
This heart beat timer of IP4 service instance times out all of its IP4 children's
received-but-not-delivered and transmitted-but-not-recycle packets, and provides
time input for its IGMP protocol.
@param[in] Event The IP4 service instance's heart beat timer.
@param[in] Context The IP4 service instance.
**/
VOID
EFIAPI
Ip4TimerTicking (
IN EFI_EVENT Event,
IN VOID *Context
);
/**
This dedicated timer is used to poll underlying network media status. In case
of cable swap or wireless network switch, a new round auto configuration will
be initiated. The timer will signal the IP4 to run DHCP configuration again.
IP4 driver will free old IP address related resource, such as route table and
Interface, then initiate a DHCP process to acquire new IP, eventually create
route table for new IP address.
@param[in] Event The IP4 service instance's heart beat timer.
@param[in] Context The IP4 service instance.
**/
VOID
EFIAPI
Ip4TimerReconfigChecking (
IN EFI_EVENT Event,
IN VOID *Context
);
/**
Decrease the life of the transmitted packets. If it is
decreased to zero, cancel the packet. This function is
called by Ip4PacketTimerTicking which time out both the
received-but-not-delivered and transmitted-but-not-recycle
packets.
@param[in] Map The IP4 child's transmit map.
@param[in] Item Current transmitted packet.
@param[in] Context Not used.
@retval EFI_SUCCESS Always returns EFI_SUCCESS.
**/
EFI_STATUS
EFIAPI
Ip4SentPacketTicking (
IN NET_MAP *Map,
IN NET_MAP_ITEM *Item,
IN VOID *Context
);
/**
The callback function for the net buffer which wraps the user's
transmit token. Although it seems this function is pretty simple,
there are some subtle things.
When user requests the IP to transmit a packet by passing it a
token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data
is wrapped in an net buffer. the net buffer's Free function is
set to Ip4FreeTxToken. The Token and token wrap are added to the
IP child's TxToken map. Then the buffer is passed to Ip4Output for
transmission. If something error happened before that, the buffer
is freed, which in turn will free the token wrap. The wrap may
have been added to the TxToken map or not, and the user's event
shouldn't be fired because we are still in the EfiIp4Transmit. If
the buffer has been sent by Ip4Output, it should be removed from
the TxToken map and user's event signaled. The token wrap and buffer
are bound together. Check the comments in Ip4Output for information
about IP fragmentation.
@param[in] Context The token's wrap.
**/
VOID
EFIAPI
Ip4FreeTxToken (
IN VOID *Context
);
extern EFI_IPSEC2_PROTOCOL *mIpSec;
extern BOOLEAN mIpSec2Installed;
#endif

1597
NetworkPkg/Ip4Dxe/Ip4Input.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,246 @@
/** @file
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_IP4_INPUT_H__
#define __EFI_IP4_INPUT_H__
#define IP4_MIN_HEADLEN 20
#define IP4_MAX_HEADLEN 60
///
/// 8(ESP header) + 16(max IV) + 16(max padding) + 2(ESP tail) + 12(max ICV) = 54
///
#define IP4_MAX_IPSEC_HEADLEN 54
#define IP4_ASSEMLE_HASH_SIZE 31
#define IP4_FRAGMENT_LIFE 120
#define 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 {
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;
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 {
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))
/**
Initialize an already allocated assemble table. This is generally
the assemble table embedded in the IP4 service instance.
@param[in, out] Table The assemble table to initialize.
**/
VOID
Ip4InitAssembleTable (
IN OUT IP4_ASSEMBLE_TABLE *Table
);
/**
Clean up the assemble table: remove all the fragments
and assemble entries.
@param[in] Table The assemble table to clean up
**/
VOID
Ip4CleanAssembleTable (
IN IP4_ASSEMBLE_TABLE *Table
);
/**
The IP4 input routine. It is called by the IP4_INTERFACE when a
IP4 fragment is received from MNP.
@param[in] Ip4Instance The IP4 child that request the receive, most like
it is NULL.
@param[in] Packet The IP4 packet received.
@param[in] IoStatus The return status of receive request.
@param[in] Flag The link layer flag for the packet received, such
as multicast.
@param[in] Context The IP4 service instance that own the MNP.
**/
VOID
Ip4AccpetFrame (
IN IP4_PROTOCOL *Ip4Instance,
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus,
IN UINT32 Flag,
IN VOID *Context
);
/**
Demultiple the packet. the packet delivery is processed in two
passes. The first pass will enque a shared copy of the packet
to each IP4 child that accepts the packet. The second pass will
deliver a non-shared copy of the packet to each IP4 child that
has pending receive requests. Data is copied if more than one
child wants to consume the packet because each IP child needs
its own copy of the packet to make changes.
@param[in] IpSb The IP4 service instance that received the packet.
@param[in] Head The header of the received packet.
@param[in] Packet The data of the received packet.
@param[in] Option Point to the IP4 packet header options.
@param[in] OptionLen Length of the IP4 packet header options.
@retval EFI_NOT_FOUND No IP child accepts the packet.
@retval EFI_SUCCESS The packet is enqueued or delivered to some IP
children.
**/
EFI_STATUS
Ip4Demultiplex (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet,
IN UINT8 *Option,
IN UINT32 OptionLen
);
/**
Enqueue a received packet to all the IP children that share
the same interface.
@param[in] IpSb The IP4 service instance that receive the packet.
@param[in] Head The header of the received packet.
@param[in] Packet The data of the received packet.
@param[in] Option Point to the IP4 packet header options.
@param[in] OptionLen Length of the IP4 packet header options.
@param[in] IpIf The interface to enqueue the packet to.
@return The number of the IP4 children that accepts the packet
**/
INTN
Ip4InterfaceEnquePacket (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet,
IN UINT8 *Option,
IN UINT32 OptionLen,
IN IP4_INTERFACE *IpIf
);
/**
Deliver the received packets to upper layer if there are both received
requests and enqueued packets. If the enqueued packet is shared, it will
duplicate it to a non-shared packet, release the shared packet, then
deliver the non-shared packet up.
@param[in] IpInstance The IP child to deliver the packet up.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources to deliver the
packets.
@retval EFI_SUCCESS All the enqueued packets that can be delivered
are delivered up.
**/
EFI_STATUS
Ip4InstanceDeliverPacket (
IN IP4_PROTOCOL *IpInstance
);
/**
Timeout the fragment and enqueued packets.
@param[in] IpSb The IP4 service instance to timeout
**/
VOID
Ip4PacketTimerTicking (
IN IP4_SERVICE *IpSb
);
/**
The work function to locate IPsec protocol to process the inbound or
outbound IP packets. The process routine handls the packet with following
actions: bypass the packet, discard the packet, or protect the packet.
@param[in] IpSb The IP4 service instance.
@param[in, out] Head The The caller supplied IP4 header.
@param[in, out] Netbuf The IP4 packet to be processed by IPsec.
@param[in, out] Options The caller supplied options.
@param[in, out] OptionsLen The length of the option.
@param[in] Direction The directionality in an SPD entry,
EfiIPsecInBound or EfiIPsecOutBound.
@param[in] Context The token's wrap.
@retval EFI_SUCCESS The IPsec protocol is not available or disabled.
@retval EFI_SUCCESS The packet was bypassed and all buffers remain the same.
@retval EFI_SUCCESS The packet was protected.
@retval EFI_ACCESS_DENIED The packet was discarded.
@retval EFI_OUT_OF_RESOURCES There is no suffcient resource to complete the operation.
@retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than the
number of input data blocks when build a fragment table.
**/
EFI_STATUS
Ip4IpSecProcessPacket (
IN IP4_SERVICE *IpSb,
IN OUT IP4_HEAD **Head,
IN OUT NET_BUF **Netbuf,
IN OUT UINT8 **Options,
IN OUT UINT32 *OptionsLen,
IN EFI_IPSEC_TRAFFIC_DIR Direction,
IN VOID *Context
);
#endif

View File

@@ -0,0 +1,45 @@
/** @file
Routines used to operate the Ip4Dxe.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef _IP4_NV_DATA_H_
#define _IP4_NV_DATA_H_
#include <Guid/Ip4Config2Hii.h>
#define FORMID_MAIN_FORM 1
#define FORMID_DEVICE_FORM 2
#define KEY_ENABLE 0x100
#define KEY_DHCP_ENABLE 0x101
#define KEY_LOCAL_IP 0x102
#define KEY_SUBNET_MASK 0x103
#define KEY_GATE_WAY 0x104
#define KEY_DNS 0x105
#define KEY_SAVE_CHANGES 0x106
#define IP_MIN_SIZE 7
#define IP_MAX_SIZE 15
#define IP4_STR_MAX_SIZE 16
#define ADDRESS_STR_MAX_SIZE 255
#define MAX_IP4_CONFIG_DNS 16
///
/// IP4_CONFIG2_IFR_NVDATA contains the IP4 configure
/// parameters for that NIC.
///
typedef struct {
UINT8 Configure; ///< NIC configure status
UINT8 DhcpEnable; ///< Static or DHCP
CHAR16 StationAddress[IP4_STR_MAX_SIZE]; ///< IP addresses
CHAR16 SubnetMask[IP4_STR_MAX_SIZE]; ///< Subnet address
CHAR16 GatewayAddress[IP4_STR_MAX_SIZE]; ///< Gateway address
CHAR16 DnsAddress[ADDRESS_STR_MAX_SIZE]; ///< DNS server address
} IP4_CONFIG2_IFR_NVDATA;
#endif

View File

@@ -0,0 +1,204 @@
/** @file
IP4 option support functions.
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Ip4Impl.h"
/**
Validate the IP4 option format for both the packets we received
and will transmit.
@param[in] Option The first byte of the option
@param[in] OptionLen The length of the whole option
@param[in] Rcvd The option is from the packet we received if TRUE,
otherwise the option we wants to transmit.
@retval TRUE The option is properly formatted
@retval FALSE The option is mal-formated
**/
BOOLEAN
Ip4OptionIsValid (
IN UINT8 *Option,
IN UINT32 OptionLen,
IN BOOLEAN Rcvd
)
{
UINT32 Cur;
UINT32 Len;
UINT32 Point;
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 formatted as |Type|Len|Point|Ip1|Ip2|...
//
if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) {
return FALSE;
}
if ((Point > Len + 1) || (Point % 4 != 0)) {
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)))) {
return FALSE;
}
Cur += Len;
break;
default:
Len = Option[Cur + 1];
if ((OptionLen - Cur < Len) || (Len < 2)) {
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 aligned to 4 bytes.
@param[in] Option The original option to copy from
@param[in] OptionLen The length of the original option
@param[in] FirstFragment Whether it is the first fragment
@param[in, out] Buf The buffer to copy options to. NULL
@param[in, out] BufLen The length of the buffer
@retval EFI_SUCCESS The options are copied over
@retval EFI_BUFFER_TOO_SMALL Buf is NULL or BufLen provided is too small.
**/
EFI_STATUS
Ip4CopyOption (
IN UINT8 *Option,
IN UINT32 OptionLen,
IN BOOLEAN FirstFragment,
IN OUT 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) != 0) {
CopyMem (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.
//
ZeroMem (Buf, Len);
CopyMem (Buf, OptBuf, Next);
*BufLen = Len;
return EFI_SUCCESS;
}

View File

@@ -0,0 +1,66 @@
/** @file
IP4 option support routines.
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_IP4_OPTION_H__
#define __EFI_IP4_OPTION_H__
#define IP4_OPTION_EOP 0
#define IP4_OPTION_NOP 1
#define IP4_OPTION_LSRR 131 // Loss source and record routing, 10000011
#define IP4_OPTION_SSRR 137 // Strict source and record routing, 10001001
#define IP4_OPTION_RR 7 // Record routing, 00000111
#define IP4_OPTION_COPY_MASK 0x80
/**
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[in] Option The first byte of the option
@param[in] OptionLen The length of the whole option
@param[in] Rcvd The option is from the packet we received if TRUE,
otherwise the option we wants to transmit.
@retval TRUE The option is properly formatted
@retval FALSE The option is mal-formated
**/
BOOLEAN
Ip4OptionIsValid (
IN UINT8 *Option,
IN UINT32 OptionLen,
IN BOOLEAN Rcvd
);
/**
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 aligned to 4 bytes.
@param[in] Option The original option to copy from
@param[in] OptionLen The length of the original option
@param[in] FirstFragment Whether it is the first fragment
@param[in, out] Buf The buffer to copy options to. NULL
@param[in, out] BufLen The length of the buffer
@retval EFI_SUCCESS The options are copied over
@retval EFI_BUFFER_TOO_SMALL Buf is NULL or BufLen provided is too small.
**/
EFI_STATUS
Ip4CopyOption (
IN UINT8 *Option,
IN UINT32 OptionLen,
IN BOOLEAN FirstFragment,
IN OUT UINT8 *Buf, OPTIONAL
IN OUT UINT32 *BufLen
);
#endif

View File

@@ -0,0 +1,482 @@
/** @file
Transmit the IP4 packet.
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#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 OUT 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 ((UINT16) 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 = (UINT16) (~NetblockChecksum ((UINT8 *) PacketHead, HeadLen));
Packet->Ip.Ip4 = 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[in] IpSb The IP4 service that wants to send the packets.
@param[in] Dst The destination of the packet
@param[in] Src The source of the packet
@return NULL if no proper interface is found, otherwise the interface that
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;
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
**/
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[in] IpSb The IP4 service instance to transmit the packet
@param[in] IpInstance The IP4 child that issues the transmission. It is
NULL if the packet is from the system.
@param[in] Packet The user data to send, excluding the IP header.
@param[in] 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[in] Option The original option to append to the IP headers
@param[in] OptLen The length of the option
@param[in] GateWay The next hop address to transmit packet to.
255.255.255.255 means broadcast.
@param[in] Callback The callback function to issue when transmission
completed.
@param[in] 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 EFI_BAD_BUFFER_SIZE The length of the IPv4 header + option length +
total data length is greater than MTU (or greater
than the maximum packet size if Token.Packet.TxData.
OverrideData.DoNotFragment is TRUE.)
@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;
BOOLEAN RawData;
//
// 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;
}
//
// Before IPsec process, prepared the IP head.
// If Ip4Output is transmitting RawData, don't update IPv4 header.
//
HeadLen = sizeof (IP4_HEAD) + ((OptLen + 3) & (~0x03));
if ((IpInstance != NULL) && IpInstance->ConfigData.RawData) {
RawData = TRUE;
} else {
Head->HeadLen = (UINT8) (HeadLen >> 2);
Head->Id = mIp4Id++;
Head->Ver = 4;
RawData = FALSE;
}
//
// Call IPsec process.
//
Status = Ip4IpSecProcessPacket (
IpSb,
&Head,
&Packet,
&Option,
&OptLen,
EfiIPsecOutBound,
Context
);
if (EFI_ERROR(Status)) {
return Status;
}
Dest = Head->Dst;
if (IP4_IS_BROADCAST (Ip4GetNetCast (Dest, IpIf)) || (Dest == IP4_ALLONE_ADDRESS)) {
//
// Set the gateway to local broadcast if the Dest 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 if (GateWay == IP4_ALLZERO_ADDRESS) {
//
// Route the packet unless overrided, that is, GateWay isn't zero.
//
if (IpInstance == NULL) {
CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src, IpIf->SubnetMask, TRUE);
} else {
CacheEntry = Ip4Route (IpInstance->RouteTable, Head->Dst, Head->Src, IpIf->SubnetMask, FALSE);
//
// If failed to route the packet by using the instance's route table,
// try to use the default route table.
//
if (CacheEntry == NULL) {
CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src, IpIf->SubnetMask, TRUE);
}
}
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->MaxPacketSize + sizeof (IP4_HEAD);
if (Packet->TotalSize + HeadLen > Mtu) {
//
// Fragmentation is diabled for RawData mode.
//
if (RawData) {
return EFI_BAD_BUFFER_SIZE;
}
//
// 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,
IpSb
);
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, IpSb);
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[in] Frame The frames hold by the low level interface
@param[in] 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.
**/
BOOLEAN
Ip4CancelPacketFragments (
IN IP4_LINK_TX_TOKEN *Frame,
IN 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.
**/
VOID
Ip4CancelPacket (
IN IP4_INTERFACE *IpIf,
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus
)
{
Ip4CancelFrames (IpIf, IoStatus, Ip4CancelPacketFragments, Packet);
}

View File

@@ -0,0 +1,120 @@
/** @file
Copyright (c) 2005 - 2006, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_IP4_OUTPUT_H__
#define __EFI_IP4_OUTPUT_H__
/**
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
**/
VOID
Ip4SysPacketSent (
IP4_PROTOCOL *Ip4Instance,
NET_BUF *Packet,
EFI_STATUS IoStatus,
UINT32 LinkFlag,
VOID *Context
);
/**
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[in] IpSb The IP4 service instance to transmit the packet
@param[in] IpInstance The IP4 child that issues the transmission. It is
NULL if the packet is from the system.
@param[in] Packet The user data to send, excluding the IP header.
@param[in] 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[in] Option The original option to append to the IP headers
@param[in] OptLen The length of the option
@param[in] GateWay The next hop address to transmit packet to.
255.255.255.255 means broadcast.
@param[in] Callback The callback function to issue when transmission
completed.
@param[in] 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
);
/**
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.
**/
VOID
Ip4CancelPacket (
IN IP4_INTERFACE *IpIf,
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus
);
/**
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 OUT NET_BUF *Packet,
IN IP4_HEAD *Head,
IN UINT8 *Option,
IN UINT32 OptLen
);
extern UINT16 mIp4Id;
#endif

View File

@@ -0,0 +1,673 @@
/** @file
Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Ip4Impl.h"
/**
Allocate a route entry then initialize it with the Dest/Netmaks
and Gateway.
@param[in] Dest The destination network
@param[in] Netmask The destination network mask
@param[in] GateWay The nexthop address
@return NULL if failed to allocate memeory, otherwise the newly created
route entry.
**/
IP4_ROUTE_ENTRY *
Ip4CreateRouteEntry (
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR GateWay
)
{
IP4_ROUTE_ENTRY *RtEntry;
RtEntry = AllocatePool (sizeof (IP4_ROUTE_ENTRY));
if (RtEntry == NULL) {
return NULL;
}
InitializeListHead (&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.
**/
VOID
Ip4FreeRouteEntry (
IN IP4_ROUTE_ENTRY *RtEntry
)
{
ASSERT (RtEntry->RefCnt > 0);
if (--RtEntry->RefCnt == 0) {
FreePool (RtEntry);
}
}
/**
Allocate and initialize an IP4 route cache entry.
@param[in] Dst The destination address
@param[in] Src The source address
@param[in] GateWay The next hop address
@param[in] 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
to the created route cache entry.
**/
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 = AllocatePool (sizeof (IP4_ROUTE_CACHE_ENTRY));
if (RtCacheEntry == NULL) {
return NULL;
}
InitializeListHead (&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.
**/
VOID
Ip4FreeRouteCacheEntry (
IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry
)
{
ASSERT (RtCacheEntry->RefCnt > 0);
if (--RtCacheEntry->RefCnt == 0) {
FreePool (RtCacheEntry);
}
}
/**
Initialize an empty route cache table.
@param[in, out] RtCache The rotue cache table to initialize.
**/
VOID
Ip4InitRouteCache (
IN OUT IP4_ROUTE_CACHE *RtCache
)
{
UINT32 Index;
for (Index = 0; Index < IP4_ROUTE_CACHE_HASH_VALUE; Index++) {
InitializeListHead (&(RtCache->CacheBucket[Index]));
}
}
/**
Clean up a route cache, that is free all the route cache
entries enqueued in the cache.
@param[in] RtCache The route cache table to clean up
**/
VOID
Ip4CleanRouteCache (
IN IP4_ROUTE_CACHE *RtCache
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
UINT32 Index;
for (Index = 0; Index < IP4_ROUTE_CACHE_HASH_VALUE; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtCache->CacheBucket[Index])) {
RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
RemoveEntryList (Entry);
Ip4FreeRouteCacheEntry (RtCacheEntry);
}
}
}
/**
Create an empty route table, includes its internal route cache
@return NULL if failed to allocate memory for the route table, otherwise
the point to newly created route table.
**/
IP4_ROUTE_TABLE *
Ip4CreateRouteTable (
VOID
)
{
IP4_ROUTE_TABLE *RtTable;
UINT32 Index;
RtTable = AllocatePool (sizeof (IP4_ROUTE_TABLE));
if (RtTable == NULL) {
return NULL;
}
RtTable->RefCnt = 1;
RtTable->TotalNum = 0;
for (Index = 0; Index <= IP4_MASK_MAX; Index++) {
InitializeListHead (&(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[in] RtTable The route table to free.
**/
VOID
Ip4FreeRouteTable (
IN IP4_ROUTE_TABLE *RtTable
)
{
LIST_ENTRY *Entry;
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_MAX; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtTable->RouteArea[Index])) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
RemoveEntryList (Entry);
Ip4FreeRouteEntry (RtEntry);
}
}
Ip4CleanRouteCache (&RtTable->Cache);
FreePool (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
**/
VOID
Ip4PurgeRouteCache (
IN OUT IP4_ROUTE_CACHE *RtCache,
IN UINTN Tag
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
UINT32 Index;
for (Index = 0; Index < IP4_ROUTE_CACHE_HASH_VALUE; 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) {
RemoveEntryList (Entry);
Ip4FreeRouteCacheEntry (RtCacheEntry);
}
}
}
}
/**
Add a route entry to the route table. All the IP4_ADDRs are in
host byte order.
@param[in, out] RtTable Route table to add route to
@param[in] Dest The destination of the network
@param[in] Netmask The netmask of the destination
@param[in] 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 OUT IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR Gateway
)
{
LIST_ENTRY *Head;
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;
}
InsertHeadList (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 OUT IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR Gateway
)
{
LIST_ENTRY *Head;
LIST_ENTRY *Entry;
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);
RemoveEntryList (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[in] RtTable The route table to search the cache for
@param[in] Dest The destination address
@param[in] Src The source address
@return NULL if no route entry to the (Dest, Src). Otherwise the point
to the correct route cache entry.
**/
IP4_ROUTE_CACHE_ENTRY *
Ip4FindRouteCache (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Src
)
{
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[in] RtTable The route table to search from
@param[in] Dst The destionation address to search
@return NULL if no route matches the Dst, otherwise the point to the
most specific route to the Dst.
**/
IP4_ROUTE_ENTRY *
Ip4FindRouteEntry (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dst
)
{
LIST_ENTRY *Entry;
IP4_ROUTE_ENTRY *RtEntry;
IP4_ROUTE_TABLE *Table;
INTN Index;
RtEntry = NULL;
for (Index = IP4_MASK_MAX; 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/create a route
cache if there is a route to the destination.
@param[in] RtTable The route table to search from
@param[in] Dest The destination address to search for
@param[in] Src The source address to search for
@param[in] SubnetMask The subnet mask of the Src address, this field is
used to check if the station is using /32 subnet.
@param[in] AlwaysTryDestAddr Always try to use the dest address as next hop even
though we can't find a matching route entry. This
field is only valid when using /32 subnet.
@return NULL if failed to route packet, otherwise a route cache
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,
IN IP4_ADDR SubnetMask,
IN BOOLEAN AlwaysTryDestAddr
)
{
LIST_ENTRY *Head;
LIST_ENTRY *Entry;
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) {
RemoveEntryList (&RtCacheEntry->Link);
InsertHeadList (Head, &RtCacheEntry->Link);
return RtCacheEntry;
}
//
// Search the route table for the most specific route
//
RtEntry = Ip4FindRouteEntry (RtTable, Dest);
if (RtEntry == NULL) {
if (SubnetMask != IP4_ALLONE_ADDRESS) {
return NULL;
} else if (!AlwaysTryDestAddr) {
return NULL;
}
}
//
// Found a route to the Dest, if it is a direct route, the packet
// will be sent directly to the destination, such as for connected
// network. Otherwise, it is an indirect route, the packet will be
// sent to the next hop router.
//
// When using /32 subnet mask, the packet will always be sent to the direct
// destination first, if we can't find a matching route cache.
//
if (SubnetMask == IP4_ALLONE_ADDRESS || ((RtEntry->Flag & IP4_DIRECT_ROUTE) != 0)) {
NextHop = Dest;
} else {
NextHop = RtEntry->NextHop;
}
if (RtEntry != NULL) {
Ip4FreeRouteEntry (RtEntry);
}
//
// Create a route cache entry, and tag it as spawned from this route entry
// For /32 subnet mask, the default route in RtEntry will be used if failed
// to send the packet to driect destination address.
//
RtCacheEntry = Ip4CreateRouteCacheEntry (Dest, Src, NextHop, (UINTN) RtEntry);
if (RtCacheEntry == NULL) {
return NULL;
}
InsertHeadList (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);
RemoveEntryList (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[in] 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
)
{
LIST_ENTRY *Entry;
IP4_ROUTE_TABLE *RtTable;
IP4_ROUTE_ENTRY *RtEntry;
EFI_IP4_ROUTE_TABLE *Table;
UINT32 Count;
INT32 Index;
RtTable = IpInstance->RouteTable;
if (IpInstance->EfiRouteTable != NULL) {
FreePool (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 = AllocatePool (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_MAX; 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,225 @@
/** @file
EFI IP4 route table and route cache table defintions.
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_IP4_ROUTE_H__
#define __EFI_IP4_ROUTE_H__
#include "Ip4Common.h"
#define IP4_DIRECT_ROUTE 0x00000001
#define IP4_ROUTE_CACHE_HASH_VALUE 31
#define 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_VALUE)
///
/// 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 {
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 {
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 {
LIST_ENTRY CacheBucket[IP4_ROUTE_CACHE_HASH_VALUE];
} 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;
struct _IP4_ROUTE_TABLE {
INTN RefCnt;
UINT32 TotalNum;
LIST_ENTRY RouteArea[IP4_MASK_NUM];
IP4_ROUTE_TABLE *Next;
IP4_ROUTE_CACHE Cache;
};
/**
Create an empty route table, includes its internal route cache
@return NULL if failed to allocate memory for the route table, otherwise
the point to newly created route table.
**/
IP4_ROUTE_TABLE *
Ip4CreateRouteTable (
VOID
);
/**
Free the route table and its associated route cache. Route
table is reference counted.
@param[in] RtTable The route table to free.
**/
VOID
Ip4FreeRouteTable (
IN IP4_ROUTE_TABLE *RtTable
);
/**
Add a route entry to the route table. All the IP4_ADDRs are in
host byte order.
@param[in, out] RtTable Route table to add route to
@param[in] Dest The destination of the network
@param[in] Netmask The netmask of the destination
@param[in] 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 OUT IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR Gateway
);
/**
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 OUT IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR Gateway
);
/**
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[in] RtTable The route table to search the cache for
@param[in] Dest The destination address
@param[in] Src The source address
@return NULL if no route entry to the (Dest, Src). Otherwise the point
to the correct route cache entry.
**/
IP4_ROUTE_CACHE_ENTRY *
Ip4FindRouteCache (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Src
);
/**
Free the route cache entry. It is reference counted.
@param RtCacheEntry The route cache entry to free.
**/
VOID
Ip4FreeRouteCacheEntry (
IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry
);
/**
Search the route table to route the packet. Return/create a route
cache if there is a route to the destination.
@param[in] RtTable The route table to search from
@param[in] Dest The destination address to search for
@param[in] Src The source address to search for
@param[in] SubnetMask The subnet mask of the Src address, this field is
used to check if the station is using /32 subnet.
@param[in] AlwaysTryDestAddr Always try to use the dest address as next hop even
though we can't find a matching route entry. This
field is only valid when using /32 subnet.
@return NULL if failed to route packet, otherwise a route cache
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,
IN IP4_ADDR SubnetMask,
IN BOOLEAN AlwaysTryDestAddr
);
/**
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[in] 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
);
#endif