Add NetworkPkg (P.UDK2010.UP3.Network.P1)

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10986 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
hhtian
2010-11-01 06:13:54 +00:00
parent 12873d5766
commit a3bcde70e6
142 changed files with 83988 additions and 0 deletions

View File

@@ -0,0 +1,313 @@
/** @file
Implementation of EFI_COMPONENT_NAME_PROTOCOL and
EFI_COMPONENT_NAME2_PROTOCOL protocol.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ip6Impl.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
Ip6ComponentNameGetDriverName (
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 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 not a valid EFI_HANDLE.
@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
Ip6ComponentNameGetControllerName (
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 gIp6ComponentName = {
Ip6ComponentNameGetDriverName,
Ip6ComponentNameGetControllerName,
"eng"
};
//
// EFI Component Name 2 Protocol.
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIp6ComponentName2 = {
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) Ip6ComponentNameGetDriverName,
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) Ip6ComponentNameGetControllerName,
"en"
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIp6DriverNameTable[] = {
{
"eng;en",
L"IP6 Network Service Driver"
},
{
NULL,
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
Ip6ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mIp6DriverNameTable,
DriverName,
(BOOLEAN) (This == &gIp6ComponentName)
);
}
/**
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 not a valid EFI_HANDLE.
@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
Ip6ComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
return EFI_UNSUPPORTED;
}

View File

@@ -0,0 +1,796 @@
/** @file
The implementation of common functions shared by IP6 driver.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ip6Impl.h"
/**
Build a array of EFI_IP6_ADDRESS_INFO to be returned to the caller. The number
of EFI_IP6_ADDRESS_INFO is also returned. If AddressList is NULL,
only the address count is returned.
@param[in] IpSb The IP6 service binding instance.
@param[out] AddressCount The number of returned addresses.
@param[out] AddressList The pointer to the array of EFI_IP6_ADDRESS_INFO.
This is an optional parameter.
@retval EFI_SUCCESS The address array successfully built.
@retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the address info.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
**/
EFI_STATUS
Ip6BuildEfiAddressList (
IN IP6_SERVICE *IpSb,
OUT UINT32 *AddressCount,
OUT EFI_IP6_ADDRESS_INFO **AddressList OPTIONAL
)
{
UINT32 Count;
LIST_ENTRY *Entry;
EFI_IP6_ADDRESS_INFO *EfiAddrInfo;
IP6_ADDRESS_INFO *AddrInfo;
if (AddressCount == NULL) {
return EFI_INVALID_PARAMETER;
}
if (IpSb->LinkLocalOk) {
Count = 1 + IpSb->DefaultInterface->AddressCount;
} else {
Count = 0;
}
*AddressCount = Count;
if ((AddressList == NULL) || (Count == 0)) {
return EFI_SUCCESS;
}
if (*AddressList == NULL) {
*AddressList = AllocatePool (sizeof (EFI_IP6_ADDRESS_INFO) * Count);
if (*AddressList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
}
EfiAddrInfo = *AddressList;
IP6_COPY_ADDRESS (&EfiAddrInfo->Address, &IpSb->LinkLocalAddr);
EfiAddrInfo->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;
EfiAddrInfo++;
Count = 1;
NET_LIST_FOR_EACH (Entry, &IpSb->DefaultInterface->AddressList) {
AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
IP6_COPY_ADDRESS (&EfiAddrInfo->Address, &AddrInfo->Address);
EfiAddrInfo->PrefixLength = AddrInfo->PrefixLength;
EfiAddrInfo++;
Count++;
}
ASSERT (Count == *AddressCount);
return EFI_SUCCESS;
}
/**
Generate the multicast addresses identify the group of all IPv6 nodes or IPv6
routers defined in RFC4291.
All Nodes Addresses: FF01::1, FF02::1.
All Router Addresses: FF01::2, FF02::2, FF05::2.
@param[in] Router If TRUE, generate all routers addresses,
else generate all node addresses.
@param[in] Scope interface-local(1), link-local(2), or site-local(5)
@param[out] Ip6Addr The generated multicast address.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@retval EFI_SUCCESS The address is generated.
**/
EFI_STATUS
Ip6SetToAllNodeMulticast (
IN BOOLEAN Router,
IN UINT8 Scope,
OUT EFI_IPv6_ADDRESS *Ip6Addr
)
{
if (Ip6Addr == NULL) {
return EFI_INVALID_PARAMETER;
}
if (!Router && Scope == IP6_SITE_LOCAL_SCOPE) {
return EFI_INVALID_PARAMETER;
}
ZeroMem (Ip6Addr, sizeof (EFI_IPv6_ADDRESS));
Ip6Addr->Addr[0] = 0xFF;
Ip6Addr->Addr[1] = Scope;
if (!Router) {
Ip6Addr->Addr[15] = 0x1;
} else {
Ip6Addr->Addr[15] = 0x2;
}
return EFI_SUCCESS;
}
/**
This function converts MAC address to 64 bits interface ID according to RFC4291
and returns the interface ID. Currently only 48-bit MAC address is supported by
this function.
@param[in, out] IpSb The IP6 service binding instance.
@retval NULL The operation fails.
@return Pointer to the generated interface ID.
**/
UINT8 *
Ip6CreateInterfaceID (
IN OUT IP6_SERVICE *IpSb
)
{
UINT8 InterfaceId[8];
UINT8 Byte;
EFI_MAC_ADDRESS *MacAddr;
UINT32 AddrLen;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
AddrLen = IpSb->SnpMode.HwAddressSize;
//
// Currently only IEEE 802 48-bit MACs are supported to create link local address.
//
if (AddrLen != IP6_MAC_LEN || IpSb->InterfaceIdLen != IP6_IF_ID_LEN) {
return NULL;
}
MacAddr = &IpSb->SnpMode.CurrentAddress;
//
// Convert MAC address to 64 bits interface ID according to Appendix A of RFC4291:
// 1. Insert 0xFFFE to the middle
// 2. Invert the universal/local bit - bit 6 in network order
//
CopyMem (InterfaceId, MacAddr, 3);
InterfaceId[3] = 0xFF;
InterfaceId[4] = 0xFE;
CopyMem (&InterfaceId[5], &MacAddr->Addr[3], 3);
Byte = (UINT8) (InterfaceId[0] & IP6_U_BIT);
if (Byte == IP6_U_BIT) {
InterfaceId[0] &= ~IP6_U_BIT;
} else {
InterfaceId[0] |= IP6_U_BIT;
}
//
// Return the interface ID.
//
return AllocateCopyPool (IpSb->InterfaceIdLen, InterfaceId);
}
/**
This function creates link-local address from interface identifier. The
interface identifier is normally created from MAC address. It might be manually
configured by administrator if the link-local address created from MAC address
is a duplicate address.
@param[in, out] IpSb The IP6 service binding instance.
@retval NULL If the operation fails.
@return The generated Link Local address, in network order.
**/
EFI_IPv6_ADDRESS *
Ip6CreateLinkLocalAddr (
IN OUT IP6_SERVICE *IpSb
)
{
EFI_IPv6_ADDRESS *Ip6Addr;
EFI_IP6_CONFIG_PROTOCOL *Ip6Config;
UINTN DataSize;
EFI_IP6_CONFIG_INTERFACE_ID InterfaceId;
EFI_STATUS Status;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
if (IpSb->InterfaceId != NULL) {
FreePool (IpSb->InterfaceId);
}
//
// Get the interface id if it is manully configured.
//
Ip6Config = &IpSb->Ip6ConfigInstance.Ip6Config;
DataSize = sizeof (EFI_IP6_CONFIG_INTERFACE_ID);
ZeroMem (&InterfaceId, DataSize);
Status = Ip6Config->GetData (
Ip6Config,
Ip6ConfigDataTypeAltInterfaceId,
&DataSize,
&InterfaceId
);
if (Status == EFI_NOT_FOUND) {
//
// Since the interface id is not configured, generate the interface id from
// MAC address.
//
IpSb->InterfaceId = Ip6CreateInterfaceID (IpSb);
if (IpSb->InterfaceId == NULL) {
return NULL;
}
CopyMem (&InterfaceId, IpSb->InterfaceId, IpSb->InterfaceIdLen);
//
// Record the interface id.
//
Status = Ip6Config->SetData (
Ip6Config,
Ip6ConfigDataTypeAltInterfaceId,
DataSize,
&InterfaceId
);
if (EFI_ERROR (Status)) {
FreePool (IpSb->InterfaceId);
IpSb->InterfaceId = NULL;
return NULL;
}
} else if (!EFI_ERROR (Status)) {
IpSb->InterfaceId = AllocateCopyPool (DataSize, &InterfaceId);
if (IpSb->InterfaceId == NULL) {
return NULL;
}
} else {
return NULL;
}
//
// Append FE80::/64 to the left of IPv6 address then return.
//
Ip6Addr = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS));
if (Ip6Addr == NULL) {
FreePool (IpSb->InterfaceId);
IpSb->InterfaceId = NULL;
return NULL;
}
CopyMem (&Ip6Addr->Addr[8], IpSb->InterfaceId, IpSb->InterfaceIdLen);
Ip6Addr->Addr[1] = 0x80;
Ip6Addr->Addr[0] = 0xFE;
return Ip6Addr;
}
/**
Compute the solicited-node multicast address for an unicast or anycast address,
by taking the low-order 24 bits of this address, and appending those bits to
the prefix FF02:0:0:0:0:1:FF00::/104.
@param[in] Ip6Addr The unicast or anycast address, in network order.
@param[out] MulticastAddr The generated solicited-node multicast address,
in network order.
**/
VOID
Ip6CreateSNMulticastAddr (
IN EFI_IPv6_ADDRESS *Ip6Addr,
OUT EFI_IPv6_ADDRESS *MulticastAddr
)
{
ASSERT (Ip6Addr != NULL && MulticastAddr != NULL);
ZeroMem (MulticastAddr, sizeof (EFI_IPv6_ADDRESS));
MulticastAddr->Addr[0] = 0xFF;
MulticastAddr->Addr[1] = 0x02;
MulticastAddr->Addr[11] = 0x1;
MulticastAddr->Addr[12] = 0xFF;
CopyMem (&MulticastAddr->Addr[13], &Ip6Addr->Addr[13], 3);
}
/**
Insert a node IP6_ADDRESS_INFO to an IP6 interface.
@param[in, out] IpIf Points to an IP6 interface.
@param[in] AddrInfo Points to IP6_ADDRESS_INFO
**/
VOID
Ip6AddAddr (
IN OUT IP6_INTERFACE *IpIf,
IN IP6_ADDRESS_INFO *AddrInfo
)
{
InsertHeadList (&IpIf->AddressList, &AddrInfo->Link);
IpIf->AddressCount++;
}
/**
Destroy the IP instance if its StationAddress is removed. It is the help function
for Ip6RemoveAddr().
@param[in, out] IpSb Points to an IP6 service binding instance.
@param[in] Address The to be removed address
**/
VOID
Ip6DestroyInstanceByAddress (
IN OUT IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Address
)
{
BOOLEAN OneDestroyed;
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
LIST_ENTRY *Entry;
IP6_PROTOCOL *Instance;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
ServiceBinding = &IpSb->ServiceBinding;
//
// Upper layer IP protocol consumers may have tight relationship between several
// IP protocol instances, in other words, calling ServiceBinding->DestroyChild to
// destroy one IP child may cause other related IP children destroyed too. This
// will probably leave hole in the children list when we iterate it. So everytime
// we just destroy one child then back to the start point to iterate the list.
//
do {
OneDestroyed = FALSE;
NET_LIST_FOR_EACH (Entry, &IpSb->Children) {
Instance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
if ((Instance->State == IP6_STATE_CONFIGED) && EFI_IP6_EQUAL (&Instance->ConfigData.StationAddress, Address)) {
ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
OneDestroyed = TRUE;
break;
}
}
} while (OneDestroyed);
}
/**
Remove the IPv6 address from the address list node points to IP6_ADDRESS_INFO.
This function removes the matching IPv6 addresses from the address list and
adjusts the address count of the address list. If IpSb is not NULL, this function
calls Ip6LeaveGroup to see whether it should call Mnp->Groups() to remove the
its solicited-node multicast MAC address from the filter list and sends out
a Multicast Listener Done. If Prefix is NULL, all address in the address list
will be removed. If Prefix is not NULL, the address that matching the Prefix
with PrefixLength in the address list will be removed.
@param[in] IpSb NULL or points to IP6 service binding instance.
@param[in, out] AddressList Address list array.
@param[in, out] AddressCount The count of addresses in address list array.
@param[in] Prefix NULL or an IPv6 address prefix.
@param[in] PrefixLength The length of Prefix.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_NOT_FOUND The address matching the Prefix with PrefixLength
cannot be found in the address list.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
**/
EFI_STATUS
Ip6RemoveAddr (
IN IP6_SERVICE *IpSb OPTIONAL,
IN OUT LIST_ENTRY *AddressList,
IN OUT UINT32 *AddressCount,
IN EFI_IPv6_ADDRESS *Prefix OPTIONAL,
IN UINT8 PrefixLength
)
{
EFI_STATUS Status;
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
IP6_ADDRESS_INFO *AddrInfo;
EFI_IPv6_ADDRESS SnMCastAddr;
if (IsListEmpty (AddressList) || *AddressCount < 1 || PrefixLength > IP6_PREFIX_NUM) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_NOT_FOUND;
NET_LIST_FOR_EACH_SAFE (Entry, Next, AddressList) {
AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
if (Prefix == NULL ||
(PrefixLength == 128 && EFI_IP6_EQUAL (Prefix, &AddrInfo->Address)) ||
(PrefixLength == AddrInfo->PrefixLength && NetIp6IsNetEqual (Prefix, &AddrInfo->Address, PrefixLength))
) {
if (IpSb != NULL) {
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
Ip6CreateSNMulticastAddr (&AddrInfo->Address, &SnMCastAddr);
Ip6LeaveGroup (IpSb, &SnMCastAddr);
//
// Destroy any instance who is using the dying address as the source address.
//
Ip6DestroyInstanceByAddress (IpSb, &AddrInfo->Address);
}
RemoveEntryList (Entry);
FreePool (AddrInfo);
(*AddressCount)--;
Status = EFI_SUCCESS;
}
}
return Status;
}
/**
Check whether the incoming Ipv6 address is a solicited-node multicast address.
@param[in] Ip6 Ip6 address, in network order.
@retval TRUE Yes, solicited-node multicast address
@retval FALSE No
**/
BOOLEAN
Ip6IsSNMulticastAddr (
IN EFI_IPv6_ADDRESS *Ip6
)
{
EFI_IPv6_ADDRESS Sn;
BOOLEAN Flag;
Ip6CreateSNMulticastAddr (Ip6, &Sn);
Flag = FALSE;
if (CompareMem (Sn.Addr, Ip6->Addr, 13) == 0) {
Flag = TRUE;
}
return Flag;
}
/**
Check whether the incoming IPv6 address is one of the maintained addresses in
the IP6 service binding instance.
@param[in] IpSb Points to a IP6 service binding instance.
@param[in] Address The IP6 address to be checked.
@param[out] Interface If not NULL, output the IP6 interface which
maintains the Address.
@param[out] AddressInfo If not NULL, output the IP6 address information
of the Address.
@retval TRUE Yes, it is one of the maintained address.
@retval FALSE No, it is not one of the maintained address.
**/
BOOLEAN
Ip6IsOneOfSetAddress (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Address,
OUT IP6_INTERFACE **Interface OPTIONAL,
OUT IP6_ADDRESS_INFO **AddressInfo OPTIONAL
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Entry2;
IP6_INTERFACE *IpIf;
IP6_ADDRESS_INFO *TmpAddressInfo;
//
// Check link-local address first
//
if (IpSb->LinkLocalOk && EFI_IP6_EQUAL (&IpSb->LinkLocalAddr, Address)) {
if (Interface != NULL) {
*Interface = IpSb->DefaultInterface;
}
if (AddressInfo != NULL) {
*AddressInfo = NULL;
}
return TRUE;
}
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {
TmpAddressInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
if (EFI_IP6_EQUAL (&TmpAddressInfo->Address, Address)) {
if (Interface != NULL) {
*Interface = IpIf;
}
if (AddressInfo != NULL) {
*AddressInfo = TmpAddressInfo;
}
return TRUE;
}
}
}
return FALSE;
}
/**
Check whether the incoming MAC address is valid.
@param[in] IpSb Points to a IP6 service binding instance.
@param[in] LinkAddress The MAC address.
@retval TRUE Yes, it is valid.
@retval FALSE No, it is not valid.
**/
BOOLEAN
Ip6IsValidLinkAddress (
IN IP6_SERVICE *IpSb,
IN EFI_MAC_ADDRESS *LinkAddress
)
{
UINT32 Index;
//
// TODO: might be updated later to be more acceptable.
//
for (Index = IpSb->SnpMode.HwAddressSize; Index < sizeof (EFI_MAC_ADDRESS); Index++) {
if (LinkAddress->Addr[Index] != 0) {
return FALSE;
}
}
return TRUE;
}
/**
Copy the PrefixLength bits from Src to Dest.
@param[out] Dest A pointer to the buffer to copy to.
@param[in] Src A pointer to the buffer to copy from.
@param[in] PrefixLength The number of bits to copy.
**/
VOID
Ip6CopyAddressByPrefix (
OUT EFI_IPv6_ADDRESS *Dest,
IN EFI_IPv6_ADDRESS *Src,
IN UINT8 PrefixLength
)
{
UINT8 Byte;
UINT8 Bit;
UINT8 Mask;
ASSERT (Dest != NULL && Src != NULL);
ASSERT (PrefixLength < IP6_PREFIX_NUM);
Byte = (UINT8) (PrefixLength / 8);
Bit = (UINT8) (PrefixLength % 8);
ZeroMem (Dest, sizeof (EFI_IPv6_ADDRESS));
CopyMem (Dest, Src, Byte);
if (Bit > 0) {
Mask = (UINT8) (0xFF << (8 - Bit));
ASSERT (Byte < 16);
Dest->Addr[Byte] = (UINT8) (Src->Addr[Byte] & Mask);
}
}
/**
Get the MAC address for a multicast IP address. Call
Mnp's McastIpToMac to find the MAC address instead of
hard-coding 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 The multicast IP successfully
translated to a multicast MAC address.
@retval Other The address is not converted because an error occurred.
**/
EFI_STATUS
Ip6GetMulticastMac (
IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
IN EFI_IPv6_ADDRESS *Multicast,
OUT EFI_MAC_ADDRESS *Mac
)
{
EFI_IP_ADDRESS EfiIp;
IP6_COPY_ADDRESS (&EfiIp.v6, Multicast);
return Mnp->McastIpToMac (Mnp, TRUE, &EfiIp, Mac);
}
/**
Set the Ip6 variable data.
@param[in] IpSb Points to an IP6 service binding instance.
@retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.
@retval other Set variable failed.
**/
EFI_STATUS
Ip6SetVariableData (
IN IP6_SERVICE *IpSb
)
{
UINT32 NumConfiguredInstance;
LIST_ENTRY *Entry;
UINTN VariableDataSize;
EFI_IP6_VARIABLE_DATA *Ip6VariableData;
EFI_IP6_ADDRESS_PAIR *Ip6AddressPair;
IP6_PROTOCOL *IpInstance;
CHAR16 *NewMacString;
EFI_STATUS Status;
NumConfiguredInstance = 0;
//
// Go through the children list to count the configured children.
//
NET_LIST_FOR_EACH (Entry, &IpSb->Children) {
IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
if (IpInstance->State == IP6_STATE_CONFIGED) {
NumConfiguredInstance++;
}
}
//
// Calculate the size of the Ip6VariableData. As there may be no IP child,
// we should add extra buffer for the address paris only if the number of configured
// children is more than 1.
//
VariableDataSize = sizeof (EFI_IP6_VARIABLE_DATA);
if (NumConfiguredInstance > 1) {
VariableDataSize += sizeof (EFI_IP6_ADDRESS_PAIR) * (NumConfiguredInstance - 1);
}
Ip6VariableData = AllocatePool (VariableDataSize);
if (Ip6VariableData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Ip6VariableData->DriverHandle = IpSb->Image;
Ip6VariableData->AddressCount = NumConfiguredInstance;
Ip6AddressPair = &Ip6VariableData->AddressPairs[0];
//
// Go through the children list to fill the configured children's address pairs.
//
NET_LIST_FOR_EACH (Entry, &IpSb->Children) {
IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
if (IpInstance->State == IP6_STATE_CONFIGED) {
Ip6AddressPair->InstanceHandle = IpInstance->Handle;
Ip6AddressPair->PrefixLength = IpInstance->PrefixLength;
IP6_COPY_ADDRESS (&Ip6AddressPair->Ip6Address, &IpInstance->ConfigData.StationAddress);
Ip6AddressPair++;
}
}
//
// Get the mac string.
//
Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &NewMacString);
if (EFI_ERROR (Status)) {
goto Exit;
}
if (IpSb->MacString != NULL) {
//
// The variable is set already, we're going to update it.
//
if (StrCmp (IpSb->MacString, NewMacString) != 0) {
//
// The mac address is changed, delete the previous variable first.
//
gRT->SetVariable (
IpSb->MacString,
&gEfiIp6ServiceBindingProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
0,
NULL
);
}
FreePool (IpSb->MacString);
}
IpSb->MacString = NewMacString;
Status = gRT->SetVariable (
IpSb->MacString,
&gEfiIp6ServiceBindingProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
VariableDataSize,
(VOID *) Ip6VariableData
);
Exit:
FreePool (Ip6VariableData);
return Status;
}
/**
Clear the variable and free the resource.
@param[in] IpSb Ip6 service binding instance.
**/
VOID
Ip6ClearVariableData (
IN IP6_SERVICE *IpSb
)
{
ASSERT (IpSb->MacString != NULL);
gRT->SetVariable (
IpSb->MacString,
&gEfiIp6ServiceBindingProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
0,
NULL
);
FreePool (IpSb->MacString);
IpSb->MacString = NULL;
}
/**
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, out] Head The IP head to convert.
@return Point to the converted IP head.
**/
EFI_IP6_HEADER *
Ip6NtohHead (
IN OUT EFI_IP6_HEADER *Head
)
{
Head->FlowLabelL = NTOHS (Head->FlowLabelL);
Head->PayloadLength = NTOHS (Head->PayloadLength);
return Head;
}

View File

@@ -0,0 +1,338 @@
/** @file
Common definition and functions for IP6 driver.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_COMMON_H__
#define __EFI_IP6_COMMON_H__
#define IP6_LINK_EQUAL(Mac1, Mac2) (CompareMem ((Mac1), (Mac2), sizeof (EFI_MAC_ADDRESS)) == 0)
//
// Convert the Microsecond to second. IP transmit/receive time is
// in the unit of microsecond. IP ticks once per second.
//
#define IP6_US_TO_SEC(Us) (((Us) + 999999) / 1000000)
#define IP6_ETHER_PROTO 0x86DD
#define IP6_MAC_LEN 6
#define IP6_IF_ID_LEN 8
#define IP6_INTERFACE_LOCAL_SCOPE 1
#define IP6_LINK_LOCAL_SCOPE 2
#define IP6_SITE_LOCAL_SCOPE 5
#define IP6_INFINIT_LIFETIME 0xFFFFFFFF
#define IP6_HOP_LIMIT 255
//
// Make it to 64 since all 54 bits are zero.
//
#define IP6_LINK_LOCAL_PREFIX_LENGTH 64
#define IP6_TIMER_INTERVAL_IN_MS 100
#define IP6_ONE_SECOND_IN_MS 1000
//
// The packet is received as link level broadcast/multicast/promiscuous.
//
#define IP6_LINK_BROADCAST 0x00000001
#define IP6_LINK_MULTICAST 0x00000002
#define IP6_LINK_PROMISC 0x00000004
#define IP6_U_BIT 0x02
typedef enum {
Ip6Promiscuous = 1,
Ip6Unicast,
Ip6Multicast,
Ip6AnyCast
} IP6_ADDRESS_TYPE;
typedef struct _IP6_INTERFACE IP6_INTERFACE;
typedef struct _IP6_PROTOCOL IP6_PROTOCOL;
typedef struct _IP6_SERVICE IP6_SERVICE;
typedef struct _IP6_ADDRESS_INFO IP6_ADDRESS_INFO;
/**
Build a array of EFI_IP6_ADDRESS_INFO to be returned to the caller. The number
of EFI_IP6_ADDRESS_INFO is also returned. If AddressList is NULL,
only the address count is returned.
@param[in] IpSb The IP6 service binding instance.
@param[out] AddressCount The number of returned addresses.
@param[out] AddressList The pointer to the array of EFI_IP6_ADDRESS_INFO.
This is an optional parameter.
@retval EFI_SUCCESS The address array is successfully build
@retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the address info.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
**/
EFI_STATUS
Ip6BuildEfiAddressList (
IN IP6_SERVICE *IpSb,
OUT UINT32 *AddressCount,
OUT EFI_IP6_ADDRESS_INFO **AddressList OPTIONAL
);
/**
Generate the multicast addresses identify the group of all IPv6 nodes or IPv6
routers defined in RFC4291.
All Nodes Addresses: FF01::1, FF02::1.
All Router Addresses: FF01::2, FF02::2, FF05::2.
@param[in] Router If TRUE, generate all routers addresses,
else generate all node addresses.
@param[in] Scope interface-local(1), link-local(2), or site-local(5)
@param[out] Ip6Addr The generated multicast address.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@retval EFI_SUCCESS The address is generated.
**/
EFI_STATUS
Ip6SetToAllNodeMulticast (
IN BOOLEAN Router,
IN UINT8 Scope,
OUT EFI_IPv6_ADDRESS *Ip6Addr
);
/**
This function converts MAC address to 64 bits interface ID according to RFC4291
and returns the interface ID. Currently only 48-bit MAC address is supported by
this function.
@param[in, out] IpSb The IP6 service binding instance.
@retval NULL The operation fails.
@return Pointer to the generated interface ID.
**/
UINT8 *
Ip6CreateInterfaceID (
IN OUT IP6_SERVICE *IpSb
);
/**
This function creates link-local address from interface identifier. The
interface identifier is normally created from MAC address. It might be manually
configured by administrator if the link-local address created from MAC address
is a duplicate address.
@param[in, out] IpSb The IP6 service binding instance.
@retval NULL If the operation fails.
@return The generated Link Local address, in network order.
**/
EFI_IPv6_ADDRESS *
Ip6CreateLinkLocalAddr (
IN OUT IP6_SERVICE *IpSb
);
/**
Compute the solicited-node multicast address for an unicast or anycast address,
by taking the low-order 24 bits of this address, and appending those bits to
the prefix FF02:0:0:0:0:1:FF00::/104.
@param Ip6Addr The unicast or anycast address, in network order.
@param MulticastAddr The generated solicited-node multicast address,
in network order.
**/
VOID
Ip6CreateSNMulticastAddr (
IN EFI_IPv6_ADDRESS *Ip6Addr,
OUT EFI_IPv6_ADDRESS *MulticastAddr
);
/**
Check whether the incoming Ipv6 address is a solicited-node multicast address.
@param[in] Ip6 Ip6 address, in network order.
@retval TRUE Yes, solicited-node multicast address
@retval FALSE No
**/
BOOLEAN
Ip6IsSNMulticastAddr (
IN EFI_IPv6_ADDRESS *Ip6
);
/**
Check whether the incoming IPv6 address is one of the maintained address in
the IP6 service binding instance.
@param[in] IpSb Points to a IP6 service binding instance
@param[in] Address The IP6 address to be checked.
@param[out] Interface If not NULL, output the IP6 interface which
maintains the Address.
@param[out] AddressInfo If not NULL, output the IP6 address information
of the Address.
@retval TRUE Yes, it is one of the maintained addresses.
@retval FALSE No, it is not one of the maintained addresses.
**/
BOOLEAN
Ip6IsOneOfSetAddress (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Address,
OUT IP6_INTERFACE **Interface OPTIONAL,
OUT IP6_ADDRESS_INFO **AddressInfo OPTIONAL
);
/**
Check whether the incoming MAC address is valid.
@param[in] IpSb Points to a IP6 service binding instance.
@param[in] LinkAddress The MAC address.
@retval TRUE Yes, it is valid.
@retval FALSE No, it is not valid.
**/
BOOLEAN
Ip6IsValidLinkAddress (
IN IP6_SERVICE *IpSb,
IN EFI_MAC_ADDRESS *LinkAddress
);
/**
Copy the PrefixLength bits from Src to Dest.
@param[out] Dest A pointer to the buffer to copy to.
@param[in] Src A pointer to the buffer to copy from.
@param[in] PrefixLength The number of bits to copy.
**/
VOID
Ip6CopyAddressByPrefix (
OUT EFI_IPv6_ADDRESS *Dest,
IN EFI_IPv6_ADDRESS *Src,
IN UINT8 PrefixLength
);
/**
Insert a node IP6_ADDRESS_INFO to an IP6 interface.
@param[in, out] IpIf Points to an IP6 interface.
@param[in] AddrInfo Points to an IP6_ADDRESS_INFO.
**/
VOID
Ip6AddAddr (
IN OUT IP6_INTERFACE *IpIf,
IN IP6_ADDRESS_INFO *AddrInfo
);
/**
Remove the IPv6 address from the address list node points to IP6_ADDRESS_INFO.
This function removes the matching IPv6 addresses from the address list and
adjusts the address count of the address list. If IpSb is not NULL, this function
calls Ip6LeaveGroup to see whether it should call Mnp->Groups() to remove the
its solicited-node multicast MAC address from the filter list and sends out
a Multicast Listener Done. If Prefix is NULL, all address in the address list
will be removed. If Prefix is not NULL, the address that matching the Prefix
with PrefixLength in the address list will be removed.
@param[in] IpSb NULL or points to IP6 service binding instance.
@param[in, out] AddressList address list array
@param[in, out] AddressCount the count of addresses in address list array
@param[in] Prefix NULL or an IPv6 address prefix
@param[in] PrefixLength the length of Prefix
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_NOT_FOUND The address matching the Prefix with PrefixLength
cannot be found in address list.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
**/
EFI_STATUS
Ip6RemoveAddr (
IN IP6_SERVICE *IpSb OPTIONAL,
IN OUT LIST_ENTRY *AddressList,
IN OUT UINT32 *AddressCount,
IN EFI_IPv6_ADDRESS *Prefix OPTIONAL,
IN UINT8 PrefixLength
);
/**
Set the Ip6 variable data.
@param[in] IpSb Points to an IP6 service binding instance
@retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.
@retval other Set variable failed.
**/
EFI_STATUS
Ip6SetVariableData (
IN IP6_SERVICE *IpSb
);
/**
Clear the variable and free the resource.
@param[in] IpSb Ip6 service binding instance.
**/
VOID
Ip6ClearVariableData (
IN IP6_SERVICE *IpSb
);
/**
Get the MAC address for a multicast IP address. Call
Mnp's McastIpToMac to find the MAC address instead of
hard-coding 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 The multicast IP is successfully
translated to a multicast MAC address.
@retval Other The address is not converted because an error occurred.
**/
EFI_STATUS
Ip6GetMulticastMac (
IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
IN EFI_IPv6_ADDRESS *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, out] Head The IP head to convert.
@return Point to the converted IP head.
**/
EFI_IP6_HEADER *
Ip6NtohHead (
IN OUT EFI_IP6_HEADER *Head
);
#endif

View File

