support.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,126 行 · 第 1/2 页
C
1,126 行
/*++
Copyright (c) 2004 - 2005, 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:
support.c
Abstract:
Miscellaneous support routines for PxeDhcp4 protocol.
--*/
#include "PxeDhcp4.h"
#define DebugPrint(x)
//
// #define DebugPrint(x) Aprint x
//
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
UINT16
htons (
UINTN n
)
{
return (UINT16) ((n >> 8) | (n << 8));
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
UINT32
htonl (
UINTN n
)
{
return (UINT32) ((n >> 24) | ((n >> 8) & 0xFF00) | ((n & 0xFF00) << 8) | (n << 24));
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
VOID
EFIAPI
timeout_notify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
ASSERT (Context);
if (Context != NULL) {
((PXE_DHCP4_PRIVATE_DATA *) Context)->TimeoutOccurred = TRUE;
}
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
VOID
EFIAPI
periodic_notify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
ASSERT (Context);
if (Context != NULL) {
((PXE_DHCP4_PRIVATE_DATA *) Context)->PeriodicOccurred = TRUE;
}
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
find_opt (
IN DHCP4_PACKET *Packet,
IN UINT8 OpCode,
IN UINTN Skip,
OUT DHCP4_OP **OpPtr
)
/*++
Routine description:
Locate option inside DHCP packet.
Parameters:
Packet := Pointer to DHCP packet structure.
OpCode := Option op-code to find.
Skip := Number of found op-codes to skip.
OpPtr := Pointer to found op-code pointer.
Returns:
EFI_SUCCESS := Option was found
EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL
EFI_INVALID_PARAMETER := OpCode == DHCP4_PAD
EFI_INVALID_PARAMETER := OpCode == DHCP4_END && Skip != 0
EFI_INVALID_PARAMETER := DHCP magik number in Packet is not valid
EFI_NOT_FOUND := op-code was not found in packet
EFI_INVALID_PARAMETER := If present, DHCP_MAX_MESSAGE_SIZE option
does not have a valid value.
--*/
{
UINTN msg_size;
UINTN buf_len;
UINTN n;
UINT8 *buf;
UINT8 *end_ptr;
UINT8 overload;
//
// Verify parameters.
//
if (Packet == NULL || OpPtr == NULL || OpCode == DHCP4_PAD || (OpCode == DHCP4_END && Skip != 0)) {
return EFI_INVALID_PARAMETER;
}
if (Packet->dhcp4.magik != htonl (DHCP4_MAGIK_NUMBER)) {
return EFI_INVALID_PARAMETER;
}
//
// Initialize search variables.
//
*OpPtr = NULL;
msg_size = DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);
overload = 0;
end_ptr = NULL;
buf = Packet->dhcp4.options;
buf_len = msg_size - (Packet->dhcp4.options - Packet->raw);
//
// Start searching for requested option.
//
for (n = 0;;) {
//
// If match is found, decrement skip count and return
// when desired match is found.
//
if (buf[n] == OpCode) {
*OpPtr = (DHCP4_OP *) &buf[n];
if (Skip-- == 0) {
return EFI_SUCCESS;
}
}
//
// Skip past current option. Check for option overload
// and message size options since these will affect the
// amount of data to be searched.
//
switch (buf[n]) {
case DHCP4_PAD:
//
// Remember the first pad byte of a group. This
// could be the end of a badly formed packet.
//
if (end_ptr == NULL) {
end_ptr = &buf[n];
}
++n;
break;
case DHCP4_END:
//
// If we reach the end we are done.
//
end_ptr = NULL;
return EFI_NOT_FOUND;
case DHCP4_OPTION_OVERLOAD:
//
// Remember the option overload value since it
// could cause the search to continue into
// the fname and sname fields.
//
end_ptr = NULL;
if (buf[n + 1] == 1) {
overload = buf[n + 2];
}
n += 2 + buf[n + 1];
break;
case DHCP4_MAX_MESSAGE_SIZE:
//
// Remember the message size value since it could
// change the amount of option buffer to search.
//
end_ptr = NULL;
if (buf[n + 1] == 2 && buf == Packet->dhcp4.options) {
msg_size = ((buf[n + 2] << 8) | buf[n + 3]) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);
if (msg_size < 328) {
return EFI_INVALID_PARAMETER;
}
buf_len = msg_size - (Packet->dhcp4.options - Packet->raw);
if (n + 2 + buf[n + 1] > buf_len) {
return EFI_INVALID_PARAMETER;
}
}
/* fall thru */
default:
end_ptr = NULL;
n += 2 + buf[n + 1];
}
//
// Keep searching until the end of the buffer is reached.
//
if (n < buf_len) {
continue;
}
//
// Reached end of current buffer. Check if we are supposed
// to search the fname and sname buffers.
//
if (buf == Packet->dhcp4.options &&
(overload == DHCP4_OVERLOAD_FNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)
) {
buf = Packet->dhcp4.fname;
buf_len = 128;
n = 0;
continue;
}
if (buf != Packet->dhcp4.sname && (overload == DHCP4_OVERLOAD_SNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)) {
buf = Packet->dhcp4.sname;
buf_len = 64;
n = 0;
continue;
}
//
// End of last buffer reached. If this was a search
// for the end of the options, go back to the start
// of the current pad block.
//
if (OpCode == DHCP4_END && end_ptr != NULL) {
*OpPtr = (DHCP4_OP *) end_ptr;
return EFI_SUCCESS;
}
return EFI_NOT_FOUND;
}
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
add_opt (
IN DHCP4_PACKET *Packet,
IN DHCP4_OP *OpPtr
)
/*++
Routine description:
Add option to DHCP packet.
Parameters:
Packet := Pointer to DHCP packet structure.
OpPtr := Pointer to DHCP option.
Returns:
EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL
EFI_INVALID_PARAMETER := OpPtr->op == DHCP4_PAD || OpPtr->op == DHCP4_END
EFI_INVALID_PARAMETER := DHCP magik number in DHCP packet is not valid
EFI_INVALID_PARAMETER := If DHCP_MAX_MESSAGE_SIZE option is present and
is not valid
EFI_INVALID_PARAMETER := If DHCP_OPTION_OVERLOAD option is present and
is not valid
EFI_DEVICE_ERROR := Cannot determine end of packet
EFI_BUFFER_TOO_SMALL := Not enough room in packet to add option
EFI_SUCCESS := Option added to DHCP packet
--*/
{
EFI_STATUS efi_status;
DHCP4_OP *msg_size_op;
DHCP4_OP *overload_op;
DHCP4_OP *op;
UINTN msg_size;
UINTN buf_len;
UINT32 magik;
UINT8 *buf;
//
// Verify parameters.
//
ASSERT (Packet);
ASSERT (OpPtr);
if (Packet == NULL || OpPtr == NULL) {
return EFI_INVALID_PARAMETER;
}
switch (OpPtr->op) {
case DHCP4_PAD:
case DHCP4_END:
//
// No adding PAD or END.
//
return EFI_INVALID_PARAMETER;
}
//
// Check the DHCP magik number.
//
EfiCopyMem (&magik, &Packet->dhcp4.magik, 4);
if (magik != htonl (DHCP4_MAGIK_NUMBER)) {
return EFI_INVALID_PARAMETER;
}
//
// Find the DHCP message size option.
//
msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE;
efi_status = find_opt (
Packet,
DHCP4_MAX_MESSAGE_SIZE,
0,
&msg_size_op
);
if (EFI_ERROR (efi_status)) {
if (efi_status != EFI_NOT_FOUND) {
DebugPrint (
("%s:%d:%r\n",
__FILE__,
__LINE__,
efi_status)
);
return efi_status;
}
msg_size_op = NULL;
} else {
EfiCopyMem (&msg_size, msg_size_op->data, 2);
msg_size = htons (msg_size);
if (msg_size < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) {
return EFI_INVALID_PARAMETER;
}
}
//
// Find the DHCP option overload option.
//
efi_status = find_opt (
Packet,
DHCP4_OPTION_OVERLOAD,
0,
&overload_op
);
if (EFI_ERROR (efi_status)) {
if (efi_status != EFI_NOT_FOUND) {
DebugPrint (
("%s:%d:%r\n",
__FILE__,
__LINE__,
efi_status)
);
return efi_status;
}
overload_op = NULL;
} else {
if (overload_op->len != 1) {
return EFI_INVALID_PARAMETER;
}
switch (overload_op->data[0]) {
case 1:
case 2:
case 3:
break;
default:
return EFI_INVALID_PARAMETER;
}
}
//
// Find the end of the packet.
//
efi_status = find_opt (Packet, DHCP4_END, 0, &op);
if (EFI_ERROR (efi_status)) {
return EFI_INVALID_PARAMETER;
}
//
// Find which buffer the end is in.
//
if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.options)) {
buf_len = (msg_size - ((UINT8 *) &Packet->dhcp4.options - (UINT8 *) &Packet->raw)) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);
} else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.fname)) {
buf_len = 128;
} else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.sname)) {
buf_len = 64;
} else {
return EFI_DEVICE_ERROR;
}
//
// Add option to current buffer if there is no overlow.
//
if ((UINTN) ((&op->op - buf) + 3 + op->len) < buf_len) {
EfiCopyMem (op, OpPtr, OpPtr->len + 2);
op->data[op->len] = DHCP4_END;
return EFI_SUCCESS;
}
//
// Error if there is no space for option.
//
return EFI_BUFFER_TOO_SMALL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
start_udp (
IN PXE_DHCP4_PRIVATE_DATA *Private,
IN OPTIONAL EFI_IP_ADDRESS *StationIp,
IN OPTIONAL EFI_IP_ADDRESS *SubnetMask
)
/*++
Routine description:
Setup PXE BaseCode UDP stack.
Parameters:
Private := Pointer to PxeDhcp4 private data.
StationIp := Pointer to IP address or NULL if not known.
SubnetMask := Pointer to subnet mask or NULL if not known.
Returns:
EFI_INVALID_PARAMETER := Private == NULL || Private->PxeBc == NULL
EFI_INVALID_PARAMETER := Only one of StationIp and SubnetMask is given
EFI_SUCCESS := UDP stack is ready
other := Error from PxeBc->SetIpFilter() or PxeBc->SetStationIp()
--*/
{
EFI_PXE_BASE_CODE_IP_FILTER bcast_filter;
EFI_STATUS efi_status;
//
//
//
ASSERT (Private);
ASSERT (Private->PxeBc);
if (Private == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Private->PxeBc == NULL) {
return EFI_INVALID_PARAMETER;
}
if (StationIp != NULL && SubnetMask == NULL) {
return EFI_INVALID_PARAMETER;
}
if (StationIp == NULL && SubnetMask != NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Setup broadcast receive filter...
//
EfiZeroMem (&bcast_filter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
bcast_filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;
bcast_filter.IpCnt = 0;
efi_status = Private->PxeBc->SetIpFilter (
Private->PxeBc,
&bcast_filter
);
if (EFI_ERROR (efi_status)) {
DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
return efi_status;
}
//
// Configure station IP address and subnet mask...
//
efi_status = Private->PxeBc->SetStationIp (
Private->PxeBc,
StationIp,
SubnetMask
);
if (EFI_ERROR (efi_status)) {
DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
}
return efi_status;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
VOID
stop_udp (
IN PXE_DHCP4_PRIVATE_DATA *Private
)
{
//
//
//
ASSERT (Private);
ASSERT (Private->PxeBc);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
start_receive_events (
IN PXE_DHCP4_PRIVATE_DATA *Private,
IN UINTN SecondsTimeout
)
/*++
Routine description:
Create periodic and timeout receive events.
Parameters:
Private := Pointer to PxeDhcp4 private data.
SecondsTimeout := Number of seconds to wait before timeout.
Returns:
--*/
{
EFI_STATUS efi_status;
UINTN random;
//
//
//
ASSERT (Private);
ASSERT (SecondsTimeout);
if (Private == NULL || SecondsTimeout == 0) {
return EFI_INVALID_PARAMETER;
}
//
// Need a bettern randomizer...
// For now adjust the timeout value by the least significant
// digit in the MAC address.
//
random = 0;
if (Private->PxeDhcp4.Data != NULL) {
if (Private->PxeDhcp4.Data->Discover.dhcp4.hlen != 0 && Private->PxeDhcp4.Data->Discover.dhcp4.hlen <= 16) {
random = 0xFFF & Private->PxeDhcp4.Data->Discover.dhcp4.chaddr[Private->PxeDhcp4.Data->Discover.dhcp4.hlen - 1];
}
}
//
// Setup timeout event and start timer.
//
efi_status = gBS->CreateEvent (
EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
EFI_TPL_NOTIFY,
&timeout_notify,
Private,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?