pxe_bc_ip.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 860 行 · 第 1/2 页
C
860 行
Private,
GatewayIp,
sizeof (IPV4_HEADER),
sizeof (IPV4_HEADER),
MessagePtr,
IPV4_FRAG_SIZE,
Private->Function
);
if (EFI_ERROR (StatCode)) {
DEBUG (
(EFI_D_WARN,
"\nIp4Send() Exit #3 %xh (%r)",
StatCode,
StatCode)
);
return StatCode;
}
MessagePtr += IPV4_FRAG_SIZE;
MessageLength -= IPV4_FRAG_SIZE;
FragmentOffset += IPV4_FRAG_OFF_INC;
IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);
}
* (UINT8 *) (&IP_TX_HEADER.FragmentFields) &= ~(IP_MORE_FRAG >> 8);
HdrSize = 0;
}
//
// transmit
//
return Ipv4Xmt (
Private,
GatewayIp,
sizeof (IPV4_HEADER),
sizeof (IPV4_HEADER) + HdrSize,
MessagePtr,
MessageLength,
Private->Function
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// return true if dst IP in receive header matched with what's enabled
//
STATIC
BOOLEAN
IPgood (
PXE_BASECODE_DEVICE *Private,
IPV4_HEADER *IpHeader
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
UINTN Index;
PxeBcMode = Private->EfiBc.Mode;
if (PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {
return TRUE;
}
if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) &&
IS_MULTICAST (&IpHeader->DestAddr)
) {
return TRUE;
}
if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) &&
PxeBcMode->StationIp.Addr[0] == IpHeader->DestAddr.L
) {
return TRUE;
}
if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) && IpHeader->DestAddr.L == BROADCAST_IPv4) {
return TRUE;
}
for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; ++Index) {
if (IpHeader->DestAddr.L == PxeBcMode->IpFilter.IpList[Index].Addr[0]) {
return TRUE;
}
}
return FALSE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// receive up to MessageLength message into MessagePtr for protocol Prot
// return message length, src/dest ips if select any, and pointer to protocol
// header routine will filter based on source and/or dest ip if OpFlags set.
//
EFI_STATUS
IpReceive (
PXE_BASECODE_DEVICE *Private,
PXE_OPFLAGS OpFlags,
EFI_IP_ADDRESS *SrcIpPtr,
EFI_IP_ADDRESS *DestIpPtr,
UINT8 Prot,
VOID *HeaderPtr,
UINTN HdrSize,
UINT8 *MessagePtr,
UINTN *MessageLengthPtr,
EFI_EVENT TimeoutEvent
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
EFI_STATUS StatCode;
UINTN ByteCount;
UINTN FragmentCount;
UINTN ExpectedPacketLength;
UINTN Id;
BOOLEAN GotFirstFragment;
BOOLEAN GotLastFragment;
DEBUG (
(EFI_D_NET,
"\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d",
HeaderPtr,
HdrSize,
MessagePtr,
*MessageLengthPtr)
);
PxeBcMode = Private->EfiBc.Mode;
PxeBcMode->IcmpErrorReceived = FALSE;
ExpectedPacketLength = 0;
GotFirstFragment = FALSE;
GotLastFragment = FALSE;
FragmentCount = 0;
ByteCount = 0;
Id = 0;
for (;;) {
IPV4_HEADER IpHdr;
UINTN FFlds;
UINTN TotalLength;
UINTN FragmentOffset;
UINTN HeaderSize;
UINTN BufferSize;
UINTN IpHeaderLength;
UINTN DataLength;
UINT16 Protocol;
UINT8 *NextHdrPtr;
UINT8 *PacketPtr;
StatCode = WaitForReceive (
Private,
Private->Function,
TimeoutEvent,
&HeaderSize,
&BufferSize,
&Protocol
);
if (EFI_ERROR (StatCode)) {
return StatCode;
}
PacketPtr = Private->ReceiveBufferPtr + HeaderSize;
if (Protocol == PXE_PROTOCOL_ETHERNET_ARP) {
HandleArpReceive (
Private,
(ARP_PACKET *) PacketPtr,
Private->ReceiveBufferPtr
);
continue;
}
if (Protocol != PXE_PROTOCOL_ETHERNET_IP) {
continue;
}
#if SUPPORT_IPV6
if (PxeBcMode->UsingIpv6) {
//
// TBD
//
}
#endif
#define IpRxHeader ((IPV4_HEADER *) PacketPtr)
//
// filter for version & check sum
//
IpHeaderLength = IPV4_HEADER_LENGTH (IpRxHeader);
if ((IpRxHeader->VersionIhl >> 4) != IPVER4) {
continue;
}
if (IpChecksum ((UINT16 *) IpRxHeader, IpHeaderLength)) {
continue;
}
IpHdr = *IpRxHeader;
TotalLength = NTOHS (IpHdr.TotalLength);
if (IpHdr.Protocol == PROT_TCP) {
//
// The NextHdrPtr is used to seed the header buffer we are passing back.
// That being the case, we want to see everything in pPkt which contains
// everything but the ethernet (or whatever) frame. IP + TCP in this case.
//
DataLength = TotalLength;
NextHdrPtr = PacketPtr;
} else {
DataLength = TotalLength - IpHeaderLength;
NextHdrPtr = PacketPtr + IpHeaderLength;
}
//
// If this is an ICMP, it might not be for us.
// Double check the state of the IP stack and the
// packet fields before assuming it is an ICMP
// error. ICMP requests are not supported by the
// PxeBc IP stack and should be ignored.
//
if (IpHdr.Protocol == PROT_ICMP) {
ICMPV4_HEADER *Icmpv4;
Icmpv4 = (ICMPV4_HEADER *) NextHdrPtr;
//
// For now only obvious ICMP error replies will be accepted by
// this stack. This still makes us vulnerable to DoS attacks.
// But at least we will not be killed by DHCP daemons.
//
switch (Icmpv4->Type) {
case ICMP_REDIRECT:
case ICMP_ECHO:
case ICMP_ROUTER_ADV:
case ICMP_ROUTER_SOLICIT:
case ICMP_TIMESTAMP:
case ICMP_TIMESTAMP_REPLY:
case ICMP_INFO_REQ:
case ICMP_INFO_REQ_REPLY:
case ICMP_SUBNET_MASK_REQ:
case ICMP_SUBNET_MASK_REPLY:
default:
continue;
//
// %%TBD - This should be implemented.
//
case ICMP_ECHO_REPLY:
continue;
case ICMP_DEST_UNREACHABLE:
case ICMP_TIME_EXCEEDED:
case ICMP_PARAMETER_PROBLEM:
case ICMP_SOURCE_QUENCH:
PxeBcMode->IcmpErrorReceived = TRUE;
EfiCopyMem (
&PxeBcMode->IcmpError,
NextHdrPtr,
sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
);
DEBUG (
(EFI_D_NET,
"\nIpReceive() Exit #1 %Xh (%r)",
EFI_ICMP_ERROR,
EFI_ICMP_ERROR)
);
}
return EFI_ICMP_ERROR;
}
if (IpHdr.Protocol == PROT_IGMP) {
HandleIgmp (Private, (IGMPV2_MESSAGE *) NextHdrPtr, DataLength);
DEBUG ((EFI_D_NET, "\n IGMP"));
continue;
}
//
// check for protocol
//
if (IpHdr.Protocol != Prot) {
continue;
}
//
// do filtering
//
if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr && SrcIpPtr->Addr[0] != IpHdr.SrcAddr.L) {
DEBUG ((EFI_D_NET, "\n Not expected source IP address."));
continue;
}
if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) {
if (!IPgood (Private, &IpHdr)) {
continue;
}
} else if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP)) {
if (DestIpPtr == NULL) {
if (PxeBcMode->StationIp.Addr[0] != IpHdr.DestAddr.L) {
continue;
}
} else if (DestIpPtr->Addr[0] != IpHdr.DestAddr.L) {
continue;
}
}
//
// get some data we need
//
FFlds = NTOHS (IpHdr.FragmentFields);
FragmentOffset = ((FFlds & IP_FRAG_OFF_MSK) << 3);
/* Keep count of fragments that belong to this session.
* If we get packets with a different IP ID number,
* ignore them. Ignored packets should be handled
* by the upper level protocol.
*/
if (FragmentCount == 0) {
Id = IpHdr.Id;
if (DestIpPtr != NULL) {
DestIpPtr->Addr[0] = IpHdr.DestAddr.L;
}
if (SrcIpPtr != NULL) {
SrcIpPtr->Addr[0] = IpHdr.SrcAddr.L;
}
} else {
if (IpHdr.Id != Id) {
continue;
}
}
++FragmentCount;
/* Fragment management.
*/
if (FragmentOffset == 0) {
/* This is the first fragment (may also be the
* only fragment).
*/
GotFirstFragment = TRUE;
/* If there is a separate protocol header buffer,
* copy the header, adjust the data pointer and
* the data length.
*/
if (HdrSize != 0) {
EfiCopyMem (HeaderPtr, NextHdrPtr, HdrSize);
NextHdrPtr += HdrSize;
DataLength -= HdrSize;
}
} else {
/* If there is a separate protocol header buffer,
* adjust the fragment offset.
*/
FragmentOffset -= HdrSize;
}
/* See if this is the last fragment.
*/
if (!(FFlds & IP_MORE_FRAG)) {
//
// This is the last fragment (may also be the only fragment).
//
GotLastFragment = TRUE;
/* Compute the expected length of the assembled
* packet. This will be used to decide if we
* have gotten all of the fragments.
*/
ExpectedPacketLength = FragmentOffset + DataLength;
}
DEBUG (
(EFI_D_NET,
"\n ID = %Xh Off = %d Len = %d",
Id,
FragmentOffset,
DataLength)
);
/* Check for receive buffer overflow.
*/
if (FragmentOffset + DataLength > *MessageLengthPtr) {
/* There is not enough space in the receive
* buffer for the fragment.
*/
DEBUG (
(EFI_D_NET,
"\nIpReceive() Exit #3 %Xh (%r)",
EFI_BUFFER_TOO_SMALL,
EFI_BUFFER_TOO_SMALL)
);
return EFI_BUFFER_TOO_SMALL;
}
/* Copy data into receive buffer.
*/
if (DataLength != 0) {
DEBUG ((EFI_D_NET, " To = %Xh", MessagePtr + FragmentOffset));
EfiCopyMem (MessagePtr + FragmentOffset, NextHdrPtr, DataLength);
ByteCount += DataLength;
}
/* If we have seen the first and last fragments and
* the receive byte count is at least as large as the
* expected byte count, return SUCCESS.
*
* We could be tricked by receiving a fragment twice
* but the upper level protocol should figure this
* out.
*/
if (GotFirstFragment && GotLastFragment && ByteCount >= ExpectedPacketLength) {
*MessageLengthPtr = ExpectedPacketLength;
return EFI_SUCCESS;
}
}
}
/* eof - pxe_bc_ip.c */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?