@@ -0,0 +1,170 @@
/** @file
VFR file used by the IP6 configuration component.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ip6NvData.h"
#define EFI_NETWORK_DEVICE_CLASS 0x04
formset
guid = IP6_CONFIG_NVDATA_GUID,
title = STRING_TOKEN(STR_IP6_CONFIG_FORM_TITLE),
help = STRING_TOKEN(STR_IP6_CONFIG_FORM_HELP),
class = EFI_NETWORK_DEVICE_CLASS,
subclass = 0x03,
varstore IP6_CONFIG_IFR_NVDATA,
name = IP6_CONFIG_IFR_NVDATA,
guid = IP6_CONFIG_NVDATA_GUID;
form formid = FORMID_MAIN_FORM,
title = STRING_TOKEN(STR_IP6_DEVICE_FORM_TITLE);
text
help = STRING_TOKEN(STR_IP6_INTERFACE_NAME_HELP),
text = STRING_TOKEN(STR_IP6_INTERFACE_NAME),
text = STRING_TOKEN(STR_IP6_INTERFACE_NAME_CONTENT);
text
help = STRING_TOKEN(STR_IP6_INTERFACE_TYPE_HELP),
text = STRING_TOKEN(STR_IP6_INTERFACE_TYPE),
text = STRING_TOKEN(STR_IP6_INTERFACE_TYPE_CONTENT);
text
help = STRING_TOKEN(STR_IP6_MAC_ADDRESS_HELP),
text = STRING_TOKEN(STR_IP6_MAC_ADDRESS),
text = STRING_TOKEN(STR_IP6_MAC_ADDRESS_CONTENT);
text
help = STRING_TOKEN(STR_IP6_HOST_ADDRESS_HELP),
text = STRING_TOKEN(STR_IP6_HOST_ADDRESS),
text = STRING_TOKEN(STR_NULL);
label HOST_ADDRESS_LABEL;
label LABEL_END;
text
help = STRING_TOKEN(STR_IP6_ROUTE_TABLE_HELP),
text = STRING_TOKEN(STR_IP6_ROUTE_TABLE),
text = STRING_TOKEN(STR_NULL);
label ROUTE_TABLE_LABEL;
label LABEL_END;
text
help = STRING_TOKEN(STR_IP6_GATEWAY_ADDRESS_HELP),
text = STRING_TOKEN(STR_IP6_GATEWAY_ADDRESS),
text = STRING_TOKEN(STR_NULL);
label GATEWAY_ADDRESS_LABEL;
label LABEL_END;
text
help = STRING_TOKEN(STR_IP6_DNS_ADDRESS_HELP),
text = STRING_TOKEN(STR_IP6_DNS_ADDRESS),
text = STRING_TOKEN(STR_NULL);
label DNS_ADDRESS_LABEL;
label LABEL_END;
string varid = IP6_CONFIG_IFR_NVDATA.InterfaceId,
prompt = STRING_TOKEN(STR_IP6_INTERFACE_ID),
help = STRING_TOKEN(STR_IP6_INTERFACE_ID_HELP),
flags = INTERACTIVE,
key = KEY_INTERFACE_ID,
minsize = INTERFACE_ID_STR_MIN_SIZE,
maxsize = INTERFACE_ID_STR_MAX_SIZE,
endstring;
numeric varid = IP6_CONFIG_IFR_NVDATA.DadTransmitCount,
prompt = STRING_TOKEN(STR_IP6_DAD_TRANSMIT_COUNT),
help = STRING_TOKEN(STR_IP6_DAD_TRANSMIT_COUNT_HELP),
flags = 0,
minimum = 0,
maximum = DAD_MAX_TRANSMIT_COUNT,
step = 0,
endnumeric;
oneof varid = IP6_CONFIG_IFR_NVDATA.Policy,
prompt = STRING_TOKEN(STR_POLICY_TYPE_PROMPT),
help = STRING_TOKEN(STR_POLICY_TYPE_HELP),
option text = STRING_TOKEN(STR_POLICY_TYPE_AUTO), value = IP6_POLICY_AUTO, flags = DEFAULT;
option text = STRING_TOKEN(STR_POLICY_TYPE_MANUAL), value = IP6_POLICY_MANUAL, flags = 0;
endoneof;
subtitle text = STRING_TOKEN(STR_NULL);
suppressif ideqval IP6_CONFIG_IFR_NVDATA.Policy == IP6_POLICY_AUTO;
goto FORMID_MANUAL_CONFIG_FORM,
prompt = STRING_TOKEN(STR_IP6_AD_CONFIG_FORM),
help = STRING_TOKEN(STR_IP6_AD_CONFIG_FORM_HELP),
flags = 0;
subtitle text = STRING_TOKEN(STR_NULL);
endif;
text
help = STRING_TOKEN (STR_SAVE_CHANGES_HELP),
text = STRING_TOKEN (STR_SAVE_CHANGES),
text = STRING_TOKEN (STR_NULL),
flags = INTERACTIVE,
key = KEY_SAVE_CHANGES;
endform;
form formid = FORMID_MANUAL_CONFIG_FORM,
title = STRING_TOKEN(STR_IP6_AD_CONFIG_FORM);
string varid = IP6_CONFIG_IFR_NVDATA.ManualAddress,
prompt = STRING_TOKEN(STR_IP6_MANUAL_ADDRESS),
help = STRING_TOKEN(STR_IP6_MANUAL_ADDRESS_HELP),
flags = INTERACTIVE,
key = KEY_MANUAL_ADDRESS,
minsize = ADDRESS_STR_MIN_SIZE,
maxsize = ADDRESS_STR_MAX_SIZE,
endstring;
string varid = IP6_CONFIG_IFR_NVDATA.GatewayAddress,
prompt = STRING_TOKEN(STR_IP6_NEW_GATEWAY_ADDRESS),
help = STRING_TOKEN(STR_IP6_NEW_GATEWAY_ADDR_HELP),
flags = INTERACTIVE,
key = KEY_GATEWAY_ADDRESS,
minsize = ADDRESS_STR_MIN_SIZE,
maxsize = ADDRESS_STR_MAX_SIZE,
endstring;
string varid = IP6_CONFIG_IFR_NVDATA.DnsAddress,
prompt = STRING_TOKEN(STR_IP6_NEW_DNS_ADDRESS),
help = STRING_TOKEN(STR_IP6_NEW_DNS_ADDRESS_HELP),
flags = INTERACTIVE,
key = KEY_DNS_ADDRESS,
minsize = ADDRESS_STR_MIN_SIZE,
maxsize = ADDRESS_STR_MAX_SIZE,
endstring;
goto FORMID_MAIN_FORM,
prompt = STRING_TOKEN (STR_SAVE_AND_EXIT),
help = STRING_TOKEN (STR_SAVE_AND_EXIT),
flags = INTERACTIVE,
key = KEY_SAVE_CONFIG_CHANGES;
goto FORMID_MAIN_FORM,
prompt = STRING_TOKEN (STR_NO_SAVE_AND_EXIT),
help = STRING_TOKEN (STR_NO_SAVE_AND_EXIT),
flags = INTERACTIVE,
key = KEY_IGNORE_CONFIG_CHANGES;
endform;
endformset;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,295 @@
/** @file
Definitions for EFI IPv6 Configuartion Protocol implementation.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __IP6_CONFIG_IMPL_H__
#define __IP6_CONFIG_IMPL_H__
#define IP6_CONFIG_INSTANCE_SIGNATURE SIGNATURE_32 ('I', 'P', '6', 'C')
#define IP6_FORM_CALLBACK_INFO_SIGNATURE SIGNATURE_32 ('I', 'F', 'C', 'I')
#define IP6_CONFIG_VARIABLE_ATTRIBUTE (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)
#define IP6_CONFIG_DEFAULT_DAD_XMITS 1
#define IP6_CONFIG_DHCP6_OPTION_ORO 6
#define IP6_CONFIG_DHCP6_OPTION_DNS_SERVERS 23
#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))
typedef struct _IP6_CONFIG_INSTANCE IP6_CONFIG_INSTANCE;
#define IP6_CONFIG_INSTANCE_FROM_PROTOCOL(Proto) \
CR ((Proto), \
IP6_CONFIG_INSTANCE, \
Ip6Config, \
IP6_CONFIG_INSTANCE_SIGNATURE \
)
#define IP6_CONFIG_INSTANCE_FROM_FORM_CALLBACK(Callback) \
CR ((Callback), \
IP6_CONFIG_INSTANCE, \
CallbackInfo, \
IP6_CONFIG_INSTANCE_SIGNATURE \
)
#define IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE(Instance) \
CR ((Instance), \
IP6_SERVICE, \
Ip6ConfigInstance, \
IP6_SERVICE_SIGNATURE \
)
#define IP6_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS(ConfigAccess) \
CR ((ConfigAccess), \
IP6_FORM_CALLBACK_INFO, \
HiiConfigAccess, \
IP6_FORM_CALLBACK_INFO_SIGNATURE \
)
/**
The prototype of work function for EfiIp6ConfigSetData().
@param[in] Instance The pointer to the IP6 config 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 IPv6
network stack was set successfully.
**/
typedef
EFI_STATUS
(*IP6_CONFIG_SET_DATA) (
IN IP6_CONFIG_INSTANCE *Instance,
IN UINTN DataSize,
IN VOID *Data
);
/**
The prototype of work function for EfiIp6ConfigGetData().
@param[in] Instance The pointer to the IP6 config 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
(*IP6_CONFIG_GET_DATA) (
IN IP6_CONFIG_INSTANCE *Instance,
IN OUT UINTN *DataSize,
IN VOID *Data OPTIONAL
);
typedef union {
VOID *Ptr;
EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo;
EFI_IP6_CONFIG_INTERFACE_ID *AltIfId;
EFI_IP6_CONFIG_POLICY *Policy;
EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS *DadXmits;
EFI_IP6_CONFIG_MANUAL_ADDRESS *ManualAddress;
EFI_IPv6_ADDRESS *Gateway;
EFI_IPv6_ADDRESS *DnsServers;
} IP6_CONFIG_DATA;
typedef struct {
IP6_CONFIG_SET_DATA SetData;
IP6_CONFIG_GET_DATA GetData;
EFI_STATUS Status;
UINT8 Attribute;
NET_MAP EventMap;
IP6_CONFIG_DATA Data;
UINTN DataSize;
} IP6_CONFIG_DATA_ITEM;
typedef struct {
UINT16 Offset;
UINTN DataSize;
EFI_IP6_CONFIG_DATA_TYPE DataType;
} IP6_CONFIG_DATA_RECORD;
#pragma pack(1)
//
// heap data that contains the data for each data record.
//
// BOOLEAN IsAltIfIdSet;
// EFI_IP6_CONFIG_POLICY Policy;
// EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;
// UINT32 ManualaddressCount;
// UINT32 GatewayCount;
// UINT32 DnsServersCount;
// EFI_IP6_CONFIG_INTERFACE_ID AltIfId;
// EFI_IP6_CONFIG_MANUAL_ADDRESS ManualAddress[];
// EFI_IPv6_ADDRESS Gateway[];
// EFI_IPv6_ADDRESS DnsServers[];
//
typedef struct {
UINT32 IaId;
UINT16 Checksum;
UINT16 DataRecordCount;
IP6_CONFIG_DATA_RECORD DataRecord[1];
} IP6_CONFIG_VARIABLE;
#pragma pack()
typedef struct {
LIST_ENTRY Link;
EFI_IP6_ADDRESS_INFO AddrInfo;
} IP6_ADDRESS_INFO_ENTRY;
typedef struct {
EFI_IP6_CONFIG_POLICY Policy; ///< manual or automatic
EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadTransmitCount; ///< dad transmits count
EFI_IP6_CONFIG_INTERFACE_ID InterfaceId; ///< alternative interface id
LIST_ENTRY ManualAddress; ///< IP addresses
UINT32 ManualAddressCount; ///< IP addresses count
LIST_ENTRY GatewayAddress; ///< Gateway address
UINT32 GatewayAddressCount; ///< Gateway address count
LIST_ENTRY DnsAddress; ///< DNS server address
UINT32 DnsAddressCount; ///< DNS server address count
} IP6_CONFIG_NVDATA;
typedef struct _IP6_FORM_CALLBACK_INFO {
UINT32 Signature;
EFI_HANDLE ChildHandle;
EFI_HII_CONFIG_ACCESS_PROTOCOL HiiConfigAccess;
EFI_DEVICE_PATH_PROTOCOL *HiiVendorDevicePath;
EFI_HII_HANDLE RegisteredHandle;
} IP6_FORM_CALLBACK_INFO;
struct _IP6_CONFIG_INSTANCE {
UINT32 Signature;
BOOLEAN Configured;
LIST_ENTRY Link;
UINT16 IfIndex;
EFI_IP6_CONFIG_INTERFACE_INFO InterfaceInfo;
EFI_IP6_CONFIG_INTERFACE_ID AltIfId;
EFI_IP6_CONFIG_POLICY Policy;
EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;
IP6_CONFIG_DATA_ITEM DataItem[Ip6ConfigDataTypeMaximum];
NET_MAP DadFailedMap;
NET_MAP DadPassedMap;
EFI_IP6_CONFIG_PROTOCOL Ip6Config;
EFI_EVENT Dhcp6SbNotifyEvent;
VOID *Registration;
EFI_HANDLE Dhcp6Handle;
EFI_DHCP6_PROTOCOL *Dhcp6;
BOOLEAN OtherInfoOnly;
UINT32 IaId;
EFI_EVENT Dhcp6Event;
UINT32 FailedIaAddressCount;
EFI_IPv6_ADDRESS *DeclineAddress;
UINT32 DeclineAddressCount;
IP6_FORM_CALLBACK_INFO CallbackInfo;
IP6_CONFIG_NVDATA Ip6NvData;
};
/**
The event process routine when the DHCPv6 server is answered with a reply packet
for an information request.
@param[in] This Points to the EFI_DHCP6_PROTOCOL.
@param[in] Context The pointer to the IP6 configuration instance data.
@param[in] Packet The DHCPv6 reply packet.
@retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.
@retval EFI_NOT_READY The reply packet does not contain the DNS server option, or
the DNS server address is not valid.
**/
EFI_STATUS
EFIAPI
Ip6ConfigOnDhcp6Reply (
IN EFI_DHCP6_PROTOCOL *This,
IN VOID *Context,
IN EFI_DHCP6_PACKET *Packet
);
/**
The work function to trigger the DHCPv6 process to perform a stateful autoconfiguration.
@param[in] Instance Pointer to the IP6 config instance data.
@param[in] OtherInfoOnly If FALSE, get stateful address and other information
via DHCPv6. Otherwise, only get the other information.
@retval EFI_SUCCESS The operation finished successfully.
@retval EFI_UNSUPPORTED The DHCP6 driver is not available.
**/
EFI_STATUS
Ip6ConfigStartStatefulAutoConfig (
IN IP6_CONFIG_INSTANCE *Instance,
IN BOOLEAN OtherInfoOnly
);
/**
Initialize an IP6_CONFIG_INSTANCE.
@param[out] Instance The buffer of IP6_CONFIG_INSTANCE to be initialized.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
@retval EFI_SUCCESS The IP6_CONFIG_INSTANCE initialized successfully.
**/
EFI_STATUS
Ip6ConfigInitInstance (
OUT IP6_CONFIG_INSTANCE *Instance
);
/**
Release an IP6_CONFIG_INSTANCE.
@param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.
**/
VOID
Ip6ConfigCleanInstance (
IN OUT IP6_CONFIG_INSTANCE *Instance
);
/**
Destory the Dhcp6 child in IP6_CONFIG_INSTANCE and release the resources.
@param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.
@retval EFI_SUCCESS The child was successfully destroyed.
@retval Others Failed to destory the child.
**/
EFI_STATUS
Ip6ConfigDestroyDhcp6 (
IN OUT IP6_CONFIG_INSTANCE *Instance
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
/** @file
The header file of Ip6ConfigNv.c.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _IP6_CONFIGNV_H_
#define _IP6_CONFIGNV_H_
#include "Ip6NvData.h"
#include "Ip6ConfigImpl.h"
extern UINT8 Ip6ConfigBin[];
extern UINT8 Ip6DxeStrings[];
#define IP6_HII_VENDOR_DEVICE_PATH_GUID \
{ \
0x13288098, 0xb11f, 0x45b9, { 0xbc, 0x4f, 0x91, 0xb5, 0x4b, 0xa3, 0x39, 0xb9 } \
}
#define IP6_ETHERNET L"Ethernet"
#define IP6_EXPERIMENTAL_ETHERNET L"Experimental Ethernet"
#define IP6_ADDRESS_DELIMITER L' '
#define IP6_LINK_LOCAL_PREFIX L"FE80::"
typedef enum {
Ip6InterfaceTypeEthernet = 1,
Ip6InterfaceTypeExperimentalEthernet
} IP6_INTERFACE_TYPE;
typedef enum {
Ip6ConfigNvHostAddress,
Ip6ConfigNvGatewayAddress,
Ip6ConfigNvDnsAddress,
Ip6ConfigNvRouteTable
} IP6_CONFIG_NV_ADDRESS_TYPE;
/**
Install HII Config Access protocol for network device and allocate resources.
@param[in, out] Instance The IP6_CONFIG_INSTANCE to create a form.
@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
Ip6ConfigFormInit (
IN OUT IP6_CONFIG_INSTANCE *Instance
);
/**
Uninstall HII Config Access protocol for network device and free resource.
@param[in, out] Instance The IP6_CONFIG_INSTANCE to unload a form.
**/
VOID
Ip6ConfigFormUnload (
IN OUT IP6_CONFIG_INSTANCE *Instance
);
#endif

View File

@@ -0,0 +1,930 @@
/** @file
The driver binding and service binding protocol for IP6 driver.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ip6Impl.h"
EFI_DRIVER_BINDING_PROTOCOL gIp6DriverBinding = {
Ip6DriverBindingSupported,
Ip6DriverBindingStart,
Ip6DriverBindingStop,
0xa,
NULL,
NULL
};
/**
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 IP6 driver which installs 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
Ip6DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gIp6DriverBinding,
ImageHandle,
&gIp6ComponentName,
&gIp6ComponentName2
);
}
/**
Test to see if this driver supports ControllerHandle.
@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
Ip6DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
//
// Test for the MNP service binding Protocol
//
return gBS->OpenProtocol (
ControllerHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
}
/**
Clean up an IP6 service binding instance. It releases all
the resource allocated by the instance. The instance may be
partly initialized, or partly destroyed. If a resource is
destroyed, it is marked as that in case the destory failed and
being called again later.
@param[in] IpSb The IP6 service binding instance to clean up.
@retval EFI_SUCCESS The resource used by the instance are cleaned up.
@retval Others Failed to clean up some of the resources.
**/
EFI_STATUS
Ip6CleanService (
IN IP6_SERVICE *IpSb
)
{
EFI_STATUS Status;
EFI_IPv6_ADDRESS AllNodes;
IP6_NEIGHBOR_ENTRY *NeighborCache;
Ip6ConfigCleanInstance (&IpSb->Ip6ConfigInstance);
//
// Leave link-scope all-nodes multicast address (FF02::1)
//
Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &AllNodes);
Status = Ip6LeaveGroup (IpSb, &AllNodes);
if (EFI_ERROR (Status)) {
return Status;
}
if (IpSb->DefaultInterface != NULL) {
Ip6CleanInterface (IpSb->DefaultInterface, NULL);
IpSb->DefaultInterface = NULL;
}
Ip6CleanDefaultRouterList (IpSb);
Ip6CleanPrefixListTable (IpSb, &IpSb->OnlinkPrefix);
Ip6CleanPrefixListTable (IpSb, &IpSb->AutonomousPrefix);
if (IpSb->RouteTable != NULL) {
Ip6CleanRouteTable (IpSb->RouteTable);
IpSb->RouteTable = NULL;
}
if (IpSb->InterfaceId != NULL) {
FreePool (IpSb->InterfaceId);
}
IpSb->InterfaceId = NULL;
Ip6CleanAssembleTable (&IpSb->Assemble);
if (IpSb->MnpChildHandle != NULL) {
if (IpSb->Mnp != NULL) {
IpSb->Mnp->Cancel (IpSb->Mnp, NULL);
IpSb->Mnp->Configure (IpSb->Mnp, NULL);
gBS->CloseProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
IpSb->Image,
IpSb->Controller
);
IpSb->Mnp = NULL;
}
NetLibDestroyServiceChild (
IpSb->Controller,
IpSb->Image,
&gEfiManagedNetworkServiceBindingProtocolGuid,
IpSb->MnpChildHandle
);
IpSb->MnpChildHandle = NULL;
}
if (IpSb->RecvRequest.MnpToken.Event != NULL) {
gBS->CloseEvent (IpSb->RecvRequest.MnpToken.Event);
}
if (IpSb->Timer != NULL) {
gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
gBS->CloseEvent (IpSb->Timer);
IpSb->Timer = NULL;
}
if (IpSb->FasterTimer != NULL) {
gBS->SetTimer (IpSb->FasterTimer, TimerCancel, 0);
gBS->CloseEvent (IpSb->FasterTimer);
IpSb->FasterTimer = NULL;
}
//
// Free the Neighbor Discovery resources
//
while (!IsListEmpty (&IpSb->NeighborTable)) {
NeighborCache = NET_LIST_HEAD (&IpSb->NeighborTable, IP6_NEIGHBOR_ENTRY, Link);
Ip6FreeNeighborEntry (IpSb, NeighborCache, FALSE, TRUE, EFI_SUCCESS, NULL, NULL);
}
return EFI_SUCCESS;
}
/**
Create a new IP6 driver service binding protocol.
@param[in] Controller The controller that has MNP service binding
installed.
@param[in] ImageHandle The IP6 driver's image handle.
@param[out] Service The variable to receive the newly created IP6
service.
@retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
@retval EFI_SUCCESS A new IP6 service binding private is created.
**/
EFI_STATUS
Ip6CreateService (
IN EFI_HANDLE Controller,
IN EFI_HANDLE ImageHandle,
OUT IP6_SERVICE **Service
)
{
IP6_SERVICE *IpSb;
EFI_STATUS Status;
EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
EFI_MANAGED_NETWORK_CONFIG_DATA *Config;
IP6_CONFIG_DATA_ITEM *DataItem;
ASSERT (Service != NULL);
*Service = NULL;
//
// allocate a service private data then initialize all the filed to
// empty resources, so if any thing goes wrong when allocating
// resources, Ip6CleanService can be called to clean it up.
//
IpSb = AllocateZeroPool (sizeof (IP6_SERVICE));
if (IpSb == NULL) {
return EFI_OUT_OF_RESOURCES;
}
IpSb->Signature = IP6_SERVICE_SIGNATURE;
IpSb->ServiceBinding.CreateChild = Ip6ServiceBindingCreateChild;
IpSb->ServiceBinding.DestroyChild = Ip6ServiceBindingDestroyChild;
IpSb->State = IP6_SERVICE_UNSTARTED;
IpSb->InDestroy = FALSE;
IpSb->NumChildren = 0;
InitializeListHead (&IpSb->Children);
InitializeListHead (&IpSb->Interfaces);
IpSb->DefaultInterface = NULL;
IpSb->RouteTable = NULL;
IpSb->RecvRequest.Signature = IP6_LINK_RX_SIGNATURE;
IpSb->RecvRequest.CallBack = NULL;
IpSb->RecvRequest.Context = NULL;
MnpToken = &IpSb->RecvRequest.MnpToken;
MnpToken->Event = NULL;
MnpToken->Status = EFI_NOT_READY;
MnpToken->Packet.RxData = NULL;
Ip6CreateAssembleTable (&IpSb->Assemble);
IpSb->MldCtrl.Mldv1QuerySeen = 0;
InitializeListHead (&IpSb->MldCtrl.Groups);
ZeroMem (&IpSb->LinkLocalAddr, sizeof (EFI_IPv6_ADDRESS));
IpSb->LinkLocalOk = FALSE;
IpSb->LinkLocalDadFail = FALSE;
IpSb->Dhcp6NeedStart = FALSE;
IpSb->Dhcp6NeedInfoRequest = FALSE;
IpSb->CurHopLimit = IP6_HOP_LIMIT;
IpSb->LinkMTU = IP6_MIN_LINK_MTU;
IpSb->BaseReachableTime = IP6_REACHABLE_TIME;
Ip6UpdateReachableTime (IpSb);
//
// RFC4861 RETRANS_TIMER: 1,000 milliseconds
//
IpSb->RetransTimer = IP6_RETRANS_TIMER;
IpSb->RoundRobin = 0;
InitializeListHead (&IpSb->NeighborTable);
InitializeListHead (&IpSb->DefaultRouterList);
InitializeListHead (&IpSb->OnlinkPrefix);
InitializeListHead (&IpSb->AutonomousPrefix);
IpSb->InterfaceIdLen = IP6_IF_ID_LEN;
IpSb->InterfaceId = NULL;
IpSb->RouterAdvertiseReceived = FALSE;
IpSb->SolicitTimer = IP6_MAX_RTR_SOLICITATIONS;
IpSb->Ticks = 0;
IpSb->Image = ImageHandle;
IpSb->Controller = Controller;
IpSb->MnpChildHandle = NULL;
IpSb->Mnp = NULL;
Config = &IpSb->MnpConfigData;
Config->ReceivedQueueTimeoutValue = 0;
Config->TransmitQueueTimeoutValue = 0;
Config->ProtocolTypeFilter = IP6_ETHER_PROTO;
Config->EnableUnicastReceive = TRUE;
Config->EnableMulticastReceive = TRUE;
Config->EnableBroadcastReceive = TRUE;
Config->EnablePromiscuousReceive = FALSE;
Config->FlushQueuesOnReset = TRUE;
Config->EnableReceiveTimestamps = FALSE;
Config->DisableBackgroundPolling = FALSE;
ZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));
IpSb->Timer = NULL;
IpSb->FasterTimer = NULL;
ZeroMem (&IpSb->Ip6ConfigInstance, sizeof (IP6_CONFIG_INSTANCE));
IpSb->MacString = NULL;
//
// Create various resources. First create the route table, timer
// event, MNP token event and MNP child.
//
IpSb->RouteTable = Ip6CreateRouteTable ();
if (IpSb->RouteTable == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL | EVT_TIMER,
TPL_CALLBACK,
Ip6TimerTicking,
IpSb,
&IpSb->Timer
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL | EVT_TIMER,
TPL_CALLBACK,
Ip6NdFasterTimerTicking,
IpSb,
&IpSb->FasterTimer
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = NetLibCreateServiceChild (
Controller,
ImageHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
&IpSb->MnpChildHandle
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = gBS->OpenProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
(VOID **) (&IpSb->Mnp),
ImageHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip6ServiceConfigMnp (IpSb, TRUE);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
IpSb->MaxPacketSize = IP6_MIN_LINK_MTU - sizeof (EFI_IP6_HEADER);
if (NetLibGetVlanId (IpSb->Controller) != 0) {
//
// This is a VLAN device, reduce MTU by VLAN tag length
//
IpSb->MaxPacketSize -= NET_VLAN_TAG_LEN;
}
IpSb->OldMaxPacketSize = IpSb->MaxPacketSize;
//
// Currently only ETHERNET is supported in IPv6 stack, since
// link local address requires an IEEE 802 48-bit MACs for
// EUI-64 format interface identifier mapping.
//
if (IpSb->SnpMode.IfType != NET_IFTYPE_ETHERNET) {
Status = EFI_UNSUPPORTED;
goto ON_ERROR;
}
Status = Ip6InitMld (IpSb);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
//
// The timer expires every 100 (IP6_TIMER_INTERVAL_IN_MS) milliseconds.
//
Status = gBS->SetTimer (IpSb->FasterTimer, TimerPeriodic, TICKS_PER_MS * IP6_TIMER_INTERVAL_IN_MS);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
//
// The timer expires every 1000 (IP6_ONE_SECOND_IN_MS) milliseconds.
//
Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_MS * IP6_ONE_SECOND_IN_MS);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
Ip6OnFrameReceived,
&IpSb->RecvRequest,
&MnpToken->Event
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip6ReceiveFrame (Ip6AcceptFrame, IpSb);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &IpSb->MacString);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip6ConfigInitInstance (&IpSb->Ip6ConfigInstance);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
IpSb->DefaultInterface = Ip6CreateInterface (IpSb, TRUE);
if (IpSb->DefaultInterface == NULL) {
Status = EFI_DEVICE_ERROR;
goto ON_ERROR;
}
//
// If there is any manual address, set it.
//
DataItem = &IpSb->Ip6ConfigInstance.DataItem[Ip6ConfigDataTypeManualAddress];
if (DataItem->Data.Ptr != NULL) {
DataItem->SetData (
&IpSb->Ip6ConfigInstance,
DataItem->DataSize,
DataItem->Data.Ptr
);
}
InsertHeadList (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);
*Service = IpSb;
return EFI_SUCCESS;
ON_ERROR:
Ip6CleanService (IpSb);
FreePool (IpSb);
return Status;
}
/**
Start this driver on ControllerHandle.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to bind driver to.
@param[in] RemainingDevicePath Optional parameter used to pick a specific child
device to start.
@retval EFI_SUCCES This driver is added to ControllerHandle.
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
@retval other This driver does not support this device.
**/
EFI_STATUS
EFIAPI
Ip6DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
IP6_SERVICE *IpSb;
EFI_STATUS Status;
//
// Test for the Ip6 service binding protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp6ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (Status == EFI_SUCCESS) {
return EFI_ALREADY_STARTED;
}
Status = Ip6CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (IpSb != NULL);
//
// Install the Ip6ServiceBinding Protocol onto ControlerHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiIp6ServiceBindingProtocolGuid,
&IpSb->ServiceBinding,
&gEfiIp6ConfigProtocolGuid,
&IpSb->Ip6ConfigInstance.Ip6Config,
NULL
);
if (EFI_ERROR (Status)) {
Ip6CleanService (IpSb);
FreePool (IpSb);
} else {
//
// Initialize the IP6 ID
//
mIp6Id = NET_RANDOM (NetRandomInitSeed ());
Ip6SetVariableData (IpSb);
}
return Status;
}
/**
Stop this driver on ControllerHandle.
@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 An array of child handles to be freed. May be NULL
if NumberOfChildren is 0.
@retval EFI_SUCCESS The device was stopped.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
**/
EFI_STATUS
EFIAPI
Ip6DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
)
{
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
IP6_SERVICE *IpSb;
IP6_PROTOCOL *IpInstance;
EFI_HANDLE NicHandle;
EFI_STATUS Status;
BOOLEAN IsDhcp6;
EFI_TPL OldTpl;
INTN State;
IsDhcp6 = FALSE;
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);
if (NicHandle != NULL) {
//
// DriverBindingStop is triggered by the uninstallation of the EFI DHCPv6
// Protocol used by Ip6Config.
//
IsDhcp6 = TRUE;
} else {
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
if (NicHandle == NULL) {
return EFI_DEVICE_ERROR;
}
}
Status = gBS->OpenProtocol (
NicHandle,
&gEfiIp6ServiceBindingProtocolGuid,
(VOID **) &ServiceBinding,
This->DriverBindingHandle,
NicHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
IpSb = IP6_SERVICE_FROM_PROTOCOL (ServiceBinding);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
if (IpSb->InDestroy) {
Status = EFI_SUCCESS;
goto Exit;
}
if (IsDhcp6) {
Status = Ip6ConfigDestroyDhcp6 (&IpSb->Ip6ConfigInstance);
gBS->CloseEvent (IpSb->Ip6ConfigInstance.Dhcp6Event);
IpSb->Ip6ConfigInstance.Dhcp6Event = NULL;
} else if (NumberOfChildren == 0) {
IpSb->InDestroy = TRUE;
State = IpSb->State;
IpSb->State = IP6_SERVICE_DESTROY;
//
// Clear the variable data.
//
Ip6ClearVariableData (IpSb);
Status = Ip6CleanService (IpSb);
if (EFI_ERROR (Status)) {
IpSb->State = State;
goto Exit;
}
Status = gBS->UninstallMultipleProtocolInterfaces (
NicHandle,
&gEfiIp6ServiceBindingProtocolGuid,
ServiceBinding,
&gEfiIp6ConfigProtocolGuid,
&IpSb->Ip6ConfigInstance.Ip6Config,
NULL
);
ASSERT_EFI_ERROR (Status);
FreePool (IpSb);
} else {
//
// NumberOfChildren is not zero, destroy all IP6 children instances.
//
while (!IsListEmpty (&IpSb->Children)) {
IpInstance = NET_LIST_HEAD (&IpSb->Children, IP6_PROTOCOL, Link);
ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);
}
if (IpSb->NumChildren != 0) {
Status = EFI_DEVICE_ERROR;
}
}
Exit:
gBS->RestoreTPL (OldTpl);
return Status;
}
/**
Creates a child handle with a set of I/O services.
@param[in] This Protocol instance pointer.
@param[in] ChildHandle Pointer to the handle of the child to create. If
it is NULL, then a new handle is created. If it
is not NULL, then the I/O services are added to
the existing child handle.
@retval EFI_SUCCES The child handle was created with the I/O services.
@retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
the child.
@retval other The child handle was not created.
**/
EFI_STATUS
EFIAPI
Ip6ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
)
{
IP6_SERVICE *IpSb;
IP6_PROTOCOL *IpInstance;
EFI_TPL OldTpl;
EFI_STATUS Status;
VOID *Mnp;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
IpSb = IP6_SERVICE_FROM_PROTOCOL (This);
if (IpSb->LinkLocalDadFail) {
return EFI_DEVICE_ERROR;
}
IpInstance = AllocatePool (sizeof (IP6_PROTOCOL));
if (IpInstance == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Ip6InitProtocol (IpSb, IpInstance);
//
// Install Ip6 onto ChildHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiIp6ProtocolGuid,
&IpInstance->Ip6Proto,
NULL
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
IpInstance->Handle = *ChildHandle;
//
// Open the Managed Network protocol BY_CHILD.
//
Status = gBS->OpenProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
(VOID **) &Mnp,
gIp6DriverBinding.DriverBindingHandle,
IpInstance->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
gBS->UninstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiIp6ProtocolGuid,
&IpInstance->Ip6Proto,
NULL
);
goto ON_ERROR;
}
//
// Insert it into the service binding instance.
//
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&IpSb->Children, &IpInstance->Link);
IpSb->NumChildren++;
gBS->RestoreTPL (OldTpl);
ON_ERROR:
if (EFI_ERROR (Status)) {
Ip6CleanProtocol (IpInstance);
FreePool (IpInstance);
}
return Status;
}
/**
Destroys a child handle with a set of I/O services.
@param[in] This Protocol instance pointer.
@param[in] ChildHandle Handle of the child to destroy.
@retval EFI_SUCCES The I/O services were removed from the child
handle.
@retval EFI_UNSUPPORTED The child handle does not support the I/O services
that are being removed.
@retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
@retval EFI_ACCESS_DENIED The child handle could not be destroyed because
its I/O services are being used.
@retval other The child handle was not destroyed.
**/
EFI_STATUS
EFIAPI
Ip6ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
EFI_STATUS Status;
IP6_SERVICE *IpSb;
IP6_PROTOCOL *IpInstance;
EFI_IP6_PROTOCOL *Ip6;
EFI_TPL OldTpl;
INTN State;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Retrieve the private context data structures
//
IpSb = IP6_SERVICE_FROM_PROTOCOL (This);
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiIp6ProtocolGuid,
(VOID **) &Ip6,
gIp6DriverBinding.DriverBindingHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
IpInstance = IP6_INSTANCE_FROM_PROTOCOL (Ip6);
if (IpInstance->Service != IpSb) {
return EFI_INVALID_PARAMETER;
}
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
//
// A child can be destroyed more than once. For example,
// Ip6DriverBindingStop will destory all of its children.
// when UDP driver is being stopped, it will destory all
// the IP child it opens.
//
if (IpInstance->State == IP6_STATE_DESTROY) {
gBS->RestoreTPL (OldTpl);
return EFI_SUCCESS;
}
State = IpInstance->State;
IpInstance->State = IP6_STATE_DESTROY;
//
// Close the Managed Network protocol.
//
gBS->CloseProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
gIp6DriverBinding.DriverBindingHandle,
ChildHandle
);
//
// Uninstall the IP6 protocol first. Many thing happens during
// this:
// 1. The consumer of the IP6 protocol will be stopped if it
// opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
// stopped, IP driver's stop function will be called, and uninstall
// EFI_IP6_PROTOCOL will trigger the UDP's stop function. This
// makes it possible to create the network stack bottom up, and
// stop it top down.
// 2. the upper layer will recycle the received packet. The recycle
// event's TPL is higher than this function. The recycle events
// will be called back before preceeding. If any packets not recycled,
// that means there is a resource leak.
//
Status = gBS->UninstallProtocolInterface (
ChildHandle,
&gEfiIp6ProtocolGuid,
&IpInstance->Ip6Proto
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip6CleanProtocol (IpInstance);
Ip6SetVariableData (IpSb);
if (EFI_ERROR (Status)) {
gBS->InstallMultipleProtocolInterfaces (
&ChildHandle,
&gEfiIp6ProtocolGuid,
Ip6,
NULL
);
goto ON_ERROR;
}
RemoveEntryList (&IpInstance->Link);
ASSERT (IpSb->NumChildren > 0);
IpSb->NumChildren--;
gBS->RestoreTPL (OldTpl);
FreePool (IpInstance);
return EFI_SUCCESS;
ON_ERROR:
IpInstance->State = State;
gBS->RestoreTPL (OldTpl);
return Status;
}

