pxe_bc_ip.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 860 行 · 第 1/2 页
C
860 行
/*++
Copyright (c) 2004, 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:
pxe_bc_ip.c
Abstract:
--*/
#include "bc.h"
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
BOOLEAN
OnSameSubnet (
IN UINTN IpLength,
IN EFI_IP_ADDRESS *Ip1,
IN EFI_IP_ADDRESS *Ip2,
IN EFI_IP_ADDRESS *SubnetMask
)
/*++
Routine Description:
Check if two IP addresses are on the same subnet.
Arguments:
IpLength - Length of IP address in bytes.
Ip1 - IP address to check.
Ip2 - IP address to check.
SubnetMask - Subnet mask to check with.
Returns:
TRUE - IP addresses are on the same subnet.
FALSE - IP addresses are on different subnets.
--*/
{
if (IpLength == 0 || Ip1 == NULL || Ip2 == NULL || SubnetMask == NULL) {
return FALSE;
}
while (IpLength-- != 0) {
if ((Ip1->v6.Addr[IpLength] ^ Ip2->v6.Addr[IpLength]) & SubnetMask->v6.Addr[IpLength]) {
return FALSE;
}
}
return TRUE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
VOID
IpAddRouter (
IN PXE_BASECODE_DEVICE *Private,
IN EFI_IP_ADDRESS *RouterIpPtr
)
/*++
Routine Description:
Add router to router table.
Arguments:
Private - Pointer PxeBc instance data.
RouterIpPtr - Pointer to router IP address.
Returns:
Nothing
--*/
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
UINTN Index;
if (Private == NULL || RouterIpPtr == NULL) {
return ;
}
PxeBcMode = Private->EfiBc.Mode;
//
// if we are filled up or this is not on the same subnet, forget it
//
if ((PxeBcMode->RouteTableEntries == PXE_ROUTER_TABLE_SIZE) ||
!OnSameSubnet(Private->IpLength, &PxeBcMode->StationIp, RouterIpPtr, &PxeBcMode->SubnetMask)) {
return ;
}
//
// make sure we don't already have it
//
for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
if (!EfiCompareMem (
&PxeBcMode->RouteTable[Index].GwAddr,
RouterIpPtr,
Private->IpLength
)) {
return ;
}
}
//
// keep it
//
EfiZeroMem (
&PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries],
sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY)
);
EfiCopyMem (
&PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries++].GwAddr,
RouterIpPtr,
Private->IpLength
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// return router ip to use for DestIp (0 if none)
//
STATIC
EFI_IP_ADDRESS *
GetRouterIp (
PXE_BASECODE_DEVICE *Private,
EFI_IP_ADDRESS *DestIpPtr
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
UINTN Index;
if (Private == NULL || DestIpPtr == NULL) {
return NULL;
}
PxeBcMode = Private->EfiBc.Mode;
for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
if (OnSameSubnet (
Private->IpLength,
&PxeBcMode->RouteTable[Index].IpAddr,
DestIpPtr,
&PxeBcMode->RouteTable[Index].SubnetMask
)) {
return &PxeBcMode->RouteTable[Index].GwAddr;
}
}
return NULL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// routine to send ipv4 packet
// ipv4 header of length HdrLth in TransmitBufferPtr
// routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data
// and gets dest MAC address
//
#define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr)
#define IP_TX_HEADER IP_TX_BUFFER->IpHeader
EFI_STATUS
Ipv4Xmt (
PXE_BASECODE_DEVICE *Private,
UINT32 GatewayIp,
UINTN IpHeaderLength,
UINTN TotalHeaderLength,
VOID *Data,
UINTN DataLength,
EFI_PXE_BASE_CODE_FUNCTION Function
)
{
EFI_MAC_ADDRESS DestMac;
EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
EFI_STATUS StatCode;
UINTN PacketLength;
Snp = Private->SimpleNetwork;
PxeBcMode = Private->EfiBc.Mode;
StatCode = EFI_SUCCESS;
PacketLength = TotalHeaderLength + DataLength;
//
// get dest MAC address
// multicast - convert to hw equiv
// unicast on same net, use arp
// on different net, arp for router
//
if (IP_TX_HEADER.DestAddr.L == BROADCAST_IPv4) {
DestMac = Snp->Mode->BroadcastAddress;
} else if (IS_MULTICAST (&IP_TX_HEADER.DestAddr)) {
StatCode = (*Snp->MCastIpToMac) (Snp, PxeBcMode->UsingIpv6, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr, &DestMac);
} else {
UINT32 Ip;
if (OnSameSubnet (
Private->IpLength,
&PxeBcMode->StationIp,
(EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr,
&PxeBcMode->SubnetMask
)) {
Ip = IP_TX_HEADER.DestAddr.L;
} else if (GatewayIp != 0) {
Ip = GatewayIp;
} else {
EFI_IP_ADDRESS *TmpIp;
TmpIp = GetRouterIp (Private, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr);
if (TmpIp == NULL) {
DEBUG (
(EFI_D_WARN,
"\nIpv4Xmit() Exit #1 %xh (%r)",
EFI_NO_RESPONSE,
EFI_NO_RESPONSE)
);
return EFI_NO_RESPONSE;
//
// no router
//
}
Ip = TmpIp->Addr[0];
}
if (!GetHwAddr (
Private,
(EFI_IP_ADDRESS *) &Ip,
(EFI_MAC_ADDRESS *) &DestMac
)) {
if (!PxeBcMode->AutoArp) {
DEBUG (
(EFI_D_WARN,
"\nIpv4Xmit() Exit #2 %xh (%r)",
EFI_DEVICE_ERROR,
EFI_DEVICE_ERROR)
);
return EFI_DEVICE_ERROR;
} else {
StatCode = DoArp (
Private,
(EFI_IP_ADDRESS *) &Ip,
(EFI_MAC_ADDRESS *) &DestMac
);
}
}
}
if (EFI_ERROR (StatCode)) {
DEBUG ((EFI_D_WARN, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode, StatCode));
return StatCode;
}
//
// fill in packet info
//
SET_IPV4_VER_HDL (&IP_TX_HEADER, IpHeaderLength);
IP_TX_HEADER.TotalLength = HTONS (PacketLength);
IP_TX_HEADER.HeaderChecksum = IpChecksum ((UINT16 *) &IP_TX_HEADER, IpHeaderLength);
EfiCopyMem (((UINT8 *) &IP_TX_HEADER) + TotalHeaderLength, Data, DataLength);
//
// send it
//
return SendPacket (
Private,
(UINT8 *) &IP_TX_HEADER - Snp->Mode->MediaHeaderSize,
&IP_TX_HEADER,
PacketLength,
&DestMac,
PXE_PROTOCOL_ETHERNET_IP,
Function
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// send ipv4 packet with option
//
EFI_STATUS
Ipv4SendWOp (
PXE_BASECODE_DEVICE *Private,
UINT32 GatewayIp,
UINT8 *Msg,
UINTN MessageLength,
UINT8 Prot,
UINT8 *Option,
UINTN OptionLength,
UINT32 DestIp,
EFI_PXE_BASE_CODE_FUNCTION Function
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
UINTN HdrLth;
PxeBcMode = Private->EfiBc.Mode;
HdrLth = sizeof (IPV4_HEADER) + OptionLength;
EfiZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));
IP_TX_HEADER.TimeToLive = PxeBcMode->TTL;
IP_TX_HEADER.TypeOfService = PxeBcMode->ToS;
IP_TX_HEADER.Protocol = Prot;
IP_TX_HEADER.SrcAddr.L = *(UINT32 *) &PxeBcMode->StationIp;
IP_TX_HEADER.DestAddr.L = DestIp;
IP_TX_HEADER.Id = Random (Private);
EfiCopyMem (IP_TX_BUFFER->u.Data, Option, OptionLength);
return Ipv4Xmt (
Private,
GatewayIp,
HdrLth,
HdrLth,
Msg,
MessageLength,
Function
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize
//
EFI_STATUS
Ip4Send (
PXE_BASECODE_DEVICE *Private, // pointer to instance data
UINTN MayFrag, //
UINT8 Prot, // protocol
UINT32 SrcIp, // Source IP address
UINT32 DestIp, // Destination IP address
UINT32 GatewayIp, // used if not NULL and needed
UINTN HdrSize, // protocol header byte length
UINT8 *MessagePtr, // pointer to data
UINTN MessageLength // data byte length
)
{
EFI_STATUS StatCode;
UINTN TotDataLength;
TotDataLength = HdrSize + MessageLength;
if (TotDataLength > MAX_IPV4_DATA_SIZE) {
DEBUG (
(EFI_D_WARN,
"\nIp4Send() Exit #1 %xh (%r)",
EFI_BAD_BUFFER_SIZE,
EFI_BAD_BUFFER_SIZE)
);
return EFI_BAD_BUFFER_SIZE;
}
EfiZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));
IP_TX_HEADER.TimeToLive = DEFAULT_TTL;
IP_TX_HEADER.Protocol = Prot;
IP_TX_HEADER.SrcAddr.L = SrcIp;
IP_TX_HEADER.DestAddr.L = DestIp;
IP_TX_HEADER.Id = Random (Private);
if (!MayFrag) {
*(UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_NO_FRAG >> 8;
}
//
// check for need to fragment
//
if (TotDataLength > MAX_IPV4_FRAME_DATA_SIZE) {
UINTN DataLengthSent;
UINT16 FragmentOffset;
FragmentOffset = IP_MORE_FRAG;
//
// frag offset field
//
if (!MayFrag) {
DEBUG (
(EFI_D_WARN,
"\nIp4Send() Exit #2 %xh (%r)",
EFI_BAD_BUFFER_SIZE,
EFI_BAD_BUFFER_SIZE)
);
return EFI_BAD_BUFFER_SIZE;
}
//
// send out in fragments - first includes upper level header
// all are max and include more frag bit except last
//
* (UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_MORE_FRAG >> 8;
#define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)
#define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)
DataLengthSent = IPV4_FRAG_SIZE - HdrSize;
StatCode = Ipv4Xmt (
Private,
GatewayIp,
sizeof (IPV4_HEADER),
sizeof (IPV4_HEADER) + HdrSize,
MessagePtr,
DataLengthSent,
Private->Function
);
if (EFI_ERROR (StatCode)) {
DEBUG (
(EFI_D_WARN,
"\nIp4Send() Exit #3 %xh (%r)",
StatCode,
StatCode)
);
return StatCode;
}
MessagePtr += DataLengthSent;
MessageLength -= DataLengthSent;
FragmentOffset += IPV4_FRAG_OFF_INC;
IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);
while (MessageLength > IPV4_FRAG_SIZE) {
StatCode = Ipv4Xmt (
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?