ip4impl.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,133 行 · 第 1/4 页
C
2,133 行
Config - The configure data.
Returns:
EFI_SUCCESS - The IP4 child is successfully configured.
EFI_DEVICE_ERROR - Failed to free the pending transive or to configure
underlying MNP or other errors.
EFI_NO_MAPPING - The IP4 child is configured to use default address,
but the default address hasn't been configured. The
IP4 child doesn't need to be reconfigured when default
address is configured.
--*/
{
IP4_SERVICE *IpSb;
IP4_INTERFACE *IpIf;
EFI_STATUS Status;
IP4_ADDR Ip;
IP4_ADDR Netmask;
IpSb = IpInstance->Service;
//
// User is changing packet filters. It must be stopped
// before the station address can be changed.
//
if (IpInstance->State == IP4_STATE_CONFIGED) {
//
// Cancel all the pending transmit/receive from upper layer
//
Status = Ip4Cancel (IpInstance, NULL);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
IpInstance->ConfigData = *Config;
return EFI_SUCCESS;
}
//
// Configure a fresh IP4 protocol instance. Create a route table.
// Each IP child has its own route table, which may point to the
// default table if it is using default address.
//
Status = EFI_OUT_OF_RESOURCES;
IpInstance->RouteTable = Ip4CreateRouteTable ();
if (IpInstance->RouteTable == NULL) {
return Status;
}
//
// Set up the interface.
//
Ip = EFI_NTOHL (Config->StationAddress);
Netmask = EFI_NTOHL (Config->SubnetMask);
if (!Config->UseDefaultAddress) {
//
// Find whether there is already an interface with the same
// station address. All the instances with the same station
// address shares one interface.
//
IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);
if (IpIf != NULL) {
NET_GET_REF (IpIf);
} else {
IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
if (IpIf == NULL) {
goto ON_ERROR;
}
Status = Ip4SetAddress (IpIf, Ip, Netmask);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
Ip4FreeInterface (IpIf, IpInstance);
goto ON_ERROR;
}
NetListInsertTail (&IpSb->Interfaces, &IpIf->Link);
}
//
// Add a route to this connected network in the route table
//
Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);
} else {
//
// Use the default address. If the default configuration hasn't
// been started, start it.
//
if (IpSb->State == IP4_SERVICE_UNSTARTED) {
Status = Ip4StartAutoConfig (IpSb);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
}
IpIf = IpSb->DefaultInterface;
NET_GET_REF (IpSb->DefaultInterface);
//
// If default address is used, so is the default route table.
// Any route set by the instance has the precedence over the
// routes in the default route table. Link the default table
// after the instance's table. Routing will search the local
// table first.
//
NET_GET_REF (IpSb->DefaultRouteTable);
IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;
}
IpInstance->Interface = IpIf;
NetListInsertTail (&IpIf->IpInstances, &IpInstance->AddrLink);
IpInstance->ConfigData = *Config;
IpInstance->State = IP4_STATE_CONFIGED;
//
// Although EFI_NO_MAPPING is an error code, the IP child has been
// successfully configured and doesn't need reconfiguration when
// default address is acquired.
//
if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
return EFI_NO_MAPPING;
}
return EFI_SUCCESS;
ON_ERROR:
Ip4FreeRouteTable (IpInstance->RouteTable);
IpInstance->RouteTable = NULL;
return Status;
}
EFI_STATUS
Ip4CleanProtocol (
IN IP4_PROTOCOL *IpInstance
)
/*++
Routine Description:
Clean up the IP4 child, release all the resources used by it.
Arguments:
IpInstance - The IP4 child to clean up.
Returns:
EFI_SUCCESS - The IP4 child is cleaned up
EFI_DEVICE_ERROR - Some resources failed to be released
--*/
{
if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {
return EFI_DEVICE_ERROR;
}
if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {
return EFI_DEVICE_ERROR;
}
//
// Some packets haven't been recycled. It is because either the
// user forgets to recycle the packets, or because the callback
// hasn't been called. Just leave it alone.
//
if (!NetListIsEmpty (&IpInstance->Delivered)) {
;
}
if (IpInstance->Interface != NULL) {
NetListRemoveEntry (&IpInstance->AddrLink);
Ip4FreeInterface (IpInstance->Interface, IpInstance);
IpInstance->Interface = NULL;
}
if (IpInstance->RouteTable != NULL) {
if (IpInstance->RouteTable->Next != NULL) {
Ip4FreeRouteTable (IpInstance->RouteTable->Next);
}
Ip4FreeRouteTable (IpInstance->RouteTable);
IpInstance->RouteTable = NULL;
}
if (IpInstance->EfiRouteTable != NULL) {
NetFreePool (IpInstance->EfiRouteTable);
IpInstance->EfiRouteTable = NULL;
IpInstance->EfiRouteCount = 0;
}
if (IpInstance->Groups != NULL) {
NetFreePool (IpInstance->Groups);
IpInstance->Groups = NULL;
IpInstance->GroupCount = 0;
}
NetMapClean (&IpInstance->TxTokens);
NetMapClean (&IpInstance->RxTokens);
return EFI_SUCCESS;
}
BOOLEAN
Ip4StationAddressValid (
IN IP4_ADDR Ip,
IN IP4_ADDR Netmask
)
/*++
Routine Description:
Validate that Ip/Netmask pair is OK to be used as station
address. Only continuous netmasks are supported. and check
that StationAddress is a unicast address on the newtwork.
Arguments:
Ip - The IP address to validate
Netmask - The netmaks of the IP
Returns:
TRUE - The Ip/Netmask pair is valid
FALSE - The
--*/
{
IP4_ADDR NetBrdcastMask;
INTN Len;
INTN Type;
//
// Only support the station address with 0.0.0.0/0 to enable DHCP client.
//
if (Netmask == IP4_ALLZERO_ADDRESS) {
return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);
}
//
// Only support the continuous net masks
//
if ((Len = NetGetMaskLength (Netmask)) == IP4_MASK_NUM) {
return FALSE;
}
//
// Station address can't be class D or class E address
//
if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {
return FALSE;
}
//
// Station address can't be subnet broadcast/net broadcast address
//
if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {
return FALSE;
}
NetBrdcastMask = mIp4AllMasks[NET_MIN (Len, Type << 3)];
if (Ip == (Ip | ~NetBrdcastMask)) {
return FALSE;
}
return TRUE;
}
STATIC
EFI_STATUS
EFIAPI
EfiIp4Configure (
IN EFI_IP4_PROTOCOL *This,
IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL
)
/*++
Routine Description:
Configure the EFI_IP4_PROTOCOL instance. If IpConfigData is NULL,
the instance is cleaned up. If the instance hasn't been configure
before, it will be initialized. Otherwise, the filter setting of
the instance is updated.
Arguments:
This - The IP4 child to configure
IpConfigData - The configuration to apply. If NULL, clean it up.
Returns:
EFI_INVALID_PARAMETER - The parameter is invalid
EFI_NO_MAPPING - The default address hasn't been configured
and the instance wants to use it.
EFI_SUCCESS - The instance is configured.
--*/
{
IP4_PROTOCOL *IpInstance;
EFI_IP4_CONFIG_DATA *Current;
EFI_TPL OldTpl;
EFI_STATUS Status;
BOOLEAN AddrOk;
//
// First, validate the parameters
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
//
// Validate the configuration first.
//
if (IpConfigData != NULL) {
//
// This implementation doesn't support RawData
//
if (IpConfigData->RawData) {
Status = EFI_UNSUPPORTED;
goto ON_EXIT;
}
//
// Check whether the station address is a valid unicast address
//
if (!IpConfigData->UseDefaultAddress) {
AddrOk = Ip4StationAddressValid (
EFI_NTOHL (IpConfigData->StationAddress),
EFI_NTOHL (IpConfigData->SubnetMask)
);
if (!AddrOk) {
Status = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
}
//
// User can only update packet filters when already configured.
// If it wants to change the station address, it must configure(NULL)
// the instance first.
//
if (IpInstance->State == IP4_STATE_CONFIGED) {
Current = &IpInstance->ConfigData;
if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {
Status = EFI_ALREADY_STARTED;
goto ON_EXIT;
}
if (!Current->UseDefaultAddress &&
(!EFI_IP_EQUAL (Current->StationAddress, IpConfigData->StationAddress) ||
!EFI_IP_EQUAL (Current->SubnetMask, IpConfigData->SubnetMask))) {
Status = EFI_ALREADY_STARTED;
goto ON_EXIT;
}
if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {
return EFI_NO_MAPPING;
}
}
}
//
// Configure the instance or clean it up.
//
if (IpConfigData != NULL) {
Status = Ip4ConfigProtocol (IpInstance, IpConfigData);
} else {
Status = Ip4CleanProtocol (IpInstance);
//
// Don't change the state if it is DESTORY, consider the following
// valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
// Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
// the unload fails miserably.
//
if (IpInstance->State == IP4_STATE_CONFIGED) {
IpInstance->State = IP4_STATE_UNCONFIGED;
}
}
//
// Update the MNP's configure data. Ip4ServiceConfigMnp will check
// whether it is necessary to reconfigure the MNP.
//
Ip4ServiceConfigMnp (IpInstance->Service, FALSE);
//
// Update the variable data.
//
Ip4SetVariableData (IpInstance->Service);
ON_EXIT:
NET_RESTORE_TPL (OldTpl);
return Status;
}
EFI_STATUS
Ip4Groups (
IN IP4_PROTOCOL *IpInstance,
IN BOOLEAN JoinFlag,
IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
)
/*++
Routine Description:
Change the IP4 child's multicast setting. The caller
should make sure that the parameters is valid.
Arguments:
IpInstance - The IP4 child to change the setting.
JoinFlag - TRUE to join the group, otherwise leave it
GroupAddress - The target group address
Returns:
EFI_ALREADY_STARTED - Want to join the group, but already a member of it
EFI_OUT_OF_RESOURCES - Failed to allocate some resources.
EFI_DEVICE_ERROR - Failed to set the group configuraton
EFI_SUCCESS - Successfully updated the group setting.
EFI_NOT_FOUND - Try to leave the group which it isn't a member.
--*/
{
IP4_ADDR *Members;
IP4_ADDR Group;
UINT32 Index;
//
// Add it to the instance's Groups, and join the group by IGMP.
// IpInstance->Groups is in network byte order. IGMP operates in
// host byte order
//
if (JoinFlag) {
Group = EFI_IP4 (*GroupAddress);
for (Index = 0; Index < IpInstance->GroupCount; Index++) {
if (IpInstance->Groups[Index] == Group) {
return EFI_ALREADY_STARTED;
}
}
Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);
if (Members == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {
NetFreePool (Members);
return EFI_DEVICE_ERROR;
}
if (IpInstance->Groups != NULL) {
NetFreePool (IpInstance->Groups);
}
IpInstance->Groups = Members;
IpInstance->GroupCount++;
return EFI_SUCCESS;
}
//
// Leave the group. Leave all the groups if GroupAddress is NULL.
// Must iterate from the end to the beginning because the GroupCount
// is decreamented each time an address is removed..
//
for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {
Group = IpInstance->Groups[Index - 1];
if ((GroupAddress == NULL) || (Group == EFI_IP4 (*GroupAddress))) {
if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {
return EFI_DEVICE_ERROR;
}
Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);
IpInstance->GroupCount--;
if (IpInstance->GroupCount == 0) {
ASSERT (Index == 1);
NetFreePool (IpInstance->Groups);
IpInstance->Groups = NULL;
}
if (GroupAddress != NULL) {
return EFI_SUCCESS;
}
}
}
return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);
}
STATIC
EFI_STATUS
EFIAPI
EfiIp4Groups (
IN EFI_IP4_PROTOCOL *This,
IN BOOLEAN JoinFlag,
IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL
)
/*++
Routine Description:
Change the IP4 child's multicast setting. If JoinFlag is true,
the child wants to join the group. Otherwise it wants to leave
the group. If JoinFlag is false, and GroupAddress is NULL,
it will leave all the groups which is a member.
Arguments:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?