View File

@@ -0,0 +1,185 @@
/** @file
The driver binding and service binding protocol for IP6 driver.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_DRIVER_H__
#define __EFI_IP6_DRIVER_H__
extern EFI_DRIVER_BINDING_PROTOCOL gIp6DriverBinding;
extern EFI_COMPONENT_NAME_PROTOCOL gIp6ComponentName;
extern EFI_COMPONENT_NAME2_PROTOCOL gIp6ComponentName2;
/**
Clean up an IP6 service binding instance. It releases all
the resource allocated by the instance. The instance may be
partly initialized, or partly destroyed. If a resource is
destroyed, it is marked as that in case the destory failed and
being called again later.
@param[in] IpSb The IP6 service binding instance to clean up.
@retval EFI_SUCCESS The resource used by the instance are cleaned up.
@retval Others Failed to clean up some of the resources.
**/
EFI_STATUS
Ip6CleanService (
IN IP6_SERVICE *IpSb
);
//
// 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 IP6 driver which installs 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
Ip6DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
//
// Function prototypes for the Drivr Binding Protocol
//
/**
Test to see if this driver supports ControllerHandle.
@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
Ip6DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
/**
Start this driver on ControllerHandle.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to bind driver to.
@param[in] RemainingDevicePath Optional parameter used to pick a specific child
device to start.
@retval EFI_SUCCES This driver is added to ControllerHandle.
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
@retval other This driver does not support this device.
**/
EFI_STATUS
EFIAPI
Ip6DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
/**
Stop this driver on ControllerHandle.
@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 An array of child handles to be freed. May be NULL
if NumberOfChildren is 0.
@retval EFI_SUCCESS The device was stopped.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
**/
EFI_STATUS
EFIAPI
Ip6DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
);
//
// Function ptototypes for the ServiceBinding Prococol
//
/**
Creates a child handle with a set of I/O services.
@param[in] This Protocol instance pointer.
@param[in] ChildHandle Pointer to the handle of the child to create. If
it is NULL, then a new handle is created. If it
is not NULL, then the I/O services are added to
the existing child handle.
@retval EFI_SUCCES The child handle was created with the I/O services.
@retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
the child.
@retval other The child handle was not created.
**/
EFI_STATUS
EFIAPI
Ip6ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
);
/**
Destroys a child handle with a set of I/O services.
@param[in] This Protocol instance pointer.
@param[in] ChildHandle Handle of the child to destroy.
@retval EFI_SUCCES The I/O services were removed from the child
handle.
@retval EFI_UNSUPPORTED The child handle does not support the I/O services
that are being removed.
@retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
@retval EFI_ACCESS_DENIED The child handle could not be destroyed because
its I/O services are being used.
@retval other The child handle was not destroyed.
**/
EFI_STATUS
EFIAPI
Ip6ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
);
#endif

View File

@@ -0,0 +1,100 @@
## @file
# Component description file for Ip6 module.
#
# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Ip6Dxe
FILE_GUID = 5BEDB5CC-D830-4eb2-8742-2D4CC9B54F2C
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = Ip6DriverEntryPoint
UNLOAD_IMAGE = NetLibDefaultUnload
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
# DRIVER_BINDING = gIp6DriverBinding
# COMPONENT_NAME = gIp6ComponentName
# COMPONENT_NAME2 = gIp6ComponentName2
#
[Sources]
Ip6Output.h
Ip6Option.h
Ip6Input.h
Ip6Nd.h
Ip6Mld.h
Ip6Impl.c
Ip6Driver.c
ComponentName.c
Ip6Nd.c
Ip6Input.c
Ip6ConfigImpl.c
Ip6ConfigImpl.h
Ip6Impl.h
Ip6Option.c
Ip6If.h
Ip6Icmp.h
Ip6Mld.c
Ip6Common.c
Ip6Route.c
Ip6If.c
Ip6Driver.h
Ip6Output.c
Ip6Icmp.c
Ip6Common.h
Ip6Route.h
Ip6DxeStrings.uni
Ip6NvData.h
Ip6ConfigNv.c
Ip6ConfigNv.h
Ip6Config.vfr
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
DevicePathLib
HiiLib
UefiHiiServicesLib
PrintLib
MemoryAllocationLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
UefiLib
DebugLib
NetLib
DpcLib
[Protocols]
gEfiManagedNetworkServiceBindingProtocolGuid
gEfiManagedNetworkProtocolGuid
gEfiIp6ServiceBindingProtocolGuid
gEfiIp6ProtocolGuid
gEfiIp6ConfigProtocolGuid
gEfiDhcp6ServiceBindingProtocolGuid
gEfiDhcp6ProtocolGuid
gEfiIpSecProtocolGuid
gEfiHiiConfigAccessProtocolGuid
[Guids]
gEfiIfrTianoGuid ## CONSUMES ## GUID

Binary file not shown.

684
NetworkPkg/Ip6Dxe/Ip6Icmp.c Normal file
View File

@@ -0,0 +1,684 @@
/** @file
The ICMPv6 handle routines to process the ICMPv6 control messages.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ip6Impl.h"
EFI_IP6_ICMP_TYPE mIp6SupportedIcmp[23] = {
{
ICMP_V6_DEST_UNREACHABLE,
ICMP_V6_NO_ROUTE_TO_DEST
},
{
ICMP_V6_DEST_UNREACHABLE,
ICMP_V6_COMM_PROHIBITED
},
{
ICMP_V6_DEST_UNREACHABLE,
ICMP_V6_BEYOND_SCOPE
},
{
ICMP_V6_DEST_UNREACHABLE,
ICMP_V6_ADDR_UNREACHABLE
},
{
ICMP_V6_DEST_UNREACHABLE,
ICMP_V6_PORT_UNREACHABLE
},
{
ICMP_V6_DEST_UNREACHABLE,
ICMP_V6_SOURCE_ADDR_FAILED
},
{
ICMP_V6_DEST_UNREACHABLE,
ICMP_V6_ROUTE_REJECTED
},
{
ICMP_V6_PACKET_TOO_BIG,
ICMP_V6_DEFAULT_CODE
},
{
ICMP_V6_TIME_EXCEEDED,
ICMP_V6_TIMEOUT_HOP_LIMIT
},
{
ICMP_V6_TIME_EXCEEDED,
ICMP_V6_TIMEOUT_REASSEMBLE
},
{
ICMP_V6_PARAMETER_PROBLEM,
ICMP_V6_ERRONEOUS_HEADER
},
{
ICMP_V6_PARAMETER_PROBLEM,
ICMP_V6_UNRECOGNIZE_NEXT_HDR
},
{
ICMP_V6_PARAMETER_PROBLEM,
ICMP_V6_UNRECOGNIZE_OPTION
},
{
ICMP_V6_ECHO_REQUEST,
ICMP_V6_DEFAULT_CODE
},
{
ICMP_V6_ECHO_REPLY,
ICMP_V6_DEFAULT_CODE
},
{
ICMP_V6_LISTENER_QUERY,
ICMP_V6_DEFAULT_CODE
},
{
ICMP_V6_LISTENER_REPORT,
ICMP_V6_DEFAULT_CODE
},
{
ICMP_V6_LISTENER_REPORT_2,
ICMP_V6_DEFAULT_CODE
},
{
ICMP_V6_LISTENER_DONE,
ICMP_V6_DEFAULT_CODE
},
{
ICMP_V6_ROUTER_SOLICIT,
ICMP_V6_DEFAULT_CODE
},
{
ICMP_V6_ROUTER_ADVERTISE,
ICMP_V6_DEFAULT_CODE
},
{
ICMP_V6_NEIGHBOR_SOLICIT,
ICMP_V6_DEFAULT_CODE
},
{
ICMP_V6_NEIGHBOR_ADVERTISE,
ICMP_V6_DEFAULT_CODE
},
};
/**
Reply an ICMPv6 echo request.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the ICMPv6 informational message.
@param[in] Packet The content of the ICMPv6 message with the IP head
removed.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
@retval EFI_SUCCESS Successfully answered the ICMPv6 Echo request.
@retval Others Failed to answer the ICMPv6 Echo request.
**/
EFI_STATUS
Ip6IcmpReplyEcho (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
)
{
IP6_ICMP_INFORMATION_HEAD *Icmp;
NET_BUF *Data;
EFI_STATUS Status;
EFI_IP6_HEADER ReplyHead;
Status = EFI_OUT_OF_RESOURCES;
//
// make a copy the packet, it is really a bad idea to
// send the MNP's buffer back to MNP.
//
Data = NetbufDuplicate (Packet, NULL, IP6_MAX_HEADLEN);
if (Data == NULL) {
goto 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 = (IP6_ICMP_INFORMATION_HEAD *) NetbufGetByte (Data, 0, NULL);
if (Icmp == NULL) {
NetbufFree (Data);
goto Exit;
}
Icmp->Head.Type = ICMP_V6_ECHO_REPLY;
Icmp->Head.Checksum = 0;
//
// Generate the IPv6 basic header
// If the Echo Reply is a response to a Echo Request sent to one of the node's unicast address,
// the Source address of the Echo Reply must be the same address.
//
ZeroMem (&ReplyHead, sizeof (EFI_IP6_HEADER));
ReplyHead.PayloadLength = HTONS ((UINT16) (Packet->TotalSize));
ReplyHead.NextHeader = IP6_ICMP;
ReplyHead.HopLimit = IpSb->CurHopLimit;
IP6_COPY_ADDRESS (&ReplyHead.DestinationAddress, &Head->SourceAddress);
if (Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) {
IP6_COPY_ADDRESS (&ReplyHead.SourceAddress, &Head->DestinationAddress);
}
//
// If source is unspecified, Ip6Output will select a source for us
//
Status = Ip6Output (
IpSb,
NULL,
NULL,
Data,
&ReplyHead,
NULL,
0,
Ip6SysPacketSent,
NULL
);
Exit:
NetbufFree (Packet);
return Status;
}
/**
Process Packet Too Big message sent by a router in response to a packet that
it cannot forward because the packet is larger than the MTU of outgoing link.
Since this driver already uses IPv6 minimum link MTU as the maximum packet size,
if Packet Too Big message is still received, do not reduce the packet size, but
rather include a Fragment header in the subsequent packets.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the ICMPv6 error packet.
@param[in] Packet The content of the ICMPv6 error with the IP head
removed.
@retval EFI_SUCCESS The ICMPv6 error processed successfully.
@retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lack of
resource.
@retval EFI_NOT_FOUND The packet too big message is not sent to us.
**/
EFI_STATUS
Ip6ProcessPacketTooBig (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
)
{
IP6_ICMP_ERROR_HEAD Icmp;
UINT32 Mtu;
IP6_ROUTE_ENTRY *RouteEntry;
EFI_IPv6_ADDRESS *DestAddress;
NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
Mtu = NTOHL (Icmp.Fourth);
DestAddress = &Icmp.IpHead.DestinationAddress;
if (Mtu < IP6_MIN_LINK_MTU) {
//
// Normally the multicast address is considered to be on-link and not recorded
// in route table. Here it is added into the table since the MTU information
// need be recorded.
//
if (IP6_IS_MULTICAST (DestAddress)) {
RouteEntry = Ip6CreateRouteEntry (DestAddress, 128, NULL);
if (RouteEntry == NULL) {
NetbufFree (Packet);
return EFI_OUT_OF_RESOURCES;
}
RouteEntry->Flag = IP6_DIRECT_ROUTE | IP6_PACKET_TOO_BIG;
InsertHeadList (&IpSb->RouteTable->RouteArea[128], &RouteEntry->Link);
IpSb->RouteTable->TotalNum++;
} else {
RouteEntry = Ip6FindRouteEntry (IpSb->RouteTable, DestAddress, NULL);
if (RouteEntry == NULL) {
NetbufFree (Packet);
return EFI_NOT_FOUND;
}
RouteEntry->Flag = RouteEntry->Flag | IP6_PACKET_TOO_BIG;
Ip6FreeRouteEntry (RouteEntry);
}
}
NetbufFree (Packet);
return EFI_SUCCESS;
}
/**
Process the ICMPv6 error packet, and deliver the packet to upper layer.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the ICMPv6 error packet.
@param[in] Packet The content of the ICMPv6 error with the IP head
removed.
@retval EFI_SUCCESS The ICMPv6 error processed successfully.
@retval EFI_INVALID_PARAMETER The packet is invalid.
@retval Others Failed to process the packet.
**/
EFI_STATUS
Ip6ProcessIcmpError (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
)
{
IP6_ICMP_ERROR_HEAD Icmp;
//
// Check the validity of the packet
//
if (Packet->TotalSize < sizeof (Icmp)) {
goto DROP;
}
NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
if (Icmp.Head.Type == ICMP_V6_PACKET_TOO_BIG) {
return Ip6ProcessPacketTooBig (IpSb, Head, Packet);
}
//
// Notify the upper-layer process that an ICMPv6 eror message is received.
//
IP6_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;
return Ip6Demultiplex (IpSb, Head, Packet);
DROP:
NetbufFree (Packet);
Packet = NULL;
return EFI_INVALID_PARAMETER;
}
/**
Process the ICMPv6 informational messages. If it is an ICMPv6 echo
request, answer it. If it is a MLD message, trigger MLD routines to
process it. If it is a ND message, trigger ND routines to process it.
Otherwise, deliver it to upper layer.
@param[in] IpSb The IP service that receivd the packet.
@param[in] Head The IP head of the ICMPv6 informational packet.
@param[in] Packet The content of the ICMPv6 informational packet
with IP head removed.
@retval EFI_INVALID_PARAMETER The packet is invalid.
@retval EFI_SUCCESS The ICMPv6 informational message processed.
@retval Others Failed to process ICMPv6 informational message.
**/
EFI_STATUS
Ip6ProcessIcmpInformation (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
)
{
IP6_ICMP_INFORMATION_HEAD Icmp;
EFI_STATUS Status;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE);
ASSERT (Head != NULL);
NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
Status = EFI_INVALID_PARAMETER;
switch (Icmp.Head.Type) {
case ICMP_V6_ECHO_REQUEST:
//
// If ICMPv6 echo, reply it
//
if (Icmp.Head.Code == 0) {
Status = Ip6IcmpReplyEcho (IpSb, Head, Packet);
}
break;
case ICMP_V6_LISTENER_QUERY:
Status = Ip6ProcessMldQuery (IpSb, Head, Packet);
break;
case ICMP_V6_LISTENER_REPORT:
case ICMP_V6_LISTENER_REPORT_2:
Status = Ip6ProcessMldReport (IpSb, Head, Packet);
break;
case ICMP_V6_NEIGHBOR_SOLICIT:
Status = Ip6ProcessNeighborSolicit (IpSb, Head, Packet);
break;
case ICMP_V6_NEIGHBOR_ADVERTISE:
Status = Ip6ProcessNeighborAdvertise (IpSb, Head, Packet);
break;
case ICMP_V6_ROUTER_ADVERTISE:
Status = Ip6ProcessRouterAdvertise (IpSb, Head, Packet);
break;
case ICMP_V6_REDIRECT:
Status = Ip6ProcessRedirect (IpSb, Head, Packet);
break;
case ICMP_V6_ECHO_REPLY:
Status = Ip6Demultiplex (IpSb, Head, Packet);
break;
default:
Status = EFI_INVALID_PARAMETER;
break;
}
return Status;
}
/**
Handle the ICMPv6 packet. First validate the message format,
then, according to the message types, process it as an informational packet or
an error packet.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the ICMPv6 packet.
@param[in] Packet The content of the ICMPv6 packet with IP head
removed.
@retval EFI_INVALID_PARAMETER The packet is malformated.
@retval EFI_SUCCESS The ICMPv6 message successfully processed.
@retval Others Failed to handle the ICMPv6 packet.
**/
EFI_STATUS
Ip6IcmpHandle (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
)
{
IP6_ICMP_HEAD Icmp;
UINT16 PseudoCheckSum;
UINT16 CheckSum;
//
// Check the validity of the incoming packet.
//
if (Packet->TotalSize < sizeof (Icmp)) {
goto DROP;
}
NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
//
// Make sure checksum is valid.
//
PseudoCheckSum = NetIp6PseudoHeadChecksum (
&Head->SourceAddress,
&Head->DestinationAddress,
IP6_ICMP,
Packet->TotalSize
);
CheckSum = (UINT16) ~NetAddChecksum (PseudoCheckSum, NetbufChecksum (Packet));
if (CheckSum != 0) {
goto DROP;
}
//
// According to the packet type, call corresponding process
//
if (Icmp.Type <= ICMP_V6_ERROR_MAX) {
return Ip6ProcessIcmpError (IpSb, Head, Packet);
} else {
return Ip6ProcessIcmpInformation (IpSb, Head, Packet);
}
DROP:
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}
/**
Retrieve the Prefix address according to the PrefixLength by clear the useless
bits.
@param[in] PrefixLength The prefix length of the prefix.
@param[in, out] Prefix On input, points to the original prefix address
with dirty bits; on output, points to the updated
address with useless bit clear.
**/
VOID
Ip6GetPrefix (
IN UINT8 PrefixLength,
IN OUT EFI_IPv6_ADDRESS *Prefix
)
{
UINT8 Byte;
UINT8 Bit;
UINT8 Mask;
UINT8 Value;
ASSERT ((Prefix != NULL) && (PrefixLength < IP6_PREFIX_NUM));
if (PrefixLength == 0) {
ZeroMem (Prefix, sizeof (EFI_IPv6_ADDRESS));
return ;
}
if (PrefixLength == IP6_PREFIX_NUM - 1) {
return ;
}
Byte = (UINT8) (PrefixLength / 8);
Bit = (UINT8) (PrefixLength % 8);
Value = Prefix->Addr[Byte];
if ((Byte > 0) && (Byte < 16)) {
ZeroMem (Prefix->Addr + Byte, 16 - Byte);
}
if (Bit > 0) {
Mask = (UINT8) (0xFF << (8 - Bit));
Prefix->Addr[Byte] = (UINT8) (Value & Mask);
}
}
/**
Check whether the DestinationAddress is an anycast address.
@param[in] IpSb The IP service that received the packet.
@param[in] DestinationAddress Points to the Destination Address of the packet.
@retval TRUE The DestinationAddress is anycast address.
@retval FALSE The DestinationAddress is not anycast address.
**/
BOOLEAN
Ip6IsAnycast (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *DestinationAddress
)
{
IP6_PREFIX_LIST_ENTRY *PrefixEntry;
EFI_IPv6_ADDRESS Prefix;
BOOLEAN Flag;
ZeroMem (&Prefix, sizeof (EFI_IPv6_ADDRESS));
Flag = FALSE;
//
// If the address is known as on-link or autonomous prefix, record it as
// anycast address.
//
do {
PrefixEntry = Ip6FindPrefixListEntry (IpSb, Flag, 255, DestinationAddress);
if (PrefixEntry != NULL) {
IP6_COPY_ADDRESS (&Prefix, &PrefixEntry->Prefix);
Ip6GetPrefix (PrefixEntry->PrefixLength, &Prefix);
if (EFI_IP6_EQUAL (&Prefix, DestinationAddress)) {
return TRUE;
}
}
Flag = (BOOLEAN) !Flag;
} while (Flag);
return FALSE;
}
/**
Generate ICMPv6 error message and send it out to DestinationAddress. Currently
Destination Unreachable message, Time Exceeded message and Parameter Problem
message are supported.
@param[in] IpSb The IP service that received the packet.
@param[in] Packet The packet which invoking ICMPv6 error.
@param[in] SourceAddress If not NULL, points to the SourceAddress.
Otherwise, the IP layer will select a source address
according to the DestinationAddress.
@param[in] DestinationAddress Points to the Destination Address of the ICMPv6
error message.
@param[in] Type The type of the ICMPv6 message.
@param[in] Code The additional level of the ICMPv6 message.
@param[in] Pointer If not NULL, identifies the octet offset within
the invoking packet where the error was detected.
@retval EFI_INVALID_PARAMETER The packet is malformated.
@retval EFI_OUT_OF_RESOURCES There is no sufficient resource to complete the
operation.
@retval EFI_SUCCESS The ICMPv6 message was successfully sent out.
@retval Others Failed to generate the ICMPv6 packet.
**/
EFI_STATUS
Ip6SendIcmpError (
IN IP6_SERVICE *IpSb,
IN NET_BUF *Packet,
IN EFI_IPv6_ADDRESS *SourceAddress OPTIONAL,
IN EFI_IPv6_ADDRESS *DestinationAddress,
IN UINT8 Type,
IN UINT8 Code,
IN UINT32 *Pointer OPTIONAL
)
{
UINT32 PacketLen;
NET_BUF *ErrorMsg;
UINT16 PayloadLen;
EFI_IP6_HEADER Head;
IP6_ICMP_INFORMATION_HEAD *IcmpHead;
UINT8 *ErrorBody;
if (DestinationAddress == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// An ICMPv6 error message must not be originated as a result of receiving
// a packet whose source address does not uniquely identify a single node --
// e.g., the IPv6 Unspecified Address, an IPv6 multicast address, or an address
// known by the ICMP message originator to be an IPv6 anycast address.
//
if (NetIp6IsUnspecifiedAddr (DestinationAddress) ||
IP6_IS_MULTICAST (DestinationAddress) ||
Ip6IsAnycast (IpSb, DestinationAddress)
) {
return EFI_INVALID_PARAMETER;
}
switch (Type) {
case ICMP_V6_DEST_UNREACHABLE:
case ICMP_V6_TIME_EXCEEDED:
break;
case ICMP_V6_PARAMETER_PROBLEM:
if (Pointer == NULL) {
return EFI_INVALID_PARAMETER;
}
break;
default:
return EFI_INVALID_PARAMETER;
}
PacketLen = sizeof (IP6_ICMP_ERROR_HEAD) + Packet->TotalSize;
if (PacketLen > IpSb->MaxPacketSize) {
PacketLen = IpSb->MaxPacketSize;
}
ErrorMsg = NetbufAlloc (PacketLen);
if (ErrorMsg == NULL) {
return EFI_OUT_OF_RESOURCES;
}
PayloadLen = (UINT16) (PacketLen - sizeof (EFI_IP6_HEADER));
//
// Create the basic IPv6 header.
//
ZeroMem (&Head, sizeof (EFI_IP6_HEADER));
Head.PayloadLength = HTONS (PayloadLen);
Head.NextHeader = IP6_ICMP;
Head.HopLimit = IpSb->CurHopLimit;
if (SourceAddress != NULL) {
IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
} else {
ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));
}
IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
NetbufReserve (ErrorMsg, sizeof (EFI_IP6_HEADER));
//
// Fill in the ICMP error message head
//
IcmpHead = (IP6_ICMP_INFORMATION_HEAD *) NetbufAllocSpace (ErrorMsg, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
if (IcmpHead == NULL) {
NetbufFree (ErrorMsg);
return EFI_OUT_OF_RESOURCES;
}
ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
IcmpHead->Head.Type = Type;
IcmpHead->Head.Code = Code;
if (Pointer != NULL) {
IcmpHead->Fourth = HTONL (*Pointer);
}
//
// Fill in the ICMP error message body
//
PayloadLen -= sizeof (IP6_ICMP_INFORMATION_HEAD);
ErrorBody = NetbufAllocSpace (ErrorMsg, PayloadLen, FALSE);
if (ErrorBody != NULL) {
ZeroMem (ErrorBody, PayloadLen);
NetbufCopy (Packet, 0, PayloadLen, ErrorBody);
}
//
// Transmit the packet
//
return Ip6Output (IpSb, NULL, NULL, ErrorMsg, &Head, NULL, 0, Ip6SysPacketSent, NULL);
}

108
NetworkPkg/Ip6Dxe/Ip6Icmp.h Normal file
View File

@@ -0,0 +1,108 @@
/** @file
Header file for ICMPv6 protocol.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_ICMP_H__
#define __EFI_IP6_ICMP_H__
#define ICMP_V6_DEFAULT_CODE 0
#define ICMP_V6_ERROR_MAX 127
//
// ICMPv6 message classes, each class of ICMPv6 message shares
// a common message format. INVALID_MESSAGE is only a flag.
//
#define ICMP_V6_INVALID_MESSAGE 0
#define ICMP_V6_ERROR_MESSAGE 1
#define ICMP_V6_INFORMATION_MESSAGE 2
extern EFI_IP6_ICMP_TYPE mIp6SupportedIcmp[];
/**
Handle the ICMPv6 packet. First validate the message format,
then, according to the message types, process it as an informational packet or
an error packet.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the ICMPv6 packet.
@param[in] Packet The content of the ICMPv6 packet with IP head
removed.
@retval EFI_INVALID_PARAMETER The packet is malformated.
@retval EFI_SUCCESS The ICMPv6 message successfully processed.
@retval Others Failed to handle the ICMPv6 packet.
**/
EFI_STATUS
Ip6IcmpHandle (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
);
/**
Check whether the DestinationAddress is an anycast address.
@param[in] IpSb The IP service that received the packet.
@param[in] DestinationAddress Points to the Destination Address of the packet.
@retval TRUE The DestinationAddress is anycast address.
@retval FALSE The DestinationAddress is not anycast address.
**/
BOOLEAN
Ip6IsAnycast (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *DestinationAddress
);
/**
Generate ICMPv6 error message and send it out to DestinationAddress. Currently
Destination Unreachable message, Time Exceeded message and Parameter Problem
message are supported.
@param[in] IpSb The IP service that received the packet.
@param[in] Packet The packet which invoking ICMPv6 error.
@param[in] SourceAddress If not NULL, points to the SourceAddress.
Otherwise, the IP layer will select a source address
according to the DestinationAddress.
@param[in] DestinationAddress Points to the Destination Address of the ICMPv6
error message.
@param[in] Type The type of the ICMPv6 message.
@param[in] Code The additional level of the ICMPv6 message.
@param[in] Pointer If not NULL, identifies the octet offset within
the invoking packet where the error was detected.
@retval EFI_INVALID_PARAMETER The packet is malformated.
@retval EFI_OUT_OF_RESOURCES There is no sufficient resource to complete the
operation.
@retval EFI_SUCCESS The ICMPv6 message was successfully sent out.
@retval Others Failed to generate the ICMPv6 packet.
**/
EFI_STATUS
Ip6SendIcmpError (
IN IP6_SERVICE *IpSb,
IN NET_BUF *Packet,
IN EFI_IPv6_ADDRESS *SourceAddress OPTIONAL,
IN EFI_IPv6_ADDRESS *DestinationAddress,
IN UINT8 Type,
IN UINT8 Code,
IN UINT32 *Pointer OPTIONAL
);
#endif

802
NetworkPkg/Ip6Dxe/Ip6If.c Normal file
View File

