[Change summary]:

1. Update NetLib to a combined NetLib support dual network stack:
1) Add Network Debug facility for IPv4 stack.
2) Extend the library APIs to support IPv6 stack:
   a. NetIp6IsUnspecifiedAddr
   b. NetIp6IsLinkLocalAddr   
   c. NetIp6IsNetEqual
   d. NetLibCreateIPv6DPathNode.
   e. NetIp6PseudoHeadChecksum
   f. NetIp6IsValidUnicast
3) Update the structure definitions:
   a. Update NET_BUF to add EFI_IP6_HEADER and EFI_UDP_HEADER
   b. Add NET_IP6_PSEUDO_HDR
4) Update Ip4IsUnicast to NetIp4IsUnicast

2. Update the impacted modules to adopt the combined NetLib.

3. Clean up coding style errors in all network drivers and libraries.


git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9391 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
tye
2009-11-04 08:18:34 +00:00
parent 7be273b7f5
commit f6b7393ceb
54 changed files with 1603 additions and 809 deletions

View File

@ -81,6 +81,452 @@ IP4_ADDR gIp4AllMasks[IP4_MASK_NUM] = {
EFI_IPv4_ADDRESS mZeroIp4Addr = {{0, 0, 0, 0}};
//
// Any error level digitally larger than mNetDebugLevelMax
// will be silently discarded.
//
UINTN mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;
UINT32 mSyslogPacketSeq = 0xDEADBEEF;
//
// You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp
// here to direct the syslog packets to the syslog deamon. The
// default is broadcast to both the ethernet and IP.
//
UINT8 mSyslogDstMac[NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
UINT32 mSyslogDstIp = 0xffffffff;
UINT32 mSyslogSrcIp = 0;
CHAR8 *
mMonthName[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
};
/**
Locate the handles that support SNP, then open one of them
to send the syslog packets. The caller isn't required to close
the SNP after use because the SNP is opened by HandleProtocol.
@return The point to SNP if one is properly openned. Otherwise NULL
**/
EFI_SIMPLE_NETWORK_PROTOCOL *
SyslogLocateSnp (
VOID
)
{
EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
EFI_STATUS Status;
EFI_HANDLE *Handles;
UINTN HandleCount;
UINTN Index;
//
// Locate the handles which has SNP installed.
//
Handles = NULL;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiSimpleNetworkProtocolGuid,
NULL,
&HandleCount,
&Handles
);
if (EFI_ERROR (Status) || (HandleCount == 0)) {
return NULL;
}
//
// Try to open one of the ethernet SNP protocol to send packet
//
Snp = NULL;
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (
Handles[Index],
&gEfiSimpleNetworkProtocolGuid,
(VOID **) &Snp
);
if ((Status == EFI_SUCCESS) && (Snp != NULL) &&
(Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&
(Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {
break;
}
Snp = NULL;
}
FreePool (Handles);
return Snp;
}
/**
Transmit a syslog packet synchronously through SNP. The Packet
already has the ethernet header prepended. This function should
fill in the source MAC because it will try to locate a SNP each
time it is called to avoid the problem if SNP is unloaded.
This code snip is copied from MNP.
@param[in] Packet - The Syslog packet
@param[in] Length - The length of the packet
@retval EFI_DEVICE_ERROR - Failed to locate a usable SNP protocol
@retval EFI_TIMEOUT - Timeout happened to send the packet.
@retval EFI_SUCCESS - Packet is sent.
**/
EFI_STATUS
SyslogSendPacket (
IN CHAR8 *Packet,
IN UINT32 Length
)
{
EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
ETHER_HEAD *Ether;
EFI_STATUS Status;
EFI_EVENT TimeoutEvent;
UINT8 *TxBuf;
Snp = SyslogLocateSnp ();
if (Snp == NULL) {
return EFI_DEVICE_ERROR;
}
Ether = (ETHER_HEAD *) Packet;
CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);
//
// Start the timeout event.
//
Status = gBS->CreateEvent (
EVT_TIMER,
TPL_NOTIFY,
NULL,
NULL,
&TimeoutEvent
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
for (;;) {
//
// Transmit the packet through SNP.
//
Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);
if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {
Status = EFI_DEVICE_ERROR;
break;
}
//
// If Status is EFI_SUCCESS, the packet is put in the transmit queue.
// if Status is EFI_NOT_READY, the transmit engine of the network
// interface is busy. Both need to sync SNP.
//
TxBuf = NULL;
do {
//
// Get the recycled transmit buffer status.
//
Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);
if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
Status = EFI_TIMEOUT;
break;
}
} while (TxBuf == NULL);
if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {
break;
}
//
// Status is EFI_NOT_READY. Restart the timer event and
// call Snp->Transmit again.
//
gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);
}
gBS->SetTimer (TimeoutEvent, TimerCancel, 0);
ON_EXIT:
gBS->CloseEvent (TimeoutEvent);
return Status;
}
/**
Build a syslog packet, including the Ethernet/Ip/Udp headers
and user's message.
@param[in] Level - Syslog servity level
@param[in] Module - The module that generates the log
@param[in] File - The file that contains the current log
@param[in] Line - The line of code in the File that contains the current log
@param[in] Message - The log message
@param[in] BufLen - The lenght of the Buf
@param[out] Buf - The buffer to put the packet data
Returns:
The length of the syslog packet built.
**/
UINT32
SyslogBuildPacket (
IN UINT32 Level,
IN UINT8 *Module,
IN UINT8 *File,
IN UINT32 Line,
IN UINT8 *Message,
IN UINT32 BufLen,
OUT CHAR8 *Buf
)
{
ETHER_HEAD *Ether;
IP4_HEAD *Ip4;
EFI_UDP_HEADER *Udp4;
EFI_TIME Time;
UINT32 Pri;
UINT32 Len;
//
// Fill in the Ethernet header. Leave alone the source MAC.
// SyslogSendPacket will fill in the address for us.
//
Ether = (ETHER_HEAD *) Buf;
CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);
ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);
Ether->EtherType = HTONS (0x0800); // IPv4 protocol
Buf += sizeof (ETHER_HEAD);
BufLen -= sizeof (ETHER_HEAD);
//
// Fill in the IP header
//
Ip4 = (IP4_HEAD *) Buf;
Ip4->HeadLen = 5;
Ip4->Ver = 4;
Ip4->Tos = 0;
Ip4->TotalLen = 0;
Ip4->Id = (UINT16) mSyslogPacketSeq;
Ip4->Fragment = 0;
Ip4->Ttl = 16;
Ip4->Protocol = 0x11;
Ip4->Checksum = 0;
Ip4->Src = mSyslogSrcIp;
Ip4->Dst = mSyslogDstIp;
Buf += sizeof (IP4_HEAD);
BufLen -= sizeof (IP4_HEAD);
//
// Fill in the UDP header, Udp checksum is optional. Leave it zero.
//
Udp4 = (EFI_UDP_HEADER *) Buf;
Udp4->SrcPort = HTONS (514);
Udp4->DstPort = HTONS (514);
Udp4->Length = 0;
Udp4->Checksum = 0;
Buf += sizeof (EFI_UDP_HEADER);
BufLen -= sizeof (EFI_UDP_HEADER);
//
// Build the syslog message body with <PRI> Timestamp machine module Message
//
Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);
gRT->GetTime (&Time, NULL);
//
// Use %a to format the ASCII strings, %s to format UNICODE strings
//
Len = 0;
Len += (UINT32) AsciiSPrint (
Buf,
BufLen,
"<%d> %a %d %d:%d:%d ",
Pri,
mMonthName [Time.Month-1],
Time.Day,
Time.Hour,
Time.Minute,
Time.Second
);
Len--;
Len += (UINT32) AsciiSPrint (
Buf + Len,
BufLen - Len,
"Tiano %a: %a (Line: %d File: %a)",
Module,
Message,
Line,
File
);
Len--;
//
// OK, patch the IP length/checksum and UDP length fields.
//
Len += sizeof (EFI_UDP_HEADER);
Udp4->Length = HTONS ((UINT16) Len);
Len += sizeof (IP4_HEAD);
Ip4->TotalLen = HTONS ((UINT16) Len);
Ip4->Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD)));
return Len + sizeof (ETHER_HEAD);
}
/**
Allocate a buffer, then format the message to it. This is a
help function for the NET_DEBUG_XXX macros. The PrintArg of
these macros treats the variable length print parameters as a
single parameter, and pass it to the NetDebugASPrint. For
example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))
if extracted to:
NetDebugOutput (
NETDEBUG_LEVEL_TRACE,
"Tcp",
__FILE__,
__LINE__,
NetDebugASPrint ("State transit to %a\n", Name)
)
@param Format The ASCII format string.
@param ... The variable length parameter whose format is determined
by the Format string.
@return The buffer containing the formatted message,
or NULL if failed to allocate memory.
**/
CHAR8 *
NetDebugASPrint (
IN CHAR8 *Format,
...
)
{
VA_LIST Marker;
CHAR8 *Buf;
Buf = (CHAR8 *) AllocatePool (NET_DEBUG_MSG_LEN);
if (Buf == NULL) {
return NULL;
}
VA_START (Marker, Format);
AsciiVSPrint (Buf, NET_DEBUG_MSG_LEN, Format, Marker);
VA_END (Marker);
return Buf;
}
/**
Builds an UDP4 syslog packet and send it using SNP.
This function will locate a instance of SNP then send the message through it.
Because it isn't open the SNP BY_DRIVER, apply caution when using it.
@param Level The servity level of the message.
@param Module The Moudle that generates the log.
@param File The file that contains the log.
@param Line The exact line that contains the log.
@param Message The user message to log.
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet
@retval EFI_SUCCESS The log is discard because that it is more verbose
than the mNetDebugLevelMax. Or, it has been sent out.
**/
EFI_STATUS
NetDebugOutput (
IN UINT32 Level,
IN UINT8 *Module,
IN UINT8 *File,
IN UINT32 Line,
IN UINT8 *Message
)
{
CHAR8 *Packet;
UINT32 Len;
EFI_STATUS Status;
//
// Check whether the message should be sent out
//
if (Message == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Level > mNetDebugLevelMax) {
Status = EFI_SUCCESS;
goto ON_EXIT;
}
//
// Allocate a maxium of 1024 bytes, the caller should ensure
// that the message plus the ethernet/ip/udp header is shorter
// than this
//
Packet = (CHAR8 *) AllocatePool (NET_SYSLOG_PACKET_LEN);
if (Packet == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT;
}
//
// Build the message: Ethernet header + IP header + Udp Header + user data
//
Len = SyslogBuildPacket (
Level,
Module,
File,
Line,
Message,
NET_SYSLOG_PACKET_LEN,
Packet
);
mSyslogPacketSeq++;
Status = SyslogSendPacket (Packet, Len);
FreePool (Packet);
ON_EXIT:
FreePool (Message);
return Status;
}
/**
Return the length of the mask.
@ -179,7 +625,7 @@ NetGetIpClass (
**/
BOOLEAN
EFIAPI
Ip4IsUnicast (
NetIp4IsUnicast (
IN IP4_ADDR Ip,
IN IP4_ADDR NetMask
)
@ -218,7 +664,7 @@ Ip4IsUnicast (
**/
BOOLEAN
Ip6IsValidUnicast (
NetIp6IsValidUnicast (
IN EFI_IPv6_ADDRESS *Ip6
)
{
@ -244,6 +690,113 @@ Ip6IsValidUnicast (
return TRUE;
}
/**
Check whether the incoming Ipv6 address is the unspecified address or not.
@param[in] Ip6 - Ip6 address, in network order.
@retval TRUE - Yes, unspecified
@retval FALSE - No
**/
BOOLEAN
NetIp6IsUnspecifiedAddr (
IN EFI_IPv6_ADDRESS *Ip6
)
{
UINT8 Index;
for (Index = 0; Index < 16; Index++) {
if (Ip6->Addr[Index] != 0) {
return FALSE;
}
}
return TRUE;
}
/**
Check whether the incoming Ipv6 address is a link-local address.
@param[in] Ip6 - Ip6 address, in network order.
@retval TRUE - Yes, link-local address
@retval FALSE - No
**/
BOOLEAN
NetIp6IsLinkLocalAddr (
IN EFI_IPv6_ADDRESS *Ip6
)
{
UINT8 Index;
ASSERT (Ip6 != NULL);
if (Ip6->Addr[0] != 0xFE) {
return FALSE;
}
if (Ip6->Addr[1] != 0x80) {
return FALSE;
}
for (Index = 2; Index < 8; Index++) {
if (Ip6->Addr[Index] != 0) {
return FALSE;
}
}
return TRUE;
}
/**
Check whether the Ipv6 address1 and address2 are on the connected network.
@param[in] Ip1 - Ip6 address1, in network order.
@param[in] Ip2 - Ip6 address2, in network order.
@param[in] PrefixLength - The prefix length of the checking net.
@retval TRUE - Yes, connected.
@retval FALSE - No.
**/
BOOLEAN
NetIp6IsNetEqual (
EFI_IPv6_ADDRESS *Ip1,
EFI_IPv6_ADDRESS *Ip2,
UINT8 PrefixLength
)
{
UINT8 Byte;
UINT8 Bit;
UINT8 Mask;
ASSERT (Ip1 != NULL && Ip2 != NULL);
if (PrefixLength == 0) {
return TRUE;
}
Byte = (UINT8) (PrefixLength / 8);
Bit = (UINT8) (PrefixLength % 8);
if (CompareMem (Ip1, Ip2, Byte) != 0) {
return FALSE;
}
if (Bit > 0) {
Mask = (UINT8) (0xFF << (8 - Bit));
if ((Ip1->Addr[Byte] & Mask) != (Ip2->Addr[Byte] & Mask)) {
return FALSE;
}
}
return TRUE;
}
/**
Switches the endianess of an IPv6 address
@ -1432,7 +1985,7 @@ ON_EXIT:
Get other info from parameters to make up the whole IPv4 device path node.
@param[in, out] Node Pointer to the IPv4 device path node.
@param[in] Controller The handle where the NIC IP4 config protocol resides.
@param[in] Controller The controller handle.
@param[in] LocalIp The local IPv4 address.
@param[in] LocalPort The local port.
@param[in] RemoteIp The remote IPv4 address.
@ -1473,6 +2026,47 @@ NetLibCreateIPv4DPathNode (
}
}
/**
Create an IPv6 device path node.
The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
The header subtype of IPv6 device path node is MSG_IPv6_DP.
Get other info from parameters to make up the whole IPv6 device path node.
@param[in, out] Node Pointer to the IPv6 device path node.
@param[in] Controller The controller handle.
@param[in] LocalIp The local IPv6 address.
@param[in] LocalPort The local port.
@param[in] RemoteIp The remote IPv6 address.
@param[in] RemotePort The remote port.
@param[in] Protocol The protocol type in the IP header.
**/
VOID
EFIAPI
NetLibCreateIPv6DPathNode (
IN OUT IPv6_DEVICE_PATH *Node,
IN EFI_HANDLE Controller,
IN EFI_IPv6_ADDRESS *LocalIp,
IN UINT16 LocalPort,
IN EFI_IPv6_ADDRESS *RemoteIp,
IN UINT16 RemotePort,
IN UINT16 Protocol
)
{
Node->Header.Type = MESSAGING_DEVICE_PATH;
Node->Header.SubType = MSG_IPv6_DP;
SetDevicePathNodeLength (&Node->Header, sizeof (IPv6_DEVICE_PATH));
CopyMem (&Node->LocalIpAddress, LocalIp, sizeof (EFI_IPv6_ADDRESS));
CopyMem (&Node->RemoteIpAddress, RemoteIp, sizeof (EFI_IPv6_ADDRESS));
Node->LocalPort = LocalPort;
Node->RemotePort = RemotePort;
Node->Protocol = Protocol;
Node->StaticIpAddress = FALSE;
}
/**
Find the UNDI/SNP handle from controller and protocol GUID.