dhcp4io.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,756 行 · 第 1/3 页
C
1,756 行
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Dhcp4Io.c
Abstract:
EFI DHCP protocol implementation
--*/
#include "Dhcp4Impl.h"
UINT32 mDhcp4DefaultTimeout[4] = { 4, 8, 16, 32 };
EFI_STATUS
DhcpInitRequest (
IN DHCP_SERVICE *DhcpSb
)
/*++
Routine Description:
Send an initial DISCOVER or REQUEST message according to the
DHCP service's current state.
Arguments:
DhcpSb - The DHCP service instance
Returns:
EFI_SUCCESS - The request has been sent
--*/
{
EFI_STATUS Status;
ASSERT ((DhcpSb->DhcpState == Dhcp4Init) || (DhcpSb->DhcpState == Dhcp4InitReboot));
if (DhcpSb->DhcpState == Dhcp4Init) {
DhcpSetState (DhcpSb, Dhcp4Selecting, FALSE);
Status = DhcpSendMessage (DhcpSb, NULL, NULL, DHCP_MSG_DISCOVER, NULL);
if (EFI_ERROR (Status)) {
DhcpSb->DhcpState = Dhcp4Init;
return Status;
}
DhcpSb->WaitOffer = DHCP_WAIT_OFFER;
} else {
DhcpSetState (DhcpSb, Dhcp4Rebooting, FALSE);
Status = DhcpSendMessage (DhcpSb, NULL, NULL, DHCP_MSG_REQUEST, NULL);
if (EFI_ERROR (Status)) {
DhcpSb->DhcpState = Dhcp4InitReboot;
return Status;
}
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
DhcpCallUser (
IN DHCP_SERVICE *DhcpSb,
IN EFI_DHCP4_EVENT Event,
IN EFI_DHCP4_PACKET *Packet, OPTIONAL
OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL
)
/*++
Routine Description:
Call user provided callback function, and return the value the
function returns. If the user doesn't provide a callback, a
proper return value is selected to let the caller continue the
normal process.
Arguments:
DhcpSb - The DHCP service instance
Event - The event as defined in the spec
Packet - The current packet trigger the event
NewPacket - The user's return new packet
Returns:
EFI_NOT_READY - Direct the caller to continue collecting the offer.
EFI_SUCCESS - The user function returns success.
EFI_ABORTED - The user function ask it to abort.
--*/
{
EFI_DHCP4_CONFIG_DATA *Config;
EFI_STATUS Status;
if (NewPacket != NULL) {
*NewPacket = NULL;
}
//
// If user doesn't provide the call back function, return the value
// that directs the client to continue the normal process.
// In Dhcp4Selecting EFI_SUCCESS tells the client to stop collecting
// the offers and select a offer, EFI_NOT_READY tells the client to
// collect more offers.
//
Config = &DhcpSb->ActiveConfig;
if (Config->Dhcp4Callback == NULL) {
if (Event == Dhcp4RcvdOffer) {
return EFI_NOT_READY;
}
return EFI_SUCCESS;
}
Status = Config->Dhcp4Callback (
&DhcpSb->ActiveChild->Dhcp4Protocol,
Config->CallbackContext,
DhcpSb->DhcpState,
Event,
Packet,
NewPacket
);
//
// User's callback should only return EFI_SUCCESS, EFI_NOT_READY,
// and EFI_ABORTED. If it returns values other than those, assume
// it to be EFI_ABORTED.
//
if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_READY)) {
return Status;
}
return EFI_ABORTED;
}
VOID
DhcpNotifyUser (
IN DHCP_SERVICE *DhcpSb,
IN INTN Which
)
/*++
Routine Description:
Notify the user about the operation result.
Arguments:
DhcpSb - DHCP service instance
Which - which notify function to signal
Returns:
None
--*/
{
DHCP_PROTOCOL *Child;
if ((Child = DhcpSb->ActiveChild) == NULL) {
return ;
}
if ((Child->CompletionEvent != NULL) &&
((Which == DHCP_NOTIFY_COMPLETION) || (Which == DHCP_NOTIFY_ALL))) {
gBS->SignalEvent (Child->CompletionEvent);
Child->CompletionEvent = NULL;
}
if ((Child->RenewRebindEvent != NULL) &&
((Which == DHCP_NOTIFY_RENEWREBIND) || (Which == DHCP_NOTIFY_ALL))) {
gBS->SignalEvent (Child->RenewRebindEvent);
Child->RenewRebindEvent = NULL;
}
}
EFI_STATUS
DhcpSetState (
IN DHCP_SERVICE *DhcpSb,
IN INTN State,
IN BOOLEAN CallUser
)
/*++
Routine Description:
Set the DHCP state. If CallUser is true, it will try to notify
the user before change the state by DhcpNotifyUser. It returns
EFI_ABORTED if the user return EFI_ABORTED, otherwise, it returns
EFI_SUCCESS. If CallUser is FALSE, it isn't necessary to test
the return value of this function.
Arguments:
DhcpSb - The DHCP service instance
State - The new DHCP state to change to
CallUser - Whether we need to call user
Returns:
EFI_SUCCESS - The state is changed
EFI_ABORTED - The user asks to abort the DHCP process.
--*/
{
EFI_STATUS Status;
if (CallUser) {
Status = EFI_SUCCESS;
if (State == Dhcp4Renewing) {
Status = DhcpCallUser (DhcpSb, Dhcp4EnterRenewing, NULL, NULL);
} else if (State == Dhcp4Rebinding) {
Status = DhcpCallUser (DhcpSb, Dhcp4EnterRebinding, NULL, NULL);
} else if (State == Dhcp4Bound) {
Status = DhcpCallUser (DhcpSb, Dhcp4BoundCompleted, NULL, NULL);
}
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// Update the retransmission timer during the state transition.
// This will clear the retry count. This is also why the rule
// first transit the state, then send packets.
//
if (State == Dhcp4Init) {
DhcpSb->MaxRetries = DhcpSb->ActiveConfig.DiscoverTryCount;
} else {
DhcpSb->MaxRetries = DhcpSb->ActiveConfig.RequestTryCount;
}
if (DhcpSb->MaxRetries == 0) {
DhcpSb->MaxRetries = 4;
}
DhcpSb->CurRetry = 0;
DhcpSb->PacketToLive = 0;
DhcpSb->DhcpState = State;
return EFI_SUCCESS;
}
STATIC
VOID
DhcpSetTransmitTimer (
IN DHCP_SERVICE *DhcpSb
)
/*++
Routine Description:
Set the retransmit timer for the packet. It will select from either
the discover timeouts/request timeouts or the default timeout values.
Arguments:
DhcpSb - The DHCP service instance.
Returns:
None
--*/
{
UINT32 *Times;
ASSERT (DhcpSb->MaxRetries > DhcpSb->CurRetry);
if (DhcpSb->DhcpState == Dhcp4Init) {
Times = DhcpSb->ActiveConfig.DiscoverTimeout;
} else {
Times = DhcpSb->ActiveConfig.RequestTimeout;
}
if (Times == NULL) {
Times = mDhcp4DefaultTimeout;
}
DhcpSb->PacketToLive = Times[DhcpSb->CurRetry];
}
STATIC
VOID
DhcpComputeLease (
IN DHCP_SERVICE *DhcpSb,
IN DHCP_PARAMETER *Para
)
/*++
Routine Description:
Compute the lease. If the server grants a permanent lease, just
process it as a normal timeout value since the lease will last
more than 100 years.
Arguments:
DhcpSb - The DHCP service instance
Para - The DHCP parameter extracted from the server's response.
Returns:
None
--*/
{
ASSERT (Para != NULL);
DhcpSb->Lease = Para->Lease;
DhcpSb->T2 = Para->T2;
DhcpSb->T1 = Para->T1;
if (DhcpSb->Lease == 0) {
DhcpSb->Lease = DHCP_DEFAULT_LEASE;
}
if ((DhcpSb->T2 == 0) || (DhcpSb->T2 >= Para->Lease)) {
DhcpSb->T2 = Para->Lease - (Para->Lease >> 3);
}
if ((DhcpSb->T1 == 0) || (DhcpSb->T1 >= Para->T2)) {
DhcpSb->T1 = DhcpSb->Lease >> 1;
}
}
EFI_STATUS
DhcpConfigLeaseIoPort (
IN UDP_IO_PORT *UdpIo,
IN VOID *Context
)
/*++
Routine Description:
Configure a UDP IO port to use the acquired lease address.
DHCP driver needs this port to unicast packet to the server
such as DHCP release.
Arguments:
UdpIo - The UDP IO port to configure
Context - The opaque parameter to the function.
Returns:
EFI_SUCCESS - The UDP IO port is successfully configured.
Others - It failed to configure the port.
--*/
{
EFI_UDP4_CONFIG_DATA UdpConfigData;
EFI_IPv4_ADDRESS Subnet;
EFI_IPv4_ADDRESS Gateway;
DHCP_SERVICE *DhcpSb;
EFI_STATUS Status;
DhcpSb = (DHCP_SERVICE *) Context;
UdpConfigData.AcceptBroadcast = FALSE;
UdpConfigData.AcceptPromiscuous = FALSE;
UdpConfigData.AcceptAnyPort = FALSE;
UdpConfigData.AllowDuplicatePort = TRUE;
UdpConfigData.TypeOfService = 0;
UdpConfigData.TimeToLive = 64;
UdpConfigData.DoNotFragment = FALSE;
UdpConfigData.ReceiveTimeout = 1;
UdpConfigData.TransmitTimeout = 0;
UdpConfigData.UseDefaultAddress = FALSE;
UdpConfigData.StationPort = DHCP_CLIENT_PORT;
UdpConfigData.RemotePort = DHCP_SERVER_PORT;
EFI_IP4 (UdpConfigData.StationAddress)= HTONL (DhcpSb->ClientAddr);
EFI_IP4 (UdpConfigData.SubnetMask) = HTONL (DhcpSb->Netmask);
EFI_IP4 (UdpConfigData.RemoteAddress) = 0;
Status = UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Add a default route if received from the server.
//
if ((DhcpSb->Para != NULL) && (DhcpSb->Para->Router != 0)) {
EFI_IP4 (Subnet) = 0;
EFI_IP4 (Gateway) = HTONL (DhcpSb->Para->Router);
UdpIo->Udp->Routes (UdpIo->Udp, FALSE, &Subnet, &Subnet, &Gateway);
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
DhcpLeaseAcquired (
IN DHCP_SERVICE *DhcpSb
)
/*++
Routine Description:
Update the lease states when a new lease is acquired. It will not only
save the acquired the address and lease time, it will also create a UDP
child to provide address resolution for the address.
Arguments:
DhcpSb - The DHCP service instance
Returns:
EFI_OUT_OF_RESOURCES - Failed to allocate resources.
EFI_SUCCESS - The lease is recorded.
--*/
{
INTN Class;
DhcpSb->ClientAddr = EFI_NTOHL (DhcpSb->Selected->Dhcp4.Header.YourAddr);
if (DhcpSb->Para != NULL) {
DhcpSb->Netmask = DhcpSb->Para->NetMask;
DhcpSb->ServerAddr = DhcpSb->Para->ServerId;
}
if (DhcpSb->Netmask == 0) {
Class = NetGetIpClass (DhcpSb->ClientAddr);
DhcpSb->Netmask = mIp4AllMasks[Class << 3];
}
if (DhcpSb->LeaseIoPort != NULL) {
UdpIoFreePort (DhcpSb->LeaseIoPort);
}
//
// Create a UDP/IP child to provide ARP service for the Leased IP,
// and transmit unicast packet with it as source address. Don't
// start receive on this port, the queued packet will be timeout.
//
DhcpSb->LeaseIoPort = UdpIoCreatePort (
DhcpSb->Controller,
DhcpSb->Image,
DhcpConfigLeaseIoPort,
DhcpSb
);
if (DhcpSb->LeaseIoPort == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (!DHCP_IS_BOOTP (DhcpSb->Para)) {
DhcpComputeLease (DhcpSb, DhcpSb->Para);
}
return DhcpSetState (DhcpSb, Dhcp4Bound, TRUE);
}
VOID
DhcpCleanLease (
IN DHCP_SERVICE *DhcpSb
)
/*++
Routine Description:
Clean up the DHCP related states, IoStatus isn't reset.
Arguments:
DhcpSb - The DHCP instance service.
Returns:
None
--*/
{
DhcpSb->DhcpState = Dhcp4Init;
DhcpSb->Xid = DhcpSb->Xid + 1;
DhcpSb->ClientAddr = 0;
DhcpSb->ServerAddr = 0;
if (DhcpSb->LastOffer != NULL) {
NetFreePool (DhcpSb->LastOffer);
DhcpSb->LastOffer = NULL;
}
if (DhcpSb->Selected != NULL) {
NetFreePool (DhcpSb->Selected);
DhcpSb->Selected = NULL;
}
if (DhcpSb->Para != NULL) {
NetFreePool (DhcpSb->Para);
DhcpSb->Para = NULL;
}
DhcpSb->Lease = 0;
DhcpSb->T1 = 0;
DhcpSb->T2 = 0;
DhcpSb->ExtraRefresh = FALSE;
if (DhcpSb->LeaseIoPort != NULL) {
UdpIoFreePort (DhcpSb->LeaseIoPort);
DhcpSb->LeaseIoPort = NULL;
}
if (DhcpSb->LastPacket != NULL) {
NetbufFree (DhcpSb->LastPacket);
DhcpSb->LastPacket = NULL;
}
DhcpSb->PacketToLive = 0;
DhcpSb->CurRetry = 0;
DhcpSb->MaxRetries = 0;
DhcpSb->WaitOffer = 0;
DhcpSb->LeaseLife = 0;
}
STATIC
EFI_STATUS
DhcpChooseOffer (
IN DHCP_SERVICE *DhcpSb
)
/*++
Routine Description:
Select a offer among all the offers collected. If the offer selected is
of BOOTP, the lease is recorded and user notified. If the offer is of
DHCP, it will request the offer from the server.
Arguments:
DhcpSb - The DHCP service instance.
Returns:
EFI_SUCCESS - One of the offer is selected.
--*/
{
EFI_DHCP4_PACKET *Selected;
EFI_DHCP4_PACKET *NewPacket;
EFI_STATUS Status;
ASSERT (DhcpSb->LastOffer != NULL);
//
// Stop waiting more offers
//
DhcpSb->WaitOffer = 0;
//
// User will cache previous offers if he wants to select
// from multiple offers. If user provides an invalid packet,
// use the last offer, otherwise use the provided packet.
//
NewPacket = NULL;
Status = DhcpCallUser (DhcpSb, Dhcp4SelectOffer, DhcpSb->LastOffer, &NewPacket);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?