@@ -0,0 +1,802 @@
/** @file
Implement IP6 pesudo interface.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ip6Impl.h"
/**
Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK.
@param[in] Event The transmit token's event.
@param[in] Context The Context which is pointed to the token.
**/
VOID
EFIAPI
Ip6OnFrameSent (
IN EFI_EVENT Event,
IN VOID *Context
);
/**
Fileter function to cancel all the frame related to an IP instance.
@param[in] Frame The transmit request to test whether to cancel.
@param[in] Context The context which is the Ip instance that issued
the transmit.
@retval TRUE The frame belongs to this instance and is to be
removed.
@retval FALSE The frame doesn't belong to this instance.
**/
BOOLEAN
Ip6CancelInstanceFrame (
IN IP6_LINK_TX_TOKEN *Frame,
IN VOID *Context
)
{
if (Frame->IpInstance == (IP6_PROTOCOL *) Context) {
return TRUE;
}
return FALSE;
}
/**
Set the interface's address. This will trigger the DAD process for the
address to set. To set an already set address, the lifetimes wil be
updated to the new value passed in.
@param[in] Interface The interface to set the address.
@param[in] Ip6Addr The interface's to be assigned IPv6 address.
@param[in] IsAnycast If TRUE, the unicast IPv6 address is anycast.
Otherwise, it is not anycast.
@param[in] PrefixLength The prefix length of the Ip6Addr.
@param[in] ValidLifetime The valid lifetime for this address.
@param[in] PreferredLifetime The preferred lifetime for this address.
@param[in] DadCallback The caller's callback to trigger when DAD finishes.
This is an optional parameter that may be NULL.
@param[in] Context The context that will be passed to DadCallback.
This is an optional parameter that may be NULL.
@retval EFI_SUCCESS The interface is scheduled to be configured with
the specified address.
@retval EFI_OUT_OF_RESOURCES Failed to set the interface's address due to
lack of resources.
**/
EFI_STATUS
Ip6SetAddress (
IN IP6_INTERFACE *Interface,
IN EFI_IPv6_ADDRESS *Ip6Addr,
IN BOOLEAN IsAnycast,
IN UINT8 PrefixLength,
IN UINT32 ValidLifetime,
IN UINT32 PreferredLifetime,
IN IP6_DAD_CALLBACK DadCallback OPTIONAL,
IN VOID *Context OPTIONAL
)
{
IP6_SERVICE *IpSb;
IP6_ADDRESS_INFO *AddressInfo;
LIST_ENTRY *Entry;
IP6_PREFIX_LIST_ENTRY *PrefixEntry;
UINT64 Delay;
IP6_DELAY_JOIN_LIST *DelayNode;
NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE);
IpSb = Interface->Service;
if (Ip6IsOneOfSetAddress (IpSb, Ip6Addr, NULL, &AddressInfo)) {
ASSERT (AddressInfo != NULL);
//
// Update the lifetime.
//
AddressInfo->ValidLifetime = ValidLifetime;
AddressInfo->PreferredLifetime = PreferredLifetime;
if (DadCallback != NULL) {
DadCallback (TRUE, Ip6Addr, Context);
}
return EFI_SUCCESS;
}
AddressInfo = (IP6_ADDRESS_INFO *) AllocatePool (sizeof (IP6_ADDRESS_INFO));
if (AddressInfo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
AddressInfo->Signature = IP6_ADDR_INFO_SIGNATURE;
IP6_COPY_ADDRESS (&AddressInfo->Address, Ip6Addr);
AddressInfo->IsAnycast = IsAnycast;
AddressInfo->PrefixLength = PrefixLength;
AddressInfo->ValidLifetime = ValidLifetime;
AddressInfo->PreferredLifetime = PreferredLifetime;
if (AddressInfo->PrefixLength == 0) {
//
// Find an appropriate prefix from on-link prefixes and update the prefixlength.
// Longest prefix match is used here.
//
NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
PrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
if (NetIp6IsNetEqual (&PrefixEntry->Prefix, &AddressInfo->Address, PrefixEntry->PrefixLength)) {
AddressInfo->PrefixLength = PrefixEntry->PrefixLength;
break;
}
}
}
if (AddressInfo->PrefixLength == 0) {
//
// If the prefix length is still zero, try the autonomous prefixes.
// Longest prefix match is used here.
//
NET_LIST_FOR_EACH (Entry, &IpSb->AutonomousPrefix) {
PrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
if (NetIp6IsNetEqual (&PrefixEntry->Prefix, &AddressInfo->Address, PrefixEntry->PrefixLength)) {
AddressInfo->PrefixLength = PrefixEntry->PrefixLength;
break;
}
}
}
if (AddressInfo->PrefixLength == 0) {
//
// BUGBUG: Stil fail, use 64 as the default prefix length.
//
AddressInfo->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;
}
//
// Node should delay joining the solicited-node mulitcast address by a random delay
// between 0 and MAX_RTR_SOLICITATION_DELAY (1 second).
// Thus queue the address to be processed in Duplicate Address Detection module
// after the delay time (in milliseconds).
//
Delay = (UINT64) NET_RANDOM (NetRandomInitSeed ());
Delay = MultU64x32 (Delay, IP6_ONE_SECOND_IN_MS);
Delay = RShiftU64 (Delay, 32);
DelayNode = (IP6_DELAY_JOIN_LIST *) AllocatePool (sizeof (IP6_DELAY_JOIN_LIST));
if (DelayNode == NULL) {
FreePool (AddressInfo);
return EFI_OUT_OF_RESOURCES;
}
DelayNode->DelayTime = (UINT32) (DivU64x32 (Delay, IP6_TIMER_INTERVAL_IN_MS));
DelayNode->Interface = Interface;
DelayNode->AddressInfo = AddressInfo;
DelayNode->DadCallback = DadCallback;
DelayNode->Context = Context;
InsertTailList (&Interface->DelayJoinList, &DelayNode->Link);
return EFI_SUCCESS;
}
/**
Create an IP6_INTERFACE.
@param[in] IpSb The IP6 service binding instance.
@param[in] LinkLocal If TRUE, the instance is created for link-local address.
Otherwise, it is not for a link-local address.
@return Point to the created IP6_INTERFACE, otherwise NULL.
**/
IP6_INTERFACE *
Ip6CreateInterface (
IN IP6_SERVICE *IpSb,
IN BOOLEAN LinkLocal
)
{
EFI_STATUS Status;
IP6_INTERFACE *Interface;
EFI_IPv6_ADDRESS *Ip6Addr;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
Interface = AllocatePool (sizeof (IP6_INTERFACE));
if (Interface == NULL) {
return NULL;
}
Interface->Signature = IP6_INTERFACE_SIGNATURE;
Interface->RefCnt = 1;
InitializeListHead (&Interface->AddressList);
Interface->AddressCount = 0;
Interface->Configured = FALSE;
Interface->Service = IpSb;
Interface->Controller = IpSb->Controller;
Interface->Image = IpSb->Image;
InitializeListHead (&Interface->ArpQues);
InitializeListHead (&Interface->SentFrames);
Interface->DupAddrDetect = IpSb->Ip6ConfigInstance.DadXmits.DupAddrDetectTransmits;
InitializeListHead (&Interface->DupAddrDetectList);
InitializeListHead (&Interface->DelayJoinList);
InitializeListHead (&Interface->IpInstances);
Interface->PromiscRecv = FALSE;
if (!LinkLocal) {
return Interface;
}
//
// Get the link local addr
//
Ip6Addr = Ip6CreateLinkLocalAddr (IpSb);
if (Ip6Addr == NULL) {
goto ON_ERROR;
}
//
// Perform DAD - Duplicate Address Detection.
//
Status = Ip6SetAddress (
Interface,
Ip6Addr,
FALSE,
IP6_LINK_LOCAL_PREFIX_LENGTH,
(UINT32) IP6_INFINIT_LIFETIME,
(UINT32) IP6_INFINIT_LIFETIME,
NULL,
NULL
);
FreePool (Ip6Addr);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
return Interface;
ON_ERROR:
FreePool (Interface);
return NULL;
}
/**
Free the interface used by IpInstance. All the IP instance with
the same Ip/prefix pair share the same interface. It is reference
counted. All the frames that haven't been sent will be cancelled.
Because the IpInstance is optional, the caller must remove
IpInstance from the interface's instance list.
@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.
**/
VOID
Ip6CleanInterface (
IN IP6_INTERFACE *Interface,
IN IP6_PROTOCOL *IpInstance OPTIONAL
)
{
IP6_DAD_ENTRY *Duplicate;
IP6_DELAY_JOIN_LIST *Delay;
NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE);
ASSERT (Interface->RefCnt > 0);
//
// Remove all the pending transmit token related to this IP instance.
//
Ip6CancelFrames (Interface, EFI_ABORTED, Ip6CancelInstanceFrame, IpInstance);
if (--Interface->RefCnt > 0) {
return;
}
//
// Destory the interface if this is the last IP instance.
// Remove all the system transmitted packets
// from this interface, cancel the receive request if exists.
//
Ip6CancelFrames (Interface, EFI_ABORTED, Ip6CancelInstanceFrame, NULL);
ASSERT (IsListEmpty (&Interface->IpInstances));
ASSERT (IsListEmpty (&Interface->ArpQues));
ASSERT (IsListEmpty (&Interface->SentFrames));
while (!IsListEmpty (&Interface->DupAddrDetectList)) {
Duplicate = NET_LIST_HEAD (&Interface->DupAddrDetectList, IP6_DAD_ENTRY, Link);
NetListRemoveHead (&Interface->DupAddrDetectList);
FreePool (Duplicate);
}
while (!IsListEmpty (&Interface->DelayJoinList)) {
Delay = NET_LIST_HEAD (&Interface->DelayJoinList, IP6_DELAY_JOIN_LIST, Link);
NetListRemoveHead (&Interface->DelayJoinList);
FreePool (Delay);
}
Ip6RemoveAddr (Interface->Service, &Interface->AddressList, &Interface->AddressCount, NULL, 0);
RemoveEntryList (&Interface->Link);
FreePool (Interface);
}
/**
Create and wrap a transmit request into a newly allocated IP6_LINK_TX_TOKEN.
@param[in] Interface The interface to send out from.
@param[in] IpInstance The IpInstance that transmit the packet. NULL if
the packet is sent by the IP6 driver itself.
@param[in] Packet The packet to transmit
@param[in] CallBack Call back function to execute if transmission
finished.
@param[in] Context Opaque parameter to the callback.
@return The wrapped token if succeed or NULL.
**/
IP6_LINK_TX_TOKEN *
Ip6CreateLinkTxToken (
IN IP6_INTERFACE *Interface,
IN IP6_PROTOCOL *IpInstance OPTIONAL,
IN NET_BUF *Packet,
IN IP6_FRAME_CALLBACK CallBack,
IN VOID *Context
)
{
EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
EFI_MANAGED_NETWORK_TRANSMIT_DATA *MnpTxData;
IP6_LINK_TX_TOKEN *Token;
EFI_STATUS Status;
UINT32 Count;
Token = AllocatePool (sizeof (IP6_LINK_TX_TOKEN) + (Packet->BlockOpNum - 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA));
if (Token == NULL) {
return NULL;
}
Token->Signature = IP6_LINK_TX_SIGNATURE;
InitializeListHead (&Token->Link);
Token->IpInstance = IpInstance;
Token->CallBack = CallBack;
Token->Packet = Packet;
Token->Context = Context;
ZeroMem (&Token->DstMac, sizeof (EFI_MAC_ADDRESS));
IP6_COPY_LINK_ADDRESS (&Token->SrcMac, &Interface->Service->SnpMode.CurrentAddress);
MnpToken = &(Token->MnpToken);
MnpToken->Status = EFI_NOT_READY;
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
Ip6OnFrameSent,
Token,
&MnpToken->Event
);
if (EFI_ERROR (Status)) {
FreePool (Token);
return NULL;
}
MnpTxData = &Token->MnpTxData;
MnpToken->Packet.TxData = MnpTxData;
MnpTxData->DestinationAddress = &Token->DstMac;
MnpTxData->SourceAddress = &Token->SrcMac;
MnpTxData->ProtocolType = IP6_ETHER_PROTO;
MnpTxData->DataLength = Packet->TotalSize;
MnpTxData->HeaderLength = 0;
Count = Packet->BlockOpNum;
NetbufBuildExt (Packet, (NET_FRAGMENT *) MnpTxData->FragmentTable, &Count);
MnpTxData->FragmentCount = (UINT16)Count;
return Token;
}
/**
Free the link layer transmit token. It will close the event,
then free the memory used.
@param[in] Token Token to free.
**/
VOID
Ip6FreeLinkTxToken (
IN IP6_LINK_TX_TOKEN *Token
)
{
NET_CHECK_SIGNATURE (Token, IP6_LINK_TX_SIGNATURE);
gBS->CloseEvent (Token->MnpToken.Event);
FreePool (Token);
}
/**
Callback function when the received packet is freed.
Check Ip6OnFrameReceived for information.
@param[in] Context Points to EFI_MANAGED_NETWORK_RECEIVE_DATA.
**/
VOID
EFIAPI
Ip6RecycleFrame (
IN VOID *Context
)
{
EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;
RxData = (EFI_MANAGED_NETWORK_RECEIVE_DATA *) Context;
gBS->SignalEvent (RxData->RecycleEvent);
}
/**
Received a frame from MNP. Wrap it in net buffer then deliver
it to IP's input function. The ownship of the packet also
is transferred to IP. When Ip is finished with this packet, it
will call NetbufFree to release the packet, NetbufFree will
again call the Ip6RecycleFrame to signal MNP's event and free
the token used.
@param[in] Context Context for the callback.
**/
VOID
EFIAPI
Ip6OnFrameReceivedDpc (
IN VOID *Context
)
{
EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
EFI_MANAGED_NETWORK_RECEIVE_DATA *MnpRxData;
IP6_LINK_RX_TOKEN *Token;
NET_FRAGMENT Netfrag;
NET_BUF *Packet;
UINT32 Flag;
IP6_SERVICE *IpSb;
Token = (IP6_LINK_RX_TOKEN *) Context;
NET_CHECK_SIGNATURE (Token, IP6_LINK_RX_SIGNATURE);
//
// First clear the interface's receive request in case the
// caller wants to call Ip6ReceiveFrame in the callback.
//
IpSb = (IP6_SERVICE *) Token->Context;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
MnpToken = &Token->MnpToken;
MnpRxData = MnpToken->Packet.RxData;
if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {
Token->CallBack (NULL, MnpToken->Status, 0, Token->Context);
return ;
}
//
// Wrap the frame in a net buffer then deliever it to IP input.
// IP will reassemble the packet, and deliver it to upper layer
//
Netfrag.Len = MnpRxData->DataLength;
Netfrag.Bulk = MnpRxData->PacketData;
Packet = NetbufFromExt (&Netfrag, 1, IP6_MAX_HEADLEN, 0, Ip6RecycleFrame, Token->MnpToken.Packet.RxData);
if (Packet == NULL) {
gBS->SignalEvent (MnpRxData->RecycleEvent);
Token->CallBack (NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);
return ;
}
Flag = (MnpRxData->BroadcastFlag ? IP6_LINK_BROADCAST : 0);
Flag |= (MnpRxData->MulticastFlag ? IP6_LINK_MULTICAST : 0);
Flag |= (MnpRxData->PromiscuousFlag ? IP6_LINK_PROMISC : 0);
Token->CallBack (Packet, EFI_SUCCESS, Flag, Token->Context);
}
/**
Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
@param Event The receive event delivered to MNP for receive.
@param Context Context for the callback.
**/
VOID
EFIAPI
Ip6OnFrameReceived (
IN EFI_EVENT Event,
IN VOID *Context
)
{
//
// Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK
//
QueueDpc (TPL_CALLBACK, Ip6OnFrameReceivedDpc, Context);
}
/**
Request to receive the packet from the interface.
@param[in] CallBack Function to call when receive finished.
@param[in] IpSb Points to IP6 service binding instance.
@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.
**/
EFI_STATUS
Ip6ReceiveFrame (
IN IP6_FRAME_CALLBACK CallBack,
IN IP6_SERVICE *IpSb
)
{
EFI_STATUS Status;
IP6_LINK_RX_TOKEN *Token;
if (IpSb->InDestroy) {
return EFI_INVALID_PARAMETER;
}
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
Token = &IpSb->RecvRequest;
Token->CallBack = CallBack;
Token->Context = (VOID *) IpSb;
Status = IpSb->Mnp->Receive (IpSb->Mnp, &Token->MnpToken);
if (EFI_ERROR (Status)) {
return Status;
}
return EFI_SUCCESS;
}
/**
Callback funtion when frame transmission is finished. It will
call the frame owner's callback function to tell it the result.
@param[in] Context Context which points to the token.
**/
VOID
EFIAPI
Ip6OnFrameSentDpc (
IN VOID *Context
)
{
IP6_LINK_TX_TOKEN *Token;
Token = (IP6_LINK_TX_TOKEN *) Context;
NET_CHECK_SIGNATURE (Token, IP6_LINK_TX_SIGNATURE);
RemoveEntryList (&Token->Link);
Token->CallBack (
Token->Packet,
Token->MnpToken.Status,
0,
Token->Context
);
Ip6FreeLinkTxToken (Token);
}
/**
Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK.
@param[in] Event The transmit token's event.
@param[in] Context Context which points to the token.
**/
VOID
EFIAPI
Ip6OnFrameSent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
//
// Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK
//
QueueDpc (TPL_CALLBACK, Ip6OnFrameSentDpc, Context);
}
/**
Send a frame from the interface. If the next hop is a multicast address,
it is transmitted immediately. If the next hop is a unicast,
and the NextHop's MAC is not known, it will perform address resolution.
If an error occurred, 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 IP6 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 callback.
@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 successfully transmitted.
**/
EFI_STATUS
Ip6SendFrame (
IN IP6_INTERFACE *Interface,
IN IP6_PROTOCOL *IpInstance OPTIONAL,
IN NET_BUF *Packet,
IN EFI_IPv6_ADDRESS *NextHop,
IN IP6_FRAME_CALLBACK CallBack,
IN VOID *Context
)
{
IP6_SERVICE *IpSb;
IP6_LINK_TX_TOKEN *Token;
EFI_STATUS Status;
IP6_NEIGHBOR_ENTRY *NeighborCache;
LIST_ENTRY *Entry;
IP6_NEIGHBOR_ENTRY *ArpQue;
IpSb = Interface->Service;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
//
// Only when link local address is performing DAD, the interface could be used in unconfigured.
//
if (IpSb->LinkLocalOk) {
ASSERT (Interface->Configured);
}
Token = Ip6CreateLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);
if (Token == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (IP6_IS_MULTICAST (NextHop)) {
Status = Ip6GetMulticastMac (IpSb->Mnp, NextHop, &Token->DstMac);
if (EFI_ERROR (Status)) {
goto Error;
}
goto SendNow;
}
//
// If send to itself, directly send out
//
if (EFI_IP6_EQUAL (&Packet->Ip.Ip6->DestinationAddress, &Packet->Ip.Ip6->SourceAddress)) {
IP6_COPY_LINK_ADDRESS (&Token->DstMac, &IpSb->SnpMode.CurrentAddress);
goto SendNow;
}
//
// If unicast, check the neighbor state.
//
NeighborCache = Ip6FindNeighborEntry (IpSb, NextHop);
ASSERT (NeighborCache != NULL);
if (NeighborCache->Interface == NULL) {
NeighborCache->Interface = Interface;
}
switch (NeighborCache->State) {
case EfiNeighborStale:
NeighborCache->State = EfiNeighborDelay;
NeighborCache->Ticks = (UINT32) IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME);
//
// Fall through
//
case EfiNeighborReachable:
case EfiNeighborDelay:
case EfiNeighborProbe:
IP6_COPY_LINK_ADDRESS (&Token->DstMac, &NeighborCache->LinkAddress);
goto SendNow;
break;
default:
break;
}
//
// Have to do asynchronous ARP resolution. First check whether there is
// already a pending request.
//
NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {
ArpQue = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, ArpList);
if (ArpQue == NeighborCache) {
InsertTailList (&NeighborCache->Frames, &Token->Link);
NeighborCache->ArpFree = TRUE;
return EFI_SUCCESS;
}
}
//
// First frame requires ARP.
//
InsertTailList (&NeighborCache->Frames, &Token->Link);
InsertTailList (&Interface->ArpQues, &NeighborCache->ArpList);
NeighborCache->ArpFree = TRUE;
return EFI_SUCCESS;
SendNow:
//
// Insert the tx token into the SentFrames list before calling Mnp->Transmit.
// Remove it if the returned status is not EFI_SUCCESS.
//
InsertTailList (&Interface->SentFrames, &Token->Link);
Status = IpSb->Mnp->Transmit (IpSb->Mnp, &Token->MnpToken);
if (EFI_ERROR (Status)) {
RemoveEntryList (&Token->Link);
goto Error;
}
return EFI_SUCCESS;
Error:
Ip6FreeLinkTxToken (Token);
return Status;
}
/**
The heartbeat timer of IP6 service instance. It times out
all of its IP6 children's received-but-not-delivered and
transmitted-but-not-recycle packets.
@param[in] Event The IP6 service instance's heartbeat timer.
@param[in] Context The IP6 service instance.
**/
VOID
EFIAPI
Ip6TimerTicking (
IN EFI_EVENT Event,
IN VOID *Context
)
{
IP6_SERVICE *IpSb;
IpSb = (IP6_SERVICE *) Context;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
Ip6PacketTimerTicking (IpSb);
Ip6NdTimerTicking (IpSb);
Ip6MldTimerTicking (IpSb);
}

267
NetworkPkg/Ip6Dxe/Ip6If.h Normal file
View File

@@ -0,0 +1,267 @@
/** @file
Definition for IP6 pesudo interface structure.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_IF_H__
#define __EFI_IP6_IF_H__
#define IP6_LINK_RX_SIGNATURE SIGNATURE_32 ('I', 'P', '6', 'R')
#define IP6_LINK_TX_SIGNATURE SIGNATURE_32 ('I', 'P', '6', 'T')
#define IP6_INTERFACE_SIGNATURE SIGNATURE_32 ('I', 'P', '6', 'I')
#define IP6_ADDR_INFO_SIGNATURE SIGNATURE_32 ('I', 'P', 'A', 'I')
//
// This prototype is used by both receive and transmission.
// When receiving Netbuf is allocated by IP6_INTERFACE, and
// released by IP6. Flag shows whether the frame is received
// as unicast/multicast/anycast...
//
// When transmitting, the Netbuf is from IP6, and provided
// to the callback as a reference. Flag isn't used.
//
// IpInstance can be NULL which means that it is the IP6 driver
// itself sending the packets. IP6 driver may send packets that
// don't belong to any instance, such as ICMP errors, ICMP
// informational packets. IpInstance is used as a tag in
// this module.
//
typedef
VOID
(*IP6_FRAME_CALLBACK) (
NET_BUF *Packet,
EFI_STATUS IoStatus,
UINT32 LinkFlag,
VOID *Context
);
//
// Each receive request is wrapped in an IP6_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;
IP6_FRAME_CALLBACK CallBack;
VOID *Context;
EFI_MANAGED_NETWORK_COMPLETION_TOKEN MnpToken;
} IP6_LINK_RX_TOKEN;
//
// Each transmit request is wrapped in an IP6_LINK_TX_TOKEN.
// Upon completion, the Callback will be called.
//
typedef struct {
UINT32 Signature;
LIST_ENTRY Link;
IP6_PROTOCOL *IpInstance;
IP6_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;
} IP6_LINK_TX_TOKEN;
struct _IP6_ADDRESS_INFO {
UINT32 Signature;
LIST_ENTRY Link;
EFI_IPv6_ADDRESS Address;
BOOLEAN IsAnycast;
UINT8 PrefixLength;
UINT32 ValidLifetime;
UINT32 PreferredLifetime;
};
//
// Callback to select which frame to cancel. Caller can cancel a
// single frame, or all the frame from an IP instance.
//
typedef
BOOLEAN
(*IP6_FRAME_TO_CANCEL) (
IP6_LINK_TX_TOKEN *Frame,
VOID *Context
);
struct _IP6_INTERFACE {
UINT32 Signature;
LIST_ENTRY Link;
INTN RefCnt;
//
// IP address and prefix length of the interface. The fileds
// are invalid if (Configured == FALSE)
//
LIST_ENTRY AddressList;
UINT32 AddressCount;
BOOLEAN Configured;
IP6_SERVICE *Service;
EFI_HANDLE Controller;
EFI_HANDLE Image;
//
// Queues to keep the frames sent and waiting ARP request.
//
LIST_ENTRY ArpQues;
LIST_ENTRY SentFrames;
//
// The interface's configuration variables
//
UINT32 DupAddrDetect;
LIST_ENTRY DupAddrDetectList;
LIST_ENTRY DelayJoinList;
//
// 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 IP6_INTERFACE.
@param[in] IpSb The IP6 service binding instance.
@param[in] LinkLocal If TRUE, the instance is created for link-local address.
Otherwise, it is not for a link-local address.
@return Point to the created IP6_INTERFACE, otherwise NULL.
**/
IP6_INTERFACE *
Ip6CreateInterface (
IN IP6_SERVICE *IpSb,
IN BOOLEAN LinkLocal
);
/**
Free the interface used by IpInstance. All the IP instance with
the same Ip/prefix pair share the same interface. It is reference
counted. All the frames that haven't been sent will be cancelled.
Because the IpInstance is optional, the caller must remove
IpInstance from the interface's instance list.
@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.
**/
VOID
Ip6CleanInterface (
IN IP6_INTERFACE *Interface,
IN IP6_PROTOCOL *IpInstance OPTIONAL
);
/**
Free the link layer transmit token. It will close the event
then free the memory used.
@param[in] Token Token to free.
**/
VOID
Ip6FreeLinkTxToken (
IN IP6_LINK_TX_TOKEN *Token
);
/**
Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK
@param Event The receive event delivered to MNP for receive.
@param Context Context for the callback.
**/
VOID
EFIAPI
Ip6OnFrameReceived (
IN EFI_EVENT Event,
IN VOID *Context
);
/**
Request to receive the packet from the interface.
@param[in] CallBack Function to call when the receive finished.
@param[in] IpSb Points to the IP6 service binding instance.
@retval EFI_ALREADY_STARTED There is already a pending receive request.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources to receive.
@retval EFI_SUCCESS The recieve request has been started.
**/
EFI_STATUS
Ip6ReceiveFrame (
IN IP6_FRAME_CALLBACK CallBack,
IN IP6_SERVICE *IpSb
);
/**
Send a frame from the interface. If the next hop is multicast address,
it is transmitted immediately. If the next hop is a unicast,
and the NextHop's MAC is not known, it will perform address resolution.
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 IP6 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.
@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 successfully transmitted.
**/
EFI_STATUS
Ip6SendFrame (
IN IP6_INTERFACE *Interface,
IN IP6_PROTOCOL *IpInstance OPTIONAL,
IN NET_BUF *Packet,
IN EFI_IPv6_ADDRESS *NextHop,
IN IP6_FRAME_CALLBACK CallBack,
IN VOID *Context
);
/**
The heartbeat timer of IP6 service instance. It times out
all of its IP6 children's received-but-not-delivered and
transmitted-but-not-recycle packets.
@param[in] Event The IP6 service instance's heart beat timer.
@param[in] Context The IP6 service instance.
**/
VOID
EFIAPI
Ip6TimerTicking (
IN EFI_EVENT Event,
IN VOID *Context
);
#endif

1857
NetworkPkg/Ip6Dxe/Ip6Impl.c Normal file

File diff suppressed because it is too large Load Diff

751
NetworkPkg/Ip6Dxe/Ip6Impl.h Normal file
View File

@@ -0,0 +1,751 @@
/** @file
Implementation of EFI_IP6_PROTOCOL protocol interfaces and type definitions.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_IMPL_H__
#define __EFI_IP6_IMPL_H__
#include <Uefi.h>
#include <Protocol/ServiceBinding.h>
#include <Protocol/ManagedNetwork.h>
#include <Protocol/IpSec.h>
#include <Protocol/Ip6.h>
#include <Protocol/Ip6Config.h>
#include <Protocol/Dhcp6.h>
#include <Protocol/DevicePath.h>
#include <Protocol/HiiConfigRouting.h>
#include <Protocol/HiiConfigAccess.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.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/HiiLib.h>
#include <Library/UefiHiiServicesLib.h>
#include <Library/DevicePathLib.h>
#include <Library/PrintLib.h>
#include <Guid/MdeModuleHii.h>
#include "Ip6Common.h"
#include "Ip6Driver.h"
#include "Ip6Icmp.h"
#include "Ip6If.h"
#include "Ip6Input.h"
#include "Ip6Mld.h"
#include "Ip6Nd.h"
#include "Ip6Option.h"
#include "Ip6Output.h"
#include "Ip6Route.h"
#include "Ip6ConfigNv.h"
#include "Ip6ConfigImpl.h"
#define IP6_PROTOCOL_SIGNATURE SIGNATURE_32 ('I', 'P', '6', 'P')
#define IP6_SERVICE_SIGNATURE SIGNATURE_32 ('I', 'P', '6', 'S')
//
// The state of IP6 protocol. It starts from UNCONFIGED. if it is
// successfully configured, it goes to CONFIGED. if configure NULL
// is called, it becomes UNCONFIGED again. If (partly) destroyed, it
// becomes DESTROY.
//
#define IP6_STATE_UNCONFIGED 0
#define IP6_STATE_CONFIGED 1
#define IP6_STATE_DESTROY 2
//
// The state of IP6 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 IP6_SERVICE_UNSTARTED 0
#define IP6_SERVICE_STARTED 1
#define IP6_SERVICE_CONFIGED 2
#define IP6_SERVICE_DESTROY 3
#define IP6_INSTANCE_FROM_PROTOCOL(Ip6) \
CR ((Ip6), IP6_PROTOCOL, Ip6Proto, IP6_PROTOCOL_SIGNATURE)
#define IP6_SERVICE_FROM_PROTOCOL(Sb) \
CR ((Sb), IP6_SERVICE, ServiceBinding, IP6_SERVICE_SIGNATURE)
#define IP6_NO_MAPPING(IpInstance) (!(IpInstance)->Interface->Configured)
extern EFI_IPSEC_PROTOCOL *mIpSec;
//
// IP6_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 IP6_TXTOKEN_WRAP will be released, and
// user's event signalled.
//
typedef struct {
IP6_PROTOCOL *IpInstance;
EFI_IP6_COMPLETION_TOKEN *Token;
EFI_EVENT IpSecRecycleSignal;
NET_BUF *Packet;
BOOLEAN Sent;
INTN Life;
} IP6_TXTOKEN_WRAP;
typedef struct {
EFI_EVENT IpSecRecycleSignal;
NET_BUF *Packet;
} IP6_IPSEC_WRAP;
//
// IP6_RXDATA_WRAP wraps the data IP6 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
// IP6_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;
IP6_PROTOCOL *IpInstance;
NET_BUF *Packet;
EFI_IP6_RECEIVE_DATA RxData;
} IP6_RXDATA_WRAP;
struct _IP6_PROTOCOL {
UINT32 Signature;
EFI_IP6_PROTOCOL Ip6Proto;
EFI_HANDLE Handle;
INTN State;
IP6_SERVICE *Service;
LIST_ENTRY Link; // Link to all the IP protocol from the service
UINT8 PrefixLength; // PrefixLength of the configured station address.
//
// User's transmit/receive tokens, and received/deliverd packets
//
NET_MAP RxTokens;
NET_MAP TxTokens; // map between (User's Token, IP6_TXTOKE_WRAP)
LIST_ENTRY Received; // Received but not delivered packet
LIST_ENTRY Delivered; // Delivered and to be recycled packets
EFI_LOCK RecycleLock;
IP6_INTERFACE *Interface;
LIST_ENTRY AddrLink; // Ip instances with the same IP address.
EFI_IPv6_ADDRESS *GroupList; // stored in network order.
UINT32 GroupCount;
EFI_IP6_CONFIG_DATA ConfigData;
};
struct _IP6_SERVICE {
UINT32 Signature;
EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
INTN State;
BOOLEAN InDestroy;
//
// List of all the IP instances and interfaces, and default
// interface and route table and caches.
//
UINTN NumChildren;
LIST_ENTRY Children;
LIST_ENTRY Interfaces;
IP6_INTERFACE *DefaultInterface;
IP6_ROUTE_TABLE *RouteTable;
IP6_LINK_RX_TOKEN RecvRequest;
//
// Ip reassemble utilities and MLD data
//
IP6_ASSEMBLE_TABLE Assemble;
IP6_MLD_SERVICE_DATA MldCtrl;
EFI_IPv6_ADDRESS LinkLocalAddr;
BOOLEAN LinkLocalOk;
BOOLEAN LinkLocalDadFail;
BOOLEAN Dhcp6NeedStart;
BOOLEAN Dhcp6NeedInfoRequest;
//
// ND data
//
UINT8 CurHopLimit;
UINT32 LinkMTU;
UINT32 BaseReachableTime;
UINT32 ReachableTime;
UINT32 RetransTimer;
LIST_ENTRY NeighborTable;
LIST_ENTRY OnlinkPrefix;
LIST_ENTRY AutonomousPrefix;
LIST_ENTRY DefaultRouterList;
UINT32 RoundRobin;
UINT8 InterfaceIdLen;
UINT8 *InterfaceId;
BOOLEAN RouterAdvertiseReceived;
UINT8 SolicitTimer;
UINT32 Ticks;
//
// 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 FasterTimer;
//
// IPv6 Configuration Protocol instance
//
IP6_CONFIG_INSTANCE Ip6ConfigInstance;
//
// The string representation of the current mac address of the
// NIC this IP6_SERVICE works on.
//
CHAR16 *MacString;
UINT32 MaxPacketSize;
UINT32 OldMaxPacketSize;
};
/**
The callback function for the net buffer which wraps the user's
transmit token. Although this function seems simple,
there are some subtle aspects.
When a user requests the IP to transmit a packet by passing it a
token, the token is wrapped in an IP6_TXTOKEN_WRAP and the data
is wrapped in a net buffer. The net buffer's Free function is
set to Ip6FreeTxToken. The Token and token wrap are added to the
IP child's TxToken map. Then the buffer is passed to Ip6Output for
transmission. If an error occurs before that, the buffer
is freed, which in turn frees the token wrap. The wrap may
have been added to the TxToken map or not, and the user's event
shouldn't be signaled because we are still in the EfiIp6Transmit. If
the buffer has been sent by Ip6Output, it should be removed from
the TxToken map and the user's event signaled. The token wrap and buffer
are bound together. Refer to the comments in Ip6Output for information
about IP fragmentation.
@param[in] Context The token's wrap.
**/
VOID
EFIAPI
Ip6FreeTxToken (
IN VOID *Context
);
/**
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 promiscuous 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
whether that is changed or not.
@param[in] IpSb The IP6 service instance that is to be changed.
@param[in] Force Force the configuration or not.
@retval EFI_SUCCESS The MNP successfully configured/reconfigured.
@retval Others The configuration failed.
**/
EFI_STATUS
Ip6ServiceConfigMnp (
IN IP6_SERVICE *IpSb,
IN BOOLEAN Force
);
/**
Cancel the user's receive/transmit request. It is the worker function of
EfiIp6Cancel API.
@param[in] IpInstance The IP6 child.
@param[in] Token The token to cancel. If NULL, all tokens will be
cancelled.
@retval EFI_SUCCESS The token was cancelled.
@retval EFI_NOT_FOUND The token isn't found on either the
transmit or receive queue.
@retval EFI_DEVICE_ERROR Not all tokens are cancelled when Token is NULL.
**/
EFI_STATUS
Ip6Cancel (
IN IP6_PROTOCOL *IpInstance,
IN EFI_IP6_COMPLETION_TOKEN *Token OPTIONAL
);
/**
Initialize the IP6_PROTOCOL structure to the unconfigured states.
@param[in] IpSb The IP6 service instance.
@param[in, out] IpInstance The IP6 child instance.
**/
VOID
Ip6InitProtocol (
IN IP6_SERVICE *IpSb,
IN OUT IP6_PROTOCOL *IpInstance
);
/**
Clean up the IP6 child, release all the resources used by it.
@param[in, out] IpInstance The IP6 child to clean up.
@retval EFI_SUCCESS The IP6 child was cleaned up
@retval EFI_DEVICE_ERROR Some resources failed to be released.
**/
EFI_STATUS
Ip6CleanProtocol (
IN OUT IP6_PROTOCOL *IpInstance
);
//
// EFI_IP6_PROTOCOL interface prototypes
//
/**
Gets the current operational settings for this instance of the EFI IPv6 Protocol driver.
The GetModeData() function returns the current operational mode data for this driver instance.
The data fields in EFI_IP6_MODE_DATA are read only. This function is used optionally to
retrieve the operational mode data of underlying networks or drivers.
@param[in] This The pointer to the EFI_IP6_PROTOCOL instance.
@param[out] Ip6ModeData The pointer to the EFI IPv6 Protocol mode data structure.
@param[out] MnpConfigData The pointer to the managed network configuration data structure.
@param[out] SnpModeData The pointer to the simple network mode data structure.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated.
**/
EFI_STATUS
EFIAPI
EfiIp6GetModeData (
IN EFI_IP6_PROTOCOL *This,
OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL,
OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
);
/**
Assigns an IPv6 address and subnet mask to this EFI IPv6 Protocol driver instance.
The Configure() function is used to set, change, or reset the operational parameters and filter
settings for this EFI IPv6 Protocol instance. Until these parameters have been set, no network traffic
can be sent or received by this instance. Once the parameters have been reset (by calling this
function with Ip6ConfigData set to NULL), no more traffic can be sent or received until these
parameters have been set again. Each EFI IPv6 Protocol instance can be started and stopped
independently of each other by enabling or disabling their receive filter settings with the
Configure() function.
If Ip6ConfigData.StationAddress is a valid non-zero IPv6 unicast address, it is required
to be one of the currently configured IPv6 addresses list in the EFI IPv6 drivers, or else
EFI_INVALID_PARAMETER will be returned. If Ip6ConfigData.StationAddress is
unspecified, the IPv6 driver will bind a source address according to the source address selection
algorithm. Clients could frequently call GetModeData() to check get a currently configured IPv6.
If both Ip6ConfigData.StationAddress and Ip6ConfigData.Destination are unspecified, when
transmitting the packet afterwards, the source address filled in each outgoing IPv6 packet
is decided based on the destination of this packet.
If operational parameters are reset or changed, any pending transmit and receive requests will be
cancelled. Their completion token status will be set to EFI_ABORTED, and their events will be
signaled.
@param[in] This The pointer to the EFI_IP6_PROTOCOL instance.
@param[in] Ip6ConfigData The pointer to the EFI IPv6 Protocol configuration data structure.
If NULL, reset the configuration data.
@retval EFI_SUCCESS The driver instance was successfully opened.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- This is NULL.
- Ip6ConfigData.StationAddress is neither zero nor
a unicast IPv6 address.
- Ip6ConfigData.StationAddress is neither zero nor
one of the configured IP addresses in the EFI IPv6 driver.
- Ip6ConfigData.DefaultProtocol is illegal.
@retval EFI_OUT_OF_RESOURCES The EFI IPv6 Protocol driver instance data could not be allocated.
@retval EFI_NO_MAPPING The IPv6 driver was responsible for choosing a source address for
this instance, but no source address was available for use.
@retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the IPv6
address or prefix length can be changed.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv6
Protocol driver instance was not opened.
@retval EFI_UNSUPPORTED Default protocol specified through
Ip6ConfigData.DefaulProtocol isn't supported.
**/
EFI_STATUS
EFIAPI
EfiIp6Configure (
IN EFI_IP6_PROTOCOL *This,
IN EFI_IP6_CONFIG_DATA *Ip6ConfigData OPTIONAL
);
/**
Joins and leaves multicast groups.
The Groups() function is used to join and leave multicast group sessions. Joining a group will
enable reception of matching multicast packets. Leaving a group will disable reception of matching
multicast packets. Source-Specific Multicast isn't required to be supported.
If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
@param[in] This The pointer to the EFI_IP6_PROTOCOL instance.
@param[in] JoinFlag Set to TRUE to join the multicast group session and FALSE to leave.
@param[in] GroupAddress The pointer to the IPv6 multicast address.
This is an optional parameter that may be NULL.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
- This is NULL.
- JoinFlag is TRUE and GroupAddress is NULL.
- GroupAddress is not NULL and *GroupAddress is
not a multicast IPv6 address.
- GroupAddress is not NULL and *GroupAddress is in the
range of SSM destination address.
@retval EFI_NOT_STARTED This instance has not been started.
@retval EFI_OUT_OF_RESOURCES System resources could not be allocated.
@retval EFI_UNSUPPORTED This EFI IPv6 Protocol implementation does not support multicast groups.
@retval EFI_ALREADY_STARTED The group address is already in the group table (when
JoinFlag is TRUE).
@retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE).
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
**/
EFI_STATUS
EFIAPI
EfiIp6Groups (
IN EFI_IP6_PROTOCOL *This,
IN BOOLEAN JoinFlag,
IN EFI_IPv6_ADDRESS *GroupAddress OPTIONAL
);
/**
Adds and deletes routing table entries.
The Routes() function adds a route to or deletes a route from the routing table.
Routes are determined by comparing the leftmost PrefixLength bits of Destination with
the destination IPv6 address arithmetically. The gateway address must be on the same subnet as the
configured station address.
The default route is added with Destination and PrefixLegth both set to all zeros. The
default route matches all destination IPv6 addresses that do not match any other routes.
All EFI IPv6 Protocol instances share a routing table.
@param[in] This The pointer to the EFI_IP6_PROTOCOL instance.
@param[in] DeleteRoute Set to TRUE to delete this route from the routing table. Set to
FALSE to add this route to the routing table. Destination,
PrefixLength and Gateway are used as the key to each
route entry.
@param[in] Destination The address prefix of the subnet that needs to be routed.
This is an optional parameter that may be NULL.
@param[in] PrefixLength The prefix length of Destination. Ignored if Destination
is NULL.
@param[in] GatewayAddress The unicast gateway IPv6 address for this route.
This is an optional parameter that may be NULL.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_NOT_STARTED The driver instance has not been started.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- This is NULL.
- When DeleteRoute is TRUE, both Destination and
GatewayAddress are NULL.
- When DeleteRoute is FALSE, either Destination or
GatewayAddress is NULL.
- *GatewayAddress is not a valid unicast IPv6 address.
- *GatewayAddress is one of the local configured IPv6
addresses.
@retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
@retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE).
@retval EFI_ACCESS_DENIED The route is already defined in the routing table (when
DeleteRoute is FALSE).
**/
EFI_STATUS
EFIAPI
EfiIp6Routes (
IN EFI_IP6_PROTOCOL *This,
IN BOOLEAN DeleteRoute,
IN EFI_IPv6_ADDRESS *Destination OPTIONAL,
IN UINT8 PrefixLength,
IN EFI_IPv6_ADDRESS *GatewayAddress OPTIONAL
);
/**
Add or delete Neighbor cache entries.
The Neighbors() function is used to add, update, or delete an entry from a neighbor cache.
IPv6 neighbor cache entries are typically inserted and updated by the network protocol driver as
network traffic is processed. Most neighbor cache entries will timeout and be deleted if the network
traffic stops. Neighbor cache entries that were inserted by Neighbors() may be static (will not
timeout) or dynamic (will timeout).
The implementation should follow the neighbor cache timeout mechanism defined in
RFC4861. The default neighbor cache timeout value should be tuned for the expected network
environment.
@param[in] This The pointer to the EFI_IP6_PROTOCOL instance.
@param[in] DeleteFlag Set to TRUE to delete the specified cache entry. Set to FALSE to
add (or update, if it already exists and Override is TRUE) the
specified cache entry. TargetIp6Address is used as the key
to find the requested cache entry.
@param[in] TargetIp6Address The pointer to the Target IPv6 address.
@param[in] TargetLinkAddress The pointer to link-layer address of the target. Ignored if NULL.
@param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
cache, it will be deleted after Timeout. A value of zero means that
the entry is permanent. A non-zero value means that the entry is
dynamic.
@param[in] Override If TRUE, the cached link-layer address of the matching entry will
be overridden and updated; if FALSE, EFI_ACCESS_DENIED
will be returned if a corresponding cache entry already exists.
@retval EFI_SUCCESS The data has been queued for transmission.
@retval EFI_NOT_STARTED This instance has not been started.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- This is NULL.
- TargetIpAddress is NULL.
- *TargetLinkAddress is invalid when not NULL.
- *TargetIpAddress is not a valid unicast IPv6 address.
- *TargetIpAddress is one of the local configured IPv6
addresses.
@retval EFI_OUT_OF_RESOURCES Could not add the entry to the neighbor cache.
@retval EFI_NOT_FOUND This entry is not in the neighbor cache (when DeleteFlag is
TRUE or when DeleteFlag is FALSE while
TargetLinkAddress is NULL.).
@retval EFI_ACCESS_DENIED The to-be-added entry is already defined in the neighbor cache,
and that entry is tagged as un-overridden (when Override
is FALSE).
**/
EFI_STATUS
EFIAPI
EfiIp6Neighbors (
IN EFI_IP6_PROTOCOL *This,
IN BOOLEAN DeleteFlag,
IN EFI_IPv6_ADDRESS *TargetIp6Address,
IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL,
IN UINT32 Timeout,
IN BOOLEAN Override
);
/**
Places outgoing data packets into the transmit queue.
The Transmit() function places a sending request in the transmit queue of this
EFI IPv6 Protocol instance. Whenever the packet in the token is sent out or some
errors occur, the event in the token will be signaled and the status is updated.
@param[in] This The pointer to the EFI_IP6_PROTOCOL instance.
@param[in] Token The pointer to the transmit token.
@retval EFI_SUCCESS The data has been queued for transmission.
@retval EFI_NOT_STARTED This instance has not been started.
@retval EFI_NO_MAPPING The IPv6 driver was responsible for choosing
a source address for this transmission,
but no source address was available for use.
@retval EFI_INVALID_PARAMETER One or more of the following is TRUE:
- This is NULL.
- Token is NULL.
- Token.Event is NULL.
- Token.Packet.TxData is NULL.
- Token.Packet.ExtHdrsLength is not zero and
Token.Packet.ExtHdrs is NULL.
- Token.Packet.FragmentCount is zero.
- One or more of the Token.Packet.TxData.
FragmentTable[].FragmentLength fields is zero.
- One or more of the Token.Packet.TxData.
FragmentTable[].FragmentBuffer fields is NULL.
- Token.Packet.TxData.DataLength is zero or not
equal to the sum of fragment lengths.
- Token.Packet.TxData.DestinationAddress is non-
zero when DestinationAddress is configured as
non-zero when doing Configure() for this
EFI IPv6 protocol instance.
- Token.Packet.TxData.DestinationAddress is
unspecified when DestinationAddress is unspecified
when doing Configure() for this EFI IPv6 protocol
instance.
@retval EFI_ACCESS_DENIED The transmit completion token with the same Token.
The event was already in the transmit queue.
@retval EFI_NOT_READY The completion token could not be queued because
the transmit queue is full.
@retval EFI_NOT_FOUND Not route is found to the destination address.
@retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.
@retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too
short to transmit.
@retval EFI_BAD_BUFFER_SIZE If Token.Packet.TxData.DataLength is beyond the
maximum that which can be described through the
Fragment Offset field in Fragment header when
performing fragmentation.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
**/
EFI_STATUS
EFIAPI
EfiIp6Transmit (
IN EFI_IP6_PROTOCOL *This,
IN EFI_IP6_COMPLETION_TOKEN *Token
);
/**
Places a receiving request into the receiving queue.
The Receive() function places a completion token into the receive packet queue.
This function is always asynchronous.
The Token.Event field in the completion token must be filled in by the caller
and cannot be NULL. When the receive operation completes, the EFI IPv6 Protocol
driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
is signaled.
Current Udp implementation creates an IP child for each Udp child.
It initates a asynchronous receive immediately whether or not
there is no mapping. Therefore, disable the returning EFI_NO_MAPPING for now.
To enable it, the following check must be performed:
if (NetIp6IsUnspecifiedAddr (&Config->StationAddress) && IP6_NO_MAPPING (IpInstance)) {
Status = EFI_NO_MAPPING;
goto Exit;
}
@param[in] This The pointer to the EFI_IP6_PROTOCOL instance.
@param[in] Token The pointer to a token that is associated with the
receive data descriptor.
@retval EFI_SUCCESS The receive completion token was cached.
@retval EFI_NOT_STARTED This EFI IPv6 Protocol instance has not been started.
@retval EFI_NO_MAPPING When IP6 driver responsible for binding source address to this instance,
while no source address is available for use.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
- This is NULL.
- Token is NULL.
- Token.Event is NULL.
@retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system
resources (usually memory).
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
The EFI IPv6 Protocol instance has been reset to startup defaults.
@retval EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already
in the receive queue.
@retval EFI_NOT_READY The receive request could not be queued because the receive queue is full.
**/
EFI_STATUS
EFIAPI
EfiIp6Receive (
IN EFI_IP6_PROTOCOL *This,
IN EFI_IP6_COMPLETION_TOKEN *Token
);
/**
Abort an asynchronous transmit or receive request.
The Cancel() function is used to abort a pending transmit or receive request.
If the token is in the transmit or receive request queues, after calling this
function, Token->Status will be set to EFI_ABORTED, and then Token->Event will
be signaled. If the token is not in one of the queues, which usually means the
asynchronous operation has completed, this function will not signal the token,
and EFI_NOT_FOUND is returned.
@param[in] This The pointer to the EFI_IP6_PROTOCOL instance.
@param[in] Token The pointer to a token that has been issued by
EFI_IP6_PROTOCOL.Transmit() or
EFI_IP6_PROTOCOL.Receive(). If NULL, all pending
tokens are aborted. Type EFI_IP6_COMPLETION_TOKEN is
defined in EFI_IP6_PROTOCOL.Transmit().
@retval EFI_SUCCESS The asynchronous I/O request was aborted and
Token->Event was signaled. When Token is NULL, all
pending requests were aborted, and their events were signaled.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_NOT_STARTED This instance has not been started.
@retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was
not found in the transmit or receive queue. It has either completed
or was not issued by Transmit() and Receive().
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
**/
EFI_STATUS
EFIAPI
EfiIp6Cancel (
IN EFI_IP6_PROTOCOL *This,
IN EFI_IP6_COMPLETION_TOKEN *Token OPTIONAL
);
/**
Polls for incoming data packets and processes outgoing data packets.
The Poll() function polls for incoming data packets and processes outgoing data
packets. Network drivers and applications can call the EFI_IP6_PROTOCOL.Poll()
function to increase the rate that data packets are moved between the communications
device and the transmit and receive queues.
In some systems the periodic timer event may not poll the underlying communications
device fast enough to transmit and/or receive all data packets without missing
incoming packets or dropping outgoing packets. Drivers and applications that are
experiencing packet loss should try calling the EFI_IP6_PROTOCOL.Poll() function
more often.
@param[in] This The pointer to the EFI_IP6_PROTOCOL instance.
@retval EFI_SUCCESS Incoming or outgoing data was processed.
@retval EFI_NOT_STARTED This EFI IPv6 Protocol instance has not been started.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
@retval EFI_NOT_READY No incoming or outgoing data was processed.
@retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue.
Consider increasing the polling rate.
**/
EFI_STATUS
EFIAPI
EfiIp6Poll (
IN EFI_IP6_PROTOCOL *This
);
#endif

1710
NetworkPkg/Ip6Dxe/Ip6Input.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,235 @@
/** @file
IP6 internal functions and definitions to process the incoming packets.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_INPUT_H__
#define __EFI_IP6_INPUT_H__
#define IP6_MIN_HEADLEN 40
#define IP6_MAX_HEADLEN 120
///
/// 8(ESP header) + 16(max IV) + 16(max padding) + 2(ESP tail) + 12(max ICV) = 54
///
#define IP6_MAX_IPSEC_HEADLEN 54
#define IP6_ASSEMLE_HASH_SIZE 127
///
/// Lift time in seconds.
///
#define IP6_FRAGMENT_LIFE 60
#define IP6_MAX_PACKET_SIZE 65535
#define IP6_GET_CLIP_INFO(Packet) ((IP6_CLIP_INFO *) ((Packet)->ProtoData))
#define IP6_ASSEMBLE_HASH(Dst, Src, Id) \
((*((UINT32 *) (Dst)) + *((UINT32 *) (Src)) + (Id)) % IP6_ASSEMLE_HASH_SIZE)
#define IP6_RXDATA_WRAP_SIZE(NumFrag) \
(sizeof (IP6_RXDATA_WRAP) + sizeof (EFI_IP6_FRAGMENT_DATA) * ((NumFrag) - 1))
//
// 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 {
UINT32 LinkFlag;
INT32 CastType;
INT32 Start;
INT32 End;
INT32 Length;
UINT32 Life;
EFI_STATUS Status;
UINT32 Id;
UINT16 HeadLen;
UINT8 NextHeader;
UINT8 LastFrag;
UINT32 FormerNextHeader;
} IP6_CLIP_INFO;
//
// Structure used to assemble IP packets.
//
typedef struct {
LIST_ENTRY Link;
LIST_ENTRY Fragments; // List of all the fragments of this packet
//
// Identity of one IP6 packet. Each fragment of a packet has
// the same (Dst, Src, Id).
//
EFI_IPv6_ADDRESS Dst;
EFI_IPv6_ADDRESS Src;
UINT32 Id;
UINT32 TotalLen;
UINT32 CurLen;
UINT32 Life; // Count down life for the packet.
EFI_IP6_HEADER *Head; // IP head of the first fragment
IP6_CLIP_INFO *Info; // Per packet information of the first fragment
NET_BUF *Packet; // The first fragment of the packet
} IP6_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[IP6_ASSEMLE_HASH_SIZE];
} IP6_ASSEMBLE_TABLE;
/**
The IP6 input routine. It is called by the IP6_INTERFACE when an
IP6 fragment is received from MNP.
@param[in] Packet The IP6 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 IP6 service instance that own the MNP.
**/
VOID
Ip6AcceptFrame (
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus,
IN UINT32 Flag,
IN VOID *Context
);
/**
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
Ip6InstanceDeliverPacket (
IN IP6_PROTOCOL *IpInstance
);
/**
The work function to locate IPsec protocol to process the inbound or
outbound IP packets. The process routine handls the packet with the following
actions: bypass the packet, discard the packet, or protect the packet.
@param[in] IpSb The IP6 service instance.
@param[in] Head The caller supplied IP6 header.
@param[in, out] LastHead The next header field of last IP header.
@param[in, out] Netbuf The IP6 packet to be processed by IPsec.
@param[in] ExtHdrs The caller supplied options.
@param[in] ExtHdrsLen 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 are not suffcient resources 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 building a fragment table.
**/
EFI_STATUS
Ip6IpSecProcessPacket (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN OUT UINT8 *LastHead,
IN OUT NET_BUF **Netbuf,
IN VOID *ExtHdrs,
IN UINT32 ExtHdrsLen,
IN EFI_IPSEC_TRAFFIC_DIR Direction,
IN VOID *Context
);
/**
Initialize an already allocated assemble table. This is generally
the assemble table embedded in the IP6 service instance.
@param[in, out] Table The assemble table to initialize.
**/
VOID
Ip6CreateAssembleTable (
IN OUT IP6_ASSEMBLE_TABLE *Table
);
/**
Clean up the assemble table: remove all the fragments
and assemble entries.
@param[in, out] Table The assemble table to clean up.
**/
VOID
Ip6CleanAssembleTable (
IN OUT IP6_ASSEMBLE_TABLE *Table
);
/**
Demultiple the packet. the packet delivery is processed in two
passes. The first pass will enque a shared copy of the packet
to each IP6 child that accepts the packet. The second pass will
deliver a non-shared copy of the packet to each IP6 child that
has pending receive requests. Data is copied if more than one
child wants to consume the packet bacause each IP child need
its own copy of the packet to make changes.
@param[in] IpSb The IP6 service instance that received the packet.
@param[in] Head The header of the received packet.
@param[in] Packet The data of the received packet.
@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
Ip6Demultiplex (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
);
/**
Timeout the fragmented, enqueued, and transmitted packets.
@param[in] IpSb The IP6 service instance to timeout.
**/
VOID
Ip6PacketTimerTicking (
IN IP6_SERVICE *IpSb
);
#endif

908
NetworkPkg/Ip6Dxe/Ip6Mld.c Normal file
View File

@@ -0,0 +1,908 @@
/** @file
Multicast Listener Discovery support routines.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ip6Impl.h"
/**
Create a IP6_MLD_GROUP list entry node and record to IP6 service binding data.
@param[in, out] IpSb Points to IP6 service binding instance.
@param[in] MulticastAddr The IPv6 multicast address to be recorded.
@param[in] DelayTimer The maximum allowed delay before sending a responding
report, in units of milliseconds.
@return The created IP6_ML_GROUP list entry or NULL.
**/
IP6_MLD_GROUP *
Ip6CreateMldEntry (
IN OUT IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *MulticastAddr,
IN UINT32 DelayTimer
)
{
IP6_MLD_GROUP *Entry;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
ASSERT (MulticastAddr != NULL && IP6_IS_MULTICAST (MulticastAddr));
Entry = AllocatePool (sizeof (IP6_MLD_GROUP));
if (Entry != NULL) {
Entry->RefCnt = 1;
Entry->DelayTimer = DelayTimer;
Entry->SendByUs = FALSE;
IP6_COPY_ADDRESS (&Entry->Address, MulticastAddr);
InsertTailList (&IpSb->MldCtrl.Groups, &Entry->Link);
}
return Entry;
}
/**
Search a IP6_MLD_GROUP list entry node from a list array.
@param[in] IpSb Points to IP6 service binding instance.
@param[in] MulticastAddr The IPv6 multicast address to be searched.
@return The found IP6_ML_GROUP list entry or NULL.
**/
IP6_MLD_GROUP *
Ip6FindMldEntry (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *MulticastAddr
)
{
LIST_ENTRY *Entry;
IP6_MLD_GROUP *Group;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
ASSERT (MulticastAddr != NULL && IP6_IS_MULTICAST (MulticastAddr));
NET_LIST_FOR_EACH (Entry, &IpSb->MldCtrl.Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IP6_MLD_GROUP, Link);
if (EFI_IP6_EQUAL (MulticastAddr, &Group->Address)) {
return Group;
}
}
return NULL;
}
/**
Count the number of IP6 multicast groups that are mapped to the
same MAC address. Several IP6 multicast address may be mapped to
the same MAC address.
@param[in] MldCtrl The MLD control block to search in.
@param[in] Mac The MAC address to search.
@return The number of the IP6 multicast group that mapped to the same
multicast group Mac.
**/
INTN
Ip6FindMac (
IN IP6_MLD_SERVICE_DATA *MldCtrl,
IN EFI_MAC_ADDRESS *Mac
)
{
LIST_ENTRY *Entry;
IP6_MLD_GROUP *Group;
INTN Count;
Count = 0;
NET_LIST_FOR_EACH (Entry, &MldCtrl->Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IP6_MLD_GROUP, Link);
if (NET_MAC_EQUAL (&Group->Mac, Mac, sizeof (EFI_MAC_ADDRESS))) {
Count++;
}
}
return Count;
}
/**
Generate MLD report message and send it out to MulticastAddr.
@param[in] IpSb The IP service to send the packet.
@param[in] Interface The IP interface to send the packet.
If NULL, a system interface will be selected.
@param[in] MulticastAddr The specific IPv6 multicast address to which
the message sender is listening.
@retval EFI_OUT_OF_RESOURCES There are not sufficient resources to complete the
operation.
@retval EFI_SUCCESS The MLD report message was successfully sent out.
**/
EFI_STATUS
Ip6SendMldReport (
IN IP6_SERVICE *IpSb,
IN IP6_INTERFACE *Interface OPTIONAL,
IN EFI_IPv6_ADDRESS *MulticastAddr
)
{
IP6_MLD_HEAD *MldHead;
NET_BUF *Packet;
EFI_IP6_HEADER Head;
UINT16 PayloadLen;
UINTN OptionLen;
UINT8 *Options;
EFI_STATUS Status;
UINT16 HeadChecksum;
UINT16 PseudoChecksum;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
ASSERT (MulticastAddr != NULL && IP6_IS_MULTICAST (MulticastAddr));
//
// Generate the packet to be sent
// IPv6 basic header + Hop by Hop option + MLD message
//
OptionLen = 0;
Status = Ip6FillHopByHop (NULL, &OptionLen, IP6_ICMP);
ASSERT (Status == EFI_BUFFER_TOO_SMALL);
PayloadLen = (UINT16) (OptionLen + sizeof (IP6_MLD_HEAD));
Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32) PayloadLen);
if (Packet == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Create the basic IPv6 header.
// RFC3590: Use link-local address as source address if it is available,
// otherwise use the unspecified address.
//
Head.FlowLabelL = 0;
Head.FlowLabelH = 0;
Head.PayloadLength = HTONS (PayloadLen);
Head.NextHeader = IP6_HOP_BY_HOP;
Head.HopLimit = 1;
IP6_COPY_ADDRESS (&Head.DestinationAddress, MulticastAddr);
//
// If Link-Local address is not ready, we use unspecified address.
//
IP6_COPY_ADDRESS (&Head.SourceAddress, &IpSb->LinkLocalAddr);
NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
//
// Fill a IPv6 Router Alert option in a Hop-by-Hop Options Header
//
Options = NetbufAllocSpace (Packet, (UINT32) OptionLen, FALSE);
ASSERT (Options != NULL);
Status = Ip6FillHopByHop (Options, &OptionLen, IP6_ICMP);
if (EFI_ERROR (Status)) {
NetbufFree (Packet);
Packet = NULL;
return Status;
}
//
// Fill in MLD message - Report
//
MldHead = (IP6_MLD_HEAD *) NetbufAllocSpace (Packet, sizeof (IP6_MLD_HEAD), FALSE);
ASSERT (MldHead != NULL);
ZeroMem (MldHead, sizeof (IP6_MLD_HEAD));
MldHead->Head.Type = ICMP_V6_LISTENER_REPORT;
MldHead->Head.Code = 0;
IP6_COPY_ADDRESS (&MldHead->Group, MulticastAddr);
HeadChecksum = NetblockChecksum ((UINT8 *) MldHead, sizeof (IP6_MLD_HEAD));
PseudoChecksum = NetIp6PseudoHeadChecksum (
&Head.SourceAddress,
&Head.DestinationAddress,
IP6_ICMP,
sizeof (IP6_MLD_HEAD)
);
MldHead->Head.Checksum = (UINT16) ~NetAddChecksum (HeadChecksum, PseudoChecksum);
//
// Transmit the packet
//
return Ip6Output (IpSb, Interface, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
}
/**
Generate MLD Done message and send it out to MulticastAddr.
@param[in] IpSb The IP service to send the packet.
@param[in] MulticastAddr The specific IPv6 multicast address to which
the message sender is ceasing to listen.
@retval EFI_OUT_OF_RESOURCES There are not sufficient resources to complete the
operation.
@retval EFI_SUCCESS The MLD report message was successfully sent out.
**/
EFI_STATUS
Ip6SendMldDone (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *MulticastAddr
)
{
IP6_MLD_HEAD *MldHead;
NET_BUF *Packet;
EFI_IP6_HEADER Head;
UINT16 PayloadLen;
UINTN OptionLen;
UINT8 *Options;
EFI_STATUS Status;
EFI_IPv6_ADDRESS Destination;
UINT16 HeadChecksum;
UINT16 PseudoChecksum;
NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
ASSERT (MulticastAddr != NULL && IP6_IS_MULTICAST (MulticastAddr));
//
// Generate the packet to be sent
// IPv6 basic header + Hop by Hop option + MLD message
//
OptionLen = 0;
Status = Ip6FillHopByHop (NULL, &OptionLen, IP6_ICMP);
ASSERT (Status == EFI_BUFFER_TOO_SMALL);
PayloadLen = (UINT16) (OptionLen + sizeof (IP6_MLD_HEAD));
Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32) PayloadLen);
if (Packet == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Create the basic IPv6 header.
//
Head.FlowLabelL = 0;
Head.FlowLabelH = 0;
Head.PayloadLength = HTONS (PayloadLen);
Head.NextHeader = IP6_HOP_BY_HOP;
Head.HopLimit = 1;
//
// If Link-Local address is not ready, we use unspecified address.
//
IP6_COPY_ADDRESS (&Head.SourceAddress, &IpSb->LinkLocalAddr);
Ip6SetToAllNodeMulticast (TRUE, IP6_LINK_LOCAL_SCOPE, &Destination);
IP6_COPY_ADDRESS (&Head.DestinationAddress, &Destination);
NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
//
// Fill a IPv6 Router Alert option in a Hop-by-Hop Options Header
//
Options = NetbufAllocSpace (Packet, (UINT32) OptionLen, FALSE);
ASSERT (Options != NULL);
Status = Ip6FillHopByHop (Options, &OptionLen, IP6_ICMP);
if (EFI_ERROR (Status)) {
NetbufFree (Packet);
Packet = NULL;
return Status;
}
//
// Fill in MLD message - Done
//
MldHead = (IP6_MLD_HEAD *) NetbufAllocSpace (Packet, sizeof (IP6_MLD_HEAD), FALSE);
ASSERT (MldHead != NULL);
ZeroMem (MldHead, sizeof (IP6_MLD_HEAD));
MldHead->Head.Type = ICMP_V6_LISTENER_DONE;
MldHead->Head.Code = 0;
IP6_COPY_ADDRESS (&MldHead->Group, MulticastAddr);
HeadChecksum = NetblockChecksum ((UINT8 *) MldHead, sizeof (IP6_MLD_HEAD));
PseudoChecksum = NetIp6PseudoHeadChecksum (
&Head.SourceAddress,
&Head.DestinationAddress,
IP6_ICMP,
sizeof (IP6_MLD_HEAD)
);
MldHead->Head.Checksum = (UINT16) ~NetAddChecksum (HeadChecksum, PseudoChecksum);
//
// Transmit the packet
//
return Ip6Output (IpSb, NULL, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
}
/**
Init the MLD data of the IP6 service instance. Configure
MNP to receive ALL SYSTEM multicast.
@param[in] IpSb The IP6 service whose MLD is to be initialized.
@retval EFI_OUT_OF_RESOURCES There are not sufficient resourcet to complete the
operation.
@retval EFI_SUCCESS The MLD module successfully initialized.
**/
EFI_STATUS
Ip6InitMld (
IN IP6_SERVICE *IpSb
)
{
EFI_IPv6_ADDRESS AllNodes;
IP6_MLD_GROUP *Group;
EFI_STATUS Status;
//
// Join the link-scope all-nodes multicast address (FF02::1).
// This address is started in Idle Listener state and never transitions to
// another state, and never sends a Report or Done for that address.
//
Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &AllNodes);
Group = Ip6CreateMldEntry (IpSb, &AllNodes, (UINT32) IP6_INFINIT_LIFETIME);
if (Group == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = Ip6GetMulticastMac (IpSb->Mnp, &AllNodes, &Group->Mac);
if (EFI_ERROR (Status)) {
goto ERROR;
}
//
// Configure MNP to receive all-nodes multicast
//
Status = IpSb->Mnp->Groups (IpSb->Mnp, TRUE, &Group->Mac);
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
goto ERROR;
}
return EFI_SUCCESS;
ERROR:
RemoveEntryList (&Group->Link);
FreePool (Group);
return Status;
}
/**
Add a group address to the array of group addresses.
The caller should make sure that no duplicated address
existed in the array.
@param[in, out] IpInstance Points to an IP6_PROTOCOL instance.
@param[in] Group The IP6 multicast address to add.
@retval EFI_OUT_OF_RESOURCES There are not sufficient resources to complete
the operation.
@retval EFI_SUCESS The address is added to the group address array.
**/
EFI_STATUS
Ip6CombineGroups (
IN OUT IP6_PROTOCOL *IpInstance,
IN EFI_IPv6_ADDRESS *Group
)
{
EFI_IPv6_ADDRESS *GroupList;
NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
ASSERT (Group != NULL && IP6_IS_MULTICAST (Group));
IpInstance->GroupCount++;
GroupList = AllocatePool (IpInstance->GroupCount * sizeof (EFI_IPv6_ADDRESS));
if (GroupList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (IpInstance->GroupCount > 1) {
ASSERT (IpInstance->GroupList != NULL);
CopyMem (
GroupList,
IpInstance->GroupList,
(IpInstance->GroupCount - 1) * sizeof (EFI_IPv6_ADDRESS)
);
FreePool (IpInstance->GroupList);
}
IP6_COPY_ADDRESS (GroupList + (IpInstance->GroupCount - 1), Group);
IpInstance->GroupList = GroupList;
return EFI_SUCCESS;
}
/**
Remove a group address from the array of group addresses.
Although the function doesn't assume the byte order of Group,
the network byte order is used by the caller.
@param[in, out] IpInstance Points to an IP6_PROTOCOL instance.
@param[in] Group The IP6 multicast address to remove.
@retval EFI_NOT_FOUND Cannot find the to be removed group address.
@retval EFI_SUCCESS The group address was successfully removed.
**/
EFI_STATUS
Ip6RemoveGroup (
IN OUT IP6_PROTOCOL *IpInstance,
IN EFI_IPv6_ADDRESS *Group
)
{
UINT32 Index;
UINT32 Count;
Count = IpInstance->GroupCount;
for (Index = 0; Index < Count; Index++) {
if (EFI_IP6_EQUAL (IpInstance->GroupList + Index, Group)) {
break;
}
}
if (Index == Count) {
return EFI_NOT_FOUND;
}
while (Index < Count - 1) {
IP6_COPY_ADDRESS (IpInstance->GroupList + Index, IpInstance->GroupList + Index + 1);
Index++;
}
ASSERT (IpInstance->GroupCount > 0);
IpInstance->GroupCount--;
return EFI_SUCCESS;
}
/**
Join the multicast group on behalf of this IP6 service binding instance.
@param[in] IpSb The IP6 service binding instance.
@param[in] Interface Points to an IP6_INTERFACE structure.
@param[in] Address The group address 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
Ip6JoinGroup (
IN IP6_SERVICE *IpSb,
IN IP6_INTERFACE *Interface,
IN EFI_IPv6_ADDRESS *Address
)
{
IP6_MLD_GROUP *Group;
EFI_STATUS Status;
Group = Ip6FindMldEntry (IpSb, Address);
if (Group != NULL) {
Group->RefCnt++;
return EFI_SUCCESS;
}
//
// Repeat the report once or twcie after short delays [Unsolicited Report Interval] (default:10s)
// Simulate this operation as a Multicast-Address-Specific Query was received for that addresss.
//
Group = Ip6CreateMldEntry (IpSb, Address, IP6_UNSOLICITED_REPORT_INTERVAL);
if (Group == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Group->SendByUs = TRUE;
Status = Ip6GetMulticastMac (IpSb->Mnp, Address, &Group->Mac);
if (EFI_ERROR (Status)) {
return Status;
}
Status = IpSb->Mnp->Groups (IpSb->Mnp, TRUE, &Group->Mac);
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
goto ERROR;
}
//
// Send unsolicited report when a node starts listening to a multicast address
//
Status = Ip6SendMldReport (IpSb, Interface, Address);
if (EFI_ERROR (Status)) {
goto ERROR;
}
return EFI_SUCCESS;
ERROR:
RemoveEntryList (&Group->Link);
FreePool (Group);
return Status;
}
/**
Leave the IP6 multicast group.
@param[in] IpSb The IP6 service binding instance.
@param[in] Address The group address to leave.
@retval EFI_NOT_FOUND The IP6 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
Ip6LeaveGroup (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Address
)
{
IP6_MLD_GROUP *Group;
EFI_STATUS Status;
Group = Ip6FindMldEntry (IpSb, 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) && (--Group->RefCnt > 0)) {
return EFI_SUCCESS;
}
//
// If multiple IP6 group addresses are mapped to the same
// multicast MAC address, don't configure the MNP to leave
// the MAC.
//
if (Ip6FindMac (&IpSb->MldCtrl, &Group->Mac) == 1) {
Status = IpSb->Mnp->Groups (IpSb->Mnp, FALSE, &Group->Mac);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
return Status;
}
}
//
// Send a leave report if we are the last node to report
//
if (Group->SendByUs) {
Status = Ip6SendMldDone (IpSb, Address);
if (EFI_ERROR (Status)) {
return Status;
}
}
RemoveEntryList (&Group->Link);
FreePool (Group);
return EFI_SUCCESS;
}
/**
Worker function for EfiIp6Groups(). The caller
should make sure that the parameters are valid.
@param[in] IpInstance The IP6 child to change the setting.
@param[in] JoinFlag TRUE to join the group, otherwise leave it.
@param[in] GroupAddress The target group address. If NULL, leave all
the group addresses.
@retval EFI_ALREADY_STARTED Wants to join the group, but is already a member of it
@retval EFI_OUT_OF_RESOURCES Failed to allocate sufficient 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
Ip6Groups (
IN IP6_PROTOCOL *IpInstance,
IN BOOLEAN JoinFlag,
IN EFI_IPv6_ADDRESS *GroupAddress OPTIONAL
)
{
EFI_STATUS Status;
IP6_SERVICE *IpSb;
UINT32 Index;
EFI_IPv6_ADDRESS *Group;
IpSb = IpInstance->Service;
if (JoinFlag) {
ASSERT (GroupAddress != NULL);
for (Index = 0; Index < IpInstance->GroupCount; Index++) {
if (EFI_IP6_EQUAL (IpInstance->GroupList + Index, GroupAddress)) {
return EFI_ALREADY_STARTED;
}
}
Status = Ip6JoinGroup (IpSb, IpInstance->Interface, GroupAddress);
if (!EFI_ERROR (Status)) {
return Ip6CombineGroups (IpInstance, GroupAddress);
}
return Status;
}
//
// Leave the group. Leave all the groups if GroupAddress is NULL.
//
for (Index = IpInstance->GroupCount; Index > 0; Index--) {
Group = IpInstance->GroupList + (Index - 1);
if ((GroupAddress == NULL) || EFI_IP6_EQUAL (Group, GroupAddress)) {
Status = Ip6LeaveGroup (IpInstance->Service, Group);
if (EFI_ERROR (Status)) {
return Status;
}
Ip6RemoveGroup (IpInstance, Group);
if (IpInstance->GroupCount == 0) {
ASSERT (Index == 1);
FreePool (IpInstance->GroupList);
IpInstance->GroupList = NULL;
}
if (GroupAddress != NULL) {
return EFI_SUCCESS;
}
}
}
return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);
}
/**
Set a random value of the delay timer for the multicast address from the range
[0, Maximum Response Delay]. If a timer for any address is already
running, it is reset to the new random value only if the requested
Maximum Response Delay is less than the remaining value of the
running timer. If the Query packet specifies a Maximum Response
Delay of zero, each timer is effectively set to zero, and the action
specified below for timer expiration is performed immediately.
@param[in] IpSb The IP6 service binding instance.
@param[in] MaxRespDelay The Maximum Response Delay, in milliseconds.
@param[in] MulticastAddr The multicast address.
@param[in, out] Group Points to a IP6_MLD_GROUP list entry node.
@retval EFI_SUCCESS The delay timer is successfully updated or
timer expiration is performed immediately.
@retval Others Failed to send out MLD report message.
**/
EFI_STATUS
Ip6UpdateDelayTimer (
IN IP6_SERVICE *IpSb,
IN UINT16 MaxRespDelay,
IN EFI_IPv6_ADDRESS *MulticastAddr,
IN OUT IP6_MLD_GROUP *Group
)
{
UINT32 Delay;
//
// If the Query packet specifies a Maximum Response Delay of zero, perform timer
// expiration immediately.
//
if (MaxRespDelay == 0) {
Group->DelayTimer = 0;
return Ip6SendMldReport (IpSb, NULL, MulticastAddr);
}
Delay = (UINT32) (MaxRespDelay / 1000);
//
// Sets a delay timer to a random value selected from the range [0, Maximum Response Delay]
// If a timer is already running, resets it if the request Maximum Response Delay
// is less than the remaining value of the running timer.
//
if (Group->DelayTimer == 0 || Delay < Group->DelayTimer) {
Group->DelayTimer = Delay / 4294967295UL * NET_RANDOM (NetRandomInitSeed ());
}
return EFI_SUCCESS;
}
/**
Process the Multicast Listener Query message.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the MLD query packet.
@param[in] Packet The content of the MLD query packet with IP head
removed.
@retval EFI_SUCCESS The MLD query packet processed successfully.
@retval EFI_INVALID_PARAMETER The packet is invalid.
@retval Others Failed to process the packet.
**/
EFI_STATUS
Ip6ProcessMldQuery (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
)
{
EFI_IPv6_ADDRESS AllNodes;
IP6_MLD_GROUP *Group;
IP6_MLD_HEAD MldPacket;
LIST_ENTRY *Entry;
EFI_STATUS Status;
Status = EFI_INVALID_PARAMETER;
//
// Check the validity of the packet, generic query or specific query
//
if (!NetIp6IsUnspecifiedAddr (&Head->SourceAddress) && !NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
goto Exit;
}
if (Head->HopLimit != 1 || !IP6_IS_MULTICAST (&Head->DestinationAddress)) {
goto Exit;
}
//
// The Packet points to MLD report raw data without Hop-By-Hop option.
//
NetbufCopy (Packet, 0, sizeof (IP6_MLD_HEAD), (UINT8 *) &MldPacket);
MldPacket.MaxRespDelay = NTOHS (MldPacket.MaxRespDelay);
Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &AllNodes);
if (!EFI_IP6_EQUAL (&Head->DestinationAddress, &AllNodes)) {
//
// Receives a Multicast-Address-Specific Query, check it firstly
//
if (!EFI_IP6_EQUAL (&Head->DestinationAddress, &MldPacket.Group)) {
goto Exit;
}
//
// The node is not listening but it receives the specific query. Just return.
//
Group = Ip6FindMldEntry (IpSb, &MldPacket.Group);
if (Group == NULL) {
Status = EFI_SUCCESS;
goto Exit;
}
Status = Ip6UpdateDelayTimer (
IpSb,
MldPacket.MaxRespDelay,
&MldPacket.Group,
Group
);
goto Exit;
}
//
// Receives a General Query, sets a delay timer for each multicast address it is listening
//
NET_LIST_FOR_EACH (Entry, &IpSb->MldCtrl.Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IP6_MLD_GROUP, Link);
Status = Ip6UpdateDelayTimer (IpSb, MldPacket.MaxRespDelay, &Group->Address, Group);
if (EFI_ERROR (Status)) {
goto Exit;
}
}
Status = EFI_SUCCESS;
Exit:
NetbufFree (Packet);
return Status;
}
/**
Process the Multicast Listener Report message.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the MLD report packet.
@param[in] Packet The content of the MLD report packet with IP head
removed.
@retval EFI_SUCCESS The MLD report packet processed successfully.
@retval EFI_INVALID_PARAMETER The packet is invalid.
**/
EFI_STATUS
Ip6ProcessMldReport (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
)
{
IP6_MLD_HEAD MldPacket;
IP6_MLD_GROUP *Group;
EFI_STATUS Status;
Status = EFI_INVALID_PARAMETER;
//
// Validate the incoming message, if invalid, drop it.
//
if (!NetIp6IsUnspecifiedAddr (&Head->SourceAddress) && !NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
goto Exit;
}
if (Head->HopLimit != 1 || !IP6_IS_MULTICAST (&Head->DestinationAddress)) {
goto Exit;
}
//
// The Packet points to MLD report raw data without Hop-By-Hop option.
//
NetbufCopy (Packet, 0, sizeof (IP6_MLD_HEAD), (UINT8 *) &MldPacket);
if (!EFI_IP6_EQUAL (&Head->DestinationAddress, &MldPacket.Group)) {
goto Exit;
}
Group = Ip6FindMldEntry (IpSb, &MldPacket.Group);
if (Group == NULL) {
goto Exit;
}
//
// The report is sent by another node, stop its own timer relates to the multicast address and clear
//
if (!Group->SendByUs) {
Group->DelayTimer = 0;
}
Status = EFI_SUCCESS;
Exit:
NetbufFree (Packet);
return Status;
}
/**
The heartbeat timer of MLD module. It sends out a solicited MLD report when
DelayTimer expires.
@param[in] IpSb The IP6 service binding instance.
**/
VOID
Ip6MldTimerTicking (
IN IP6_SERVICE *IpSb
)
{
IP6_MLD_GROUP *Group;
LIST_ENTRY *Entry;
//
// Send solicited report when timer expires
//
NET_LIST_FOR_EACH (Entry, &IpSb->MldCtrl.Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IP6_MLD_GROUP, Link);
if ((Group->DelayTimer > 0) && (--Group->DelayTimer == 0)) {
Ip6SendMldReport (IpSb, NULL, &Group->Address);
}
}
}

198
NetworkPkg/Ip6Dxe/Ip6Mld.h Normal file
View File

@@ -0,0 +1,198 @@
/** @file
Multicast Listener Discovery support routines.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_MLD_H__
#define __EFI_IP6_MLD_H__
#define IP6_UNSOLICITED_REPORT_INTERVAL 10
#pragma pack(1)
typedef struct {
IP6_ICMP_HEAD Head;
UINT16 MaxRespDelay;
UINT16 Reserved;
EFI_IPv6_ADDRESS Group;
} IP6_MLD_HEAD;
#pragma pack()
//
// The status of multicast group. It isn't necessary to maintain
// explicit state of host state diagram. A group with finity
// DelayTime (less than 0xffffffff) is in "delaying listener" state. otherwise, it is in
// "idle listener" state.
//
typedef struct {
LIST_ENTRY Link;
INTN RefCnt;
EFI_IPv6_ADDRESS Address;
UINT32 DelayTimer;
BOOLEAN SendByUs;
EFI_MAC_ADDRESS Mac;
} IP6_MLD_GROUP;
//
// The MLD status. Each IP6 service instance has a MLD_SERVICE_DATA
// attached. The Mldv1QuerySeen remember whether the server on this
// connected network is v1 or v2.
//
typedef struct {
INTN Mldv1QuerySeen;
LIST_ENTRY Groups;
} IP6_MLD_SERVICE_DATA;
/**
Search a IP6_MLD_GROUP list entry node from a list array.
@param[in] IpSb Points to an IP6 service binding instance.
@param[in] MulticastAddr The IPv6 multicast address to be searched.
@return The found IP6_ML_GROUP list entry or NULL.
**/
IP6_MLD_GROUP *
Ip6FindMldEntry (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *MulticastAddr
);
/**
Init the MLD data of the IP6 service instance, configure
MNP to receive ALL SYSTEM multicasts.
@param[in] IpSb The IP6 service whose MLD is to be initialized.
@retval EFI_OUT_OF_RESOURCES There are not sufficient resources to complete the
operation.
@retval EFI_SUCCESS The MLD module successfully initialized.
**/
EFI_STATUS
Ip6InitMld (
IN IP6_SERVICE *IpSb
);
/**
Join the multicast group on behalf of this IP6 service binding instance.
@param[in] IpSb The IP6 service binding instance.
@param[in] Interface Points to an IP6_INTERFACE structure.
@param[in] Address The group address to join.
@retval EFI_SUCCESS Successfully joined the multicast group.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
@retval Others Failed to join the multicast group.
**/
EFI_STATUS
Ip6JoinGroup (
IN IP6_SERVICE *IpSb,
IN IP6_INTERFACE *Interface,
IN EFI_IPv6_ADDRESS *Address
);
/**
Leave the IP6 multicast group.
@param[in] IpSb The IP6 service binding instance.
@param[in] Address The group address to leave.
@retval EFI_NOT_FOUND The IP6 service instance isn't in the group.
@retval EFI_SUCCESS Successfully left the multicast group.
@retval Others Failed to leave the multicast group.
**/
EFI_STATUS
Ip6LeaveGroup (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Address
);
/**
Worker function for EfiIp6Groups(). The caller
should verify that the parameters are valid.
@param[in] IpInstance The IP6 child to change the setting.
@param[in] JoinFlag TRUE to join the group, otherwise leave it.
@param[in] GroupAddress The target group address. If NULL, leave all
the group addresses.
@retval EFI_ALREADY_STARTED Wants to join the group, but is 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 Tried to leave a group of whom it isn't a member.
**/
EFI_STATUS
Ip6Groups (
IN IP6_PROTOCOL *IpInstance,
IN BOOLEAN JoinFlag,
IN EFI_IPv6_ADDRESS *GroupAddress OPTIONAL
);
/**
Process the Multicast Listener Query message.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the MLD query packet.
@param[in] Packet The content of the MLD query packet with IP head
removed.
@retval EFI_SUCCESS The MLD query packet processed successfully.
@retval EFI_INVALID_PARAMETER The packet is invalid.
@retval Others Failed to process the packet.
**/
EFI_STATUS
Ip6ProcessMldQuery (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
);
/**
Process the Multicast Listener Report message.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the MLD report packet.
@param[in] Packet The content of the MLD report packet with IP head
removed.
@retval EFI_SUCCESS The MLD report packet processed successfully.
@retval EFI_INVALID_PARAMETER The packet is invalid.
**/
EFI_STATUS
Ip6ProcessMldReport (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
);
/**
The heartbeat timer of the MLD module. It sends out solicited MLD report when
DelayTimer expires.
@param[in] IpSb The IP6 service binding instance.
**/
VOID
Ip6MldTimerTicking (
IN IP6_SERVICE *IpSb
);
#endif

3141
NetworkPkg/Ip6Dxe/Ip6Nd.c Normal file

File diff suppressed because it is too large Load Diff

750
NetworkPkg/Ip6Dxe/Ip6Nd.h Normal file
View File

@@ -0,0 +1,750 @@
/** @file
Definition of Neighbor Discovery support routines.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_ND_H__
#define __EFI_IP6_ND_H__
#define IP6_GET_TICKS(Ms) (((Ms) + IP6_TIMER_INTERVAL_IN_MS - 1) / IP6_TIMER_INTERVAL_IN_MS)
enum {
IP6_INF_ROUTER_LIFETIME = 0xFFFF,
IP6_MAX_RTR_SOLICITATION_DELAY = 1000, ///< 1000 milliseconds
IP6_MAX_RTR_SOLICITATIONS = 3,
IP6_RTR_SOLICITATION_INTERVAL = 4000,
IP6_MIN_RANDOM_FACTOR_SCALED = 1,
IP6_MAX_RANDOM_FACTOR_SCALED = 3,
IP6_RANDOM_FACTOR_SCALE = 2,
IP6_MAX_MULTICAST_SOLICIT = 3,
IP6_MAX_UNICAST_SOLICIT = 3,
IP6_MAX_ANYCAST_DELAY_TIME = 1,
IP6_MAX_NEIGHBOR_ADV = 3,
IP6_REACHABLE_TIME = 30000,
IP6_RETRANS_TIMER = 1000,
IP6_DELAY_FIRST_PROBE_TIME = 5000,
IP6_MIN_LINK_MTU = 1280,
IP6_MAX_LINK_MTU = 1500,
IP6_IS_ROUTER_FLAG = 0x80,
IP6_SOLICITED_FLAG = 0x40,
IP6_OVERRIDE_FLAG = 0x20,
IP6_M_ADDR_CONFIG_FLAG = 0x80,
IP6_O_CONFIG_FLAG = 0x40,
IP6_ON_LINK_FLAG = 0x80,
IP6_AUTO_CONFIG_FLAG = 0x40,
IP6_ND_LENGTH = 24,
IP6_RA_LENGTH = 16,
IP6_REDITECT_LENGTH = 40,
IP6_DAD_ENTRY_SIGNATURE = SIGNATURE_32 ('I', 'P', 'D', 'E')
};
typedef
VOID
(*IP6_ARP_CALLBACK) (
VOID *Context
);
typedef struct _IP6_ETHE_ADDR_OPTION {
UINT8 Type;
UINT8 Length;
UINT8 EtherAddr[6];
} IP6_ETHER_ADDR_OPTION;
typedef struct _IP6_MTU_OPTION {
UINT8 Type;
UINT8 Length;
UINT16 Reserved;
UINT32 Mtu;
} IP6_MTU_OPTION;
typedef struct _IP6_PREFIX_INFO_OPTION {
UINT8 Type;
UINT8 Length;
UINT8 PrefixLength;
UINT8 Reserved1;
UINT32 ValidLifetime;
UINT32 PreferredLifetime;
UINT32 Reserved2;
EFI_IPv6_ADDRESS Prefix;
} IP6_PREFIX_INFO_OPTION;
typedef
VOID
(*IP6_DAD_CALLBACK) (
IN BOOLEAN IsDadPassed,
IN EFI_IPv6_ADDRESS *TargetAddress,
IN VOID *Context
);
typedef struct _IP6_DAD_ENTRY {
UINT32 Signature;
LIST_ENTRY Link;
UINT32 MaxTransmit;
UINT32 Transmit;
UINT32 Receive;
UINT32 RetransTick;
IP6_ADDRESS_INFO *AddressInfo;
EFI_IPv6_ADDRESS Destination;
IP6_DAD_CALLBACK Callback;
VOID *Context;
} IP6_DAD_ENTRY;
typedef struct _IP6_DELAY_JOIN_LIST {
LIST_ENTRY Link;
UINT32 DelayTime; ///< in tick per 50 milliseconds
IP6_INTERFACE *Interface;
IP6_ADDRESS_INFO *AddressInfo;
IP6_DAD_CALLBACK DadCallback;
VOID *Context;
} IP6_DELAY_JOIN_LIST;
typedef struct _IP6_NEIGHBOR_ENTRY {
LIST_ENTRY Link;
LIST_ENTRY ArpList;
INTN RefCnt;
BOOLEAN IsRouter;
BOOLEAN ArpFree;
BOOLEAN Dynamic;
EFI_IPv6_ADDRESS Neighbor;
EFI_MAC_ADDRESS LinkAddress;
EFI_IP6_NEIGHBOR_STATE State;
UINT32 Transmit;
UINT32 Ticks;
LIST_ENTRY Frames;
IP6_INTERFACE *Interface;
IP6_ARP_CALLBACK CallBack;
} IP6_NEIGHBOR_ENTRY;
typedef struct _IP6_DEFAULT_ROUTER {
LIST_ENTRY Link;
INTN RefCnt;
UINT16 Lifetime;
EFI_IPv6_ADDRESS Router;
IP6_NEIGHBOR_ENTRY *NeighborCache;
} IP6_DEFAULT_ROUTER;
typedef struct _IP6_PREFIX_LIST_ENTRY {
LIST_ENTRY Link;
INTN RefCnt;
UINT32 ValidLifetime;
UINT32 PreferredLifetime;
UINT8 PrefixLength;
EFI_IPv6_ADDRESS Prefix;
} IP6_PREFIX_LIST_ENTRY;
/**
Build a array of EFI_IP6_NEIGHBOR_CACHE to be returned to the caller. The number
of EFI_IP6_NEIGHBOR_CACHE is also returned.
@param[in] IpInstance The pointer to IP6_PROTOCOL instance.
@param[out] NeighborCount The number of returned neighbor cache entries.
@param[out] NeighborCache The pointer to the array of EFI_IP6_NEIGHBOR_CACHE.
@retval EFI_SUCCESS The EFI_IP6_NEIGHBOR_CACHE successfully built.
@retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the route table.
**/
EFI_STATUS
Ip6BuildEfiNeighborCache (
IN IP6_PROTOCOL *IpInstance,
OUT UINT32 *NeighborCount,
OUT EFI_IP6_NEIGHBOR_CACHE **NeighborCache
);
/**
Build a array of EFI_IP6_ADDRESS_INFO to be returned to the caller. The number
of prefix entries is also returned.
@param[in] IpInstance The pointer to IP6_PROTOCOL instance.
@param[out] PrefixCount The number of returned prefix entries.
@param[out] PrefixTable The pointer to the array of PrefixTable.
@retval EFI_SUCCESS The prefix table successfully built.
@retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the prefix table.
**/
EFI_STATUS
Ip6BuildPrefixTable (
IN IP6_PROTOCOL *IpInstance,
OUT UINT32 *PrefixCount,
OUT EFI_IP6_ADDRESS_INFO **PrefixTable
);
/**
Allocate and initialize an IP6 default router entry.
@param[in] IpSb The pointer to the IP6_SERVICE instance.
@param[in] Ip6Address The IPv6 address of the default router.
@param[in] RouterLifetime The lifetime associated with the default
router, in units of seconds.
@return NULL if it failed to allocate memory for the default router node.
Otherwise, point to the created default router node.
**/
IP6_DEFAULT_ROUTER *
Ip6CreateDefaultRouter (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Ip6Address,
IN UINT16 RouterLifetime
);
/**
Destroy an IP6 default router entry.
@param[in] IpSb The pointer to the IP6_SERVICE instance.
@param[in] DefaultRouter The to be destroyed IP6_DEFAULT_ROUTER.
**/
VOID
Ip6DestroyDefaultRouter (
IN IP6_SERVICE *IpSb,
IN IP6_DEFAULT_ROUTER *DefaultRouter
);
/**
Clean an IP6 default router list.
@param[in] IpSb The pointer to the IP6_SERVICE instance.
@param[in] DefaultRouter The to be destroyed IP6_DEFAULT_ROUTER.
**/
VOID
Ip6CleanDefaultRouterList (
IN IP6_SERVICE *IpSb
);
/**
Search a default router node from an IP6 default router list.
@param[in] IpSb The pointer to the IP6_SERVICE instance.
@param[in] Ip6Address The IPv6 address of the to be searched default router node.
@return NULL if it failed to find the matching default router node.
Otherwise, point to the found default router node.
**/
IP6_DEFAULT_ROUTER *
Ip6FindDefaultRouter (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Ip6Address
);
/**
The function to be called after DAD (Duplicate Address Detection) is performed.
@param[in] IsDadPassed If TRUE, the DAD operation succeed. Otherwise, the DAD operation failed.
@param[in] IpIf Points to the IP6_INTERFACE.
@param[in] DadEntry The DAD entry which already performed DAD.
**/
VOID
Ip6OnDADFinished (
IN BOOLEAN IsDadPassed,
IN IP6_INTERFACE *IpIf,
IN IP6_DAD_ENTRY *DadEntry
);
/**
Create a DAD (Duplicate Address Detection) entry and queue it to be performed.
@param[in] IpIf Points to the IP6_INTERFACE.
@param[in] AddressInfo The address information which needs DAD performed.
@param[in] Callback The callback routine that will be called after DAD
is performed. This is an optional parameter that
may be NULL.
@param[in] Context The opaque parameter for a DAD callback routine.
This is an optional parameter that may be NULL.
@retval EFI_SUCCESS The DAD entry was created and queued.
@retval EFI_OUT_OF_RESOURCES Failed to allocate the memory to complete the
operation.
**/
EFI_STATUS
Ip6InitDADProcess (
IN IP6_INTERFACE *IpIf,
IN IP6_ADDRESS_INFO *AddressInfo,
IN IP6_DAD_CALLBACK Callback OPTIONAL,
IN VOID *Context OPTIONAL
);
/**
Search IP6_DAD_ENTRY from the Duplicate Address Detection List.
@param[in] IpSb The pointer to the IP6_SERVICE instance.
@param[in] Target The address information which needs DAD performed .
@param[out] Interface If not NULL, output the IP6 interface that configures
the tentative address.
@return NULL if failed to find the matching DAD entry.
Otherwise, point to the found DAD entry.
**/
IP6_DAD_ENTRY *
Ip6FindDADEntry (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Target,
OUT IP6_INTERFACE **Interface OPTIONAL
);
/**
Allocate and initialize a IP6 prefix list entry.
@param[in] IpSb The pointer to IP6_SERVICE instance.
@param[in] OnLinkOrAuto If TRUE, the entry is created for the on link prefix list.
Otherwise, it is created for the autoconfiguration prefix list.
@param[in] ValidLifetime The length of time in seconds that the prefix
is valid for the purpose of on-link determination.
@param[in] PreferredLifetime The length of time in seconds that addresses
generated from the prefix via stateless address
autoconfiguration remain preferred.
@param[in] PrefixLength The prefix length of the Prefix.
@param[in] Prefix The prefix address.
@return NULL if it failed to allocate memory for the prefix node. Otherwise, point
to the created or existing prefix list entry.
**/
IP6_PREFIX_LIST_ENTRY *
Ip6CreatePrefixListEntry (
IN IP6_SERVICE *IpSb,
IN BOOLEAN OnLinkOrAuto,
IN UINT32 ValidLifetime,
IN UINT32 PreferredLifetime,
IN UINT8 PrefixLength,
IN EFI_IPv6_ADDRESS *Prefix
);
/**
Destory a IP6 prefix list entry.
@param[in] IpSb The pointer to IP6_SERVICE instance.
@param[in] PrefixEntry The to be destroyed prefix list entry.
@param[in] OnLinkOrAuto If TRUE, the entry is removed from on link prefix list.
Otherwise remove from autoconfiguration prefix list.
@param[in] ImmediateDelete If TRUE, remove the entry directly.
Otherwise, check the reference count to see whether
it should be removed.
**/
VOID
Ip6DestroyPrefixListEntry (
IN IP6_SERVICE *IpSb,
IN IP6_PREFIX_LIST_ENTRY *PrefixEntry,
IN BOOLEAN OnLinkOrAuto,
IN BOOLEAN ImmediateDelete
);
/**
Search the list array to find an IP6 prefix list entry.
@param[in] IpSb The pointer to IP6_SERVICE instance.
@param[in] OnLinkOrAuto If TRUE, the search the link prefix list,
Otherwise search the autoconfiguration prefix list.
@param[in] PrefixLength The prefix length of the Prefix
@param[in] Prefix The prefix address.
@return NULL if cannot find the IP6 prefix list entry. Otherwise, return the
pointer to the IP6 prefix list entry.
**/
IP6_PREFIX_LIST_ENTRY *
Ip6FindPrefixListEntry (
IN IP6_SERVICE *IpSb,
IN BOOLEAN OnLinkOrAuto,
IN UINT8 PrefixLength,
IN EFI_IPv6_ADDRESS *Prefix
);
/**
Release the resource in prefix list table, and destroy the list entry and
corresponding addresses or route entries.
@param[in] IpSb The pointer to the IP6_SERVICE instance.
@param[in] ListHead The list entry head of the prefix list table.
**/
VOID
Ip6CleanPrefixListTable (
IN IP6_SERVICE *IpSb,
IN LIST_ENTRY *ListHead
);
/**
Allocate and initialize an IP6 neighbor cache entry.
@param[in] IpSb The pointer to the IP6_SERVICE instance.
@param[in] CallBack The callback function to be called when
address resolution is finished.
@param[in] Ip6Address Points to the IPv6 address of the neighbor.
@param[in] LinkAddress Points to the MAC address of the neighbor.
Ignored if NULL.
@return NULL if failed to allocate memory for the neighbor cache entry.
Otherwise, point to the created neighbor cache entry.
**/
IP6_NEIGHBOR_ENTRY *
Ip6CreateNeighborEntry (
IN IP6_SERVICE *IpSb,
IN IP6_ARP_CALLBACK CallBack,
IN EFI_IPv6_ADDRESS *Ip6Address,
IN EFI_MAC_ADDRESS *LinkAddress OPTIONAL
);
/**
Search a IP6 neighbor cache entry.
@param[in] IpSb The pointer to the IP6_SERVICE instance.
@param[in] Ip6Address Points to the IPv6 address of the neighbor.
@return NULL if it failed to find the matching neighbor cache entry.
Otherwise, point to the found neighbor cache entry.
**/
IP6_NEIGHBOR_ENTRY *
Ip6FindNeighborEntry (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Ip6Address
);
/**
Free a IP6 neighbor cache entry and remove all the frames on the address
resolution queue that pass the FrameToCancel. That is, either FrameToCancel
is NULL, or it returns true for the frame.
@param[in] IpSb The pointer to the IP6_SERVICE instance.
@param[in] NeighborCache The to be free neighbor cache entry.
@param[in] SendIcmpError If TRUE, send out ICMP error.
@param[in] FullFree If TRUE, remove the neighbor cache entry.
Otherwise remove the pending frames.
@param[in] IoStatus The status returned to the cancelled frames'
callback function.
@param[in] FrameToCancel Function to select which frame to cancel.
This is an optional parameter that may be NULL.
@param[in] Context Opaque parameter to the FrameToCancel.
Ignored if FrameToCancel is NULL.
@retval EFI_INVALID_PARAMETER The input parameter is invalid.
@retval EFI_SUCCESS The operation finished successfully.
**/
EFI_STATUS
Ip6FreeNeighborEntry (
IN IP6_SERVICE *IpSb,
IN IP6_NEIGHBOR_ENTRY *NeighborCache,
IN BOOLEAN SendIcmpError,
IN BOOLEAN FullFree,
IN EFI_STATUS IoStatus,
IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL,
IN VOID *Context OPTIONAL
);
/**
Add Neighbor cache entries. It is a work function for EfiIp6Neighbors().
@param[in] IpSb The IP6 service binding instance.
@param[in] TargetIp6Address Pointer to Target IPv6 address.
@param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
@param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
cache. It will be deleted after Timeout. A value of zero means that
the entry is permanent. A non-zero value means that the entry is
dynamic.
@param[in] Override If TRUE, the cached link-layer address of the matching entry will
be overridden and updated; if FALSE, and if a
corresponding cache entry already existed, EFI_ACCESS_DENIED
will be returned.
@retval EFI_SUCCESS The neighbor cache entry has been added.
@retval EFI_OUT_OF_RESOURCES Could not add the entry to the neighbor cache
due to insufficient resources.
@retval EFI_NOT_FOUND TargetLinkAddress is NULL.
@retval EFI_ACCESS_DENIED The to-be-added entry is already defined in the neighbor cache,
and that entry is tagged as un-overridden (when DeleteFlag
is FALSE).
**/
EFI_STATUS
Ip6AddNeighbor (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *TargetIp6Address,
IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL,
IN UINT32 Timeout,
IN BOOLEAN Override
);
/**
Delete or update Neighbor cache entries. It is a work function for EfiIp6Neighbors().
@param[in] IpSb The IP6 service binding instance.
@param[in] TargetIp6Address Pointer to Target IPv6 address.
@param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
@param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
cache. It will be deleted after Timeout. A value of zero means that
the entry is permanent. A non-zero value means that the entry is
dynamic.
@param[in] Override If TRUE, the cached link-layer address of the matching entry will
be overridden and updated; if FALSE, and if a
corresponding cache entry already existed, EFI_ACCESS_DENIED
will be returned.
@retval EFI_SUCCESS The neighbor cache entry has been updated or deleted.
@retval EFI_NOT_FOUND This entry is not in the neighbor cache.
**/
EFI_STATUS
Ip6DelNeighbor (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *TargetIp6Address,
IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL,
IN UINT32 Timeout,
IN BOOLEAN Override
);
/**
Process the Neighbor Solicitation message. The message may be sent for Duplicate
Address Detection or Address Resolution.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the message.
@param[in] Packet The content of the message with IP head removed.
@retval EFI_SUCCESS The packet processed successfully.
@retval EFI_INVALID_PARAMETER The packet is invalid.
@retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
@retval Others Failed to process the packet.
**/
EFI_STATUS
Ip6ProcessNeighborSolicit (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
);
/**
Process the Neighbor Advertisement message.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the message.
@param[in] Packet The content of the message with IP head removed.
@retval EFI_SUCCESS The packet processed successfully.
@retval EFI_INVALID_PARAMETER The packet is invalid.
@retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
@retval Others Failed to process the packet.
**/
EFI_STATUS
Ip6ProcessNeighborAdvertise (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
);
/**
Process the Router Advertisement message according to RFC4861.
@param[in] IpSb The IP service that received the packet.
@param[in] Head The IP head of the message.
@param[in] Packet The content of the message with the IP head removed.
@retval EFI_SUCCESS The packet processed successfully.
@retval EFI_INVALID_PARAMETER The packet is invalid.
@retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the operation.
@retval Others Failed to process the packet.
**/
EFI_STATUS
Ip6ProcessRouterAdvertise (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
);
/**
Process the ICMPv6 redirect message. Find the instance, then update
its route cache.
@param[in] IpSb The IP6 service binding instance that received
the packet.
@param[in] Head The IP head of the received ICMPv6 packet.
@param[in] Packet The content of the ICMPv6 redirect packet with
the IP head removed.
@retval EFI_INVALID_PARAMETER The parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Insuffcient resources to complete the
operation.
@retval EFI_SUCCESS Successfully updated the route caches.
**/
EFI_STATUS
Ip6ProcessRedirect (
IN IP6_SERVICE *IpSb,
IN EFI_IP6_HEADER *Head,
IN NET_BUF *Packet
);
/**
Generate router solicit message and send it out to Destination Address or
All Router Link Local scope multicast address.
@param[in] IpSb The IP service to send the packet.
@param[in] Interface If not NULL, points to the IP6 interface to send
the packet.
@param[in] SourceAddress If not NULL, the source address of the message.
@param[in] DestinationAddress If not NULL, the destination address of the message.
@param[in] SourceLinkAddress If not NULL, the MAC address of the source.
A source link-layer address option will be appended
to the message.
@retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the operation.
@retval EFI_SUCCESS The router solicit message was successfully sent.
**/
EFI_STATUS
Ip6SendRouterSolicit (
IN IP6_SERVICE *IpSb,
IN IP6_INTERFACE *Interface OPTIONAL,
IN EFI_IPv6_ADDRESS *SourceAddress OPTIONAL,
IN EFI_IPv6_ADDRESS *DestinationAddress OPTIONAL,
IN EFI_MAC_ADDRESS *SourceLinkAddress OPTIONAL
);
/**
Generate the Neighbor Solicitation message and send it to the Destination Address.
@param[in] IpSb The IP service to send the packet
@param[in] SourceAddress The source address of the message.
@param[in] DestinationAddress The destination address of the message.
@param[in] TargetIp6Address The IP address of the target of the solicitation.
It must not be a multicast address.
@param[in] SourceLinkAddress The MAC address for the sender. If not NULL,
a source link-layer address option will be appended
to the message.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
operation.
@retval EFI_SUCCESS The Neighbor Advertise message was successfully sent.
**/
EFI_STATUS
Ip6SendNeighborSolicit (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *SourceAddress,
IN EFI_IPv6_ADDRESS *DestinationAddress,
IN EFI_IPv6_ADDRESS *TargetIp6Address,
IN EFI_MAC_ADDRESS *SourceLinkAddress OPTIONAL
);
/**
Set the interface's address. This will trigger the DAD process for the
address to set. To set an already set address, the lifetimes wil be
updated to the new value passed in.
@param[in] Interface The interface to set the address.
@param[in] Ip6Addr The interface's to be assigned IPv6 address.
@param[in] IsAnycast If TRUE, the unicast IPv6 address is anycast.
Otherwise, it is not anycast.
@param[in] PrefixLength The prefix length of the Ip6Addr.
@param[in] ValidLifetime The valid lifetime for this address.
@param[in] PreferredLifetime The preferred lifetime for this address.
@param[in] DadCallback The caller's callback to trigger when DAD finishes.
This is an optional parameter that may be NULL.
@param[in] Context The context that will be passed to DadCallback.
This is an optional parameter that may be NULL.
@retval EFI_SUCCESS The interface is scheduled to be configured with
the specified address.
@retval EFI_OUT_OF_RESOURCES Failed to set the interface's address due to
lack of resources.
**/
EFI_STATUS
Ip6SetAddress (
IN IP6_INTERFACE *Interface,
IN EFI_IPv6_ADDRESS *Ip6Addr,
IN BOOLEAN IsAnycast,
IN UINT8 PrefixLength,
IN UINT32 ValidLifetime,
IN UINT32 PreferredLifetime,
IN IP6_DAD_CALLBACK DadCallback OPTIONAL,
IN VOID *Context OPTIONAL
);
/**
The heartbeat timer of ND module in IP6_TIMER_INTERVAL_IN_MS milliseconds.
This time routine handles DAD module and neighbor state transition.
It is also responsible for sending out router solicitations.
@param[in] Event The IP6 service instance's heartbeat timer.
@param[in] Context The IP6 service instance.
**/
VOID
EFIAPI
Ip6NdFasterTimerTicking (
IN EFI_EVENT Event,
IN VOID *Context
);
/**
The heartbeat timer of ND module in 1 second. This time routine handles following
things: 1) maitain default router list; 2) maintain prefix options;
3) maintain route caches.
@param[in] IpSb The IP6 service binding instance.
**/
VOID
Ip6NdTimerTicking (
IN IP6_SERVICE *IpSb
);
/**
Callback function when address resolution is finished. It will cancel
all the queued frames if the address resolution failed, or transmit them
if the request succeeded.
@param[in] Context The context of the callback, a pointer to IP6_NEIGHBOR_ENTRY.
**/
VOID
Ip6OnArpResolved (
IN VOID *Context
);
/**
Update the ReachableTime in IP6 service binding instance data, in milliseconds.
@param[in, out] IpSb Points to the IP6_SERVICE.
**/
VOID
Ip6UpdateReachableTime (
IN OUT IP6_SERVICE *IpSb
);
#endif

View File

@@ -0,0 +1,70 @@
/** @file
NVData structure used by the IP6 configuration component.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _IP6_NV_DATA_H_
#define _IP6_NV_DATA_H_
#define IP6_CONFIG_NVDATA_GUID \
{ \
0x2eea107, 0x98db, 0x400e, { 0x98, 0x30, 0x46, 0xa, 0x15, 0x42, 0xd7, 0x99 } \
}
#define FORMID_MAIN_FORM 1
#define FORMID_MANUAL_CONFIG_FORM 2
#define IP6_POLICY_AUTO 0
#define IP6_POLICY_MANUAL 1
#define DAD_MAX_TRANSMIT_COUNT 10
#define KEY_INTERFACE_ID 0x101
#define KEY_MANUAL_ADDRESS 0x102
#define KEY_GATEWAY_ADDRESS 0x103
#define KEY_DNS_ADDRESS 0x104
#define KEY_SAVE_CHANGES 0x105
#define KEY_SAVE_CONFIG_CHANGES 0x106
#define KEY_IGNORE_CONFIG_CHANGES 0x107
#define HOST_ADDRESS_LABEL 0x9000
#define ROUTE_TABLE_LABEL 0xa000
#define GATEWAY_ADDRESS_LABEL 0xb000
#define DNS_ADDRESS_LABEL 0xc000
#define LABEL_END 0xffff
#define INTERFACE_ID_STR_MIN_SIZE 1
#define INTERFACE_ID_STR_MAX_SIZE 23
#define INTERFACE_ID_STR_STORAGE 24
#define IP6_STR_MAX_SIZE 40
#define ADDRESS_STR_MIN_SIZE 2
#define ADDRESS_STR_MAX_SIZE 255
///
/// IP6_CONFIG_IFR_NVDATA contains the IP6 configure
/// parameters for that NIC.
///
#pragma pack(1)
typedef struct {
UINT8 IfType; ///< interface type
UINT8 Padding[3];
UINT32 Policy; ///< manual or automatic
UINT32 DadTransmitCount; ///< dad transmits count
CHAR16 InterfaceId[INTERFACE_ID_STR_STORAGE]; ///< alternative interface id
CHAR16 ManualAddress[ADDRESS_STR_MAX_SIZE]; ///< IP addresses
CHAR16 GatewayAddress[ADDRESS_STR_MAX_SIZE]; ///< Gateway address
CHAR16 DnsAddress[ADDRESS_STR_MAX_SIZE]; ///< DNS server address
} IP6_CONFIG_IFR_NVDATA;
#pragma pack()
#endif

View File

@@ -0,0 +1,758 @@
/** @file
IP6 option support functions and routines.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ip6Impl.h"
/**
Validate the IP6 option format for both the packets we received
and that we will transmit. It will compute the ICMPv6 error message fields
if the option is malformated.
@param[in] IpSb The IP6 service data.
@param[in] Packet The to be validated packet.
@param[in] Option The first byte of the option.
@param[in] OptionLen The length of the whole option.
@param[in] Pointer Identifies the octet offset within
the invoking packet where the error was detected.
@retval TRUE The option is properly formatted.
@retval FALSE The option is malformated.
**/
BOOLEAN
Ip6IsOptionValid (
IN IP6_SERVICE *IpSb,
IN NET_BUF *Packet,
IN UINT8 *Option,
IN UINT8 OptionLen,
IN UINT32 Pointer
)
{
UINT8 Offset;
UINT8 OptionType;
Offset = 0;
while (Offset < OptionLen) {
OptionType = *(Option + Offset);
switch (OptionType) {
case Ip6OptionPad1:
//
// It is a Pad1 option
//
Offset++;
break;
case Ip6OptionPadN:
//
// It is a PadN option
//
Offset = (UINT8) (Offset + *(Option + Offset + 1) + 2);
break;
case Ip6OptionRouterAlert:
//
// It is a Router Alert Option
//
Offset += 4;
break;
default:
//
// The highest-order two bits specify the action must be taken if
// the processing IPv6 node does not recognize the option type.
//
switch (OptionType & Ip6OptionMask) {
case Ip6OptionSkip:
Offset = (UINT8) (Offset + *(Option + Offset + 1));
break;
case Ip6OptionDiscard:
return FALSE;
case Ip6OptionParameterProblem:
Pointer = Pointer + Offset + sizeof (EFI_IP6_HEADER);
Ip6SendIcmpError (
IpSb,
Packet,
NULL,
&Packet->Ip.Ip6->SourceAddress,
ICMP_V6_PARAMETER_PROBLEM,
2,
&Pointer
);
return FALSE;
case Ip6OptionMask:
if (!IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress)) {
Pointer = Pointer + Offset + sizeof (EFI_IP6_HEADER);
Ip6SendIcmpError (
IpSb,
Packet,
NULL,
&Packet->Ip.Ip6->SourceAddress,
ICMP_V6_PARAMETER_PROBLEM,
2,
&Pointer
);
}
return FALSE;
break;
}
break;
}
}
return TRUE;
}
/**
Validate the IP6 option format for both the packets we received
and that we will transmit. It supports the defined options in Neighbor
Discovery messages.
@param[in] Option The first byte of the option.
@param[in] OptionLen The length of the whole option.
@retval TRUE The option is properly formatted.
@retval FALSE The option is malformated.
**/
BOOLEAN
Ip6IsNDOptionValid (
IN UINT8 *Option,
IN UINT16 OptionLen
)
{
UINT16 Offset;
UINT8 OptionType;
UINT16 Length;
Offset = 0;
while (Offset < OptionLen) {
OptionType = *(Option + Offset);
Length = (UINT16) (*(Option + Offset + 1) * 8);
switch (OptionType) {
case Ip6OptionPrefixInfo:
if (Length != 32) {
return FALSE;
}
break;
case Ip6OptionMtu:
if (Length != 8) {
return FALSE;
}
break;
default:
//
// Check the length of Ip6OptionEtherSource, Ip6OptionEtherTarget, and
// Ip6OptionRedirected here. For unrecognized options, silently ignore
// and continue processsing the message.
//
if (Length == 0) {
return FALSE;
}
break;
}
Offset = (UINT16) (Offset + Length);
}
return TRUE;
}
/**
Validate whether the NextHeader is a known valid protocol or one of the user configured
protocols from the upper layer.
@param[in] IpSb The IP6 service instance.
@param[in] NextHeader The next header field.
@retval TRUE The NextHeader is a known valid protocol or user configured.
@retval FALSE The NextHeader is not a known valid protocol.
**/
BOOLEAN
Ip6IsValidProtocol (
IN IP6_SERVICE *IpSb,
IN UINT8 NextHeader
)
{
LIST_ENTRY *Entry;
IP6_PROTOCOL *IpInstance;
if (NextHeader == EFI_IP_PROTO_TCP ||
NextHeader == EFI_IP_PROTO_UDP ||
NextHeader == IP6_ICMP ||
NextHeader == IP6_ESP
) {
return TRUE;
}
if (IpSb == NULL) {
return FALSE;
}
if (IpSb->Signature != IP6_SERVICE_SIGNATURE) {
return FALSE;
}
NET_LIST_FOR_EACH (Entry, &IpSb->Children) {
IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
if (IpInstance->State == IP6_STATE_CONFIGED) {
if (IpInstance->ConfigData.DefaultProtocol == NextHeader) {
return TRUE;
}
}
}
return FALSE;
}
/**
Validate the IP6 extension header format for both the packets we received
and that we will transmit. It will compute the ICMPv6 error message fields
if the option is mal-formated.
@param[in] IpSb The IP6 service instance. This is an optional parameter.
@param[in] Packet The data of the packet. Ignored if NULL.
@param[in] NextHeader The next header field in IPv6 basic header.
@param[in] ExtHdrs The first byte of the option.
@param[in] ExtHdrsLen The length of the whole option.
@param[in] Rcvd The option is from the packet we received if TRUE,
otherwise, the option we want to transmit.
@param[out] FormerHeader The offset of NextHeader which points to Fragment
Header when we received, of the ExtHdrs.
Ignored if we transmit.
@param[out] LastHeader The pointer of NextHeader of the last extension
header processed by IP6.
@param[out] RealExtsLen The length of extension headers processed by IP6 layer.
This is an optional parameter that may be NULL.
@param[out] UnFragmentLen The length of unfragmented length of extension headers.
This is an optional parameter that may be NULL.
@param[out] Fragmented Indicate whether the packet is fragmented.
This is an optional parameter that may be NULL.
@retval TRUE The option is properly formated.
@retval FALSE The option is malformated.
**/
BOOLEAN
Ip6IsExtsValid (
IN IP6_SERVICE *IpSb OPTIONAL,
IN NET_BUF *Packet OPTIONAL,
IN UINT8 *NextHeader,
IN UINT8 *ExtHdrs,
IN UINT32 ExtHdrsLen,
IN BOOLEAN Rcvd,
OUT UINT32 *FormerHeader OPTIONAL,
OUT UINT8 **LastHeader,
OUT UINT32 *RealExtsLen OPTIONAL,
OUT UINT32 *UnFragmentLen OPTIONAL,
OUT BOOLEAN *Fragmented OPTIONAL
)
{
UINT32 Pointer;
UINT32 Offset;
UINT8 *Option;
UINT8 OptionLen;
BOOLEAN Flag;
UINT8 CountD;
UINT8 CountA;
IP6_FRAGMENT_HEADER *FragmentHead;
UINT16 FragmentOffset;
IP6_ROUTING_HEADER *RoutingHead;
if (RealExtsLen != NULL) {
*RealExtsLen = 0;
}
if (UnFragmentLen != NULL) {
*UnFragmentLen = 0;
}
if (Fragmented != NULL) {
*Fragmented = FALSE;
}
*LastHeader = NextHeader;
if (ExtHdrs == NULL && ExtHdrsLen == 0) {
return TRUE;
}
if ((ExtHdrs == NULL && ExtHdrsLen != 0) || (ExtHdrs != NULL && ExtHdrsLen == 0)) {
return FALSE;
}
Pointer = 0;
Offset = 0;
Flag = FALSE;
CountD = 0;
CountA = 0;
while (Offset <= ExtHdrsLen) {
switch (*NextHeader) {
case IP6_HOP_BY_HOP:
if (Offset != 0) {
if (!Rcvd) {
return FALSE;
}
//
// Hop-by-Hop Options header is restricted to appear immediately after an IPv6 header only.
// If not, generate a ICMP parameter problem message with code value of 1.
//
if (Pointer == 0) {
Pointer = sizeof (EFI_IP6_HEADER);
} else {
Pointer = Offset + sizeof (EFI_IP6_HEADER);
}
if ((IpSb != NULL) && (Packet != NULL) &&
!IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress)) {
Ip6SendIcmpError (
IpSb,
Packet,
NULL,
&Packet->Ip.Ip6->SourceAddress,
ICMP_V6_PARAMETER_PROBLEM,
1,
&Pointer
);
}
return FALSE;
}
Flag = TRUE;
//
// Fall through
//
case IP6_DESTINATION:
if (*NextHeader == IP6_DESTINATION) {
CountD++;
}
if (CountD > 2) {
return FALSE;
}
NextHeader = ExtHdrs + Offset;
Pointer = Offset;
Offset++;
Option = ExtHdrs + Offset;
OptionLen = (UINT8) ((*Option + 1) * 8 - 2);
Option++;
Offset++;
if (IpSb != NULL && Packet != NULL && !Ip6IsOptionValid (IpSb, Packet, Option, OptionLen, Offset)) {
return FALSE;
}
Offset = Offset + OptionLen;
if (Flag) {
if (UnFragmentLen != NULL) {
*UnFragmentLen = Offset;
}
Flag = FALSE;
}
break;
case IP6_ROUTING:
NextHeader = ExtHdrs + Offset;
RoutingHead = (IP6_ROUTING_HEADER *) NextHeader;
//
// Type 0 routing header is defined in RFC2460 and deprecated in RFC5095.
// Thus all routing types are processed as unrecognized.
//
if (RoutingHead->SegmentsLeft == 0) {
//
// Ignore the routing header and proceed to process the next header.
//
Offset = Offset + (RoutingHead->HeaderLen + 1) * 8;
if (UnFragmentLen != NULL) {
*UnFragmentLen = Offset;
}
} else {
//
// Discard the packet and send an ICMP Parameter Problem, Code 0, message
// to the packet's source address, pointing to the unrecognized routing
// type.
//
Pointer = Offset + 2 + sizeof (EFI_IP6_HEADER);
if ((IpSb != NULL) && (Packet != NULL) &&
!IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress)) {
Ip6SendIcmpError (
IpSb,
Packet,
NULL,
&Packet->Ip.Ip6->SourceAddress,
ICMP_V6_PARAMETER_PROBLEM,
0,
&Pointer
);
}
return FALSE;
}
break;
case IP6_FRAGMENT:
//
// RFC2402, AH header should after fragment header.
//
if (CountA > 1) {
return FALSE;
}
//
// RFC2460, ICMP Parameter Problem message with code 0 should be sent
// if the length of a fragment is not a multiple of 8 octects and the M
// flag of that fragment is 1, pointing to the Payload length field of the
// fragment packet.
//
if (IpSb != NULL && Packet != NULL && (ExtHdrsLen % 8) != 0) {
//
// Check whether it is the last fragment.
//
FragmentHead = (IP6_FRAGMENT_HEADER *) (ExtHdrs + Offset);
if (FragmentHead == NULL) {
return FALSE;
}
FragmentOffset = NTOHS (FragmentHead->FragmentOffset);
if (((FragmentOffset & 0x1) == 0x1) &&
!IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress)) {
Pointer = sizeof (UINT32);
Ip6SendIcmpError (
IpSb,
Packet,
NULL,
&Packet->Ip.Ip6->SourceAddress,
ICMP_V6_PARAMETER_PROBLEM,
0,
&Pointer
);
return FALSE;
}
}
if (Fragmented != NULL) {
*Fragmented = TRUE;
}
if (Rcvd && FormerHeader != NULL) {
*FormerHeader = (UINT32) (NextHeader - ExtHdrs);
}
NextHeader = ExtHdrs + Offset;
Offset = Offset + 8;
break;
case IP6_AH:
if (++CountA > 1) {
return FALSE;
}
Option = ExtHdrs + Offset;
NextHeader = Option;
Option++;
//
// RFC2402, Payload length is specified in 32-bit words, minus "2".
//
OptionLen = (UINT8) ((*Option + 2) * 4);
Offset = Offset + OptionLen;
break;
case IP6_NO_NEXT_HEADER:
*LastHeader = NextHeader;
return FALSE;
break;
default:
if (Ip6IsValidProtocol (IpSb, *NextHeader)) {
*LastHeader = NextHeader;
if (RealExtsLen != NULL) {
*RealExtsLen = Offset;
}
return TRUE;
}
//
// The Next Header value is unrecognized by the node, discard the packet and
// send an ICMP parameter problem message with code value of 1.
//
if (Offset == 0) {
//
// The Next Header directly follows IPv6 basic header.
//
Pointer = 6;
} else {
if (Pointer == 0) {
Pointer = sizeof (EFI_IP6_HEADER);
} else {
Pointer = Offset + sizeof (EFI_IP6_HEADER);
}
}
if ((IpSb != NULL) && (Packet != NULL) &&
!IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress)) {
Ip6SendIcmpError (
IpSb,
Packet,
NULL,
&Packet->Ip.Ip6->SourceAddress,
ICMP_V6_PARAMETER_PROBLEM,
1,
&Pointer
);
}
return FALSE;
}
}
*LastHeader = NextHeader;
if (RealExtsLen != NULL) {
*RealExtsLen = Offset;
}
return TRUE;
}
/**
Generate an IPv6 router alert option in network order and output it through Buffer.
@param[out] Buffer Points to a buffer to record the generated option.
@param[in, out] BufferLen The length of Buffer, in bytes.
@param[in] NextHeader The 8-bit selector indicates the type of header
immediately following the Hop-by-Hop Options header.
@retval EFI_BUFFER_TOO_SMALL The Buffer is too small to contain the generated
option. BufferLen is updated for the required size.
@retval EFI_SUCCESS The option is generated and filled in to Buffer.
**/
EFI_STATUS
Ip6FillHopByHop (
OUT UINT8 *Buffer,
IN OUT UINTN *BufferLen,
IN UINT8 NextHeader
)
{
UINT8 BufferArray[8];
if (*BufferLen < 8) {
*BufferLen = 8;
return EFI_BUFFER_TOO_SMALL;
}
//
// Form the Hop-By-Hop option in network order.
// NextHeader (1 octet) + HdrExtLen (1 octet) + RouterAlertOption(4 octets) + PadN
// The Hdr Ext Len is the length in 8-octet units, and does not including the first 8 octets.
//
ZeroMem (BufferArray, sizeof (BufferArray));
BufferArray[0] = NextHeader;
BufferArray[2] = 0x5;
BufferArray[3] = 0x2;
BufferArray[6] = 1;
CopyMem (Buffer, BufferArray, sizeof (BufferArray));
return EFI_SUCCESS;
}
/**
Insert a Fragment Header to the Extension headers and output it in UpdatedExtHdrs.
@param[in] IpSb The IP6 service instance to transmit the packet.
@param[in] NextHeader The extension header type of first extension header.
@param[in] LastHeader The extension header type of last extension header.
@param[in] ExtHdrs The length of the original extension header.
@param[in] ExtHdrsLen The length of the extension headers.
@param[in] FragmentOffset The fragment offset of the data following the header.
@param[out] UpdatedExtHdrs The updated ExtHdrs with Fragment header inserted.
It's caller's responsiblity to free this buffer.
@retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lake of
resource.
@retval EFI_UNSUPPORTED The extension header specified in ExtHdrs is not
supported currently.
@retval EFI_SUCCESS The operation performed successfully.
**/
EFI_STATUS
Ip6FillFragmentHeader (
IN IP6_SERVICE *IpSb,
IN UINT8 NextHeader,
IN UINT8 LastHeader,
IN UINT8 *ExtHdrs,
IN UINT32 ExtHdrsLen,
IN UINT16 FragmentOffset,
OUT UINT8 **UpdatedExtHdrs
)
{
UINT32 Length;
UINT8 *Buffer;
UINT32 FormerHeader;
UINT32 Offset;
UINT32 Part1Len;
UINT32 HeaderLen;
UINT8 Current;
IP6_FRAGMENT_HEADER FragmentHead;
if (UpdatedExtHdrs == NULL) {
return EFI_INVALID_PARAMETER;
}
Length = ExtHdrsLen + sizeof (IP6_FRAGMENT_HEADER);
Buffer = AllocatePool (Length);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Offset = 0;
Part1Len = 0;
FormerHeader = 0;
Current = NextHeader;
while ((ExtHdrs != NULL) && (Offset <= ExtHdrsLen)) {
switch (NextHeader) {
case IP6_ROUTING:
case IP6_HOP_BY_HOP:
case IP6_DESTINATION:
Current = NextHeader;
NextHeader = *(ExtHdrs + Offset);
if ((Current == IP6_DESTINATION) && (NextHeader != IP6_ROUTING)) {
//
// Destination Options header should occur at most twice, once before
// a Routing header and once before the upper-layer header. Here we
// find the one before the upper-layer header. Insert the Fragment
// Header before it.
//
CopyMem (Buffer, ExtHdrs, Part1Len);
*(Buffer + FormerHeader) = IP6_FRAGMENT;
//
// Exit the loop.
//
Offset = ExtHdrsLen + 1;
break;
}
FormerHeader = Offset;
HeaderLen = (*(ExtHdrs + Offset + 1) + 1) * 8;
Part1Len = Part1Len + HeaderLen;
Offset = Offset + HeaderLen;
break;
case IP6_FRAGMENT:
Current = NextHeader;
if (Part1Len != 0) {
CopyMem (Buffer, ExtHdrs, Part1Len);
}
*(Buffer + FormerHeader) = IP6_FRAGMENT;
//
// Exit the loop.
//
Offset = ExtHdrsLen + 1;
break;
case IP6_AH:
Current = NextHeader;
NextHeader = *(ExtHdrs + Offset);
//
// RFC2402, Payload length is specified in 32-bit words, minus "2".
//
HeaderLen = (*(ExtHdrs + Offset + 1) + 2) * 4;
Part1Len = Part1Len + HeaderLen;
Offset = Offset + HeaderLen;
break;
default:
if (Ip6IsValidProtocol (IpSb, NextHeader)) {
Current = NextHeader;
CopyMem (Buffer, ExtHdrs, Part1Len);
*(Buffer + FormerHeader) = IP6_FRAGMENT;
//
// Exit the loop.
//
Offset = ExtHdrsLen + 1;
break;
}
FreePool (Buffer);
return EFI_UNSUPPORTED;
}
}
//
// Append the Fragment header. If the fragment offset indicates the fragment
// is the first fragment.
//
if ((FragmentOffset & IP6_FRAGMENT_OFFSET_MASK) == 0) {
FragmentHead.NextHeader = Current;
} else {
FragmentHead.NextHeader = LastHeader;
}
FragmentHead.Reserved = 0;
FragmentHead.FragmentOffset = HTONS (FragmentOffset);
FragmentHead.Identification = mIp6Id;
CopyMem (Buffer + Part1Len, &FragmentHead, sizeof (IP6_FRAGMENT_HEADER));
if ((ExtHdrs != NULL) && (Part1Len < ExtHdrsLen)) {
//
// Append the part2 (fragmentable part) of Extension headers
//
CopyMem (
Buffer + Part1Len + sizeof (IP6_FRAGMENT_HEADER),
ExtHdrs + Part1Len,
ExtHdrsLen - Part1Len
);
}
*UpdatedExtHdrs = Buffer;
return EFI_SUCCESS;
}

View File

@@ -0,0 +1,191 @@
/** @file
Definition of IP6 option process routines.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_OPTION_H__
#define __EFI_IP6_OPTION_H__
#define IP6_FRAGMENT_OFFSET_MASK (~0x3)
typedef struct _IP6_FRAGMENT_HEADER {
UINT8 NextHeader;
UINT8 Reserved;
UINT16 FragmentOffset;
UINT32 Identification;
} IP6_FRAGMENT_HEADER;
typedef struct _IP6_ROUTING_HEADER {
UINT8 NextHeader;
UINT8 HeaderLen;
UINT8 RoutingType;
UINT8 SegmentsLeft;
} IP6_ROUTING_HEADER;
typedef enum {
Ip6OptionPad1 = 0,
Ip6OptionPadN = 1,
Ip6OptionRouterAlert = 5,
Ip6OptionSkip = 0,
Ip6OptionDiscard = 0x40,
Ip6OptionParameterProblem = 0x80,
Ip6OptionMask = 0xc0,
Ip6OptionEtherSource = 1,
Ip6OptionEtherTarget = 2,
Ip6OptionPrefixInfo = 3,
Ip6OptionRedirected = 4,
Ip6OptionMtu = 5
} IP6_OPTION_TYPE;
/**
Validate the IP6 extension header format for both the packets we received
and that we will transmit. It will compute the ICMPv6 error message fields
if the option is mal-formated.
@param[in] IpSb The IP6 service instance. This is an optional parameter.
@param[in] Packet The data of the packet. Ignored if NULL.
@param[in] NextHeader The next header field in IPv6 basic header.
@param[in] ExtHdrs The first byte of the option.
@param[in] ExtHdrsLen The length of the whole option.
@param[in] Rcvd The option is from the packet we received if TRUE,
otherwise, the option we want to transmit.
@param[out] FormerHeader The offset of NextHeader which points to Fragment
Header when we received, of the ExtHdrs.
Ignored if we transmit.
@param[out] LastHeader The pointer of NextHeader of the last extension
header processed by IP6.
@param[out] RealExtsLen The length of extension headers processed by IP6 layer.
This is an optional parameter that may be NULL.
@param[out] UnFragmentLen The length of unfragmented length of extension headers.
This is an optional parameter that may be NULL.
@param[out] Fragmented Indicate whether the packet is fragmented.
This is an optional parameter that may be NULL.
@retval TRUE The option is properly formated.
@retval FALSE The option is malformated.
**/
BOOLEAN
Ip6IsExtsValid (
IN IP6_SERVICE *IpSb OPTIONAL,
IN NET_BUF *Packet OPTIONAL,
IN UINT8 *NextHeader,
IN UINT8 *ExtHdrs,
IN UINT32 ExtHdrsLen,
IN BOOLEAN Rcvd,
OUT UINT32 *FormerHeader OPTIONAL,
OUT UINT8 **LastHeader,
OUT UINT32 *RealExtsLen OPTIONAL,
OUT UINT32 *UnFragmentLen OPTIONAL,
OUT BOOLEAN *Fragmented OPTIONAL
);
/**
Generate an IPv6 router alert option in network order and output it through Buffer.
@param[out] Buffer Points to a buffer to record the generated option.
@param[in, out] BufferLen The length of Buffer, in bytes.
@param[in] NextHeader The 8-bit selector indicates the type of header
immediately following the Hop-by-Hop Options header.
@retval EFI_BUFFER_TOO_SMALL The Buffer is too small to contain the generated
option. BufferLen is updated for the required size.
@retval EFI_SUCCESS The option is generated and filled in to Buffer.
**/
EFI_STATUS
Ip6FillHopByHop (
OUT UINT8 *Buffer,
IN OUT UINTN *BufferLen,
IN UINT8 NextHeader
);
/**
Insert a Fragment Header to the Extension headers and output it in UpdatedExtHdrs.
@param[in] IpSb The IP6 service instance to transmit the packet.
@param[in] NextHeader The extension header type of first extension header.
@param[in] LastHeader The extension header type of last extension header.
@param[in] ExtHdrs The length of the original extension header.
@param[in] ExtHdrsLen The length of the extension headers.
@param[in] FragmentOffset The fragment offset of the data following the header.
@param[out] UpdatedExtHdrs The updated ExtHdrs with Fragment header inserted.
It's caller's responsiblity to free this buffer.
@retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lake of
resource.
@retval EFI_UNSUPPORTED The extension header specified in ExtHdrs is not
supported currently.
@retval EFI_SUCCESS The operation performed successfully.
**/
EFI_STATUS
Ip6FillFragmentHeader (
IN IP6_SERVICE *IpSb,
IN UINT8 NextHeader,
IN UINT8 LastHeader,
IN UINT8 *ExtHdrs,
IN UINT32 ExtHdrsLen,
IN UINT16 FragmentOffset,
OUT UINT8 **UpdatedExtHdrs
);
/**
Copy the extension headers from the original to buffer. A Fragment header is
appended to the end.
@param[in] NextHeader The 8-bit selector indicates the type of
the fragment header's next header.
@param[in] ExtHdrs The length of the original extension header.
@param[in] LastHeader The pointer of next header of last extension header.
@param[in] FragmentOffset The fragment offset of the data following the header.
@param[in] UnFragmentHdrLen The length of unfragmented length of extension headers.
@param[in, out] Buf The buffer to copy options to.
@param[in, out] BufLen The length of the buffer.
@retval EFI_SUCCESS The options are copied over.
@retval EFI_BUFFER_TOO_SMALL The buffer caller provided is too small.
**/
EFI_STATUS
Ip6CopyExts (
IN UINT8 NextHeader,
IN UINT8 *ExtHdrs,
IN UINT8 *LastHeader,
IN UINT16 FragmentOffset,
IN UINT32 UnFragmentHdrLen,
IN OUT UINT8 *Buf,
IN OUT UINT32 *BufLen
);
/**
Validate the IP6 option format for both the packets we received
and that we will transmit. It supports the defined options in Neighbor
Discovery messages.
@param[in] Option The first byte of the option.
@param[in] OptionLen The length of the whole option.
@retval TRUE The option is properly formatted.
@retval FALSE The option is malformated.
**/
BOOLEAN
Ip6IsNDOptionValid (
IN UINT8 *Option,
IN UINT16 OptionLen
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,141 @@
/** @file
The internal functions and routines to transmit the IP6 packet.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_OUTPUT_H__
#define __EFI_IP6_OUTPUT_H__
extern UINT32 mIp6Id;
/**
Output all the available source addresses to the list entry head SourceList. The
number of source addresses are also returned.
@param[in] IpSb Points to a IP6 service binding instance.
@param[in] Destination The IPv6 destination address.
@param[out] Source The selected IPv6 source address according to
the Destination.
@retval EFI_SUCCESS The source addresses were copied to the list entry
head SourceList.
@retval EFI_NO_MAPPING The IPv6 stack is not auto configured.
**/
EFI_STATUS
Ip6SelectSourceAddress (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Destination,
OUT EFI_IPv6_ADDRESS *Source
);
/**
The default callback function for system generated packet.
It will free the packet.
@param[in] Packet The packet that transmitted.
@param[in] IoStatus The result of the transmission: succeeded or failed.
@param[in] LinkFlag Not used when transmission. Check IP6_FRAME_CALLBACK
for reference.
@param[in] Context The context provided by us.
**/
VOID
Ip6SysPacketSent (
NET_BUF *Packet,
EFI_STATUS IoStatus,
UINT32 LinkFlag,
VOID *Context
);
/**
Transmit an IP6 packet. The packet comes either from the IP6
child's consumer (IpInstance != NULL) or the IP6 driver itself
(IpInstance == NULL). It will route the packet, fragment it,
then transmit all the fragments through an interface.
@param[in] IpSb The IP6 service instance to transmit the packet.
@param[in] Interface The IP6 interface to transmit the packet. Ignored
if NULL.
@param[in] IpInstance The IP6 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: NextHeader, HopLimit,
Src, Dest, FlowLabel, PayloadLength. This function
will fill in the Ver, TrafficClass.
@param[in] ExtHdrs The extension headers to append to the IPv6 basic
header.
@param[in] ExtHdrsLen The length of the extension headers.
@param[in] Callback The callback function to issue when transmission
completed.
@param[in] Context The opaque context for the callback.
@retval EFI_INVALID_PARAMETER Any input parameter or the packet is invalid.
@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 successfully transmitted.
@retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lack of
resources.
@retval Others Failed to transmit the packet.
**/
EFI_STATUS
Ip6Output (
IN IP6_SERVICE *IpSb,
IN IP6_INTERFACE *Interface OPTIONAL,
IN IP6_PROTOCOL *IpInstance OPTIONAL,
IN NET_BUF *Packet,
IN EFI_IP6_HEADER *Head,
IN UINT8 *ExtHdrs,
IN UINT32 ExtHdrsLen,
IN IP6_FRAME_CALLBACK Callback,
IN VOID *Context
);
/**
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. Ignored if
FrameToCancel is NULL.
**/
VOID
Ip6CancelFrames (
IN IP6_INTERFACE *Interface,
IN EFI_STATUS IoStatus,
IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL,
IN VOID *Context OPTIONAL
);
/**
Cancel the Packet and all its fragments.
@param[in] IpIf The interface from which the Packet is sent.
@param[in] Packet The Packet to cancel.
@param[in] IoStatus The status returns to the sender.
**/
VOID
Ip6CancelPacket (
IN IP6_INTERFACE *IpIf,
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus
);
#endif

View File

@@ -0,0 +1,635 @@
/** @file
The functions and routines to handle the route caches and route table.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Ip6Impl.h"
/**
This is the worker function for IP6_ROUTE_CACHE_HASH(). It calculates the value
as the index of the route cache bucket according to the prefix of two IPv6 addresses.
@param[in] Ip1 The IPv6 address.
@param[in] Ip2 The IPv6 address.
@return The hash value of the prefix of two IPv6 addresses.
**/
UINT32
Ip6RouteCacheHash (
IN EFI_IPv6_ADDRESS *Ip1,
IN EFI_IPv6_ADDRESS *Ip2
)
{
UINT32 Prefix1;
UINT32 Prefix2;
Prefix1 = *((UINT32 *) ((UINTN *) (Ip1)));
Prefix2 = *((UINT32 *) ((UINTN *) (Ip2)));
return ((UINT32) (Prefix1 ^ Prefix2) % IP6_ROUTE_CACHE_HASH_SIZE);
}
/**
Allocate a route entry then initialize it with the Destination/PrefixLength
and Gateway.
@param[in] Destination The IPv6 destination address. This is an optional
parameter that may be NULL.
@param[in] PrefixLength The destination network's prefix length.
@param[in] GatewayAddress The next hop address. This is an optional parameter
that may be NULL.
@return NULL if failed to allocate memeory; otherwise, the newly created route entry.
**/
IP6_ROUTE_ENTRY *
Ip6CreateRouteEntry (
IN EFI_IPv6_ADDRESS *Destination OPTIONAL,
IN UINT8 PrefixLength,
IN EFI_IPv6_ADDRESS *GatewayAddress OPTIONAL
)
{
IP6_ROUTE_ENTRY *RtEntry;
RtEntry = AllocateZeroPool (sizeof (IP6_ROUTE_ENTRY));
if (RtEntry == NULL) {
return NULL;
}
RtEntry->RefCnt = 1;
RtEntry->Flag = 0;
RtEntry->PrefixLength = PrefixLength;
if (Destination != NULL) {
IP6_COPY_ADDRESS (&RtEntry->Destination, Destination);
}
if (GatewayAddress != NULL) {
IP6_COPY_ADDRESS (&RtEntry->NextHop, GatewayAddress);
}
return RtEntry;
}
/**
Free the route table entry. It is reference counted.
@param[in, out] RtEntry The route entry to free.
**/
VOID
Ip6FreeRouteEntry (
IN OUT IP6_ROUTE_ENTRY *RtEntry
)
{
ASSERT ((RtEntry != NULL) && (RtEntry->RefCnt > 0));
if (--RtEntry->RefCnt == 0) {
FreePool (RtEntry);
}
}
/**
Search the route table for a most specific match to the Dst. It searches
from the longest route area (prefix length == 128) 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 per 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] Destination The destionation address to search. If NULL, search
the route table by NextHop.
@param[in] NextHop The next hop address. If NULL, search the route table
by Destination.
@return NULL if no route matches the Dst. Otherwise, the point to the
@return most specific route to the Dst.
**/
IP6_ROUTE_ENTRY *
Ip6FindRouteEntry (
IN IP6_ROUTE_TABLE *RtTable,
IN EFI_IPv6_ADDRESS *Destination OPTIONAL,
IN EFI_IPv6_ADDRESS *NextHop OPTIONAL
)
{
LIST_ENTRY *Entry;
IP6_ROUTE_ENTRY *RtEntry;
INTN Index;
ASSERT (Destination != NULL || NextHop != NULL);
RtEntry = NULL;
for (Index = IP6_PREFIX_NUM - 1; Index >= 0; Index--) {
NET_LIST_FOR_EACH (Entry, &RtTable->RouteArea[Index]) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_ENTRY, Link);
if (Destination != NULL) {
if (NetIp6IsNetEqual (Destination, &RtEntry->Destination, RtEntry->PrefixLength)) {
NET_GET_REF (RtEntry);
return RtEntry;
}
} else if (NextHop != NULL) {
if (NetIp6IsNetEqual (NextHop, &RtEntry->NextHop, RtEntry->PrefixLength)) {
NET_GET_REF (RtEntry);
return RtEntry;
}
}
}
}
return NULL;
}
/**
Allocate and initialize a IP6 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. Otherwise, point
to the created route cache entry.
**/
IP6_ROUTE_CACHE_ENTRY *
Ip6CreateRouteCacheEntry (
IN EFI_IPv6_ADDRESS *Dst,
IN EFI_IPv6_ADDRESS *Src,
IN EFI_IPv6_ADDRESS *GateWay,
IN UINTN Tag
)
{
IP6_ROUTE_CACHE_ENTRY *RtCacheEntry;
RtCacheEntry = AllocatePool (sizeof (IP6_ROUTE_CACHE_ENTRY));
if (RtCacheEntry == NULL) {
return NULL;
}
RtCacheEntry->RefCnt = 1;
RtCacheEntry->Tag = Tag;
IP6_COPY_ADDRESS (&RtCacheEntry->Destination, Dst);
IP6_COPY_ADDRESS (&RtCacheEntry->Source, Src);
IP6_COPY_ADDRESS (&RtCacheEntry->NextHop, GateWay);
return RtCacheEntry;
}
/**
Free the route cache entry. It is reference counted.
@param[in, out] RtCacheEntry The route cache entry to free.
**/
VOID
Ip6FreeRouteCacheEntry (
IN OUT IP6_ROUTE_CACHE_ENTRY *RtCacheEntry
)
{
ASSERT (RtCacheEntry->RefCnt > 0);
if (--RtCacheEntry->RefCnt == 0) {
FreePool (RtCacheEntry);
}
}
/**
Find a route cache with the destination and source address. This is
used by the ICMPv6 redirect messasge process.
@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 pointer
to the correct route cache entry.
**/
IP6_ROUTE_CACHE_ENTRY *
Ip6FindRouteCache (
IN IP6_ROUTE_TABLE *RtTable,
IN EFI_IPv6_ADDRESS *Dest,
IN EFI_IPv6_ADDRESS *Src
)
{
LIST_ENTRY *Entry;
IP6_ROUTE_CACHE_ENTRY *RtCacheEntry;
UINT32 Index;
Index = IP6_ROUTE_CACHE_HASH (Dest, Src);
NET_LIST_FOR_EACH (Entry, &RtTable->Cache.CacheBucket[Index]) {
RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
if (EFI_IP6_EQUAL (Dest, &RtCacheEntry->Destination)&& EFI_IP6_EQUAL (Src, &RtCacheEntry->Source)) {
NET_GET_REF (RtCacheEntry);
return RtCacheEntry;
}
}
return NULL;
}
/**
Build an array of EFI_IP6_ROUTE_TABLE to be returned to the caller. The number
of EFI_IP6_ROUTE_TABLE is also returned.
@param[in] RouteTable The pointer of IP6_ROUTE_TABLE internal used.
@param[out] EfiRouteCount The number of returned route entries.
@param[out] EfiRouteTable The pointer to the array of EFI_IP6_ROUTE_TABLE.
If NULL, only the route entry count is returned.
@retval EFI_SUCCESS The EFI_IP6_ROUTE_TABLE successfully built.
@retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the route table.
**/
EFI_STATUS
Ip6BuildEfiRouteTable (
IN IP6_ROUTE_TABLE *RouteTable,
OUT UINT32 *EfiRouteCount,
OUT EFI_IP6_ROUTE_TABLE **EfiRouteTable OPTIONAL
)
{
LIST_ENTRY *Entry;
IP6_ROUTE_ENTRY *RtEntry;
EFI_IP6_ROUTE_TABLE *EfiTable;
UINT32 Count;
INT32 Index;
ASSERT (EfiRouteCount != NULL);
Count = RouteTable->TotalNum;
*EfiRouteCount = Count;
if ((EfiRouteTable == NULL) || (Count == 0)) {
return EFI_SUCCESS;
}
if (*EfiRouteTable == NULL) {
*EfiRouteTable = AllocatePool (sizeof (EFI_IP6_ROUTE_TABLE) * Count);
if (*EfiRouteTable == NULL) {
return EFI_OUT_OF_RESOURCES;
}
}
EfiTable = *EfiRouteTable;
//
// Copy the route entry to EFI route table.
//
Count = 0;
for (Index = IP6_PREFIX_NUM - 1; Index >= 0; Index--) {
NET_LIST_FOR_EACH (Entry, &(RouteTable->RouteArea[Index])) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_ENTRY, Link);
Ip6CopyAddressByPrefix (
&EfiTable[Count].Destination,
&RtEntry->Destination,
RtEntry->PrefixLength
);
IP6_COPY_ADDRESS (&EfiTable[Count].Gateway, &RtEntry->NextHop);
EfiTable[Count].PrefixLength = RtEntry->PrefixLength;
Count++;
}
}
ASSERT (Count == RouteTable->TotalNum);
return EFI_SUCCESS;
}
/**
Create an empty route table. This includes its internal route cache.
@return NULL if failed to allocate memory for the route table. Otherwise,
the point to newly created route table.
**/
IP6_ROUTE_TABLE *
Ip6CreateRouteTable (
VOID
)
{
IP6_ROUTE_TABLE *RtTable;
UINT32 Index;
RtTable = AllocatePool (sizeof (IP6_ROUTE_TABLE));
if (RtTable == NULL) {
return NULL;
}
RtTable->RefCnt = 1;
RtTable->TotalNum = 0;
for (Index = 0; Index < IP6_PREFIX_NUM; Index++) {
InitializeListHead (&RtTable->RouteArea[Index]);
}
for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
InitializeListHead (&RtTable->Cache.CacheBucket[Index]);
RtTable->Cache.CacheNum[Index] = 0;
}
return RtTable;
}
/**
Free the route table and its associated route cache. Route
table is reference counted.
@param[in, out] RtTable The route table to free.
**/
VOID
Ip6CleanRouteTable (
IN OUT IP6_ROUTE_TABLE *RtTable
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
IP6_ROUTE_ENTRY *RtEntry;
IP6_ROUTE_CACHE_ENTRY *RtCacheEntry;
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 < IP6_PREFIX_NUM; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtTable->RouteArea[Index]) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_ENTRY, Link);
RemoveEntryList (Entry);
Ip6FreeRouteEntry (RtEntry);
}
}
for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtTable->Cache.CacheBucket[Index]) {
RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
RemoveEntryList (Entry);
Ip6FreeRouteCacheEntry (RtCacheEntry);
}
}
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[in] RtCache Route cache to remove the entries from.
@param[in] Tag The Tag of the entries to remove.
**/
VOID
Ip6PurgeRouteCache (
IN IP6_ROUTE_CACHE *RtCache,
IN UINTN Tag
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
IP6_ROUTE_CACHE_ENTRY *RtCacheEntry;
UINT32 Index;
for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtCache->CacheBucket[Index]) {
RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
if (RtCacheEntry->Tag == Tag) {
RemoveEntryList (Entry);
Ip6FreeRouteCacheEntry (RtCacheEntry);
}
}
}
}
/**
Add a route entry to the route table. It is the help function for EfiIp6Routes.
@param[in, out] RtTable Route table to add route to.
@param[in] Destination The destination of the network.
@param[in] PrefixLength The PrefixLength of the destination.
@param[in] GatewayAddress 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 was added successfully.
**/
EFI_STATUS
Ip6AddRoute (
IN OUT IP6_ROUTE_TABLE *RtTable,
IN EFI_IPv6_ADDRESS *Destination,
IN UINT8 PrefixLength,
IN EFI_IPv6_ADDRESS *GatewayAddress
)
{
LIST_ENTRY *ListHead;
LIST_ENTRY *Entry;
IP6_ROUTE_ENTRY *Route;
ListHead = &RtTable->RouteArea[PrefixLength];
//
// First check whether the route exists
//
NET_LIST_FOR_EACH (Entry, ListHead) {
Route = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_ENTRY, Link);
if (NetIp6IsNetEqual (Destination, &Route->Destination, PrefixLength) &&
EFI_IP6_EQUAL (GatewayAddress, &Route->NextHop)) {
return EFI_ACCESS_DENIED;
}
}
//
// Create a route entry and insert it to the route area.
//
Route = Ip6CreateRouteEntry (Destination, PrefixLength, GatewayAddress);
if (Route == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (NetIp6IsUnspecifiedAddr (GatewayAddress)) {
Route->Flag = IP6_DIRECT_ROUTE;
}
InsertHeadList (ListHead, &Route->Link);
RtTable->TotalNum++;
return EFI_SUCCESS;
}
/**
Remove a route entry and all the route caches spawn from it.
It is the help function for EfiIp6Routes.
@param[in, out] RtTable The route table to remove the route from.
@param[in] Destination The destination network.
@param[in] PrefixLength The PrefixLength of the Destination.
@param[in] GatewayAddress The next hop address.
@retval EFI_SUCCESS The route entry was successfully removed.
@retval EFI_NOT_FOUND There is no route entry in the table with that
property.
**/
EFI_STATUS
Ip6DelRoute (
IN OUT IP6_ROUTE_TABLE *RtTable,
IN EFI_IPv6_ADDRESS *Destination,
IN UINT8 PrefixLength,
IN EFI_IPv6_ADDRESS *GatewayAddress
)
{
LIST_ENTRY *ListHead;
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
IP6_ROUTE_ENTRY *Route;
UINT32 TotalNum;
ListHead = &RtTable->RouteArea[PrefixLength];
TotalNum = RtTable->TotalNum;
NET_LIST_FOR_EACH_SAFE (Entry, Next, ListHead) {
Route = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_ENTRY, Link);
if (Destination != NULL && !NetIp6IsNetEqual (Destination, &Route->Destination, PrefixLength)) {
continue;
}
if (GatewayAddress != NULL && !EFI_IP6_EQUAL (GatewayAddress, &Route->NextHop)) {
continue;
}
Ip6PurgeRouteCache (&RtTable->Cache, (UINTN) Route);
RemoveEntryList (Entry);
Ip6FreeRouteEntry (Route);
ASSERT (RtTable->TotalNum > 0);
RtTable->TotalNum--;
}
return TotalNum == RtTable->TotalNum ? EFI_NOT_FOUND : EFI_SUCCESS;
}
/**
Search the route table to route the packet. Return/create a route
cache if there is a route to the destination.
@param[in] IpSb The IP6 service data.
@param[in] Dest The destination address to search for.
@param[in] Src The source address to search for.
@return NULL if it failed to route the packet. Otherwise, a route cache
entry that can be used to route packets.
**/
IP6_ROUTE_CACHE_ENTRY *
Ip6Route (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Dest,
IN EFI_IPv6_ADDRESS *Src
)
{
IP6_ROUTE_TABLE *RtTable;
LIST_ENTRY *ListHead;
IP6_ROUTE_CACHE_ENTRY *RtCacheEntry;
IP6_ROUTE_ENTRY *RtEntry;
EFI_IPv6_ADDRESS NextHop;
UINT32 Index;
RtTable = IpSb->RouteTable;
ASSERT (RtTable != NULL);
//
// Search the destination cache in IP6_ROUTE_TABLE.
//
Index = IP6_ROUTE_CACHE_HASH (Dest, Src);
ListHead = &RtTable->Cache.CacheBucket[Index];
RtCacheEntry = Ip6FindRouteCache (RtTable, Dest, Src);
//
// If found, promote the cache entry to the head of the hash bucket.
//
if (RtCacheEntry != NULL) {
RemoveEntryList (&RtCacheEntry->Link);
InsertHeadList (ListHead, &RtCacheEntry->Link);
return RtCacheEntry;
}
//
// Search the route table for the most specific route
//
RtEntry = Ip6FindRouteEntry (RtTable, Dest, NULL);
if (RtEntry == NULL) {
return NULL;
}
//
// Found a route to the Dest, if it is a direct route, the packet
// will be send directly to the destination, such as for connected
// network. Otherwise, it is an indirect route, the packet will be
// send the next hop router.
//
if ((RtEntry->Flag & IP6_DIRECT_ROUTE) == IP6_DIRECT_ROUTE) {
IP6_COPY_ADDRESS (&NextHop, Dest);
} else {
IP6_COPY_ADDRESS (&NextHop, &RtEntry->NextHop);
}
Ip6FreeRouteEntry (RtEntry);
//
// Create a route cache entry, and tag it as spawned from this route entry
//
RtCacheEntry = Ip6CreateRouteCacheEntry (Dest, Src, &NextHop, (UINTN) RtEntry);
if (RtCacheEntry == NULL) {
return NULL;
}
InsertHeadList (ListHead, &RtCacheEntry->Link);
NET_GET_REF (RtCacheEntry);
RtTable->Cache.CacheNum[Index]++;
return RtCacheEntry;
}

View File

@@ -0,0 +1,299 @@
/** @file
EFI IP6 route table and route cache table defintions.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_IP6_ROUTE_H__
#define __EFI_IP6_ROUTE_H__
#define IP6_DIRECT_ROUTE 0x00000001
#define IP6_PACKET_TOO_BIG 0x00000010
#define IP6_ROUTE_CACHE_HASH_SIZE 31
///
/// Max NO. of cache entry per hash bucket
///
#define IP6_ROUTE_CACHE_MAX 32
#define IP6_ROUTE_CACHE_HASH(Ip1, Ip2) Ip6RouteCacheHash ((Ip1), (Ip2))
typedef struct {
LIST_ENTRY Link;
INTN RefCnt;
UINT32 Flag;
UINT8 PrefixLength;
EFI_IPv6_ADDRESS Destination;
EFI_IPv6_ADDRESS NextHop;
} IP6_ROUTE_ENTRY;
typedef struct {
LIST_ENTRY Link;
INTN RefCnt;
UINTN Tag;
EFI_IPv6_ADDRESS Destination;
EFI_IPv6_ADDRESS Source;
EFI_IPv6_ADDRESS NextHop;
} IP6_ROUTE_CACHE_ENTRY;
typedef struct {
LIST_ENTRY CacheBucket[IP6_ROUTE_CACHE_HASH_SIZE];
UINT8 CacheNum[IP6_ROUTE_CACHE_HASH_SIZE];
} IP6_ROUTE_CACHE;
//
// Each IP6 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 prefix length 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 _IP6_ROUTE_TABLE {
INTN RefCnt;
UINT32 TotalNum;
LIST_ENTRY RouteArea[IP6_PREFIX_NUM];
IP6_ROUTE_CACHE Cache;
} IP6_ROUTE_TABLE;
/**
This is the worker function for IP6_ROUTE_CACHE_HASH(). It calculates the value
as the index of the route cache bucket according to the prefix of two IPv6 addresses.
@param[in] Ip1 The IPv6 address.
@param[in] Ip2 The IPv6 address.
@return The hash value of the prefix of two IPv6 addresses.
**/
UINT32
Ip6RouteCacheHash (
IN EFI_IPv6_ADDRESS *Ip1,
IN EFI_IPv6_ADDRESS *Ip2
);
/**
Allocate and initialize an IP6 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 it failed to allocate memory for the cache. Otherwise, point
to the created route cache entry.
**/
IP6_ROUTE_CACHE_ENTRY *
Ip6CreateRouteCacheEntry (
IN EFI_IPv6_ADDRESS *Dst,
IN EFI_IPv6_ADDRESS *Src,
IN EFI_IPv6_ADDRESS *GateWay,
IN UINTN Tag
);
/**
Free the route cache entry. It is reference counted.
@param[in, out] RtCacheEntry The route cache entry to free.
**/
VOID
Ip6FreeRouteCacheEntry (
IN OUT IP6_ROUTE_CACHE_ENTRY *RtCacheEntry
);
/**
Find a route cache with the destination and source address. This is
used by the ICMPv6 redirect messasge process.
@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, point
to the correct route cache entry.
**/
IP6_ROUTE_CACHE_ENTRY *
Ip6FindRouteCache (
IN IP6_ROUTE_TABLE *RtTable,
IN EFI_IPv6_ADDRESS *Dest,
IN EFI_IPv6_ADDRESS *Src
);
/**
Build a array of EFI_IP6_ROUTE_TABLE to be returned to the caller. The number
of EFI_IP6_ROUTE_TABLE is also returned.
@param[in] RouteTable The pointer of IP6_ROUTE_TABLE internal used.
@param[out] EfiRouteCount The number of returned route entries.
@param[out] EfiRouteTable The pointer to the array of EFI_IP6_ROUTE_TABLE.
If NULL, only the route entry count is returned.
@retval EFI_SUCCESS The EFI_IP6_ROUTE_TABLE successfully built.
@retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the route table.
**/
EFI_STATUS
Ip6BuildEfiRouteTable (
IN IP6_ROUTE_TABLE *RouteTable,
OUT UINT32 *EfiRouteCount,
OUT EFI_IP6_ROUTE_TABLE **EfiRouteTable OPTIONAL
);
/**
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.
**/
IP6_ROUTE_TABLE *
Ip6CreateRouteTable (
VOID
);
/**
Free the route table and its associated route cache. Route
table is reference counted.
@param[in, out] RtTable The route table to free.
**/
VOID
Ip6CleanRouteTable (
IN OUT IP6_ROUTE_TABLE *RtTable
);
/**
Allocate a route entry then initialize it with the Destination/PrefixLength
and Gateway.
@param[in] Destination The IPv6 destination address. This is an optional
parameter that may be NULL.
@param[in] PrefixLength The destination network's prefix length.
@param[in] GatewayAddress The next hop address. This is optional parameter
that may be NULL.
@return NULL if it failed to allocate memeory. Otherwise, the newly created route entry.
**/
IP6_ROUTE_ENTRY *
Ip6CreateRouteEntry (
IN EFI_IPv6_ADDRESS *Destination OPTIONAL,
IN UINT8 PrefixLength,
IN EFI_IPv6_ADDRESS *GatewayAddress OPTIONAL
);
/**
Search the route table for a most specific match to the Dst. It searches
from the longest route area (prefix length == 128) 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 per 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] Destination The destionation address to search. If NULL, search
the route table by NextHop.
@param[in] NextHop The next hop address. If NULL, search the route table
by Destination.
@return NULL if no route matches the Dst. Otherwise the point to the
most specific route to the Dst.
**/
IP6_ROUTE_ENTRY *
Ip6FindRouteEntry (
IN IP6_ROUTE_TABLE *RtTable,
IN EFI_IPv6_ADDRESS *Destination OPTIONAL,
IN EFI_IPv6_ADDRESS *NextHop OPTIONAL
);
/**
Free the route table entry. It is reference counted.
@param[in, out] RtEntry The route entry to free.
**/
VOID
Ip6FreeRouteEntry (
IN OUT IP6_ROUTE_ENTRY *RtEntry
);
/**
Add a route entry to the route table. It is the help function for EfiIp6Routes.
@param[in, out] RtTable Route table to add route to.
@param[in] Destination The destination of the network.
@param[in] PrefixLength The PrefixLength of the destination.
@param[in] GatewayAddress 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 was added successfully.
**/
EFI_STATUS
Ip6AddRoute (
IN OUT IP6_ROUTE_TABLE *RtTable,
IN EFI_IPv6_ADDRESS *Destination,
IN UINT8 PrefixLength,
IN EFI_IPv6_ADDRESS *GatewayAddress
);
/**
Remove a route entry and all the route caches spawn from it.
It is the help function for EfiIp6Routes.
@param[in, out] RtTable The route table to remove the route from.
@param[in] Destination The destination network.
@param[in] PrefixLength The PrefixLength of the Destination.
@param[in] GatewayAddress The next hop address.
@retval EFI_SUCCESS Successfully removed the route entry.
@retval EFI_NOT_FOUND There is no route entry in the table with that
properity.
**/
EFI_STATUS
Ip6DelRoute (
IN OUT IP6_ROUTE_TABLE *RtTable,
IN EFI_IPv6_ADDRESS *Destination,
IN UINT8 PrefixLength,
IN EFI_IPv6_ADDRESS *GatewayAddress
);
/**
Search the route table to route the packet. Return/create a route
cache if there is a route to the destination.
@param[in] IpSb The IP6 service data.
@param[in] Dest The destination address to search for.
@param[in] Src The source address to search for.
@return NULL if failed to route packet. Otherwise, a route cache
entry that can be used to route packet.
**/
IP6_ROUTE_CACHE_ENTRY *
Ip6Route (
IN IP6_SERVICE *IpSb,
IN EFI_IPv6_ADDRESS *Dest,
IN EFI_IPv6_ADDRESS *Src
);
#endif