EFI_IP4_COMPLETION_TOKEN *SndToken;
} IP_IO_SEND_ENTRY;
-typedef struct _EFI_IP4_OVERRIDE_DATA IP_IO_OVERRIDE;
+typedef EFI_IP4_OVERRIDE_DATA IP_IO_OVERRIDE;
typedef struct _IP_IO_IP_INFO {
IP4_ADDR Addr;
IN UINT8 Proto,
IN UINT16 Len
);
+
+//\r
+// The debug level definition. This value is also used as the\r
+// syslog's servity level. Don't change it.\r
+//\r
+enum {\r
+ NETDEBUG_LEVEL_TRACE = 5,\r
+ NETDEBUG_LEVEL_WARNING = 4,\r
+ NETDEBUG_LEVEL_ERROR = 3,\r
+};\r
+\r
+#ifdef EFI_NETWORK_STACK_DEBUG\r
+\r
+//\r
+// The debug output expects the ASCII format string, Use %a to print ASCII\r
+// string, and %s to print UNICODE string. PrintArg must be enclosed in ().\r
+// For example: NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name));\r
+//\r
+#define NET_DEBUG_TRACE(Module, PrintArg) \\r
+ NetDebugOutput ( \\r
+ NETDEBUG_LEVEL_TRACE, \\r
+ Module, \\r
+ __FILE__, \\r
+ __LINE__, \\r
+ NetDebugASPrint PrintArg \\r
+ )\r
+\r
+#define NET_DEBUG_WARNING(Module, PrintArg) \\r
+ NetDebugOutput ( \\r
+ NETDEBUG_LEVEL_WARNING, \\r
+ Module, \\r
+ __FILE__, \\r
+ __LINE__, \\r
+ NetDebugASPrint PrintArg \\r
+ )\r
+\r
+#define NET_DEBUG_ERROR(Module, PrintArg) \\r
+ NetDebugOutput ( \\r
+ NETDEBUG_LEVEL_ERROR, \\r
+ Module, \\r
+ __FILE__, \\r
+ __LINE__, \\r
+ NetDebugASPrint PrintArg \\r
+ )\r
+\r
+#else\r
+#define NET_DEBUG_TRACE(Module, PrintString)\r
+#define NET_DEBUG_WARNING(Module, PrintString)\r
+#define NET_DEBUG_ERROR(Module, PrintString)\r
+#endif\r
+\r
+UINT8 *\r
+NetDebugASPrint (\r
+ UINT8 *Format,\r
+ ...\r
+ );\r
+\r
+EFI_STATUS\r
+NetDebugOutput (\r
+ UINT32 Level,\r
+ UINT8 *Module,\r
+ UINT8 *File,\r
+ UINT32 Line,\r
+ UINT8 *Message\r
+ );\r
+\r
+//\r
+// Network debug message is sent out as syslog.\r
+//\r
+enum {\r
+ NET_SYSLOG_FACILITY = 16, // Syslog local facility local use\r
+ NET_SYSLOG_PACKET_LEN = 512,\r
+ NET_DEBUG_MSG_LEN = 470, // 512 - (ether+ip+udp head length)\r
+ NET_SYSLOG_TX_TIMEOUT = 500 *1000 *10, // 500ms\r
+};
#endif
\r
\r
[LibraryClasses]\r
- MemoryAllocationLib\r
- UefiLib\r
+ IpIoLib\r
BaseLib\r
- UefiBootServicesTableLib\r
- UefiRuntimeServicesTableLib\r
- BaseMemoryLib\r
DebugLib\r
- PrintLib\r
-\r
+ UefiBootServicesTableLib\r
+ MemoryAllocationLib\r
\r
[Protocols]\r
gEfiIp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiDriverDiagnosticsProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiUdp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiLoadedImageProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
gEfiIp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiDriverConfigurationProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiDriverBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiComponentNameProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
-\r
[Sources.common]\r
DxeNetLib.c\r
NetBuffer.c\r
+ NetDebug.c\r
\r
[Packages]\r
MdePkg/MdePkg.dec\r
\r
\r
[LibraryClasses]\r
- MemoryAllocationLib\r
- UefiLib\r
- BaseLib\r
- UefiBootServicesTableLib\r
- UefiRuntimeServicesTableLib\r
- BaseMemoryLib\r
- DebugLib\r
- PrintLib\r
-\r
+ NetLib
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiLib
+ MemoryAllocationLib
\r
[Protocols]\r
- gEfiIp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiDriverDiagnosticsProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiUdp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiLoadedImageProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiIp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiDriverConfigurationProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiDriverBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiComponentNameProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ NetDebug.c\r
+\r
+Abstract:\r
+\r
+ Network debug facility. The debug information is wrapped in\r
+ SYSLOG packets, then sent over SNP. This debug facility can't\r
+ be used by SNP. Apply caution when used in MNP and non-network\r
+ module because SNP is most likely not "thread safe". We assume\r
+ that the SNP supports the EHTERNET.\r
+\r
+\r
+**/\r
+\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/SimpleNetwork.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/NetLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PrintLib.h>\r
+\r
+\r
+//\r
+// Any error level digitally larger than mNetDebugLevelMax\r
+// will be silently discarded.\r
+//\r
+UINTN mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;\r
+UINT32 mSyslogPacketSeq = 0xDEADBEEF;\r
+\r
+//\r
+// You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp\r
+// here to direct the syslog packets to the syslog deamon. The\r
+// default is broadcast to both the ethernet and IP.\r
+//\r
+UINT8 mSyslogDstMac [NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
+UINT32 mSyslogDstIp = 0xffffffff;\r
+UINT32 mSyslogSrcIp = 0;\r
+\r
+UINT8 *\r
+MonthName[] = {\r
+ "Jan",\r
+ "Feb",\r
+ "Mar",\r
+ "Apr",\r
+ "May",\r
+ "Jun",\r
+ "Jul",\r
+ "Aug",\r
+ "Sep",\r
+ "Oct",\r
+ "Nov",\r
+ "Dec"\r
+};\r
+\r
+\r
+/**\r
+ Locate the handles that support SNP, then open one of them\r
+ to send the syslog packets. The caller isn't required to close\r
+ the SNP after use because the SNP is opened by HandleProtocol.\r
+\r
+ None\r
+\r
+ @return The point to SNP if one is properly openned. Otherwise NULL\r
+\r
+**/\r
+EFI_SIMPLE_NETWORK_PROTOCOL *\r
+SyslogLocateSnp (\r
+ VOID\r
+ )\r
+{\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *Handles;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Locate the handles which has SNP installed.\r
+ //\r
+ Handles = NULL;\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &Handles\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || (HandleCount == 0)) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Try to open one of the ethernet SNP protocol to send packet\r
+ //\r
+ Snp = NULL;\r
+\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ Handles[Index],\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ (VOID **) &Snp\r
+ );\r
+\r
+ if ((Status == EFI_SUCCESS) && (Snp != NULL) &&\r
+ (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&\r
+ (Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {\r
+\r
+ break;\r
+ }\r
+\r
+ Snp = NULL;\r
+ }\r
+\r
+ gBS->FreePool (Handles);\r
+ return Snp;\r
+}\r
+\r
+\r
+/**\r
+ Transmit a syslog packet synchronously through SNP. The Packet\r
+ already has the ethernet header prepended. This function should\r
+ fill in the source MAC because it will try to locate a SNP each\r
+ time it is called to avoid the problem if SNP is unloaded.\r
+ This code snip is copied from MNP.\r
+\r
+ @param Packet The Syslog packet\r
+ @param Length The length of the packet\r
+\r
+ @retval EFI_DEVICE_ERROR Failed to locate a usable SNP protocol\r
+ @retval EFI_TIMEOUT Timeout happened to send the packet.\r
+ @retval EFI_SUCCESS Packet is sent.\r
+\r
+**/\r
+EFI_STATUS\r
+SyslogSendPacket (\r
+ IN UINT8 *Packet,\r
+ IN UINT32 Length\r
+ )\r
+{\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ ETHER_HEAD *Ether;\r
+ EFI_STATUS Status;\r
+ EFI_EVENT TimeoutEvent;\r
+ UINT8 *TxBuf;\r
+\r
+ Snp = SyslogLocateSnp ();\r
+\r
+ if (Snp == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Ether = (ETHER_HEAD *) Packet;\r
+ CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);\r
+\r
+ //\r
+ // Start the timeout event.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_NOTIFY,\r
+ NULL,\r
+ NULL,\r
+ &TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ for (;;) {\r
+ //\r
+ // Transmit the packet through SNP.\r
+ //\r
+ Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);\r
+\r
+ if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // If Status is EFI_SUCCESS, the packet is put in the transmit queue.\r
+ // if Status is EFI_NOT_READY, the transmit engine of the network\r
+ // interface is busy. Both need to sync SNP.\r
+ //\r
+ TxBuf = NULL;\r
+\r
+ do {\r
+ //\r
+ // Get the recycled transmit buffer status.\r
+ //\r
+ Snp->GetStatus (Snp, NULL, &TxBuf);\r
+\r
+ if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
+ Status = EFI_TIMEOUT;\r
+ break;\r
+ }\r
+\r
+ } while (TxBuf == NULL);\r
+\r
+ if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Status is EFI_NOT_READY. Restart the timer event and\r
+ // call Snp->Transmit again.\r
+ //\r
+ gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
+ }\r
+\r
+ gBS->SetTimer (TimeoutEvent, TimerCancel, 0);\r
+\r
+ON_EXIT:\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Compute checksum for a bulk of data. This code is copied from the\r
+ Netbuffer library.\r
+\r
+ @param Bulk Pointer to the data.\r
+ @param Len Length of the data, in bytes.\r
+\r
+ @retval UINT16 The computed checksum.\r
+\r
+**/\r
+UINT16\r
+SyslogChecksum (\r
+ IN UINT8 *Bulk,\r
+ IN UINT32 Len\r
+ )\r
+{\r
+ register UINT32 Sum;\r
+\r
+ Sum = 0;\r
+\r
+ while (Len > 1) {\r
+ Sum += *(UINT16 *) Bulk;\r
+ Bulk += 2;\r
+ Len -= 2;\r
+ }\r
+\r
+ //\r
+ // Add left-over byte, if any\r
+ //\r
+ if (Len > 0) {\r
+ Sum += *(UINT8 *) Bulk;\r
+ }\r
+\r
+ //\r
+ // Fold 32-bit sum to 16 bits\r
+ //\r
+ while (Sum >> 16) {\r
+ Sum = (Sum & 0xffff) + (Sum >> 16);\r
+ }\r
+\r
+ return (UINT16) ~Sum;\r
+}\r
+\r
+\r
+/**\r
+ Build a syslog packet, including the Ethernet/Ip/Udp headers\r
+ and user's message.\r
+\r
+ @param Buf The buffer to put the packet data\r
+ @param BufLen The lenght of the Buf\r
+ @param Level Syslog servity level\r
+ @param Module The module that generates the log\r
+ @param File The file that contains the current log\r
+ @param Line The line of code in the File that contains the\r
+ current log\r
+ @param Message The log message\r
+\r
+ @return The length of the syslog packet built.\r
+\r
+**/\r
+UINT32\r
+SyslogBuildPacket (\r
+ UINT8 *Buf,\r
+ UINT32 BufLen,\r
+ UINT32 Level,\r
+ UINT8 *Module,\r
+ UINT8 *File,\r
+ UINT32 Line,\r
+ UINT8 *Message\r
+ )\r
+{\r
+ ETHER_HEAD *Ether;\r
+ IP4_HEAD *Ip4;\r
+ EFI_UDP4_HEADER *Udp4;\r
+ EFI_TIME Time;\r
+ UINT32 Pri;\r
+ UINT32 Len;\r
+\r
+ //\r
+ // Fill in the Ethernet header. Leave alone the source MAC.\r
+ // SyslogSendPacket will fill in the address for us.\r
+ //\r
+ Ether = (ETHER_HEAD *) Buf;\r
+ CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);\r
+ ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);\r
+\r
+ Ether->EtherType = HTONS (0x0800); // IP protocol\r
+\r
+ Buf += sizeof (ETHER_HEAD);\r
+ BufLen -= sizeof (ETHER_HEAD);\r
+\r
+ //\r
+ // Fill in the IP header\r
+ //\r
+ Ip4 = (IP4_HEAD *) Buf;\r
+ Ip4->HeadLen = 5;\r
+ Ip4->Ver = 4;\r
+ Ip4->Tos = 0;\r
+ Ip4->TotalLen = 0;\r
+ Ip4->Id = (UINT16) mSyslogPacketSeq;\r
+ Ip4->Fragment = 0;\r
+ Ip4->Ttl = 16;\r
+ Ip4->Protocol = 0x11;\r
+ Ip4->Checksum = 0;\r
+ Ip4->Src = mSyslogSrcIp;\r
+ Ip4->Dst = mSyslogDstIp;\r
+\r
+ Buf += sizeof (IP4_HEAD);\r
+ BufLen -= sizeof (IP4_HEAD);\r
+\r
+ //\r
+ // Fill in the UDP header, Udp checksum is optional. Leave it zero.\r
+ //\r
+ Udp4 = (EFI_UDP4_HEADER*) Buf;\r
+ Udp4->SrcPort = HTONS (514);\r
+ Udp4->DstPort = HTONS (514);\r
+ Udp4->Length = 0;\r
+ Udp4->Checksum = 0;\r
+\r
+ Buf += sizeof (EFI_UDP4_HEADER);\r
+ BufLen -= sizeof (EFI_UDP4_HEADER);\r
+\r
+ //\r
+ // Build the syslog message body with <PRI> Timestamp machine module Message\r
+ //\r
+ Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);\r
+ gRT->GetTime (&Time, NULL);\r
+\r
+ //\r
+ // Use %a to format the ASCII strings, %s to format UNICODE strings\r
+ //\r
+ Len = 0;\r
+ Len += (UINT32) AsciiSPrint (\r
+ Buf,\r
+ BufLen,\r
+ "<%d> %a %d %d:%d:%d ",\r
+ Pri,\r
+ MonthName [Time.Month-1],\r
+ Time.Day,\r
+ Time.Hour,\r
+ Time.Minute,\r
+ Time.Second\r
+ );\r
+ Len--;\r
+\r
+ Len += (UINT32) AsciiSPrint (\r
+ Buf + Len,\r
+ BufLen - Len,\r
+ "Tiano %a: %a (Line: %d File: %a)",\r
+ Module,\r
+ Message,\r
+ Line,\r
+ File\r
+ );\r
+ Len--;\r
+\r
+ //\r
+ // OK, patch the IP length/checksum and UDP length fields.\r
+ //\r
+ Len += sizeof (EFI_UDP4_HEADER);\r
+ Udp4->Length = HTONS ((UINT16) Len);\r
+\r
+ Len += sizeof (IP4_HEAD);\r
+ Ip4->TotalLen = HTONS ((UINT16) Len);\r
+ Ip4->Checksum = SyslogChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD));\r
+\r
+ return Len + sizeof (ETHER_HEAD);\r
+}\r
+\r
+\r
+/**\r
+ Allocate a buffer, then format the message to it. This is a\r
+ help function for the NET_DEBUG_XXX macros. The PrintArg of\r
+ these macros treats the variable length print parameters as a\r
+ single parameter, and pass it to the NetDebugASPrint. For\r
+ example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))\r
+ if extracted to:\r
+ NetDebugOutput (\r
+ NETDEBUG_LEVEL_TRACE,\r
+ "Tcp",\r
+ __FILE__,\r
+ __LINE__,\r
+ NetDebugASPrint ("State transit to %a\n", Name)\r
+ )\r
+ This is exactly what we want.\r
+\r
+ @param Format The ASCII format string.\r
+ @param ... The variable length parameter whose format is\r
+ determined by the Format string.\r
+\r
+ @return The buffer containing the formatted message, or NULL if failed to\r
+ @return allocate memory.\r
+\r
+**/\r
+UINT8 *\r
+NetDebugASPrint (\r
+ UINT8 *Format,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Marker;\r
+ UINT8 *Buf;\r
+\r
+ Buf = AllocatePool (NET_DEBUG_MSG_LEN);\r
+\r
+ if (Buf == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ VA_START (Marker, Format);\r
+ AsciiVSPrint (Buf, NET_DEBUG_MSG_LEN, Format, Marker);\r
+ VA_END (Marker);\r
+\r
+ return Buf;\r
+}\r
+\r
+\r
+/**\r
+ Output a debug message to syslog. This function will locate a\r
+ instance of SNP then send the message through it. Because it\r
+ isn't open the SNP BY_DRIVER, apply caution when using it.\r
+\r
+ @param Level The servity level of the message.\r
+ @param Module The Moudle that generates the log.\r
+ @param File The file that contains the log.\r
+ @param Line The exact line that contains the log.\r
+ @param Message The user message to log.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet\r
+ @retval EFI_SUCCESS The log is discard because that it is more verbose\r
+ than the mNetDebugLevelMax. Or, it has been sent\r
+ out.\r
+\r
+**/\r
+EFI_STATUS\r
+NetDebugOutput (\r
+ UINT32 Level,\r
+ UINT8 *Module,\r
+ UINT8 *File,\r
+ UINT32 Line,\r
+ UINT8 *Message\r
+ )\r
+{\r
+ UINT8 *Packet;\r
+ UINT32 Len;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Check whether the message should be sent out\r
+ //\r
+ if (Message == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (Level > mNetDebugLevelMax) {\r
+ Status = EFI_SUCCESS;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Allocate a maxium of 1024 bytes, the caller should ensure\r
+ // that the message plus the ethernet/ip/udp header is shorter\r
+ // than this\r
+ //\r
+ Packet = AllocatePool (NET_SYSLOG_PACKET_LEN);\r
+\r
+ if (Packet == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Build the message: Ethernet header + IP header + Udp Header + user data\r
+ //\r
+ Len = SyslogBuildPacket (\r
+ Packet,\r
+ NET_SYSLOG_PACKET_LEN,\r
+ Level,\r
+ Module,\r
+ File,\r
+ Line,\r
+ Message\r
+ );\r
+\r
+ mSyslogPacketSeq++;\r
+ Status = SyslogSendPacket (Packet, Len);\r
+ gBS->FreePool (Packet);\r
+\r
+ON_EXIT:\r
+ gBS->FreePool (Message);\r
+ return Status;\r
+}\r
\r
\r
[LibraryClasses]\r
- MemoryAllocationLib\r
- UefiLib\r
+ UdpIoLib\r
BaseLib\r
- UefiBootServicesTableLib\r
- UefiRuntimeServicesTableLib\r
- BaseMemoryLib\r
DebugLib\r
- PrintLib\r
-\r
+ UefiBootServicesTableLib\r
+ MemoryAllocationLib\r
\r
[Protocols]\r
- gEfiIp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiDriverDiagnosticsProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
gEfiUdp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiLoadedImageProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiIp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiDriverConfigurationProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiDriverBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
- gEfiComponentNameProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
-\r
+ gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
\ No newline at end of file
$(WORKSPACE)/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf\r
\r
$(WORKSPACE)/MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf\r
+ $(WORKSPACE)/MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf\r
+ $(WORKSPACE)/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf\r
+ $(WORKSPACE)/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf\r
+ $(WORKSPACE)/MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf\r
\r
$(WORKSPACE)/MdeModulePkg/Application/HelloWorld/HelloWorld.inf\r
\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "MnpDriver.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+MnpComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MnpComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL gMnpComponentName = {\r
+ MnpComponentNameGetDriverName,\r
+ MnpComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+STATIC EFI_UNICODE_STRING_TABLE mMnpDriverNameTable[] = {\r
+ {\r
+ "eng",\r
+ L"MNP Network Service Driver"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MnpComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ Language - A pointer to a three character ISO 639-2 language identifier.\r
+ This is the language of the driver name that that the caller\r
+ is requesting, and it must match one of the languages specified\r
+ in SupportedLanguages. The number of languages supported by a\r
+ driver is up to the driver writer.\r
+ DriverName - A pointer to the Unicode string to return. This Unicode string\r
+ is the name of the driver specified by This in the language\r
+ specified by Language.\r
+\r
+ Returns:\r
+ EFI_SUCCES - The Unicode string for the Driver specified by This\r
+ and the language specified by Language was returned\r
+ in DriverName.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - DriverName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gMnpComponentName.SupportedLanguages,\r
+ mMnpDriverNameTable,\r
+ DriverName\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MnpComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by an EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ ControllerHandle - The handle of a controller that the driver specified by\r
+ This is managing. This handle specifies the controller\r
+ whose name is to be returned.\r
+ ChildHandle - The handle of the child controller to retrieve the name\r
+ of. This is an optional parameter that may be NULL. It\r
+ will be NULL for device drivers. It will also be NULL\r
+ for a bus drivers that wish to retrieve the name of the\r
+ bus controller. It will not be NULL for a bus driver\r
+ that wishes to retrieve the name of a child controller.\r
+ Language - A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language of the controller name\r
+ that that the caller is requesting, and it must match one\r
+ of the languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up to the\r
+ driver writer.\r
+ ControllerName - A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the controller specified by\r
+ ControllerHandle and ChildHandle in the language specified\r
+ by Language from the point of view of the driver specified\r
+ by This.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The Unicode string for the user readable name in the\r
+ language specified by Language for the driver\r
+ specified by This was returned in DriverName.\r
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This is not currently managing\r
+ the controller specified by ControllerHandle and\r
+ ChildHandle.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ MnpConfig.c\r
+\r
+Abstract:\r
+\r
+ Implementation of Managed Network Protocol private services.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "MnpImpl.h"\r
+\r
+EFI_SERVICE_BINDING_PROTOCOL mMnpServiceBindingProtocol = {\r
+ MnpServiceBindingCreateChild,\r
+ MnpServiceBindingDestroyChild\r
+};\r
+\r
+EFI_MANAGED_NETWORK_PROTOCOL mMnpProtocolTemplate = {\r
+ MnpGetModeData,\r
+ MnpConfigure,\r
+ MnpMcastIpToMac,\r
+ MnpGroups,\r
+ MnpTransmit,\r
+ MnpReceive,\r
+ MnpCancel,\r
+ MnpPoll\r
+};\r
+\r
+EFI_MANAGED_NETWORK_CONFIG_DATA mMnpDefaultConfigData = {\r
+ 10000,\r
+ 10000,\r
+ 0,\r
+ FALSE,\r
+ FALSE,\r
+ FALSE,\r
+ FALSE,\r
+ FALSE,\r
+ FALSE,\r
+ FALSE\r
+};\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpAddFreeNbuf (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN UINTN Count\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpStartSnp (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpStopSnp (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpStart (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN BOOLEAN IsConfigUpdate,\r
+ IN BOOLEAN EnableSystemPoll\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpStop (\r
+ IN MNP_SERVICE_DATA *MnpServiceData\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpConfigReceiveFilters (\r
+ IN MNP_SERVICE_DATA *MnpServiceData\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+MnpGroupOpAddCtrlBlk (\r
+ IN MNP_INSTANCE_DATA *Instance,\r
+ IN MNP_GROUP_CONTROL_BLOCK *CtrlBlk,\r
+ IN MNP_GROUP_ADDRESS *GroupAddress OPTIONAL,\r
+ IN EFI_MAC_ADDRESS *MacAddress,\r
+ IN UINT32 HwAddressSize\r
+ );\r
+\r
+STATIC\r
+BOOLEAN\r
+MnpGroupOpDelCtrlBlk (\r
+ IN MNP_INSTANCE_DATA *Instance,\r
+ IN MNP_GROUP_CONTROL_BLOCK *CtrlBlk\r
+ );\r
+\r
+\r
+/**\r
+ Add some NET_BUF into MnpServiceData->FreeNbufQue. The buffer length of\r
+ the NET_BUF is specified by MnpServiceData->BufferLength.\r
+\r
+ @param MnpServiceData Pointer to the MNP_SERVICE_DATA.\r
+ @param Count Number of NET_BUFFERs to add.\r
+\r
+ @retval EFI_SUCCESS The specified amount of NET_BUFs are allocated and\r
+ added into MnpServiceData->FreeNbufQue.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate a NET_BUF structure.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpAddFreeNbuf (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN UINTN Count\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ NET_BUF *Nbuf;\r
+\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+ ASSERT ((Count > 0) && (MnpServiceData->BufferLength > 0));\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ for (Index = 0; Index < Count; Index++) {\r
+\r
+ Nbuf = NetbufAlloc (MnpServiceData->BufferLength);\r
+ if (Nbuf == NULL) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpAddFreeNbuf: NetBufAlloc failed.\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
+\r
+ NetbufQueAppend (&MnpServiceData->FreeNbufQue, Nbuf);\r
+ }\r
+\r
+ MnpServiceData->NbufCnt += Index;\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Allocate a free NET_BUF from MnpServiceData->FreeNbufQue. If there is none\r
+ in the queue, first try to allocate some and add them into the queue, then\r
+ fetch the NET_BUF from the updated FreeNbufQue.\r
+\r
+ @param MnpServiceData Pointer to the MNP_SERVICE_DATA.\r
+\r
+ @return Pointer to the allocated free NET_BUF structure, if NULL the operation is failed.\r
+\r
+**/\r
+NET_BUF *\r
+MnpAllocNbuf (\r
+ IN MNP_SERVICE_DATA *MnpServiceData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ NET_BUF_QUEUE *FreeNbufQue;\r
+ NET_BUF *Nbuf;\r
+ EFI_TPL OldTpl;\r
+\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ FreeNbufQue = &MnpServiceData->FreeNbufQue;\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
+\r
+ //\r
+ // Check whether there are available buffers, or else try to add some.\r
+ //\r
+ if (FreeNbufQue->BufNum == 0) {\r
+\r
+ if ((MnpServiceData->NbufCnt + MNP_NET_BUFFER_INCREASEMENT) > MNP_MAX_NET_BUFFER_NUM) {\r
+\r
+ MNP_DEBUG_ERROR (\r
+ ("MnpAllocNbuf: The maximum NET_BUF size is reached for MNP driver instance %p.\n",\r
+ MnpServiceData)\r
+ );\r
+\r
+ Nbuf = NULL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = MnpAddFreeNbuf (MnpServiceData, MNP_NET_BUFFER_INCREASEMENT);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (\r
+ ("MnpAllocNbuf: Failed to add NET_BUFs into the FreeNbufQue, %r.\n",\r
+ Status)\r
+ );\r
+ //\r
+ // Don't return NULL, perhaps MnpAddFreeNbuf does add some NET_BUFs but\r
+ // the amount is less than MNP_NET_BUFFER_INCREASEMENT.\r
+ //\r
+ }\r
+ }\r
+\r
+ Nbuf = NetbufQueRemove (FreeNbufQue);\r
+\r
+ //\r
+ // Increase the RefCnt.\r
+ //\r
+ if (Nbuf != NULL) {\r
+ NET_GET_REF (Nbuf);\r
+ }\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Nbuf;\r
+}\r
+\r
+\r
+/**\r
+ Try to reclaim the Nbuf into the buffer pool.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+ @param Nbuf Pointer to the NET_BUF to free.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+MnpFreeNbuf (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN NET_BUF *Nbuf\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+ ASSERT (Nbuf->RefCnt > 1);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
+\r
+ NET_PUT_REF (Nbuf);\r
+\r
+ if (Nbuf->RefCnt == 1) {\r
+ //\r
+ // Trim all buffer contained in the Nbuf, then append it to the NbufQue.\r
+ //\r
+ NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_TAIL);\r
+ NetbufQueAppend (&MnpServiceData->FreeNbufQue, Nbuf);\r
+ }\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+}\r
+\r
+\r
+/**\r
+ Initialize the mnp service context data.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+ @param Snp Pointer to the simple network protocol.\r
+\r
+ @retval EFI_SUCCESS The mnp service context is initialized.\r
+ @retval Other Some error occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpInitializeServiceData (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_HANDLE ControllerHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+\r
+ MnpServiceData->Signature = MNP_SERVICE_DATA_SIGNATURE;\r
+\r
+ MnpServiceData->ControllerHandle = ControllerHandle;\r
+\r
+ //\r
+ // Copy the ServiceBinding structure.\r
+ //\r
+ MnpServiceData->ServiceBinding = mMnpServiceBindingProtocol;\r
+\r
+ //\r
+ // Open the Simple Network protocol.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ (VOID **) &Snp,\r
+ ImageHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Get MTU from Snp.\r
+ //\r
+ SnpMode = Snp->Mode;\r
+ MnpServiceData->Snp = Snp;\r
+ MnpServiceData->Mtu = SnpMode->MaxPacketSize;\r
+\r
+ //\r
+ // Initialize the lists.\r
+ //\r
+ NetListInit (&MnpServiceData->GroupAddressList);\r
+ NetListInit (&MnpServiceData->ChildrenList);\r
+\r
+ //\r
+ // Get the buffer length used to allocate NET_BUF to hold data received\r
+ // from SNP. Do this before fill the FreeNetBufQue.\r
+ //\r
+ MnpServiceData->BufferLength = MnpServiceData->Mtu + SnpMode->MediaHeaderSize + NET_ETHER_FCS_SIZE;\r
+\r
+ //\r
+ // Initialize the FreeNetBufQue and pre-allocate some NET_BUFs.\r
+ //\r
+ NetbufQueInit (&MnpServiceData->FreeNbufQue);\r
+ Status = MnpAddFreeNbuf (MnpServiceData, MNP_INIT_NET_BUFFER_NUM);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpInitializeServiceData: MnpAddFreeNbuf failed, %r.\n", Status));\r
+ goto ERROR;\r
+ }\r
+ //\r
+ // Get one NET_BUF from the FreeNbufQue for rx cache.\r
+ //\r
+ MnpServiceData->RxNbufCache = MnpAllocNbuf (MnpServiceData);\r
+ NetbufAllocSpace (\r
+ MnpServiceData->RxNbufCache,\r
+ MnpServiceData->BufferLength,\r
+ NET_BUF_TAIL\r
+ );\r
+\r
+ //\r
+ // Allocate buffer pool for tx.\r
+ //\r
+ MnpServiceData->TxBuf = NetAllocatePool (MnpServiceData->Mtu + SnpMode->MediaHeaderSize);\r
+ if (MnpServiceData->TxBuf == NULL) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpInitializeServiceData: NetAllocatePool failed.\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+\r
+ goto ERROR;\r
+ }\r
+\r
+ //\r
+ // Create the system poll timer.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
+ NET_TPL_LOCK,\r
+ MnpSystemPoll,\r
+ MnpServiceData,\r
+ &MnpServiceData->PollTimer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpInitializeServiceData: CreateEvent for poll timer failed.\n"));\r
+ goto ERROR;\r
+ }\r
+\r
+ //\r
+ // Create the timer for packet timeout check.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
+ NET_TPL_EVENT,\r
+ MnpCheckPacketTimeout,\r
+ MnpServiceData,\r
+ &MnpServiceData->TimeoutCheckTimer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpInitializeServiceData: CreateEvent for packet timeout check failed.\n"));\r
+ goto ERROR;\r
+ }\r
+\r
+ //\r
+ // Create the timer for tx timeout check.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ NET_TPL_SLOW_TIMER,\r
+ NULL,\r
+ NULL,\r
+ &MnpServiceData->TxTimeoutEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpInitializeServiceData: CreateEvent for tx timeout event failed.\n"));\r
+ }\r
+\r
+ERROR:\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Free the dynamic allocated resources if necessary.\r
+ //\r
+ if (MnpServiceData->TimeoutCheckTimer != NULL) {\r
+\r
+ gBS->CloseEvent (MnpServiceData->TimeoutCheckTimer);\r
+ }\r
+\r
+ if (MnpServiceData->PollTimer != NULL) {\r
+\r
+ gBS->CloseEvent (MnpServiceData->PollTimer);\r
+ }\r
+\r
+ if (MnpServiceData->TxBuf != NULL) {\r
+\r
+ NetFreePool (MnpServiceData->TxBuf);\r
+ }\r
+\r
+ if (MnpServiceData->RxNbufCache != NULL) {\r
+\r
+ MnpFreeNbuf (MnpServiceData, MnpServiceData->RxNbufCache);\r
+ }\r
+\r
+ if (MnpServiceData->FreeNbufQue.BufNum != 0) {\r
+\r
+ NetbufQueFlush (&MnpServiceData->FreeNbufQue);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Flush the mnp service context data.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+MnpFlushServiceData (\r
+ MNP_SERVICE_DATA *MnpServiceData\r
+ )\r
+{\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ //\r
+ // The GroupAddressList must be empty.\r
+ //\r
+ ASSERT (NetListIsEmpty (&MnpServiceData->GroupAddressList));\r
+\r
+ //\r
+ // Close the event.\r
+ //\r
+ gBS->CloseEvent (&MnpServiceData->TxTimeoutEvent);\r
+ gBS->CloseEvent (&MnpServiceData->TimeoutCheckTimer);\r
+ gBS->CloseEvent (&MnpServiceData->PollTimer);\r
+\r
+ //\r
+ // Free the tx buffer.\r
+ //\r
+ NetFreePool (MnpServiceData->TxBuf);\r
+\r
+ //\r
+ // Free the RxNbufCache.\r
+ //\r
+ MnpFreeNbuf (MnpServiceData, MnpServiceData->RxNbufCache);\r
+\r
+ //\r
+ // Flush the FreeNbufQue.\r
+ //\r
+ MnpServiceData->NbufCnt -= MnpServiceData->FreeNbufQue.BufNum;\r
+ NetbufQueFlush (&MnpServiceData->FreeNbufQue);\r
+\r
+ DEBUG_CODE (\r
+\r
+ if (MnpServiceData->NbufCnt != 0) {\r
+\r
+ MNP_DEBUG_WARN (("MnpFlushServiceData: Memory leak, MnpServiceData->NbufCnt != 0.\n"));\r
+ }\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Initialize the mnp instance context data.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+ @param Instance Pointer to the mnp instance context data to\r
+ initialize.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+MnpInitializeInstanceData (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN MNP_INSTANCE_DATA *Instance\r
+ )\r
+{\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+ ASSERT (Instance != NULL);\r
+\r
+ //\r
+ // Set the signature.\r
+ //\r
+ Instance->Signature = MNP_INSTANCE_DATA_SIGNATURE;\r
+\r
+ //\r
+ // Copy the MNP Protocol interfaces from the template.\r
+ //\r
+ Instance->ManagedNetwork = mMnpProtocolTemplate;\r
+\r
+ //\r
+ // Copy the default config data.\r
+ //\r
+ Instance->ConfigData = mMnpDefaultConfigData;\r
+\r
+ //\r
+ // Initialize the lists.\r
+ //\r
+ NetListInit (&Instance->GroupCtrlBlkList);\r
+ NetListInit (&Instance->RcvdPacketQueue);\r
+ NetListInit (&Instance->RxDeliveredPacketQueue);\r
+\r
+ //\r
+ // Initialize the RxToken Map.\r
+ //\r
+ NetMapInit (&Instance->RxTokenMap);\r
+\r
+ //\r
+ // Save the MnpServiceData info.\r
+ //\r
+ Instance->MnpServiceData = MnpServiceData;\r
+}\r
+\r
+\r
+/**\r
+ Check whether the token specified by Arg maches the token in Item.\r
+\r
+ @param Map Pointer to the NET_MAP.\r
+ @param Item Pointer to the NET_MAP_ITEM\r
+ @param Arg Pointer to the Arg, it's a pointer to the token to\r
+ check.\r
+\r
+ @retval EFI_SUCCESS The token specified by Arg is different from the\r
+ token in Item.\r
+ @retval EFI_ACCESS_DENIED The token specified by Arg is the same as that in\r
+ Item.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpTokenExist (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Arg\r
+ )\r
+{\r
+ EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token;\r
+ EFI_MANAGED_NETWORK_COMPLETION_TOKEN *TokenInItem;\r
+\r
+ Token = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Arg;\r
+ TokenInItem = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;\r
+\r
+ if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {\r
+ //\r
+ // The token is the same either the two tokens equals or the Events in\r
+ // the two tokens are the same.\r
+ //\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Cancel the token specified by Arg if it matches the token in Item.\r
+\r
+ @param Map Pointer to the NET_MAP.\r
+ @param Item Pointer to the NET_MAP_ITEM\r
+ @param Arg Pointer to the Arg, it's a pointer to the token to\r
+ cancel.\r
+\r
+ @retval EFI_SUCCESS The Arg is NULL, and the token in Item is\r
+ cancelled, or the Arg isn't NULL, and the token in\r
+ Item is different from the Arg.\r
+ @retval EFI_ABORTED The Arg isn't NULL, the token in Item mathces the\r
+ Arg, and the token is cancelled.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpCancelTokens (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Arg\r
+ )\r
+{\r
+ EFI_MANAGED_NETWORK_COMPLETION_TOKEN *TokenToCancel;\r
+\r
+ if ((Arg != NULL) && (Item->Key != Arg)) {\r
+ //\r
+ // The token in Item is not the token specified by Arg.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ TokenToCancel = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;\r
+\r
+ //\r
+ // Cancel this token with status set to EFI_ABORTED.\r
+ //\r
+ TokenToCancel->Status = EFI_ABORTED;\r
+ gBS->SignalEvent (TokenToCancel->Event);\r
+\r
+ //\r
+ // Remove the item from the map.\r
+ //\r
+ NetMapRemoveItem (Map, Item, NULL);\r
+\r
+ if (Arg != NULL) {\r
+ //\r
+ // Only abort the token specified by Arg if Arg isn't NULL.\r
+ //\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Start and initialize the simple network.\r
+\r
+ @param Snp Pointer to the simple network protocol.\r
+\r
+ @retval EFI_SUCCESS The simple network protocol is started.\r
+ @retval Other Some error occurs.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpStartSnp (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Snp != NULL);\r
+\r
+ //\r
+ // Start the simple network.\r
+ //\r
+ Status = Snp->Start (Snp);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Initialize the simple network.\r
+ //\r
+ Status = Snp->Initialize (Snp, 0, 0);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop the simple network.\r
+\r
+ @param Snp Pointer to the simple network protocol.\r
+\r
+ @retval EFI_SUCCESS The simple network is stopped.\r
+ @retval Other Some error occurs.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpStopSnp (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Snp != NULL);\r
+\r
+ //\r
+ // Shut down the simple network.\r
+ //\r
+ Status = Snp->Shutdown (Snp);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Stop the simple network.\r
+ //\r
+ Status = Snp->Stop (Snp);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Start the managed network, this function is called when one instance is configured\r
+ or reconfigured.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+ @param IsConfigUpdate The instance is reconfigured or it's the first time\r
+ the instanced is configured.\r
+ @param EnableSystemPoll Enable the system polling or not.\r
+\r
+ @retval EFI_SUCCESS The managed network is started and some\r
+ configuration is updated.\r
+ @retval Other Some error occurs.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpStart (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN BOOLEAN IsConfigUpdate,\r
+ IN BOOLEAN EnableSystemPoll\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_TIMER_DELAY TimerOpType;\r
+\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (!IsConfigUpdate) {\r
+ //\r
+ // If it's not a configuration update, increase the configured children number.\r
+ //\r
+ MnpServiceData->ConfiguredChildrenNumber++;\r
+\r
+ if (MnpServiceData->ConfiguredChildrenNumber == 1) {\r
+ //\r
+ // It's the first configured child, start the simple network.\r
+ //\r
+ Status = MnpStartSnp (MnpServiceData->Snp);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpStart: MnpStartSnp failed, %r.\n", Status));\r
+ goto ErrorExit;\r
+ }\r
+\r
+ //\r
+ // Start the timeout timer.\r
+ //\r
+ Status = gBS->SetTimer (\r
+ MnpServiceData->TimeoutCheckTimer,\r
+ TimerPeriodic,\r
+ MNP_TIMEOUT_CHECK_INTERVAL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (\r
+ ("MnpStart, gBS->SetTimer for TimeoutCheckTimer %r.\n",\r
+ Status)\r
+ );\r
+ goto ErrorExit;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (MnpServiceData->EnableSystemPoll ^ EnableSystemPoll) {\r
+ //\r
+ // The EnableSystemPoll differs with the current state, disable or enable\r
+ // the system poll.\r
+ //\r
+ TimerOpType = EnableSystemPoll ? TimerPeriodic : TimerCancel;\r
+\r
+ Status = gBS->SetTimer (MnpServiceData->PollTimer, TimerOpType, MNP_SYS_POLL_INTERVAL);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpStart: gBS->SetTimer for PollTimer failed, %r.\n", Status));\r
+ goto ErrorExit;\r
+ }\r
+\r
+ MnpServiceData->EnableSystemPoll = EnableSystemPoll;\r
+ }\r
+\r
+ //\r
+ // Change the receive filters if need.\r
+ //\r
+ Status = MnpConfigReceiveFilters (MnpServiceData);\r
+\r
+ErrorExit:\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop the managed network.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+\r
+ @retval EFI_SUCCESS The managed network is stopped.\r
+ @retval Other Some error occurs.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpStop (\r
+ IN MNP_SERVICE_DATA *MnpServiceData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+ ASSERT (MnpServiceData->ConfiguredChildrenNumber > 0);\r
+\r
+ //\r
+ // Configure the receive filters.\r
+ //\r
+ MnpConfigReceiveFilters (MnpServiceData);\r
+\r
+ //\r
+ // Decrease the children number.\r
+ //\r
+ MnpServiceData->ConfiguredChildrenNumber--;\r
+\r
+ if (MnpServiceData->ConfiguredChildrenNumber > 0) {\r
+ //\r
+ // If there are other configured chilren, return and keep the timers and\r
+ // simple network unchanged.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // No configured children now.\r
+ //\r
+\r
+ if (MnpServiceData->EnableSystemPoll) {\r
+ //\r
+ // The system poll in on, cancel the poll timer.\r
+ //\r
+ Status = gBS->SetTimer (MnpServiceData->PollTimer, TimerCancel, 0);\r
+ MnpServiceData->EnableSystemPoll = FALSE;\r
+ }\r
+\r
+ //\r
+ // Cancel the timeout timer.\r
+ //\r
+ Status = gBS->SetTimer (MnpServiceData->TimeoutCheckTimer, TimerCancel, 0);\r
+\r
+ //\r
+ // Stop the simple network.\r
+ //\r
+ Status = MnpStopSnp (MnpServiceData->Snp);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Flush the instance's received data.\r
+\r
+ @param Instance Pointer to the mnp instance context data.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+MnpFlushRcvdDataQueue (\r
+ IN MNP_INSTANCE_DATA *Instance\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+ MNP_RXDATA_WRAP *RxDataWrap;\r
+\r
+ NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
+\r
+ while (!NetListIsEmpty (&Instance->RcvdPacketQueue)) {\r
+ //\r
+ // Remove all the Wraps.\r
+ //\r
+ RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);\r
+\r
+ //\r
+ // Recycle the RxDataWrap.\r
+ //\r
+ MnpRecycleRxData (NULL, (VOID *) RxDataWrap);\r
+ Instance->RcvdPacketQueueSize--;\r
+ }\r
+\r
+ ASSERT (Instance->RcvdPacketQueueSize == 0);\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+}\r
+\r
+\r
+/**\r
+ Configure the Instance using ConfigData.\r
+\r
+ @param Instance Pointer to the mnp instance context data.\r
+ @param ConfigData Pointer to the configuration data used to configure\r
+ the isntance.\r
+\r
+ @retval EFI_SUCCESS The Instance is configured.\r
+ @retval EFI_UNSUPPORTED EnableReceiveTimestamps is on and the\r
+ implementation doesn't support it.\r
+ @retval Other Some error occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpConfigureInstance (\r
+ IN MNP_INSTANCE_DATA *Instance,\r
+ IN EFI_MANAGED_NETWORK_CONFIG_DATA *ConfigData OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ EFI_MANAGED_NETWORK_CONFIG_DATA *OldConfigData;\r
+ EFI_MANAGED_NETWORK_CONFIG_DATA *NewConfigData;\r
+ BOOLEAN IsConfigUpdate;\r
+\r
+ NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ if ((ConfigData != NULL) && ConfigData->EnableReceiveTimestamps) {\r
+ //\r
+ // Don't support timestamp.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ MnpServiceData = Instance->MnpServiceData;\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ IsConfigUpdate = (BOOLEAN) ((Instance->Configured) && (ConfigData != NULL));\r
+\r
+ OldConfigData = &Instance->ConfigData;\r
+ NewConfigData = ConfigData;\r
+ if (NewConfigData == NULL) {\r
+ //\r
+ // Restore back the default config data if a reset of this instance\r
+ // is required.\r
+ //\r
+ NewConfigData = &mMnpDefaultConfigData;\r
+ }\r
+\r
+ //\r
+ // Reset the instance's receive filter.\r
+ //\r
+ Instance->ReceiveFilter = 0;\r
+\r
+ //\r
+ // Clear the receive counters according to the old ConfigData.\r
+ //\r
+ if (OldConfigData->EnableUnicastReceive) {\r
+ MnpServiceData->UnicastCount--;\r
+ }\r
+\r
+ if (OldConfigData->EnableMulticastReceive) {\r
+ MnpServiceData->MulticastCount--;\r
+ }\r
+\r
+ if (OldConfigData->EnableBroadcastReceive) {\r
+ MnpServiceData->BroadcastCount--;\r
+ }\r
+\r
+ if (OldConfigData->EnablePromiscuousReceive) {\r
+ MnpServiceData->PromiscuousCount--;\r
+ }\r
+\r
+ //\r
+ // Set the receive filter counters and the receive filter of the\r
+ // instance according to the new ConfigData.\r
+ //\r
+ if (NewConfigData->EnableUnicastReceive) {\r
+ MnpServiceData->UnicastCount++;\r
+ Instance->ReceiveFilter |= MNP_RECEIVE_UNICAST;\r
+ }\r
+\r
+ if (NewConfigData->EnableMulticastReceive) {\r
+ MnpServiceData->MulticastCount++;\r
+ }\r
+\r
+ if (NewConfigData->EnableBroadcastReceive) {\r
+ MnpServiceData->BroadcastCount++;\r
+ Instance->ReceiveFilter |= MNP_RECEIVE_BROADCAST;\r
+ }\r
+\r
+ if (NewConfigData->EnablePromiscuousReceive) {\r
+ MnpServiceData->PromiscuousCount++;\r
+ }\r
+\r
+ if (OldConfigData->FlushQueuesOnReset) {\r
+\r
+ MnpFlushRcvdDataQueue (Instance);\r
+ }\r
+\r
+ if (ConfigData == NULL) {\r
+\r
+ NetMapIterate (&Instance->RxTokenMap, MnpCancelTokens, NULL);\r
+ }\r
+\r
+ if (!NewConfigData->EnableMulticastReceive) {\r
+\r
+ MnpGroupOp (Instance, FALSE, NULL, NULL);\r
+ }\r
+\r
+ //\r
+ // Save the new configuration data.\r
+ //\r
+ *OldConfigData = *NewConfigData;\r
+\r
+ Instance->Configured = (BOOLEAN) (ConfigData != NULL);\r
+\r
+ if (Instance->Configured) {\r
+ //\r
+ // The instance is configured, start the Mnp.\r
+ //\r
+ Status = MnpStart (\r
+ MnpServiceData,\r
+ IsConfigUpdate,\r
+ !NewConfigData->DisableBackgroundPolling\r
+ );\r
+ } else {\r
+ //\r
+ // The instance is changed to the unconfigured state, stop the Mnp.\r
+ //\r
+ Status = MnpStop (MnpServiceData);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Configure the Snp receive filters according to the instances' receive filter\r
+ settings.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+\r
+ @retval EFI_SUCCESS The receive filters is configured.\r
+ @retval EFI_OUT_OF_RESOURCES The receive filters can't be configured due to lack\r
+ of memory resource.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpConfigReceiveFilters (\r
+ IN MNP_SERVICE_DATA *MnpServiceData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ EFI_MAC_ADDRESS *MCastFilter;\r
+ UINT32 MCastFilterCnt;\r
+ UINT32 EnableFilterBits;\r
+ UINT32 DisableFilterBits;\r
+ BOOLEAN ResetMCastFilters;\r
+ NET_LIST_ENTRY *Entry;\r
+ UINT32 Index;\r
+ MNP_GROUP_ADDRESS *GroupAddress;\r
+\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ Snp = MnpServiceData->Snp;\r
+\r
+ //\r
+ // Initialize the enable filter and disable filter.\r
+ //\r
+ EnableFilterBits = 0;\r
+ DisableFilterBits = Snp->Mode->ReceiveFilterMask;\r
+\r
+ if (MnpServiceData->UnicastCount != 0) {\r
+ //\r
+ // Enable unicast if any instance wants to receive unicast.\r
+ //\r
+ EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
+ }\r
+\r
+ if (MnpServiceData->BroadcastCount != 0) {\r
+ //\r
+ // Enable broadcast if any instance wants to receive broadcast.\r
+ //\r
+ EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
+ }\r
+\r
+ MCastFilter = NULL;\r
+ MCastFilterCnt = 0;\r
+ ResetMCastFilters = TRUE;\r
+\r
+ if ((MnpServiceData->MulticastCount != 0) && (MnpServiceData->GroupAddressCount != 0)) {\r
+ //\r
+ // There are instances configured to receive multicast and already some group\r
+ // addresses are joined.\r
+ //\r
+\r
+ ResetMCastFilters = FALSE;\r
+\r
+ if (MnpServiceData->GroupAddressCount <= Snp->Mode->MaxMCastFilterCount) {\r
+ //\r
+ // The joind group address is less than simple network's maximum count.\r
+ // Just configure the snp to do the multicast filtering.\r
+ //\r
+\r
+ EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
+\r
+ //\r
+ // Allocate pool for the mulicast addresses.\r
+ //\r
+ MCastFilterCnt = MnpServiceData->GroupAddressCount;\r
+ MCastFilter = NetAllocatePool (sizeof (EFI_MAC_ADDRESS) * MCastFilterCnt);\r
+ if (MCastFilter == NULL) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpConfigReceiveFilters: Failed to allocate memory resource for MCastFilter.\n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Fill the multicast HW address buffer.\r
+ //\r
+ Index = 0;\r
+ NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {\r
+\r
+ GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
+ *(MCastFilter + Index) = GroupAddress->Address;\r
+ Index++;\r
+\r
+ ASSERT (Index <= MCastFilterCnt);\r
+ }\r
+ } else {\r
+ //\r
+ // The maximum multicast is reached, set the filter to be promiscuous\r
+ // multicast.\r
+ //\r
+\r
+ if (Snp->Mode->ReceiveFilterMask & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {\r
+ EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+ } else {\r
+ //\r
+ // Either MULTICAST or PROMISCUOUS_MULTICAST is not supported by Snp,\r
+ // set the NIC to be promiscuous although this will tremendously degrade\r
+ // the performance.\r
+ //\r
+ EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (MnpServiceData->PromiscuousCount != 0) {\r
+ //\r
+ // Enable promiscuous if any instance wants to receive promiscuous.\r
+ //\r
+ EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
+ }\r
+\r
+ //\r
+ // Set the disable filter.\r
+ //\r
+ DisableFilterBits ^= EnableFilterBits;\r
+\r
+ //\r
+ // Configure the receive filters of SNP.\r
+ //\r
+ Status = Snp->ReceiveFilters (\r
+ Snp,\r
+ EnableFilterBits,\r
+ DisableFilterBits,\r
+ ResetMCastFilters,\r
+ MCastFilterCnt,\r
+ MCastFilter\r
+ );\r
+ DEBUG_CODE (\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (\r
+ ("MnpConfigReceiveFilters: Snp->ReceiveFilters failed, %r.\n",\r
+ Status)\r
+ );\r
+ }\r
+ );\r
+\r
+ if (MCastFilter != NULL) {\r
+ //\r
+ // Free the buffer used to hold the group addresses.\r
+ //\r
+ NetFreePool (MCastFilter);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Add a group address control block which controls the MacAddress for\r
+ this instance.\r
+\r
+ @param Instance Pointer to the mnp instance context data.\r
+ @param CtrlBlk Pointer to the group address control block.\r
+ @param GroupAddress Pointer to the group adress.\r
+ @param MacAddress Pointer to the mac address.\r
+ @param HwAddressSize The hardware address size.\r
+\r
+ @retval EFI_SUCCESS The group address control block is added.\r
+ @retval EFI_OUT_OF_RESOURCE Failed due to lack of memory resources.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MnpGroupOpAddCtrlBlk (\r
+ IN MNP_INSTANCE_DATA *Instance,\r
+ IN MNP_GROUP_CONTROL_BLOCK *CtrlBlk,\r
+ IN MNP_GROUP_ADDRESS *GroupAddress OPTIONAL,\r
+ IN EFI_MAC_ADDRESS *MacAddress,\r
+ IN UINT32 HwAddressSize\r
+ )\r
+{\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+\r
+ NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ MnpServiceData = Instance->MnpServiceData;\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ if (GroupAddress == NULL) {\r
+\r
+ ASSERT (MacAddress != NULL);\r
+\r
+ //\r
+ // Allocate a new GroupAddress to be added into MNP's GroupAddressList.\r
+ //\r
+ GroupAddress = NetAllocatePool (sizeof (MNP_GROUP_ADDRESS));\r
+ if (GroupAddress == NULL) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpGroupOpFormCtrlBlk: Failed to allocate memory resource.\n"));\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ GroupAddress->Address = *MacAddress;\r
+ GroupAddress->RefCnt = 0;\r
+ NetListInsertTail (\r
+ &MnpServiceData->GroupAddressList,\r
+ &GroupAddress->AddrEntry\r
+ );\r
+ MnpServiceData->GroupAddressCount++;\r
+ }\r
+\r
+ //\r
+ // Increase the RefCnt.\r
+ //\r
+ GroupAddress->RefCnt++;\r
+\r
+ //\r
+ // Add the CtrlBlk into the instance's GroupCtrlBlkList.\r
+ //\r
+ CtrlBlk->GroupAddress = GroupAddress;\r
+ NetListInsertTail (&Instance->GroupCtrlBlkList, &CtrlBlk->CtrlBlkEntry);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Delete a group control block from the instance. If the controlled group address's\r
+ reference count reaches zero, the group address is removed too.\r
+\r
+ @param Instance Pointer to the instance context data.\r
+ @param CtrlBlk Pointer to the group control block to delete.\r
+\r
+ @return The group address controlled by the control block is no longer used or not.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+MnpGroupOpDelCtrlBlk (\r
+ IN MNP_INSTANCE_DATA *Instance,\r
+ IN MNP_GROUP_CONTROL_BLOCK *CtrlBlk\r
+ )\r
+{\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ MNP_GROUP_ADDRESS *GroupAddress;\r
+\r
+ NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ MnpServiceData = Instance->MnpServiceData;\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ //\r
+ // Remove and free the CtrlBlk.\r
+ //\r
+ GroupAddress = CtrlBlk->GroupAddress;\r
+ NetListRemoveEntry (&CtrlBlk->CtrlBlkEntry);\r
+ NetFreePool (CtrlBlk);\r
+\r
+ ASSERT (GroupAddress->RefCnt > 0);\r
+\r
+ //\r
+ // Count down the RefCnt.\r
+ //\r
+ GroupAddress->RefCnt--;\r
+\r
+ if (GroupAddress->RefCnt == 0) {\r
+ //\r
+ // Free this GroupAddress entry if no instance uses it.\r
+ //\r
+ MnpServiceData->GroupAddressCount--;\r
+ NetListRemoveEntry (&GroupAddress->AddrEntry);\r
+ NetFreePool (GroupAddress);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Do the group operations for this instance.\r
+\r
+ @param Instance Pointer to the instance context data.\r
+ @param JoinFlag Set to TRUE to join a group. Set to TRUE to leave a\r
+ group/groups.\r
+ @param MacAddress Pointer to the group address to join or leave.\r
+ @param CtrlBlk Pointer to the group control block if JoinFlag if\r
+ FALSE.\r
+\r
+ @retval EFI_SUCCESS The group operation finished.\r
+ @retval Other Some error occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpGroupOp (\r
+ IN MNP_INSTANCE_DATA *Instance,\r
+ IN BOOLEAN JoinFlag,\r
+ IN EFI_MAC_ADDRESS *MacAddress OPTIONAL,\r
+ IN MNP_GROUP_CONTROL_BLOCK *CtrlBlk OPTIONAL\r
+ )\r
+{\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *NextEntry;\r
+ MNP_GROUP_ADDRESS *GroupAddress;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+ MNP_GROUP_CONTROL_BLOCK *NewCtrlBlk;\r
+ EFI_STATUS Status;\r
+ BOOLEAN AddressExist;\r
+ BOOLEAN NeedUpdate;\r
+\r
+ NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ MnpServiceData = Instance->MnpServiceData;\r
+ SnpMode = MnpServiceData->Snp->Mode;\r
+\r
+ if (JoinFlag) {\r
+ //\r
+ // A new gropu address is to be added.\r
+ //\r
+\r
+ GroupAddress = NULL;\r
+ AddressExist = FALSE;\r
+\r
+ //\r
+ // Allocate memory for the control block.\r
+ //\r
+ NewCtrlBlk = NetAllocatePool (sizeof (MNP_GROUP_CONTROL_BLOCK));\r
+ if (NewCtrlBlk == NULL) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpGroupOp: Failed to allocate memory resource.\n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {\r
+ //\r
+ // Check whether the MacAddress is already joined by other instances.\r
+ //\r
+ GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
+ if (0 == NetCompareMem (\r
+ MacAddress,\r
+ &GroupAddress->Address,\r
+ SnpMode->HwAddressSize\r
+ )) {\r
+\r
+ AddressExist = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!AddressExist) {\r
+ GroupAddress = NULL;\r
+ }\r
+\r
+ //\r
+ // Add the GroupAddress for this instance.\r
+ //\r
+ Status = MnpGroupOpAddCtrlBlk (\r
+ Instance,\r
+ NewCtrlBlk,\r
+ GroupAddress,\r
+ MacAddress,\r
+ SnpMode->HwAddressSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ return Status;\r
+ }\r
+\r
+ NeedUpdate = TRUE;\r
+ } else {\r
+\r
+ if (MacAddress != NULL) {\r
+\r
+ ASSERT (CtrlBlk != NULL);\r
+\r
+ //\r
+ // Leave the specific multicast mac address.\r
+ //\r
+ NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, CtrlBlk);\r
+ } else {\r
+ //\r
+ // Leave all multicast mac addresses.\r
+ //\r
+ NeedUpdate = FALSE;\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->GroupCtrlBlkList) {\r
+\r
+ NewCtrlBlk = NET_LIST_USER_STRUCT (\r
+ Entry,\r
+ MNP_GROUP_CONTROL_BLOCK,\r
+ CtrlBlkEntry\r
+ );\r
+ //\r
+ // Update is required if the group address left is no longer used\r
+ // by other instances.\r
+ //\r
+ NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, NewCtrlBlk);\r
+ }\r
+ }\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (NeedUpdate) {\r
+ //\r
+ // Reconfigure the receive filters if necessary.\r
+ //\r
+ Status = MnpConfigReceiveFilters (MnpServiceData);\r
+ }\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 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:
+
+ MnpDebug.h
+
+Abstract:
+
+
+**/
+
+#ifndef _MNP_DEBUG_H_
+#define _MNP_DEBUG_H_
+
+#define MNP_DEBUG_TRACE(PrintArg) NET_DEBUG_TRACE ("Mnp", PrintArg)
+#define MNP_DEBUG_WARN(PrintArg) NET_DEBUG_WARNING ("Mnp", PrintArg)
+#define MNP_DEBUG_ERROR(PrintArg) NET_DEBUG_ERROR ("Mnp", PrintArg)
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ MnpDriver.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "MnpDriver.h"\r
+#include "MnpDebug.h"\r
+#include "MnpImpl.h"\r
+\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gMnpDriverBinding = {\r
+ MnpDriverBindingSupported,\r
+ MnpDriverBindingStart,\r
+ MnpDriverBindingStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to test.\r
+ @param RemainingDevicePath Optional parameter use to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCES This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Test to see if MNP is already installed.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ //\r
+ // Test to see if SNP is installed.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Start this driver on ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to bind driver to.\r
+ @param RemainingDevicePath Optional parameter use to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCES This driver is added to ControllerHandle.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on\r
+ ControllerHandle.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ BOOLEAN MnpInitialized;\r
+\r
+ MnpInitialized = FALSE;\r
+\r
+ MnpServiceData = NetAllocateZeroPool (sizeof (MNP_SERVICE_DATA));\r
+ if (MnpServiceData == NULL) {\r
+ MNP_DEBUG_ERROR (("MnpDriverBindingStart(): Failed to allocate the "\r
+ L"Mnp Service Data.\n"));\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Initialize the Mnp Service Data.\r
+ //\r
+ Status = MnpInitializeServiceData (MnpServiceData, This->DriverBindingHandle, ControllerHandle);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpDriverBindingStart: MnpInitializeServiceData "\r
+ L"failed, %r.\n",Status));\r
+ goto ErrorExit;\r
+ }\r
+\r
+ MnpInitialized = TRUE;\r
+\r
+ //\r
+ // Install the MNP Service Binding Protocol.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ControllerHandle,\r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ &MnpServiceData->ServiceBinding,\r
+ NULL\r
+ );\r
+\r
+ErrorExit:\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ if (MnpInitialized) {\r
+ //\r
+ // Flush the Mnp Service Data.\r
+ //\r
+ MnpFlushServiceData (MnpServiceData);\r
+ }\r
+\r
+ //\r
+ // Close the Simple Network Protocol.\r
+ //\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ NetFreePool (MnpServiceData);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop this driver on ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to stop driver on.\r
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number\r
+ of children is zero stop the entire bus driver.\r
+ @param ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+ @retval EFI_SUCCES This driver is removed ControllerHandle.\r
+ @retval other This driver was not removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ MNP_INSTANCE_DATA *Instance;\r
+\r
+ //\r
+ // Retrieve the MNP service binding protocol from the ControllerHandle.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ (VOID **) &ServiceBinding,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (\r
+ ("MnpDriverBindingStop: Locate MNP Service Binding Protocol failed, %r.\n",\r
+ Status)\r
+ );\r
+ goto EXIT;\r
+ }\r
+\r
+ MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (ServiceBinding);\r
+\r
+ while (!NetListIsEmpty (&MnpServiceData->ChildrenList)) {\r
+ //\r
+ // Don't use NetListRemoveHead here, the remove opreration will be done\r
+ // in ServiceBindingDestroyChild.\r
+ //\r
+ Instance = NET_LIST_HEAD (\r
+ &MnpServiceData->ChildrenList,\r
+ MNP_INSTANCE_DATA,\r
+ InstEntry\r
+ );\r
+\r
+ ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);\r
+ }\r
+\r
+ //\r
+ // Uninstall the MNP Service Binding Protocol.\r
+ //\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ControllerHandle,\r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ ServiceBinding,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpDriverBindingStop: Uninstall MNP Service Binding Protocol failed, %r.\n"));\r
+ goto EXIT;\r
+ }\r
+\r
+ //\r
+ // Close the openned Snp protocol.\r
+ //\r
+ Status = gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpDriverBindingStop: Close SNP Protocol failed, %r.\n", Status));\r
+ goto EXIT;\r
+ }\r
+\r
+ //\r
+ // Flush the Mnp service data.\r
+ //\r
+ MnpFlushServiceData (MnpServiceData);\r
+\r
+ NetFreePool (MnpServiceData);\r
+\r
+EXIT:\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Creates a child handle with a set of I/O services.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ChildHandle Pointer to the handle of the child to create. If\r
+ it is NULL, then a new handle is created. If it is\r
+ not NULL, then the I/O services are added to the\r
+ existing child handle.\r
+\r
+ @retval EFI_SUCCES The child handle was created with the I/O\r
+ services.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
+ the child.\r
+ @retval other The child handle was not created.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpServiceBindingCreateChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE *ChildHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ MNP_INSTANCE_DATA *Instance;\r
+ VOID *Snp;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((This == NULL) || (ChildHandle == NULL)) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Allocate buffer for the new instance.\r
+ //\r
+ Instance = NetAllocateZeroPool (sizeof (MNP_INSTANCE_DATA));\r
+ if (Instance == NULL) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpServiceBindingCreateChild: Faild to allocate memory for the new instance.\n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Init the instance data.\r
+ //\r
+ MnpInitializeInstanceData (MnpServiceData, Instance);\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ ChildHandle,\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ &Instance->ManagedNetwork,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (\r
+ ("MnpServiceBindingCreateChild: Failed to install the MNP protocol, %r.\n",\r
+ Status)\r
+ );\r
+ goto ErrorExit;\r
+ }\r
+\r
+ //\r
+ // Save the instance's childhandle.\r
+ //\r
+ Instance->Handle = *ChildHandle;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ MnpServiceData->ControllerHandle,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ (VOID **) &Snp,\r
+ gMnpDriverBinding.DriverBindingHandle,\r
+ Instance->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ //\r
+ // Add the child instance into ChildrenList.\r
+ //\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ NetListInsertTail (&MnpServiceData->ChildrenList, &Instance->InstEntry);\r
+ MnpServiceData->ChildrenNumber++;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ErrorExit:\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ if (Instance->Handle != NULL) {\r
+\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ &Instance->ManagedNetwork,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ NetFreePool (Instance);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Destroys a child handle with a set of I/O services.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ChildHandle Handle of the child to destroy.\r
+\r
+ @retval EFI_SUCCES The I/O services were removed from the child\r
+ handle.\r
+ @retval EFI_UNSUPPORTED The child handle does not support the I/O services\r
+ that are being removed.\r
+ @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.\r
+ @retval EFI_ACCESS_DENIED The child handle could not be destroyed because\r
+ its I/O services are being used.\r
+ @retval other The child handle was not destroyed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpServiceBindingDestroyChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ChildHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ EFI_MANAGED_NETWORK_PROTOCOL *ManagedNetwork;\r
+ MNP_INSTANCE_DATA *Instance;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((This == NULL) || (ChildHandle == NULL)) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Try to retrieve ManagedNetwork Protocol from ChildHandle.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ (VOID **) &ManagedNetwork,\r
+ gMnpDriverBinding.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Instance = MNP_INSTANCE_DATA_FROM_THIS (ManagedNetwork);\r
+\r
+ //\r
+ // MnpServiceBindingDestroyChild may be called twice: first called by\r
+ // MnpServiceBindingStop, second called by uninstalling the MNP protocol\r
+ // in this ChildHandle. Use destroyed to make sure the resource clean code\r
+ // will only excecute once.\r
+ //\r
+ if (Instance->Destroyed) {\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Instance->Destroyed = TRUE;\r
+\r
+ //\r
+ // Close the Simple Network protocol.\r
+ //\r
+ gBS->CloseProtocol (\r
+ MnpServiceData->ControllerHandle,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ gMnpDriverBinding.DriverBindingHandle,\r
+ ChildHandle\r
+ );\r
+\r
+ //\r
+ // Uninstall the ManagedNetwork protocol.\r
+ //\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandle,\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ &Instance->ManagedNetwork,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (\r
+ ("MnpServiceBindingDestroyChild: Failed to uninstall the ManagedNetwork protocol, %r.\n",\r
+ Status)\r
+ );\r
+\r
+ Instance->Destroyed = FALSE;\r
+ return Status;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ //\r
+ // Reset the configuration.\r
+ //\r
+ ManagedNetwork->Configure (ManagedNetwork, NULL);\r
+\r
+ //\r
+ // Try to flush the RcvdPacketQueue.\r
+ //\r
+ MnpFlushRcvdDataQueue (Instance);\r
+\r
+ //\r
+ // Clean the RxTokenMap.\r
+ //\r
+ NetMapClean (&Instance->RxTokenMap);\r
+\r
+ //\r
+ // Remove this instance from the ChildrenList.\r
+ //\r
+ NetListRemoveEntry (&Instance->InstEntry);\r
+ MnpServiceData->ChildrenNumber--;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ NetFreePool (Instance);\r
+\r
+ return Status;\r
+}\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (MnpDriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MnpDriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The entry point for Mnp driver which installs the driver binding and component name\r
+ protocol on its ImageHandle.\r
+\r
+Arguments:\r
+\r
+ ImageHandle - The image handle of the driver.\r
+ SystemTable - The system table.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - If the driver binding and component name protocols are successfully\r
+ installed, otherwise if failed.\r
+\r
+--*/\r
+{\r
+ return NetLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gMnpDriverBinding,\r
+ ImageHandle,\r
+ &gMnpComponentName,\r
+ NULL,\r
+ NULL\r
+ );\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2007, 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:
+
+ MnpDriver.h
+
+Abstract:
+
+
+**/
+
+#ifndef _MNP_DRIVER_H_
+#define _MNP_DRIVER_H_
+#include <PiDxe.h>\r
+\r
+#include <Protocol/ManagedNetwork.h>\r
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/ServiceBinding.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>
+#include <Library/NetLib.h>
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include "MnpDebug.h"
+
+//
+// Required Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gMnpDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gMnpComponentName;
+
+#define MNP_SERVICE_DATA_SIGNATURE EFI_SIGNATURE_32 ('M', 'n', 'p', 'S')
+
+typedef struct _MNP_SERVICE_DATA {
+ UINT32 Signature;
+
+ EFI_HANDLE ControllerHandle;
+
+ EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+
+ UINT32 Mtu;
+
+ NET_LIST_ENTRY ChildrenList;
+ UINTN ChildrenNumber;
+ UINTN ConfiguredChildrenNumber;
+
+ NET_LIST_ENTRY GroupAddressList;
+ UINT32 GroupAddressCount;
+
+ EFI_EVENT TxTimeoutEvent;
+
+ NET_BUF_QUEUE FreeNbufQue;
+ INTN NbufCnt;
+
+ EFI_EVENT PollTimer;
+ BOOLEAN EnableSystemPoll;
+
+ EFI_EVENT TimeoutCheckTimer;
+
+ UINT32 UnicastCount;
+ UINT32 BroadcastCount;
+ UINT32 MulticastCount;
+ UINT32 PromiscuousCount;
+
+ //
+ // The size of the data buffer in the MNP_PACKET_BUFFER used to
+ // store a packet.
+ //
+ UINT32 BufferLength;
+ NET_BUF *RxNbufCache;
+ UINT8 *TxBuf;
+} MNP_SERVICE_DATA;
+
+#define MNP_SERVICE_DATA_FROM_THIS(a) \
+ CR ( \
+ (a), \
+ MNP_SERVICE_DATA, \
+ ServiceBinding, \
+ MNP_SERVICE_DATA_SIGNATURE \
+ )
+
+EFI_STATUS
+EFIAPI
+MnpDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MnpDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MnpDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+EFI_STATUS
+EFIAPI
+MnpServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE *ChildHandle
+ );
+
+EFI_STATUS
+EFIAPI
+MnpServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ );
+
+#endif
--- /dev/null
+#/** @file\r
+# Component name for module Mnp\r
+#\r
+# FIX ME!\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+# All rights reserved. This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = MnpDxe\r
+ FILE_GUID = 025BBFC7-E6A9-4b8b-82AD-6815A1AEAF4A\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ EDK_RELEASE_VERSION = 0x00020000\r
+ EFI_SPECIFICATION_VERSION = 0x00020000\r
+\r
+ ENTRY_POINT = MnpDriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+ MnpDebug.h\r
+ MnpMain.c\r
+ MnpIo.c\r
+ MnpDriver.h\r
+ ComponentName.c\r
+ MnpDriver.c\r
+ MnpConfig.c\r
+ MnpImpl.h\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ UefiLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ DebugLib\r
+ NetLib\r
+\r
+\r
+[Protocols]\r
+ gEfiManagedNetworkServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiManagedNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+\r
--- /dev/null
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+ <MsaHeader>\r
+ <ModuleName>MnpDxe</ModuleName>\r
+ <ModuleType>DXE_DRIVER</ModuleType>\r
+ <GuidValue>025BBFC7-E6A9-4b8b-82AD-6815A1AEAF4A</GuidValue>\r
+ <Version>1.0</Version>\r
+ <Abstract>Component name for module Mnp</Abstract>\r
+ <Description>FIX ME!</Description>\r
+ <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+ <License>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.</License>\r
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>\r
+ </MsaHeader>\r
+ <ModuleDefinitions>\r
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+ <BinaryModule>false</BinaryModule>\r
+ <OutputFileBasename>MnpDxe</OutputFileBasename>\r
+ </ModuleDefinitions>\r
+ <LibraryClassDefinitions>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>DebugLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiDriverEntryPoint</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiBootServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiLib</Keyword>\r
+ </LibraryClass>\r
+ </LibraryClassDefinitions>\r
+ <SourceFiles>\r
+ <Filename>MnpImpl.h</Filename>\r
+ <Filename>MnpConfig.c</Filename>\r
+ <Filename>MnpDriver.c</Filename>\r
+ <Filename>ComponentName.c</Filename>\r
+ <Filename>MnpDriver.h</Filename>\r
+ <Filename>MnpIo.c</Filename>\r
+ <Filename>MnpMain.c</Filename>\r
+ <Filename>MnpDebug.h</Filename>\r
+ </SourceFiles>\r
+ <PackageDependencies>\r
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+ </PackageDependencies>\r
+ <Protocols>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiManagedNetworkProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiManagedNetworkServiceBindingProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ </Protocols>\r
+ <Externs>\r
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+ <Extern>\r
+ <ModuleEntryPoint>MnpDriverEntryPoint</ModuleEntryPoint>\r
+ </Extern>\r
+ </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2007, 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:
+
+ MnpImpl.h
+
+Abstract:
+
+
+**/
+
+#ifndef _MNP_IMPL_H_
+#define _MNP_IMPL_H_
+
+#include "MnpDriver.h"
+#include "MnpDebug.h"
+
+#define NET_ETHER_FCS_SIZE 4
+
+#define MNP_SYS_POLL_INTERVAL (2 * TICKS_PER_MS) // 2 milliseconds
+#define MNP_TIMEOUT_CHECK_INTERVAL (50 * TICKS_PER_MS) // 50 milliseconds
+#define MNP_TX_TIMEOUT_TIME (500 * TICKS_PER_MS) // 500 milliseconds
+#define MNP_INIT_NET_BUFFER_NUM 512
+#define MNP_NET_BUFFER_INCREASEMENT 64
+#define MNP_MAX_NET_BUFFER_NUM 65536
+
+#define MNP_MAX_RCVD_PACKET_QUE_SIZE 256
+
+#define MNP_RECEIVE_UNICAST 0x01
+#define MNP_RECEIVE_BROADCAST 0x02
+
+#define UNICAST_PACKET MNP_RECEIVE_UNICAST
+#define BROADCAST_PACKET MNP_RECEIVE_BROADCAST
+
+#define MNP_INSTANCE_DATA_SIGNATURE EFI_SIGNATURE_32 ('M', 'n', 'p', 'I')
+
+#define MNP_INSTANCE_DATA_FROM_THIS(a) \
+ CR ( \
+ (a), \
+ MNP_INSTANCE_DATA, \
+ ManagedNetwork, \
+ MNP_INSTANCE_DATA_SIGNATURE \
+ )
+
+typedef struct _MNP_INSTANCE_DATA {
+ UINT32 Signature;
+
+ MNP_SERVICE_DATA *MnpServiceData;
+
+ EFI_HANDLE Handle;
+
+ NET_LIST_ENTRY InstEntry;
+
+ EFI_MANAGED_NETWORK_PROTOCOL ManagedNetwork;
+
+ BOOLEAN Configured;
+ BOOLEAN Destroyed;
+
+ NET_LIST_ENTRY GroupCtrlBlkList;
+
+ NET_MAP RxTokenMap;
+
+ NET_LIST_ENTRY RxDeliveredPacketQueue;
+ NET_LIST_ENTRY RcvdPacketQueue;
+ UINTN RcvdPacketQueueSize;
+
+ EFI_MANAGED_NETWORK_CONFIG_DATA ConfigData;
+
+ UINT8 ReceiveFilter;
+} MNP_INSTANCE_DATA;
+
+typedef struct _MNP_GROUP_ADDRESS {
+ NET_LIST_ENTRY AddrEntry;
+ EFI_MAC_ADDRESS Address;
+ INTN RefCnt;
+} MNP_GROUP_ADDRESS;
+
+typedef struct _MNP_GROUP_CONTROL_BLOCK {
+ NET_LIST_ENTRY CtrlBlkEntry;
+ MNP_GROUP_ADDRESS *GroupAddress;
+} MNP_GROUP_CONTROL_BLOCK;
+
+typedef struct _MNP_RXDATA_WRAP {
+ NET_LIST_ENTRY WrapEntry;
+ MNP_INSTANCE_DATA *Instance;
+ EFI_MANAGED_NETWORK_RECEIVE_DATA RxData;
+ NET_BUF *Nbuf;
+ UINT64 TimeoutTick;
+} MNP_RXDATA_WRAP;
+
+EFI_STATUS
+MnpInitializeServiceData (
+ IN MNP_SERVICE_DATA *MnpServiceData,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle
+ );
+
+VOID
+MnpFlushServiceData (
+ MNP_SERVICE_DATA *MnpServiceData
+ );
+
+VOID
+MnpInitializeInstanceData (
+ IN MNP_SERVICE_DATA *MnpServiceData,
+ IN MNP_INSTANCE_DATA *Instance
+ );
+
+EFI_STATUS
+MnpTokenExist (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Arg
+ );
+
+EFI_STATUS
+MnpCancelTokens (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Arg
+ );
+
+VOID
+MnpFlushRcvdDataQueue (
+ IN MNP_INSTANCE_DATA *Instance
+ );
+
+EFI_STATUS
+MnpConfigureInstance (
+ IN MNP_INSTANCE_DATA *Instance,
+ IN EFI_MANAGED_NETWORK_CONFIG_DATA *ConfigData OPTIONAL
+ );
+
+EFI_STATUS
+MnpGroupOp (
+ IN MNP_INSTANCE_DATA *Instance,
+ IN BOOLEAN JoinFlag,
+ IN EFI_MAC_ADDRESS *MacAddr OPTIONAL,
+ IN MNP_GROUP_CONTROL_BLOCK *CtrlBlk OPTIONAL
+ );
+
+BOOLEAN
+MnpIsValidTxToken (
+ IN MNP_INSTANCE_DATA *Instance,
+ IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token
+ );
+
+VOID
+MnpBuildTxPacket (
+ IN MNP_SERVICE_DATA *MnpServiceData,
+ IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData,
+ OUT UINT8 **PktBuf,
+ OUT UINT32 *PktLen
+ );
+
+EFI_STATUS
+MnpSyncSendPacket (
+ IN MNP_SERVICE_DATA *MnpServiceData,
+ IN UINT8 *Packet,
+ IN UINT32 Length,
+ IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token
+ );
+
+EFI_STATUS
+MnpInstanceDeliverPacket (
+ IN MNP_INSTANCE_DATA *Instance
+ );
+
+VOID
+EFIAPI
+MnpRecycleRxData (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+MnpReceivePacket (
+ IN MNP_SERVICE_DATA *MnpServiceData
+ );
+
+NET_BUF *
+MnpAllocNbuf (
+ IN MNP_SERVICE_DATA *MnpServiceData
+ );
+
+VOID
+MnpFreeNbuf (
+ IN MNP_SERVICE_DATA *MnpServiceData,
+ IN NET_BUF *Nbuf
+ );
+
+VOID
+EFIAPI
+MnpCheckPacketTimeout (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+VOID
+EFIAPI
+MnpSystemPoll (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+EFIAPI
+MnpGetModeData (
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,
+ OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
+ OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MnpConfigure (
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,
+ IN EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MnpMcastIpToMac (
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Ipv6Flag,
+ IN EFI_IP_ADDRESS *IpAddress,
+ OUT EFI_MAC_ADDRESS *MacAddress
+ );
+
+EFI_STATUS
+EFIAPI
+MnpGroups (
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,
+ IN BOOLEAN JoinFlag,
+ IN EFI_MAC_ADDRESS *MacAddress OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MnpTransmit (
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,
+ IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token
+ );
+
+EFI_STATUS
+EFIAPI
+MnpCancel (
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,
+ IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+MnpReceive (
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,
+ IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token
+ );
+
+EFI_STATUS
+EFIAPI
+MnpPoll (
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This
+ );
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ MnpIo.c\r
+\r
+Abstract:\r
+\r
+ Implementation of Managed Network Protocol I/O functions.\r
+\r
+\r
+**/\r
+\r
+#include <Library/NetLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include "MnpImpl.h"\r
+\r
+\r
+/**\r
+ Validates the Mnp transmit token.\r
+\r
+ @param Instance Pointer to the Mnp instance context data.\r
+ @param Token Pointer to the transmit token to check.\r
+\r
+ @return The Token is valid or not.\r
+\r
+**/\r
+BOOLEAN\r
+MnpIsValidTxToken (\r
+ IN MNP_INSTANCE_DATA *Instance,\r
+ IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token\r
+ )\r
+{\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+ EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;\r
+ UINT32 Index;\r
+ UINT32 TotalLength;\r
+ EFI_MANAGED_NETWORK_FRAGMENT_DATA *FragmentTable;\r
+\r
+ MnpServiceData = Instance->MnpServiceData;\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ SnpMode = MnpServiceData->Snp->Mode;\r
+ TxData = Token->Packet.TxData;\r
+\r
+ if ((Token->Event == NULL) || (TxData == NULL) || (TxData->FragmentCount == 0)) {\r
+ //\r
+ // The token is invalid if the Event is NULL, or the TxData is NULL, or\r
+ // the fragment count is zero.\r
+ //\r
+ MNP_DEBUG_WARN (("MnpIsValidTxToken: Invalid Token.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ if ((TxData->DestinationAddress != NULL) && (TxData->HeaderLength != 0)) {\r
+ //\r
+ // The token is invalid if the HeaderLength isn't zero while the DestinationAddress\r
+ // is NULL (The destination address is already put into the packet).\r
+ //\r
+ MNP_DEBUG_WARN (("MnpIsValidTxToken: DestinationAddress isn't NULL, HeaderLength must be 0.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ TotalLength = 0;\r
+ FragmentTable = TxData->FragmentTable;\r
+ for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
+\r
+ if ((FragmentTable[Index].FragmentLength == 0) || (FragmentTable[Index].FragmentBuffer == NULL)) {\r
+ //\r
+ // The token is invalid if any FragmentLength is zero or any FragmentBuffer is NULL.\r
+ //\r
+ MNP_DEBUG_WARN (("MnpIsValidTxToken: Invalid FragmentLength or FragmentBuffer.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ TotalLength += FragmentTable[Index].FragmentLength;\r
+ }\r
+\r
+ if ((TxData->DestinationAddress == NULL) && (FragmentTable[0].FragmentLength < TxData->HeaderLength)) {\r
+ //\r
+ // Media header is split between fragments.\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ if (TotalLength != (TxData->DataLength + TxData->HeaderLength)) {\r
+ //\r
+ // The length calculated from the fragment information doesn't equal to the\r
+ // sum of the DataLength and the HeaderLength.\r
+ //\r
+ MNP_DEBUG_WARN (("MnpIsValidTxData: Invalid Datalength compared with the sum of fragment length.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ if (TxData->DataLength > MnpServiceData->Mtu) {\r
+ //\r
+ // The total length is larger than the MTU.\r
+ //\r
+ MNP_DEBUG_WARN (("MnpIsValidTxData: TxData->DataLength exceeds Mtu.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Build the packet to transmit from the TxData passed in.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+ @param TxData Pointer to the transmit data containing the\r
+ information to build the packet.\r
+ @param PktBuf Pointer to record the address of the packet.\r
+ @param PktLen Pointer to a UINT32 variable used to record the\r
+ packet's length.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+MnpBuildTxPacket (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData,\r
+ OUT UINT8 **PktBuf,\r
+ OUT UINT32 *PktLen\r
+ )\r
+{\r
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+ UINT8 *DstPos;\r
+ UINT16 Index;\r
+\r
+ if ((TxData->DestinationAddress == NULL) && (TxData->FragmentCount == 1)) {\r
+ //\r
+ // Media header is in FragmentTable and there is only one fragment,\r
+ // use fragment buffer directly.\r
+ //\r
+ *PktBuf = TxData->FragmentTable[0].FragmentBuffer;\r
+ *PktLen = TxData->FragmentTable[0].FragmentLength;\r
+ } else {\r
+ //\r
+ // Either media header isn't in FragmentTable or there is more than\r
+ // one fragment, copy the data into the packet buffer. Reserve the\r
+ // media header space if necessary.\r
+ //\r
+ SnpMode = MnpServiceData->Snp->Mode;\r
+ DstPos = MnpServiceData->TxBuf;\r
+\r
+ *PktLen = 0;\r
+ if (TxData->DestinationAddress != NULL) {\r
+ //\r
+ // If dest address is not NULL, move DstPos to reserve space for the\r
+ // media header. Add the media header length to buflen.\r
+ //\r
+ DstPos += SnpMode->MediaHeaderSize;\r
+ *PktLen += SnpMode->MediaHeaderSize;\r
+ }\r
+\r
+ for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
+ //\r
+ // Copy the data.\r
+ //\r
+ NetCopyMem (\r
+ DstPos,\r
+ TxData->FragmentTable[Index].FragmentBuffer,\r
+ TxData->FragmentTable[Index].FragmentLength\r
+ );\r
+ DstPos += TxData->FragmentTable[Index].FragmentLength;\r
+ }\r
+\r
+ //\r
+ // Set the buffer pointer and the buffer length.\r
+ //\r
+ *PktBuf = MnpServiceData->TxBuf;\r
+ *PktLen += TxData->DataLength + TxData->HeaderLength;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Synchronously send out the packet.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+ @param Packet Pointer to the pakcet buffer.\r
+ @param Length The length of the packet.\r
+ @param Token Pointer to the token the packet generated from.\r
+\r
+ @retval EFI_SUCCESS The packet is sent out.\r
+ @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.\r
+ @retval EFI_DEVICE_ERROR An unexpected network error occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpSyncSendPacket (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN UINT8 *Packet,\r
+ IN UINT32 Length,\r
+ IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;\r
+ UINT32 HeaderSize;\r
+ UINT8 *TxBuf;\r
+\r
+ Snp = MnpServiceData->Snp;\r
+ TxData = Token->Packet.TxData;\r
+\r
+ HeaderSize = Snp->Mode->MediaHeaderSize - TxData->HeaderLength;\r
+\r
+ //\r
+ // Start the timeout event.\r
+ //\r
+ Status = gBS->SetTimer (\r
+ MnpServiceData->TxTimeoutEvent,\r
+ TimerRelative,\r
+ MNP_TX_TIMEOUT_TIME\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ goto SIGNAL_TOKEN;\r
+ }\r
+\r
+ for (;;) {\r
+ //\r
+ // Transmit the packet through SNP.\r
+ //\r
+ Status = Snp->Transmit (\r
+ Snp,\r
+ HeaderSize,\r
+ Length,\r
+ Packet,\r
+ TxData->SourceAddress,\r
+ TxData->DestinationAddress,\r
+ &TxData->ProtocolType\r
+ );\r
+ if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // If Status is EFI_SUCCESS, the packet is put in the transmit queue.\r
+ // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.\r
+ // Both need to sync SNP.\r
+ //\r
+ TxBuf = NULL;\r
+ do {\r
+ //\r
+ // Get the recycled transmit buffer status.\r
+ //\r
+ Snp->GetStatus (Snp, NULL, &TxBuf);\r
+\r
+ if (!EFI_ERROR (gBS->CheckEvent (MnpServiceData->TxTimeoutEvent))) {\r
+\r
+ Status = EFI_TIMEOUT;\r
+ break;\r
+ }\r
+ } while (TxBuf == NULL);\r
+\r
+ if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {\r
+\r
+ break;\r
+ } else {\r
+ //\r
+ // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.\r
+ //\r
+ gBS->SetTimer (\r
+ MnpServiceData->TxTimeoutEvent,\r
+ TimerRelative,\r
+ MNP_TX_TIMEOUT_TIME\r
+ );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Cancel the timer event.\r
+ //\r
+ gBS->SetTimer (MnpServiceData->TxTimeoutEvent, TimerCancel, 0);\r
+\r
+SIGNAL_TOKEN:\r
+\r
+ Token->Status = Status;\r
+ gBS->SignalEvent (Token->Event);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Try to deliver the received packet to the instance.\r
+\r
+ @param Instance Pointer to the mnp instance context data.\r
+\r
+ @retval EFI_SUCCESS The received packet is delivered, or there is no\r
+ packet to deliver, or there is no available receive\r
+ token.\r
+ @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpInstanceDeliverPacket (\r
+ IN MNP_INSTANCE_DATA *Instance\r
+ )\r
+{\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ MNP_RXDATA_WRAP *RxDataWrap;\r
+ NET_BUF *DupNbuf;\r
+ EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+ EFI_MANAGED_NETWORK_COMPLETION_TOKEN *RxToken;\r
+\r
+ MnpServiceData = Instance->MnpServiceData;\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ if (NetMapIsEmpty (&Instance->RxTokenMap) || NetListIsEmpty (&Instance->RcvdPacketQueue)) {\r
+ //\r
+ // No pending received data or no available receive token, return.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ ASSERT (Instance->RcvdPacketQueueSize != 0);\r
+\r
+ RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);\r
+ if (RxDataWrap->Nbuf->RefCnt > 2) {\r
+ //\r
+ // There are other instances share this Nbuf, duplicate to get a\r
+ // copy to allow the instance to do R/W operations.\r
+ //\r
+ DupNbuf = MnpAllocNbuf (MnpServiceData);\r
+ if (DupNbuf == NULL) {\r
+ MNP_DEBUG_WARN (("MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Duplicate the net buffer.\r
+ //\r
+ NetbufDuplicate (RxDataWrap->Nbuf, DupNbuf, 0);\r
+ MnpFreeNbuf (MnpServiceData, RxDataWrap->Nbuf);\r
+ RxDataWrap->Nbuf = DupNbuf;\r
+ }\r
+\r
+ //\r
+ // All resources are OK, remove the packet from the queue.\r
+ //\r
+ NetListRemoveHead (&Instance->RcvdPacketQueue);\r
+ Instance->RcvdPacketQueueSize--;\r
+\r
+ RxData = &RxDataWrap->RxData;\r
+ SnpMode = MnpServiceData->Snp->Mode;\r
+\r
+ //\r
+ // Set all the buffer pointers.\r
+ //\r
+ RxData->MediaHeader = NetbufGetByte (RxDataWrap->Nbuf, 0, NULL);\r
+ RxData->DestinationAddress = RxData->MediaHeader;\r
+ RxData->SourceAddress = (UINT8 *) RxData->MediaHeader + SnpMode->HwAddressSize;\r
+ RxData->PacketData = (UINT8 *) RxData->MediaHeader + SnpMode->MediaHeaderSize;\r
+\r
+ //\r
+ // Insert this RxDataWrap into the delivered queue.\r
+ //\r
+ NetListInsertTail (&Instance->RxDeliveredPacketQueue, &RxDataWrap->WrapEntry);\r
+\r
+ //\r
+ // Get the receive token from the RxTokenMap.\r
+ //\r
+ RxToken = NetMapRemoveHead (&Instance->RxTokenMap, NULL);\r
+\r
+ //\r
+ // Signal this token's event.\r
+ //\r
+ RxToken->Packet.RxData = &RxDataWrap->RxData;\r
+ RxToken->Status = EFI_SUCCESS;\r
+ gBS->SignalEvent (RxToken->Event);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Deliver the received packet for the instances belonging to the MnpServiceData.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+MnpDeliverPacket (\r
+ IN MNP_SERVICE_DATA *MnpServiceData\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ MNP_INSTANCE_DATA *Instance;\r
+\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {\r
+ Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);\r
+ NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ //\r
+ // Try to deliver packet for this instance.\r
+ //\r
+ MnpInstanceDeliverPacket (Instance);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Recycle the RxData and other resources used to hold and deliver the received\r
+ packet.\r
+\r
+ @param Event The event this notify function registered to.\r
+ @param Context Pointer to the context data registerd to the Event.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MnpRecycleRxData (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ MNP_RXDATA_WRAP *RxDataWrap;\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+\r
+ ASSERT (Context != NULL);\r
+\r
+ RxDataWrap = (MNP_RXDATA_WRAP *) Context;\r
+ NET_CHECK_SIGNATURE (RxDataWrap->Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ ASSERT (RxDataWrap->Nbuf != NULL);\r
+\r
+ MnpServiceData = RxDataWrap->Instance->MnpServiceData;\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ //\r
+ // Free this Nbuf.\r
+ //\r
+ MnpFreeNbuf (MnpServiceData, RxDataWrap->Nbuf);\r
+ RxDataWrap->Nbuf = NULL;\r
+\r
+ //\r
+ // Close the recycle event.\r
+ //\r
+ gBS->CloseEvent (RxDataWrap->RxData.RecycleEvent);\r
+\r
+ //\r
+ // Remove this Wrap entry from the list.\r
+ //\r
+ NetListRemoveEntry (&RxDataWrap->WrapEntry);\r
+\r
+ NetFreePool (RxDataWrap);\r
+}\r
+\r
+\r
+/**\r
+ Queue the received packet into instance's receive queue.\r
+\r
+ @param Instance Pointer to the mnp instance context data.\r
+ @param RxDataWrap Pointer to the Wrap structure containing the\r
+ received data and other information.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+MnpQueueRcvdPacket (\r
+ IN MNP_INSTANCE_DATA *Instance,\r
+ IN MNP_RXDATA_WRAP *RxDataWrap\r
+ )\r
+{\r
+ MNP_RXDATA_WRAP *OldRxDataWrap;\r
+\r
+ NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ //\r
+ // Check the queue size. If it exceeds the limit, drop one packet\r
+ // from the head.\r
+ //\r
+ if (Instance->RcvdPacketQueueSize == MNP_MAX_RCVD_PACKET_QUE_SIZE) {\r
+\r
+ MNP_DEBUG_WARN (("MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));\r
+\r
+ //\r
+ // Get the oldest packet.\r
+ //\r
+ OldRxDataWrap = NET_LIST_HEAD (\r
+ &Instance->RcvdPacketQueue,\r
+ MNP_RXDATA_WRAP,\r
+ WrapEntry\r
+ );\r
+\r
+ //\r
+ // Recycle this OldRxDataWrap, this entry will be removed by the callee.\r
+ //\r
+ MnpRecycleRxData (NULL, (VOID *) OldRxDataWrap);\r
+ Instance->RcvdPacketQueueSize--;\r
+ }\r
+\r
+ //\r
+ // Update the timeout tick using the configured parameter.\r
+ //\r
+ RxDataWrap->TimeoutTick = Instance->ConfigData.ReceivedQueueTimeoutValue;\r
+\r
+ //\r
+ // Insert this Wrap into the instance queue.\r
+ //\r
+ NetListInsertTail (&Instance->RcvdPacketQueue, &RxDataWrap->WrapEntry);\r
+ Instance->RcvdPacketQueueSize++;\r
+}\r
+\r
+\r
+/**\r
+ Match the received packet with the instance receive filters.\r
+\r
+ @param Instance Pointer to the mnp instance context data.\r
+ @param RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.\r
+ @param GroupAddress Pointer to the GroupAddress, the GroupAddress is\r
+ non-NULL and it contains the destination multicast\r
+ mac address of the received packet if the packet\r
+ destinated to a multicast mac address.\r
+ @param PktAttr The received packets attribute.\r
+\r
+ @return The received packet matches the instance's receive filters or not.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+MnpMatchPacket (\r
+ IN MNP_INSTANCE_DATA *Instance,\r
+ IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData,\r
+ IN MNP_GROUP_ADDRESS *GroupAddress OPTIONAL,\r
+ IN UINT8 PktAttr\r
+ )\r
+{\r
+ EFI_MANAGED_NETWORK_CONFIG_DATA *ConfigData;\r
+ NET_LIST_ENTRY *Entry;\r
+ MNP_GROUP_CONTROL_BLOCK *GroupCtrlBlk;\r
+\r
+ NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ ConfigData = &Instance->ConfigData;\r
+\r
+ if (ConfigData->EnablePromiscuousReceive) {\r
+ //\r
+ // Always match if this instance is configured to be promiscuous.\r
+ //\r
+ return TRUE;\r
+ }\r
+ //\r
+ // Check the protocol type.\r
+ //\r
+ if ((ConfigData->ProtocolTypeFilter != 0) && (ConfigData->ProtocolTypeFilter != RxData->ProtocolType)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // The protocol type is matched, check receive filter, include unicast and broadcast.\r
+ //\r
+ if ((Instance->ReceiveFilter & PktAttr) != 0) {\r
+ return TRUE;\r
+ }\r
+\r
+ //\r
+ // Check multicast addresses.\r
+ //\r
+ if (ConfigData->EnableMulticastReceive && RxData->MulticastFlag) {\r
+\r
+ ASSERT (GroupAddress != NULL);\r
+\r
+ NET_LIST_FOR_EACH (Entry, &Instance->GroupCtrlBlkList) {\r
+\r
+ GroupCtrlBlk = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_CONTROL_BLOCK, CtrlBlkEntry);\r
+ if (GroupCtrlBlk->GroupAddress == GroupAddress) {\r
+ //\r
+ // The instance is configured to receiveing packets destinated to this\r
+ // multicast address.\r
+ //\r
+ return TRUE;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // No match.\r
+ //\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Analyse the received packets.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+ @param Nbuf Pointer to the net buffer holding the received\r
+ packet.\r
+ @param RxData Pointer to the buffer used to save the analysed\r
+ result in EFI_MANAGED_NETWORK_RECEIVE_DATA.\r
+ @param GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to\r
+ pass out the address of the multicast address the\r
+ received packet destinated to.\r
+ @param PktAttr Pointer to the buffer used to save the analysed\r
+ packet attribute.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+MnpAnalysePacket (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN NET_BUF *Nbuf,\r
+ IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData,\r
+ OUT MNP_GROUP_ADDRESS **GroupAddress,\r
+ OUT UINT8 *PktAttr\r
+ )\r
+{\r
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+ UINT8 *BufPtr;\r
+ NET_LIST_ENTRY *Entry;\r
+\r
+ SnpMode = MnpServiceData->Snp->Mode;\r
+\r
+ //\r
+ // Get the packet buffer.\r
+ //\r
+ BufPtr = NetbufGetByte (Nbuf, 0, NULL);\r
+ ASSERT (BufPtr != NULL);\r
+\r
+ //\r
+ // Set the initial values.\r
+ //\r
+ RxData->BroadcastFlag = FALSE;\r
+ RxData->MulticastFlag = FALSE;\r
+ RxData->PromiscuousFlag = FALSE;\r
+ *PktAttr = UNICAST_PACKET;\r
+\r
+ if (!NET_MAC_EQUAL (&SnpMode->CurrentAddress, BufPtr, SnpMode->HwAddressSize)) {\r
+ //\r
+ // This packet isn't destinated to our current mac address, it't not unicast.\r
+ //\r
+ *PktAttr = 0;\r
+\r
+ if (NET_MAC_EQUAL (&SnpMode->BroadcastAddress, BufPtr, SnpMode->HwAddressSize)) {\r
+ //\r
+ // It's broadcast.\r
+ //\r
+ RxData->BroadcastFlag = TRUE;\r
+ *PktAttr = BROADCAST_PACKET;\r
+ } else if ((*BufPtr & 0x01) == 0x1) {\r
+ //\r
+ // It's multicast, try to match the multicast filters.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {\r
+\r
+ *GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
+ if (NET_MAC_EQUAL (BufPtr, &((*GroupAddress)->Address), SnpMode->HwAddressSize)) {\r
+ RxData->MulticastFlag = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!RxData->MulticastFlag) {\r
+ //\r
+ // No match, set GroupAddress to NULL. This multicast packet must\r
+ // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.\r
+ //\r
+ *GroupAddress = NULL;\r
+ RxData->PromiscuousFlag = TRUE;\r
+\r
+ if (MnpServiceData->PromiscuousCount == 0) {\r
+ //\r
+ // Skip the below code, there is no receiver of this packet.\r
+ //\r
+ return ;\r
+ }\r
+ }\r
+ } else {\r
+ RxData->PromiscuousFlag = TRUE;\r
+ }\r
+ }\r
+\r
+ NetZeroMem (&RxData->Timestamp, sizeof (EFI_TIME));\r
+\r
+ //\r
+ // Fill the common parts of RxData.\r
+ //\r
+ RxData->PacketLength = Nbuf->TotalSize;\r
+ RxData->HeaderLength = SnpMode->MediaHeaderSize;\r
+ RxData->AddressLength = SnpMode->HwAddressSize;\r
+ RxData->DataLength = RxData->PacketLength - RxData->HeaderLength;\r
+ RxData->ProtocolType = NTOHS (*(UINT16 *) (BufPtr + 2 * SnpMode->HwAddressSize));\r
+}\r
+\r
+\r
+/**\r
+ Wrap the RxData.\r
+\r
+ @param Instance Pointer to the mnp instance context data.\r
+ @param RxData Pointer to the receive data to wrap.\r
+\r
+ @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.\r
+\r
+**/\r
+STATIC\r
+MNP_RXDATA_WRAP *\r
+MnpWrapRxData (\r
+ IN MNP_INSTANCE_DATA *Instance,\r
+ IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MNP_RXDATA_WRAP *RxDataWrap;\r
+\r
+ //\r
+ // Allocate memory.\r
+ //\r
+ RxDataWrap = NetAllocatePool (sizeof (MNP_RXDATA_WRAP));\r
+ if (RxDataWrap == NULL) {\r
+ MNP_DEBUG_ERROR (("MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));\r
+ return NULL;\r
+ }\r
+\r
+ RxDataWrap->Instance = Instance;\r
+\r
+ //\r
+ // Fill the RxData in RxDataWrap,\r
+ //\r
+ RxDataWrap->RxData = *RxData;\r
+\r
+ //\r
+ // Create the recycle event.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ NET_TPL_RECYCLE,\r
+ MnpRecycleRxData,\r
+ RxDataWrap,\r
+ &RxDataWrap->RxData.RecycleEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MNP_DEBUG_ERROR (("MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status));\r
+ NetFreePool (RxDataWrap);\r
+ return NULL;\r
+ }\r
+\r
+ return RxDataWrap;\r
+}\r
+\r
+\r
+/**\r
+ Enqueue the received the packets to the instances belonging to the\r
+ MnpServiceData.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+ @param Nbuf Pointer to the net buffer representing the received\r
+ packet.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+MnpEnqueuePacket (\r
+ IN MNP_SERVICE_DATA *MnpServiceData,\r
+ IN NET_BUF *Nbuf\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ MNP_INSTANCE_DATA *Instance;\r
+ EFI_MANAGED_NETWORK_RECEIVE_DATA RxData;\r
+ UINT8 PktAttr;\r
+ MNP_GROUP_ADDRESS *GroupAddress;\r
+ MNP_RXDATA_WRAP *RxDataWrap;\r
+\r
+ //\r
+ // First, analyse the packet header.\r
+ //\r
+ MnpAnalysePacket (MnpServiceData, Nbuf, &RxData, &GroupAddress, &PktAttr);\r
+\r
+ if (RxData.PromiscuousFlag && (MnpServiceData->PromiscuousCount == 0)) {\r
+ //\r
+ // No receivers, no more action need.\r
+ //\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Iterate the children to find match.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {\r
+\r
+ Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);\r
+ NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ if (!Instance->Configured) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Check the packet against the instance receive filters.\r
+ //\r
+ if (MnpMatchPacket (Instance, &RxData, GroupAddress, PktAttr)) {\r
+\r
+ //\r
+ // Wrap the RxData.\r
+ //\r
+ RxDataWrap = MnpWrapRxData (Instance, &RxData);\r
+ if (RxDataWrap == NULL) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Associate RxDataWrap with Nbuf and increase the RefCnt.\r
+ //\r
+ RxDataWrap->Nbuf = Nbuf;\r
+ NET_GET_REF (RxDataWrap->Nbuf);\r
+\r
+ //\r
+ // Queue the packet into the instance queue.\r
+ //\r
+ MnpQueueRcvdPacket (Instance, RxDataWrap);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Try to receive a packet and deliver it.\r
+\r
+ @param MnpServiceData Pointer to the mnp service context data.\r
+\r
+ @retval EFI_SUCCESS add return value to function comment\r
+ @retval EFI_NOT_STARTED The simple network protocol is not started.\r
+ @retval EFI_NOT_READY No packet received.\r
+ @retval EFI_DEVICE_ERROR An unexpected error occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpReceivePacket (\r
+ IN MNP_SERVICE_DATA *MnpServiceData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ NET_BUF *Nbuf;\r
+ UINT8 *BufPtr;\r
+ UINTN BufLen;\r
+ UINTN HeaderSize;\r
+ UINT32 Trimmed;\r
+\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ Snp = MnpServiceData->Snp;\r
+ if (Snp->Mode->State != EfiSimpleNetworkInitialized) {\r
+ //\r
+ // The simple network protocol is not started.\r
+ //\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ if (NetListIsEmpty (&MnpServiceData->ChildrenList)) {\r
+ //\r
+ // There is no child, no need to receive packets.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (MnpServiceData->RxNbufCache == NULL) {\r
+ //\r
+ // Try to get a new buffer as there may be buffers recycled.\r
+ //\r
+ MnpServiceData->RxNbufCache = MnpAllocNbuf (MnpServiceData);\r
+\r
+ if (MnpServiceData->RxNbufCache == NULL) {\r
+ //\r
+ // No availabe buffer in the buffer pool.\r
+ //\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ NetbufAllocSpace (\r
+ MnpServiceData->RxNbufCache,\r
+ MnpServiceData->BufferLength,\r
+ NET_BUF_TAIL\r
+ );\r
+ }\r
+\r
+ Nbuf = MnpServiceData->RxNbufCache;\r
+ BufLen = Nbuf->TotalSize;\r
+ BufPtr = NetbufGetByte (Nbuf, 0, NULL);\r
+ ASSERT (BufPtr != NULL);\r
+\r
+ //\r
+ // Receive packet through Snp.\r
+ //\r
+ Status = Snp->Receive (Snp, &HeaderSize, &BufLen, BufPtr, NULL, NULL, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG_CODE (\r
+ if (Status != EFI_NOT_READY) {\r
+ MNP_DEBUG_ERROR (("MnpReceivePacket: Snp->Receive() = %r.\n", Status));\r
+ }\r
+ );\r
+\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Sanity check.\r
+ //\r
+ if ((HeaderSize != Snp->Mode->MediaHeaderSize) || (BufLen < HeaderSize)) {\r
+\r
+ MNP_DEBUG_WARN (\r
+ ("MnpReceivePacket: Size error, HL:TL = %d:%d.\n",\r
+ HeaderSize,\r
+ BufLen)\r
+ );\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Trimmed = 0;\r
+ if (Nbuf->TotalSize != BufLen) {\r
+ //\r
+ // Trim the packet from tail.\r
+ //\r
+ Trimmed = NetbufTrim (Nbuf, Nbuf->TotalSize - (UINT32) BufLen, NET_BUF_TAIL);\r
+ ASSERT (Nbuf->TotalSize == BufLen);\r
+ }\r
+\r
+ //\r
+ // Enqueue the packet to the matched instances.\r
+ //\r
+ MnpEnqueuePacket (MnpServiceData, Nbuf);\r
+\r
+ if (Nbuf->RefCnt > 2) {\r
+ //\r
+ // RefCnt > 2 indicates there is at least one receiver of this packet.\r
+ // Free the current RxNbufCache and allocate a new one.\r
+ //\r
+ MnpFreeNbuf (MnpServiceData, Nbuf);\r
+\r
+ Nbuf = MnpAllocNbuf (MnpServiceData);\r
+ MnpServiceData->RxNbufCache = Nbuf;\r
+ if (Nbuf == NULL) {\r
+ MNP_DEBUG_ERROR (("MnpReceivePacket: Alloc packet for receiving cache failed.\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ NetbufAllocSpace (Nbuf, MnpServiceData->BufferLength, NET_BUF_TAIL);\r
+ } else {\r
+ //\r
+ // No receiver for this packet.\r
+ //\r
+ NetbufAllocSpace (Nbuf, Trimmed, NET_BUF_TAIL);\r
+ goto EXIT;\r
+ }\r
+ //\r
+ // Deliver the queued packets.\r
+ //\r
+ MnpDeliverPacket (MnpServiceData);\r
+\r
+EXIT:\r
+\r
+ ASSERT (Nbuf->TotalSize == MnpServiceData->BufferLength);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Remove the received packets if timeout occurs.\r
+\r
+ @param Event The event this notify function registered to.\r
+ @param Context Pointer to the context data registered to the\r
+ event.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MnpCheckPacketTimeout (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *RxEntry;\r
+ NET_LIST_ENTRY *NextEntry;\r
+ MNP_INSTANCE_DATA *Instance;\r
+ MNP_RXDATA_WRAP *RxDataWrap;\r
+ EFI_TPL OldTpl;\r
+\r
+ MnpServiceData = (MNP_SERVICE_DATA *) Context;\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {\r
+\r
+ Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);\r
+ NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
+\r
+ if (!Instance->Configured || (Instance->ConfigData.ReceivedQueueTimeoutValue == 0)) {\r
+ //\r
+ // This instance is not configured or there is no receive time out,\r
+ // just skip to the next instance.\r
+ //\r
+ continue;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
+\r
+ NET_LIST_FOR_EACH_SAFE (RxEntry, NextEntry, &Instance->RcvdPacketQueue) {\r
+\r
+ RxDataWrap = NET_LIST_USER_STRUCT (RxEntry, MNP_RXDATA_WRAP, WrapEntry);\r
+\r
+ if (RxDataWrap->TimeoutTick >= MNP_TIMEOUT_CHECK_INTERVAL) {\r
+\r
+ RxDataWrap->TimeoutTick -= MNP_TIMEOUT_CHECK_INTERVAL;\r
+ } else {\r
+ //\r
+ // Drop the timeout packet.\r
+ //\r
+ MNP_DEBUG_WARN (("MnpCheckPacketTimeout: Received packet timeout.\n"));\r
+ MnpRecycleRxData (NULL, RxDataWrap);\r
+ Instance->RcvdPacketQueueSize--;\r
+ }\r
+ }\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Poll to receive the packets from Snp. This function is either called by upperlayer\r
+ protocols/applications or the system poll timer notify mechanism.\r
+\r
+ @param Event The event this notify function registered to.\r
+ @param Context Pointer to the context data registered to the\r
+ event.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MnpSystemPoll (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+\r
+ MnpServiceData = (MNP_SERVICE_DATA *) Context;\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ //\r
+ // Try to receive packets from Snp.\r
+ //\r
+ MnpReceivePacket (MnpServiceData);\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ MnpMain.c\r
+\r
+Abstract:\r
+\r
+ Implementation of Managed Network Protocol public services.\r
+\r
+\r
+**/\r
+\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/BaseLib.h>\r
+\r
+#include "MnpImpl.h"\r
+\r
+\r
+/**\r
+ Get configuration data of this instance.\r
+\r
+ @param This Pointer to the Managed Network Protocol.\r
+ @param MnpConfigData Pointer to strorage for MNP operational\r
+ parameters.\r
+ @param SnpModeData Pointer to strorage for SNP operational\r
+ parameters.\r
+\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+ @retval EFI_INVALID_PARAMETER This is NULL.\r
+ @retval EFI_NOT_STARTED This MNP child driver instance has not been\r
+ configured The default values are returned in\r
+ MnpConfigData if it is not NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpGetModeData (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,\r
+ OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,\r
+ OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL\r
+ )\r
+{\r
+ MNP_INSTANCE_DATA *Instance;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ if (This == NULL) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (MnpConfigData != NULL) {\r
+ //\r
+ // Copy the instance configuration data.\r
+ //\r
+ *MnpConfigData = Instance->ConfigData;\r
+ }\r
+\r
+ if (SnpModeData != NULL) {\r
+ //\r
+ // Copy the underlayer Snp mode data.\r
+ //\r
+ Snp = Instance->MnpServiceData->Snp;\r
+ *SnpModeData = *(Snp->Mode);\r
+ }\r
+\r
+ if (!Instance->Configured) {\r
+ Status = EFI_NOT_STARTED;\r
+ } else {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Set or clear the operational parameters for the MNP child driver.\r
+\r
+ @param This Pointer to the Managed Network Protocol.\r
+ @param MnpConfigData Pointer to the configuration data that will be\r
+ assigned to the MNP child driver instance. If\r
+ NULL, the MNP child driver instance is reset to\r
+ startup defaults and all pending transmit and\r
+ receive requests are flushed.\r
+\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+ @retval EFI_INVALID_PARAMETER One or more parameter is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Required system resources (usually memory) could\r
+ not be allocated.\r
+ @retval EFI_UNSUPPORTED EnableReceiveTimestamps is TRUE, this\r
+ implementation doesn't support it.\r
+ @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
+ @retval Other The MNP child driver instance has been reset to\r
+ startup defaults.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpConfigure (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,\r
+ IN EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL\r
+ )\r
+{\r
+ MNP_INSTANCE_DATA *Instance;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ if ((This == NULL) ||\r
+ ((MnpConfigData != NULL) &&\r
+ (MnpConfigData->ProtocolTypeFilter > 0) &&\r
+ (MnpConfigData->ProtocolTypeFilter <= 1500))) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if ((MnpConfigData == NULL) && (!Instance->Configured)) {\r
+ //\r
+ // If the instance is not configured and a reset is requested, just return.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Configure the instance.\r
+ //\r
+ Status = MnpConfigureInstance (Instance, MnpConfigData);\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Translate a multicast IP address to a multicast hardware (MAC) address.\r
+\r
+ @param This Pointer to the Managed Network Protocol.\r
+ @param Ipv6Flag Set to TRUE if IpAddress is an IPv6 multicast\r
+ address. Set to FALSE if IpAddress is an IPv4\r
+ multicast address.\r
+ @param IpAddress Pointer to the multicast IP address to convert.\r
+ @param MacAddress Pointer to the resulting multicast MAC address.\r
+\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+ @retval EFI_INVALID_PARAMETER One or more parameter is invalid.\r
+ @retval EFI_NOT_STARTED This MNP child driver instance has not been\r
+ configured.\r
+ @retval EFI_UNSUPPORTED Ipv6Flag is TRUE, this implementation doesn't\r
+ supported it.\r
+ @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
+ @retval Other The address could not be converted.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpMcastIpToMac (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,\r
+ IN BOOLEAN Ipv6Flag,\r
+ IN EFI_IP_ADDRESS *IpAddress,\r
+ OUT EFI_MAC_ADDRESS *MacAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MNP_INSTANCE_DATA *Instance;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((This == NULL) || (IpAddress == NULL) || (MacAddress == NULL)) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Ipv6Flag) {\r
+ //\r
+ // Currently IPv6 isn't supported.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (!IP4_IS_MULTICAST (EFI_NTOHL (*IpAddress))) {\r
+ //\r
+ // The IPv4 address passed in is not a multicast address.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (!Instance->Configured) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Snp = Instance->MnpServiceData->Snp;\r
+ ASSERT (Snp != NULL);\r
+\r
+ if (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) {\r
+ //\r
+ // Translate the IPv4 address into a multicast MAC address if the NIC is an\r
+ // ethernet NIC.\r
+ //\r
+ MacAddress->Addr[0] = 0x01;\r
+ MacAddress->Addr[1] = 0x00;\r
+ MacAddress->Addr[2] = 0x5E;\r
+ MacAddress->Addr[3] = IpAddress->v4.Addr[1] & 0x7F;\r
+ MacAddress->Addr[4] = IpAddress->v4.Addr[2];\r
+ MacAddress->Addr[5] = IpAddress->v4.Addr[3];\r
+\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ //\r
+ // Invoke Snp to translate the multicast IP address.\r
+ //\r
+ Status = Snp->MCastIpToMac (\r
+ Snp,\r
+ Ipv6Flag,\r
+ IpAddress,\r
+ MacAddress\r
+ );\r
+ }\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Enable or disable receie filters for multicast address.\r
+\r
+ @param This Pointer to the Managed Network Protocol.\r
+ @param JoinFlag Set to TRUE to join this multicast group. Set to\r
+ FALSE to leave this multicast group.\r
+ @param MacAddress Pointer to the multicast MAC group (address) to\r
+ join or leave.\r
+\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+ @retval EFI_INVALID_PARAMETER One or more parameter is invalid\r
+ @retval EFI_NOT_STARTED This MNP child driver instance has not been\r
+ configured.\r
+ @retval EFI_ALREADY_STARTED The supplied multicast group is already joined.\r
+ @retval EFI_NOT_FOUND The supplied multicast group is not joined.\r
+ @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
+ @retval Other The requested operation could not be completed.\r
+ The MNP multicast group settings are unchanged.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpGroups (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,\r
+ IN BOOLEAN JoinFlag,\r
+ IN EFI_MAC_ADDRESS *MacAddress OPTIONAL\r
+ )\r
+{\r
+ MNP_INSTANCE_DATA *Instance;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+ MNP_GROUP_CONTROL_BLOCK *GroupCtrlBlk;\r
+ MNP_GROUP_ADDRESS *GroupAddress;\r
+ NET_LIST_ENTRY *ListEntry;\r
+ BOOLEAN AddressExist;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ if (This == NULL || (JoinFlag && (MacAddress == NULL))) {\r
+ //\r
+ // This is NULL, or it's a join operation but MacAddress is NULL.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+ SnpMode = Instance->MnpServiceData->Snp->Mode;\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (!Instance->Configured) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if ((!Instance->ConfigData.EnableMulticastReceive) ||\r
+ ((MacAddress != NULL) && !NET_MAC_IS_MULTICAST (MacAddress, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize))) {\r
+ //\r
+ // The instance isn't configured to do mulitcast receive. OR\r
+ // the passed in MacAddress is not a mutlticast mac address.\r
+ //\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ AddressExist = FALSE;\r
+ GroupCtrlBlk = NULL;\r
+\r
+ if (MacAddress != NULL) {\r
+ //\r
+ // Search the instance's GroupCtrlBlkList to find the specific address.\r
+ //\r
+ NET_LIST_FOR_EACH (ListEntry, &Instance->GroupCtrlBlkList) {\r
+\r
+ GroupCtrlBlk = NET_LIST_USER_STRUCT (\r
+ ListEntry,\r
+ MNP_GROUP_CONTROL_BLOCK,\r
+ CtrlBlkEntry\r
+ );\r
+ GroupAddress = GroupCtrlBlk->GroupAddress;\r
+ if (0 == NetCompareMem (\r
+ MacAddress,\r
+ &GroupAddress->Address,\r
+ SnpMode->HwAddressSize\r
+ )) {\r
+ //\r
+ // There is already the same multicast mac address configured.\r
+ //\r
+ AddressExist = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (JoinFlag && AddressExist) {\r
+ //\r
+ // The multicast mac address to join already exists.\r
+ //\r
+ Status = EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ if (!JoinFlag && !AddressExist) {\r
+ //\r
+ // The multicast mac address to leave doesn't exist in this instance.\r
+ //\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ } else if (NetListIsEmpty (&Instance->GroupCtrlBlkList)) {\r
+ //\r
+ // The MacAddress is NULL and there is no configured multicast mac address,\r
+ // just return.\r
+ //\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // OK, it is time to take action.\r
+ //\r
+ Status = MnpGroupOp (Instance, JoinFlag, MacAddress, GroupCtrlBlk);\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Place an outgoing packet into the transmit queue.\r
+\r
+ @param This Pointer to the Managed Network Protocol.\r
+ @param Token Pointer to a token associated with the transmit\r
+ data descriptor.\r
+\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+ @retval EFI_INVALID_PARAMETER One or more parameter is invalid\r
+ @retval EFI_NOT_STARTED This MNP child driver instance has not been\r
+ configured.\r
+ @retval EFI_ACCESS_DENIED The transmit completion token is already in the\r
+ transmit queue.\r
+ @retval EFI_OUT_OF_RESOURCES The transmit data could not be queued due to a\r
+ lack of system resources (usually memory).\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
+ The MNP child driver instance has been reset to\r
+ startup defaults.\r
+ @retval EFI_NOT_READY The transmit request could not be queued because\r
+ the transmit queue is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpTransmit (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,\r
+ IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MNP_INSTANCE_DATA *Instance;\r
+ MNP_SERVICE_DATA *MnpServiceData;\r
+ UINT8 *PktBuf;\r
+ UINT32 PktLen;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((This == NULL) || (Token == NULL)) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (!Instance->Configured) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (!MnpIsValidTxToken (Instance, Token)) {\r
+ //\r
+ // The Token is invalid.\r
+ //\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ MnpServiceData = Instance->MnpServiceData;\r
+ NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
+\r
+ //\r
+ // Build the tx packet\r
+ //\r
+ MnpBuildTxPacket (MnpServiceData, Token->Packet.TxData, &PktBuf, &PktLen);\r
+\r
+ //\r
+ // OK, send the packet synchronously.\r
+ //\r
+ Status = MnpSyncSendPacket (MnpServiceData, PktBuf, PktLen, Token);\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Place an asynchronous receiving request into the receiving queue.\r
+\r
+ @param This Pointer to the EFI_MANAGED_NETWORK_PROTOCOL\r
+ instance.\r
+ @param Token Pointer to a token associated with the receive\r
+ data descriptor.\r
+\r
+ @retval EFI_SUCCESS The receive completion token was cached.\r
+ @retval EFI_NOT_STARTED This MNP child driver instance has not been\r
+ configured.\r
+ @retval EFI_INVALID_PARAMETER One or more parameter is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The transmit data could not be queued due to a\r
+ lack of system resources (usually memory).\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
+ The MNP child driver instance has been reset to\r
+ startup defaults.\r
+ @retval EFI_ACCESS_DENIED The receive completion token was already in the\r
+ receive queue.\r
+ @retval EFI_NOT_READY The receive request could not be queued because\r
+ the receive queue is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpReceive (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,\r
+ IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MNP_INSTANCE_DATA *Instance;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (!Instance->Configured) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Check whether this token(event) is already in the rx token queue.\r
+ //\r
+ Status = NetMapIterate (&Instance->RxTokenMap, MnpTokenExist, (VOID *) Token);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Insert the Token into the RxTokenMap.\r
+ //\r
+ Status = NetMapInsertTail (&Instance->RxTokenMap, (VOID *) Token, NULL);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Try to deliver any buffered packets.\r
+ //\r
+ Status = MnpInstanceDeliverPacket (Instance);\r
+ }\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Abort a pending transmit or receive request.\r
+\r
+ @param This Pointer to the EFI_MANAGED_NETWORK_PROTOCOL\r
+ instance.\r
+ @param Token Pointer to a token that has been issued by\r
+ EFI_MANAGED_NETWORK_PROTOCOL.Transmit() or\r
+ EFI_MANAGED_NETWORK_PROTOCOL.Receive(). If NULL,\r
+ all pending tokens are aborted.\r
+\r
+ @retval EFI_SUCCESS The asynchronous I/O request was aborted and\r
+ Token->Event was signaled.\r
+ @retval EFI_NOT_STARTED This MNP child driver instance has not been\r
+ configured.\r
+ @retval EFI_INVALID_PARAMETER This is NULL.\r
+ @retval EFI_NOT_FOUND The asynchronous I/O request was not found in the\r
+ transmit or receive queue. It has either completed\r
+ or was not issued by Transmit() and Receive().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpCancel (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This,\r
+ IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MNP_INSTANCE_DATA *Instance;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (This == NULL) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (!Instance->Configured) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Iterate the RxTokenMap to cancel the specified Token.\r
+ //\r
+ Status = NetMapIterate (&Instance->RxTokenMap, MnpCancelTokens, (VOID *) Token);\r
+\r
+ if (Token != NULL) {\r
+\r
+ Status = (Status == EFI_ABORTED) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+ }\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Poll the network interface to do transmit/receive work.\r
+\r
+ @param This Pointer to the EFI_MANAGED_NETWORK_PROTOCOL\r
+ instance.\r
+\r
+ @retval EFI_SUCCESS Incoming or outgoing data was processed.\r
+ @retval EFI_NOT_STARTED This MNP child driver instance has not been\r
+ configured.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
+ The MNP child driver instance has been reset to\r
+ startup defaults.\r
+ @retval EFI_NOT_READY No incoming or outgoing data was processed.\r
+ @retval EFI_TIMEOUT Data was dropped out of the transmit and/or\r
+ receive queue.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MnpPoll (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *This\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MNP_INSTANCE_DATA *Instance;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MNP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (!Instance->Configured) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Try to receive packets.\r
+ //\r
+ Status = MnpReceivePacket (Instance->MnpServiceData);\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+\r
+#include "Snp.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL gSimpleNetworkComponentName = {\r
+ SimpleNetworkComponentNameGetDriverName,\r
+ SimpleNetworkComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mSimpleNetworkDriverNameTable[] = {\r
+ {\r
+ "eng",\r
+ L"Simple Network Protocol Driver"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ Language - A pointer to a three character ISO 639-2 language identifier.\r
+ This is the language of the driver name that that the caller\r
+ is requesting, and it must match one of the languages specified\r
+ in SupportedLanguages. The number of languages supported by a\r
+ driver is up to the driver writer.\r
+ DriverName - A pointer to the Unicode string to return. This Unicode string\r
+ is the name of the driver specified by This in the language\r
+ specified by Language.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The Unicode string for the Driver specified by This\r
+ and the language specified by Language was returned\r
+ in DriverName.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - DriverName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gSimpleNetworkComponentName.SupportedLanguages,\r
+ mSimpleNetworkDriverNameTable,\r
+ DriverName\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by an EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ ControllerHandle - The handle of a controller that the driver specified by\r
+ This is managing. This handle specifies the controller\r
+ whose name is to be returned.\r
+ ChildHandle - The handle of the child controller to retrieve the name\r
+ of. This is an optional parameter that may be NULL. It\r
+ will be NULL for device drivers. It will also be NULL\r
+ for a bus drivers that wish to retrieve the name of the\r
+ bus controller. It will not be NULL for a bus driver\r
+ that wishes to retrieve the name of a child controller.\r
+ Language - A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language of the controller name\r
+ that that the caller is requesting, and it must match one\r
+ of the languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up to the\r
+ driver writer.\r
+ ControllerName - A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the controller specified by\r
+ ControllerHandle and ChildHandle in the language specified\r
+ by Language from the point of view of the driver specified\r
+ by This.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The Unicode string for the user readable name in the\r
+ language specified by Language for the driver\r
+ specified by This was returned in DriverName.\r
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This is not currently managing\r
+ the controller specified by ControllerHandle and\r
+ ChildHandle.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+#/** @file\r
+# Component name for module SNP\r
+#\r
+# FIX ME!\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+# All rights reserved. This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SnpDxe\r
+ FILE_GUID = A2f436EA-A127-4EF8-957C-8048606FF670\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ EDK_RELEASE_VERSION = 0x00020000\r
+ EFI_SPECIFICATION_VERSION = 0x00020000\r
+\r
+ ENTRY_POINT = InitializeSnpNiiDriver\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+ receive.c\r
+ snp.h\r
+ nvdata.c\r
+ get_status.c\r
+ start.c\r
+ snp.c\r
+ stop.c\r
+ statistics.c\r
+ reset.c\r
+ shutdown.c\r
+ mcast_ip_to_mac.c\r
+ transmit.c\r
+ WaitForPacket.c\r
+ receive_filters.c\r
+ initialize.c\r
+ ComponentName.c\r
+ callback.c\r
+ station_address.c\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ UefiLib\r
+ BaseLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ BaseMemoryLib\r
+ DebugLib\r
+\r
+\r
+[Protocols]\r
+ gEfiPciIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiNetworkInterfaceIdentifierProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiNetworkInterfaceIdentifierProtocolGuid_31 # PROTOCOL ALWAYS_CONSUMED\r
--- /dev/null
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+ <MsaHeader>\r
+ <ModuleName>SnpDxe</ModuleName>\r
+ <ModuleType>DXE_DRIVER</ModuleType>\r
+ <GuidValue>A2f436EA-A127-4EF8-957C-8048606FF670</GuidValue>\r
+ <Version>1.0</Version>\r
+ <Abstract>Component name for module SNP</Abstract>\r
+ <Description>FIX ME!</Description>\r
+ <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+ <License>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.</License>\r
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>\r
+ </MsaHeader>\r
+ <ModuleDefinitions>\r
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+ <BinaryModule>false</BinaryModule>\r
+ <OutputFileBasename>SnpDxe</OutputFileBasename>\r
+ </ModuleDefinitions>\r
+ <LibraryClassDefinitions>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>DebugLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>BaseMemoryLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiDriverEntryPoint</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiBootServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>BaseLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiLib</Keyword>\r
+ </LibraryClass>\r
+ </LibraryClassDefinitions>\r
+ <SourceFiles>\r
+ <Filename>station_address.c</Filename>\r
+ <Filename>SNPEntry.c</Filename>\r
+ <Filename>callback.c</Filename>\r
+ <Filename>ComponentName.c</Filename>\r
+ <Filename>initialize.c</Filename>\r
+ <Filename>receive_filters.c</Filename>\r
+ <Filename>WaitForPacket.c</Filename>\r
+ <Filename>transmit.c</Filename>\r
+ <Filename>mcast_ip_to_mac.c</Filename>\r
+ <Filename>shutdown.c</Filename>\r
+ <Filename>reset.c</Filename>\r
+ <Filename>statistics.c</Filename>\r
+ <Filename>stop.c</Filename>\r
+ <Filename>snp.c</Filename>\r
+ <Filename>start.c</Filename>\r
+ <Filename>get_status.c</Filename>\r
+ <Filename>nvdata.c</Filename>\r
+ <Filename>snp.h</Filename>\r
+ <Filename>receive.c</Filename>\r
+ </SourceFiles>\r
+ <PackageDependencies>\r
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+ </PackageDependencies>\r
+ <Protocols>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiNetworkInterfaceIdentifierProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiPciIoProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ </Protocols>\r
+ <Externs>\r
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+ <Extern>\r
+ <ModuleEntryPoint>InitializeSnpNiiDriver</ModuleEntryPoint>\r
+ </Extern>\r
+ </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
--- /dev/null
+/** @file\r
+Copyright (c) 2004, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ WaitForPacket.c\r
+\r
+Abstract:\r
+ Event handler to check for available packet.\r
+\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+\r
+\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SnpWaitForPacketNotify (\r
+ EFI_EVENT Event,\r
+ VOID *SnpPtr\r
+ )\r
+{\r
+ PXE_DB_GET_STATUS PxeDbGetStatus;\r
+\r
+ //\r
+ // Do nothing if either parameter is a NULL pointer.\r
+ //\r
+ if (Event == NULL || SnpPtr == NULL) {\r
+ return ;\r
+ }\r
+ //\r
+ // Do nothing if the SNP interface is not initialized.\r
+ //\r
+ switch (((SNP_DRIVER *) SnpPtr)->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ case EfiSimpleNetworkStarted:\r
+ default:\r
+ return ;\r
+ }\r
+ //\r
+ // Fill in CDB for UNDI GetStatus().\r
+ //\r
+ ((SNP_DRIVER *) SnpPtr)->cdb.OpCode = PXE_OPCODE_GET_STATUS;\r
+ ((SNP_DRIVER *) SnpPtr)->cdb.OpFlags = 0;\r
+ ((SNP_DRIVER *) SnpPtr)->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ ((SNP_DRIVER *) SnpPtr)->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ ((SNP_DRIVER *) SnpPtr)->cdb.DBsize = sizeof (UINT32) * 2;\r
+ ((SNP_DRIVER *) SnpPtr)->cdb.DBaddr = (UINT64)(UINTN) (((SNP_DRIVER *) SnpPtr)->db);\r
+ ((SNP_DRIVER *) SnpPtr)->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ ((SNP_DRIVER *) SnpPtr)->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ ((SNP_DRIVER *) SnpPtr)->cdb.IFnum = ((SNP_DRIVER *) SnpPtr)->if_num;\r
+ ((SNP_DRIVER *) SnpPtr)->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Clear contents of DB buffer.\r
+ //\r
+ ZeroMem (((SNP_DRIVER *) SnpPtr)->db, sizeof (UINT32) * 2);\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ (*((SNP_DRIVER *) SnpPtr)->issue_undi32_command) ((UINT64)(UINTN) &((SNP_DRIVER *) SnpPtr)->cdb);\r
+\r
+ if (((SNP_DRIVER *) SnpPtr)->cdb.StatCode != EFI_SUCCESS) {\r
+ return ;\r
+ }\r
+ //\r
+ // We might have a packet. Check the receive length and signal\r
+ // the event if the length is not zero.\r
+ //\r
+ CopyMem (\r
+ &PxeDbGetStatus,\r
+ ((SNP_DRIVER *) SnpPtr)->db,\r
+ sizeof (UINT32) * 2\r
+ );\r
+\r
+ if (PxeDbGetStatus.RxFrameLen != 0) {\r
+ gBS->SignalEvent (Event);\r
+ }\r
+}\r
+\r
+/* eof - WaitForPacket.c */\r
--- /dev/null
+/*++\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ callback.c\r
+\r
+Abstract:\r
+ This file contains two sets of callback routines for undi3.0 and undi3.1.\r
+ the callback routines for Undi3.1 have an extra parameter UniqueId which\r
+ stores the interface context for the NIC that snp is trying to talk..\r
+\r
+--*/\r
+\r
+\r
+#include "Snp.h"\r
+\r
+//\r
+// Global variables\r
+// these 2 global variables are used only for 3.0 undi. we could not place\r
+// them in the snp structure because we will not know which snp structure\r
+// in the callback context!\r
+//\r
+STATIC BOOLEAN mInitializeLock = TRUE;\r
+STATIC EFI_LOCK mLock;\r
+\r
+//\r
+// End Global variables\r
+//\r
+extern EFI_PCI_IO_PROTOCOL *mPciIoFncs;\r
+\r
+VOID\r
+snp_undi32_callback_v2p_30 (\r
+ IN UINT64 CpuAddr,\r
+ IN OUT UINT64 DeviceAddrPtr\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine with a virtual or CPU address that SNP provided\r
+ to convert it to a physical or device address. Since EFI uses the identical\r
+ mapping, this routine returns the physical address same as the virtual address\r
+ for most of the addresses. an address above 4GB cannot generally be used as a\r
+ device address, it needs to be mapped to a lower physical address. This routine\r
+ does not call the map routine itself, but it assumes that the mapping was done\r
+ at the time of providing the address to UNDI. This routine just looks up the\r
+ address in a map table (which is the v2p structure chain)\r
+\r
+Arguments:\r
+ CpuAddr - virtual address of a buffer\r
+ DeviceAddrPtr - pointer to the physical address\r
+\r
+Returns:\r
+ void - The DeviceAddrPtr will contain 0 in case of any error\r
+\r
+--*/\r
+{\r
+ struct s_v2p *v2p;\r
+ //\r
+ // Do nothing if virtual address is zero or physical pointer is NULL.\r
+ // No need to map if the virtual address is within 4GB limit since\r
+ // EFI uses identical mapping\r
+ //\r
+ if ((CpuAddr == 0) || (DeviceAddrPtr == 0)) {\r
+ DEBUG ((EFI_D_ERROR, "\nv2p: Null virtual address or physical pointer.\n"));\r
+ return ;\r
+ }\r
+\r
+ if (CpuAddr < FOUR_GIGABYTES) {\r
+ *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr;\r
+ return ;\r
+ }\r
+ //\r
+ // SNP creates a vaddr tp paddr mapping at the time of calling undi with any\r
+ // big address, this callback routine just looks up in the v2p list and\r
+ // returns the physical address for any given virtual address.\r
+ //\r
+ if (find_v2p (&v2p, (VOID *) (UINTN) CpuAddr) != EFI_SUCCESS) {\r
+ *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr;\r
+ } else {\r
+ *(UINT64 *) (UINTN) DeviceAddrPtr = v2p->paddr;\r
+ }\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_block_30 (\r
+ IN UINT32 Enable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine when it wants to have exclusive access to a critical\r
+ section of the code/data\r
+\r
+Arguments:\r
+ Enable - non-zero indicates acquire\r
+ zero indicates release\r
+\r
+Returns:\r
+ void\r
+--*/\r
+{\r
+ //\r
+ // tcpip was calling snp at tpl_notify and if we acquire a lock that was\r
+ // created at a lower level (TPL_CALLBACK) it gives an assert!\r
+ //\r
+ if (mInitializeLock) {\r
+ EfiInitializeLock (&mLock, TPL_NOTIFY);\r
+ mInitializeLock = FALSE;\r
+ }\r
+\r
+ if (Enable != 0) {\r
+ EfiAcquireLock (&mLock);\r
+ } else {\r
+ EfiReleaseLock (&mLock);\r
+ }\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_delay_30 (\r
+ IN UINT64 MicroSeconds\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine with the number of micro seconds when it wants to\r
+ pause.\r
+\r
+Arguments:\r
+ MicroSeconds - number of micro seconds to pause, ususlly multiple of 10\r
+\r
+Returns:\r
+ void\r
+--*/\r
+{\r
+ if (MicroSeconds != 0) {\r
+ gBS->Stall ((UINTN) MicroSeconds);\r
+ }\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_memio_30 (\r
+ IN UINT8 ReadOrWrite,\r
+ IN UINT8 NumBytes,\r
+ IN UINT64 Address,\r
+ IN OUT UINT64 BufferAddr\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ This is the IO routine for UNDI. This is not currently being used by UNDI3.0\r
+ because Undi3.0 uses io/mem offsets relative to the beginning of the device\r
+ io/mem address and so it needs to use the PCI_IO_FUNCTION that abstracts the\r
+ start of the device's io/mem addresses. Since SNP cannot retrive the context\r
+ of the undi3.0 interface it cannot use the PCI_IO_FUNCTION that specific for\r
+ that NIC and uses one global IO functions structure, this does not work.\r
+ This however works fine for EFI1.0 Undis because they use absolute addresses\r
+ for io/mem access.\r
+\r
+Arguments:\r
+ ReadOrWrite - indicates read or write, IO or Memory\r
+ NumBytes - number of bytes to read or write\r
+ Address - IO or memory address to read from or write to\r
+ BufferAddr - memory location to read into or that contains the bytes\r
+ to write\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
+\r
+ switch (NumBytes) {\r
+ case 2:\r
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;\r
+ break;\r
+\r
+ case 4:\r
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;\r
+ break;\r
+\r
+ case 8:\r
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;\r
+ break;\r
+\r
+ default:\r
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;\r
+ }\r
+\r
+ switch (ReadOrWrite) {\r
+ case PXE_IO_READ:\r
+ mPciIoFncs->Io.Read (\r
+ mPciIoFncs,\r
+ Width,\r
+ 1, // BAR 1, IO base address\r
+ Address,\r
+ 1, // count\r
+ (VOID *) (UINTN) BufferAddr\r
+ );\r
+ break;\r
+\r
+ case PXE_IO_WRITE:\r
+ mPciIoFncs->Io.Write (\r
+ mPciIoFncs,\r
+ Width,\r
+ 1, // BAR 1, IO base address\r
+ Address,\r
+ 1, // count\r
+ (VOID *) (UINTN) BufferAddr\r
+ );\r
+ break;\r
+\r
+ case PXE_MEM_READ:\r
+ mPciIoFncs->Mem.Read (\r
+ mPciIoFncs,\r
+ Width,\r
+ 0, // BAR 0, Memory base address\r
+ Address,\r
+ 1, // count\r
+ (VOID *) (UINTN) BufferAddr\r
+ );\r
+ break;\r
+\r
+ case PXE_MEM_WRITE:\r
+ mPciIoFncs->Mem.Write (\r
+ mPciIoFncs,\r
+ Width,\r
+ 0, // BAR 0, Memory base address\r
+ Address,\r
+ 1, // count\r
+ (VOID *) (UINTN) BufferAddr\r
+ );\r
+ break;\r
+ }\r
+\r
+ return ;\r
+}\r
+//\r
+// New callbacks for 3.1:\r
+// there won't be a virtual2physical callback for UNDI 3.1 because undi3.1 uses\r
+// the MemMap call to map the required address by itself!\r
+//\r
+VOID\r
+snp_undi32_callback_block (\r
+ IN UINT64 UniqueId,\r
+ IN UINT32 Enable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI3.1 at undi_start time.\r
+ UNDI call this routine when it wants to have exclusive access to a critical\r
+ section of the code/data\r
+\r
+Arguments:\r
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store\r
+ Undi interface context (Undi does not read or write this variable)\r
+ Enable - non-zero indicates acquire\r
+ zero indicates release\r
+\r
+Returns:\r
+ void\r
+\r
+--*/\r
+{\r
+ SNP_DRIVER *snp;\r
+\r
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;\r
+ //\r
+ // tcpip was calling snp at tpl_notify and when we acquire a lock that was\r
+ // created at a lower level (TPL_CALLBACK) it gives an assert!\r
+ //\r
+ if (Enable != 0) {\r
+ EfiAcquireLock (&snp->lock);\r
+ } else {\r
+ EfiReleaseLock (&snp->lock);\r
+ }\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_delay (\r
+ IN UINT64 UniqueId,\r
+ IN UINT64 MicroSeconds\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine with the number of micro seconds when it wants to\r
+ pause.\r
+\r
+Arguments:\r
+ MicroSeconds - number of micro seconds to pause, ususlly multiple of 10\r
+\r
+Returns:\r
+ void\r
+--*/\r
+{\r
+ if (MicroSeconds != 0) {\r
+ gBS->Stall ((UINTN) MicroSeconds);\r
+ }\r
+}\r
+\r
+/*\r
+ * IO routine for UNDI start CPB.\r
+ */\r
+VOID\r
+snp_undi32_callback_memio (\r
+ UINT64 UniqueId,\r
+ UINT8 ReadOrWrite,\r
+ UINT8 NumBytes,\r
+ UINT64 Address,\r
+ UINT64 BufferAddr\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ This is the IO routine for UNDI3.1.\r
+\r
+Arguments:\r
+ ReadOrWrite - indicates read or write, IO or Memory\r
+ NumBytes - number of bytes to read or write\r
+ Address - IO or memory address to read from or write to\r
+ BufferAddr - memory location to read into or that contains the bytes\r
+ to write\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
+\r
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;\r
+\r
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;\r
+ switch (NumBytes) {\r
+ case 2:\r
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;\r
+ break;\r
+\r
+ case 4:\r
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;\r
+ break;\r
+\r
+ case 8:\r
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;\r
+ break;\r
+ }\r
+\r
+ switch (ReadOrWrite) {\r
+ case PXE_IO_READ:\r
+ snp->IoFncs->Io.Read (\r
+ snp->IoFncs,\r
+ Width,\r
+ snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address\r
+ Address,\r
+ 1, // count\r
+ (VOID *) (UINTN) BufferAddr\r
+ );\r
+ break;\r
+\r
+ case PXE_IO_WRITE:\r
+ snp->IoFncs->Io.Write (\r
+ snp->IoFncs,\r
+ Width,\r
+ snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address\r
+ Address,\r
+ 1, // count\r
+ (VOID *) (UINTN) BufferAddr\r
+ );\r
+ break;\r
+\r
+ case PXE_MEM_READ:\r
+ snp->IoFncs->Mem.Read (\r
+ snp->IoFncs,\r
+ Width,\r
+ snp->MemoryBarIndex, // BAR 0, Memory base address\r
+ Address,\r
+ 1, // count\r
+ (VOID *) (UINTN) BufferAddr\r
+ );\r
+ break;\r
+\r
+ case PXE_MEM_WRITE:\r
+ snp->IoFncs->Mem.Write (\r
+ snp->IoFncs,\r
+ Width,\r
+ snp->MemoryBarIndex, // BAR 0, Memory base address\r
+ Address,\r
+ 1, // count\r
+ (VOID *) (UINTN) BufferAddr\r
+ );\r
+ break;\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_map (\r
+ IN UINT64 UniqueId,\r
+ IN UINT64 CpuAddr,\r
+ IN UINT32 NumBytes,\r
+ IN UINT32 Direction,\r
+ IN OUT UINT64 DeviceAddrPtr\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine when it has to map a CPU address to a device\r
+ address.\r
+\r
+Arguments:\r
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store\r
+ Undi interface context (Undi does not read or write this variable)\r
+ CpuAddr - Virtual address to be mapped!\r
+ NumBytes - size of memory to be mapped\r
+ Direction - direction of data flow for this memory's usage:\r
+ cpu->device, device->cpu or both ways\r
+ DeviceAddrPtr - pointer to return the mapped device address\r
+\r
+Returns:\r
+ None\r
+\r
+--*/\r
+{\r
+ EFI_PHYSICAL_ADDRESS *DevAddrPtr;\r
+ EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;\r
+ UINTN BuffSize;\r
+ SNP_DRIVER *snp;\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+\r
+ BuffSize = (UINTN) NumBytes;\r
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;\r
+ DevAddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;\r
+\r
+ if (CpuAddr == 0) {\r
+ *DevAddrPtr = 0;\r
+ return ;\r
+ }\r
+\r
+ switch (Direction) {\r
+ case TO_AND_FROM_DEVICE:\r
+ DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;\r
+ break;\r
+\r
+ case FROM_DEVICE:\r
+ DirectionFlag = EfiPciIoOperationBusMasterWrite;\r
+ break;\r
+\r
+ case TO_DEVICE:\r
+ DirectionFlag = EfiPciIoOperationBusMasterRead;\r
+ break;\r
+\r
+ default:\r
+ *DevAddrPtr = 0;\r
+ //\r
+ // any non zero indicates error!\r
+ //\r
+ return ;\r
+ }\r
+ //\r
+ // find an unused map_list entry\r
+ //\r
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {\r
+ if (snp->map_list[Index].virt == 0) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index >= MAX_MAP_LENGTH) {\r
+ DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n"));\r
+ *DevAddrPtr = 0;\r
+ return ;\r
+ }\r
+\r
+ snp->map_list[Index].virt = (EFI_PHYSICAL_ADDRESS) CpuAddr;\r
+\r
+ Status = snp->IoFncs->Map (\r
+ snp->IoFncs,\r
+ DirectionFlag,\r
+ (VOID *) (UINTN) CpuAddr,\r
+ &BuffSize,\r
+ DevAddrPtr,\r
+ &(snp->map_list[Index].map_cookie)\r
+ );\r
+ if (Status != EFI_SUCCESS) {\r
+ *DevAddrPtr = 0;\r
+ snp->map_list[Index].virt = 0;\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_unmap (\r
+ IN UINT64 UniqueId,\r
+ IN UINT64 CpuAddr,\r
+ IN UINT32 NumBytes,\r
+ IN UINT32 Direction,\r
+ IN UINT64 DeviceAddr\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine when it wants to unmap an address that was previously\r
+ mapped using map callback\r
+\r
+Arguments:\r
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store\r
+ Undi interface context (Undi does not read or write this variable)\r
+ CpuAddr - Virtual address that was mapped!\r
+ NumBytes - size of memory mapped\r
+ Direction- direction of data flow for this memory's usage:\r
+ cpu->device, device->cpu or both ways\r
+ DeviceAddr - the mapped device address\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+ SNP_DRIVER *snp;\r
+ UINT16 Index;\r
+\r
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;\r
+\r
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {\r
+ if (snp->map_list[Index].virt == CpuAddr) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index >= MAX_MAP_LENGTH)\r
+ {\r
+ DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n"));\r
+ return ;\r
+ }\r
+\r
+ snp->IoFncs->Unmap (snp->IoFncs, snp->map_list[Index].map_cookie);\r
+ snp->map_list[Index].virt = 0;\r
+ snp->map_list[Index].map_cookie = NULL;\r
+ return ;\r
+}\r
+\r
+VOID\r
+snp_undi32_callback_sync (\r
+ UINT64 UniqueId,\r
+ UINT64 CpuAddr,\r
+ UINT32 NumBytes,\r
+ UINT32 Direction,\r
+ UINT64 DeviceAddr\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is a callback routine supplied to UNDI at undi_start time.\r
+ UNDI call this routine when it wants synchronize the virtual buffer contents\r
+ with the mapped buffer contents. The virtual and mapped buffers need not\r
+ correspond to the same physical memory (especially if the virtual address is\r
+ > 4GB). Depending on the direction for which the buffer is mapped, undi will\r
+ need to synchronize their contents whenever it writes to/reads from the buffer\r
+ using either the cpu address or the device address.\r
+\r
+ EFI does not provide a sync call, since virt=physical, we sould just do\r
+ the synchronization ourself here!\r
+\r
+Arguments:\r
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store\r
+ Undi interface context (Undi does not read or write this variable)\r
+ CpuAddr - Virtual address that was mapped!\r
+ NumBytes - size of memory mapped\r
+ Direction- direction of data flow for this memory's usage:\r
+ cpu->device, device->cpu or both ways\r
+ DeviceAddr - the mapped device address\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+ if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {\r
+ return ;\r
+\r
+ }\r
+\r
+ switch (Direction) {\r
+ case FROM_DEVICE:\r
+ CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);\r
+ break;\r
+\r
+ case TO_DEVICE:\r
+ CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);\r
+ break;\r
+ }\r
+\r
+ return ;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ get_status.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-03 M(f)J Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+STATIC\r
+/**\r
+ this routine calls undi to get the status of the interrupts, get the list of\r
+ transmit buffers that completed transmitting!\r
+\r
+ @param snp pointer to snp driver structure\r
+ @param InterruptStatusPtr a non null pointer gets the interrupt status\r
+ @param TransmitBufferListPtrs a non null ointer gets the list of pointers of\r
+ previously transmitted buffers whose\r
+ transmission was completed asynchrnously.\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_getstatus (\r
+ SNP_DRIVER *snp,\r
+ UINT32 *InterruptStatusPtr,\r
+ VOID **TransmitBufferListPtr\r
+ )\r
+{\r
+ PXE_DB_GET_STATUS *db;\r
+ UINT16 InterruptFlags;\r
+ UINT64 TempData;\r
+\r
+ db = snp->db;\r
+ snp->cdb.OpCode = PXE_OPCODE_GET_STATUS;\r
+\r
+ snp->cdb.OpFlags = 0;\r
+\r
+ if (TransmitBufferListPtr != NULL) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS;\r
+ }\r
+\r
+ if (InterruptStatusPtr != NULL) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_GET_INTERRUPT_STATUS;\r
+ }\r
+\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+\r
+ //\r
+ // size DB for return of one buffer\r
+ //\r
+ snp->cdb.DBsize = (UINT16) (((UINT16) (sizeof (PXE_DB_GET_STATUS)) - (UINT16) (sizeof db->TxBuffer)) + (UINT16) (sizeof db->TxBuffer[0]));\r
+\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.get_status() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != EFI_SUCCESS) {\r
+ DEBUG (\r
+ (EFI_D_NET,\r
+ "\nsnp->undi.get_status() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatFlags)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // report the values back..\r
+ //\r
+ if (InterruptStatusPtr != NULL) {\r
+ InterruptFlags = (UINT16) (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK);\r
+\r
+ *InterruptStatusPtr = 0;\r
+\r
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_RECEIVE) {\r
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;\r
+ }\r
+\r
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_TRANSMIT) {\r
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;\r
+ }\r
+\r
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_COMMAND) {\r
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;\r
+ }\r
+\r
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_SOFTWARE) {\r
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;\r
+ }\r
+\r
+ }\r
+\r
+ if (TransmitBufferListPtr != NULL) {\r
+ *TransmitBufferListPtr =\r
+ (\r
+ (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) ||\r
+ (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY)\r
+ ) ? 0 : (VOID *) (UINTN) db->TxBuffer[0];\r
+\r
+ TempData = (UINT64) (UINTN) (*TransmitBufferListPtr);\r
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {\r
+ del_v2p ((VOID *) (UINTN) (db->TxBuffer[0]));\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for getting the status\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ calls the pxe_getstatus routine to actually get the undi status\r
+\r
+ @param this context pointer\r
+ @param InterruptStatusPtr a non null pointer gets the interrupt status\r
+ @param TransmitBufferListPtrs a non null ointer gets the list of pointers of\r
+ previously transmitted buffers whose\r
+ transmission was completed asynchrnously.\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_get_status (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+ OUT UINT32 *InterruptStatusPtr OPTIONAL,\r
+ OUT VOID **TransmitBufferListPtr OPTIONAL\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (InterruptStatusPtr == NULL && TransmitBufferListPtr == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ if (snp == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = pxe_getstatus (snp, InterruptStatusPtr, TransmitBufferListPtr);\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ initialize.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-09 M(f)J Genesis.\r
+\r
+**/\r
+\r
+\r
+#include "Snp.h"\r
+\r
+VOID\r
+EFIAPI\r
+SnpWaitForPacketNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *SnpPtr\r
+ );\r
+\r
+\r
+/**\r
+ this routine calls undi to initialize the interface.\r
+\r
+ @param snp pointer to snp driver structure\r
+ @param CableDetectFlag Do/don't detect the cable (depending on what undi\r
+ supports)\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_init (\r
+ SNP_DRIVER *snp,\r
+ UINT16 CableDetectFlag\r
+ )\r
+{\r
+ PXE_CPB_INITIALIZE *cpb;\r
+ VOID *addr;\r
+ EFI_STATUS Status;\r
+\r
+ cpb = snp->cpb;\r
+ if (snp->tx_rx_bufsize != 0) {\r
+ Status = snp->IoFncs->AllocateBuffer (\r
+ snp->IoFncs,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ SNP_MEM_PAGES (snp->tx_rx_bufsize),\r
+ &addr,\r
+ 0\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->pxe_init() AllocateBuffer %xh (%r)\n",\r
+ Status,\r
+ Status)\r
+ );\r
+\r
+ return Status;\r
+ }\r
+\r
+ ASSERT (addr);\r
+\r
+ snp->tx_rx_buffer = addr;\r
+ }\r
+\r
+ cpb->MemoryAddr = (UINT64)(UINTN) snp->tx_rx_buffer;\r
+\r
+ cpb->MemoryLength = snp->tx_rx_bufsize;\r
+\r
+ //\r
+ // let UNDI decide/detect these values\r
+ //\r
+ cpb->LinkSpeed = 0;\r
+ cpb->TxBufCnt = 0;\r
+ cpb->TxBufSize = 0;\r
+ cpb->RxBufCnt = 0;\r
+ cpb->RxBufSize = 0;\r
+\r
+ cpb->DuplexMode = PXE_DUPLEX_DEFAULT;\r
+\r
+ cpb->LoopBackMode = LOOPBACK_NORMAL;\r
+\r
+ snp->cdb.OpCode = PXE_OPCODE_INITIALIZE;\r
+ snp->cdb.OpFlags = CableDetectFlag;\r
+\r
+ snp->cdb.CPBsize = sizeof (PXE_CPB_INITIALIZE);\r
+ snp->cdb.DBsize = sizeof (PXE_DB_INITIALIZE);\r
+\r
+ snp->cdb.CPBaddr = (UINT64)(UINTN) snp->cpb;\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) snp->db;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.initialize() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode == PXE_STATCODE_SUCCESS) {\r
+ snp->mode.State = EfiSimpleNetworkInitialized;\r
+\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ DEBUG (\r
+ (EFI_D_WARN,\r
+ "\nsnp->undi.initialize() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ if (snp->tx_rx_buffer != NULL) {\r
+ snp->IoFncs->FreeBuffer (\r
+ snp->IoFncs,\r
+ SNP_MEM_PAGES (snp->tx_rx_bufsize),\r
+ (VOID *) snp->tx_rx_buffer\r
+ );\r
+ }\r
+\r
+ snp->tx_rx_buffer = NULL;\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for initializing the interface\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ calls the pxe_initialize routine to actually do the undi initialization\r
+\r
+ @param this context pointer\r
+ @param extra_rx_buffer_size optional parameter, indicates extra space for\r
+ rx_buffers\r
+ @param extra_tx_buffer_size optional parameter, indicates extra space for\r
+ tx_buffers\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_initialize (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,\r
+ IN UINTN extra_rx_buffer_size OPTIONAL,\r
+ IN UINTN extra_tx_buffer_size OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS EfiStatus;\r
+ SNP_DRIVER *snp;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ //\r
+ //\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ if (snp == NULL) {\r
+ EfiStatus = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkStarted:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ EfiStatus = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ EfiStatus = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EfiStatus = gBS->CreateEvent (\r
+ EVT_NOTIFY_WAIT,\r
+ TPL_NOTIFY,\r
+ &SnpWaitForPacketNotify,\r
+ snp,\r
+ &snp->snp.WaitForPacket\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ snp->snp.WaitForPacket = NULL;\r
+ EfiStatus = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ snp->mode.MCastFilterCount = 0;\r
+ snp->mode.ReceiveFilterSetting = 0;\r
+ ZeroMem (snp->mode.MCastFilter, sizeof snp->mode.MCastFilter);\r
+ CopyMem (\r
+ &snp->mode.CurrentAddress,\r
+ &snp->mode.PermanentAddress,\r
+ sizeof (EFI_MAC_ADDRESS)\r
+ );\r
+\r
+ //\r
+ // Compute tx/rx buffer sizes based on UNDI init info and parameters.\r
+ //\r
+ snp->tx_rx_bufsize = (UINT32) (snp->init_info.MemoryRequired + extra_rx_buffer_size + extra_tx_buffer_size);\r
+\r
+ if (snp->mode.MediaPresentSupported) {\r
+ if (pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) == EFI_SUCCESS) {\r
+ snp->mode.MediaPresent = TRUE;\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+\r
+ snp->mode.MediaPresent = FALSE;\r
+\r
+ EfiStatus = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ gBS->CloseEvent (snp->snp.WaitForPacket);\r
+ }\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EfiStatus;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ mcast_ip_to_mac.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-17 M(f)J Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+/**\r
+ this routine calls undi to convert an multicast IP address to a MAC address\r
+\r
+ @param snp pointer to snp driver structure\r
+ @param IPv6 flag to indicate if this is an ipv6 address\r
+ @param IP multicast IP address\r
+ @param MAC pointer to hold the return MAC address\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_ip2mac (\r
+ IN SNP_DRIVER *snp,\r
+ IN BOOLEAN IPv6,\r
+ IN EFI_IP_ADDRESS *IP,\r
+ IN OUT EFI_MAC_ADDRESS *MAC\r
+ )\r
+{\r
+ PXE_CPB_MCAST_IP_TO_MAC *cpb;\r
+ PXE_DB_MCAST_IP_TO_MAC *db;\r
+\r
+ cpb = snp->cpb;\r
+ db = snp->db;\r
+ snp->cdb.OpCode = PXE_OPCODE_MCAST_IP_TO_MAC;\r
+ snp->cdb.OpFlags = (UINT16) (IPv6 ? PXE_OPFLAGS_MCAST_IPV6_TO_MAC : PXE_OPFLAGS_MCAST_IPV4_TO_MAC);\r
+ snp->cdb.CPBsize = sizeof (PXE_CPB_MCAST_IP_TO_MAC);\r
+ snp->cdb.DBsize = sizeof (PXE_DB_MCAST_IP_TO_MAC);\r
+\r
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ CopyMem (&cpb->IP, IP, sizeof (PXE_IP_ADDR));\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.mcast_ip_to_mac() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ switch (snp->cdb.StatCode) {\r
+ case PXE_STATCODE_SUCCESS:\r
+ break;\r
+\r
+ case PXE_STATCODE_INVALID_CPB:\r
+ return EFI_INVALID_PARAMETER;\r
+\r
+ case PXE_STATCODE_UNSUPPORTED:\r
+ DEBUG (\r
+ (EFI_D_NET,\r
+ "\nsnp->undi.mcast_ip_to_mac() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+ return EFI_UNSUPPORTED;\r
+\r
+ default:\r
+ //\r
+ // UNDI command failed. Return EFI_DEVICE_ERROR\r
+ // to caller.\r
+ //\r
+ DEBUG (\r
+ (EFI_D_NET,\r
+ "\nsnp->undi.mcast_ip_to_mac() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CopyMem (MAC, &db->MAC, sizeof (PXE_MAC_ADDR));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for converting a multicast IP address to\r
+ a MAC address.\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ calls the pxe_ip2mac routine to actually do the conversion\r
+\r
+ @param this context pointer\r
+ @param IPv6 flag to indicate if this is an ipv6 address\r
+ @param IP multicast IP address\r
+ @param MAC pointer to hold the return MAC address\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_mcast_ip_to_mac (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,\r
+ IN BOOLEAN IPv6,\r
+ IN EFI_IP_ADDRESS *IP,\r
+ OUT EFI_MAC_ADDRESS *MAC\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Get pointer to SNP driver instance for *this.\r
+ //\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (IP == NULL || MAC == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = pxe_ip2mac (snp, IPv6, IP, MAC);\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ nvdata.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-03 M(f)J Genesis.\r
+\r
+**/\r
+\r
+#include "snp.h"\r
+\r
+\r
+/**\r
+ This routine calls Undi to read the desired number of eeprom bytes.\r
+\r
+ @param snp pointer to the snp driver structure\r
+ @param RegOffset eeprom register value relative to the base address\r
+ @param NumBytes number of bytes to read\r
+ @param BufferPtr pointer where to read into\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_nvdata_read (\r
+ IN SNP_DRIVER *snp,\r
+ IN UINTN RegOffset,\r
+ IN UINTN NumBytes,\r
+ IN OUT VOID *BufferPtr\r
+ )\r
+{\r
+ PXE_DB_NVDATA *db;\r
+\r
+ db = snp->db;\r
+ snp->cdb.OpCode = PXE_OPCODE_NVDATA;\r
+\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_NVDATA_READ;\r
+\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+\r
+ snp->cdb.DBsize = sizeof (PXE_DB_NVDATA);\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.nvdata () "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ switch (snp->cdb.StatCode) {\r
+ case PXE_STATCODE_SUCCESS:\r
+ break;\r
+\r
+ case PXE_STATCODE_UNSUPPORTED:\r
+ DEBUG (\r
+ (EFI_D_NET,\r
+ "\nsnp->undi.nvdata() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return EFI_UNSUPPORTED;\r
+\r
+ default:\r
+ DEBUG (\r
+ (EFI_D_NET,\r
+ "\nsnp->undi.nvdata() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CopyMem (BufferPtr, db->Data.Byte + RegOffset, NumBytes);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This is an interface call provided by SNP.\r
+ It does the basic checking on the input parameters and retrieves snp structure\r
+ and then calls the read_nvdata() call which does the actual reading\r
+\r
+ @param this context pointer\r
+ @param ReadOrWrite true for reading and false for writing\r
+ @param RegOffset eeprom register relative to the base\r
+ @param NumBytes how many bytes to read\r
+ @param BufferPtr address of memory to read into\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_nvdata (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,\r
+ IN BOOLEAN ReadOrWrite,\r
+ IN UINTN RegOffset,\r
+ IN UINTN NumBytes,\r
+ IN OUT VOID *BufferPtr\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Get pointer to SNP driver instance for *this.\r
+ //\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ //\r
+ // Return error if the SNP is not initialized.\r
+ //\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Return error if non-volatile memory variables are not valid.\r
+ //\r
+ if (snp->mode.NvRamSize == 0 || snp->mode.NvRamAccessSize == 0) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Check for invalid parameter combinations.\r
+ //\r
+ if ((NumBytes == 0) ||\r
+ (BufferPtr == NULL) ||\r
+ (RegOffset >= snp->mode.NvRamSize) ||\r
+ (RegOffset + NumBytes > snp->mode.NvRamSize) ||\r
+ (NumBytes % snp->mode.NvRamAccessSize != 0) ||\r
+ (RegOffset % snp->mode.NvRamAccessSize != 0)\r
+ ) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // check the implementation flags of undi if we can write the nvdata!\r
+ //\r
+ if (!ReadOrWrite) {\r
+ Status = EFI_UNSUPPORTED;\r
+ } else {\r
+ Status = pxe_nvdata_read (snp, RegOffset, NumBytes, BufferPtr);\r
+ }\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ receive.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-03 M(f)J Genesis.\r
+\r
+**/\r
+\r
+\r
+#include "Snp.h"\r
+\r
+/**\r
+ this routine calls undi to receive a packet and fills in the data in the\r
+ input pointers!\r
+\r
+ @param snp pointer to snp driver structure\r
+ @param BufferPtr pointer to the memory for the received data\r
+ @param BuffSizePtr is a pointer to the length of the buffer on entry and\r
+ contains the length of the received data on return\r
+ @param HeaderSizePtr pointer to the header portion of the data received.\r
+ @param SourceAddrPtr optional parameter, is a pointer to contain the\r
+ source ethernet address on return\r
+ @param DestinationAddrPtr optional parameter, is a pointer to contain the\r
+ destination ethernet address on return\r
+ @param ProtocolPtr optional parameter, is a pointer to contain the\r
+ protocol type from the ethernet header on return\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_receive (\r
+ SNP_DRIVER *snp,\r
+ VOID *BufferPtr,\r
+ UINTN *BuffSizePtr,\r
+ UINTN *HeaderSizePtr,\r
+ EFI_MAC_ADDRESS *SourceAddrPtr,\r
+ EFI_MAC_ADDRESS *DestinationAddrPtr,\r
+ UINT16 *ProtocolPtr\r
+ )\r
+{\r
+ PXE_CPB_RECEIVE *cpb;\r
+ PXE_DB_RECEIVE *db;\r
+ UINTN buf_size;\r
+ UINT64 TempData;\r
+\r
+ cpb = snp->cpb;\r
+ db = snp->db;\r
+ buf_size = *BuffSizePtr;\r
+ //\r
+ // IMPORTANT NOTE:\r
+ // In case of the older 3.0 UNDI, if the input buffer address is beyond 4GB,\r
+ // DO NOT call the map function on the given buffer, instead use\r
+ // a global buffer. The reason is that UNDI3.0 has some unnecessary check of\r
+ // making sure that all the addresses (whether or not they will be given\r
+ // to the NIC ) supplied to it are below 4GB. It may or may not use\r
+ // the mapped address after all (like in case of CPB and DB)!\r
+ // Instead of using the global buffer whose address is allocated within the\r
+ // 2GB limit if I start mapping the given buffer we lose the data, here is\r
+ // why!!!\r
+ // if our address is > 4GB, the map call creates another buffer below 2GB and\r
+ // copies data to/from the original buffer to the mapped buffer either at\r
+ // map time or unmap time depending on the map direction.\r
+ // UNDI will not complain since we already mapped the buffer to be\r
+ // within the 2GB limit but will not use (I know undi) the mapped address\r
+ // since it does not give the user buffers to the NIC's receive unit,\r
+ // It just copies the received packet into the user buffer using the virtual\r
+ // (CPU) address rather than the mapped (device or physical) address.\r
+ // When the UNDI call returns, if we then unmap the buffer, we will lose\r
+ // the contents because unmap copies the contents of the mapped buffer into\r
+ // the original buffer (since the direction is FROM_DEVICE) !!!\r
+ //\r
+ // this is not a problem in Undi 3.1 because this undi uses it's map callback\r
+ // routine to map a cpu address to device address and it does it only if\r
+ // it is giving the address to the device and unmaps it before using the cpu\r
+ // address!\r
+ //\r
+ TempData = (UINT64) (UINTN) BufferPtr;\r
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {\r
+ cpb->BufferAddr = (UINT64)(UINTN) snp->receive_buf;\r
+ cpb->BufferLen = (UINT32) (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
+ } else {\r
+ cpb->BufferAddr = (UINT64)(UINTN) BufferPtr;\r
+ cpb->BufferLen = (UINT32) *BuffSizePtr;\r
+ }\r
+\r
+ cpb->reserved = 0;\r
+\r
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
+\r
+ snp->cdb.CPBsize = sizeof (PXE_CPB_RECEIVE);\r
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;\r
+\r
+ snp->cdb.DBsize = sizeof (PXE_DB_RECEIVE);\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "\nsnp->undi.receive () "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ switch (snp->cdb.StatCode) {\r
+ case PXE_STATCODE_SUCCESS:\r
+ break;\r
+\r
+ case PXE_STATCODE_NO_DATA:\r
+ DEBUG (\r
+ (EFI_D_INFO,\r
+ "\nsnp->undi.receive () %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return EFI_NOT_READY;\r
+\r
+ default:\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.receive() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ *BuffSizePtr = db->FrameLen;\r
+\r
+ if (HeaderSizePtr != NULL) {\r
+ *HeaderSizePtr = db->MediaHeaderLen;\r
+ }\r
+\r
+ if (SourceAddrPtr != NULL) {\r
+ CopyMem (SourceAddrPtr, &db->SrcAddr, snp->mode.HwAddressSize);\r
+ }\r
+\r
+ if (DestinationAddrPtr != NULL) {\r
+ CopyMem (DestinationAddrPtr, &db->DestAddr, snp->mode.HwAddressSize);\r
+ }\r
+\r
+ if (ProtocolPtr != NULL) {\r
+ *ProtocolPtr = (UINT16) PXE_SWAP_UINT16 (db->Protocol); /* we need to do the byte swapping */\r
+ }\r
+\r
+ TempData = (UINT64) (UINTN) BufferPtr;\r
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {\r
+ CopyMem (BufferPtr, snp->receive_buf, snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
+ }\r
+\r
+ return (*BuffSizePtr <= buf_size) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;\r
+}\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for receiving network data.\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ calls the pxe_receive routine to actually do the receive!\r
+\r
+ @param this context pointer\r
+ @param HeaderSizePtr optional parameter and is a pointer to the header\r
+ portion of the data received.\r
+ @param BuffSizePtr is a pointer to the length of the buffer on entry and\r
+ contains the length of the received data on return\r
+ @param BufferPtr pointer to the memory for the received data\r
+ @param SourceAddrPtr optional parameter, is a pointer to contain the\r
+ source ethernet address on return\r
+ @param DestinationAddrPtr optional parameter, is a pointer to contain the\r
+ destination ethernet address on return\r
+ @param ProtocolPtr optional parameter, is a pointer to contain the\r
+ protocol type from the ethernet header on return\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_receive (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+ OUT UINTN *HeaderSizePtr OPTIONAL,\r
+ IN OUT UINTN *BuffSizePtr,\r
+ OUT VOID *BufferPtr,\r
+ OUT EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL,\r
+ OUT EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL,\r
+ OUT UINT16 *ProtocolPtr OPTIONAL\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if ((BuffSizePtr == NULL) || (BufferPtr == NULL)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (!snp->mode.ReceiveFilterSetting) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = pxe_receive (\r
+ snp,\r
+ BufferPtr,\r
+ BuffSizePtr,\r
+ HeaderSizePtr,\r
+ SourceAddrPtr,\r
+ DestinationAddrPtr,\r
+ ProtocolPtr\r
+ );\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ receive_filters.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-17 M(f)J Genesis.\r
+\r
+**/\r
+\r
+\r
+\r
+#include "Snp.h"\r
+\r
+/**\r
+ this routine calls undi to enable the receive filters.\r
+\r
+ @param snp pointer to snp driver structure\r
+ @param EnableFlags bit mask for enabling the receive filters\r
+ @param MCastAddressCount multicast address count for a new multicast address\r
+ list\r
+ @param MCastAddressList list of new multicast addresses\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_rcvfilter_enable (\r
+ SNP_DRIVER *snp,\r
+ UINT32 EnableFlags,\r
+ UINTN MCastAddressCount,\r
+ EFI_MAC_ADDRESS *MCastAddressList\r
+ )\r
+{\r
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE;\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;\r
+ }\r
+\r
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;\r
+ }\r
+\r
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;\r
+ }\r
+\r
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;\r
+ }\r
+\r
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;\r
+ }\r
+\r
+ if (MCastAddressCount != 0) {\r
+ snp->cdb.CPBsize = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS));\r
+ snp->cdb.CPBaddr = (UINT64)(UINTN) snp->cpb;\r
+ CopyMem (snp->cpb, MCastAddressList, snp->cdb.CPBsize);\r
+ }\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != EFI_SUCCESS) {\r
+ //\r
+ // UNDI command failed. Return UNDI status to caller.\r
+ //\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.receive_filters() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ switch (snp->cdb.StatCode) {\r
+ case PXE_STATCODE_INVALID_CDB:\r
+ case PXE_STATCODE_INVALID_CPB:\r
+ case PXE_STATCODE_INVALID_PARAMETER:\r
+ return EFI_INVALID_PARAMETER;\r
+\r
+ case PXE_STATCODE_UNSUPPORTED:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ this routine calls undi to disable the receive filters.\r
+\r
+ @param snp pointer to snp driver structure\r
+ @param DisableFlags bit mask for disabling the receive filters\r
+ @param ResetMCastList boolean flag to reset/delete the multicast filter list\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_rcvfilter_disable (\r
+ SNP_DRIVER *snp,\r
+ UINT32 DisableFlags,\r
+ BOOLEAN ResetMCastList\r
+ )\r
+{\r
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ snp->cdb.OpFlags = (UINT16) (DisableFlags ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED);\r
+\r
+ if (ResetMCastList) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST;\r
+ }\r
+\r
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;\r
+ }\r
+\r
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;\r
+ }\r
+\r
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;\r
+ }\r
+\r
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;\r
+ }\r
+\r
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {\r
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;\r
+ }\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != EFI_SUCCESS) {\r
+ //\r
+ // UNDI command failed. Return UNDI status to caller.\r
+ //\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.receive_filters() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ this routine calls undi to read the receive filters.\r
+\r
+ @param snp pointer to snp driver structure\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_rcvfilter_read (\r
+ SNP_DRIVER *snp\r
+ )\r
+{\r
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_READ;\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.DBsize = (UINT16) (snp->mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS));\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ if (snp->cdb.DBsize == 0) {\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) NULL;\r
+ } else {\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) snp->db;\r
+ ZeroMem (snp->db, snp->cdb.DBsize);\r
+ }\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != EFI_SUCCESS) {\r
+ //\r
+ // UNDI command failed. Return UNDI status to caller.\r
+ //\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.receive_filters() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Convert UNDI32 StatFlags to EFI SNP filter flags.\r
+ //\r
+ snp->mode.ReceiveFilterSetting = 0;\r
+\r
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) {\r
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
+ }\r
+\r
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) {\r
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
+ }\r
+\r
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) {\r
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
+ }\r
+\r
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) {\r
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+ }\r
+\r
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {\r
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
+ }\r
+\r
+ CopyMem (snp->mode.MCastFilter, snp->db, snp->cdb.DBsize);\r
+\r
+ //\r
+ // Count number of active entries in multicast filter list.\r
+ //\r
+ {\r
+ EFI_MAC_ADDRESS ZeroMacAddr;\r
+\r
+ SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0);\r
+\r
+ for (snp->mode.MCastFilterCount = 0;\r
+ snp->mode.MCastFilterCount < snp->mode.MaxMCastFilterCount;\r
+ snp->mode.MCastFilterCount++\r
+ ) {\r
+ if (CompareMem (\r
+ &snp->mode.MCastFilter[snp->mode.MCastFilterCount],\r
+ &ZeroMacAddr,\r
+ sizeof ZeroMacAddr\r
+ ) == 0) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for reading/enabling/disabling the\r
+ receive filters.\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ checks the parameter validity, calls one of the above routines to actually\r
+ do the work\r
+\r
+ @param this context pointer\r
+ @param EnableFlags bit mask for enabling the receive filters\r
+ @param DisableFlags bit mask for disabling the receive filters\r
+ @param ResetMCastList boolean flag to reset/delete the multicast filter list\r
+ @param MCastAddressCount multicast address count for a new multicast address\r
+ list\r
+ @param MCastAddressList list of new multicast addresses\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_receive_filters (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+ IN UINT32 EnableFlags,\r
+ IN UINT32 DisableFlags,\r
+ IN BOOLEAN ResetMCastList,\r
+ IN UINTN MCastAddressCount OPTIONAL,\r
+ IN EFI_MAC_ADDRESS * MCastAddressList OPTIONAL\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // check if we are asked to enable or disable something that the UNDI\r
+ // does not even support!\r
+ //\r
+ if (((EnableFlags &~snp->mode.ReceiveFilterMask) != 0) ||\r
+ ((DisableFlags &~snp->mode.ReceiveFilterMask) != 0)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (ResetMCastList) {\r
+\r
+ DisableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & snp->mode.ReceiveFilterMask;\r
+ MCastAddressCount = 0;\r
+ MCastAddressList = NULL;\r
+ } else {\r
+ if (MCastAddressCount != 0) {\r
+ if ((MCastAddressCount > snp->mode.MaxMCastFilterCount) ||\r
+ (MCastAddressList == NULL)) {\r
+\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (EnableFlags == 0 && DisableFlags == 0 && !ResetMCastList && MCastAddressCount == 0) {\r
+ Status = EFI_SUCCESS;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastAddressCount == 0) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if ((EnableFlags != 0) || (MCastAddressCount != 0)) {\r
+ Status = pxe_rcvfilter_enable (\r
+ snp,\r
+ EnableFlags,\r
+ MCastAddressCount,\r
+ MCastAddressList\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+\r
+ if ((DisableFlags != 0) || ResetMCastList) {\r
+ Status = pxe_rcvfilter_disable (snp, DisableFlags, ResetMCastList);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+\r
+ Status = pxe_rcvfilter_read (snp);\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ reset.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-09 M(f)J Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+ This routine calls undi to reset the nic.\r
+\r
+ @param snp pointer to the snp driver structure\r
+\r
+ @return EFI_SUCCESSFUL for a successful completion\r
+ @return other for failed calls\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_reset (\r
+ SNP_DRIVER *snp\r
+ )\r
+{\r
+ snp->cdb.OpCode = PXE_OPCODE_RESET;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.reset() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+ DEBUG (\r
+ (EFI_D_WARN,\r
+ "\nsnp->undi32.reset() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ //\r
+ // UNDI could not be reset. Return UNDI error.\r
+ //\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for resetting the NIC\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ calls the pxe_reset routine to actually do the reset!\r
+\r
+ @param this context pointer\r
+ @param ExtendedVerification not implemented\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_reset (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Resolve Warning 4 unreferenced parameter problem\r
+ //\r
+ ExtendedVerification = 0;\r
+\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = pxe_reset (snp);\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ shutdown.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-14 M(f)J Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+ this routine calls undi to shut down the interface.\r
+\r
+ @param snp pointer to snp driver structure\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_shutdown (\r
+ IN SNP_DRIVER *snp\r
+ )\r
+{\r
+ snp->cdb.OpCode = PXE_OPCODE_SHUTDOWN;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.shutdown() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+ //\r
+ // UNDI could not be shutdown. Return UNDI error.\r
+ //\r
+ DEBUG ((EFI_D_WARN, "\nsnp->undi.shutdown() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Free allocated memory.\r
+ //\r
+ if (snp->tx_rx_buffer != NULL) {\r
+ snp->IoFncs->FreeBuffer (\r
+ snp->IoFncs,\r
+ SNP_MEM_PAGES (snp->tx_rx_bufsize),\r
+ (VOID *) snp->tx_rx_buffer\r
+ );\r
+ }\r
+\r
+ snp->tx_rx_buffer = NULL;\r
+ snp->tx_rx_bufsize = 0;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for shutting down the interface\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ calls the pxe_shutdown routine to actually do the undi shutdown\r
+\r
+ @param this context pointer\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_shutdown (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ //\r
+ //\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ //\r
+ //\r
+ //\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ Status = pxe_shutdown (snp);\r
+\r
+ snp->mode.State = EfiSimpleNetworkStarted;\r
+ snp->mode.ReceiveFilterSetting = 0;\r
+\r
+ snp->mode.MCastFilterCount = 0;\r
+ snp->mode.ReceiveFilterSetting = 0;\r
+ ZeroMem (snp->mode.MCastFilter, sizeof snp->mode.MCastFilter);\r
+ CopyMem (\r
+ &snp->mode.CurrentAddress,\r
+ &snp->mode.PermanentAddress,\r
+ sizeof (EFI_MAC_ADDRESS)\r
+ );\r
+\r
+ gBS->CloseEvent (snp->snp.WaitForPacket);\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2005, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ snp.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+EFI_STATUS\r
+pxe_start (\r
+ SNP_DRIVER *snp\r
+ );\r
+EFI_STATUS\r
+pxe_stop (\r
+ SNP_DRIVER *snp\r
+ );\r
+EFI_STATUS\r
+pxe_init (\r
+ SNP_DRIVER *snp,\r
+ UINT16 OpFlags\r
+ );\r
+EFI_STATUS\r
+pxe_shutdown (\r
+ SNP_DRIVER *snp\r
+ );\r
+EFI_STATUS\r
+pxe_get_stn_addr (\r
+ SNP_DRIVER *snp\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSnpNiiDriver (\r
+ IN EFI_HANDLE image_handle,\r
+ IN EFI_SYSTEM_TABLE *system_table\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+//\r
+// Simple Network Protocol Driver Global Variables\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL mSimpleNetworkDriverBinding = {\r
+ SimpleNetworkDriverSupported,\r
+ SimpleNetworkDriverStart,\r
+ SimpleNetworkDriverStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+//\r
+// Module global variables needed to support undi 3.0 interface\r
+//\r
+EFI_PCI_IO_PROTOCOL *mPciIoFncs;\r
+struct s_v2p *_v2p = NULL; // undi3.0 map_list head\r
+// End Global variables\r
+//\r
+\r
+/**\r
+ This routine maps the given CPU address to a Device address. It creates a\r
+ an entry in the map list with the virtual and physical addresses and the\r
+ un map cookie.\r
+\r
+ @param v2p pointer to return a map list node pointer.\r
+ @param type the direction in which the data flows from the given\r
+ virtual address device->cpu or cpu->device or both\r
+ ways.\r
+ @param vaddr virtual address (or CPU address) to be mapped\r
+ @param bsize size of the buffer to be mapped.\r
+\r
+ @retval EFI_SUCEESS routine has completed the mapping\r
+ @retval other error as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+add_v2p (\r
+ IN OUT struct s_v2p **v2p,\r
+ EFI_PCI_IO_PROTOCOL_OPERATION type,\r
+ VOID *vaddr,\r
+ UINTN bsize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if ((v2p == NULL) || (vaddr == NULL) || (bsize == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *v2p = AllocatePool (sizeof (struct s_v2p));\r
+ if (*v2p != NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = mPciIoFncs->Map (\r
+ mPciIoFncs,\r
+ type,\r
+ vaddr,\r
+ &bsize,\r
+ &(*v2p)->paddr,\r
+ &(*v2p)->unmap\r
+ );\r
+ if (Status != EFI_SUCCESS) {\r
+ FreePool (*v2p);\r
+ return Status;\r
+ }\r
+ (*v2p)->vaddr = vaddr;\r
+ (*v2p)->bsize = bsize;\r
+ (*v2p)->next = _v2p;\r
+ _v2p = *v2p;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This routine searches the linked list of mapped address nodes (for undi3.0\r
+ interface) to find the node that corresponds to the given virtual address and\r
+ returns a pointer to that node.\r
+\r
+ @param v2p pointer to return a map list node pointer.\r
+ @param vaddr virtual address (or CPU address) to be searched in\r
+ the map list\r
+\r
+ @retval EFI_SUCEESS if a match found!\r
+ @retval Other match not found\r
+\r
+**/\r
+EFI_STATUS\r
+find_v2p (\r
+ struct s_v2p **v2p,\r
+ VOID *vaddr\r
+ )\r
+{\r
+ struct s_v2p *v;\r
+\r
+ if (v2p == NULL || vaddr == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ for (v = _v2p; v != NULL; v = v->next) {\r
+ if (v->vaddr == vaddr) {\r
+ *v2p = v;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ This routine unmaps the given virtual address and frees the memory allocated\r
+ for the map list node corresponding to that address.\r
+\r
+ @param vaddr virtual address (or CPU address) to be unmapped\r
+\r
+ @retval EFI_SUCEESS if successfully unmapped\r
+ @retval Other as indicated by the error\r
+\r
+**/\r
+EFI_STATUS\r
+del_v2p (\r
+ VOID *vaddr\r
+ )\r
+{\r
+ struct s_v2p *v;\r
+ struct s_v2p *t;\r
+ EFI_STATUS Status;\r
+\r
+ if (vaddr == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (_v2p == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Is our node at the head of the list??\r
+ //\r
+ if ((v = _v2p)->vaddr == vaddr) {\r
+ _v2p = _v2p->next;\r
+\r
+ Status = mPciIoFncs->Unmap (mPciIoFncs, v->unmap);\r
+\r
+ FreePool (v);\r
+\r
+ if (Status) {\r
+ DEBUG ((EFI_D_ERROR, "Unmap failed with status = %x\n", Status));\r
+ }\r
+ return Status;\r
+ }\r
+\r
+ for (; v->next != NULL; v = t) {\r
+ if ((t = v->next)->vaddr == vaddr) {\r
+ v->next = t->next;\r
+ Status = mPciIoFncs->Unmap (mPciIoFncs, t->unmap);\r
+ FreePool (t);\r
+\r
+ if (Status) {\r
+ DEBUG ((EFI_D_ERROR, "Unmap failed with status = %x\n", Status));\r
+ }\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+issue_hwundi_command (\r
+ UINT64 cdb\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+ DEBUG ((EFI_D_ERROR, "\nissue_hwundi_command() - This should not be called!"));\r
+\r
+ if (cdb == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+\r
+ }\r
+ //\r
+ // %%TBD - For now, nothing is done.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+ Compute 8-bit checksum of a buffer.\r
+\r
+ @param ptr Pointer to buffer.\r
+ @param len Length of buffer in bytes.\r
+\r
+ @return 8-bit checksum of all bytes in buffer.\r
+ @return If ptr is NULL or len is zero, zero is returned.\r
+\r
+**/\r
+STATIC\r
+UINT8\r
+calc_8bit_cksum (\r
+ VOID *ptr,\r
+ UINTN len\r
+ )\r
+{\r
+ UINT8 *bptr;\r
+ UINT8 cksum;\r
+\r
+ bptr = ptr;\r
+ cksum = 0;\r
+\r
+ if (ptr == NULL || len == 0) {\r
+ return 0;\r
+ }\r
+\r
+ while (len--) {\r
+ cksum = (UINT8) (cksum +*bptr++);\r
+ }\r
+\r
+ return cksum;\r
+}\r
+\r
+\r
+/**\r
+ Test to see if this driver supports Controller. Any Controller\r
+ that contains a Nii protocol can be supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;\r
+ PXE_UNDI *pxe;\r
+ BOOLEAN IsUndi31;\r
+\r
+ IsUndi31 = FALSE;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+ (VOID **) &NiiProtocol,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED)\r
+ {\r
+ DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %x\n", Controller));\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ if (!EFI_ERROR (Status))\r
+ {\r
+ DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %x\n", Controller));\r
+ IsUndi31 = TRUE;\r
+ } else {\r
+ //\r
+ // try the older 3.0 driver\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+ (VOID **) &NiiProtocol,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Support(): UNDI3.0 found on handle %x\n", Controller));\r
+ }\r
+ //\r
+ // check the version, we don't want to connect to the undi16\r
+ //\r
+ if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.\r
+ //\r
+ if (NiiProtocol->ID & 0x0F) {\r
+ DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->ID);\r
+\r
+ //\r
+ // Verify !PXE revisions.\r
+ //\r
+ if (pxe->hw.Signature != PXE_ROMID_SIGNATURE) {\r
+ DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ if (pxe->hw.Rev < PXE_ROMID_REV) {\r
+ DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ if (pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {\r
+\r
+ DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+\r
+ } else if (pxe->hw.MajorVer == PXE_ROMID_MAJORVER && pxe->hw.MinorVer < PXE_ROMID_MINORVER) {\r
+ DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Do S/W UNDI specific checks.\r
+ //\r
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {\r
+ if (pxe->sw.EntryPoint < pxe->sw.Len) {\r
+ DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ if (pxe->sw.BusCnt == 0) {\r
+ DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ DEBUG ((EFI_D_INFO, "Support(): supported on %x\n", Controller));\r
+\r
+Done:\r
+ if (IsUndi31) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ } else {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ called for any handle that we said "supported" in the above call!\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to start\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval other This driver failed to start this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;\r
+ EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath;\r
+ EFI_STATUS Status;\r
+ PXE_UNDI *pxe;\r
+ SNP_DRIVER *snp;\r
+ VOID *addr;\r
+ VOID *addrUnmap;\r
+ EFI_PHYSICAL_ADDRESS paddr;\r
+ EFI_HANDLE Handle;\r
+ UINTN Size;\r
+ BOOLEAN UndiNew;\r
+ PXE_PCI_CONFIG_INFO ConfigInfo;\r
+ PCI_TYPE00 *ConfigHeader;\r
+ UINT32 *TempBar;\r
+ UINT8 BarIndex;\r
+ PXE_STATFLAGS InitStatFlags;\r
+\r
+ DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() "));\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &NiiDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->LocateDevicePath (\r
+ &gEfiPciIoProtocolGuid,\r
+ &NiiDevicePath,\r
+ &Handle\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Handle,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &mPciIoFncs,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get the NII interface. look for 3.1 undi first, if it is not there\r
+ // then look for 3.0, validate the interface.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+ (VOID **) &Nii,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // probably not a 3.1 UNDI\r
+ //\r
+ UndiNew = TRUE;\r
+ DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));\r
+\r
+ } else {\r
+ UndiNew = FALSE;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+ (VOID **) &Nii,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Start(): UNDI3.0 found\n"));\r
+ }\r
+\r
+ pxe = (PXE_UNDI *) (UINTN) (Nii->ID);\r
+\r
+ if (calc_8bit_cksum (pxe, pxe->hw.Len) != 0) {\r
+ DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));\r
+ goto NiiError;\r
+ }\r
+\r
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
+ //\r
+ // We can get any packets.\r
+ //\r
+ } else if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
+ //\r
+ // We need to be able to get broadcast packets for DHCP.\r
+ // If we do not have promiscuous support, we must at least have\r
+ // broadcast support or we cannot do DHCP!\r
+ //\r
+ } else {\r
+ DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));\r
+ goto NiiError;\r
+ }\r
+ //\r
+ // OK, we like this UNDI, and we know snp is not already there on this handle\r
+ // Allocate and initialize a new simple network protocol structure.\r
+ //\r
+ Status = mPciIoFncs->AllocateBuffer (\r
+ mPciIoFncs,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
+ &addr,\r
+ 0\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));\r
+ goto NiiError;\r
+ }\r
+\r
+ snp = (SNP_DRIVER *) (UINTN) addr;\r
+\r
+ if (!UndiNew) {\r
+ Size = SNP_MEM_PAGES (sizeof (SNP_DRIVER));\r
+\r
+ Status = mPciIoFncs->Map (\r
+ mPciIoFncs,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ addr,\r
+ &Size,\r
+ &paddr,\r
+ &addrUnmap\r
+ );\r
+\r
+ ASSERT (paddr);\r
+\r
+ DEBUG ((EFI_D_NET, "\nSNP_DRIVER @ %Xh, sizeof(SNP_DRIVER) == %d", addr, sizeof (SNP_DRIVER)));\r
+ snp = (SNP_DRIVER *) (UINTN) paddr;\r
+ snp->SnpDriverUnmap = addrUnmap;\r
+ }\r
+\r
+ ZeroMem (snp, sizeof (SNP_DRIVER));\r
+\r
+ snp->IoFncs = mPciIoFncs;\r
+ snp->IsOldUndi = (BOOLEAN) (!UndiNew);\r
+\r
+ snp->Signature = SNP_DRIVER_SIGNATURE;\r
+\r
+ EfiInitializeLock (&snp->lock, TPL_NOTIFY);\r
+\r
+ snp->snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
+ snp->snp.Start = snp_undi32_start;\r
+ snp->snp.Stop = snp_undi32_stop;\r
+ snp->snp.Initialize = snp_undi32_initialize;\r
+ snp->snp.Reset = snp_undi32_reset;\r
+ snp->snp.Shutdown = snp_undi32_shutdown;\r
+ snp->snp.ReceiveFilters = snp_undi32_receive_filters;\r
+ snp->snp.StationAddress = snp_undi32_station_address;\r
+ snp->snp.Statistics = snp_undi32_statistics;\r
+ snp->snp.MCastIpToMac = snp_undi32_mcast_ip_to_mac;\r
+ snp->snp.NvData = snp_undi32_nvdata;\r
+ snp->snp.GetStatus = snp_undi32_get_status;\r
+ snp->snp.Transmit = snp_undi32_transmit;\r
+ snp->snp.Receive = snp_undi32_receive;\r
+ snp->snp.WaitForPacket = NULL;\r
+\r
+ snp->snp.Mode = &snp->mode;\r
+\r
+ snp->tx_rx_bufsize = 0;\r
+ snp->tx_rx_buffer = NULL;\r
+\r
+ snp->if_num = Nii->IfNum;\r
+\r
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {\r
+ snp->is_swundi = FALSE;\r
+ snp->issue_undi32_command = &issue_hwundi_command;\r
+ } else {\r
+ snp->is_swundi = TRUE;\r
+\r
+ if ((pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {\r
+ snp->issue_undi32_command = (issue_undi32_command) (UINTN) pxe->sw.EntryPoint;\r
+ } else {\r
+ snp->issue_undi32_command = (issue_undi32_command) (UINTN) ((UINT8) (UINTN) pxe + pxe->sw.EntryPoint);\r
+ }\r
+ }\r
+ //\r
+ // Allocate a global CPB and DB buffer for this UNDI interface.\r
+ // we do this because:\r
+ //\r
+ // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be\r
+ // within 2GB limit, create them here and map them so that when undi calls\r
+ // v2p callback to check if the physical address is < 2gb, we will pass.\r
+ //\r
+ // -This is not a requirement for 3.1 or later UNDIs but the code looks\r
+ // simpler if we use the same cpb, db variables for both old and new undi\r
+ // interfaces from all the SNP interface calls (we don't map the buffers\r
+ // for the newer undi interfaces though)\r
+ // .\r
+ // -it is OK to allocate one global set of CPB, DB pair for each UNDI\r
+ // interface as EFI does not multi-task and so SNP will not be re-entered!\r
+ //\r
+ Status = mPciIoFncs->AllocateBuffer (\r
+ mPciIoFncs,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ SNP_MEM_PAGES (4096),\r
+ &addr,\r
+ 0\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));\r
+ goto Error_DeleteSNP;\r
+ }\r
+\r
+ if (snp->IsOldUndi) {\r
+ Size = SNP_MEM_PAGES (4096);\r
+\r
+ Status = mPciIoFncs->Map (\r
+ mPciIoFncs,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ addr,\r
+ &Size,\r
+ &paddr,\r
+ &snp->CpbUnmap\r
+ );\r
+\r
+ ASSERT (paddr);\r
+\r
+ snp->cpb = (VOID *) (UINTN) paddr;\r
+ snp->db = (VOID *) ((UINTN) paddr + 2048);\r
+ } else {\r
+ snp->cpb = (VOID *) (UINTN) addr;\r
+ snp->db = (VOID *) ((UINTN) addr + 2048);\r
+ }\r
+ //\r
+ // pxe_start call is going to give the callback functions to UNDI, these callback\r
+ // functions use the BarIndex values from the snp structure, so these must be initialized\r
+ // with default values before doing a pxe_start. The correct values can be obtained after\r
+ // getting the config information from UNDI\r
+ //\r
+ snp->MemoryBarIndex = 0;\r
+ snp->IoBarIndex = 1;\r
+\r
+ //\r
+ // we need the undi init information many times in this snp code, just get it\r
+ // once here and store it in the snp driver structure. to get Init Info\r
+ // from UNDI we have to start undi first.\r
+ //\r
+ Status = pxe_start (snp);\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ goto Error_DeleteCPBDB;\r
+ }\r
+\r
+ snp->cdb.OpCode = PXE_OPCODE_GET_INIT_INFO;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
+\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED;\r
+\r
+ snp->cdb.DBsize = sizeof snp->init_info;\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) &snp->init_info;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.get_init_info() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ //\r
+ // Save the INIT Stat Code...\r
+ //\r
+ InitStatFlags = snp->cdb.StatFlags;\r
+\r
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.init_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r
+ pxe_stop (snp);\r
+ goto Error_DeleteCPBDB;\r
+ }\r
+\r
+ snp->cdb.OpCode = PXE_OPCODE_GET_CONFIG_INFO;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
+\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED;\r
+\r
+ snp->cdb.DBsize = sizeof ConfigInfo;\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) &ConfigInfo;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.get_config_info() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.config_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r
+ pxe_stop (snp);\r
+ goto Error_DeleteCPBDB;\r
+ }\r
+ //\r
+ // Find the correct BAR to do IO.\r
+ //\r
+ //\r
+ // Enumerate through the PCI BARs for the device to determine which one is\r
+ // the IO BAR. Save the index of the BAR into the adapter info structure.\r
+ // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped\r
+ //\r
+ ConfigHeader = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];\r
+ TempBar = (UINT32 *) &ConfigHeader->Device.Bar[0];\r
+ for (BarIndex = 0; BarIndex <= 5; BarIndex++) {\r
+ if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {\r
+ //\r
+ // This is a 64-bit memory bar, skip this and the\r
+ // next bar as well.\r
+ //\r
+ TempBar++;\r
+ }\r
+\r
+ if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {\r
+ snp->IoBarIndex = BarIndex;\r
+ break;\r
+ }\r
+\r
+ TempBar++;\r
+ }\r
+\r
+ //\r
+ // We allocate 2 more global buffers for undi 3.0 interface. We use these\r
+ // buffers to pass to undi when the user buffers are beyond 4GB.\r
+ // UNDI 3.0 wants all the addresses passed to it to be\r
+ // within 2GB limit, create them here and map them so that when undi calls\r
+ // v2p callback to check if the physical address is < 2gb, we will pass.\r
+ //\r
+ // For 3.1 and later UNDIs, we do not do this because undi is\r
+ // going to call the map() callback if and only if it wants to use the\r
+ // device address for any address it receives.\r
+ //\r
+ if (snp->IsOldUndi) {\r
+ //\r
+ // buffer for receive\r
+ //\r
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
+ Status = mPciIoFncs->AllocateBuffer (\r
+ mPciIoFncs,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ Size,\r
+ &addr,\r
+ 0\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ DEBUG ((EFI_D_ERROR, "\nCould not allocate receive buffer.\n"));\r
+ goto Error_DeleteCPBDB;\r
+ }\r
+\r
+ Status = mPciIoFncs->Map (\r
+ mPciIoFncs,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ addr,\r
+ &Size,\r
+ &paddr,\r
+ &snp->ReceiveBufUnmap\r
+ );\r
+\r
+ ASSERT (paddr);\r
+\r
+ snp->receive_buf = (UINT8 *) (UINTN) paddr;\r
+\r
+ //\r
+ // buffer for fill_header\r
+ //\r
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen);\r
+ Status = mPciIoFncs->AllocateBuffer (\r
+ mPciIoFncs,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ Size,\r
+ &addr,\r
+ 0\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ DEBUG ((EFI_D_ERROR, "\nCould not allocate fill_header buffer.\n"));\r
+ goto Error_DeleteRCVBuf;\r
+ }\r
+\r
+ Status = mPciIoFncs->Map (\r
+ mPciIoFncs,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ addr,\r
+ &Size,\r
+ &paddr,\r
+ &snp->FillHdrBufUnmap\r
+ );\r
+\r
+ ASSERT (paddr);\r
+ snp->fill_hdr_buf = (UINT8 *) (UINTN) paddr;\r
+ }\r
+ //\r
+ // Initialize simple network protocol mode structure\r
+ //\r
+ snp->mode.State = EfiSimpleNetworkStopped;\r
+ snp->mode.HwAddressSize = snp->init_info.HWaddrLen;\r
+ snp->mode.MediaHeaderSize = snp->init_info.MediaHeaderLen;\r
+ snp->mode.MaxPacketSize = snp->init_info.FrameDataLen;\r
+ snp->mode.NvRamAccessSize = snp->init_info.NvWidth;\r
+ snp->mode.NvRamSize = snp->init_info.NvCount * snp->mode.NvRamAccessSize;\r
+ snp->mode.IfType = snp->init_info.IFtype;\r
+ snp->mode.MaxMCastFilterCount = snp->init_info.MCastFilterCnt;\r
+ snp->mode.MCastFilterCount = 0;\r
+\r
+ switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {\r
+ case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:\r
+ snp->mode.MediaPresentSupported = TRUE;\r
+ break;\r
+\r
+ case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:\r
+ default:\r
+ snp->mode.MediaPresentSupported = FALSE;\r
+ }\r
+\r
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {\r
+ snp->mode.MacAddressChangeable = TRUE;\r
+ } else {\r
+ snp->mode.MacAddressChangeable = FALSE;\r
+ }\r
+\r
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {\r
+ snp->mode.MultipleTxSupported = TRUE;\r
+ } else {\r
+ snp->mode.MultipleTxSupported = FALSE;\r
+ }\r
+\r
+ snp->mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
+\r
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {\r
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+\r
+ }\r
+\r
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
+\r
+ }\r
+\r
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
+\r
+ }\r
+\r
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {\r
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
+\r
+ }\r
+\r
+ if (pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) {\r
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+\r
+ }\r
+\r
+ snp->mode.ReceiveFilterSetting = 0;\r
+\r
+ //\r
+ // need to get the station address to save in the mode structure. we need to\r
+ // initialize the UNDI first for this.\r
+ //\r
+ snp->tx_rx_bufsize = snp->init_info.MemoryRequired;\r
+ Status = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);\r
+\r
+ if (Status) {\r
+ pxe_stop (snp);\r
+ goto Error_DeleteHdrBuf;\r
+ }\r
+\r
+ Status = pxe_get_stn_addr (snp);\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ DEBUG ((EFI_D_ERROR, "\nsnp->undi.get_station_addr() failed.\n"));\r
+ pxe_shutdown (snp);\r
+ pxe_stop (snp);\r
+ goto Error_DeleteHdrBuf;\r
+ }\r
+\r
+ snp->mode.MediaPresent = FALSE;\r
+\r
+ //\r
+ // We should not leave UNDI started and initialized here. this DriverStart()\r
+ // routine must only find and attach the SNP interface to UNDI layer that it\r
+ // finds on the given handle!\r
+ // The UNDI layer will be started when upper layers call snp->start.\r
+ // How ever, this DriverStart() must fill up the snp mode structure which\r
+ // contains the MAC address of the NIC. For this reason we started and\r
+ // initialized UNDI here, now we are done, do a shutdown and stop of the\r
+ // UNDI interface!\r
+ //\r
+ pxe_shutdown (snp);\r
+ pxe_stop (snp);\r
+\r
+ //\r
+ // add SNP to the undi handle\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Controller,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &(snp->snp)\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+Error_DeleteHdrBuf:\r
+ if (snp->IsOldUndi) {\r
+ Status = mPciIoFncs->Unmap (\r
+ mPciIoFncs,\r
+ snp->FillHdrBufUnmap\r
+ );\r
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen);\r
+ mPciIoFncs->FreeBuffer (\r
+ mPciIoFncs,\r
+ Size,\r
+ snp->fill_hdr_buf\r
+ );\r
+ }\r
+\r
+Error_DeleteRCVBuf:\r
+ if (snp->IsOldUndi) {\r
+ Status = mPciIoFncs->Unmap (\r
+ mPciIoFncs,\r
+ snp->ReceiveBufUnmap\r
+ );\r
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
+ mPciIoFncs->FreeBuffer (\r
+ mPciIoFncs,\r
+ Size,\r
+ snp->receive_buf\r
+ );\r
+\r
+ }\r
+\r
+Error_DeleteCPBDB:\r
+ if (snp->IsOldUndi) {\r
+ Status = mPciIoFncs->Unmap (\r
+ mPciIoFncs,\r
+ snp->CpbUnmap\r
+ );\r
+ }\r
+\r
+ Status = mPciIoFncs->FreeBuffer (\r
+ mPciIoFncs,\r
+ SNP_MEM_PAGES (4096),\r
+ snp->cpb\r
+ );\r
+\r
+Error_DeleteSNP:\r
+ if (snp->IsOldUndi) {\r
+ Status = mPciIoFncs->Unmap (\r
+ mPciIoFncs,\r
+ snp->SnpDriverUnmap\r
+ );\r
+ }\r
+\r
+ mPciIoFncs->FreeBuffer (\r
+ mPciIoFncs,\r
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
+ snp\r
+ );\r
+NiiError:\r
+ if (!UndiNew) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ } else {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SimpleNetworkDriverStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;\r
+ SNP_DRIVER *Snp;\r
+\r
+ //\r
+ // Get our context back.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ (VOID **) &SnpProtocol,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);\r
+\r
+ Status = gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ &Snp->snp\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (!Snp->IsOldUndi) {\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ } else {\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ }\r
+\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ pxe_shutdown (Snp);\r
+ pxe_stop (Snp);\r
+\r
+ if (Snp->IsOldUndi) {\r
+ Status = mPciIoFncs->Unmap (\r
+ mPciIoFncs,\r
+ Snp->FillHdrBufUnmap\r
+ );\r
+\r
+ mPciIoFncs->FreeBuffer (\r
+ mPciIoFncs,\r
+ SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen),\r
+ Snp->fill_hdr_buf\r
+ );\r
+ Status = mPciIoFncs->Unmap (\r
+ mPciIoFncs,\r
+ Snp->ReceiveBufUnmap\r
+ );\r
+\r
+ mPciIoFncs->FreeBuffer (\r
+ mPciIoFncs,\r
+ SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen + Snp->init_info.FrameDataLen),\r
+ Snp->receive_buf\r
+ );\r
+\r
+ Status = mPciIoFncs->Unmap (\r
+ mPciIoFncs,\r
+ Snp->CpbUnmap\r
+ );\r
+ Status = mPciIoFncs->Unmap (\r
+ mPciIoFncs,\r
+ Snp->SnpDriverUnmap\r
+ );\r
+ }\r
+\r
+ mPciIoFncs->FreeBuffer (\r
+ mPciIoFncs,\r
+ SNP_MEM_PAGES (4096),\r
+ Snp->cpb\r
+ );\r
+\r
+ mPciIoFncs->FreeBuffer (\r
+ mPciIoFncs,\r
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
+ Snp\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Install all the driver protocol\r
+\r
+ @param entry EFI_IMAGE_ENTRY_POINT)\r
+\r
+ @retval EFI_SUCEESS Initialization routine has found UNDI hardware,\r
+ loaded it's ROM, and installed a notify event for\r
+ the Network Indentifier Interface Protocol\r
+ successfully.\r
+ @retval Other Return value from HandleProtocol for\r
+ DeviceIoProtocol or LoadedImageProtocol\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSnpNiiDriver (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ return EfiLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &mSimpleNetworkDriverBinding,\r
+ NULL,\r
+ COMPONENT_NAME,\r
+ NULL,\r
+ NULL\r
+ );\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2004 - 2007, 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:
+ snp.h
+
+Abstract:
+
+Revision history:
+
+
+**/
+#ifndef _SNP_H
+#define _SNP_H
+
+
+#include <PiDxe.h>\r
+\r
+#include <Protocol/SimpleNetwork.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/NetworkInterfaceIdentifier.h>\r
+#include <Protocol/DevicePath.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci22.h>
+
+#define FOUR_GIGABYTES (UINT64) 0x100000000ULL
+
+//
+// Driver Consumed Protocol Prototypes
+//
+//@MT:#include EFI_PROTOCOL_DEFINITION (DevicePath)
+//@MT:#include EFI_PROTOCOL_DEFINITION (PciIo)
+//@MT:#include EFI_PROTOCOL_DEFINITION (EfiNetworkInterfaceIdentifier)
+
+//
+// Driver Produced Protocol Prototypes
+//
+//@MT:#include EFI_PROTOCOL_DEFINITION (DriverBinding)
+//@MT:#include EFI_PROTOCOL_DEFINITION (ComponentName)
+//@MT:#include EFI_PROTOCOL_DEFINITION (ComponentName2)
+//@MT:#include EFI_PROTOCOL_DEFINITION (SimpleNetwork)
+
+#define SNP_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('s', 'n', 'd', 's')
+#define MAX_MAP_LENGTH 100
+
+#define PCI_BAR_IO_MASK 0x00000003
+#define PCI_BAR_IO_MODE 0x00000001
+
+#define PCI_BAR_MEM_MASK 0x0000000F
+#define PCI_BAR_MEM_MODE 0x00000000
+#define PCI_BAR_MEM_64BIT 0x00000004
+
+typedef struct {
+ UINT32 Signature;
+ EFI_LOCK lock;
+
+ EFI_SIMPLE_NETWORK_PROTOCOL snp;
+ EFI_SIMPLE_NETWORK_MODE mode;
+
+ EFI_HANDLE device_handle;
+ EFI_DEVICE_PATH_PROTOCOL *device_path;
+
+ //
+ // Local instance data needed by SNP driver
+ //
+ // Pointer to S/W UNDI API entry point
+ // This will be NULL for H/W UNDI
+ //
+ EFI_STATUS (*issue_undi32_command) (UINT64 cdb);
+
+ BOOLEAN is_swundi;
+
+ //
+ // undi interface number, if one undi manages more nics
+ //
+ PXE_IFNUM if_num;
+
+ //
+ // Allocated tx/rx buffer that was passed to UNDI Initialize.
+ //
+ UINT32 tx_rx_bufsize;
+ VOID *tx_rx_buffer;
+ //
+ // mappable buffers for receive and fill header for undi3.0
+ // these will be used if the user buffers are above 4GB limit (instead of
+ // mapping the user buffers)
+ //
+ UINT8 *receive_buf;
+ VOID *ReceiveBufUnmap;
+ UINT8 *fill_hdr_buf;
+ VOID *FillHdrBufUnmap;
+
+ EFI_PCI_IO_PROTOCOL *IoFncs;
+ UINT8 IoBarIndex;
+ UINT8 MemoryBarIndex;
+ BOOLEAN IsOldUndi; // true for EFI1.0 UNDI (3.0) drivers
+ //
+ // Buffers for command descriptor block, command parameter block
+ // and data block.
+ //
+ PXE_CDB cdb;
+ VOID *cpb;
+ VOID *CpbUnmap;
+ VOID *db;
+
+ //
+ // UNDI structure, we need to remember the init info for a long time!
+ //
+ PXE_DB_GET_INIT_INFO init_info;
+
+ VOID *SnpDriverUnmap;
+ //
+ // when ever we map an address, we must remember it's address and the un-map
+ // cookie so that we can unmap later
+ //
+ struct s_map_list {
+ EFI_PHYSICAL_ADDRESS virt;
+ VOID *map_cookie;
+ } map_list[MAX_MAP_LENGTH];
+}
+SNP_DRIVER;
+
+#define EFI_SIMPLE_NETWORK_DEV_FROM_THIS(a) CR (a, SNP_DRIVER, snp, SNP_DRIVER_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gSimpleNetworkComponentName;
+
+//
+// Virtual to physical mapping for all UNDI 3.0s.
+//
+extern struct s_v2p {
+ struct s_v2p *next;
+ VOID *vaddr;
+ UINTN bsize;
+ EFI_PHYSICAL_ADDRESS paddr;
+ VOID *unmap;
+}
+*_v2p;
+
+EFI_STATUS
+add_v2p (
+ struct s_v2p **v2p,
+ EFI_PCI_IO_PROTOCOL_OPERATION type,
+ VOID *vaddr,
+ UINTN bsize
+ )
+;
+
+EFI_STATUS
+find_v2p (
+ struct s_v2p **v2p,
+ VOID *vaddr
+ )
+;
+
+EFI_STATUS
+del_v2p (
+ VOID *vaddr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_block_30 (
+ IN UINT32 Enable
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_delay_30 (
+ IN UINT64 MicroSeconds
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_memio_30 (
+ IN UINT8 ReadOrWrite,
+ IN UINT8 NumBytes,
+ IN UINT64 MemOrPortAddress,
+ IN OUT UINT64 BufferPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_v2p_30 (
+ IN UINT64 CpuAddr,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_block (
+ IN UINT64 UniqueId,
+ IN UINT32 Enable
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_delay (
+ IN UINT64 UniqueId,
+ IN UINT64 MicroSeconds
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_memio (
+ IN UINT64 UniqueId,
+ IN UINT8 ReadOrWrite,
+ IN UINT8 NumBytes,
+ IN UINT64 MemOrPortAddr,
+ IN OUT UINT64 BufferPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_map (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_unmap (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr // not a pointer to device address
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_sync (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr // not a pointer to device address
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_start (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_stop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_initialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN UINTN extra_rx_buffer_size OPTIONAL,
+ IN UINTN extra_tx_buffer_size OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_reset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN ExtendedVerification
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_shutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_receive_filters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN UINT32 enable,
+ IN UINT32 disable,
+ IN BOOLEAN reset_mcast_filter,
+ IN UINTN mcast_filter_count OPTIONAL,
+ IN EFI_MAC_ADDRESS * mcast_filter OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_station_address (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN BOOLEAN reset,
+ IN EFI_MAC_ADDRESS *new OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_statistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN BOOLEAN reset,
+ IN OUT UINTN *statistics_size OPTIONAL,
+ IN OUT EFI_NETWORK_STATISTICS * statistics_table OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_mcast_ip_to_mac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_nvdata (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN read_write,
+ IN UINTN offset,
+ IN UINTN buffer_size,
+ IN OUT VOID *buffer
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_get_status (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINT32 *interrupt_status OPTIONAL,
+ OUT VOID **tx_buffer OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_transmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN UINTN header_size,
+ IN UINTN buffer_size,
+ IN VOID *buffer,
+ IN EFI_MAC_ADDRESS * src_addr OPTIONAL,
+ IN EFI_MAC_ADDRESS * dest_addr OPTIONAL,
+ IN UINT16 *protocol OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_receive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINTN *header_size OPTIONAL,
+ IN OUT UINTN *buffer_size,
+ OUT VOID *buffer,
+ OUT EFI_MAC_ADDRESS * src_addr OPTIONAL,
+ OUT EFI_MAC_ADDRESS * dest_addr OPTIONAL,
+ OUT UINT16 *protocol OPTIONAL
+ )
+;
+
+typedef
+EFI_STATUS
+(*issue_undi32_command) (
+ UINT64 cdb
+ );
+typedef
+VOID
+(*ptr) (
+ VOID
+ );
+
+
+/**
+ Install all the driver protocol
+
+ @param ImageHandle Driver image handle
+ @param SystemTable System services table
+
+ @retval EFI_SUCEESS Initialization routine has found UNDI hardware, loaded it's
+ ROM, and installed a notify event for the Network
+ Indentifier Interface Protocol successfully.
+ @retval Other Return value from HandleProtocol for DeviceIoProtocol or
+ LoadedImageProtocol
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSnpNiiDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+;
+
+#ifdef EFI_SIZE_REDUCTION_APPLIED
+ #define COMPONENT_NAME_CODE(code)
+ #define COMPONENT_NAME NULL
+#else
+ #define COMPONENT_NAME_CODE(code) code
+ #define COMPONENT_NAME &gSimpleNetworkComponentName
+#endif
+
+#define SNP_MEM_PAGES(x) (((x) - 1) / 4096 + 1)
+
+
+#endif /* _SNP_H */
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ start.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-07 M(f)J Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+ this routine calls undi to start the interface and changes the snp state!\r
+\r
+ @param snp pointer to snp driver structure\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_start (\r
+ SNP_DRIVER *snp\r
+ )\r
+{\r
+ PXE_CPB_START_30 *cpb;\r
+ PXE_CPB_START_31 *cpb_31;\r
+\r
+ cpb = snp->cpb;\r
+ cpb_31 = snp->cpb;\r
+ //\r
+ // Initialize UNDI Start CDB for H/W UNDI\r
+ //\r
+ snp->cdb.OpCode = PXE_OPCODE_START;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Make changes to H/W UNDI Start CDB if this is\r
+ // a S/W UNDI.\r
+ //\r
+ if (snp->is_swundi) {\r
+ if (snp->IsOldUndi) {\r
+ snp->cdb.CPBsize = sizeof (PXE_CPB_START_30);\r
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;\r
+\r
+ cpb->Delay = (UINT64)(UINTN) &snp_undi32_callback_delay_30;\r
+ cpb->Block = (UINT64)(UINTN) &snp_undi32_callback_block_30;\r
+\r
+ //\r
+ // Virtual == Physical. This can be set to zero.\r
+ //\r
+ cpb->Virt2Phys = (UINT64)(UINTN) &snp_undi32_callback_v2p_30;\r
+ cpb->Mem_IO = (UINT64)(UINTN) &snp_undi32_callback_memio_30;\r
+ } else {\r
+ snp->cdb.CPBsize = sizeof (PXE_CPB_START_31);\r
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb_31;\r
+\r
+ cpb_31->Delay = (UINT64)(UINTN) &snp_undi32_callback_delay;\r
+ cpb_31->Block = (UINT64)(UINTN) &snp_undi32_callback_block;\r
+\r
+ //\r
+ // Virtual == Physical. This can be set to zero.\r
+ //\r
+ cpb_31->Virt2Phys = (UINT64)(UINTN) 0;\r
+ cpb_31->Mem_IO = (UINT64)(UINTN) &snp_undi32_callback_memio;\r
+\r
+ cpb_31->Map_Mem = (UINT64)(UINTN) &snp_undi32_callback_map;\r
+ cpb_31->UnMap_Mem = (UINT64)(UINTN) &snp_undi32_callback_unmap;\r
+ cpb_31->Sync_Mem = (UINT64)(UINTN) &snp_undi32_callback_sync;\r
+\r
+ cpb_31->Unique_ID = (UINT64)(UINTN) snp;\r
+ }\r
+ }\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.start() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+ //\r
+ // UNDI could not be started. Return UNDI error.\r
+ //\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.start() %xh:%xh\n",\r
+ snp->cdb.StatCode,\r
+ snp->cdb.StatFlags)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Set simple network state to Started and return success.\r
+ //\r
+ snp->mode.State = EfiSimpleNetworkStarted;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for starting the interface\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ calls the pxe_start routine to actually do start undi interface\r
+\r
+ @param This context pointer\r
+\r
+ @retval EFI_INVALID_PARAMETER "This" is Null\r
+ @retval No SNP driver can be extracted from "This"\r
+ @retval EFI_ALREADY_STARTED The state of SNP is EfiSimpleNetworkStarted or\r
+ EfiSimpleNetworkInitialized\r
+ @retval EFI_DEVICE_ERROR The state of SNP is other than\r
+ EfiSimpleNetworkStarted,\r
+ EfiSimpleNetworkInitialized, and\r
+ EfiSimpleNetworkStopped\r
+ @retval EFI_SUCCESS UNDI interface is succesfully started\r
+ @retval Other Error occurs while calling pxe_start function.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_start (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This\r
+ )\r
+{\r
+ SNP_DRIVER *Snp;\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ switch (Snp->mode.State) {\r
+ case EfiSimpleNetworkStopped:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStarted:\r
+ case EfiSimpleNetworkInitialized:\r
+ Status = EFI_ALREADY_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = pxe_start (Snp);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // clear the map_list in SNP structure\r
+ //\r
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {\r
+ Snp->map_list[Index].virt = 0;\r
+ Snp->map_list[Index].map_cookie = 0;\r
+ }\r
+\r
+ Snp->mode.MCastFilterCount = 0;\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ station_address.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-17 M(f)J Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+ this routine calls undi to read the MAC address of the NIC and updates the\r
+ mode structure with the address.\r
+\r
+ @param snp pointer to snp driver structure\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_get_stn_addr (\r
+ SNP_DRIVER *snp\r
+ )\r
+{\r
+ PXE_DB_STATION_ADDRESS *db;\r
+\r
+ db = snp->db;\r
+ snp->cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ;\r
+\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+\r
+ snp->cdb.DBsize = sizeof (PXE_DB_STATION_ADDRESS);\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.station_addr() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Set new station address in SNP->Mode structure and return success.\r
+ //\r
+ CopyMem (\r
+ &(snp->mode.CurrentAddress),\r
+ &db->StationAddr,\r
+ snp->mode.HwAddressSize\r
+ );\r
+\r
+ CopyMem (\r
+ &snp->mode.BroadcastAddress,\r
+ &db->BroadcastAddr,\r
+ snp->mode.HwAddressSize\r
+ );\r
+\r
+ CopyMem (\r
+ &snp->mode.PermanentAddress,\r
+ &db->PermanentAddr,\r
+ snp->mode.HwAddressSize\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ this routine calls undi to set a new MAC address for the NIC,\r
+\r
+ @param snp pointer to snp driver structure\r
+ @param NewMacAddr pointer to a mac address to be set for the nic, if this is\r
+ NULL then this routine resets the mac address to the NIC's\r
+ original address.\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_set_stn_addr (\r
+ SNP_DRIVER *snp,\r
+ EFI_MAC_ADDRESS *NewMacAddr\r
+ )\r
+{\r
+ PXE_CPB_STATION_ADDRESS *cpb;\r
+ PXE_DB_STATION_ADDRESS *db;\r
+\r
+ cpb = snp->cpb;\r
+ db = snp->db;\r
+ snp->cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;\r
+\r
+ if (NewMacAddr == NULL) {\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_RESET;\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ } else {\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ;\r
+ //\r
+ // even though the OPFLAGS are set to READ, supplying a new address\r
+ // in the CPB will make undi change the mac address to the new one.\r
+ //\r
+ CopyMem (&cpb->StationAddr, NewMacAddr, snp->mode.HwAddressSize);\r
+\r
+ snp->cdb.CPBsize = sizeof (PXE_CPB_STATION_ADDRESS);\r
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;\r
+ }\r
+\r
+ snp->cdb.DBsize = sizeof (PXE_DB_STATION_ADDRESS);\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.station_addr() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ //\r
+ // UNDI command failed. Return UNDI status to caller.\r
+ //\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // read the changed address and save it in SNP->Mode structure\r
+ //\r
+ pxe_get_stn_addr (snp);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for changing the NIC's mac address.\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ calls the above routines to actually do the work\r
+\r
+ @param this context pointer\r
+ @param NewMacAddr pointer to a mac address to be set for the nic, if this is\r
+ NULL then this routine resets the mac address to the NIC's\r
+ original address.\r
+ @param ResetFlag If true, the mac address will change to NIC's original\r
+ address\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_station_address (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+ IN BOOLEAN ResetFlag,\r
+ IN EFI_MAC_ADDRESS * NewMacAddr OPTIONAL\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Check for invalid parameter combinations.\r
+ //\r
+ if ((this == NULL) ||\r
+ (!ResetFlag && (NewMacAddr == NULL))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ //\r
+ // Return error if the SNP is not initialized.\r
+ //\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (ResetFlag) {\r
+ Status = pxe_set_stn_addr (snp, NULL);\r
+ } else {\r
+ Status = pxe_set_stn_addr (snp, NewMacAddr);\r
+ }\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ statistics.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-17 M(f)J Genesis.\r
+\r
+**/\r
+\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for getting the NIC's statistics.\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ calls the pxe_ routine to actually do the\r
+\r
+ @param this context pointer\r
+ @param ResetFlag true to reset the NIC's statistics counters to zero.\r
+ @param StatTableSizePtr pointer to the statistics table size\r
+ @param StatTablePtr pointer to the statistics table\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_statistics (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+ IN BOOLEAN ResetFlag,\r
+ IN OUT UINTN *StatTableSizePtr OPTIONAL,\r
+ IN OUT EFI_NETWORK_STATISTICS * StatTablePtr OPTIONAL\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ PXE_DB_STATISTICS *db;\r
+ UINT64 *stp;\r
+ UINT64 mask;\r
+ UINTN size;\r
+ UINTN n;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Get pointer to SNP driver instance for *this.\r
+ //\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ //\r
+ // Return error if the SNP is not initialized.\r
+ //\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // if we are not resetting the counters, we have to have a valid stat table\r
+ // with >0 size. if no reset, no table and no size, return success.\r
+ //\r
+ if (!ResetFlag && StatTableSizePtr == NULL) {\r
+ Status = StatTablePtr ? EFI_INVALID_PARAMETER : EFI_SUCCESS;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Initialize UNDI Statistics CDB\r
+ //\r
+ snp->cdb.OpCode = PXE_OPCODE_STATISTICS;\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ if (ResetFlag) {\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATISTICS_RESET;\r
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;\r
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;\r
+ db = snp->db;\r
+ } else {\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATISTICS_READ;\r
+ snp->cdb.DBsize = sizeof (PXE_DB_STATISTICS);\r
+ snp->cdb.DBaddr = (UINT64)(UINTN) (db = snp->db);\r
+ }\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.statistics() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ switch (snp->cdb.StatCode) {\r
+ case PXE_STATCODE_SUCCESS:\r
+ break;\r
+\r
+ case PXE_STATCODE_UNSUPPORTED:\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.statistics() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.statistics() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (ResetFlag) {\r
+ Status = EFI_SUCCESS;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (StatTablePtr == NULL) {\r
+ *StatTableSizePtr = sizeof (EFI_NETWORK_STATISTICS);\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Convert the UNDI statistics information to SNP statistics\r
+ // information.\r
+ //\r
+ ZeroMem (StatTablePtr, *StatTableSizePtr);\r
+ stp = (UINT64 *) StatTablePtr;\r
+ size = 0;\r
+\r
+ for (n = 0, mask = 1; n < 64; n++, mask = LShiftU64 (mask, 1), stp++) {\r
+ //\r
+ // There must be room for a full UINT64. Partial\r
+ // numbers will not be stored.\r
+ //\r
+ if ((n + 1) * sizeof (UINT64) > *StatTableSizePtr) {\r
+ break;\r
+ }\r
+\r
+ if (db->Supported & mask) {\r
+ *stp = db->Data[n];\r
+ size = n + 1;\r
+ } else {\r
+ SetMem (stp, sizeof (UINT64), 0xFF);\r
+ }\r
+ }\r
+ //\r
+ // Compute size up to last supported statistic.\r
+ //\r
+ while (++n < 64) {\r
+ if (db->Supported & (mask = LShiftU64 (mask, 1))) {\r
+ size = n;\r
+ }\r
+ }\r
+\r
+ size *= sizeof (UINT64);\r
+\r
+ if (*StatTableSizePtr >= size) {\r
+ *StatTableSizePtr = size;\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ *StatTableSizePtr = size;\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+ stop.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-09 M(f)J Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+ this routine calls undi to stop the interface and changes the snp state\r
+\r
+ @param snp pointer to snp driver structure\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+pxe_stop (\r
+ SNP_DRIVER *snp\r
+ )\r
+{\r
+ snp->cdb.OpCode = PXE_OPCODE_STOP;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;\r
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;\r
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Issue UNDI command\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.stop() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
+\r
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
+ DEBUG (\r
+ (EFI_D_WARN,\r
+ "\nsnp->undi.stop() %xh:%xh\n",\r
+ snp->cdb.StatCode,\r
+ snp->cdb.StatFlags)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Set simple network state to Started and return success.\r
+ //\r
+ snp->mode.State = EfiSimpleNetworkStopped;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This is the SNP interface routine for stopping the interface.\r
+ This routine basically retrieves snp structure, checks the SNP state and\r
+ calls the pxe_stop routine to actually stop the undi interface\r
+\r
+ @param this context pointer\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_stop (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkStarted:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = pxe_stop (snp);\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module name:\r
+\r
+ transmit.c\r
+\r
+Abstract:\r
+\r
+Revision history:\r
+ 2000-Feb-03 M(f)J Genesis.\r
+\r
+**/\r
+\r
+#include "Snp.h"\r
+\r
+\r
+/**\r
+ This routine calls undi to create the meadia header for the given data buffer.\r
+\r
+ @param snp pointer to SNP driver structure\r
+ @param MacHeaderPtr address where the media header will be filled in.\r
+ @param MacHeaderSize size of the memory at MacHeaderPtr\r
+ @param BufferPtr data buffer pointer\r
+ @param BufferLength Size of data in the BufferPtr\r
+ @param DestinationAddrPtr address of the destination mac address buffer\r
+ @param SourceAddrPtr address of the source mac address buffer\r
+ @param ProtocolPtr address of the protocol type\r
+\r
+ @retval EFI_SUCCESS if successfully completed the undi call\r
+ @retval Other error return from undi call.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_fillheader (\r
+ SNP_DRIVER *snp,\r
+ VOID *MacHeaderPtr,\r
+ UINTN MacHeaderSize,\r
+ VOID *BufferPtr,\r
+ UINTN BufferLength,\r
+ EFI_MAC_ADDRESS *DestinationAddrPtr,\r
+ EFI_MAC_ADDRESS *SourceAddrPtr,\r
+ UINT16 *ProtocolPtr\r
+ )\r
+{\r
+ PXE_CPB_FILL_HEADER_FRAGMENTED *cpb;\r
+ EFI_STATUS Status;\r
+ struct s_v2p *pkt_v2p;\r
+ UINT64 TempData;\r
+\r
+ cpb = snp->cpb;\r
+ if (SourceAddrPtr) {\r
+ CopyMem (\r
+ (VOID *) cpb->SrcAddr,\r
+ (VOID *) SourceAddrPtr,\r
+ snp->mode.HwAddressSize\r
+ );\r
+ } else {\r
+ CopyMem (\r
+ (VOID *) cpb->SrcAddr,\r
+ (VOID *) &(snp->mode.CurrentAddress),\r
+ snp->mode.HwAddressSize\r
+ );\r
+ }\r
+\r
+ CopyMem (\r
+ (VOID *) cpb->DestAddr,\r
+ (VOID *) DestinationAddrPtr,\r
+ snp->mode.HwAddressSize\r
+ );\r
+\r
+ //\r
+ // we need to do the byte swapping\r
+ //\r
+ cpb->Protocol = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr);\r
+\r
+ cpb->PacketLen = (UINT32) (BufferLength);\r
+ cpb->MediaHeaderLen = (UINT16) MacHeaderSize;\r
+\r
+ cpb->FragCnt = 2;\r
+ cpb->reserved = 0;\r
+\r
+ cpb->FragDesc[0].FragAddr = (UINT64)(UINTN) MacHeaderPtr;\r
+ cpb->FragDesc[0].FragLen = (UINT32) MacHeaderSize;\r
+ cpb->FragDesc[1].FragAddr = (UINT64)(UINTN) BufferPtr;\r
+ cpb->FragDesc[1].FragLen = (UINT32) BufferLength;\r
+\r
+ cpb->FragDesc[0].reserved = cpb->FragDesc[1].reserved = 0;\r
+\r
+ if (snp->IsOldUndi) {\r
+ TempData = (UINT64) (UINTN) MacHeaderPtr;\r
+ if (TempData >= FOUR_GIGABYTES) {\r
+ cpb->FragDesc[0].FragAddr = (UINT64) (UINTN) snp->fill_hdr_buf;\r
+ cpb->FragDesc[0].FragLen = (UINT32) snp->init_info.MediaHeaderLen;\r
+ }\r
+\r
+ TempData = (UINT64) (UINTN) (BufferPtr);\r
+ if (TempData >= FOUR_GIGABYTES) {\r
+ //\r
+ // Let the device just read this buffer\r
+ //\r
+ Status = add_v2p (\r
+ &pkt_v2p,\r
+ EfiPciIoOperationBusMasterRead,\r
+ BufferPtr,\r
+ BufferLength\r
+ );\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+ //\r
+ // give the virtual address to UNDI and it will call back on Virt2Phys\r
+ // to get the mapped address, if it needs it\r
+ //\r
+ cpb->FragDesc[1].FragLen = (UINT32) pkt_v2p->bsize;\r
+ }\r
+ }\r
+\r
+ snp->cdb.OpCode = PXE_OPCODE_FILL_HEADER;\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;\r
+\r
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;\r
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;\r
+\r
+ snp->cdb.CPBsize = sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);\r
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.fill_header() "));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);\r
+\r
+ if (snp->IsOldUndi) {\r
+ TempData = (UINT64) (UINTN) (BufferPtr);\r
+ if (TempData >= FOUR_GIGABYTES) {\r
+ del_v2p (BufferPtr);\r
+ }\r
+ //\r
+ // if we used the global buffer for header, copy the contents\r
+ //\r
+ TempData = (UINT64) (UINTN) MacHeaderPtr;\r
+ if (TempData >= FOUR_GIGABYTES) {\r
+ CopyMem (\r
+ MacHeaderPtr,\r
+ snp->fill_hdr_buf,\r
+ snp->init_info.MediaHeaderLen\r
+ );\r
+ }\r
+ }\r
+\r
+ switch (snp->cdb.StatCode) {\r
+ case PXE_STATCODE_SUCCESS:\r
+ return EFI_SUCCESS;\r
+\r
+ case PXE_STATCODE_INVALID_PARAMETER:\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.fill_header() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+\r
+ default:\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.fill_header() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This routine calls undi to transmit the given data buffer\r
+\r
+ @param snp pointer to SNP driver structure\r
+ @param BufferPtr data buffer pointer\r
+ @param BufferLength Size of data in the BufferPtr\r
+\r
+ @retval EFI_SUCCESS if successfully completed the undi call\r
+ @retval Other error return from undi call.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+pxe_transmit (\r
+ SNP_DRIVER *snp,\r
+ VOID *BufferPtr,\r
+ UINTN BufferLength\r
+ )\r
+{\r
+ PXE_CPB_TRANSMIT *cpb;\r
+ EFI_STATUS Status;\r
+ struct s_v2p *v2p;\r
+ UINT64 TempData;\r
+\r
+ cpb = snp->cpb;\r
+ cpb->FrameAddr = (UINT64) (UINTN) BufferPtr;\r
+ cpb->DataLen = (UINT32) BufferLength;\r
+ \r
+ TempData = (UINT64) (UINTN) BufferPtr;\r
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {\r
+ //\r
+ // we need to create a mapping now and give it to the undi when it calls\r
+ // the Virt2Phys on this address.\r
+ // this is a transmit, just map it for the device to READ\r
+ //\r
+ Status = add_v2p (\r
+ &v2p,\r
+ EfiPciIoOperationBusMasterRead,\r
+ BufferPtr,\r
+ BufferLength\r
+ );\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ cpb->DataLen = (UINT32) v2p->bsize;\r
+ }\r
+\r
+ cpb->MediaheaderLen = 0;\r
+ cpb->reserved = 0;\r
+\r
+ snp->cdb.OpFlags = PXE_OPFLAGS_TRANSMIT_WHOLE;\r
+\r
+ snp->cdb.CPBsize = sizeof (PXE_CPB_TRANSMIT);\r
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;\r
+\r
+ snp->cdb.OpCode = PXE_OPCODE_TRANSMIT;\r
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;\r
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;\r
+\r
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
+ snp->cdb.IFnum = snp->if_num;\r
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
+\r
+ //\r
+ // Issue UNDI command and check result.\r
+ //\r
+ DEBUG ((EFI_D_NET, "\nsnp->undi.transmit() "));\r
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.OpCode == %x", snp->cdb.OpCode));\r
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.CPBaddr == %X", snp->cdb.CPBaddr));\r
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.DBaddr == %X", snp->cdb.DBaddr));\r
+ DEBUG ((EFI_D_NET, "\ncpb->FrameAddr == %X\n", cpb->FrameAddr));\r
+\r
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);\r
+\r
+ DEBUG ((EFI_D_NET, "\nexit snp->undi.transmit() "));\r
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.StatCode == %r", snp->cdb.StatCode));\r
+\r
+ //\r
+ // we will unmap the buffers in get_status call, not here\r
+ //\r
+ switch (snp->cdb.StatCode) {\r
+ case PXE_STATCODE_SUCCESS:\r
+ return EFI_SUCCESS;\r
+\r
+ case PXE_STATCODE_QUEUE_FULL:\r
+ case PXE_STATCODE_BUSY:\r
+ Status = EFI_NOT_READY;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "\nsnp->undi.transmit() %xh:%xh\n",\r
+ snp->cdb.StatFlags,\r
+ snp->cdb.StatCode)\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This is the snp interface routine for transmitting a packet. this routine\r
+ basically retrieves the snp structure, checks the snp state and calls\r
+ pxe_fill_header and pxe_transmit calls to complete the transmission.\r
+\r
+ @param this pointer to SNP driver context\r
+ @param MacHeaderSize size of the memory at MacHeaderPtr\r
+ @param BufferLength Size of data in the BufferPtr\r
+ @param BufferPtr data buffer pointer\r
+ @param SourceAddrPtr address of the source mac address buffer\r
+ @param DestinationAddrPtr address of the destination mac address buffer\r
+ @param ProtocolPtr address of the protocol type\r
+\r
+ @retval EFI_SUCCESS if successfully completed the undi call\r
+ @retval Other error return from undi call.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+snp_undi32_transmit (\r
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
+ IN UINTN MacHeaderSize,\r
+ IN UINTN BufferLength,\r
+ IN VOID *BufferPtr,\r
+ IN EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL,\r
+ IN EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL,\r
+ IN UINT16 *ProtocolPtr OPTIONAL\r
+ )\r
+{\r
+ SNP_DRIVER *snp;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (this == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ if (snp == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ switch (snp->mode.State) {\r
+ case EfiSimpleNetworkInitialized:\r
+ break;\r
+\r
+ case EfiSimpleNetworkStopped:\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+\r
+ default:\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (BufferPtr == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (BufferLength < snp->mode.MediaHeaderSize) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // if the MacHeaderSize is non-zero, we need to fill up the header and for that\r
+ // we need the destination address and the protocol\r
+ //\r
+ if (MacHeaderSize != 0) {\r
+ if (MacHeaderSize != snp->mode.MediaHeaderSize || DestinationAddrPtr == 0 || ProtocolPtr == 0) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = pxe_fillheader (\r
+ snp,\r
+ BufferPtr,\r
+ MacHeaderSize,\r
+ (UINT8 *) BufferPtr + MacHeaderSize,\r
+ BufferLength - MacHeaderSize,\r
+ DestinationAddrPtr,\r
+ SourceAddrPtr,\r
+ ProtocolPtr\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+\r
+ Status = pxe_transmit (snp, BufferPtr, BufferLength);\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+TcpComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TcpComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL gTcp4ComponentName = {\r
+ TcpComponentNameGetDriverName,\r
+ TcpComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mTcpDriverNameTable[] = {\r
+ {\r
+ "eng",\r
+ L"Tcp Network Service Driver"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TcpComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ Language - A pointer to a three character ISO 639-2 language identifier.\r
+ This is the language of the driver name that that the caller\r
+ is requesting, and it must match one of the languages\r
+ specified in SupportedLanguages. The number of languages\r
+ supported by a driver is up to the driver writer.\r
+ DriverName - A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the driver specified by This in the\r
+ language specified by Language.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCES - The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - DriverName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gTcp4ComponentName.SupportedLanguages,\r
+ mTcpDriverNameTable,\r
+ DriverName\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TcpComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by an EFI Driver.\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ ControllerHandle - The handle of a controller that the driver specified by\r
+ This is managing. This handle specifies the controller\r
+ whose name is to be returned.\r
+ ChildHandle - The handle of the child controller to retrieve the name\r
+ of. This is an optional parameter that may be NULL.\r
+ It will be NULL for device drivers. It will also be\r
+ NULL for a bus drivers that wish to retrieve the name of\r
+ the bus controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a child\r
+ controller.\r
+ Language - A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language of the controller\r
+ name that that the caller is requesting, and it must\r
+ match one of the languages specified in supported\r
+ languages. The number of languages supported by a driver\r
+ is up to the driver writer.\r
+ ControllerName - A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the controller specified by\r
+ ControllerHandle and ChildHandle in the language\r
+ specified by Language from the point of view of the\r
+ driver specified by This.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The Unicode string for the user readable name in\r
+ the language specified by Language for the driver\r
+ specified by This was returned in DriverName.\r
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ SockImpl.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "SockImpl.h"\r
+\r
+STATIC\r
+UINT32\r
+SockTcpDataToRcv (\r
+ IN SOCK_BUFFER *SockBuffer,\r
+ OUT BOOLEAN *IsOOB,\r
+ IN UINT32 BufLen\r
+ );\r
+\r
+STATIC\r
+VOID\r
+SockProcessSndToken (\r
+ IN SOCKET *Sock\r
+ );\r
+\r
+VOID\r
+SockFreeFoo (\r
+ IN EFI_EVENT Event\r
+ )\r
+{\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Get the length of the data that can be retrieved from the socket\r
+ receive buffer.\r
+\r
+ @param SockBuffer Pointer to the socket receive buffer.\r
+ @param IsUrg Pointer to a BOOLEAN variable. If TRUE the data is\r
+ OOB.\r
+ @param BufLen The maximum length of the data buffer to store the\r
+ received data in socket layer.\r
+\r
+ @return The length of the data can be retreived.\r
+\r
+**/\r
+STATIC\r
+UINT32\r
+SockTcpDataToRcv (\r
+ IN SOCK_BUFFER *SockBuffer,\r
+ OUT BOOLEAN *IsUrg,\r
+ IN UINT32 BufLen\r
+ )\r
+{\r
+ NET_BUF *RcvBufEntry;\r
+ UINT32 DataLen;\r
+ TCP_RSV_DATA *TcpRsvData;\r
+ BOOLEAN Urg;\r
+\r
+ ASSERT (SockBuffer && IsUrg && (BufLen > 0));\r
+\r
+ RcvBufEntry = SockBufFirst (SockBuffer);\r
+ ASSERT (RcvBufEntry);\r
+\r
+ TcpRsvData = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;\r
+\r
+ *IsUrg = ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
+\r
+ if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
+\r
+ DataLen = NET_MIN (TcpRsvData->UrgLen, BufLen);\r
+\r
+ if (DataLen < TcpRsvData->UrgLen) {\r
+ TcpRsvData->UrgLen = TcpRsvData->UrgLen - DataLen;\r
+ } else {\r
+ TcpRsvData->UrgLen = 0;\r
+ }\r
+\r
+ return DataLen;\r
+\r
+ }\r
+\r
+ DataLen = RcvBufEntry->TotalSize;\r
+\r
+ RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
+\r
+ while ((BufLen > DataLen) && (RcvBufEntry != NULL)) {\r
+\r
+ TcpRsvData = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;\r
+\r
+ Urg = ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);\r
+\r
+ if (*IsUrg != Urg) {\r
+ break;\r
+ }\r
+\r
+ if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {\r
+\r
+ if (TcpRsvData->UrgLen + DataLen < BufLen) {\r
+ TcpRsvData->UrgLen = 0;\r
+ } else {\r
+ TcpRsvData->UrgLen = TcpRsvData->UrgLen - (BufLen - DataLen);\r
+ }\r
+\r
+ return NET_MIN (TcpRsvData->UrgLen + DataLen, BufLen);\r
+\r
+ }\r
+\r
+ DataLen += RcvBufEntry->TotalSize;\r
+\r
+ RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);\r
+ }\r
+\r
+ DataLen = NET_MIN (BufLen, DataLen);\r
+ return DataLen;\r
+}\r
+\r
+\r
+/**\r
+ Copy data from socket buffer to application provided receive buffer.\r
+\r
+ @param Sock Pointer to the socket.\r
+ @param TcpRxData Pointer to the application provided receive buffer.\r
+ @param RcvdBytes The maximum length of the data can be copied.\r
+ @param IsOOB If TURE the data is OOB, else the data is normal.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+SockSetTcpRxData (\r
+ IN SOCKET *Sock,\r
+ IN VOID *TcpRxData,\r
+ IN UINT32 RcvdBytes,\r
+ IN BOOLEAN IsOOB\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT32 CopyBytes;\r
+ UINT32 OffSet;\r
+ EFI_TCP4_RECEIVE_DATA *RxData;\r
+ EFI_TCP4_FRAGMENT_DATA *Fragment;\r
+\r
+ RxData = (EFI_TCP4_RECEIVE_DATA *) TcpRxData;\r
+\r
+ OffSet = 0;\r
+\r
+ ASSERT (RxData->DataLength >= RcvdBytes);\r
+\r
+ RxData->DataLength = RcvdBytes;\r
+ RxData->UrgentFlag = IsOOB;\r
+\r
+ for (Index = 0; (Index < RxData->FragmentCount) && (RcvdBytes > 0); Index++) {\r
+\r
+ Fragment = &RxData->FragmentTable[Index];\r
+ CopyBytes = NET_MIN (Fragment->FragmentLength, RcvdBytes);\r
+\r
+ NetbufQueCopy (\r
+ Sock->RcvBuffer.DataQueue,\r
+ OffSet,\r
+ CopyBytes,\r
+ Fragment->FragmentBuffer\r
+ );\r
+\r
+ Fragment->FragmentLength = CopyBytes;\r
+ RcvdBytes -= CopyBytes;\r
+ OffSet += CopyBytes;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Get received data from the socket layer to the receive token.\r
+\r
+ @param Sock Pointer to the socket.\r
+ @param RcvToken Pointer to the application provided receive token.\r
+\r
+ @return The length of data received in this token.\r
+\r
+**/\r
+UINT32\r
+SockProcessRcvToken (\r
+ IN SOCKET *Sock,\r
+ IN SOCK_IO_TOKEN *RcvToken\r
+ )\r
+{\r
+ UINT32 TokenRcvdBytes;\r
+ EFI_TCP4_RECEIVE_DATA *RxData;\r
+ BOOLEAN IsUrg;\r
+\r
+ ASSERT (Sock);\r
+\r
+ ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+ RxData = RcvToken->Packet.RxData;\r
+\r
+ TokenRcvdBytes = SockTcpDataToRcv (\r
+ &Sock->RcvBuffer,\r
+ &IsUrg,\r
+ RxData->DataLength\r
+ );\r
+\r
+ //\r
+ // Copy data from RcvBuffer of socket to user\r
+ // provided RxData and set the fields in TCP RxData\r
+ //\r
+ SockSetTcpRxData (Sock, RxData, TokenRcvdBytes, IsUrg);\r
+\r
+ SOCK_TRIM_RCV_BUFF (Sock, TokenRcvdBytes);\r
+ SIGNAL_TOKEN (&(RcvToken->Token), EFI_SUCCESS);\r
+\r
+ return TokenRcvdBytes;\r
+}\r
+\r
+\r
+/**\r
+ Process the TCP send data, buffer the tcp txdata and append\r
+ the buffer to socket send buffer,then try to send it.\r
+\r
+ @param Sock Pointer to the socket.\r
+ @param TcpTxData Pointer to the tcp txdata.\r
+\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.\r
+\r
+**/\r
+EFI_STATUS\r
+SockProcessTcpSndData (\r
+ IN SOCKET *Sock,\r
+ IN VOID *TcpTxData\r
+ )\r
+{\r
+ NET_BUF *SndData;\r
+ EFI_STATUS Status;\r
+ EFI_TCP4_TRANSMIT_DATA *TxData;\r
+\r
+ TxData = (EFI_TCP4_TRANSMIT_DATA *) TcpTxData;\r
+\r
+ //\r
+ // transform this TxData into a NET_BUFFER\r
+ // and insert it into Sock->SndBuffer\r
+ //\r
+ SndData = NetbufFromExt (\r
+ (NET_FRAGMENT *) TxData->FragmentTable,\r
+ TxData->FragmentCount,\r
+ 0,\r
+ 0,\r
+ SockFreeFoo,\r
+ NULL\r
+ );\r
+\r
+ if (NULL == SndData) {\r
+ SOCK_DEBUG_ERROR (("SockKProcessSndData: Failed to"\r
+ " call NetBufferFromExt\n"));\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NetbufQueAppend (Sock->SndBuffer.DataQueue, SndData);\r
+\r
+ //\r
+ // notify the low layer protocol to handle this send token\r
+ //\r
+ if (TxData->Urgent) {\r
+ Status = Sock->ProtoHandler (Sock, SOCK_SNDURG, NULL);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if (TxData->Push) {\r
+ Status = Sock->ProtoHandler (Sock, SOCK_SNDPUSH, NULL);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // low layer protocol should really handle the sending\r
+ // process when catching SOCK_SND request\r
+ //\r
+ Status = Sock->ProtoHandler (Sock, SOCK_SND, NULL);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Flush the tokens in the specific token list.\r
+\r
+ @param Sock Pointer to the socket.\r
+ @param PendingTokenList Pointer to the token list to be flushed.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SockFlushPendingToken (\r
+ IN SOCKET *Sock,\r
+ IN NET_LIST_ENTRY *PendingTokenList\r
+ )\r
+{\r
+ SOCK_TOKEN *SockToken;\r
+ SOCK_COMPLETION_TOKEN *Token;\r
+\r
+ ASSERT (Sock && PendingTokenList);\r
+\r
+ while (!NetListIsEmpty (PendingTokenList)) {\r
+ SockToken = NET_LIST_HEAD (\r
+ PendingTokenList,\r
+ SOCK_TOKEN,\r
+ TokenList\r
+ );\r
+\r
+ Token = SockToken->Token;\r
+ SIGNAL_TOKEN (Token, Sock->SockError);\r
+\r
+ NetListRemoveEntry (&(SockToken->TokenList));\r
+ NetFreePool (SockToken);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Wake up the connection token while the connection is\r
+ successfully established, then try to process any\r
+ pending send token.\r
+\r
+ @param Sock Pointer to the socket.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SockWakeConnToken (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ ASSERT (Sock->ConnectionToken != NULL);\r
+\r
+ SIGNAL_TOKEN (Sock->ConnectionToken, EFI_SUCCESS);\r
+ Sock->ConnectionToken = NULL;\r
+\r
+ //\r
+ // check to see if some pending send token existed?\r
+ //\r
+ SockProcessSndToken (Sock);\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Wake up the listen token while the connection is\r
+ established successfully.\r
+\r
+ @param Sock Pointer to the socket.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SockWakeListenToken (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ SOCKET *Parent;\r
+ SOCK_TOKEN *SockToken;\r
+ EFI_TCP4_LISTEN_TOKEN *ListenToken;\r
+\r
+ Parent = Sock->Parent;\r
+\r
+ ASSERT (Parent && SOCK_IS_LISTENING (Parent) && SOCK_IS_CONNECTED (Sock));\r
+\r
+ if (!NetListIsEmpty (&Parent->ListenTokenList)) {\r
+ SockToken = NET_LIST_HEAD (\r
+ &Parent->ListenTokenList,\r
+ SOCK_TOKEN,\r
+ TokenList\r
+ );\r
+\r
+ ListenToken = (EFI_TCP4_LISTEN_TOKEN *) SockToken->Token;\r
+ ListenToken->NewChildHandle = Sock->SockHandle;\r
+\r
+ SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);\r
+\r
+ NetListRemoveEntry (&SockToken->TokenList);\r
+ NetFreePool (SockToken);\r
+\r
+ NetListRemoveEntry (&Sock->ConnectionList);\r
+\r
+ Parent->ConnCnt--;\r
+ SOCK_DEBUG_WARN (("SockWakeListenToken: accept a socket,"\r
+ "now conncnt is %d", Parent->ConnCnt));\r
+\r
+ Sock->Parent = NULL;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Wake up the receive token while some data is received.\r
+\r
+ @param Sock Pointer to the socket.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SockWakeRcvToken (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ UINT32 RcvdBytes;\r
+ UINT32 TokenRcvdBytes;\r
+ SOCK_TOKEN *SockToken;\r
+ SOCK_IO_TOKEN *RcvToken;\r
+\r
+ ASSERT (Sock->RcvBuffer.DataQueue);\r
+\r
+ RcvdBytes = (Sock->RcvBuffer.DataQueue)->BufSize;\r
+\r
+ ASSERT (RcvdBytes > 0);\r
+\r
+ while (RcvdBytes > 0 && !NetListIsEmpty (&Sock->RcvTokenList)) {\r
+\r
+ SockToken = NET_LIST_HEAD (\r
+ &Sock->RcvTokenList,\r
+ SOCK_TOKEN,\r
+ TokenList\r
+ );\r
+\r
+ RcvToken = (SOCK_IO_TOKEN *) SockToken->Token;\r
+ TokenRcvdBytes = SockProcessRcvToken (Sock, RcvToken);\r
+\r
+ if (0 == TokenRcvdBytes) {\r
+ return ;\r
+ }\r
+\r
+ NetListRemoveEntry (&(SockToken->TokenList));\r
+ NetFreePool (SockToken);\r
+ RcvdBytes -= TokenRcvdBytes;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Process the send token.\r
+\r
+ @param Sock Pointer to the socket.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SockProcessSndToken (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ UINT32 FreeSpace;\r
+ SOCK_TOKEN *SockToken;\r
+ UINT32 DataLen;\r
+ SOCK_IO_TOKEN *SndToken;\r
+ EFI_TCP4_TRANSMIT_DATA *TxData;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Sock && (SOCK_STREAM == Sock->Type));\r
+\r
+ FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r
+\r
+ //\r
+ // to determine if process a send token using\r
+ // socket layer flow control policy\r
+ //\r
+ while ((FreeSpace >= Sock->SndBuffer.LowWater) &&\r
+ !NetListIsEmpty (&Sock->SndTokenList)) {\r
+\r
+ SockToken = NET_LIST_HEAD (\r
+ &(Sock->SndTokenList),\r
+ SOCK_TOKEN,\r
+ TokenList\r
+ );\r
+\r
+ //\r
+ // process this token\r
+ //\r
+ NetListRemoveEntry (&(SockToken->TokenList));\r
+ NetListInsertTail (\r
+ &(Sock->ProcessingSndTokenList),\r
+ &(SockToken->TokenList)\r
+ );\r
+\r
+ //\r
+ // Proceess it in the light of SockType\r
+ //\r
+ SndToken = (SOCK_IO_TOKEN *) SockToken->Token;\r
+ TxData = SndToken->Packet.TxData;\r
+\r
+ DataLen = TxData->DataLength;\r
+ Status = SockProcessTcpSndData (Sock, TxData);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto OnError;\r
+ }\r
+\r
+ if (DataLen >= FreeSpace) {\r
+ FreeSpace = 0;\r
+\r
+ } else {\r
+ FreeSpace -= DataLen;\r
+\r
+ }\r
+ }\r
+\r
+ return ;\r
+\r
+OnError:\r
+\r
+ NetListRemoveEntry (&SockToken->TokenList);\r
+ SIGNAL_TOKEN (SockToken->Token, Status);\r
+ NetFreePool (SockToken);\r
+}\r
+\r
+\r
+/**\r
+ Create a socket with initial data SockInitData.\r
+\r
+ @param SockInitData Pointer to the initial data of the socket.\r
+\r
+ @return Pointer to the newly created socket.\r
+\r
+**/\r
+SOCKET *\r
+SockCreate (\r
+ IN SOCK_INIT_DATA *SockInitData\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+ SOCKET *Parent;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (SockInitData && SockInitData->ProtoHandler);\r
+ ASSERT (SockInitData->Type == SOCK_STREAM);\r
+\r
+ Parent = SockInitData->Parent;\r
+\r
+ if (Parent && (Parent->ConnCnt == Parent->BackLog)) {\r
+ SOCK_DEBUG_ERROR (\r
+ ("SockCreate: Socket parent has "\r
+ "reached its connection limit with %d ConnCnt and %d BackLog\n",\r
+ Parent->ConnCnt,\r
+ Parent->BackLog)\r
+ );\r
+\r
+ return NULL;\r
+ }\r
+\r
+ Sock = NetAllocateZeroPool (sizeof (SOCKET));\r
+ if (NULL == Sock) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockCreate: No resource to create a new socket\n"));\r
+ return NULL;\r
+ }\r
+\r
+ NetListInit (&Sock->ConnectionList);\r
+ NetListInit (&Sock->ListenTokenList);\r
+ NetListInit (&Sock->RcvTokenList);\r
+ NetListInit (&Sock->SndTokenList);\r
+ NetListInit (&Sock->ProcessingSndTokenList);\r
+\r
+ NET_LOCK_INIT (&(Sock->Lock));\r
+\r
+ Sock->SndBuffer.DataQueue = NetbufQueAlloc ();\r
+ if (NULL == Sock->SndBuffer.DataQueue) {\r
+ SOCK_DEBUG_ERROR (("SockCreate: No resource to allocate"\r
+ " SndBuffer for new socket\n"));\r
+\r
+ goto OnError;\r
+ }\r
+\r
+ Sock->RcvBuffer.DataQueue = NetbufQueAlloc ();\r
+ if (NULL == Sock->RcvBuffer.DataQueue) {\r
+ SOCK_DEBUG_ERROR (("SockCreate: No resource to allocate "\r
+ "RcvBuffer for new socket\n"));\r
+\r
+ goto OnError;\r
+ }\r
+\r
+ Sock->Signature = SOCK_SIGNATURE;\r
+\r
+ Sock->Parent = Parent;\r
+ Sock->BackLog = SockInitData->BackLog;\r
+ Sock->ProtoHandler = SockInitData->ProtoHandler;\r
+ Sock->SndBuffer.HighWater = SockInitData->SndBufferSize;\r
+ Sock->RcvBuffer.HighWater = SockInitData->RcvBufferSize;\r
+ Sock->Type = SockInitData->Type;\r
+ Sock->DriverBinding = SockInitData->DriverBinding;\r
+ Sock->State = SockInitData->State;\r
+\r
+ Sock->SockError = EFI_ABORTED;\r
+ Sock->SndBuffer.LowWater = SOCK_BUFF_LOW_WATER;\r
+ Sock->RcvBuffer.LowWater = SOCK_BUFF_LOW_WATER;\r
+\r
+ //\r
+ // Install protocol on Sock->SockHandle\r
+ //\r
+ NetCopyMem (\r
+ &(Sock->NetProtocol.TcpProtocol),\r
+ SockInitData->Protocol,\r
+ sizeof (EFI_TCP4_PROTOCOL)\r
+ );\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Sock->SockHandle,\r
+ &gEfiTcp4ProtocolGuid,\r
+ &(Sock->NetProtocol.TcpProtocol),\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ SOCK_DEBUG_ERROR (("SockCreate: Install TCP protocol in "\r
+ "socket failed with %r\n", Status));\r
+\r
+ goto OnError;\r
+ }\r
+\r
+ if (Parent != NULL) {\r
+ ASSERT (Parent->BackLog > 0);\r
+ ASSERT (SOCK_IS_LISTENING (Parent));\r
+\r
+ //\r
+ // need to add it into Parent->ConnectionList\r
+ // if the Parent->ConnCnt < Parent->BackLog\r
+ //\r
+ Parent->ConnCnt++;\r
+\r
+ SOCK_DEBUG_WARN (("SockCreate: Create a new socket and"\r
+ "add to parent, now conncnt is %d\n", Parent->ConnCnt));\r
+\r
+ NetListInsertTail (&Parent->ConnectionList, &Sock->ConnectionList);\r
+ }\r
+\r
+ return Sock;\r
+\r
+OnError:\r
+ if (NULL != Sock) {\r
+\r
+ if (NULL != Sock->SndBuffer.DataQueue) {\r
+ NetbufQueFree (Sock->SndBuffer.DataQueue);\r
+ }\r
+\r
+ if (NULL != Sock->RcvBuffer.DataQueue) {\r
+ NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
+ }\r
+\r
+ NetFreePool (Sock);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Destroy a socket.\r
+\r
+ @param Sock Pointer to the socket.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+SockDestroy (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ VOID *SockProtocol;\r
+ EFI_GUID *ProtocolGuid;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+ //\r
+ // Flush the completion token buffered\r
+ // by sock and rcv, snd buffer\r
+ //\r
+ if (!SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+ SockConnFlush (Sock);\r
+ SockSetState (Sock, SO_CLOSED);\r
+ Sock->ConfigureState = SO_UNCONFIGURED;\r
+\r
+ }\r
+ //\r
+ // Destory the RcvBuffer Queue and SendBuffer Queue\r
+ //\r
+ NetbufQueFree (Sock->RcvBuffer.DataQueue);\r
+ NetbufQueFree (Sock->SndBuffer.DataQueue);\r
+\r
+ //\r
+ // Remove it from parent connection list if needed\r
+ //\r
+ if (Sock->Parent) {\r
+\r
+ NetListRemoveEntry (&(Sock->ConnectionList));\r
+ (Sock->Parent->ConnCnt)--;\r
+\r
+ SOCK_DEBUG_WARN (("SockDestory: Delete a unaccepted socket from parent"\r
+ "now conncnt is %d\n", Sock->Parent->ConnCnt));\r
+\r
+ Sock->Parent = NULL;\r
+ }\r
+\r
+ //\r
+ // Set the protocol guid and driver binding handle\r
+ // in the light of Sock->SockType\r
+ //\r
+ ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
+\r
+ //\r
+ // Retrieve the protocol installed on this sock\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Sock->SockHandle,\r
+ ProtocolGuid,\r
+ &SockProtocol,\r
+ Sock->DriverBinding,\r
+ Sock->SockHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockDestroy: Open protocol installed "\r
+ "on socket failed with %r\n", Status));\r
+\r
+ goto FreeSock;\r
+ }\r
+\r
+ //\r
+ // Uninstall the protocol installed on this sock\r
+ // in the light of Sock->SockType\r
+ //\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ Sock->SockHandle,\r
+ ProtocolGuid,\r
+ SockProtocol,\r
+ NULL\r
+ );\r
+\r
+FreeSock:\r
+ NetFreePool (Sock);\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Flush the socket.\r
+\r
+ @param Sock Pointer to the socket.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+SockConnFlush (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ SOCKET *Child;\r
+\r
+ ASSERT (Sock);\r
+\r
+ //\r
+ // Clear the flag in this socket\r
+ //\r
+ Sock->Flag = 0;\r
+\r
+ //\r
+ // Flush the SndBuffer and RcvBuffer of Sock\r
+ //\r
+ NetbufQueFlush (Sock->SndBuffer.DataQueue);\r
+ NetbufQueFlush (Sock->RcvBuffer.DataQueue);\r
+\r
+ //\r
+ // Signal the pending token\r
+ //\r
+ if (Sock->ConnectionToken != NULL) {\r
+ SIGNAL_TOKEN (Sock->ConnectionToken, Sock->SockError);\r
+ Sock->ConnectionToken = NULL;\r
+ }\r
+\r
+ if (Sock->CloseToken != NULL) {\r
+ SIGNAL_TOKEN (Sock->CloseToken, Sock->SockError);\r
+ Sock->CloseToken = NULL;\r
+ }\r
+\r
+ SockFlushPendingToken (Sock, &(Sock->ListenTokenList));\r
+ SockFlushPendingToken (Sock, &(Sock->RcvTokenList));\r
+ SockFlushPendingToken (Sock, &(Sock->SndTokenList));\r
+ SockFlushPendingToken (Sock, &(Sock->ProcessingSndTokenList));\r
+\r
+ //\r
+ // Destroy the pending connection, if it is a listening socket\r
+ //\r
+ if (SOCK_IS_LISTENING (Sock)) {\r
+ while (!NetListIsEmpty (&Sock->ConnectionList)) {\r
+ Child = NET_LIST_HEAD (\r
+ &Sock->ConnectionList,\r
+ SOCKET,\r
+ ConnectionList\r
+ );\r
+\r
+ SockDestroyChild (Child);\r
+ }\r
+\r
+ Sock->ConnCnt = 0;\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Set the state of the socket.\r
+\r
+ @param Sock Pointer to the socket.\r
+ @param State The new state to be set.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+SockSetState (\r
+ IN SOCKET *Sock,\r
+ IN SOCK_STATE State\r
+ )\r
+{\r
+ Sock->State = State;\r
+}\r
+\r
+\r
+/**\r
+ Clone a new socket including its associated protocol control block.\r
+\r
+ @param Sock Pointer to the socket to be cloned.\r
+\r
+ @retval * Pointer to the newly cloned socket. If NULL, error\r
+ condition occurred.\r
+\r
+**/\r
+SOCKET *\r
+SockClone (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ SOCKET *ClonedSock;\r
+ SOCK_INIT_DATA InitData;\r
+\r
+ InitData.BackLog = Sock->BackLog;\r
+ InitData.Parent = Sock;\r
+ InitData.State = Sock->State;\r
+ InitData.ProtoHandler = Sock->ProtoHandler;\r
+ InitData.Type = Sock->Type;\r
+ InitData.RcvBufferSize = Sock->RcvBuffer.HighWater;\r
+ InitData.SndBufferSize = Sock->SndBuffer.HighWater;\r
+ InitData.DriverBinding = Sock->DriverBinding;\r
+ InitData.Protocol = &(Sock->NetProtocol);\r
+\r
+ ClonedSock = SockCreate (&InitData);\r
+\r
+ if (NULL == ClonedSock) {\r
+ SOCK_DEBUG_ERROR (("SockClone: no resource to create a cloned sock\n"));\r
+ return NULL;\r
+ }\r
+\r
+ NetCopyMem (\r
+ ClonedSock->ProtoReserved,\r
+ Sock->ProtoReserved,\r
+ PROTO_RESERVED_LEN\r
+ );\r
+\r
+ SockSetState (ClonedSock, SO_CONNECTING);\r
+ ClonedSock->ConfigureState = Sock->ConfigureState;\r
+\r
+ return ClonedSock;\r
+}\r
+\r
+\r
+/**\r
+ Called by the low layer protocol to indicate the socket\r
+ a connection is established. This function just changes\r
+ the socket's state to SO_CONNECTED and signals the token\r
+ used for connection establishment.\r
+\r
+ @param Sock Pointer to the socket associated with the\r
+ established connection.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+SockConnEstablished (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+\r
+ ASSERT (SO_CONNECTING == Sock->State);\r
+\r
+ SockSetState (Sock, SO_CONNECTED);\r
+\r
+ if (NULL == Sock->Parent) {\r
+ SockWakeConnToken (Sock);\r
+ } else {\r
+ SockWakeListenToken (Sock);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Called by the low layer protocol to indicate the connection\r
+ is closed. This function flushes the socket, sets the state\r
+ to SO_CLOSED and signals the close token.\r
+\r
+ @param Sock Pointer to the socket associated with the closed\r
+ connection.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+SockConnClosed (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ if (Sock->CloseToken) {\r
+ SIGNAL_TOKEN (Sock->CloseToken, EFI_SUCCESS);\r
+ Sock->CloseToken = NULL;\r
+ }\r
+\r
+ SockConnFlush (Sock);\r
+ SockSetState (Sock, SO_CLOSED);\r
+\r
+ if (Sock->Parent != NULL) {\r
+ SockDestroyChild (Sock);\r
+ }\r
+\r
+}\r
+\r
+\r
+/**\r
+ Called by low layer protocol to indicate that some\r
+ data is sent or processed. This function trims the\r
+ sent data in the socket send buffer, signals the\r
+ data token if proper\r
+\r
+ @param Sock Pointer to the socket.\r
+ @param Count The length of the data processed or sent, in bytes.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+SockDataSent (\r
+ IN SOCKET *Sock,\r
+ IN UINT32 Count\r
+ )\r
+{\r
+ SOCK_TOKEN *SockToken;\r
+ SOCK_COMPLETION_TOKEN *SndToken;\r
+\r
+ ASSERT (!NetListIsEmpty (&Sock->ProcessingSndTokenList));\r
+ ASSERT (Count <= (Sock->SndBuffer.DataQueue)->BufSize);\r
+\r
+ NetbufQueTrim (Sock->SndBuffer.DataQueue, Count);\r
+\r
+ //\r
+ // To check if we can signal some snd token in this socket\r
+ //\r
+ while (Count > 0) {\r
+ SockToken = NET_LIST_HEAD (\r
+ &(Sock->ProcessingSndTokenList),\r
+ SOCK_TOKEN,\r
+ TokenList\r
+ );\r
+\r
+ SndToken = SockToken->Token;\r
+\r
+ if (SockToken->RemainDataLen <= Count) {\r
+\r
+ NetListRemoveEntry (&(SockToken->TokenList));\r
+ SIGNAL_TOKEN (SndToken, EFI_SUCCESS);\r
+ Count -= SockToken->RemainDataLen;\r
+ NetFreePool (SockToken);\r
+ } else {\r
+\r
+ SockToken->RemainDataLen -= Count;\r
+ Count = 0;\r
+ }\r
+ }\r
+\r
+ //\r
+ // to judge if we can process some send token in\r
+ // Sock->SndTokenList, if so process those send token\r
+ //\r
+ SockProcessSndToken (Sock);\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Called by the low layer protocol to copy some data in socket send\r
+ buffer starting from the specific offset to a buffer provided by\r
+ the caller.\r
+\r
+ @param Sock Pointer to the socket.\r
+ @param Offset The start point of the data to be copied.\r
+ @param Len The length of the data to be copied.\r
+ @param Dest Pointer to the destination to copy the data.\r
+\r
+ @return The data size copied.\r
+\r
+**/\r
+UINT32\r
+SockGetDataToSend (\r
+ IN SOCKET *Sock,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Len,\r
+ IN UINT8 *Dest\r
+ )\r
+{\r
+ ASSERT (Sock && SOCK_STREAM == Sock->Type);\r
+\r
+ return NetbufQueCopy (\r
+ Sock->SndBuffer.DataQueue,\r
+ Offset,\r
+ Len,\r
+ Dest\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Called by the low layer protocol to deliver received data\r
+ to socket layer. This function will append the data to the\r
+ socket receive buffer, set ther urgent data length and then\r
+ check if any receive token can be signaled.\r
+\r
+ @param Sock Pointer to the socket.\r
+ @param NetBuffer Pointer to the buffer that contains the received\r
+ data.\r
+ @param UrgLen The length of the urgent data in the received data.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+SockDataRcvd (\r
+ IN SOCKET *Sock,\r
+ IN NET_BUF *NetBuffer,\r
+ IN UINT32 UrgLen\r
+ )\r
+{\r
+ ASSERT (Sock && Sock->RcvBuffer.DataQueue &&\r
+ UrgLen <= NetBuffer->TotalSize);\r
+\r
+ NET_GET_REF (NetBuffer);\r
+\r
+ ((TCP_RSV_DATA *) (NetBuffer->ProtoData))->UrgLen = UrgLen;\r
+\r
+ NetbufQueAppend (Sock->RcvBuffer.DataQueue, NetBuffer);\r
+\r
+ SockWakeRcvToken (Sock);\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Get the length of the free space of the specific socket buffer.\r
+\r
+ @param Sock Pointer to the socket.\r
+ @param Which Flag to indicate which socket buffer to check,\r
+ either send buffer or receive buffer.\r
+\r
+ @return The length of the free space, in bytes.\r
+\r
+**/\r
+UINT32\r
+SockGetFreeSpace (\r
+ IN SOCKET *Sock,\r
+ IN UINT32 Which\r
+ )\r
+{\r
+ UINT32 BufferCC;\r
+ SOCK_BUFFER *SockBuffer;\r
+\r
+ ASSERT (Sock && ((SOCK_SND_BUF == Which) || (SOCK_RCV_BUF == Which)));\r
+\r
+ if (SOCK_SND_BUF == Which) {\r
+ SockBuffer = &(Sock->SndBuffer);\r
+ } else {\r
+ SockBuffer = &(Sock->RcvBuffer);\r
+ }\r
+\r
+ BufferCC = (SockBuffer->DataQueue)->BufSize;\r
+\r
+ if (BufferCC >= SockBuffer->HighWater) {\r
+\r
+ return 0;\r
+ }\r
+\r
+ return SockBuffer->HighWater - BufferCC;\r
+}\r
+\r
+\r
+/**\r
+ Signal the receive token with the specific error or\r
+ set socket error code after error is received.\r
+\r
+ @param Sock Pointer to the socket.\r
+ @param Error The error code received.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+SockRcvdErr (\r
+ IN SOCKET *Sock,\r
+ IN EFI_STATUS Error\r
+ )\r
+{\r
+ SOCK_TOKEN *SockToken;\r
+\r
+ if (!NetListIsEmpty (&Sock->RcvTokenList)) {\r
+\r
+ SockToken = NET_LIST_HEAD (\r
+ &Sock->RcvTokenList,\r
+ SOCK_TOKEN,\r
+ TokenList\r
+ );\r
+\r
+ NetListRemoveEntry (&SockToken->TokenList);\r
+\r
+ SIGNAL_TOKEN (SockToken->Token, Error);\r
+\r
+ NetFreePool (SockToken);\r
+ } else {\r
+\r
+ SOCK_ERROR (Sock, Error);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Called by the low layer protocol to indicate that there\r
+ will be no more data from the communication peer. This\r
+ function set the socket's state to SO_NO_MORE_DATA and\r
+ signal all queued IO tokens with the error status\r
+ EFI_CONNECTION_FIN.\r
+\r
+ @param Sock Pointer to the socket.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+SockNoMoreData (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ EFI_STATUS Err;\r
+\r
+ SOCK_NO_MORE_DATA (Sock);\r
+\r
+ if (!NetListIsEmpty (&Sock->RcvTokenList)) {\r
+\r
+ ASSERT (0 == GET_RCV_DATASIZE (Sock));\r
+\r
+ Err = Sock->SockError;\r
+\r
+ SOCK_ERROR (Sock, EFI_CONNECTION_FIN);\r
+\r
+ SockFlushPendingToken (Sock, &Sock->RcvTokenList);\r
+\r
+ SOCK_ERROR (Sock, Err);\r
+\r
+ }\r
+\r
+}\r
+\r
+\r
+/**\r
+ Get the first buffer block in the specific socket buffer.\r
+\r
+ @param Sockbuf Pointer to the socket buffer.\r
+\r
+ @return Pointer to the first buffer in the queue. NULL if the queue is empty.\r
+\r
+**/\r
+NET_BUF *\r
+SockBufFirst (\r
+ IN SOCK_BUFFER *Sockbuf\r
+ )\r
+{\r
+ NET_LIST_ENTRY *NetbufList;\r
+\r
+ NetbufList = &(Sockbuf->DataQueue->BufList);\r
+\r
+ if (NetListIsEmpty (NetbufList)) {\r
+ return NULL;\r
+ }\r
+\r
+ return NET_LIST_HEAD (NetbufList, NET_BUF, List);\r
+}\r
+\r
+\r
+/**\r
+ Get the next buffer block in the specific socket buffer.\r
+\r
+ @param Sockbuf Pointer to the socket buffer.\r
+ @param SockEntry Pointer to the buffer block prior to the required\r
+ one.\r
+\r
+ @return Pointer to the buffer block next to SockEntry. NULL if SockEntry is the tail or head entry.\r
+\r
+**/\r
+NET_BUF *\r
+SockBufNext (\r
+ IN SOCK_BUFFER *Sockbuf,\r
+ IN NET_BUF *SockEntry\r
+ )\r
+{\r
+ NET_LIST_ENTRY *NetbufList;\r
+\r
+ NetbufList = &(Sockbuf->DataQueue->BufList);\r
+\r
+ if ((SockEntry->List.ForwardLink == NetbufList) ||\r
+ (SockEntry->List.BackLink == &SockEntry->List) ||\r
+ (SockEntry->List.ForwardLink == &SockEntry->List)\r
+ ) {\r
+\r
+ return NULL;\r
+ }\r
+\r
+ return NET_LIST_USER_STRUCT (SockEntry->List.ForwardLink, NET_BUF, List);\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 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:
+
+ SockImpl.h
+
+Abstract:
+
+
+**/
+
+#ifndef _SOCK_IMPL_H_
+#define _SOCK_IMPL_H_
+
+#include "Socket.h"
+
+#define SOCK_DEBUG_ERROR(PrintArg) NET_DEBUG_ERROR("Sock", PrintArg)
+#define SOCK_DEBUG_WARN(PrintArg) NET_DEBUG_WARNING("Sock", PrintArg)
+#define SOCK_DEBUG_TRACE(PrintArg) NET_DEBUG_TRACE("Sock", PrintArg)
+
+#define SOCK_TRIM_RCV_BUFF(Sock, Len) \
+ (NetbufQueTrim ((Sock)->RcvBuffer.DataQueue, (Len)))
+
+#define SIGNAL_TOKEN(Token, TokenStatus) \
+ do { \
+ (Token)->Status = (TokenStatus); \
+ gBS->SignalEvent ((Token)->Event); \
+ } while (0)
+
+#define SOCK_HEADER_SPACE (60 + 60 + 72)
+
+//
+// Supporting function for both SockImpl and SockInterface
+//
+VOID
+SockFreeFoo (
+ IN EFI_EVENT Event
+ );
+
+EFI_STATUS
+SockProcessTcpSndData (
+ IN SOCKET *Sock,
+ IN VOID *TcpTxData
+ );
+
+VOID
+SockSetTcpRxData (
+ IN SOCKET *Sock,
+ IN VOID *TcpRxData,
+ IN UINT32 RcvdBytes,
+ IN BOOLEAN IsOOB
+ );
+
+UINT32
+SockProcessRcvToken (
+ IN SOCKET *Sock,
+ IN SOCK_IO_TOKEN *RcvToken
+ );
+
+VOID
+SockConnFlush (
+ IN SOCKET *Sock
+ );
+
+SOCKET *
+SockCreate (
+ IN SOCK_INIT_DATA *SockInitData
+ );
+
+VOID
+SockDestroy (
+ IN SOCKET *Sock
+ );
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ SockInterface.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "SockImpl.h"\r
+\r
+\r
+/**\r
+ Check whether the Event is in the List.\r
+\r
+ @param List Pointer to the token list to be searched.\r
+ @param Event The event to be checked.\r
+\r
+ @retval BOOLEAN If TRUE, the specific Event exists in the List. If\r
+ FALSE, the specific Event is not in the List.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+SockTokenExistedInList (\r
+ IN NET_LIST_ENTRY *List,\r
+ IN EFI_EVENT Event\r
+ )\r
+{\r
+ NET_LIST_ENTRY *ListEntry;\r
+ SOCK_TOKEN *SockToken;\r
+\r
+ NET_LIST_FOR_EACH (ListEntry, List) {\r
+ SockToken = NET_LIST_USER_STRUCT (\r
+ ListEntry,\r
+ SOCK_TOKEN,\r
+ TokenList\r
+ );\r
+\r
+ if (Event == SockToken->Token->Event) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Call SockTokenExistedInList() to check whether the Event is\r
+ in the related socket's lists.\r
+\r
+ @param Sock Pointer to the instance's socket.\r
+ @param Event The event to be checked.\r
+\r
+ @return The specific Event exists in one of socket's lists or not.\r
+\r
+**/\r
+BOOLEAN\r
+SockTokenExisted (\r
+ IN SOCKET *Sock,\r
+ IN EFI_EVENT Event\r
+ )\r
+{\r
+\r
+ if (SockTokenExistedInList (&Sock->SndTokenList, Event) ||\r
+ SockTokenExistedInList (&Sock->ProcessingSndTokenList, Event) ||\r
+ SockTokenExistedInList (&Sock->RcvTokenList, Event) ||\r
+ SockTokenExistedInList (&Sock->ListenTokenList, Event)\r
+ ) {\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ if ((Sock->ConnectionToken != NULL) &&\r
+ (Sock->ConnectionToken->Event == Event)) {\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ if ((Sock->CloseToken != NULL) && (Sock->CloseToken->Event == Event)) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Buffer a token into the specific list of socket Sock.\r
+\r
+ @param Sock Pointer to the instance's socket.\r
+ @param List Pointer to the list to store the token.\r
+ @param Token Pointer to the token to be buffered.\r
+ @param DataLen The data length of the buffer contained in Token.\r
+\r
+ @return Pointer to the token that wraps Token. If NULL, error condition occurred.\r
+\r
+**/\r
+SOCK_TOKEN *\r
+SockBufferToken (\r
+ IN SOCKET *Sock,\r
+ IN NET_LIST_ENTRY *List,\r
+ IN VOID *Token,\r
+ IN UINT32 DataLen\r
+ )\r
+{\r
+ SOCK_TOKEN *SockToken;\r
+\r
+ SockToken = NetAllocatePool (sizeof (SOCK_TOKEN));\r
+ if (NULL == SockToken) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockBufferIOToken: No Memory "\r
+ "to allocate SockToken\n"));\r
+\r
+ return NULL;\r
+ }\r
+\r
+ SockToken->Sock = Sock;\r
+ SockToken->Token = (SOCK_COMPLETION_TOKEN *) Token;\r
+ SockToken->RemainDataLen = DataLen;\r
+ NetListInsertTail (List, &SockToken->TokenList);\r
+\r
+ return SockToken;\r
+}\r
+\r
+\r
+/**\r
+ Destory the socket Sock and its associated protocol control block.\r
+\r
+ @param Sock The socket to be destroyed.\r
+\r
+ @retval EFI_SUCCESS The socket Sock is destroyed successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
+\r
+**/\r
+EFI_STATUS\r
+SockDestroyChild (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Sock && Sock->ProtoHandler);\r
+\r
+ if (Sock->IsDestroyed) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Sock->IsDestroyed = TRUE;\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockDestroyChild: Get the lock to "\r
+ "access socket failed with %r\n", Status));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ //\r
+ // force protocol layer to detach the PCB\r
+ //\r
+ Status = Sock->ProtoHandler (Sock, SOCK_DETACH, NULL);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockDestroyChild: Protocol detach socket"\r
+ " failed with %r\n", Status));\r
+\r
+ Sock->IsDestroyed = FALSE;\r
+ } else if (SOCK_IS_CONFIGURED (Sock)) {\r
+\r
+ SockConnFlush (Sock);\r
+ SockSetState (Sock, SO_CLOSED);\r
+\r
+ Sock->ConfigureState = SO_UNCONFIGURED;\r
+ }\r
+\r
+ NET_UNLOCK (&(Sock->Lock));\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SockDestroy (Sock);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Create a socket and its associated protocol control block\r
+ with the intial data SockInitData and protocol specific\r
+ data ProtoData.\r
+\r
+ @param SockInitData Inital data to setting the socket.\r
+ @param ProtoData Pointer to the protocol specific data.\r
+ @param Len Length of the protocol specific data.\r
+\r
+ @return Pointer to the newly created socket. If NULL, error condition occured.\r
+\r
+**/\r
+SOCKET *\r
+SockCreateChild (\r
+ IN SOCK_INIT_DATA *SockInitData,\r
+ IN VOID *ProtoData,\r
+ IN UINT32 Len\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (ProtoData && (Len <= PROTO_RESERVED_LEN));\r
+\r
+ //\r
+ // create a new socket\r
+ //\r
+ Sock = SockCreate (SockInitData);\r
+ if (NULL == Sock) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockCreateChild: No resource to "\r
+ "create a new socket\n"));\r
+\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Open the\r
+ //\r
+\r
+ //\r
+ // copy the protodata into socket\r
+ //\r
+ NetCopyMem (Sock->ProtoReserved, ProtoData, Len);\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockCreateChild: Get the lock to "\r
+ "access socket failed with %r\n", Status));\r
+\r
+ SockDestroy (Sock);\r
+ return NULL;\r
+ }\r
+ //\r
+ // inform the protocol layer to attach the socket\r
+ // with a new protocol control block\r
+ //\r
+ Status = Sock->ProtoHandler (Sock, SOCK_ATTACH, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockCreateChild: Protocol failed to"\r
+ " attach a socket with %r\n", Status));\r
+\r
+ SockDestroy (Sock);\r
+ Sock = NULL;\r
+ }\r
+\r
+ NET_UNLOCK (&(Sock->Lock));\r
+ return Sock;\r
+}\r
+\r
+\r
+/**\r
+ Configure the specific socket Sock using configuration data\r
+ ConfigData.\r
+\r
+ @param Sock Pointer to the socket to be configured.\r
+ @param ConfigData Pointer to the configuration data.\r
+\r
+ @retval EFI_SUCCESS The socket is configured successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket or the\r
+ socket is already configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockConfigure (\r
+ IN SOCKET *Sock,\r
+ IN VOID *ConfigData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockConfigure: Get the access for "\r
+ "socket failed with %r", Status));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_CONFIGURED (Sock)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto OnExit;\r
+ }\r
+\r
+ ASSERT (Sock->State == SO_CLOSED);\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_CONFIGURE, ConfigData);\r
+\r
+OnExit:\r
+ NET_UNLOCK (&(Sock->Lock));\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Initiate a connection establishment process.\r
+\r
+ @param Sock Pointer to the socket to initiate the initate the\r
+ connection.\r
+ @param Token Pointer to the token used for the connection\r
+ operation.\r
+\r
+ @retval EFI_SUCCESS The connection is initialized successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is closed, or the socket is not configured to\r
+ be an active one, or the token is already in one of\r
+ this socket's lists.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockConnect (\r
+ IN SOCKET *Sock,\r
+ IN VOID *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockConnect: Get the access for "\r
+ "socket failed with %r", Status));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto OnExit;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto OnExit;\r
+ }\r
+\r
+ if (!SOCK_IS_CLOSED (Sock) || !SOCK_IS_CONFIGURED_ACTIVE (Sock)) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto OnExit;\r
+ }\r
+\r
+ Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
+\r
+ if (SockTokenExisted (Sock, Event)) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto OnExit;\r
+ }\r
+\r
+ Sock->ConnectionToken = (SOCK_COMPLETION_TOKEN *) Token;\r
+ SockSetState (Sock, SO_CONNECTING);\r
+ Status = Sock->ProtoHandler (Sock, SOCK_CONNECT, NULL);\r
+\r
+OnExit:\r
+ NET_UNLOCK (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Issue a listen token to get an existed connected network instance\r
+ or wait for a connection if there is none.\r
+\r
+ @param Sock Pointer to the socket to accept connections.\r
+ @param Token The token to accept a connection.\r
+\r
+ @retval EFI_SUCCESS Either a connection is accpeted or the Token is\r
+ buffered for further acception.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is closed, or the socket is not configured to\r
+ be a passive one, or the token is already in one of\r
+ this socket's lists.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+ @retval EFI_OUT_OF_RESOURCE Failed to buffer the Token due to memory limit.\r
+\r
+**/\r
+EFI_STATUS\r
+SockAccept (\r
+ IN SOCKET *Sock,\r
+ IN VOID *Token\r
+ )\r
+{\r
+ EFI_TCP4_LISTEN_TOKEN *ListenToken;\r
+ NET_LIST_ENTRY *ListEntry;\r
+ EFI_STATUS Status;\r
+ SOCKET *Socket;\r
+ EFI_EVENT Event;\r
+\r
+ ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockAccept: Get the access for socket"\r
+ " failed with %r", Status));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto Exit;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ if (!SOCK_IS_LISTENING (Sock)) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
+\r
+ if (SockTokenExisted (Sock, Event)) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ ListenToken = (EFI_TCP4_LISTEN_TOKEN *) Token;\r
+\r
+ //\r
+ // Check if a connection has already in this Sock->ConnectionList\r
+ //\r
+ NET_LIST_FOR_EACH (ListEntry, &Sock->ConnectionList) {\r
+\r
+ Socket = NET_LIST_USER_STRUCT (ListEntry, SOCKET, ConnectionList);\r
+\r
+ if (SOCK_IS_CONNECTED (Socket)) {\r
+ ListenToken->NewChildHandle = Socket->SockHandle;\r
+ SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);\r
+\r
+ NetListRemoveEntry (ListEntry);\r
+\r
+ ASSERT (Socket->Parent);\r
+\r
+ Socket->Parent->ConnCnt--;\r
+\r
+ SOCK_DEBUG_WARN (("SockAccept: Accept a socket,"\r
+ "now conncount is %d", Socket->Parent->ConnCnt)\r
+ );\r
+ Socket->Parent = NULL;\r
+\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Buffer this token for latter incoming connection request\r
+ //\r
+ if (NULL == SockBufferToken (Sock, &(Sock->ListenTokenList), Token, 0)) {\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+Exit:\r
+ NET_UNLOCK (&(Sock->Lock));\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Issue a token with data to the socket to send out.\r
+\r
+ @param Sock Pointer to the socket to process the token with\r
+ data.\r
+ @param Token The token with data that needs to send out.\r
+\r
+ @retval EFI_SUCCESS The token is processed successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is closed, or the socket is not in a\r
+ synchronized state , or the token is already in one\r
+ of this socket's lists.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+ @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.\r
+\r
+**/\r
+EFI_STATUS\r
+SockSend (\r
+ IN SOCKET *Sock,\r
+ IN VOID *Token\r
+ )\r
+{\r
+ SOCK_IO_TOKEN *SndToken;\r
+ EFI_EVENT Event;\r
+ UINT32 FreeSpace;\r
+ EFI_TCP4_TRANSMIT_DATA *TxData;\r
+ EFI_STATUS Status;\r
+ SOCK_TOKEN *SockToken;\r
+ UINT32 DataLen;\r
+\r
+ ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockSend: Get the access for socket"\r
+ " failed with %r", Status));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto Exit;\r
+ }\r
+\r
+ SndToken = (SOCK_IO_TOKEN *) Token;\r
+ TxData = (EFI_TCP4_TRANSMIT_DATA *) SndToken->Packet.TxData;\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ if (!(SOCK_IS_CONNECTING (Sock) || SOCK_IS_CONNECTED (Sock))) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // check if a token is already in the token buffer\r
+ //\r
+ Event = SndToken->Token.Event;\r
+\r
+ if (SockTokenExisted (Sock, Event)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ DataLen = TxData->DataLength;\r
+\r
+ //\r
+ // process this sending token now or buffer it only?\r
+ //\r
+ FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r
+\r
+ if ((FreeSpace < Sock->SndBuffer.LowWater) || !SOCK_IS_CONNECTED (Sock)) {\r
+\r
+ SockToken = SockBufferToken (\r
+ Sock,\r
+ &Sock->SndTokenList,\r
+ SndToken,\r
+ DataLen\r
+ );\r
+\r
+ if (NULL == SockToken) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+\r
+ SockToken = SockBufferToken (\r
+ Sock,\r
+ &Sock->ProcessingSndTokenList,\r
+ SndToken,\r
+ DataLen\r
+ );\r
+\r
+ if (NULL == SockToken) {\r
+ SOCK_DEBUG_ERROR (("SockSend: Failed to buffer IO token into"\r
+ " socket processing SndToken List\n", Status));\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ Status = SockProcessTcpSndData (Sock, TxData);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ SOCK_DEBUG_ERROR (("SockSend: Failed to process "\r
+ "Snd Data\n", Status));\r
+\r
+ NetListRemoveEntry (&(SockToken->TokenList));\r
+ NetFreePool (SockToken);\r
+ }\r
+ }\r
+\r
+Exit:\r
+ NET_UNLOCK (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Issue a token to get data from the socket.\r
+\r
+ @param Sock Pointer to the socket to get data from.\r
+ @param Token The token to store the received data from the\r
+ socket.\r
+\r
+ @retval EFI_SUCCESS The token is processed successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is closed, or the socket is not in a\r
+ synchronized state , or the token is already in one\r
+ of this socket's lists.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+ @retval EFI_CONNECTION_FIN The connection is closed and there is no more data.\r
+ @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.\r
+\r
+**/\r
+EFI_STATUS\r
+SockRcv (\r
+ IN SOCKET *Sock,\r
+ IN VOID *Token\r
+ )\r
+{\r
+ SOCK_IO_TOKEN *RcvToken;\r
+ UINT32 RcvdBytes;\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+\r
+ ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockRcv: Get the access for socket"\r
+ " failed with %r", Status));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+\r
+ Status = EFI_NO_MAPPING;\r
+ goto Exit;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ if (!(SOCK_IS_CONNECTED (Sock) || SOCK_IS_CONNECTING (Sock))) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ RcvToken = (SOCK_IO_TOKEN *) Token;\r
+\r
+ //\r
+ // check if a token is already in the token buffer of this socket\r
+ //\r
+ Event = RcvToken->Token.Event;\r
+ if (SockTokenExisted (Sock, Event)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ RcvToken = (SOCK_IO_TOKEN *) Token;\r
+ RcvdBytes = GET_RCV_DATASIZE (Sock);\r
+\r
+ //\r
+ // check whether an error has happened before\r
+ //\r
+ if (EFI_ABORTED != Sock->SockError) {\r
+\r
+ SIGNAL_TOKEN (&(RcvToken->Token), Sock->SockError);\r
+ Sock->SockError = EFI_ABORTED;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // check whether can not receive and there is no any\r
+ // data buffered in Sock->RcvBuffer\r
+ //\r
+ if (SOCK_IS_NO_MORE_DATA (Sock) && (0 == RcvdBytes)) {\r
+\r
+ Status = EFI_CONNECTION_FIN;\r
+ goto Exit;\r
+ }\r
+\r
+ if (RcvdBytes != 0) {\r
+ Status = SockProcessRcvToken (Sock, RcvToken);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_CONSUMED, NULL);\r
+ } else {\r
+\r
+ if (NULL == SockBufferToken (Sock, &Sock->RcvTokenList, RcvToken, 0)) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+Exit:\r
+ NET_UNLOCK (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Reset the socket and its associated protocol control block.\r
+\r
+ @param Sock Pointer to the socket to be flushed.\r
+\r
+ @retval EFI_SUCCESS The socket is flushed successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
+\r
+**/\r
+EFI_STATUS\r
+SockFlush (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockFlush: Get the access for socket"\r
+ " failed with %r", Status));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (!SOCK_IS_CONFIGURED (Sock)) {\r
+ goto Exit;\r
+ }\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_FLUSH, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockFlush: Protocol failed handling"\r
+ " SOCK_FLUSH with %r", Status));\r
+\r
+ goto Exit;\r
+ }\r
+\r
+ SOCK_ERROR (Sock, EFI_ABORTED);\r
+ SockConnFlush (Sock);\r
+ SockSetState (Sock, SO_CLOSED);\r
+\r
+ Sock->ConfigureState = SO_UNCONFIGURED;\r
+\r
+Exit:\r
+ NET_UNLOCK (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Close or abort the socket associated connection.\r
+\r
+ @param Sock Pointer to the socket of the connection to close or\r
+ abort.\r
+ @param Token The token for close operation.\r
+ @param OnAbort TRUE for aborting the connection, FALSE to close it.\r
+\r
+ @retval EFI_SUCCESS The close or abort operation is initialized\r
+ successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is closed, or the socket is not in a\r
+ synchronized state , or the token is already in one\r
+ of this socket's lists.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockClose (\r
+ IN SOCKET *Sock,\r
+ IN VOID *Token,\r
+ IN BOOLEAN OnAbort\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+\r
+ ASSERT (SOCK_STREAM == Sock->Type);\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+ SOCK_DEBUG_ERROR (("SockClose: Get the access for socket"\r
+ " failed with %r", Status));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto Exit;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ if (SOCK_IS_DISCONNECTING (Sock)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
+\r
+ if (SockTokenExisted (Sock, Event)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ Sock->CloseToken = Token;\r
+ SockSetState (Sock, SO_DISCONNECTING);\r
+\r
+ if (OnAbort) {\r
+ Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);\r
+ } else {\r
+ Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);\r
+ }\r
+\r
+Exit:\r
+ NET_UNLOCK (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Get the mode data of the low layer protocol.\r
+\r
+ @param Sock Pointer to the socket to get mode data from.\r
+ @param Mode Pointer to the data to store the low layer mode\r
+ information.\r
+\r
+ @retval EFI_SUCCESS The mode data is got successfully.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockGetMode (\r
+ IN SOCKET *Sock,\r
+ IN VOID *Mode\r
+ )\r
+{\r
+ return Sock->ProtoHandler (Sock, SOCK_MODE, Mode);\r
+}\r
+\r
+\r
+/**\r
+ Configure the low level protocol to join a multicast group for\r
+ this socket's connection.\r
+\r
+ @param Sock Pointer to the socket of the connection to join the\r
+ specific multicast group.\r
+ @param GroupInfo Pointer to the multicast group info.\r
+\r
+ @retval EFI_SUCCESS The configuration is done successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockGroup (\r
+ IN SOCKET *Sock,\r
+ IN VOID *GroupInfo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ SOCK_DEBUG_ERROR (("SockGroup: Get the access for socket"\r
+ " failed with %r", Status));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_GROUP, GroupInfo);\r
+\r
+Exit:\r
+ NET_UNLOCK (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Add or remove route information in IP route table associated\r
+ with this socket.\r
+\r
+ @param Sock Pointer to the socket associated with the IP route\r
+ table to operate on.\r
+ @param RouteInfo Pointer to the route information to be processed.\r
+\r
+ @retval EFI_SUCCESS The route table is updated successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockRoute (\r
+ IN SOCKET *Sock,\r
+ IN VOID *RouteInfo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = NET_TRYLOCK (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+ SOCK_DEBUG_ERROR (("SockRoute: Get the access for socket"\r
+ " failed with %r", Status));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto Exit;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_ROUTE, RouteInfo);\r
+\r
+Exit:\r
+ NET_UNLOCK (&(Sock->Lock));\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 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:
+
+ Socket.h
+
+Abstract:
+
+
+**/
+
+#ifndef _SOCKET_H_
+#define _SOCKET_H_
+
+#include <PiDxe.h>\r
+\r
+#include <Protocol/IP4.h>\r
+#include <Protocol/Tcp4.h>
+#include <Protocol/Udp4.h>\r
+
+#include <Library/NetLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#define SOCK_SND_BUF 0
+#define SOCK_RCV_BUF 1
+
+#define SOCK_BUFF_LOW_WATER 2 * 1024
+#define SOCK_RCV_BUFF_SIZE 8 * 1024
+#define SOCK_SND_BUFF_SIZE 8 * 1024
+#define SOCK_BACKLOG 5
+
+#define PROTO_RESERVED_LEN 20
+
+#define SO_NO_MORE_DATA 0x0001
+
+//
+//
+//
+// When a socket is created it enters into SO_UNCONFIGURED,
+// no actions can be taken on this socket, only after calling
+// SockConfigure. The state transition diagram of socket is
+// as following:
+//
+// SO_UNCONFIGURED --- SO_CONFIGURED --- SO_CONNECTING
+// ^ | |
+// | ---> SO_LISTENING |
+// | |
+// |------------------SO_DISCONNECTING<-- SO_CONNECTED
+//
+// A passive socket can only go into SO_LISTENING and
+// SO_UNCONFIGURED state. SO_XXXING state is a middle state
+// when a socket is undergoing a protocol procedure such
+// as requesting a TCP connection.
+//
+//
+//
+typedef enum {
+ SO_CLOSED = 0,
+ SO_LISTENING,
+ SO_CONNECTING,
+ SO_CONNECTED,
+ SO_DISCONNECTING
+} SOCK_STATE;
+
+typedef enum {
+ SO_UNCONFIGURED = 0,
+ SO_CONFIGURED_ACTIVE,
+ SO_CONFIGURED_PASSIVE,
+ SO_NO_MAPPING
+} SOCK_CONFIGURE_STATE;
+
+#define SOCK_NO_MORE_DATA(Sock) ((Sock)->Flag |= SO_NO_MORE_DATA)
+
+#define SOCK_IS_UNCONFIGURED(Sock) ((Sock)->ConfigureState == SO_UNCONFIGURED)
+
+#define SOCK_IS_CONFIGURED(Sock) \
+ (((Sock)->ConfigureState == SO_CONFIGURED_ACTIVE) || \
+ ((Sock)->ConfigureState == SO_CONFIGURED_PASSIVE))
+
+#define SOCK_IS_CONFIGURED_ACTIVE(Sock) \
+ ((Sock)->ConfigureState == SO_CONFIGURED_ACTIVE)
+
+#define SOCK_IS_CONNECTED_PASSIVE(Sock) \
+ ((Sock)->ConfigureState == SO_CONFIGURED_PASSIVE)
+
+#define SOCK_IS_NO_MAPPING(Sock) \
+ ((Sock)->ConfigureState == SO_NO_MAPPING)
+
+#define SOCK_IS_CLOSED(Sock) ((Sock)->State == SO_CLOSED)
+
+#define SOCK_IS_LISTENING(Sock) ((Sock)->State == SO_LISTENING)
+
+#define SOCK_IS_CONNECTING(Sock) ((Sock)->State == SO_CONNECTING)
+
+#define SOCK_IS_CONNECTED(Sock) ((Sock)->State == SO_CONNECTED)
+
+#define SOCK_IS_DISCONNECTING(Sock) ((Sock)->State == SO_DISCONNECTING)
+
+#define SOCK_IS_NO_MORE_DATA(Sock) (0 != ((Sock)->Flag & SO_NO_MORE_DATA))
+
+#define SOCK_SIGNATURE EFI_SIGNATURE_32 ('S', 'O', 'C', 'K')
+
+#define SOCK_FROM_THIS(a) CR ((a), SOCKET, NetProtocol, SOCK_SIGNATURE)
+
+#define SET_RCV_BUFFSIZE(Sock, Size) ((Sock)->RcvBuffer.HighWater = (Size))
+
+#define GET_RCV_BUFFSIZE(Sock) ((Sock)->RcvBuffer.HighWater)
+
+#define GET_RCV_DATASIZE(Sock) (((Sock)->RcvBuffer.DataQueue)->BufSize)
+
+#define SET_SND_BUFFSIZE(Sock, Size) ((Sock)->SndBuffer.HighWater = (Size))
+
+#define GET_SND_BUFFSIZE(Sock) ((Sock)->SndBuffer.HighWater)
+
+#define GET_SND_DATASIZE(Sock) (((Sock)->SndBuffer.DataQueue)->BufSize)
+
+#define SET_BACKLOG(Sock, Value) ((Sock)->BackLog = (Value))
+
+#define GET_BACKLOG(Sock) ((Sock)->BackLog)
+
+#define SOCK_ERROR(Sock, Error) ((Sock)->SockError = (Error))
+
+#define SND_BUF_HDR_LEN(Sock) \
+ ((SockBufFirst (&((Sock)->SndBuffer)))->TotalSize)
+
+#define RCV_BUF_HDR_LEN(Sock) \
+ ((SockBufFirst (&((Sock)->RcvBuffer)))->TotalSize)
+
+#define SOCK_FROM_TOKEN(Token) (((SOCK_TOKEN *) (Token))->Sock)
+
+#define PROTO_TOKEN_FORM_SOCK(SockToken, Type) \
+ ((Type *) (((SOCK_TOKEN *) (SockToken))->Token))
+
+typedef struct _SOCKET SOCKET;
+
+typedef struct _SOCK_COMPLETION_TOKEN {
+ EFI_EVENT Event;
+ EFI_STATUS Status;
+} SOCK_COMPLETION_TOKEN;
+
+typedef struct _SOCK_IO_TOKEN {
+ SOCK_COMPLETION_TOKEN Token;
+ union {
+ VOID *RxData;
+ VOID *TxData;
+ } Packet;
+} SOCK_IO_TOKEN;
+
+//
+// the request issued from socket layer to protocol layer
+//
+typedef enum {
+ SOCK_ATTACH, // attach current socket to a new PCB
+ SOCK_DETACH, // detach current socket from the PCB
+ SOCK_CONFIGURE, // configure attached PCB
+ SOCK_FLUSH, // flush attached PCB
+ SOCK_SND, // need protocol to send something
+ SOCK_SNDPUSH, // need protocol to send pushed data
+ SOCK_SNDURG, // need protocol to send urgent data
+ SOCK_CONSUMED, // application has retrieved data from socket
+ SOCK_CONNECT, // need to connect to a peer
+ SOCK_CLOSE, // need to close the protocol process
+ SOCK_ABORT, // need to reset the protocol process
+ SOCK_POLL, // need to poll to the protocol layer
+ SOCK_ROUTE, // need to add a route information
+ SOCK_MODE, // need to get the mode data of the protocol
+ SOCK_GROUP // need to join a mcast group
+} SOCK_REQUEST;
+
+//
+// the socket type
+//
+typedef enum {
+ SOCK_DGRAM, // this socket providing datagram service
+ SOCK_STREAM // this socket providing stream service
+} SOCK_TYPE;
+
+//
+// the handler of protocol for request from socket
+//
+typedef
+EFI_STATUS
+(*SOCK_PROTO_HANDLER) (
+ IN SOCKET * Socket, // the socket issuing the request to protocol
+ IN SOCK_REQUEST Request, // the request issued by socket
+ IN VOID *RequestData // the request related data
+ );
+
+//
+// the buffer structure of rcvd data and send data used by socket
+//
+typedef struct _SOCK_BUFFER {
+ UINT32 HighWater; // the buffersize upper limit of sock_buffer
+ UINT32 LowWater; // the low warter mark of sock_buffer
+ NET_BUF_QUEUE *DataQueue; // the queue to buffer data
+} SOCK_BUFFER;
+
+//
+// the initialize data for create a new socket
+//
+typedef struct _SOCK_INIT_DATA {
+ SOCK_TYPE Type;
+ SOCK_STATE State;
+
+ SOCKET *Parent; // the parent of this socket
+ UINT32 BackLog; // the connection limit for listening socket
+ UINT32 SndBufferSize; // the high warter mark of send buffer
+ UINT32 RcvBufferSize; // the high warter mark of receive buffer
+ VOID *Protocol; // the pointer to protocol function template
+ // wanted to install on socket
+
+ SOCK_PROTO_HANDLER ProtoHandler;
+
+ EFI_HANDLE DriverBinding; // the driver binding handle
+} SOCK_INIT_DATA;
+
+//
+// socket provided oprerations for low layer protocol
+//
+
+//
+// socket provided operations for user interface
+//
+VOID
+SockSetState (
+ IN SOCKET *Sock,
+ IN SOCK_STATE State
+ );
+
+//
+// when the connection establishment process for a Sock
+// is finished low layer protocol calling this function
+// to notify socket layer
+//
+VOID
+SockConnEstablished (
+ IN SOCKET *Sock
+ );
+
+VOID
+SockConnClosed (
+ IN SOCKET *Sock
+ );
+
+//
+// called by low layer protocol to trim send buffer of
+// Sock, when Count data is sent out completely
+//
+VOID
+SockDataSent (
+ IN SOCKET *Sock,
+ IN UINT32 Count
+ );
+
+//
+// called by low layer protocol to get Len of data from
+// socket to send and copy it in Dest
+//
+UINT32
+SockGetDataToSend (
+ IN SOCKET *Sock,
+ IN UINT32 Offset,
+ IN UINT32 Len,
+ IN UINT8 *Dest
+ );
+
+//
+// called by low layer protocol to notify socket no more data can be
+// received
+//
+VOID
+SockNoMoreData (
+ IN SOCKET *Sock
+ );
+
+//
+// called by low layer protocol to append a NetBuffer
+// to rcv buffer of sock
+//
+VOID
+SockDataRcvd (
+ IN SOCKET *Sock,
+ IN NET_BUF *NetBuffer,
+ IN UINT32 UrgLen
+ );
+
+UINT32
+SockGetFreeSpace (
+ IN SOCKET *Sock,
+ IN UINT32 Which
+ );
+
+SOCKET *
+SockClone (
+ IN SOCKET *Sock
+ );
+
+VOID
+SockRcvdErr (
+ IN SOCKET *Sock,
+ IN EFI_STATUS Error
+ );
+
+//
+// the socket structure representing a network service access point
+//
+typedef struct _SOCKET {
+
+ //
+ // socket description information
+ //
+ UINT32 Signature;
+ EFI_HANDLE SockHandle; // the virtual handle of the socket
+ EFI_HANDLE DriverBinding; // socket't driver binding protocol
+ SOCK_CONFIGURE_STATE ConfigureState;
+ SOCK_TYPE Type;
+ SOCK_STATE State;
+ UINT16 Flag;
+ NET_LOCK Lock; // the lock of socket
+ SOCK_BUFFER SndBuffer; // send buffer of application's data
+ SOCK_BUFFER RcvBuffer; // receive buffer of received data
+ EFI_STATUS SockError; // the error returned by low layer protocol
+ BOOLEAN IsDestroyed;
+
+ //
+ // fields used to manage the connection request
+ //
+ UINT32 BackLog; // the limit of connection to this socket
+ UINT32 ConnCnt; // the current count of connections to it
+ SOCKET *Parent; // listening parent that accept the connection
+ NET_LIST_ENTRY ConnectionList; // the connections maintained by this socket
+ //
+ // the queue to buffer application's asynchronous token
+ //
+ NET_LIST_ENTRY ListenTokenList;
+ NET_LIST_ENTRY RcvTokenList;
+ NET_LIST_ENTRY SndTokenList;
+ NET_LIST_ENTRY ProcessingSndTokenList;
+
+ SOCK_COMPLETION_TOKEN *ConnectionToken; // app's token to signal if connected
+ SOCK_COMPLETION_TOKEN *CloseToken; // app's token to signal if closed
+
+ //
+ // interface for low level protocol
+ //
+ SOCK_PROTO_HANDLER ProtoHandler; // the request handler of protocol
+ UINT8 ProtoReserved[PROTO_RESERVED_LEN]; // Data fields reserved for protocol
+ union {
+ EFI_TCP4_PROTOCOL TcpProtocol;
+ EFI_UDP4_PROTOCOL UdpProtocol;
+ } NetProtocol;
+} SOCKET;
+
+//
+// the token structure buffered in socket layer
+//
+typedef struct _SOCK_TOKEN {
+ NET_LIST_ENTRY TokenList; // the entry to add in the token list
+ SOCK_COMPLETION_TOKEN *Token; // The application's token
+ UINT32 RemainDataLen; // unprocessed data length
+ SOCKET *Sock; // the poninter to the socket this token
+ // belongs to
+} SOCK_TOKEN;
+
+//
+// reserved data to access the NET_BUF delivered by UDP driver
+//
+typedef struct _UDP_RSV_DATA {
+ EFI_TIME TimeStamp;
+ EFI_UDP4_SESSION_DATA Session;
+} UDP_RSV_DATA;
+
+//
+// reserved data to access the NET_BUF delivered by TCP driver
+//
+typedef struct _TCP_RSV_DATA {
+ UINT32 UrgLen;
+} TCP_RSV_DATA;
+
+//
+// call it to creat a socket and attach it to a PCB
+//
+SOCKET *
+SockCreateChild (
+ IN SOCK_INIT_DATA *SockInitData,
+ IN VOID *ProtoData,
+ IN UINT32 Len
+ );
+
+//
+// call it to destroy a socket and its related PCB
+//
+EFI_STATUS
+SockDestroyChild (
+ IN SOCKET *Sock
+ );
+
+//
+// call it to configure a socket and its related PCB
+//
+EFI_STATUS
+SockConfigure (
+ IN SOCKET *Sock,
+ IN VOID *ConfigData
+ );
+
+//
+// call it to connect a socket to the peer
+//
+EFI_STATUS
+SockConnect (
+ IN SOCKET *Sock,
+ IN VOID *Token
+ );
+
+//
+// call it to issue an asynchronous listen token to the socket
+//
+EFI_STATUS
+SockAccept (
+ IN SOCKET *Sock,
+ IN VOID *Token
+ );
+
+//
+// Call it to send data using this socket
+//
+EFI_STATUS
+SockSend (
+ IN SOCKET *Sock,
+ IN VOID *Token
+ );
+
+//
+// Call it to receive data from this socket
+//
+EFI_STATUS
+SockRcv (
+ IN SOCKET *Sock,
+ IN VOID *Token
+ );
+
+//
+// Call it to flush a socket
+//
+EFI_STATUS
+SockFlush (
+ IN SOCKET *Sock
+ );
+
+//
+// Call it to close a socket in the light of policy in Token
+//
+EFI_STATUS
+SockClose (
+ IN SOCKET *Sock,
+ IN VOID *Token,
+ IN BOOLEAN OnAbort
+ );
+
+//
+// Call it to get the mode data of low layer protocol
+//
+EFI_STATUS
+SockGetMode (
+ IN SOCKET *Sock,
+ IN VOID *Mode
+ );
+
+//
+// call it to add this socket instance into a group
+//
+EFI_STATUS
+SockGroup (
+ IN SOCKET *Sock,
+ IN VOID *GroupInfo
+ );
+
+//
+// call it to add a route entry for this socket instance
+//
+EFI_STATUS
+SockRoute (
+ IN SOCKET *Sock,
+ IN VOID *RouteInfo
+ );
+
+//
+// Supporting function to operate on socket buffer
+//
+NET_BUF *
+SockBufFirst (
+ IN SOCK_BUFFER *Sockbuf
+ );
+
+NET_BUF *
+SockBufNext (
+ IN SOCK_BUFFER *Sockbuf,
+ IN NET_BUF *SockEntry
+ );
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Tcp4Dispatcher.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+#define TCP_COMP_VAL(Min, Max, Default, Val) \\r
+ ((((Val) <= (Max)) && ((Val) >= (Min))) ? (Val) : (Default))\r
+\r
+STATIC\r
+EFI_STATUS\r
+Tcp4Route (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP4_ROUTE_INFO *RouteInfo\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Add or remove a route entry in the IP route table associated\r
+ with this TCP instance.\r
+\r
+Arguments:\r
+\r
+ Tcb - Pointer to the TCP_CB of this TCP instance.\r
+ RouteInfo - Pointer to the route info to be processed.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The operation completed successfully.\r
+ EFI_NOT_STARTED - The driver instance has not been started.\r
+ EFI_NO_MAPPING - When using the default address, configuration(DHCP,\r
+ BOOTP, RARP, etc.) is not finished yet.\r
+ EFI_OUT_OF_RESOURCES - Could not add the entry to the routing table.\r
+ EFI_NOT_FOUND - This route is not in the routing table\r
+ (when RouteInfo->DeleteRoute is TRUE).\r
+ EFI_ACCESS_DENIED - The route is already defined in the routing table\r
+ (when RouteInfo->DeleteRoute is FALSE).\r
+\r
+--*/\r
+{\r
+ EFI_IP4_PROTOCOL *Ip;\r
+\r
+ Ip = Tcb->IpInfo->Ip;\r
+\r
+ ASSERT (Ip);\r
+\r
+ return Ip->Routes (\r
+ Ip,\r
+ RouteInfo->DeleteRoute,\r
+ RouteInfo->SubnetAddress,\r
+ RouteInfo->SubnetMask,\r
+ RouteInfo->GatewayAddress\r
+ );\r
+\r
+}\r
+\r
+\r
+/**\r
+ Get the operational settings of this TCP instance.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Mode Pointer to the buffer to store the operational\r
+ settings.\r
+\r
+ @retval EFI_SUCCESS The mode data is read.\r
+ @retval EFI_NOT_STARTED No configuration data is available because this\r
+ instance hasn't been started.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Tcp4GetMode (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP4_MODE_DATA *Mode\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+ EFI_TCP4_CONFIG_DATA *ConfigData;\r
+ EFI_TCP4_ACCESS_POINT *AccessPoint;\r
+ EFI_TCP4_OPTION *Option;\r
+ EFI_IP4_PROTOCOL *Ip;\r
+\r
+ Sock = Tcb->Sk;\r
+\r
+ if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp4ConfigData != NULL)) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ if (Mode->Tcp4State) {\r
+ *(Mode->Tcp4State) = Tcb->State;\r
+ }\r
+\r
+ if (Mode->Tcp4ConfigData) {\r
+\r
+ ConfigData = Mode->Tcp4ConfigData;\r
+ AccessPoint = &(ConfigData->AccessPoint);\r
+ Option = ConfigData->ControlOption;\r
+\r
+ ConfigData->TypeOfService = Tcb->TOS;\r
+ ConfigData->TimeToLive = Tcb->TTL;\r
+\r
+ AccessPoint->UseDefaultAddress = Tcb->UseDefaultAddr;\r
+\r
+ EFI_IP4 (AccessPoint->StationAddress) = Tcb->LocalEnd.Ip;\r
+ AccessPoint->SubnetMask = Tcb->SubnetMask;\r
+ AccessPoint->StationPort = NTOHS (Tcb->LocalEnd.Port);\r
+\r
+ EFI_IP4 (AccessPoint->RemoteAddress) = Tcb->RemoteEnd.Ip;\r
+ AccessPoint->RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
+ AccessPoint->ActiveFlag = (BOOLEAN) (Tcb->State != TCP_LISTEN);\r
+\r
+ if (Option != NULL) {\r
+ Option->ReceiveBufferSize = GET_RCV_BUFFSIZE (Tcb->Sk);\r
+ Option->SendBufferSize = GET_SND_BUFFSIZE (Tcb->Sk);\r
+ Option->MaxSynBackLog = GET_BACKLOG (Tcb->Sk);\r
+\r
+ Option->ConnectionTimeout = Tcb->ConnectTimeout / TCP_TICK_HZ;\r
+ Option->DataRetries = Tcb->MaxRexmit;\r
+ Option->FinTimeout = Tcb->FinWait2Timeout / TCP_TICK_HZ;\r
+ Option->TimeWaitTimeout = Tcb->TimeWaitTimeout / TCP_TICK_HZ;\r
+ Option->KeepAliveProbes = Tcb->MaxKeepAlive;\r
+ Option->KeepAliveTime = Tcb->KeepAliveIdle / TCP_TICK_HZ;\r
+ Option->KeepAliveInterval = Tcb->KeepAlivePeriod / TCP_TICK_HZ;\r
+\r
+ Option->EnableNagle = !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);\r
+ Option->EnableTimeStamp = !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS);\r
+ Option->EnableWindowScaling = !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS);\r
+\r
+ Option->EnableSelectiveAck = FALSE;\r
+ Option->EnablePathMtuDiscovery = FALSE;\r
+ }\r
+ }\r
+\r
+ Ip = Tcb->IpInfo->Ip;\r
+ ASSERT (Ip);\r
+\r
+ return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);\r
+}\r
+\r
+\r
+/**\r
+ If AP->StationPort isn't zero, check whether the access point\r
+ is registered, else generate a random station port for this\r
+ access point.\r
+\r
+ @param AP Pointer to the access point.\r
+\r
+ @retval EFI_SUCCESS The check is passed or the port is assigned.\r
+ @retval EFI_INVALID_PARAMETER The non-zero station port is already used.\r
+ @retval EFI_OUT_OF_RESOURCES No port can be allocated.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Tcp4Bind (\r
+ IN EFI_TCP4_ACCESS_POINT *AP\r
+ )\r
+{\r
+ BOOLEAN Cycle;\r
+\r
+ if (0 != AP->StationPort) {\r
+ //\r
+ // check if a same endpoint is bound\r
+ //\r
+ if (TcpFindTcbByPeer (&AP->StationAddress, AP->StationPort)) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else {\r
+ //\r
+ // generate a random port\r
+ //\r
+ Cycle = FALSE;\r
+\r
+ if (TCP4_PORT_USER_RESERVED == mTcp4RandomPort) {\r
+ mTcp4RandomPort = TCP4_PORT_KNOWN;\r
+ }\r
+\r
+ mTcp4RandomPort++;\r
+\r
+ while (TcpFindTcbByPeer (&AP->StationAddress, mTcp4RandomPort)) {\r
+\r
+ mTcp4RandomPort++;\r
+\r
+ if (mTcp4RandomPort <= TCP4_PORT_KNOWN) {\r
+\r
+ if (Cycle) {\r
+ TCP4_DEBUG_ERROR (("Tcp4Bind: no port can be allocated "\r
+ "for this pcb\n"));\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ mTcp4RandomPort = TCP4_PORT_KNOWN + 1;\r
+\r
+ Cycle = TRUE;\r
+ }\r
+\r
+ }\r
+\r
+ AP->StationPort = mTcp4RandomPort;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Flush the Tcb add its associated protocols..\r
+\r
+ @param Tcb Pointer to the TCP_CB to be flushed.\r
+\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Tcp4FlushPcb (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+ TCP4_PROTO_DATA *TcpProto;\r
+\r
+ IpIoConfigIp (Tcb->IpInfo, NULL);\r
+\r
+ Sock = Tcb->Sk;\r
+ TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+\r
+ if (SOCK_IS_CONFIGURED (Sock)) {\r
+ NetListRemoveEntry (&Tcb->List);\r
+\r
+ TcpSetVariableData (TcpProto->TcpService);\r
+ }\r
+\r
+ NetbufFreeList (&Tcb->SndQue);\r
+ NetbufFreeList (&Tcb->RcvQue);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+Tcp4AttachPcb (\r
+ IN SOCKET *Sk\r
+ )\r
+{\r
+ TCP_CB *Tcb;\r
+ TCP4_PROTO_DATA *ProtoData;\r
+ IP_IO *IpIo;\r
+\r
+ Tcb = NetAllocateZeroPool (sizeof (TCP_CB));\r
+\r
+ if (Tcb == NULL) {\r
+\r
+ TCP4_DEBUG_ERROR (("Tcp4ConfigurePcb: failed to allocate a TCB\n"));\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;\r
+ IpIo = ProtoData->TcpService->IpIo;\r
+\r
+ //\r
+ // Create an IpInfo for this Tcb.\r
+ //\r
+ Tcb->IpInfo = IpIoAddIp (IpIo);\r
+ if (Tcb->IpInfo == NULL) {\r
+\r
+ NetFreePool (Tcb);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NetListInit (&Tcb->List);\r
+ NetListInit (&Tcb->SndQue);\r
+ NetListInit (&Tcb->RcvQue);\r
+\r
+ Tcb->State = TCP_CLOSED;\r
+ Tcb->Sk = Sk;\r
+ ProtoData->TcpPcb = Tcb;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+VOID\r
+Tcp4DetachPcb (\r
+ IN SOCKET *Sk\r
+ )\r
+{\r
+ TCP4_PROTO_DATA *ProtoData;\r
+ TCP_CB *Tcb;\r
+\r
+ ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;\r
+ Tcb = ProtoData->TcpPcb;\r
+\r
+ ASSERT (Tcb != NULL);\r
+\r
+ Tcp4FlushPcb (Tcb);\r
+\r
+ IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);\r
+\r
+ NetFreePool (Tcb);\r
+\r
+ ProtoData->TcpPcb = NULL;\r
+}\r
+\r
+\r
+/**\r
+ Configure the Tcb using CfgData.\r
+\r
+ @param Sk Pointer to the socket of this TCP instance.\r
+ @param SkTcb Pointer to the TCP_CB of this TCP instance.\r
+ @param CfgData Pointer to the TCP configuration data.\r
+\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+ @retval EFI_INVALID_PARAMETER A same access point has been configured in\r
+ another TCP instance.\r
+ @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Tcp4ConfigurePcb (\r
+ IN SOCKET *Sk,\r
+ IN EFI_TCP4_CONFIG_DATA *CfgData\r
+ )\r
+{\r
+ IP_IO *IpIo;\r
+ EFI_IP4_CONFIG_DATA IpCfgData;\r
+ EFI_STATUS Status;\r
+ EFI_TCP4_OPTION *Option;\r
+ TCP4_PROTO_DATA *TcpProto;\r
+ TCP_CB *Tcb;\r
+\r
+ ASSERT (CfgData && Sk && Sk->SockHandle);\r
+\r
+ TcpProto = (TCP4_PROTO_DATA *) Sk->ProtoReserved;\r
+ Tcb = TcpProto->TcpPcb;\r
+ IpIo = TcpProto->TcpService->IpIo;\r
+\r
+ ASSERT (Tcb != NULL);\r
+\r
+ //\r
+ // Add Ip for send pkt to the peer\r
+ //\r
+ IpCfgData = mIpIoDefaultIpConfigData;\r
+ IpCfgData.DefaultProtocol = EFI_IP_PROTO_TCP;\r
+ IpCfgData.UseDefaultAddress = CfgData->AccessPoint.UseDefaultAddress;\r
+ IpCfgData.StationAddress = CfgData->AccessPoint.StationAddress;\r
+ IpCfgData.SubnetMask = CfgData->AccessPoint.SubnetMask;\r
+ IpCfgData.ReceiveTimeout = (UINT32) (-1);\r
+\r
+ //\r
+ // Configure the IP instance this Tcb consumes.\r
+ //\r
+ Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto OnExit;\r
+ }\r
+\r
+ //\r
+ // Get the default address info if the instance is configured to use default address.\r
+ //\r
+ if (CfgData->AccessPoint.UseDefaultAddress) {\r
+ CfgData->AccessPoint.StationAddress = IpCfgData.StationAddress;\r
+ CfgData->AccessPoint.SubnetMask = IpCfgData.SubnetMask;\r
+ }\r
+\r
+ //\r
+ // check if we can bind this endpoint in CfgData\r
+ //\r
+ Status = Tcp4Bind (&(CfgData->AccessPoint));\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ TCP4_DEBUG_ERROR (("Tcp4ConfigurePcb: Bind endpoint failed "\r
+ "with %r\n", Status));\r
+\r
+ goto OnExit;\r
+ }\r
+\r
+ //\r
+ // Initalize the operating information in this Tcb\r
+ //\r
+ ASSERT (Tcb->State == TCP_CLOSED &&\r
+ NetListIsEmpty (&Tcb->SndQue) &&\r
+ NetListIsEmpty (&Tcb->RcvQue));\r
+\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);\r
+ Tcb->State = TCP_CLOSED;\r
+\r
+ Tcb->SndMss = 536;\r
+ Tcb->RcvMss = TcpGetRcvMss (Sk);\r
+\r
+ Tcb->SRtt = 0;\r
+ Tcb->Rto = 3 * TCP_TICK_HZ;\r
+\r
+ Tcb->CWnd = Tcb->SndMss;\r
+ Tcb->Ssthresh = 0xffffffff;\r
+\r
+ Tcb->CongestState = TCP_CONGEST_OPEN;\r
+\r
+ Tcb->KeepAliveIdle = TCP_KEEPALIVE_IDLE_MIN;\r
+ Tcb->KeepAlivePeriod = TCP_KEEPALIVE_PERIOD;\r
+ Tcb->MaxKeepAlive = TCP_MAX_KEEPALIVE;\r
+ Tcb->MaxRexmit = TCP_MAX_LOSS;\r
+ Tcb->FinWait2Timeout = TCP_FIN_WAIT2_TIME;\r
+ Tcb->TimeWaitTimeout = TCP_TIME_WAIT_TIME;\r
+ Tcb->ConnectTimeout = TCP_CONNECT_TIME;\r
+\r
+ //\r
+ // initialize Tcb in the light of CfgData\r
+ //\r
+ Tcb->TTL = CfgData->TimeToLive;\r
+ Tcb->TOS = CfgData->TypeOfService;\r
+\r
+ Tcb->LocalEnd.Ip = EFI_IP4 (CfgData->AccessPoint.StationAddress);\r
+ Tcb->LocalEnd.Port = HTONS (CfgData->AccessPoint.StationPort);\r
+ Tcb->SubnetMask = CfgData->AccessPoint.SubnetMask;\r
+\r
+ Tcb->RemoteEnd.Ip = EFI_IP4 (CfgData->AccessPoint.RemoteAddress);\r
+ Tcb->RemoteEnd.Port = HTONS (CfgData->AccessPoint.RemotePort);\r
+\r
+ Option = CfgData->ControlOption;\r
+\r
+ if (Option != NULL) {\r
+ SET_RCV_BUFFSIZE (\r
+ Sk,\r
+ TCP_COMP_VAL (TCP_RCV_BUF_SIZE_MIN,\r
+ TCP_RCV_BUF_SIZE,\r
+ TCP_RCV_BUF_SIZE,\r
+ Option->ReceiveBufferSize)\r
+ );\r
+ SET_SND_BUFFSIZE (\r
+ Sk,\r
+ TCP_COMP_VAL (TCP_SND_BUF_SIZE_MIN,\r
+ TCP_SND_BUF_SIZE,\r
+ TCP_SND_BUF_SIZE,\r
+ Option->SendBufferSize)\r
+ );\r
+\r
+ SET_BACKLOG (\r
+ Sk,\r
+ TCP_COMP_VAL (TCP_BACKLOG_MIN,\r
+ TCP_BACKLOG,\r
+ TCP_BACKLOG,\r
+ Option->MaxSynBackLog)\r
+ );\r
+\r
+ Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (\r
+ TCP_MAX_LOSS_MIN,\r
+ TCP_MAX_LOSS,\r
+ TCP_MAX_LOSS,\r
+ Option->DataRetries\r
+ );\r
+ Tcb->FinWait2Timeout = TCP_COMP_VAL (\r
+ TCP_FIN_WAIT2_TIME,\r
+ TCP_FIN_WAIT2_TIME_MAX,\r
+ TCP_FIN_WAIT2_TIME,\r
+ Option->FinTimeout * TCP_TICK_HZ\r
+ );\r
+\r
+ if (Option->TimeWaitTimeout != 0) {\r
+ Tcb->TimeWaitTimeout = TCP_COMP_VAL (\r
+ TCP_TIME_WAIT_TIME,\r
+ TCP_TIME_WAIT_TIME_MAX,\r
+ TCP_TIME_WAIT_TIME,\r
+ Option->TimeWaitTimeout * TCP_TICK_HZ\r
+ );\r
+ } else {\r
+ Tcb->TimeWaitTimeout = 0;\r
+ }\r
+\r
+ if (Option->KeepAliveProbes != 0) {\r
+ TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);\r
+\r
+ Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (\r
+ TCP_MAX_KEEPALIVE_MIN,\r
+ TCP_MAX_KEEPALIVE,\r
+ TCP_MAX_KEEPALIVE,\r
+ Option->KeepAliveProbes\r
+ );\r
+ Tcb->KeepAliveIdle = TCP_COMP_VAL (\r
+ TCP_KEEPALIVE_IDLE_MIN,\r
+ TCP_KEEPALIVE_IDLE_MAX,\r
+ TCP_KEEPALIVE_IDLE_MIN,\r
+ Option->KeepAliveTime * TCP_TICK_HZ\r
+ );\r
+ Tcb->KeepAlivePeriod = TCP_COMP_VAL (\r
+ TCP_KEEPALIVE_PERIOD_MIN,\r
+ TCP_KEEPALIVE_PERIOD,\r
+ TCP_KEEPALIVE_PERIOD,\r
+ Option->KeepAliveInterval * TCP_TICK_HZ\r
+ );\r
+ }\r
+\r
+ Tcb->ConnectTimeout = TCP_COMP_VAL (\r
+ TCP_CONNECT_TIME_MIN,\r
+ TCP_CONNECT_TIME,\r
+ TCP_CONNECT_TIME,\r
+ Option->ConnectionTimeout * TCP_TICK_HZ\r
+ );\r
+\r
+ if (Option->EnableNagle == FALSE) {\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);\r
+ }\r
+\r
+ if (Option->EnableTimeStamp == FALSE) {\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);\r
+ }\r
+\r
+ if (Option->EnableWindowScaling == FALSE) {\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);\r
+ }\r
+ }\r
+\r
+ //\r
+ // update state of Tcb and socket\r
+ //\r
+ if (CfgData->AccessPoint.ActiveFlag == FALSE) {\r
+\r
+ TcpSetState (Tcb, TCP_LISTEN);\r
+ SockSetState (Sk, SO_LISTENING);\r
+\r
+ Sk->ConfigureState = SO_CONFIGURED_PASSIVE;\r
+ } else {\r
+\r
+ Sk->ConfigureState = SO_CONFIGURED_ACTIVE;\r
+ }\r
+\r
+ TcpInsertTcb (Tcb);\r
+\r
+OnExit:\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ The procotol handler provided to the socket layer, used to\r
+ dispatch the socket level requests by calling the corresponding\r
+ TCP layer functions.\r
+\r
+ @param Sock Pointer to the socket of this TCP instance.\r
+ @param Request The code of this operation request.\r
+ @param Data Pointer to the operation specific data passed in\r
+ together with the operation request.\r
+\r
+ @retval EFI_SUCCESS The socket request is completed successfully.\r
+ @retval other The error status returned by the corresponding TCP\r
+ layer function.\r
+\r
+**/\r
+EFI_STATUS\r
+Tcp4Dispatcher (\r
+ IN SOCKET *Sock,\r
+ IN SOCK_REQUEST Request,\r
+ IN VOID *Data OPTIONAL\r
+ )\r
+{\r
+ TCP_CB *Tcb;\r
+ TCP4_PROTO_DATA *ProtoData;\r
+ EFI_IP4_PROTOCOL *Ip;\r
+\r
+ ProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+ Tcb = ProtoData->TcpPcb;\r
+\r
+ switch (Request) {\r
+ case SOCK_POLL:\r
+ Ip = ProtoData->TcpService->IpIo->Ip;\r
+ Ip->Poll (Ip);\r
+ break;\r
+\r
+ case SOCK_CONSUMED:\r
+ //\r
+ // After user received data from socket buffer, socket will\r
+ // notify TCP using this message to give it a chance to send out\r
+ // window update information\r
+ //\r
+ ASSERT (Tcb);\r
+ TcpOnAppConsume (Tcb);\r
+ break;\r
+\r
+ case SOCK_SND:\r
+\r
+ ASSERT (Tcb);\r
+ TcpOnAppSend (Tcb);\r
+ break;\r
+\r
+ case SOCK_CLOSE:\r
+\r
+ TcpOnAppClose (Tcb);\r
+\r
+ break;\r
+\r
+ case SOCK_ABORT:\r
+\r
+ TcpOnAppAbort (Tcb);\r
+\r
+ break;\r
+\r
+ case SOCK_SNDPUSH:\r
+ Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);\r
+\r
+ break;\r
+\r
+ case SOCK_SNDURG:\r
+ Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);\r
+\r
+ break;\r
+\r
+ case SOCK_CONNECT:\r
+\r
+ TcpOnAppConnect (Tcb);\r
+\r
+ break;\r
+\r
+ case SOCK_ATTACH:\r
+\r
+ return Tcp4AttachPcb (Sock);\r
+\r
+ break;\r
+\r
+ case SOCK_FLUSH:\r
+\r
+ Tcp4FlushPcb (Tcb);\r
+\r
+ break;\r
+\r
+ case SOCK_DETACH:\r
+\r
+ Tcp4DetachPcb (Sock);\r
+\r
+ break;\r
+\r
+ case SOCK_CONFIGURE:\r
+\r
+ return Tcp4ConfigurePcb (\r
+ Sock,\r
+ (EFI_TCP4_CONFIG_DATA *) Data\r
+ );\r
+\r
+ break;\r
+\r
+ case SOCK_MODE:\r
+\r
+ ASSERT (Data && Tcb);\r
+\r
+ return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);\r
+\r
+ break;\r
+\r
+ case SOCK_ROUTE:\r
+\r
+ ASSERT (Data && Tcb);\r
+\r
+ return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);\r
+\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Tcp4Driver.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+\r
+UINT16 mTcp4RandomPort;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gTcp4ComponentName;\r
+\r
+TCP4_HEARTBEAT_TIMER mTcp4Timer = {\r
+ NULL,\r
+ 0\r
+};\r
+\r
+EFI_TCP4_PROTOCOL mTcp4ProtocolTemplate = {\r
+ Tcp4GetModeData,\r
+ Tcp4Configure,\r
+ Tcp4Routes,\r
+ Tcp4Connect,\r
+ Tcp4Accept,\r
+ Tcp4Transmit,\r
+ Tcp4Receive,\r
+ Tcp4Close,\r
+ Tcp4Cancel,\r
+ Tcp4Poll\r
+};\r
+\r
+SOCK_INIT_DATA mTcp4DefaultSockData = {\r
+ SOCK_STREAM,\r
+ 0,\r
+ NULL,\r
+ TCP_BACKLOG,\r
+ TCP_SND_BUF_SIZE,\r
+ TCP_RCV_BUF_SIZE,\r
+ &mTcp4ProtocolTemplate,\r
+ Tcp4Dispatcher,\r
+ NULL,\r
+};\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL mTcp4DriverBinding = {\r
+ Tcp4DriverBindingSupported,\r
+ Tcp4DriverBindingStart,\r
+ Tcp4DriverBindingStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+EFI_SERVICE_BINDING_PROTOCOL mTcp4ServiceBinding = {\r
+ Tcp4ServiceBindingCreateChild,\r
+ Tcp4ServiceBindingDestroyChild\r
+};\r
+\r
+\r
+/**\r
+ Create and start the heartbeat timer for TCP driver.\r
+\r
+ None.\r
+\r
+ @retval EFI_SUCCESS The timer is successfully created and started.\r
+ @retval other The timer is not created.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Tcp4CreateTimer (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (mTcp4Timer.RefCnt == 0) {\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ NET_TPL_TIMER,\r
+ TcpTicking,\r
+ NULL,\r
+ &mTcp4Timer.TimerEvent\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ Status = gBS->SetTimer (\r
+ mTcp4Timer.TimerEvent,\r
+ TimerPeriodic,\r
+ (UINT64) (TICKS_PER_SECOND / TCP_TICK_HZ)\r
+ );\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ mTcp4Timer.RefCnt++;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop and destroy the heartbeat timer for TCP driver.\r
+\r
+ None.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Tcp4DestroyTimer (\r
+ VOID\r
+ )\r
+{\r
+ ASSERT (mTcp4Timer.RefCnt > 0);\r
+\r
+ mTcp4Timer.RefCnt--;\r
+\r
+ if (mTcp4Timer.RefCnt > 0) {\r
+ return;\r
+ }\r
+\r
+ gBS->SetTimer (mTcp4Timer.TimerEvent, TimerCancel, 0);\r
+ gBS->CloseEvent (mTcp4Timer.TimerEvent);\r
+ mTcp4Timer.TimerEvent = NULL;\r
+}\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (Tcp4DriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4DriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The entry point for Tcp4 driver. used to install\r
+ Tcp4 driver on the ImageHandle.\r
+\r
+Arguments:\r
+\r
+ ImageHandle - The firmware allocated handle for this\r
+ driver image.\r
+ SystemTable - Pointer to the EFI system table.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Driver loaded.\r
+ other - Driver not loaded.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Seed;\r
+\r
+ //\r
+ // Install the TCP4 Driver Binding Protocol\r
+ //\r
+ Status = NetLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &mTcp4DriverBinding,\r
+ ImageHandle,\r
+ &gTcp4ComponentName,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ //\r
+ // Initialize ISS and random port.\r
+ //\r
+ Seed = NetRandomInitSeed ();\r
+ mTcpGlobalIss = NET_RANDOM (Seed) % mTcpGlobalIss;\r
+ mTcp4RandomPort = TCP4_PORT_KNOWN +\r
+ (UINT16) (NET_RANDOM(Seed) % TCP4_PORT_KNOWN);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to test.\r
+ @param RemainingDevicePath Optional parameter use to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4DriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Test for the Tcp4ServiceBinding Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiTcp4ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ //\r
+ // Test for the Ip4 Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Start this driver on ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to bind driver to.\r
+ @param RemainingDevicePath Optional parameter use to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCESS The driver is added to ControllerHandle.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to start the\r
+ driver.\r
+ @retval other The driver cannot be added to ControllerHandle.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4DriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ TCP4_SERVICE_DATA *TcpServiceData;\r
+ IP_IO_OPEN_DATA OpenData;\r
+\r
+ TcpServiceData = NetAllocateZeroPool (sizeof (TCP4_SERVICE_DATA));\r
+\r
+ if (NULL == TcpServiceData) {\r
+ TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Have no enough"\r
+ " resource to create a Tcp Servcie Data!\n"));\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Create a new IP IO to Consume it\r
+ //\r
+ TcpServiceData->IpIo = IpIoCreate (This->DriverBindingHandle, ControllerHandle);\r
+ if (NULL == TcpServiceData->IpIo) {\r
+\r
+ TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Have no enough"\r
+ " resource to create an Ip Io!\n"));\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ReleaseServiceData;\r
+ }\r
+\r
+ //\r
+ // Configure and start IpIo.\r
+ //\r
+ NetZeroMem (&OpenData, sizeof (IP_IO_OPEN_DATA));\r
+\r
+ OpenData.IpConfigData = mIpIoDefaultIpConfigData;\r
+ OpenData.IpConfigData.DefaultProtocol = EFI_IP_PROTO_TCP;\r
+\r
+ OpenData.PktRcvdNotify = Tcp4RxCallback;\r
+ Status = IpIoOpen (TcpServiceData->IpIo, &OpenData);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ReleaseServiceData;\r
+ }\r
+\r
+ //\r
+ // Create the timer event used by TCP driver\r
+ //\r
+ Status = Tcp4CreateTimer ();\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Create TcpTimer"\r
+ " Event failed with %r\n", Status));\r
+\r
+ goto ReleaseIpIo;\r
+ }\r
+\r
+ //\r
+ // Install the Tcp4ServiceBinding Protocol on the\r
+ // controller handle\r
+ //\r
+ TcpServiceData->Tcp4ServiceBinding = mTcp4ServiceBinding;\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ControllerHandle,\r
+ &gEfiTcp4ServiceBindingProtocolGuid,\r
+ &TcpServiceData->Tcp4ServiceBinding,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ TCP4_DEBUG_ERROR (("Tcp4DriverBindingStart: Install Tcp4 Service Binding"\r
+ " Protocol failed for %r\n", Status));\r
+\r
+ goto ReleaseTimer;\r
+ }\r
+\r
+ //\r
+ // Initialize member in TcpServiceData\r
+ //\r
+ TcpServiceData->ControllerHandle = ControllerHandle;\r
+ TcpServiceData->Signature = TCP4_DRIVER_SIGNATURE;\r
+ TcpServiceData->DriverBindingHandle = This->DriverBindingHandle;\r
+\r
+ TcpSetVariableData (TcpServiceData);\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ReleaseTimer:\r
+\r
+ Tcp4DestroyTimer ();\r
+\r
+ReleaseIpIo:\r
+\r
+ IpIoDestroy (TcpServiceData->IpIo);\r
+\r
+ReleaseServiceData:\r
+\r
+ NetFreePool (TcpServiceData);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop this driver on ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to stop driver on.\r
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number\r
+ of children is zero stop the entire bus driver.\r
+ @param ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+ @retval EFI_SUCCESS This driver is removed from ControllerHandle.\r
+ @retval other This driver is not removed from ControllerHandle.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4DriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE NicHandle;\r
+ EFI_SERVICE_BINDING_PROTOCOL *Tcp4ServiceBinding;\r
+ TCP4_SERVICE_DATA *TcpServiceData;\r
+ TCP_CB *TcpPcb;\r
+ SOCKET *Sock;\r
+ TCP4_PROTO_DATA *TcpProto;\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *NextEntry;\r
+\r
+ // Find the NicHandle where Tcp4 ServiceBinding Protocol is installed.\r
+ //\r
+ NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGuid);\r
+ if (NicHandle == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Retrieve the TCP driver Data Structure\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ NicHandle,\r
+ &gEfiTcp4ServiceBindingProtocolGuid,\r
+ (VOID **) &Tcp4ServiceBinding,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ TCP4_DEBUG_ERROR (("Tcp4DriverBindingStop: Locate Tcp4 Service "\r
+ " Binding Protocol failed with %r\n", Status));\r
+\r
+ return Status;\r
+ }\r
+\r
+ TcpServiceData = TCP4_FROM_THIS (Tcp4ServiceBinding);\r
+\r
+ //\r
+ // Kill TCP driver\r
+ //\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mTcpRunQue) {\r
+ TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ //\r
+ // Try to destroy this child\r
+ //\r
+ Sock = TcpPcb->Sk;\r
+ TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+\r
+ if (TcpProto->TcpService == TcpServiceData) {\r
+ Status = SockDestroyChild (Sock);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ TCP4_DEBUG_ERROR (("Tcp4DriverBindingStop: Destroy Tcp "\r
+ "instance failed with %r\n", Status));\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mTcpListenQue) {\r
+ TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ //\r
+ // Try to destroy this child\r
+ //\r
+ Sock = TcpPcb->Sk;\r
+ TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+\r
+ if (TcpProto->TcpService == TcpServiceData) {\r
+ Status = SockDestroyChild (TcpPcb->Sk);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ TCP4_DEBUG_ERROR (("Tcp4DriverBindingStop: Destroy Tcp "\r
+ "instance failed with %r\n", Status));\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Uninstall TCP servicebinding protocol\r
+ //\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ NicHandle,\r
+ &gEfiTcp4ServiceBindingProtocolGuid,\r
+ Tcp4ServiceBinding,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ TCP4_DEBUG_ERROR (("Tcp4DriverBindingStop: Uninstall TCP service "\r
+ "binding protocol failed with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Destroy the IpIO consumed by TCP driver\r
+ //\r
+ Status = IpIoDestroy (TcpServiceData->IpIo);\r
+\r
+ //\r
+ // Destroy the heartbeat timer.\r
+ //\r
+ Tcp4DestroyTimer ();\r
+\r
+ //\r
+ // Clear the variable.\r
+ //\r
+ TcpClearVariableData (TcpServiceData);\r
+\r
+ //\r
+ // Release the TCP service data\r
+ //\r
+ NetFreePool (TcpServiceData);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Creates a child handle with a set of TCP4 services.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ChildHandle Pointer to the handle of the child to create. If\r
+ it is NULL, then a new handle is created. If it is\r
+ not NULL, then the I/O services are added to the\r
+ existing child handle.\r
+\r
+ @retval EFI_SUCCESS The child handle is created.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to create the\r
+ child.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4ServiceBindingCreateChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE *ChildHandle\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+ TCP4_SERVICE_DATA *TcpServiceData;\r
+ TCP4_PROTO_DATA TcpProto;\r
+ EFI_STATUS Status;\r
+ VOID *Ip4;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (NULL == This || NULL == ChildHandle) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+ TcpServiceData = TCP4_FROM_THIS (This);\r
+ TcpProto.TcpService = TcpServiceData;\r
+ TcpProto.TcpPcb = NULL;\r
+\r
+ //\r
+ // Create a tcp instance with defualt Tcp default\r
+ // sock init data and TcpProto\r
+ //\r
+ mTcp4DefaultSockData.DriverBinding = TcpServiceData->DriverBindingHandle;\r
+\r
+ Sock = SockCreateChild (&mTcp4DefaultSockData, &TcpProto, sizeof (TCP4_PROTO_DATA));\r
+ if (NULL == Sock) {\r
+ TCP4_DEBUG_ERROR (("Tcp4DriverBindingCreateChild: "\r
+ "No resource to create a Tcp Child\n"));\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ *ChildHandle = Sock->SockHandle;\r
+\r
+ //\r
+ // Open the default Ip4 protocol of IP_IO BY_DRIVER.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ TcpServiceData->IpIo->ChildHandle,\r
+ &gEfiIp4ProtocolGuid,\r
+ (VOID **) &Ip4,\r
+ TcpServiceData->DriverBindingHandle,\r
+ Sock->SockHandle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SockDestroyChild (Sock);\r
+ }\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Destroys a child handle with a set of UDP4 services.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ChildHandle Handle of the child to be destroyed.\r
+\r
+ @retval EFI_SUCCESS The TCP4 services are removed from the child\r
+ handle.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval other The child handle is not destroyed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4ServiceBindingDestroyChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ChildHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_TCP4_PROTOCOL *Tcp4;\r
+ SOCKET *Sock;\r
+ TCP4_PROTO_DATA *TcpProtoData;\r
+ TCP4_SERVICE_DATA *TcpServiceData;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (NULL == This || NULL == ChildHandle) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ //\r
+ // retrieve the Tcp4 protocol from ChildHandle\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiTcp4ProtocolGuid,\r
+ (VOID **) &Tcp4,\r
+ mTcp4DriverBinding.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // destroy this sock and related Tcp protocol control\r
+ // block\r
+ //\r
+ Sock = SOCK_FROM_THIS (Tcp4);\r
+ TcpProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+ TcpServiceData = TcpProtoData->TcpService;\r
+\r
+ Status = SockDestroyChild (Sock);\r
+\r
+ //\r
+ // Close the Ip4 protocol.\r
+ //\r
+ gBS->CloseProtocol (\r
+ TcpServiceData->IpIo->ChildHandle,\r
+ &gEfiIp4ProtocolGuid,\r
+ TcpServiceData->DriverBindingHandle,\r
+ ChildHandle\r
+ );\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 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:
+
+ Tcp4Driver.h
+
+Abstract:
+
+
+**/
+
+#ifndef _TCP4_DRIVER_H_
+#define _TCP4_DRIVER_H_
+
+#include <Protocol/ServiceBinding.h>
+#include <Library/IpIoLib.h>
+
+#define TCP4_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('T', 'C', 'P', '4')
+
+#define TCP4_PORT_KNOWN 1024
+#define TCP4_PORT_USER_RESERVED 65535
+
+typedef struct _TCP4_HEARTBEAT_TIMER {
+ EFI_EVENT TimerEvent;
+ INTN RefCnt;
+} TCP4_HEARTBEAT_TIMER;
+
+typedef struct _TCP4_SERVICE_DATA {
+ UINT32 Signature;
+ EFI_HANDLE ControllerHandle;
+ IP_IO *IpIo; // IP Io consumed by TCP4
+ EFI_SERVICE_BINDING_PROTOCOL Tcp4ServiceBinding;
+ EFI_HANDLE DriverBindingHandle;
+ CHAR16 *MacString;
+} TCP4_SERVICE_DATA;
+
+//
+// Prototype for TCP4 driver Rcv callback function registered to IP_IO
+//
+VOID
+Tcp4RxCallback (
+ IN EFI_STATUS Status,
+ IN ICMP_ERROR IcmpErr,
+ IN EFI_NET_SESSION_DATA *NetSession,
+ IN NET_BUF *Pkt,
+ IN VOID *Context OPTIONAL
+ );
+
+INTN
+TcpSendIpPacket (
+ IN TCP_CB *Tcb,
+ IN NET_BUF *Nbuf,
+ IN UINT32 Src,
+ IN UINT32 Dest
+ );
+
+EFI_STATUS
+Tcp4Dispatcher (
+ IN SOCKET *Sock,
+ IN SOCK_REQUEST Request,
+ IN VOID *Data OPTIONAL
+ );
+
+typedef struct _TCP4_PROTO_DATA {
+ TCP4_SERVICE_DATA *TcpService;
+ TCP_CB *TcpPcb;
+} TCP4_PROTO_DATA;
+
+#define TCP4_FROM_THIS(a) \
+ CR ( \
+ (a), \
+ TCP4_SERVICE_DATA, \
+ Tcp4ServiceBinding, \
+ TCP4_DRIVER_SIGNATURE \
+ )
+
+//
+// Function prototype for the driver's entry point
+//
+EFI_STATUS
+EFIAPI
+Tcp4DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+//
+// Function prototypes for the Drivr Binding Protocol
+//
+EFI_STATUS
+EFIAPI
+Tcp4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Tcp4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Tcp4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Function ptototypes for the ServiceBinding Prococol
+//
+EFI_STATUS
+EFIAPI
+Tcp4ServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE *ChildHandle
+ );
+
+EFI_STATUS
+EFIAPI
+Tcp4ServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ );
+
+#endif
--- /dev/null
+#/** @file\r
+# Component name for module Tcp4\r
+#\r
+# FIX ME!\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+# All rights reserved. This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = Tcp4Dxe\r
+ FILE_GUID = 6d6963ab-906d-4a65-a7ca-bd40e5d6af4d\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ EDK_RELEASE_VERSION = 0x00020000\r
+ EFI_SPECIFICATION_VERSION = 0x00020000\r
+\r
+ ENTRY_POINT = Tcp4DriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+ SockImpl.c\r
+ SockInterface.c\r
+ Tcp4Proto.h\r
+ Tcp4Main.h\r
+ SockImpl.h\r
+ Tcp4Output.c\r
+ Tcp4Timer.c\r
+ Tcp4Option.h\r
+ Tcp4Dispatcher.c\r
+ Tcp4Input.c\r
+ Tcp4Misc.c\r
+ Tcp4Main.c\r
+ Socket.h\r
+ ComponentName.c\r
+ Tcp4Driver.h\r
+ Tcp4Io.c\r
+ Tcp4Driver.c\r
+ Tcp4Func.h\r
+ Tcp4Option.c\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ UefiLib\r
+ BaseLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ UefiRuntimeServicesTableLib\r
+ DebugLib\r
+ NetLib\r
+ IpIoLib\r
+\r
+[Protocols]\r
+ gEfiIp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiTcp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiIp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiTcp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+\r
--- /dev/null
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+ <MsaHeader>\r
+ <ModuleName>Tcp4Dxe</ModuleName>\r
+ <ModuleType>DXE_DRIVER</ModuleType>\r
+ <GuidValue>6d6963ab-906d-4a65-a7ca-bd40e5d6af4d</GuidValue>\r
+ <Version>1.0</Version>\r
+ <Abstract>Component name for module Tcp4</Abstract>\r
+ <Description>FIX ME!</Description>\r
+ <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+ <License>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.</License>\r
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>\r
+ </MsaHeader>\r
+ <ModuleDefinitions>\r
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+ <BinaryModule>false</BinaryModule>\r
+ <OutputFileBasename>Tcp4Dxe</OutputFileBasename>\r
+ </ModuleDefinitions>\r
+ <LibraryClassDefinitions>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>DebugLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiDriverEntryPoint</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiBootServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>BaseLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiLib</Keyword>\r
+ </LibraryClass>\r
+ </LibraryClassDefinitions>\r
+ <SourceFiles>\r
+ <Filename>Tcp4Option.c</Filename>\r
+ <Filename>Tcp4Func.h</Filename>\r
+ <Filename>Tcp4Driver.c</Filename>\r
+ <Filename>Tcp4Io.c</Filename>\r
+ <Filename>Tcp4Driver.h</Filename>\r
+ <Filename>ComponentName.c</Filename>\r
+ <Filename>Socket.h</Filename>\r
+ <Filename>Tcp4Main.c</Filename>\r
+ <Filename>Tcp4Misc.c</Filename>\r
+ <Filename>Tcp4Input.c</Filename>\r
+ <Filename>Tcp4Dispatcher.c</Filename>\r
+ <Filename>Tcp4Option.h</Filename>\r
+ <Filename>Tcp4Timer.c</Filename>\r
+ <Filename>Tcp4Output.c</Filename>\r
+ <Filename>SockImpl.h</Filename>\r
+ <Filename>Tcp4Main.h</Filename>\r
+ <Filename>Tcp4Proto.h</Filename>\r
+ <Filename>SockInterface.c</Filename>\r
+ <Filename>SockImpl.c</Filename>\r
+ </SourceFiles>\r
+ <PackageDependencies>\r
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+ </PackageDependencies>\r
+ <Protocols>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiTcp4ProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiIp4ServiceBindingProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiTcp4ServiceBindingProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiIp4ProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ </Protocols>\r
+ <Externs>\r
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+ <Extern>\r
+ <ModuleEntryPoint>Tcp4DriverEntryPoint</ModuleEntryPoint>\r
+ </Extern>\r
+ </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 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:
+
+ Tcp4Func.h
+
+Abstract:
+
+
+**/
+
+#ifndef _TCP4_FUNC_H_
+#define _TCP4_FUNC_H_
+
+//
+// Declaration of all the functions in TCP
+// protocol. It is intended to keep tcp.h
+// clear.
+//
+
+//
+// Functions in tcp.c
+//
+BOOLEAN
+TcpFindTcbByPeer (
+ IN EFI_IPv4_ADDRESS *Addr,
+ IN TCP_PORTNO Port
+ );
+
+TCP_CB *
+TcpLocateTcb (
+ IN TCP_PORTNO LocalPort,
+ IN UINT32 LocalIp,
+ IN TCP_PORTNO RemotePort,
+ IN UINT32 RemoteIp,
+ IN BOOLEAN Syn
+ );
+
+INTN
+TcpInsertTcb (
+ IN TCP_CB *Tcb
+ );
+
+TCP_CB *
+TcpCloneTcb (
+ IN TCP_CB *Tcb
+ );
+
+TCP_SEQNO
+TcpGetIss (
+ VOID
+ );
+
+VOID
+TcpInitTcbLocal (
+ IN TCP_CB *Tcb
+ );
+
+VOID
+TcpInitTcbPeer (
+ IN TCP_CB *Tcb,
+ IN TCP_SEG *Seg,
+ IN TCP_OPTION *Opt
+ );
+
+UINT16
+TcpGetRcvMss (
+ IN SOCKET *Sock
+ );
+
+VOID
+TcpSetState (
+ IN TCP_CB *Tcb,
+ IN UINT8 State
+ );
+
+//
+// Functions in Tcp4Output.c
+//
+INTN
+TcpSendIpPacket (
+ IN TCP_CB *Tcb,
+ IN NET_BUF *Nbuf,
+ IN UINT32 Src,
+ IN UINT32 Dst
+ );
+
+INTN
+TcpToSendData (
+ IN TCP_CB *Tcb,
+ IN INTN Force
+ );
+
+VOID
+TcpToSendAck (
+ IN TCP_CB *Tcb
+ );
+
+VOID
+TcpSendAck (
+ IN TCP_CB *Tcb
+ );
+
+INTN
+TcpSendZeroProbe (
+ IN TCP_CB *Tcb
+ );
+
+INTN
+TcpDeliverData (
+ IN TCP_CB *Tcb
+ );
+
+INTN
+TcpSendReset (
+ IN TCP_CB *Tcb,
+ IN TCP_HEAD *Head,
+ IN INT32 Len,
+ IN UINT32 Local,
+ IN UINT32 Remote
+ );
+
+UINT32
+TcpRcvWinOld (
+ IN TCP_CB *Tcb
+ );
+
+UINT32
+TcpRcvWinNow (
+ IN TCP_CB *Tcb
+ );
+
+INTN
+TcpRetransmit (
+ IN TCP_CB *Tcb,
+ IN TCP_SEQNO Seq
+ );
+
+UINT32
+TcpDataToSend (
+ IN TCP_CB *Tcb,
+ IN INTN Force
+ );
+
+INTN
+TcpVerifySegment (
+ IN NET_BUF *Nbuf
+ );
+
+INTN
+TcpCheckSndQue (
+ IN NET_LIST_ENTRY *Head
+ );
+
+NET_BUF *
+TcpGetSegmentSndQue (
+ IN TCP_CB *Tcb,
+ IN TCP_SEQNO Seq,
+ IN UINT32 Len
+ );
+
+NET_BUF *
+TcpGetSegmentSock (
+ IN TCP_CB *Tcb,
+ IN TCP_SEQNO Seq,
+ IN UINT32 Len
+ );
+
+NET_BUF *
+TcpGetSegment (
+ IN TCP_CB *Tcb,
+ IN TCP_SEQNO Seq,
+ IN UINT32 Len
+ );
+
+TCP_SEQNO
+TcpGetMaxSndNxt (
+ IN TCP_CB *Tcb
+ );
+
+//
+// Functions from Tcp4Input.c
+//
+VOID
+TcpIcmpInput (
+ IN NET_BUF *Nbuf,
+ IN ICMP_ERROR IcmpErr,
+ IN UINT32 Src,
+ IN UINT32 Dst
+ );
+
+INTN
+TcpInput (
+ IN NET_BUF *Nbuf,
+ IN UINT32 Src,
+ IN UINT32 Dst
+ );
+
+INTN
+TcpSeqAcceptable (
+ IN TCP_CB *Tcb,
+ IN TCP_SEG *Seg
+ );
+
+VOID
+TcpFastRecover (
+ IN TCP_CB *Tcb,
+ IN TCP_SEG *Seg
+ );
+
+VOID
+TcpFastLossRecover (
+ IN TCP_CB *Tcb,
+ IN TCP_SEG *Seg
+ );
+
+VOID
+TcpComputeRtt (
+ IN TCP_CB *Tcb,
+ IN UINT32 Measure
+ );
+
+INTN
+TcpTrimInWnd (
+ IN TCP_CB *Tcb,
+ IN NET_BUF *Buf
+ );
+
+VOID
+TcpQueueData (
+ IN TCP_CB *Tcb,
+ IN NET_BUF *Nbuf
+ );
+
+VOID
+TcpAdjustSndQue (
+ IN TCP_CB *Tcb,
+ IN TCP_SEQNO Ack
+ );
+
+//
+// Functions from Tcp4Misc.c
+//
+UINT16
+TcpChecksum (
+ IN NET_BUF *Buf,
+ IN UINT16 HeadChecksum
+ );
+
+TCP_SEG *
+TcpFormatNetbuf (
+ IN TCP_CB *Tcb,
+ IN NET_BUF *Nbuf
+ );
+
+VOID
+TcpOnAppConnect (
+ IN TCP_CB *Tcb
+ );
+
+INTN
+TcpOnAppConsume (
+ IN TCP_CB *Tcb
+ );
+
+VOID
+TcpOnAppClose (
+ IN TCP_CB *Tcb
+ );
+
+INTN
+TcpOnAppSend (
+ IN TCP_CB *Tcb
+ );
+
+VOID
+TcpOnAppAbort (
+ IN TCP_CB *Tcb
+ );
+
+VOID
+TcpResetConnection (
+ IN TCP_CB *Tcb
+ );
+
+//
+// Functions in Tcp4Timer.c
+//
+VOID
+TcpClose (
+ IN TCP_CB *Tcb
+ );
+
+VOID
+EFIAPI
+TcpTicking (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+VOID
+TcpSetTimer (
+ IN TCP_CB *Tcb,
+ IN UINT16 Timer,
+ IN UINT32 TimeOut
+ );
+
+VOID
+TcpClearTimer (
+ IN TCP_CB *Tcb,
+ IN UINT16 Timer
+ );
+
+VOID
+TcpClearAllTimer (
+ IN TCP_CB *Tcb
+ );
+
+VOID
+TcpSetProbeTimer (
+ IN TCP_CB *Tcb
+ );
+
+VOID
+TcpSetKeepaliveTimer (
+ IN TCP_CB *Tcb
+ );
+
+VOID
+TcpBackoffRto (
+ IN TCP_CB *Tcb
+ );
+
+EFI_STATUS
+TcpSetVariableData (
+ IN TCP4_SERVICE_DATA *Tcp4Service
+ );
+
+VOID
+TcpClearVariableData (
+ IN TCP4_SERVICE_DATA *Tcp4Service
+ );
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Tcp4Input.c\r
+\r
+Abstract:\r
+\r
+ TCP input process routines.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+\r
+/**\r
+ Check whether the sequence number of the incoming segment\r
+ is acceptable.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Seg Pointer to the incoming segment.\r
+\r
+ @return 1 if the sequence number is acceptable, otherwise 0.\r
+\r
+**/\r
+INTN\r
+TcpSeqAcceptable (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP_SEG *Seg\r
+ )\r
+{\r
+ return (TCP_SEQ_LEQ (Tcb->RcvWl2, Seg->End) &&\r
+ TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2 + Tcb->RcvWnd));\r
+}\r
+\r
+\r
+/**\r
+ NewReno fast recovery, RFC3782.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Seg Segment that triggers the fast recovery.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpFastRecover (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP_SEG *Seg\r
+ )\r
+{\r
+ UINT32 FlightSize;\r
+ UINT32 Acked;\r
+\r
+ //\r
+ // Step 1: Three duplicate ACKs and not in fast recovery\r
+ //\r
+ if (Tcb->CongestState != TCP_CONGEST_RECOVER) {\r
+\r
+ //\r
+ // Step 1A: Invoking fast retransmission.\r
+ //\r
+ FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
+\r
+ Tcb->Ssthresh = NET_MAX (FlightSize >> 1, (UINT32) (2 * Tcb->SndMss));\r
+ Tcb->Recover = Tcb->SndNxt;\r
+\r
+ Tcb->CongestState = TCP_CONGEST_RECOVER;\r
+ TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
+\r
+ //\r
+ // Step 2: Entering fast retransmission\r
+ //\r
+ TcpRetransmit (Tcb, Tcb->SndUna);\r
+ Tcb->CWnd = Tcb->Ssthresh + 3 * Tcb->SndMss;\r
+\r
+ TCP4_DEBUG_TRACE (("TcpFastRecover: enter fast retransmission"\r
+ " for TCB %x, recover point is %d\n", Tcb, Tcb->Recover));\r
+ return;\r
+ }\r
+\r
+ //\r
+ // During fast recovery, execute Step 3, 4, 5 of RFC3782\r
+ //\r
+ if (Seg->Ack == Tcb->SndUna) {\r
+\r
+ //\r
+ // Step 3: Fast Recovery,\r
+ // If this is a duplicated ACK, increse Cwnd by SMSS.\r
+ //\r
+\r
+ // Step 4 is skipped here only to be executed later\r
+ // by TcpToSendData\r
+ //\r
+ Tcb->CWnd += Tcb->SndMss;\r
+ TCP4_DEBUG_TRACE (("TcpFastRecover: received another"\r
+ " duplicated ACK (%d) for TCB %x\n", Seg->Ack, Tcb));\r
+\r
+ } else {\r
+\r
+ //\r
+ // New data is ACKed, check whether it is a\r
+ // full ACK or partial ACK\r
+ //\r
+ if (TCP_SEQ_GEQ (Seg->Ack, Tcb->Recover)) {\r
+\r
+ //\r
+ // Step 5 - Full ACK:\r
+ // deflate the congestion window, and exit fast recovery\r
+ //\r
+ FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
+\r
+ Tcb->CWnd = NET_MIN (Tcb->Ssthresh, FlightSize + Tcb->SndMss);\r
+\r
+ Tcb->CongestState = TCP_CONGEST_OPEN;\r
+ TCP4_DEBUG_TRACE (("TcpFastRecover: received a full ACK(%d)"\r
+ " for TCB %x, exit fast recovery\n", Seg->Ack, Tcb));\r
+\r
+ } else {\r
+\r
+ //\r
+ // Step 5 - Partial ACK:\r
+ // fast retransmit the first unacknowledge field\r
+ // , then deflate the CWnd\r
+ //\r
+ TcpRetransmit (Tcb, Seg->Ack);\r
+ Acked = TCP_SUB_SEQ (Seg->Ack, Tcb->SndUna);\r
+\r
+ //\r
+ // Deflate the CWnd by the amount of new data\r
+ // ACKed by SEG.ACK. If more than one SMSS data\r
+ // is ACKed, add back SMSS byte to CWnd after\r
+ //\r
+ if (Acked >= Tcb->SndMss) {\r
+ Acked -= Tcb->SndMss;\r
+\r
+ }\r
+\r
+ Tcb->CWnd -= Acked;\r
+\r
+ TCP4_DEBUG_TRACE (("TcpFastRecover: received a partial"\r
+ " ACK(%d) for TCB %x\n", Seg->Ack, Tcb));\r
+\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ NewReno fast loss recovery, RFC3792.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Seg Segment that triggers the fast loss recovery.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpFastLossRecover (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP_SEG *Seg\r
+ )\r
+{\r
+ if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
+\r
+ //\r
+ // New data is ACKed, check whether it is a\r
+ // full ACK or partial ACK\r
+ //\r
+ if (TCP_SEQ_GEQ (Seg->Ack, Tcb->LossRecover)) {\r
+\r
+ //\r
+ // Full ACK: exit the loss recovery.\r
+ //\r
+ Tcb->LossTimes = 0;\r
+ Tcb->CongestState = TCP_CONGEST_OPEN;\r
+\r
+ TCP4_DEBUG_TRACE (("TcpFastLossRecover: received a "\r
+ "full ACK(%d) for TCB %x\n", Seg->Ack, Tcb));\r
+\r
+ } else {\r
+\r
+ //\r
+ // Partial ACK:\r
+ // fast retransmit the first unacknowledge field.\r
+ //\r
+ TcpRetransmit (Tcb, Seg->Ack);\r
+ TCP4_DEBUG_TRACE (("TcpFastLossRecover: received a "\r
+ "partial ACK(%d) for TCB %x\n", Seg->Ack, Tcb));\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Compute the RTT as specified in RFC2988\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Measure Currently measured RTT in heart beats.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpComputeRtt (\r
+ IN TCP_CB *Tcb,\r
+ IN UINT32 Measure\r
+ )\r
+{\r
+ INT32 Var;\r
+\r
+ //\r
+ // Step 2.3: Compute the RTO for subsequent RTT measurement.\r
+ //\r
+ if (Tcb->SRtt != 0) {\r
+\r
+ Var = Tcb->SRtt - (Measure << TCP_RTT_SHIFT);\r
+\r
+ if (Var < 0) {\r
+ Var = -Var;\r
+ }\r
+\r
+ Tcb->RttVar = (3 * Tcb->RttVar + Var) >> 2;\r
+ Tcb->SRtt = 7 * (Tcb->SRtt >> 3) + Measure;\r
+\r
+ } else {\r
+ //\r
+ // Step 2.2: compute the first RTT measure\r
+ //\r
+ Tcb->SRtt = Measure << TCP_RTT_SHIFT;\r
+ Tcb->RttVar = Measure << (TCP_RTT_SHIFT - 1);\r
+ }\r
+\r
+ Tcb->Rto = (Tcb->SRtt + NET_MAX (8, 4 * Tcb->RttVar)) >> TCP_RTT_SHIFT;\r
+\r
+ //\r
+ // Step 2.4: Limit the RTO to at least 1 second\r
+ // Step 2.5: Limit the RTO to a maxium value that\r
+ // is at least 60 second\r
+ //\r
+ if (Tcb->Rto < TCP_RTO_MIN) {\r
+ Tcb->Rto = TCP_RTO_MIN;\r
+\r
+ } else if (Tcb->Rto > TCP_RTO_MAX) {\r
+ Tcb->Rto = TCP_RTO_MAX;\r
+\r
+ }\r
+\r
+ TCP4_DEBUG_TRACE (("TcpComputeRtt: new RTT for TCB %x"\r
+ " computed SRTT: %d RTTVAR: %d RTO: %d\n",\r
+ Tcb, Tcb->SRtt, Tcb->RttVar, Tcb->Rto));\r
+\r
+}\r
+\r
+\r
+/**\r
+ Trim the data, SYN and FIN to fit into the window defined by\r
+ Left and Right.\r
+\r
+ @param Nbuf Buffer that contains received TCP segment without IP header.\r
+ @param Left The sequence number of the window's left edge.\r
+ @param Right The sequence number of the window's right edge.\r
+\r
+ @return 0, the data is successfully trimmed.\r
+\r
+**/\r
+STATIC\r
+INTN\r
+TcpTrimSegment (\r
+ IN NET_BUF *Nbuf,\r
+ IN TCP_SEQNO Left,\r
+ IN TCP_SEQNO Right\r
+ )\r
+{\r
+ TCP_SEG *Seg;\r
+ TCP_SEQNO Urg;\r
+ UINT32 Drop;\r
+\r
+ Seg = TCPSEG_NETBUF (Nbuf);\r
+\r
+ //\r
+ // If the segment is completely out of window,\r
+ // truncate every thing, include SYN and FIN.\r
+ //\r
+ if (TCP_SEQ_LEQ (Seg->End, Left) || TCP_SEQ_LEQ (Right, Seg->Seq)) {\r
+\r
+ TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);\r
+ TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);\r
+\r
+ Seg->Seq = Seg->End;\r
+ NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_HEAD);\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Adjust the buffer header\r
+ //\r
+ if (TCP_SEQ_LT (Seg->Seq, Left)) {\r
+\r
+ Drop = TCP_SUB_SEQ (Left, Seg->Seq);\r
+ Urg = Seg->Seq + Seg->Urg;\r
+ Seg->Seq = Left;\r
+\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+ TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);\r
+ Drop--;\r
+ }\r
+\r
+ //\r
+ // Adjust the urgent point\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG)) {\r
+\r
+ if (TCP_SEQ_LT (Urg, Seg->Seq)) {\r
+\r
+ TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);\r
+ } else {\r
+ Seg->Urg = (UINT16) TCP_SUB_SEQ (Urg, Seg->Seq);\r
+ }\r
+ }\r
+\r
+ if (Drop) {\r
+ NetbufTrim (Nbuf, Drop, NET_BUF_HEAD);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Adjust the buffer tail\r
+ //\r
+ if (TCP_SEQ_GT (Seg->End, Right)) {\r
+\r
+ Drop = TCP_SUB_SEQ (Seg->End, Right);\r
+ Seg->End = Right;\r
+\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
+ TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);\r
+ Drop--;\r
+ }\r
+\r
+ if (Drop) {\r
+ NetbufTrim (Nbuf, Drop, NET_BUF_TAIL);\r
+ }\r
+ }\r
+\r
+ ASSERT (TcpVerifySegment (Nbuf));\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ Trim off the data outside the tcb's receive window.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Nbuf Pointer to the NET_BUF containing the received tcp segment.\r
+\r
+ @return 0, the data is trimmed.\r
+\r
+**/\r
+INTN\r
+TcpTrimInWnd (\r
+ IN TCP_CB *Tcb,\r
+ IN NET_BUF *Nbuf\r
+ )\r
+{\r
+ return TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);\r
+}\r
+\r
+\r
+/**\r
+ Process the data and FIN flag, check whether to deliver\r
+ data to the socket layer.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @retval 0 No error occurred to deliver data.\r
+ @retval -1 Error condition occurred. Proper response is to reset the\r
+ connection.\r
+\r
+**/\r
+INTN\r
+TcpDeliverData (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_BUF *Nbuf;\r
+ TCP_SEQNO Seq;\r
+ TCP_SEG *Seg;\r
+ UINT32 Urgent;\r
+\r
+ ASSERT (Tcb && Tcb->Sk);\r
+\r
+ //\r
+ // make sure there is some data queued,\r
+ // and TCP is in a proper state\r
+ //\r
+ if (NetListIsEmpty (&Tcb->RcvQue) || !TCP_CONNECTED (Tcb->State)) {\r
+\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Deliver data to the socket layer\r
+ //\r
+ Entry = Tcb->RcvQue.ForwardLink;\r
+ Seq = Tcb->RcvNxt;\r
+\r
+ while (Entry != &Tcb->RcvQue) {\r
+ Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+ Seg = TCPSEG_NETBUF (Nbuf);\r
+\r
+ ASSERT (TcpVerifySegment (Nbuf));\r
+ ASSERT (Nbuf->Tcp == NULL);\r
+\r
+ if (TCP_SEQ_GT (Seg->Seq, Seq)) {\r
+ break;\r
+ }\r
+\r
+ Entry = Entry->ForwardLink;\r
+ Seq = Seg->End;\r
+ Tcb->RcvNxt = Seq;\r
+\r
+ NetListRemoveEntry (&Nbuf->List);\r
+\r
+ //\r
+ // RFC793 Eighth step: process FIN in sequence\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
+\r
+ //\r
+ // The peer sends to us junky data after FIN,\r
+ // reset the connection.\r
+ //\r
+ if (!NetListIsEmpty (&Tcb->RcvQue)) {\r
+ TCP4_DEBUG_ERROR (("TcpDeliverData: data received after"\r
+ " FIN from peer of TCB %x, reset connection\n", Tcb));\r
+\r
+ NetbufFree (Nbuf);\r
+ return -1;\r
+ }\r
+\r
+ TCP4_DEBUG_TRACE (("TcpDeliverData: processing FIN "\r
+ "from peer of TCB %x\n", Tcb));\r
+\r
+ switch (Tcb->State) {\r
+ case TCP_SYN_RCVD:\r
+ case TCP_ESTABLISHED:\r
+\r
+ TcpSetState (Tcb, TCP_CLOSE_WAIT);\r
+ break;\r
+\r
+ case TCP_FIN_WAIT_1:\r
+\r
+ if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
+\r
+ TcpSetState (Tcb, TCP_CLOSING);\r
+ break;\r
+ }\r
+\r
+ //\r
+ // fall through\r
+ //\r
+ case TCP_FIN_WAIT_2:\r
+\r
+ TcpSetState (Tcb, TCP_TIME_WAIT);\r
+ TcpClearAllTimer (Tcb);\r
+\r
+ if (Tcb->TimeWaitTimeout != 0) {\r
+\r
+ TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
+ } else {\r
+\r
+ TCP4_DEBUG_WARN (("Connection closed immediately "\r
+ "because app disables TIME_WAIT timer for %x\n", Tcb));\r
+\r
+ TcpSendAck (Tcb);\r
+ TcpClose (Tcb);\r
+ }\r
+ break;\r
+\r
+ case TCP_CLOSE_WAIT:\r
+ case TCP_CLOSING:\r
+ case TCP_LAST_ACK:\r
+ case TCP_TIME_WAIT:\r
+ //\r
+ // The peer sends to us junk FIN byte. Discard\r
+ // the buffer then reset the connection\r
+ //\r
+ NetbufFree (Nbuf);\r
+ return -1;\r
+ break;\r
+ }\r
+\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+\r
+ Seg->End--;\r
+ }\r
+\r
+ //\r
+ // Don't delay the ack if PUSH flag is on.\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_PSH)) {\r
+\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+ }\r
+\r
+ if (Nbuf->TotalSize) {\r
+ Urgent = 0;\r
+\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
+ TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvUp)) {\r
+\r
+ if (TCP_SEQ_LEQ (Seg->End, Tcb->RcvUp)) {\r
+ Urgent = Nbuf->TotalSize;\r
+ } else {\r
+ Urgent = TCP_SUB_SEQ (Tcb->RcvUp, Seg->Seq) + 1;\r
+ }\r
+ }\r
+\r
+ SockDataRcvd (Tcb->Sk, Nbuf, Urgent);\r
+ }\r
+\r
+ if (TCP_FIN_RCVD (Tcb->State)) {\r
+\r
+ SockNoMoreData (Tcb->Sk);\r
+ }\r
+\r
+ NetbufFree (Nbuf);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ Store the data into the reassemble queue.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Nbuf Pointer to the buffer containing the data to be queued.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpQueueData (\r
+ IN TCP_CB *Tcb,\r
+ IN NET_BUF *Nbuf\r
+ )\r
+{\r
+ TCP_SEG *Seg;\r
+ NET_LIST_ENTRY *Head;\r
+ NET_LIST_ENTRY *Prev;\r
+ NET_LIST_ENTRY *Cur;\r
+ NET_BUF *Node;\r
+\r
+ ASSERT (Tcb && Nbuf && (Nbuf->Tcp == NULL));\r
+\r
+ NET_GET_REF (Nbuf);\r
+\r
+ Seg = TCPSEG_NETBUF (Nbuf);\r
+ Head = &Tcb->RcvQue;\r
+\r
+ //\r
+ // Fast path to process normal case. That is,\r
+ // no out-of-order segments are received.\r
+ //\r
+ if (NetListIsEmpty (Head)) {\r
+\r
+ NetListInsertTail (Head, &Nbuf->List);\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Find the point to insert the buffer\r
+ //\r
+ for (Prev = Head, Cur = Head->ForwardLink;\r
+ Cur != Head;\r
+ Prev = Cur, Cur = Cur->ForwardLink) {\r
+\r
+ Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
+\r
+ if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->Seq)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check whether the current segment overlaps with the\r
+ // previous segment.\r
+ //\r
+ if (Prev != Head) {\r
+ Node = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);\r
+\r
+ if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->End)) {\r
+\r
+ if (TCP_SEQ_LEQ (Seg->End, TCPSEG_NETBUF (Node)->End)) {\r
+\r
+ NetbufFree (Nbuf);\r
+ return ;\r
+ }\r
+\r
+ TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End);\r
+ }\r
+ }\r
+\r
+ NetListInsertHead (Prev, &Nbuf->List);\r
+\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+\r
+ //\r
+ // Check the segments after the insert point.\r
+ //\r
+ while (Cur != Head) {\r
+ Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
+\r
+ if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->End, Seg->End)) {\r
+\r
+ Cur = Cur->ForwardLink;\r
+\r
+ NetListRemoveEntry (&Node->List);\r
+ NetbufFree (Node);\r
+ continue;\r
+ }\r
+\r
+ if (TCP_SEQ_LT (TCPSEG_NETBUF (Node)->Seq, Seg->End)) {\r
+\r
+ if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->Seq, Seg->Seq)) {\r
+\r
+ NetListRemoveEntry (&Nbuf->List);\r
+ NetbufFree (Nbuf);\r
+ return ;\r
+ }\r
+\r
+ TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq);\r
+ break;\r
+ }\r
+\r
+ Cur = Cur->ForwardLink;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Ajust the send queue or the retransmit queue.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Ack The acknowledge seuqence number of the received segment.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpAdjustSndQue (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP_SEQNO Ack\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Head;\r
+ NET_LIST_ENTRY *Cur;\r
+ NET_BUF *Node;\r
+ TCP_SEG *Seg;\r
+\r
+ Head = &Tcb->SndQue;\r
+ Cur = Head->ForwardLink;\r
+\r
+ while (Cur != Head) {\r
+ Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
+ Seg = TCPSEG_NETBUF (Node);\r
+\r
+ if (TCP_SEQ_GEQ (Seg->Seq, Ack)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Remove completely ACKed segments\r
+ //\r
+ if (TCP_SEQ_LEQ (Seg->End, Ack)) {\r
+ Cur = Cur->ForwardLink;\r
+\r
+ NetListRemoveEntry (&Node->List);\r
+ NetbufFree (Node);\r
+ continue;\r
+ }\r
+\r
+ TcpTrimSegment (Node, Ack, Seg->End);\r
+ break;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Process the received TCP segments.\r
+\r
+ @param Nbuf Buffer that contains received TCP segment without IP header.\r
+ @param Src Source address of the segment, or the peer's IP address.\r
+ @param Dst Destination address of the segment, or the local end's IP\r
+ address.\r
+\r
+ @retval 0 Segment is processed successfully. It is either accepted or\r
+ discarded. But no connection is reset by the segment.\r
+ @retval -1 A connection is reset by the segment.\r
+\r
+**/\r
+INTN\r
+TcpInput (\r
+ IN NET_BUF *Nbuf,\r
+ IN UINT32 Src,\r
+ IN UINT32 Dst\r
+ )\r
+{\r
+ TCP_CB *Tcb;\r
+ TCP_CB *Parent;\r
+ TCP_OPTION Option;\r
+ TCP_HEAD *Head;\r
+ INT32 Len;\r
+ TCP_SEG *Seg;\r
+ TCP_SEQNO Right;\r
+ TCP_SEQNO Urg;\r
+\r
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
+\r
+ Parent = NULL;\r
+ Tcb = NULL;\r
+\r
+ Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
+ Len = Nbuf->TotalSize - (Head->HeadLen << 2);\r
+\r
+ if ((Head->HeadLen < 5) || (Len < 0) ||\r
+ TcpChecksum (Nbuf, NetPseudoHeadChecksum (Src, Dst, 6, 0))) {\r
+\r
+ TCP4_DEBUG_TRACE (("TcpInput: received an mal-formated packet\n"));\r
+ goto DISCARD;\r
+ }\r
+\r
+ if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) {\r
+ Len++;\r
+ }\r
+\r
+ if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) {\r
+ Len++;\r
+ }\r
+\r
+ Tcb = TcpLocateTcb (\r
+ Head->DstPort,\r
+ Dst,\r
+ Head->SrcPort,\r
+ Src,\r
+ (BOOLEAN) TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)\r
+ );\r
+\r
+ if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {\r
+ TCP4_DEBUG_TRACE (("TcpInput: send reset because no TCB find\n"));\r
+\r
+ Tcb = NULL;\r
+ goto SEND_RESET;\r
+ }\r
+\r
+ Seg = TcpFormatNetbuf (Tcb, Nbuf);\r
+\r
+ //\r
+ // RFC1122 recommended reaction to illegal option\r
+ // (in fact, an illegal option length) is reset.\r
+ //\r
+ if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {\r
+ TCP4_DEBUG_ERROR (("TcpInput: reset the peer because"\r
+ " of mal-format option for Tcb %x\n", Tcb));\r
+\r
+ goto SEND_RESET;\r
+ }\r
+\r
+ //\r
+ // From now on, the segment is headless\r
+ //\r
+ NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD);\r
+ Nbuf->Tcp = NULL;\r
+\r
+ //\r
+ // TODO: add fast path process here\r
+ //\r
+\r
+ //\r
+ // Process the segment in LISTEN state.\r
+ //\r
+ if (Tcb->State == TCP_LISTEN) {\r
+ //\r
+ // First step: Check RST\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
+ TCP4_DEBUG_WARN (("TcpInput: discard a reset segment "\r
+ "for TCB %x in listening\n", Tcb));\r
+\r
+ goto DISCARD;\r
+ }\r
+\r
+ //\r
+ // Second step: Check ACK.\r
+ // Any ACK sent to TCP in LISTEN is reseted.\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
+ TCP4_DEBUG_WARN (("TcpInput: send reset because of"\r
+ " segment with ACK for TCB %x in listening\n", Tcb));\r
+\r
+ goto SEND_RESET;\r
+ }\r
+\r
+ //\r
+ // Third step: Check SYN\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+ //\r
+ // create a child TCB to handle the data\r
+ //\r
+ Parent = Tcb;\r
+\r
+ Tcb = TcpCloneTcb (Parent);\r
+ if (Tcb == NULL) {\r
+ TCP4_DEBUG_ERROR (("TcpInput: discard a segment because"\r
+ "failed to clone a child for TCB%x\n", Tcb));\r
+\r
+ goto DISCARD;\r
+ }\r
+\r
+ TCP4_DEBUG_TRACE (("TcpInput: create a child for TCB %x"\r
+ " in listening\n", Tcb));\r
+\r
+ //\r
+ // init the TCB structure\r
+ //\r
+ Tcb->LocalEnd.Ip = Dst;\r
+ Tcb->LocalEnd.Port = Head->DstPort;\r
+ Tcb->RemoteEnd.Ip = Src;\r
+ Tcb->RemoteEnd.Port = Head->SrcPort;\r
+\r
+ TcpInitTcbLocal (Tcb);\r
+ TcpInitTcbPeer (Tcb, Seg, &Option);\r
+\r
+ TcpSetState (Tcb, TCP_SYN_RCVD);\r
+ TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
+ TcpTrimInWnd (Tcb, Nbuf);\r
+\r
+ goto StepSix;\r
+ }\r
+\r
+ goto DISCARD;\r
+\r
+ } else if (Tcb->State == TCP_SYN_SENT) {\r
+ //\r
+ // First step: Check ACK bit\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) {\r
+\r
+ TCP4_DEBUG_WARN (("TcpInput: send reset because of "\r
+ "wrong ACK received for TCB %x in SYN_SENT\n", Tcb));\r
+\r
+ goto SEND_RESET;\r
+ }\r
+\r
+ //\r
+ // Second step: Check RST bit\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
+\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
+\r
+ TCP4_DEBUG_WARN (("TcpInput: connection reset by"\r
+ " peer for TCB%x in SYN_SENT\n", Tcb));\r
+\r
+ SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
+ goto DROP_CONNECTION;\r
+ } else {\r
+\r
+ TCP4_DEBUG_WARN (("TcpInput: discard a reset segment "\r
+ "because of no ACK for TCB%x in SYN_SENT\n", Tcb));\r
+\r
+ goto DISCARD;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Third step: Check security and precedence. Skipped\r
+ //\r
+\r
+ //\r
+ // Fourth step: Check SYN. Pay attention to sitimulatous open\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+\r
+ TcpInitTcbPeer (Tcb, Seg, &Option);\r
+\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
+\r
+ Tcb->SndUna = Seg->Ack;\r
+ }\r
+\r
+ TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
+\r
+ if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) {\r
+\r
+ TcpSetState (Tcb, TCP_ESTABLISHED);\r
+\r
+ TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
+ TcpDeliverData (Tcb);\r
+\r
+ if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&\r
+ TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
+\r
+ TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
+ TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
+ }\r
+\r
+ TcpTrimInWnd (Tcb, Nbuf);\r
+\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+\r
+ TCP4_DEBUG_TRACE (("TcpInput: connection established"\r
+ " for TCB %x in SYN_SENT\n", Tcb));\r
+\r
+ goto StepSix;\r
+ } else {\r
+ //\r
+ // Received a SYN segment without ACK, simultanous open.\r
+ //\r
+ TcpSetState (Tcb, TCP_SYN_RCVD);\r
+\r
+ ASSERT (Tcb->SndNxt == Tcb->Iss + 1);\r
+ TcpAdjustSndQue (Tcb, Tcb->SndNxt);\r
+\r
+ TcpTrimInWnd (Tcb, Nbuf);\r
+\r
+ TCP4_DEBUG_WARN (("TcpInput: simultanous open "\r
+ "for TCB %x in SYN_SENT\n", Tcb));\r
+\r
+ goto StepSix;\r
+ }\r
+ }\r
+\r
+ goto DISCARD;\r
+ }\r
+\r
+ //\r
+ // Process segment in SYN_RCVD or TCP_CONNECTED states\r
+ //\r
+\r
+ //\r
+ // First step: Check whether SEG.SEQ is acceptable\r
+ //\r
+ if (!TcpSeqAcceptable (Tcb, Seg)) {\r
+ TCP4_DEBUG_WARN (("TcpInput: sequence acceptance"\r
+ " test failed for segment of TCB %x\n", Tcb));\r
+\r
+ if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
+ TcpSendAck (Tcb);\r
+ }\r
+\r
+ goto DISCARD;\r
+ }\r
+\r
+ if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&\r
+ (Tcb->RcvWl2 == Seg->End) &&\r
+ !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN)) {\r
+\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+ }\r
+\r
+ //\r
+ // Second step: Check the RST\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
+\r
+ TCP4_DEBUG_WARN (("TcpInput: connection reset for TCB %x\n", Tcb));\r
+\r
+ if (Tcb->State == TCP_SYN_RCVD) {\r
+\r
+ SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);\r
+\r
+ //\r
+ // This TCB comes from either a LISTEN TCB,\r
+ // or active open TCB with simultanous open.\r
+ // Do NOT signal user CONNECTION refused\r
+ // if it comes from a LISTEN TCB.\r
+ //\r
+ } else if ((Tcb->State == TCP_ESTABLISHED) ||\r
+ (Tcb->State == TCP_FIN_WAIT_1) ||\r
+ (Tcb->State == TCP_FIN_WAIT_2) ||\r
+ (Tcb->State == TCP_CLOSE_WAIT)\r
+ ) {\r
+\r
+ SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
+\r
+ } else {\r
+ //\r
+ // TODO: set socket error to CLOSED\r
+ //\r
+ }\r
+\r
+ goto DROP_CONNECTION;\r
+ }\r
+\r
+ //\r
+ // Trim the data and flags.\r
+ //\r
+ TcpTrimInWnd (Tcb, Nbuf);\r
+\r
+ //\r
+ // Third step: Check security and precedence, Ignored\r
+ //\r
+\r
+ //\r
+ // Fourth step: Check the SYN bit.\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+\r
+ TCP4_DEBUG_WARN (("TcpInput: connection reset "\r
+ "because received extra SYN for TCB %x\n", Tcb));\r
+\r
+ SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
+ goto RESET_THEN_DROP;\r
+ }\r
+\r
+ //\r
+ // Fifth step: Check the ACK\r
+ //\r
+ if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
+ TCP4_DEBUG_WARN (("TcpInput: segment discard because"\r
+ " of no ACK for connected TCB %x\n", Tcb));\r
+\r
+ goto DISCARD;\r
+\r
+ }\r
+\r
+ if (Tcb->State == TCP_SYN_RCVD) {\r
+\r
+ if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&\r
+ TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt)) {\r
+\r
+ Tcb->SndWnd = Seg->Wnd;\r
+ Tcb->SndWndMax = NET_MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
+ Tcb->SndWl1 = Seg->Seq;\r
+ Tcb->SndWl2 = Seg->Ack;\r
+ TcpSetState (Tcb, TCP_ESTABLISHED);\r
+\r
+ TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
+ TcpDeliverData (Tcb);\r
+\r
+ TCP4_DEBUG_TRACE (("TcpInput: connection established "\r
+ " for TCB %x in SYN_RCVD\n", Tcb));\r
+\r
+ //\r
+ // Continue the process as ESTABLISHED state\r
+ //\r
+ } else {\r
+ TCP4_DEBUG_WARN (("TcpInput: send reset because of"\r
+ " wrong ACK for TCB %x in SYN_RCVD\n", Tcb));\r
+\r
+ goto SEND_RESET;\r
+ }\r
+ }\r
+\r
+ if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {\r
+\r
+ TCP4_DEBUG_WARN (("TcpInput: ignore the out-of-data"\r
+ " ACK for connected TCB %x\n", Tcb));\r
+\r
+ goto StepSix;\r
+\r
+ } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {\r
+\r
+ TCP4_DEBUG_WARN (("TcpInput: discard segment for "\r
+ "future ACK for connected TCB %x\n", Tcb));\r
+\r
+ TcpSendAck (Tcb);\r
+ goto DISCARD;\r
+ }\r
+\r
+ //\r
+ // From now on: SND.UNA <= SEG.ACK <= SND.NXT.\r
+ //\r
+ if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {\r
+ //\r
+ // update TsRecent as specified in page 16 RFC1323.\r
+ // RcvWl2 equals to the variable "LastAckSent"\r
+ // defined there.\r
+ //\r
+ if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&\r
+ TCP_SEQ_LT (Tcb->RcvWl2, Seg->End)) {\r
+\r
+ Tcb->TsRecent = Option.TSVal;\r
+ Tcb->TsRecentAge = mTcpTick;\r
+ }\r
+\r
+ TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));\r
+\r
+ } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
+\r
+ ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);\r
+\r
+ TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
+ TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
+ }\r
+\r
+ if (Seg->Ack == Tcb->SndNxt) {\r
+\r
+ TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
+ } else {\r
+\r
+ TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
+ }\r
+\r
+ //\r
+ // Count duplicate acks.\r
+ //\r
+ if ((Seg->Ack == Tcb->SndUna) &&\r
+ (Tcb->SndUna != Tcb->SndNxt) &&\r
+ (Seg->Wnd == Tcb->SndWnd) &&\r
+ (0 == Len)) {\r
+\r
+ Tcb->DupAck++;\r
+ } else {\r
+\r
+ Tcb->DupAck = 0;\r
+ }\r
+\r
+ //\r
+ // Congestion avoidance, fast recovery and fast retransmission.\r
+ //\r
+ if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||\r
+ (Tcb->CongestState == TCP_CONGEST_LOSS)) {\r
+\r
+ if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
+\r
+ if (Tcb->CWnd < Tcb->Ssthresh) {\r
+\r
+ Tcb->CWnd += Tcb->SndMss;\r
+ } else {\r
+\r
+ Tcb->CWnd += NET_MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);\r
+ }\r
+\r
+ Tcb->CWnd = NET_MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);\r
+ }\r
+\r
+ if (Tcb->CongestState == TCP_CONGEST_LOSS) {\r
+ TcpFastLossRecover (Tcb, Seg);\r
+ }\r
+ } else {\r
+\r
+ TcpFastRecover (Tcb, Seg);\r
+ }\r
+\r
+ if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
+\r
+ TcpAdjustSndQue (Tcb, Seg->Ack);\r
+ Tcb->SndUna = Seg->Ack;\r
+\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
+ (TCP_SEQ_LT (Tcb->SndUp, Seg->Ack))) {\r
+\r
+ TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Update window info\r
+ //\r
+ if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||\r
+ ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack))) {\r
+\r
+ Right = Seg->Ack + Seg->Wnd;\r
+\r
+ if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {\r
+\r
+ if ((Tcb->SndWl1 == Seg->Seq) &&\r
+ (Tcb->SndWl2 == Seg->Ack) &&\r
+ (Len == 0)) {\r
+\r
+ goto NO_UPDATE;\r
+ }\r
+\r
+ TCP4_DEBUG_WARN (("TcpInput: peer shrinks the"\r
+ " window for connected TCB %x\n", Tcb));\r
+\r
+ if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&\r
+ (TCP_SEQ_LT (Right, Tcb->Recover))) {\r
+\r
+ Tcb->Recover = Right;\r
+ }\r
+\r
+ if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&\r
+ (TCP_SEQ_LT (Right, Tcb->LossRecover))) {\r
+\r
+ Tcb->LossRecover = Right;\r
+ }\r
+\r
+ if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {\r
+\r
+ Tcb->SndNxt = Right;\r
+\r
+ if (Right == Tcb->SndUna) {\r
+\r
+ TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
+ TcpSetProbeTimer (Tcb);\r
+ }\r
+ }\r
+ }\r
+\r
+ Tcb->SndWnd = Seg->Wnd;\r
+ Tcb->SndWndMax = NET_MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
+ Tcb->SndWl1 = Seg->Seq;\r
+ Tcb->SndWl2 = Seg->Ack;\r
+ }\r
+\r
+NO_UPDATE:\r
+\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&\r
+ (Tcb->SndUna == Tcb->SndNxt)) {\r
+\r
+ TCP4_DEBUG_TRACE (("TcpInput: local FIN is ACKed by"\r
+ " peer for connected TCB %x\n", Tcb));\r
+\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);\r
+ }\r
+\r
+ //\r
+ // Transit the state if proper.\r
+ //\r
+ switch (Tcb->State) {\r
+ case TCP_FIN_WAIT_1:\r
+\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
+\r
+ TcpSetState (Tcb, TCP_FIN_WAIT_2);\r
+\r
+ TcpClearAllTimer (Tcb);\r
+ TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);\r
+ }\r
+\r
+ case TCP_FIN_WAIT_2:\r
+\r
+ break;\r
+\r
+ case TCP_CLOSE_WAIT:\r
+ break;\r
+\r
+ case TCP_CLOSING:\r
+\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
+\r
+ TcpSetState (Tcb, TCP_TIME_WAIT);\r
+\r
+ TcpClearAllTimer (Tcb);\r
+\r
+ if (Tcb->TimeWaitTimeout != 0) {\r
+\r
+ TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
+ } else {\r
+\r
+ TCP4_DEBUG_WARN (("Connection closed immediately "\r
+ "because app disables TIME_WAIT timer for %x\n", Tcb));\r
+\r
+ TcpClose (Tcb);\r
+ }\r
+ }\r
+ break;\r
+\r
+ case TCP_LAST_ACK:\r
+\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
+\r
+ TcpSetState (Tcb, TCP_CLOSED);\r
+ }\r
+\r
+ break;\r
+\r
+ case TCP_TIME_WAIT:\r
+\r
+ TcpSendAck (Tcb);\r
+\r
+ if (Tcb->TimeWaitTimeout != 0) {\r
+\r
+ TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
+ } else {\r
+\r
+ TCP4_DEBUG_WARN (("Connection closed immediately "\r
+ "because app disables TIME_WAIT timer for %x\n", Tcb));\r
+\r
+ TcpClose (Tcb);\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Sixth step: Check the URG bit.update the Urg point\r
+ // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.\r
+ //\r
+StepSix:\r
+\r
+ Tcb->Idle = 0;\r
+ TcpSetKeepaliveTimer (Tcb);\r
+\r
+ if (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_PROBE)) {\r
+\r
+ TcpClearTimer (Tcb, TCP_TIMER_PROBE);\r
+ }\r
+\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) &&\r
+ !TCP_FIN_RCVD (Tcb->State)) {\r
+\r
+ TCP4_DEBUG_TRACE (("TcpInput: received urgent data "\r
+ "from peer for connected TCB %x\n", Tcb));\r
+\r
+ Urg = Seg->Seq + Seg->Urg;\r
+\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
+ TCP_SEQ_GT (Urg, Tcb->RcvUp)) {\r
+\r
+ Tcb->RcvUp = Urg;\r
+ } else {\r
+\r
+ Tcb->RcvUp = Urg;\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Seventh step: Process the segment data\r
+ //\r
+ if (Seg->End != Seg->Seq) {\r
+\r
+ if (TCP_FIN_RCVD (Tcb->State)) {\r
+\r
+ TCP4_DEBUG_WARN (("TcpInput: connection reset because"\r
+ " data is lost for connected TCB %x\n", Tcb));\r
+\r
+ goto RESET_THEN_DROP;\r
+ }\r
+\r
+ if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {\r
+ TCP4_DEBUG_WARN (("TcpInput: connection reset because"\r
+ " data is lost for connected TCB %x\n", Tcb));\r
+\r
+ goto RESET_THEN_DROP;\r
+ }\r
+\r
+ TcpQueueData (Tcb, Nbuf);\r
+ if (TcpDeliverData (Tcb) == -1) {\r
+ goto RESET_THEN_DROP;\r
+ }\r
+\r
+ if (!NetListIsEmpty (&Tcb->RcvQue)) {\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Eighth step: check the FIN.\r
+ // This step is moved to TcpDeliverData. FIN will be\r
+ // processed in sequence there. Check the comments in\r
+ // the beginning of the file header for information.\r
+ //\r
+\r
+ //\r
+ // Tcb is a new child of the listening Parent,\r
+ // commit it.\r
+ //\r
+ if (Parent) {\r
+ Tcb->Parent = Parent;\r
+ TcpInsertTcb (Tcb);\r
+ }\r
+\r
+ if ((Tcb->State != TCP_CLOSED) &&\r
+ (!TcpToSendData (Tcb, 0)) &&\r
+ (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || Nbuf->TotalSize)) {\r
+\r
+ TcpToSendAck (Tcb);\r
+ }\r
+\r
+ NetbufFree (Nbuf);\r
+ return 0;\r
+\r
+RESET_THEN_DROP:\r
+ TcpSendReset (Tcb, Head, Len, Dst, Src);\r
+\r
+DROP_CONNECTION:\r
+ ASSERT (Tcb && Tcb->Sk);\r
+\r
+ NetbufFree (Nbuf);\r
+ TcpClose (Tcb);\r
+\r
+ return -1;\r
+\r
+SEND_RESET:\r
+\r
+ TcpSendReset (Tcb, Head, Len, Dst, Src);\r
+\r
+DISCARD:\r
+\r
+ //\r
+ // Tcb is a child of Parent, and it doesn't survive\r
+ //\r
+ TCP4_DEBUG_WARN (("Tcp4Input: Discard a packet\n"));\r
+ NetbufFree (Nbuf);\r
+\r
+ if (Parent && Tcb) {\r
+\r
+ ASSERT (Tcb->Sk);\r
+ TcpClose (Tcb);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ Process the received ICMP error messages for TCP.\r
+\r
+ @param Nbuf Buffer that contains part of the TCP segment without IP header\r
+ truncated from the ICMP error packet.\r
+ @param IcmpErr The ICMP error code interpreted from ICMP error packet.\r
+ @param Src Source address of the ICMP error message.\r
+ @param Dst Destination address of the ICMP error message.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpIcmpInput (\r
+ IN NET_BUF *Nbuf,\r
+ IN ICMP_ERROR IcmpErr,\r
+ IN UINT32 Src,\r
+ IN UINT32 Dst\r
+ )\r
+{\r
+ TCP_HEAD *Head;\r
+ TCP_CB *Tcb;\r
+ TCP_SEQNO Seq;\r
+ EFI_STATUS IcmpErrStatus;\r
+ BOOLEAN IcmpErrIsHard;\r
+ BOOLEAN IcmpErrNotify;\r
+\r
+ Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
+ Tcb = TcpLocateTcb (\r
+ Head->DstPort,\r
+ Dst,\r
+ Head->SrcPort,\r
+ Src,\r
+ FALSE\r
+ );\r
+ if (Tcb == NULL || Tcb->State == TCP_CLOSED) {\r
+\r
+ goto CLEAN_EXIT;\r
+ }\r
+\r
+ //\r
+ // Validate the sequence number.\r
+ //\r
+ Seq = NTOHL (Head->Seq);\r
+ if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {\r
+\r
+ goto CLEAN_EXIT;\r
+ }\r
+\r
+ IcmpErrStatus = IpIoGetIcmpErrStatus (IcmpErr, &IcmpErrIsHard, &IcmpErrNotify);\r
+\r
+ if (IcmpErrNotify) {\r
+\r
+ SOCK_ERROR (Tcb->Sk, IcmpErrStatus);\r
+ }\r
+\r
+ if (IcmpErrIsHard) {\r
+\r
+ TcpClose (Tcb);\r
+ }\r
+\r
+CLEAN_EXIT:\r
+ NetbufFree (Nbuf);\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Tcp4Io.c\r
+\r
+Abstract:\r
+\r
+ I/O interfaces between TCP and IpIo.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Tcp4Main.h"\r
+\r
+\r
+/**\r
+ Packet receive callback function provided to IP_IO, used to call\r
+ the proper function to handle the packet received by IP.\r
+\r
+ @param Status Status of the received packet.\r
+ @param IcmpErr ICMP error number.\r
+ @param NetSession Pointer to the net session of this packet.\r
+ @param Pkt Pointer to the recieved packet.\r
+ @param Context Pointer to the context configured in IpIoOpen(), not used\r
+ now.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Tcp4RxCallback (\r
+ IN EFI_STATUS Status,\r
+ IN ICMP_ERROR IcmpErr,\r
+ IN EFI_NET_SESSION_DATA *NetSession,\r
+ IN NET_BUF *Pkt,\r
+ IN VOID *Context OPTIONAL\r
+ )\r
+{\r
+ if (EFI_SUCCESS == Status) {\r
+ TcpInput (Pkt, NetSession->Source, NetSession->Dest);\r
+ } else {\r
+ TcpIcmpInput (Pkt, IcmpErr, NetSession->Source, NetSession->Dest);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Send the segment to IP via IpIo function.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Nbuf Pointer to the TCP segment to be sent.\r
+ @param Src Source address of the TCP segment.\r
+ @param Dest Destination address of the TCP segment.\r
+\r
+ @retval 0 The segment was sent out successfully.\r
+ @retval -1 The segment was failed to send.\r
+\r
+**/\r
+INTN\r
+TcpSendIpPacket (\r
+ IN TCP_CB *Tcb,\r
+ IN NET_BUF *Nbuf,\r
+ IN UINT32 Src,\r
+ IN UINT32 Dest\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ IP_IO *IpIo;\r
+ IP_IO_OVERRIDE Override;\r
+ SOCKET *Sock;\r
+ VOID *IpSender;\r
+ TCP4_PROTO_DATA *TcpProto;\r
+\r
+ if (NULL == Tcb) {\r
+\r
+ IpIo = NULL;\r
+ IpSender = IpIoFindSender (&IpIo, Src);\r
+\r
+ if (IpSender == NULL) {\r
+ TCP4_DEBUG_WARN (("TcpSendIpPacket: No appropriate IpSender.\n"));\r
+ return -1;\r
+ }\r
+ } else {\r
+\r
+ Sock = Tcb->Sk;\r
+ TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+ IpIo = TcpProto->TcpService->IpIo;\r
+ IpSender = Tcb->IpInfo;\r
+ }\r
+\r
+ Override.TypeOfService = 0;\r
+ Override.TimeToLive = 255;\r
+ Override.DoNotFragment = FALSE;\r
+ Override.Protocol = EFI_IP_PROTO_TCP;\r
+ EFI_IP4 (Override.GatewayAddress) = 0;\r
+ EFI_IP4 (Override.SourceAddress) = Src;\r
+\r
+ Status = IpIoSend (IpIo, Nbuf, IpSender, NULL, NULL, Dest, &Override);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ TCP4_DEBUG_ERROR (("TcpSendIpPacket: return %r error\n", Status));\r
+ return -1;\r
+ }\r
+\r
+ return 0;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Tcp4Main.c\r
+\r
+Abstract:\r
+\r
+ Implementation of TCP4 protocol services.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+\r
+/**\r
+ Check the integrity of the data buffer.\r
+\r
+ @param DataLen The total length of the data buffer.\r
+ @param FragmentCount The fragment count of the fragment table.\r
+ @param FragmentTable Pointer to the fragment table of the data\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The integrity check is passed.\r
+ @retval EFI_INVALID_PARAMETER The integrity check is failed.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Tcp4ChkDataBuf (\r
+ IN UINT32 DataLen,\r
+ IN UINT32 FragmentCount,\r
+ IN EFI_TCP4_FRAGMENT_DATA *FragmentTable\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ UINT32 Len;\r
+\r
+ for (Index = 0, Len = 0; Index < FragmentCount; Index++) {\r
+ Len = Len + FragmentTable[Index].FragmentLength;\r
+ }\r
+\r
+ if (DataLen != Len) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Get the current operational status.\r
+\r
+ @param This Pointer to the EFI_TCP4_PROTOCOL instance.\r
+ @param Tcp4State Pointer to the buffer to receive the current TCP\r
+ state.\r
+ @param Tcp4ConfigData Pointer to the buffer to receive the current TCP\r
+ configuration.\r
+ @param Ip4ModeData Pointer to the buffer to receive the current\r
+ IPv4 configuration.\r
+ @param MnpConfigData Pointer to the buffer to receive the current MNP\r
+ configuration data indirectly used by the TCPv4\r
+ Instance.\r
+ @param SnpModeData Pointer to the buffer to receive the current SNP\r
+ configuration data indirectly used by the TCPv4\r
+ Instance.\r
+\r
+ @retval EFI_SUCCESS The mode data was read.\r
+ @retval EFI_NOT_STARTED No configuration data is available because this\r
+ instance hasn't been started.\r
+ @retval EFI_INVALID_PARAMETER This is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4GetModeData (\r
+ IN CONST EFI_TCP4_PROTOCOL * This,\r
+ OUT EFI_TCP4_CONNECTION_STATE * Tcp4State OPTIONAL,\r
+ OUT EFI_TCP4_CONFIG_DATA * Tcp4ConfigData OPTIONAL,\r
+ OUT EFI_IP4_MODE_DATA * Ip4ModeData OPTIONAL,\r
+ OUT EFI_MANAGED_NETWORK_CONFIG_DATA * MnpConfigData OPTIONAL,\r
+ OUT EFI_SIMPLE_NETWORK_MODE * SnpModeData OPTIONAL\r
+ )\r
+{\r
+ TCP4_MODE_DATA TcpMode;\r
+ SOCKET *Sock;\r
+\r
+ if (NULL == This) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Sock = SOCK_FROM_THIS (This);\r
+\r
+ TcpMode.Tcp4State = Tcp4State;\r
+ TcpMode.Tcp4ConfigData = Tcp4ConfigData;\r
+ TcpMode.Ip4ModeData = Ip4ModeData;\r
+ TcpMode.MnpConfigData = MnpConfigData;\r
+ TcpMode.SnpModeData = SnpModeData;\r
+\r
+ return SockGetMode (Sock, &TcpMode);\r
+}\r
+\r
+\r
+/**\r
+ Initialize or brutally reset the operational parameters for\r
+ this EFI TCPv4 instance.\r
+\r
+ @param This Pointer to the EFI_TCP4_PROTOCOL instance.\r
+ @param TcpConfigData Pointer to the configure data to configure the\r
+ instance.\r
+\r
+ @retval EFI_SUCCESS The operational settings are set, changed, or\r
+ reset successfully.\r
+ @retval EFI_NO_MAPPING When using a default address, configuration\r
+ (through DHCP, BOOTP, RARP, etc.) is not\r
+ finished.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_ACCESS_DENIED Configuring TCP instance when it is already\r
+ configured.\r
+ @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
+ @retval EFI_UNSUPPORTED One or more of the control options are not\r
+ supported in the implementation.\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Configure (\r
+ IN EFI_TCP4_PROTOCOL * This,\r
+ IN EFI_TCP4_CONFIG_DATA * TcpConfigData OPTIONAL\r
+ )\r
+{\r
+ EFI_TCP4_OPTION *Option;\r
+ SOCKET *Sock;\r
+ EFI_STATUS Status;\r
+\r
+ if (NULL == This) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Tcp protocol related parameter check will be conducted here\r
+ //\r
+ if (NULL != TcpConfigData) {\r
+ if ((EFI_IP4 (TcpConfigData->AccessPoint.RemoteAddress) != 0) &&\r
+ !Ip4IsUnicast (EFI_NTOHL (TcpConfigData->AccessPoint.RemoteAddress), 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!TcpConfigData->AccessPoint.UseDefaultAddress) {\r
+ if (!Ip4IsUnicast (EFI_NTOHL (TcpConfigData->AccessPoint.StationAddress), 0) ||\r
+ !IP4_IS_VALID_NETMASK (EFI_NTOHL (TcpConfigData->AccessPoint.SubnetMask))\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ if (TcpConfigData->AccessPoint.ActiveFlag &&\r
+ (0 == TcpConfigData->AccessPoint.RemotePort ||\r
+ (EFI_IP4 (TcpConfigData->AccessPoint.RemoteAddress) == 0))\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Option = TcpConfigData->ControlOption;\r
+ if ((NULL != Option) &&\r
+ (Option->EnableSelectiveAck || Option->EnablePathMtuDiscovery)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ Sock = SOCK_FROM_THIS (This);\r
+\r
+ if (NULL == TcpConfigData) {\r
+ return SockFlush (Sock);\r
+ }\r
+\r
+ Status = SockConfigure (Sock, TcpConfigData);\r
+\r
+ if (EFI_NO_MAPPING == Status) {\r
+ Sock->ConfigureState = SO_NO_MAPPING;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Add or delete routing entries.\r
+\r
+ @param This Pointer to the EFI_TCP4_PROTOCOL instance.\r
+ @param DeleteRoute If TRUE, delete the specified route from routing\r
+ table; if FALSE, add the specified route to\r
+ routing table.\r
+ @param SubnetAddress The destination network.\r
+ @param SubnetMask The subnet mask for the destination network.\r
+ @param GatewayAddress The gateway address for this route.\r
+\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+ @retval EFI_NOT_STARTED The EFI_TCP4_PROTOCOL instance has not been\r
+ configured.\r
+ @retval EFI_NO_MAPPING When using a default address, configuration\r
+ (through DHCP, BOOTP, RARP, etc.) is not\r
+ finished.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate enough resources to add the\r
+ entry to the routing table.\r
+ @retval EFI_NOT_FOUND This route is not in the routing table.\r
+ @retval EFI_ACCESS_DENIED This route is already in the routing table.\r
+ @retval EFI_UNSUPPORTED The TCP driver does not support this operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Routes (\r
+ IN EFI_TCP4_PROTOCOL *This,\r
+ IN BOOLEAN DeleteRoute,\r
+ IN EFI_IPv4_ADDRESS *SubnetAddress,\r
+ IN EFI_IPv4_ADDRESS *SubnetMask,\r
+ IN EFI_IPv4_ADDRESS *GatewayAddress\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+ TCP4_ROUTE_INFO RouteInfo;\r
+\r
+ if (NULL == This) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Sock = SOCK_FROM_THIS (This);\r
+\r
+ RouteInfo.DeleteRoute = DeleteRoute;\r
+ RouteInfo.SubnetAddress = SubnetAddress;\r
+ RouteInfo.SubnetMask = SubnetMask;\r
+ RouteInfo.GatewayAddress = GatewayAddress;\r
+\r
+ return SockRoute (Sock, &RouteInfo);\r
+}\r
+\r
+\r
+/**\r
+ Initiate a nonblocking TCP connection request for an active TCP instance.\r
+\r
+ @param This Pointer to the EFI_TCP4_PROTOCOL instance\r
+ @param ConnectionToken Pointer to the connection token to return when\r
+ the TCP three way handshake finishes.\r
+\r
+ @retval EFI_SUCCESS The connection request is successfully\r
+ initiated.\r
+ @retval EFI_NOT_STARTED This EFI_TCP4_PROTOCOL instance hasn't been\r
+ configured.\r
+ @retval EFI_ACCESS_DENIED The instance is not configured as an active one\r
+ or it is not in Tcp4StateClosed state.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The driver can't allocate enough resource to\r
+ initiate the active open.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Connect (\r
+ IN EFI_TCP4_PROTOCOL *This,\r
+ IN EFI_TCP4_CONNECTION_TOKEN *ConnectionToken\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+\r
+ if (NULL == This ||\r
+ NULL == ConnectionToken ||\r
+ NULL == ConnectionToken->CompletionToken.Event) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Sock = SOCK_FROM_THIS (This);\r
+\r
+ return SockConnect (Sock, ConnectionToken);\r
+}\r
+\r
+\r
+/**\r
+ Listen on the passive instance to accept an incoming connection request.\r
+\r
+ @param This Pointer to the EFI_TCP4_PROTOCOL instance\r
+ @param ListenToken Pointer to the listen token to return when\r
+ operation finishes.\r
+\r
+ @retval EFI_SUCCESS The listen token has been queued successfully.\r
+ @retval EFI_NOT_STARTED The EFI_TCP4_PROTOCOL instance hasn't been\r
+ configured.\r
+ @retval EFI_ACCESS_DENIED The instatnce is not a passive one or it is not\r
+ in Tcp4StateListen state or a same listen token\r
+ has already existed in the listen token queue of\r
+ this TCP instance.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate enough resources to finish\r
+ the operation.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Accept (\r
+ IN EFI_TCP4_PROTOCOL *This,\r
+ IN EFI_TCP4_LISTEN_TOKEN *ListenToken\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+\r
+ if (NULL == This ||\r
+ NULL == ListenToken ||\r
+ NULL == ListenToken->CompletionToken.Event) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Sock = SOCK_FROM_THIS (This);\r
+\r
+ return SockAccept (Sock, ListenToken);\r
+}\r
+\r
+\r
+/**\r
+ Queues outgoing data into the transmit queue\r
+\r
+ @param This Pointer to the EFI_TCP4_PROTOCOL instance\r
+ @param Token Pointer to the completion token to queue to the\r
+ transmit queue\r
+\r
+ @retval EFI_SUCCESS The data has been queued for transmission\r
+ @retval EFI_NOT_STARTED The EFI_TCP4_PROTOCOL instance hasn't been\r
+ configured.\r
+ @retval EFI_NO_MAPPING When using a default address, configuration\r
+ (DHCP, BOOTP, RARP, etc.) is not finished yet.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid\r
+ @retval EFI_ACCESS_DENIED One or more of the following conditions is TRUE:\r
+ * A transmit completion token with the same\r
+ Token-> CompletionToken.Event was already in the\r
+ transmission queue. * The current instance is in\r
+ Tcp4StateClosed state * The current instance is\r
+ a passive one and it is in Tcp4StateListen\r
+ state. * User has called Close() to disconnect\r
+ this connection.\r
+ @retval EFI_NOT_READY The completion token could not be queued because\r
+ the transmit queue is full.\r
+ @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data because of\r
+ resource shortage.\r
+ @retval EFI_NETWORK_UNREACHABLE There is no route to the destination network or\r
+ address.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Transmit (\r
+ IN EFI_TCP4_PROTOCOL *This,\r
+ IN EFI_TCP4_IO_TOKEN *Token\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+ EFI_STATUS Status;\r
+\r
+ if (NULL == This ||\r
+ NULL == Token ||\r
+ NULL == Token->CompletionToken.Event ||\r
+ NULL == Token->Packet.TxData ||\r
+ 0 == Token->Packet.TxData->FragmentCount ||\r
+ 0 == Token->Packet.TxData->DataLength\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = Tcp4ChkDataBuf (\r
+ Token->Packet.TxData->DataLength,\r
+ Token->Packet.TxData->FragmentCount,\r
+ Token->Packet.TxData->FragmentTable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Sock = SOCK_FROM_THIS (This);\r
+\r
+ return SockSend (Sock, Token);\r
+\r
+}\r
+\r
+\r
+/**\r
+ Place an asynchronous receive request into the receiving queue.\r
+\r
+ @param This Pointer to the EFI_TCP4_PROTOCOL instance.\r
+ @param Token Pointer to a token that is associated with the\r
+ receive data descriptor.\r
+\r
+ @retval EFI_SUCCESS The receive completion token was cached\r
+ @retval EFI_NOT_STARTED The EFI_TCP4_PROTOCOL instance hasn't been\r
+ configured.\r
+ @retval EFI_NO_MAPPING When using a default address, configuration\r
+ (DHCP, BOOTP, RARP, etc.) is not finished yet.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued\r
+ due to a lack of system resources.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
+ @retval EFI_ACCESS_DENIED One or more of the following conditions is TRUE:\r
+ * A receive completion token with the same\r
+ Token->CompletionToken.Event was already in the\r
+ receive queue. * The current instance is in\r
+ Tcp4StateClosed state. * The current instance is\r
+ a passive one and it is in Tcp4StateListen\r
+ state. * User has called Close() to disconnect\r
+ this connection.\r
+ @retval EFI_CONNECTION_FIN The communication peer has closed the connection\r
+ and there is no any buffered data in the receive\r
+ buffer of this instance.\r
+ @retval EFI_NOT_READY The receive request could not be queued because\r
+ the receive queue is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Receive (\r
+ IN EFI_TCP4_PROTOCOL *This,\r
+ IN EFI_TCP4_IO_TOKEN *Token\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+ EFI_STATUS Status;\r
+\r
+ if (NULL == This ||\r
+ NULL == Token ||\r
+ NULL == Token->CompletionToken.Event ||\r
+ NULL == Token->Packet.RxData ||\r
+ 0 == Token->Packet.RxData->FragmentCount ||\r
+ 0 == Token->Packet.RxData->DataLength\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = Tcp4ChkDataBuf (\r
+ Token->Packet.RxData->DataLength,\r
+ Token->Packet.RxData->FragmentCount,\r
+ Token->Packet.RxData->FragmentTable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Sock = SOCK_FROM_THIS (This);\r
+\r
+ return SockRcv (Sock, Token);\r
+\r
+}\r
+\r
+\r
+/**\r
+ Disconnecting a TCP connection gracefully or reset a TCP connection.\r
+\r
+ @param This Pointer to the EFI_TCP4_PROTOCOL instance\r
+ @param CloseToken Pointer to the close token to return when\r
+ operation finishes.\r
+\r
+ @retval EFI_SUCCESS The operation completed successfully\r
+ @retval EFI_NOT_STARTED The EFI_TCP4_PROTOCOL instance hasn't been\r
+ configured.\r
+ @retval EFI_ACCESS_DENIED One or more of the following are TRUE: *\r
+ Configure() has been called with TcpConfigData\r
+ set to NULL and this function has not returned.\r
+ * Previous Close() call on this instance has not\r
+ finished.\r
+ @retval EFI_INVALID_PARAMETER One ore more parameters are invalid\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate enough resource to finish the\r
+ operation\r
+ @retval EFI_DEVICE_ERROR Any unexpected and not belonged to above\r
+ category error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Close (\r
+ IN EFI_TCP4_PROTOCOL *This,\r
+ IN EFI_TCP4_CLOSE_TOKEN *CloseToken\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+\r
+ if (NULL == This ||\r
+ NULL == CloseToken ||\r
+ NULL == CloseToken->CompletionToken.Event) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Sock = SOCK_FROM_THIS (This);\r
+\r
+ return SockClose (Sock, CloseToken, CloseToken->AbortOnClose);\r
+}\r
+\r
+\r
+/**\r
+ Abort an asynchronous connection, listen, transmission or receive request.\r
+\r
+ @param This Pointer to the EFI_TCP4_PROTOCOL instance.\r
+ @param Token Pointer to a token that has been issued by\r
+ Connect(), Accept(), Transmit() or Receive(). If\r
+ NULL, all pending tokens issued by above four\r
+ functions will be aborted.\r
+\r
+ @retval EFI_UNSUPPORTED The operation is not supported in current\r
+ implementation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Cancel (\r
+ IN EFI_TCP4_PROTOCOL * This,\r
+ IN EFI_TCP4_COMPLETION_TOKEN * Token OPTIONAL\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+ Poll to receive incoming data and transmit outgoing segments.\r
+\r
+ @param This Pointer to the EFI_TCP4_PROTOCOL instance.\r
+\r
+ @retval EFI_SUCCESS Incoming or outgoing data was processed.\r
+ @retval EFI_INVALID_PARAMETER This is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
+ @retval EFI_NOT_READY No incoming or outgoing data was processed.\r
+ @retval EFI_TIMEOUT Data was dropped out of the transmission or\r
+ receive queue. Consider increasing the polling\r
+ rate.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Tcp4Poll (\r
+ IN EFI_TCP4_PROTOCOL *This\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+ EFI_STATUS Status;\r
+\r
+ if (NULL == This) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Sock = SOCK_FROM_THIS (This);\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_POLL, NULL);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 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:
+
+ Tcp4Main.h
+
+Abstract:
+
+
+**/
+
+#ifndef _TCP4_MAIN_H_
+#define _TCP4_MAIN_H_
+
+#include "Socket.h"
+
+#include "Tcp4Proto.h"
+#include "Tcp4Driver.h"
+
+
+extern UINT16 mTcp4RandomPort;
+
+//
+// Driver Produced Protocol Prototypes
+//
+//@MT:#include EFI_PROTOCOL_PRODUCER (Tcp4)
+
+#define TCP4_DEBUG_ERROR(PrintArg) NET_DEBUG_ERROR ("Tcp", PrintArg)
+#define TCP4_DEBUG_WARN(PrintArg) NET_DEBUG_WARNING ("Tcp", PrintArg)
+#define TCP4_DEBUG_TRACE(PrintArg) NET_DEBUG_TRACE ("Tcp", PrintArg)
+
+//
+// Function prototype for the Tcp4 socket request handler
+//
+EFI_STATUS
+Tcp4Dispatcher (
+ IN SOCKET *Sock,
+ IN SOCK_REQUEST Request,
+ IN VOID *Data OPTIONAL
+ );
+
+typedef struct _TCP4_MODE_DATA {
+ EFI_TCP4_CONNECTION_STATE *Tcp4State;
+ EFI_TCP4_CONFIG_DATA *Tcp4ConfigData;
+ EFI_IP4_MODE_DATA *Ip4ModeData;
+ EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData;
+ EFI_SIMPLE_NETWORK_MODE *SnpModeData;
+} TCP4_MODE_DATA;
+
+typedef struct _TCP4_ROUTE_INFO {
+ BOOLEAN DeleteRoute;
+ EFI_IPv4_ADDRESS *SubnetAddress;
+ EFI_IPv4_ADDRESS *SubnetMask;
+ EFI_IPv4_ADDRESS *GatewayAddress;
+} TCP4_ROUTE_INFO;
+
+//
+// Get the mode data of a TCP instance
+//
+EFI_STATUS
+EFIAPI
+Tcp4GetModeData (
+ IN CONST EFI_TCP4_PROTOCOL * This,
+ OUT EFI_TCP4_CONNECTION_STATE * Tcp4State OPTIONAL,
+ OUT EFI_TCP4_CONFIG_DATA * Tcp4ConfigData OPTIONAL,
+ OUT EFI_IP4_MODE_DATA * Ip4ModeData OPTIONAL,
+ OUT EFI_MANAGED_NETWORK_CONFIG_DATA * MnpConfigData OPTIONAL,
+ OUT EFI_SIMPLE_NETWORK_MODE * SnpModeData OPTIONAL
+ );
+
+//
+// Initialize or reset a TCP instance
+//
+EFI_STATUS
+EFIAPI
+Tcp4Configure (
+ IN EFI_TCP4_PROTOCOL * This,
+ IN EFI_TCP4_CONFIG_DATA * TcpConfigData OPTIONAL
+ );
+
+//
+// Add a route entry to the route table
+//
+EFI_STATUS
+EFIAPI
+Tcp4Routes (
+ IN EFI_TCP4_PROTOCOL *This,
+ IN BOOLEAN DeleteRoute,
+ IN EFI_IPv4_ADDRESS *SubnetAddress,
+ IN EFI_IPv4_ADDRESS *SubnetMask,
+ IN EFI_IPv4_ADDRESS *GatewayAddress
+ );
+
+//
+// Issue an asynchronous connection establishment
+// request to the peer
+//
+EFI_STATUS
+EFIAPI
+Tcp4Connect (
+ IN EFI_TCP4_PROTOCOL *This,
+ IN EFI_TCP4_CONNECTION_TOKEN *ConnectionToken
+ );
+
+//
+// Issue an asynchronous listent token to accept an
+// incoming connection reques
+//
+EFI_STATUS
+EFIAPI
+Tcp4Accept (
+ IN EFI_TCP4_PROTOCOL *This,
+ IN EFI_TCP4_LISTEN_TOKEN *ListenToken
+ );
+
+//
+// Issue an asynchronous IO token to transmit some data
+// through this TCP instance
+//
+EFI_STATUS
+EFIAPI
+Tcp4Transmit (
+ IN EFI_TCP4_PROTOCOL *This,
+ IN EFI_TCP4_IO_TOKEN *Token
+ );
+
+//
+// Issue an asynchronous IO token to receive some data
+// through this TCP instance
+//
+EFI_STATUS
+Tcp4Receive (
+ IN EFI_TCP4_PROTOCOL *This,
+ IN EFI_TCP4_IO_TOKEN *Token
+ );
+
+//
+// Issue an asynchronous CloseToken to close a TCP
+// connection represented by instance
+//
+EFI_STATUS
+EFIAPI
+Tcp4Close (
+ IN EFI_TCP4_PROTOCOL *This,
+ IN EFI_TCP4_CLOSE_TOKEN *CloseToken
+ );
+
+//
+// cancle an connect, listent or IO token
+//
+EFI_STATUS
+EFIAPI
+Tcp4Cancel (
+ IN EFI_TCP4_PROTOCOL * This,
+ IN EFI_TCP4_COMPLETION_TOKEN * Token OPTIONAL
+ );
+
+//
+// poll data from NIC for receive
+//
+EFI_STATUS
+EFIAPI
+Tcp4Poll (
+ IN EFI_TCP4_PROTOCOL *This
+ );
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Tcp4Misc.c\r
+\r
+Abstract:\r
+\r
+ Misc support routines for tcp.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Tcp4Main.h"\r
+\r
+NET_LIST_ENTRY mTcpRunQue = {\r
+ &mTcpRunQue,\r
+ &mTcpRunQue\r
+};\r
+\r
+NET_LIST_ENTRY mTcpListenQue = {\r
+ &mTcpListenQue,\r
+ &mTcpListenQue\r
+};\r
+\r
+TCP_SEQNO mTcpGlobalIss = 0x4d7e980b;\r
+\r
+STATIC CHAR16 *mTcpStateName[] = {\r
+ L"TCP_CLOSED",\r
+ L"TCP_LISTEN",\r
+ L"TCP_SYN_SENT",\r
+ L"TCP_SYN_RCVD",\r
+ L"TCP_ESTABLISHED",\r
+ L"TCP_FIN_WAIT_1",\r
+ L"TCP_FIN_WAIT_2",\r
+ L"TCP_CLOSING",\r
+ L"TCP_TIME_WAIT",\r
+ L"TCP_CLOSE_WAIT",\r
+ L"TCP_LAST_ACK"\r
+};\r
+\r
+\r
+/**\r
+ Initialize the Tcb local related members.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+TcpInitTcbLocal (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ //\r
+ // Compute the checksum of the fixed parts of pseudo header\r
+ //\r
+ Tcb->HeadSum = NetPseudoHeadChecksum (\r
+ Tcb->LocalEnd.Ip,\r
+ Tcb->RemoteEnd.Ip,\r
+ 0x06,\r
+ 0\r
+ );\r
+\r
+ Tcb->Iss = TcpGetIss ();\r
+ Tcb->SndUna = Tcb->Iss;\r
+ Tcb->SndNxt = Tcb->Iss;\r
+\r
+ Tcb->SndWl2 = Tcb->Iss;\r
+ Tcb->SndWnd = 536;\r
+\r
+ Tcb->RcvWnd = GET_RCV_BUFFSIZE (Tcb->Sk);\r
+\r
+ //\r
+ // Fisrt window size is never scaled\r
+ //\r
+ Tcb->RcvWndScale = 0;\r
+}\r
+\r
+\r
+/**\r
+ Initialize the peer related members.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Seg Pointer to the segment that contains the peer's\r
+ intial info.\r
+ @param Opt Pointer to the options announced by the peer.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+TcpInitTcbPeer (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP_SEG *Seg,\r
+ IN TCP_OPTION *Opt\r
+ )\r
+{\r
+ UINT16 RcvMss;\r
+\r
+ ASSERT (Tcb && Seg && Opt);\r
+ ASSERT (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN));\r
+\r
+ Tcb->SndWnd = Seg->Wnd;\r
+ Tcb->SndWndMax = Tcb->SndWnd;\r
+ Tcb->SndWl1 = Seg->Seq;\r
+\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
+ Tcb->SndWl2 = Seg->Ack;\r
+ } else {\r
+ Tcb->SndWl2 = Tcb->Iss + 1;\r
+ }\r
+\r
+ if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_MSS)) {\r
+ Tcb->SndMss = NET_MAX (64, Opt->Mss);\r
+\r
+ RcvMss = TcpGetRcvMss (Tcb->Sk);\r
+ if (Tcb->SndMss > RcvMss) {\r
+ Tcb->SndMss = RcvMss;\r
+ }\r
+\r
+ } else {\r
+ //\r
+ // One end doesn't support MSS option, use default.\r
+ //\r
+ Tcb->RcvMss = 536;\r
+ }\r
+\r
+ Tcb->CWnd = Tcb->SndMss;\r
+\r
+ Tcb->Irs = Seg->Seq;\r
+ Tcb->RcvNxt = Tcb->Irs + 1;\r
+\r
+ Tcb->RcvWl2 = Tcb->RcvNxt;\r
+\r
+ if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_WS) &&\r
+ !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS)) {\r
+\r
+ Tcb->SndWndScale = Opt->WndScale;\r
+\r
+ Tcb->RcvWndScale = TcpComputeScale (Tcb);\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS);\r
+\r
+ } else {\r
+ //\r
+ // One end doesn't support window scale option. use zero.\r
+ //\r
+ Tcb->RcvWndScale = 0;\r
+ }\r
+\r
+ if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_TS) &&\r
+ !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS)) {\r
+\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_TS);\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS);\r
+\r
+ //\r
+ // Compute the effective SndMss per RFC1122\r
+ // section 4.2.2.6. If timestamp option is\r
+ // enabled, it will always occupy 12 bytes.\r
+ //\r
+ Tcb->SndMss -= TCP_OPTION_TS_ALIGNED_LEN;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Locate a listen TCB that matchs the Local and Remote.\r
+\r
+ @param Local Pointer to the local (IP, Port).\r
+ @param Remote Pointer to the remote (IP, Port).\r
+\r
+ @return Pointer to the TCP_CB with the least number of wildcard, if NULL no match is found.\r
+\r
+**/\r
+STATIC\r
+TCP_CB *\r
+TcpLocateListenTcb (\r
+ IN TCP_PEER *Local,\r
+ IN TCP_PEER *Remote\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ TCP_CB *Node;\r
+ TCP_CB *Match;\r
+ INTN Last;\r
+ INTN Cur;\r
+\r
+ Last = 4;\r
+ Match = NULL;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
+ Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ if ((Local->Port != Node->LocalEnd.Port) ||\r
+ !TCP_PEER_MATCH (Remote, &Node->RemoteEnd) ||\r
+ !TCP_PEER_MATCH (Local, &Node->LocalEnd)\r
+ ) {\r
+\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Compute the number of wildcard\r
+ //\r
+ Cur = 0;\r
+ if (Node->RemoteEnd.Ip == 0) {\r
+ Cur++;\r
+ }\r
+\r
+ if (Node->RemoteEnd.Port == 0) {\r
+ Cur++;\r
+ }\r
+\r
+ if (Node->LocalEnd.Ip == 0) {\r
+ Cur++;\r
+ }\r
+\r
+ if (Cur < Last) {\r
+ if (Cur == 0) {\r
+ return Node;\r
+ }\r
+\r
+ Last = Cur;\r
+ Match = Node;\r
+ }\r
+ }\r
+\r
+ return Match;\r
+}\r
+\r
+\r
+/**\r
+ Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.\r
+\r
+ @param Addr Pointer to the IP address needs to match.\r
+ @param Port The port number needs to match.\r
+\r
+ @return The Tcb which matches the <Addr Port> paire exists or not.\r
+\r
+**/\r
+BOOLEAN\r
+TcpFindTcbByPeer (\r
+ IN EFI_IPv4_ADDRESS *Addr,\r
+ IN TCP_PORTNO Port\r
+ )\r
+{\r
+ TCP_PORTNO LocalPort;\r
+ NET_LIST_ENTRY *Entry;\r
+ TCP_CB *Tcb;\r
+\r
+ ASSERT ((Addr != NULL) && (Port != 0));\r
+\r
+ LocalPort = HTONS (Port);\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
+ Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ if ((EFI_IP4 (*Addr) == Tcb->LocalEnd.Ip) &&\r
+ (LocalPort == Tcb->LocalEnd.Port)) {\r
+\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
+ Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ if (((EFI_IP4 (*Addr) == Tcb->LocalEnd.Ip)) &&\r
+ (LocalPort == Tcb->LocalEnd.Port)) {\r
+\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Locate the TCP_CB related to the socket pair.\r
+\r
+ @param LocalPort The local port number.\r
+ @param LocalIp The local IP address.\r
+ @param RemotePort The remote port number.\r
+ @param RemoteIp The remote IP address.\r
+ @param Syn Whether to search the listen sockets, if TRUE, the\r
+ listen sockets are searched.\r
+\r
+ @return Pointer to the related TCP_CB, if NULL no match is found.\r
+\r
+**/\r
+TCP_CB *\r
+TcpLocateTcb (\r
+ IN TCP_PORTNO LocalPort,\r
+ IN UINT32 LocalIp,\r
+ IN TCP_PORTNO RemotePort,\r
+ IN UINT32 RemoteIp,\r
+ IN BOOLEAN Syn\r
+ )\r
+{\r
+ TCP_PEER Local;\r
+ TCP_PEER Remote;\r
+ NET_LIST_ENTRY *Entry;\r
+ TCP_CB *Tcb;\r
+\r
+ Local.Port = LocalPort;\r
+ Local.Ip = LocalIp;\r
+\r
+ Remote.Port = RemotePort;\r
+ Remote.Ip = RemoteIp;\r
+\r
+ //\r
+ // First check for exact match.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
+ Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ if (TCP_PEER_EQUAL (&Remote, &Tcb->RemoteEnd) &&\r
+ TCP_PEER_EQUAL (&Local, &Tcb->LocalEnd)) {\r
+\r
+ NetListRemoveEntry (&Tcb->List);\r
+ NetListInsertHead (&mTcpRunQue, &Tcb->List);\r
+\r
+ return Tcb;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Only check listen queue when SYN flag is on\r
+ //\r
+ if (Syn) {\r
+ return TcpLocateListenTcb (&Local, &Remote);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Insert a Tcb into the proper queue.\r
+\r
+ @param Tcb Pointer to the TCP_CB to be inserted.\r
+\r
+ @retval 0 The Tcb is inserted successfully.\r
+ @retval -1 Error condition occurred.\r
+\r
+**/\r
+INTN\r
+TcpInsertTcb (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Head;\r
+ TCP_CB *Node;\r
+ TCP4_PROTO_DATA *TcpProto;\r
+\r
+ ASSERT (\r
+ Tcb &&\r
+ (\r
+ (Tcb->State == TCP_LISTEN) ||\r
+ (Tcb->State == TCP_SYN_SENT) ||\r
+ (Tcb->State == TCP_SYN_RCVD) ||\r
+ (Tcb->State == TCP_CLOSED)\r
+ )\r
+ );\r
+\r
+ if (Tcb->LocalEnd.Port == 0) {\r
+ return -1;\r
+ }\r
+\r
+ Head = &mTcpRunQue;\r
+\r
+ if (Tcb->State == TCP_LISTEN) {\r
+ Head = &mTcpListenQue;\r
+ }\r
+\r
+ //\r
+ // Check that Tcb isn't already on the list.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, Head) {\r
+ Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ if (TCP_PEER_EQUAL (&Tcb->LocalEnd, &Node->LocalEnd) &&\r
+ TCP_PEER_EQUAL (&Tcb->RemoteEnd, &Node->RemoteEnd)) {\r
+\r
+ return -1;\r
+ }\r
+ }\r
+\r
+ NetListInsertHead (Head, &Tcb->List);\r
+\r
+ TcpProto = (TCP4_PROTO_DATA *) Tcb->Sk->ProtoReserved;\r
+ TcpSetVariableData (TcpProto->TcpService);\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ Clone a TCP_CB from Tcb.\r
+\r
+ @param Tcb Pointer to the TCP_CB to be cloned.\r
+\r
+ @return Pointer to the new cloned TCP_CB, if NULL error condition occurred.\r
+\r
+**/\r
+TCP_CB *\r
+TcpCloneTcb (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ TCP_CB *Clone;\r
+\r
+ Clone = NetAllocatePool (sizeof (TCP_CB));\r
+\r
+ if (Clone == NULL) {\r
+ return NULL;\r
+\r
+ }\r
+\r
+ NetCopyMem (Clone, Tcb, sizeof (TCP_CB));\r
+\r
+ //\r
+ // Increate the reference count of the shared IpInfo.\r
+ //\r
+ NET_GET_REF (Tcb->IpInfo);\r
+\r
+ NetListInit (&Clone->List);\r
+ NetListInit (&Clone->SndQue);\r
+ NetListInit (&Clone->RcvQue);\r
+\r
+ Clone->Sk = SockClone (Tcb->Sk);\r
+ if (Clone->Sk == NULL) {\r
+ TCP4_DEBUG_ERROR (("TcpCloneTcb: failed to clone a sock\n"));\r
+ NetFreePool (Clone);\r
+ return NULL;\r
+ }\r
+\r
+ ((TCP4_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpPcb = Clone;\r
+\r
+ return Clone;\r
+}\r
+\r
+\r
+/**\r
+ Compute an ISS to be used by a new connection.\r
+\r
+ None\r
+\r
+ @return The result ISS.\r
+\r
+**/\r
+TCP_SEQNO\r
+TcpGetIss (\r
+ VOID\r
+ )\r
+{\r
+ mTcpGlobalIss += 2048;\r
+ return mTcpGlobalIss;\r
+}\r
+\r
+\r
+/**\r
+ Get the local mss.\r
+\r
+ None\r
+\r
+ @return The mss size.\r
+\r
+**/\r
+UINT16\r
+TcpGetRcvMss (\r
+ IN SOCKET *Sock\r
+ )\r
+{\r
+ EFI_SIMPLE_NETWORK_MODE SnpMode;\r
+ TCP4_PROTO_DATA *TcpProto;\r
+ EFI_IP4_PROTOCOL *Ip;\r
+\r
+ ASSERT (Sock);\r
+\r
+ TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;\r
+ Ip = TcpProto->TcpService->IpIo->Ip;\r
+ ASSERT (Ip);\r
+\r
+ Ip->GetModeData (Ip, NULL, NULL, &SnpMode);\r
+\r
+ return (UINT16) (SnpMode.MaxPacketSize - 40);\r
+}\r
+\r
+\r
+/**\r
+ Set the Tcb's state.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param State The state to be set.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+TcpSetState (\r
+ IN TCP_CB *Tcb,\r
+ IN UINT8 State\r
+ )\r
+{\r
+ TCP4_DEBUG_TRACE (\r
+ ("Tcb (%x) state %s --> %s\n",\r
+ Tcb,\r
+ mTcpStateName[Tcb->State],\r
+ mTcpStateName[State])\r
+ );\r
+\r
+ Tcb->State = State;\r
+\r
+ switch (State) {\r
+ case TCP_ESTABLISHED:\r
+\r
+ SockConnEstablished (Tcb->Sk);\r
+ break;\r
+\r
+ case TCP_CLOSED:\r
+\r
+ SockConnClosed (Tcb->Sk);\r
+\r
+ break;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Compute the TCP segment's checksum.\r
+\r
+ @param Nbuf Pointer to the buffer that contains the TCP\r
+ segment.\r
+ @param HeadSum The checksum value of the fixed part of pseudo\r
+ header.\r
+\r
+ @return The checksum value.\r
+\r
+**/\r
+UINT16\r
+TcpChecksum (\r
+ IN NET_BUF *Nbuf,\r
+ IN UINT16 HeadSum\r
+ )\r
+{\r
+ UINT16 Checksum;\r
+\r
+ Checksum = NetbufChecksum (Nbuf);\r
+ Checksum = NetAddChecksum (Checksum, HeadSum);\r
+\r
+ Checksum = NetAddChecksum (\r
+ Checksum,\r
+ HTONS ((UINT16) Nbuf->TotalSize)\r
+ );\r
+\r
+ return ~Checksum;\r
+}\r
+\r
+\r
+/**\r
+ Translate the information from the head of the received TCP\r
+ segment Nbuf contains and fill it into a TCP_SEG structure.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Nbuf Pointer to the buffer contains the TCP segment.\r
+\r
+ @return Pointer to the TCP_SEG that contains the translated TCP head information.\r
+\r
+**/\r
+TCP_SEG *\r
+TcpFormatNetbuf (\r
+ IN TCP_CB *Tcb,\r
+ IN NET_BUF *Nbuf\r
+ )\r
+{\r
+ TCP_SEG *Seg;\r
+ TCP_HEAD *Head;\r
+\r
+ Seg = TCPSEG_NETBUF (Nbuf);\r
+ Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
+ Nbuf->Tcp = Head;\r
+\r
+ Seg->Seq = NTOHL (Head->Seq);\r
+ Seg->Ack = NTOHL (Head->Ack);\r
+ Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));\r
+\r
+ Seg->Urg = NTOHS (Head->Urg);\r
+ Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale);\r
+ Seg->Flag = Head->Flag;\r
+\r
+ //\r
+ // SYN and FIN flag occupy one sequence space each.\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+ //\r
+ // RFC requires that initial window not be scaled\r
+ //\r
+ Seg->Wnd = NTOHS (Head->Wnd);\r
+ Seg->End++;\r
+ }\r
+\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
+ Seg->End++;\r
+ }\r
+\r
+ return Seg;\r
+}\r
+\r
+\r
+/**\r
+ Reset the connection related with Tcb.\r
+\r
+ @param Tcb Pointer to the TCP_CB of the connection to be\r
+ reset.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+TcpResetConnection (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ NET_BUF *Nbuf;\r
+ TCP_HEAD *Nhead;\r
+\r
+ Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
+\r
+ if (Nbuf == NULL) {\r
+ return ;\r
+ }\r
+\r
+ Nhead = (TCP_HEAD *) NetbufAllocSpace (\r
+ Nbuf,\r
+ sizeof (TCP_HEAD),\r
+ NET_BUF_TAIL\r
+ );\r
+\r
+ ASSERT (Nhead != NULL);\r
+\r
+ Nbuf->Tcp = Nhead;\r
+\r
+ Nhead->Flag = TCP_FLG_RST;\r
+ Nhead->Seq = HTONL (Tcb->SndNxt);\r
+ Nhead->Ack = HTONL (Tcb->RcvNxt);\r
+ Nhead->SrcPort = Tcb->LocalEnd.Port;\r
+ Nhead->DstPort = Tcb->RemoteEnd.Port;\r
+ Nhead->HeadLen = (sizeof (TCP_HEAD) >> 2);\r
+ Nhead->Res = 0;\r
+ Nhead->Wnd = HTONS (0xFFFF);\r
+ Nhead->Checksum = 0;\r
+ Nhead->Urg = 0;\r
+ Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);\r
+\r
+ TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);\r
+\r
+ NetbufFree (Nbuf);\r
+}\r
+\r
+\r
+/**\r
+ Initialize an active connection,\r
+\r
+ @param Tcb Pointer to the TCP_CB that wants to initiate a\r
+ connection.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+TcpOnAppConnect (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ TcpInitTcbLocal (Tcb);\r
+ TcpSetState (Tcb, TCP_SYN_SENT);\r
+\r
+ TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
+ TcpToSendData (Tcb, 1);\r
+}\r
+\r
+\r
+/**\r
+ Initiate the connection close procedure, called when\r
+ applications want to close the connection.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpOnAppClose (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ ASSERT (Tcb);\r
+\r
+ if (!NetListIsEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk)) {\r
+\r
+ TCP4_DEBUG_WARN (("TcpOnAppClose: connection reset "\r
+ "because data is lost for TCB %x\n", Tcb));\r
+\r
+ TcpResetConnection (Tcb);\r
+ TcpClose (Tcb);\r
+ return;\r
+ }\r
+\r
+ switch (Tcb->State) {\r
+ case TCP_CLOSED:\r
+ case TCP_LISTEN:\r
+ case TCP_SYN_SENT:\r
+ TcpSetState (Tcb, TCP_CLOSED);\r
+ break;\r
+\r
+ case TCP_SYN_RCVD:\r
+ case TCP_ESTABLISHED:\r
+ TcpSetState (Tcb, TCP_FIN_WAIT_1);\r
+ break;\r
+\r
+ case TCP_CLOSE_WAIT:\r
+ TcpSetState (Tcb, TCP_LAST_ACK);\r
+ break;\r
+ }\r
+\r
+ TcpToSendData (Tcb, 1);\r
+}\r
+\r
+\r
+/**\r
+ Check whether the application's newly delivered data\r
+ can be sent out.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @retval 0 Whether the data is sent out or is buffered for\r
+ further sending.\r
+ @retval -1 The Tcb is not in a state that data is permitted to\r
+ be sent out.\r
+\r
+**/\r
+INTN\r
+TcpOnAppSend (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+\r
+ switch (Tcb->State) {\r
+ case TCP_CLOSED:\r
+ return -1;\r
+ break;\r
+\r
+ case TCP_LISTEN:\r
+ return -1;\r
+ break;\r
+\r
+ case TCP_SYN_SENT:\r
+ case TCP_SYN_RCVD:\r
+ return 0;\r
+ break;\r
+\r
+ case TCP_ESTABLISHED:\r
+ case TCP_CLOSE_WAIT:\r
+ TcpToSendData (Tcb, 0);\r
+ return 0;\r
+ break;\r
+\r
+ case TCP_FIN_WAIT_1:\r
+ case TCP_FIN_WAIT_2:\r
+ case TCP_CLOSING:\r
+ case TCP_LAST_ACK:\r
+ case TCP_TIME_WAIT:\r
+ return -1;\r
+ break;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ Application has consumed some data, check whether\r
+ to send a window updata ack or a delayed ack.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+\r
+**/\r
+INTN\r
+TcpOnAppConsume (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+\r
+ switch (Tcb->State) {\r
+ case TCP_CLOSED:\r
+ return -1;\r
+ break;\r
+\r
+ case TCP_LISTEN:\r
+ return -1;\r
+ break;\r
+\r
+ case TCP_SYN_SENT:\r
+ case TCP_SYN_RCVD:\r
+ return 0;\r
+ break;\r
+\r
+ case TCP_ESTABLISHED:\r
+ if (TcpRcvWinNow (Tcb) > TcpRcvWinOld (Tcb)) {\r
+\r
+ if (TcpRcvWinOld (Tcb) < Tcb->RcvMss) {\r
+\r
+ TCP4_DEBUG_TRACE (("TcpOnAppConsume: send a window"\r
+ " update for a window closed Tcb(%x)\n", Tcb));\r
+\r
+ TcpSendAck (Tcb);\r
+ } else if (Tcb->DelayedAck == 0) {\r
+\r
+ TCP4_DEBUG_TRACE (("TcpOnAppConsume: scheduled a delayed"\r
+ " ACK to update window for Tcb(%x)\n", Tcb));\r
+\r
+ Tcb->DelayedAck = 1;\r
+ }\r
+ }\r
+\r
+ break;\r
+\r
+ case TCP_CLOSE_WAIT:\r
+ return 0;\r
+ break;\r
+\r
+ case TCP_FIN_WAIT_1:\r
+ case TCP_FIN_WAIT_2:\r
+ case TCP_CLOSING:\r
+ case TCP_LAST_ACK:\r
+ case TCP_TIME_WAIT:\r
+ return -1;\r
+ break;\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+\r
+/**\r
+ Abort the connection by sending a reset segment, called\r
+ when the application wants to abort the connection.\r
+\r
+ @param Tcb Pointer to the TCP_CB of the TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpOnAppAbort (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ TCP4_DEBUG_WARN (("TcpOnAppAbort: connection reset "\r
+ "issued by application for TCB %x\n", Tcb));\r
+\r
+ switch (Tcb->State) {\r
+ case TCP_SYN_RCVD:\r
+ case TCP_ESTABLISHED:\r
+ case TCP_FIN_WAIT_1:\r
+ case TCP_FIN_WAIT_2:\r
+ case TCP_CLOSE_WAIT:\r
+ TcpResetConnection (Tcb);\r
+ break;\r
+ }\r
+\r
+ TcpSetState (Tcb, TCP_CLOSED);\r
+}\r
+\r
+\r
+/**\r
+ Set the Tdp4 variable data.\r
+\r
+ @param Tcp4Service Tcp4 service data.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.\r
+ @retval other Set variable failed.\r
+\r
+**/\r
+EFI_STATUS\r
+TcpSetVariableData (\r
+ IN TCP4_SERVICE_DATA *Tcp4Service\r
+ )\r
+{\r
+ UINT32 NumConfiguredInstance;\r
+ NET_LIST_ENTRY *Entry;\r
+ TCP_CB *TcpPcb;\r
+ TCP4_PROTO_DATA *TcpProto;\r
+ UINTN VariableDataSize;\r
+ EFI_TCP4_VARIABLE_DATA *Tcp4VariableData;\r
+ EFI_TCP4_SERVICE_POINT *Tcp4ServicePoint;\r
+ CHAR16 *NewMacString;\r
+ EFI_STATUS Status;\r
+\r
+ NumConfiguredInstance = 0;\r
+\r
+ //\r
+ // Go through the running queue to count the instances.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
+ TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+ if (TcpProto->TcpService == Tcp4Service) {\r
+ //\r
+ // This tcp instance belongs to the Tcp4Service.\r
+ //\r
+ NumConfiguredInstance++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Go through the listening queue to count the instances.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
+ TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+ if (TcpProto->TcpService == Tcp4Service) {\r
+ //\r
+ // This tcp instance belongs to the Tcp4Service.\r
+ //\r
+ NumConfiguredInstance++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,\r
+ // we should add extra buffer for the service points only if the number of configured\r
+ // children is more than 1.\r
+ //\r
+ VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);\r
+\r
+ if (NumConfiguredInstance > 1) {\r
+ VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
+ }\r
+\r
+ Tcp4VariableData = NetAllocatePool (VariableDataSize);\r
+ if (Tcp4VariableData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Tcp4VariableData->DriverHandle = Tcp4Service->DriverBindingHandle;\r
+ Tcp4VariableData->ServiceCount = NumConfiguredInstance;\r
+\r
+ Tcp4ServicePoint = &Tcp4VariableData->Services[0];\r
+\r
+ //\r
+ // Go through the running queue to fill the service points.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
+ TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+ if (TcpProto->TcpService == Tcp4Service) {\r
+ //\r
+ // This tcp instance belongs to the Tcp4Service.\r
+ //\r
+ Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
+ EFI_IP4 (Tcp4ServicePoint->LocalAddress) = TcpPcb->LocalEnd.Ip;\r
+ Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
+ EFI_IP4 (Tcp4ServicePoint->RemoteAddress) = TcpPcb->RemoteEnd.Ip;\r
+ Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
+\r
+ Tcp4ServicePoint++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Go through the listening queue to fill the service points.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
+ TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ TcpProto = (TCP4_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
+\r
+ if (TcpProto->TcpService == Tcp4Service) {\r
+ //\r
+ // This tcp instance belongs to the Tcp4Service.\r
+ //\r
+ Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
+ EFI_IP4 (Tcp4ServicePoint->LocalAddress) = TcpPcb->LocalEnd.Ip;\r
+ Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
+ EFI_IP4 (Tcp4ServicePoint->RemoteAddress) = TcpPcb->RemoteEnd.Ip;\r
+ Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
+\r
+ Tcp4ServicePoint++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get the mac string.\r
+ //\r
+ Status = NetLibGetMacString (\r
+ Tcp4Service->ControllerHandle,\r
+ Tcp4Service->DriverBindingHandle,\r
+ &NewMacString\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ if (Tcp4Service->MacString != NULL) {\r
+ //\r
+ // The variable is set already, we're going to update it.\r
+ //\r
+ if (StrCmp (Tcp4Service->MacString, NewMacString) != 0) {\r
+ //\r
+ // The mac address is changed, delete the previous variable first.\r
+ //\r
+ gRT->SetVariable (\r
+ Tcp4Service->MacString,\r
+ &gEfiTcp4ServiceBindingProtocolGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ NetFreePool (Tcp4Service->MacString);\r
+ }\r
+\r
+ Tcp4Service->MacString = NewMacString;\r
+\r
+ Status = gRT->SetVariable (\r
+ Tcp4Service->MacString,\r
+ &gEfiTcp4ServiceBindingProtocolGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ VariableDataSize,\r
+ (VOID *) Tcp4VariableData\r
+ );\r
+\r
+ON_ERROR:\r
+\r
+ NetFreePool (Tcp4VariableData);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Clear the variable and free the resource.\r
+\r
+ @param Tcp4Service Tcp4 service data.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpClearVariableData (\r
+ IN TCP4_SERVICE_DATA *Tcp4Service\r
+ )\r
+{\r
+ ASSERT (Tcp4Service->MacString != NULL);\r
+\r
+ gRT->SetVariable (\r
+ Tcp4Service->MacString,\r
+ &gEfiTcp4ServiceBindingProtocolGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ NetFreePool (Tcp4Service->MacString);\r
+ Tcp4Service->MacString = NULL;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Tcp4Option.c\r
+\r
+Abstract:\r
+\r
+ Routines to process TCP option.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+STATIC\r
+UINT16\r
+TcpGetUint16 (\r
+ IN UINT8 *Buf\r
+ )\r
+{\r
+ UINT16 Value;\r
+ NetCopyMem (&Value, Buf, sizeof (UINT16));\r
+ return NTOHS (Value);\r
+}\r
+\r
+STATIC\r
+VOID\r
+TcpPutUint16 (\r
+ IN UINT8 *Buf,\r
+ IN UINT16 Data\r
+ )\r
+{\r
+ Data = HTONS (Data);\r
+ NetCopyMem (Buf, &Data, sizeof (UINT16));\r
+}\r
+\r
+STATIC\r
+UINT32\r
+TcpGetUint32 (\r
+ IN UINT8 *Buf\r
+ )\r
+{\r
+ UINT32 Value;\r
+ NetCopyMem (&Value, Buf, sizeof (UINT32));\r
+ return NTOHL (Value);\r
+}\r
+\r
+STATIC\r
+VOID\r
+TcpPutUint32 (\r
+ IN UINT8 *Buf,\r
+ IN UINT32 Data\r
+ )\r
+{\r
+ Data = HTONL (Data);\r
+ NetCopyMem (Buf, &Data, sizeof (UINT32));\r
+}\r
+\r
+\r
+/**\r
+ Compute the window scale value according to the given\r
+ buffer size.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @retval UINT8 The scale value.\r
+\r
+**/\r
+UINT8\r
+TcpComputeScale (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ UINT8 Scale;\r
+ UINT32 BufSize;\r
+\r
+ ASSERT (Tcb && Tcb->Sk);\r
+\r
+ BufSize = GET_RCV_BUFFSIZE (Tcb->Sk);\r
+\r
+ Scale = 0;\r
+ while ((Scale < TCP_OPTION_MAX_WS) &&\r
+ ((UINT32) (TCP_OPTION_MAX_WIN << Scale) < BufSize)) {\r
+\r
+ Scale++;\r
+ }\r
+\r
+ return Scale;\r
+}\r
+\r
+\r
+/**\r
+ Build the TCP option in three-way handshake.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Nbuf Pointer to the buffer to store the options.\r
+\r
+ @return The total length of the TCP option field.\r
+\r
+**/\r
+UINT16\r
+TcpSynBuildOption (\r
+ IN TCP_CB *Tcb,\r
+ IN NET_BUF *Nbuf\r
+ )\r
+{\r
+ char *Data;\r
+ UINT16 Len;\r
+\r
+ ASSERT (Tcb && Nbuf && !Nbuf->Tcp);\r
+\r
+ Len = 0;\r
+\r
+ //\r
+ // Add timestamp option if not disabled by application\r
+ // and it is the first SYN segment or the peer has sent\r
+ // us its timestamp.\r
+ //\r
+ if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS) &&\r
+ (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||\r
+ TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS))) {\r
+\r
+ Data = NetbufAllocSpace (\r
+ Nbuf,\r
+ TCP_OPTION_TS_ALIGNED_LEN,\r
+ NET_BUF_HEAD\r
+ );\r
+\r
+ ASSERT (Data);\r
+ Len += TCP_OPTION_TS_ALIGNED_LEN;\r
+\r
+ TcpPutUint32 (Data, TCP_OPTION_TS_FAST);\r
+ TcpPutUint32 (Data + 4, mTcpTick);\r
+ TcpPutUint32 (Data + 8, 0);\r
+ }\r
+\r
+ //\r
+ // Build window scale option, only when are configured\r
+ // to send WS option, and either we are doing active\r
+ // open or we have received WS option from peer.\r
+ //\r
+ if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS) &&\r
+ (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||\r
+ TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS))) {\r
+\r
+ Data = NetbufAllocSpace (\r
+ Nbuf,\r
+ TCP_OPTION_WS_ALIGNED_LEN,\r
+ NET_BUF_HEAD\r
+ );\r
+\r
+ ASSERT (Data);\r
+\r
+ Len += TCP_OPTION_WS_ALIGNED_LEN;\r
+ TcpPutUint32 (Data, TCP_OPTION_WS_FAST | TcpComputeScale (Tcb));\r
+ }\r
+\r
+ //\r
+ // Build MSS option\r
+ //\r
+ Data = NetbufAllocSpace (Nbuf, TCP_OPTION_MSS_LEN, 1);\r
+ ASSERT (Data);\r
+\r
+ Len += TCP_OPTION_MSS_LEN;\r
+ TcpPutUint32 (Data, TCP_OPTION_MSS_FAST | Tcb->RcvMss);\r
+\r
+ return Len;\r
+}\r
+\r
+\r
+/**\r
+ Build the TCP option in synchronized states.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Nbuf Pointer to the buffer to store the options.\r
+\r
+ @return The total length of the TCP option field.\r
+\r
+**/\r
+UINT16\r
+TcpBuildOption (\r
+ IN TCP_CB *Tcb,\r
+ IN NET_BUF *Nbuf\r
+ )\r
+{\r
+ char *Data;\r
+ UINT16 Len;\r
+\r
+ ASSERT (Tcb && Nbuf && !Nbuf->Tcp);\r
+ Len = 0;\r
+\r
+ //\r
+ // Build Timestamp option\r
+ //\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_TS) &&\r
+ !TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_RST)) {\r
+\r
+ Data = NetbufAllocSpace (\r
+ Nbuf,\r
+ TCP_OPTION_TS_ALIGNED_LEN,\r
+ NET_BUF_HEAD\r
+ );\r
+\r
+ ASSERT (Data);\r
+ Len += TCP_OPTION_TS_ALIGNED_LEN;\r
+\r
+ TcpPutUint32 (Data, TCP_OPTION_TS_FAST);\r
+ TcpPutUint32 (Data + 4, mTcpTick);\r
+ TcpPutUint32 (Data + 8, Tcb->TsRecent);\r
+ }\r
+\r
+ return Len;\r
+}\r
+\r
+\r
+/**\r
+ Parse the supported options.\r
+\r
+ @param Tcp Pointer to the TCP_CB of this TCP instance.\r
+ @param Option Pointer to the TCP_OPTION used to store the successfully pasrsed\r
+ options.\r
+\r
+ @retval 0 The options are successfully pasrsed.\r
+ @retval -1 Ilegal option was found.\r
+\r
+**/\r
+INTN\r
+TcpParseOption (\r
+ IN TCP_HEAD *Tcp,\r
+ IN TCP_OPTION *Option\r
+ )\r
+{\r
+ UINT8 *Head;\r
+ UINT8 TotalLen;\r
+ UINT8 Cur;\r
+ UINT8 Type;\r
+ UINT8 Len;\r
+\r
+ ASSERT (Tcp && Option);\r
+\r
+ Option->Flag = 0;\r
+\r
+ TotalLen = (Tcp->HeadLen << 2) - sizeof (TCP_HEAD);\r
+ if (TotalLen <= 0) {\r
+ return 0;\r
+ }\r
+\r
+ Head = (UINT8 *) (Tcp + 1);\r
+\r
+ //\r
+ // Fast process of timestamp option\r
+ //\r
+ if ((TotalLen == TCP_OPTION_TS_ALIGNED_LEN) &&\r
+ (TcpGetUint32 (Head) == TCP_OPTION_TS_FAST)) {\r
+\r
+ Option->TSVal = TcpGetUint32 (Head + 4);\r
+ Option->TSEcr = TcpGetUint32 (Head + 8);\r
+ Option->Flag = TCP_OPTION_RCVD_TS;\r
+\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Slow path to process the options.\r
+ //\r
+ Cur = 0;\r
+\r
+ while (Cur < TotalLen) {\r
+ Type = Head[Cur];\r
+\r
+ switch (Type) {\r
+ case TCP_OPTION_MSS:\r
+ Len = Head[Cur + 1];\r
+\r
+ if ((Len != TCP_OPTION_MSS_LEN) ||\r
+ (TotalLen - Cur < TCP_OPTION_MSS_LEN)) {\r
+\r
+ return -1;\r
+ }\r
+\r
+ Option->Mss = TcpGetUint16 (&Head[Cur + 2]);\r
+ TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_MSS);\r
+\r
+ Cur += TCP_OPTION_MSS_LEN;\r
+ break;\r
+\r
+ case TCP_OPTION_WS:\r
+ Len = Head[Cur + 1];\r
+\r
+ if ((Len != TCP_OPTION_WS_LEN) ||\r
+ (TotalLen - Cur < TCP_OPTION_WS_LEN)) {\r
+\r
+ return -1;\r
+ }\r
+\r
+ Option->WndScale = NET_MIN (14, Head[Cur + 2]);\r
+ TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_WS);\r
+\r
+ Cur += TCP_OPTION_WS_LEN;\r
+ break;\r
+\r
+ case TCP_OPTION_TS:\r
+ Len = Head[Cur + 1];\r
+\r
+ if ((Len != TCP_OPTION_TS_LEN) ||\r
+ (TotalLen - Cur < TCP_OPTION_TS_LEN)) {\r
+\r
+ return -1;\r
+ }\r
+\r
+ Option->TSVal = TcpGetUint32 (&Head[Cur + 2]);\r
+ Option->TSEcr = TcpGetUint32 (&Head[Cur + 6]);\r
+ TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_TS);\r
+\r
+ Cur += TCP_OPTION_TS_LEN;\r
+ break;\r
+\r
+ case TCP_OPTION_NOP:\r
+ Cur++;\r
+ break;\r
+\r
+ case TCP_OPTION_EOP:\r
+ Cur = TotalLen;\r
+ break;\r
+\r
+ default:\r
+ Len = Head[Cur + 1];\r
+\r
+ if (TotalLen - Cur < Len || Len < 2) {\r
+ return -1;\r
+ }\r
+\r
+ Cur = Cur + Len;\r
+ break;\r
+ }\r
+\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ Check the segment against PAWS.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param TSVal The timestamp value.\r
+\r
+ @retval 1 The segment passed the PAWS check.\r
+ @retval 0 The segment failed to pass the PAWS check.\r
+\r
+**/\r
+UINT32\r
+TcpPawsOK (\r
+ IN TCP_CB *Tcb,\r
+ IN UINT32 TSVal\r
+ )\r
+{\r
+ //\r
+ // PAWS as defined in RFC1323, buggy...\r
+ //\r
+ if (TCP_TIME_LT (TSVal, Tcb->TsRecent) &&\r
+ TCP_TIME_LT (Tcb->TsRecentAge + TCP_PAWS_24DAY, mTcpTick)) {\r
+\r
+ return 0;\r
+\r
+ }\r
+\r
+ return 1;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 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:
+
+ Tcp4Option.h
+
+Abstract:
+
+
+**/
+
+#ifndef _TCP4_OPTION_H_
+#define _TCP4_OPTION_H_
+
+//
+// The structure to store the parse option value.
+// ParseOption only parse the options, don't process them.
+//
+typedef struct s_TCP_OPTION {
+ UINT8 Flag; // flag such as TCP_OPTION_RCVD_MSS
+ UINT8 WndScale; // the WndScale received
+ UINT16 Mss; // the Mss received
+ UINT32 TSVal; // the TSVal field in a timestamp option
+ UINT32 TSEcr; // the TSEcr field in a timestamp option
+} TCP_OPTION;
+
+enum {
+
+ //
+ // supported TCP option type and their length
+ //
+ TCP_OPTION_EOP = 0, // End Of oPtion
+ TCP_OPTION_NOP = 1, // No-Option.
+ TCP_OPTION_MSS = 2, // Maximum Segment Size
+ TCP_OPTION_WS = 3, // Window scale
+ TCP_OPTION_TS = 8, // Timestamp
+ TCP_OPTION_MSS_LEN = 4, // length of MSS option
+ TCP_OPTION_WS_LEN = 3, // length of window scale option
+ TCP_OPTION_TS_LEN = 10, // length of timestamp option
+ TCP_OPTION_WS_ALIGNED_LEN = 4, // length of window scale option, aligned
+ TCP_OPTION_TS_ALIGNED_LEN = 12, // length of timestamp option, aligned
+
+ //
+ // recommend format of timestamp window scale
+ // option for fast process.
+ //
+ TCP_OPTION_TS_FAST = ((TCP_OPTION_NOP << 24) |
+ (TCP_OPTION_NOP << 16) |
+ (TCP_OPTION_TS << 8) |
+ TCP_OPTION_TS_LEN),
+
+ TCP_OPTION_WS_FAST = ((TCP_OPTION_NOP << 24) |
+ (TCP_OPTION_WS << 16) |
+ (TCP_OPTION_WS_LEN << 8)),
+
+ TCP_OPTION_MSS_FAST = ((TCP_OPTION_MSS << 24) |
+ (TCP_OPTION_MSS_LEN << 16)),
+
+ //
+ // Other misc definations
+ //
+ TCP_OPTION_MAX_WS = 14, // Maxium window scale value
+ TCP_OPTION_MAX_WIN = 0xffff, // max window size in TCP header
+ TCP_OPTION_RCVD_MSS = 0x01,
+ TCP_OPTION_RCVD_WS = 0x02,
+ TCP_OPTION_RCVD_TS = 0x04,
+};
+
+UINT8
+TcpComputeScale (
+ IN TCP_CB *Tcb
+ );
+
+UINT16
+TcpSynBuildOption (
+ IN TCP_CB *Tcb,
+ IN NET_BUF *Buf
+ );
+
+UINT16
+TcpBuildOption (
+ IN TCP_CB *Tcb,
+ IN NET_BUF *Buf
+ );
+
+INTN
+TcpParseOption (
+ IN TCP_HEAD *Tcp,
+ IN TCP_OPTION *Option
+ );
+
+UINT32
+TcpPawsOK (
+ IN TCP_CB *Tcb,
+ IN UINT32 TSVal
+ );
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Tcp4Output.c\r
+\r
+Abstract:\r
+\r
+ TCP output process routines.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+STATIC UINT8 mTcpOutFlag[] = {\r
+ 0, // TCP_CLOSED\r
+ 0, // TCP_LISTEN\r
+ TCP_FLG_SYN, // TCP_SYN_SENT\r
+ TCP_FLG_SYN | TCP_FLG_ACK, // TCP_SYN_RCVD\r
+ TCP_FLG_ACK, // TCP_ESTABLISHED\r
+ TCP_FLG_FIN | TCP_FLG_ACK, // TCP_FIN_WAIT_1\r
+ TCP_FLG_ACK, // TCP_FIN_WAIT_2\r
+ TCP_FLG_ACK | TCP_FLG_FIN, // TCP_CLOSING\r
+ TCP_FLG_ACK, // TCP_TIME_WAIT\r
+ TCP_FLG_ACK, // TCP_CLOSE_WAIT\r
+ TCP_FLG_FIN | TCP_FLG_ACK // TCP_LAST_ACK\r
+};\r
+\r
+\r
+/**\r
+ Compute the sequence space left in the old receive window.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return The sequence space left in the old receive window.\r
+\r
+**/\r
+UINT32\r
+TcpRcvWinOld (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ UINT32 OldWin;\r
+\r
+ OldWin = 0;\r
+\r
+ if (TCP_SEQ_GT (Tcb->RcvWl2 + Tcb->RcvWnd, Tcb->RcvNxt)) {\r
+\r
+ OldWin = TCP_SUB_SEQ (\r
+ Tcb->RcvWl2 + Tcb->RcvWnd,\r
+ Tcb->RcvNxt\r
+ );\r
+ }\r
+\r
+ return OldWin;\r
+}\r
+\r
+\r
+/**\r
+ Compute the current receive window.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return The size of the current receive window, in bytes.\r
+\r
+**/\r
+UINT32\r
+TcpRcvWinNow (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ SOCKET *Sk;\r
+ UINT32 Win;\r
+ UINT32 Increase;\r
+ UINT32 OldWin;\r
+\r
+ Sk = Tcb->Sk;\r
+ ASSERT (Sk);\r
+\r
+ OldWin = TcpRcvWinOld (Tcb);\r
+\r
+ Win = SockGetFreeSpace (Sk, SOCK_RCV_BUF);\r
+\r
+ Increase = 0;\r
+ if (Win > OldWin) {\r
+ Increase = Win - OldWin;\r
+ }\r
+\r
+ //\r
+ // Receiver's SWS: don't advertise a bigger window\r
+ // unless it can be increased by at least one Mss or\r
+ // half of the receive buffer.\r
+ //\r
+ if ((Increase > Tcb->SndMss) ||\r
+ (2 * Increase >= GET_RCV_BUFFSIZE (Sk))) {\r
+\r
+ return Win;\r
+ }\r
+\r
+ return OldWin;\r
+}\r
+\r
+\r
+/**\r
+ Compute the value to fill in the window size field\r
+ of the outgoing segment.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Syn The flag to indicate whether the outgoing segment is a SYN\r
+ segment.\r
+\r
+ @return The value of the local receive window size used to fill the outing segment.\r
+\r
+**/\r
+STATIC\r
+UINT16\r
+TcpComputeWnd (\r
+ IN TCP_CB *Tcb,\r
+ IN BOOLEAN Syn\r
+ )\r
+{\r
+ UINT32 Wnd;\r
+\r
+ //\r
+ // RFC requires that initial window not be scaled\r
+ //\r
+ if (Syn) {\r
+\r
+ Wnd = GET_RCV_BUFFSIZE (Tcb->Sk);\r
+ } else {\r
+\r
+ Wnd = TcpRcvWinNow (Tcb);\r
+\r
+ Tcb->RcvWnd = Wnd;\r
+ }\r
+\r
+ Wnd = NET_MIN (Wnd >> Tcb->RcvWndScale, 0xffff);\r
+ return NTOHS ((UINT16) Wnd);\r
+}\r
+\r
+\r
+/**\r
+ Get the maximum SndNxt.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return The sequence number of the maximum SndNxt.\r
+\r
+**/\r
+TCP_SEQNO\r
+TcpGetMaxSndNxt (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_BUF *Nbuf;\r
+\r
+ if (NetListIsEmpty (&Tcb->SndQue)) {\r
+ return Tcb->SndNxt;\r
+ }\r
+\r
+ Entry = Tcb->SndQue.BackLink;\r
+ Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+\r
+ ASSERT (TCP_SEQ_GEQ (TCPSEG_NETBUF (Nbuf)->End, Tcb->SndNxt));\r
+ return TCPSEG_NETBUF (Nbuf)->End;\r
+}\r
+\r
+\r
+/**\r
+ Compute how much data to send.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Force Whether to ignore the sender's SWS avoidance algorithm and send\r
+ out data by force.\r
+\r
+ @return The length of the data can be sent, if 0, no data can be sent.\r
+\r
+**/\r
+UINT32\r
+TcpDataToSend (\r
+ IN TCP_CB *Tcb,\r
+ IN INTN Force\r
+ )\r
+{\r
+ SOCKET *Sk;\r
+ UINT32 Win;\r
+ UINT32 Len;\r
+ UINT32 Left;\r
+ UINT32 Limit;\r
+\r
+ Sk = Tcb->Sk;\r
+ ASSERT (Sk);\r
+\r
+ //\r
+ // TCP should NOT send data beyond the send window\r
+ // and congestion window. The right edge of send\r
+ // window is defined as SND.WL2 + SND.WND. The right\r
+ // edge of congestion window is defined as SND.UNA +\r
+ // CWND.\r
+ //\r
+ Win = 0;\r
+ Limit = Tcb->SndWl2 + Tcb->SndWnd;\r
+\r
+ if (TCP_SEQ_GT (Limit, Tcb->SndUna + Tcb->CWnd)) {\r
+\r
+ Limit = Tcb->SndUna + Tcb->CWnd;\r
+ }\r
+\r
+ if (TCP_SEQ_GT (Limit, Tcb->SndNxt)) {\r
+ Win = TCP_SUB_SEQ (Limit, Tcb->SndNxt);\r
+ }\r
+\r
+ //\r
+ // The data to send contains two parts: the data on the\r
+ // socket send queue, and the data on the TCB's send\r
+ // buffer. The later can be non-zero if the peer shrinks\r
+ // its advertised window.\r
+ //\r
+ Left = GET_SND_DATASIZE (Sk) +\r
+ TCP_SUB_SEQ (TcpGetMaxSndNxt (Tcb), Tcb->SndNxt);\r
+\r
+ Len = NET_MIN (Win, Left);\r
+\r
+ if (Len > Tcb->SndMss) {\r
+ Len = Tcb->SndMss;\r
+ }\r
+\r
+ if (Force || (Len == 0 && Left == 0)) {\r
+ return Len;\r
+ }\r
+\r
+ if (Len == 0 && Left != 0) {\r
+ goto SetPersistTimer;\r
+ }\r
+\r
+ //\r
+ // Sender's SWS avoidance: Don't send a small segment unless\r
+ // a)A full-sized segment can be sent,\r
+ // b)at least one-half of the maximum sized windows that\r
+ // the other end has ever advertised.\r
+ // c)It can send everything it has and either it isn't\r
+ // expecting an ACK or the Nagle algorithm is disabled.\r
+ //\r
+ if ((Len == Tcb->SndMss) || (2 * Len >= Tcb->SndWndMax)) {\r
+\r
+ return Len;\r
+ }\r
+\r
+ if ((Len == Left) &&\r
+ ((Tcb->SndNxt == Tcb->SndUna) ||\r
+ TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE))) {\r
+\r
+ return Len;\r
+ }\r
+\r
+ //\r
+ // RFC1122 suggests to set a timer when SWSA forbids TCP\r
+ // sending more data, and combine it with probe timer.\r
+ //\r
+SetPersistTimer:\r
+ if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {\r
+\r
+ TCP4_DEBUG_WARN (\r
+ ("TcpDataToSend: enter persistent state for TCB %x\n",\r
+ Tcb)\r
+ );\r
+\r
+ TcpSetProbeTimer (Tcb);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ Build the TCP header of the TCP segment and transmit the\r
+ segment by IP.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Nbuf Pointer to the buffer containing the segment to be sent out.\r
+\r
+ @retval 0 The segment is sent out successfully.\r
+ @retval other Error condition occurred.\r
+\r
+**/\r
+STATIC\r
+INTN\r
+TcpTransmitSegment (\r
+ IN TCP_CB *Tcb,\r
+ IN NET_BUF *Nbuf\r
+ )\r
+{\r
+ UINT16 Len;\r
+ TCP_HEAD *Head;\r
+ TCP_SEG *Seg;\r
+ BOOLEAN Syn;\r
+ UINT32 DataLen;\r
+\r
+ ASSERT (Nbuf && (Nbuf->Tcp == NULL) && TcpVerifySegment (Nbuf));\r
+\r
+ DataLen = Nbuf->TotalSize;\r
+\r
+ Seg = TCPSEG_NETBUF (Nbuf);\r
+ Syn = TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN);\r
+\r
+ if (Syn) {\r
+\r
+ Len = TcpSynBuildOption (Tcb, Nbuf);\r
+ } else {\r
+\r
+ Len = TcpBuildOption (Tcb, Nbuf);\r
+ }\r
+\r
+ ASSERT ((Len % 4 == 0) && (Len <= 40));\r
+\r
+ Len += sizeof (TCP_HEAD);\r
+\r
+ Head = (TCP_HEAD *) NetbufAllocSpace (\r
+ Nbuf,\r
+ sizeof (TCP_HEAD),\r
+ NET_BUF_HEAD\r
+ );\r
+\r
+ ASSERT (Head != NULL);\r
+\r
+ Nbuf->Tcp = Head;\r
+\r
+ Head->SrcPort = Tcb->LocalEnd.Port;\r
+ Head->DstPort = Tcb->RemoteEnd.Port;\r
+ Head->Seq = NTOHL (Seg->Seq);\r
+ Head->Ack = NTOHL (Tcb->RcvNxt);\r
+ Head->HeadLen = (UINT8) (Len >> 2);\r
+ Head->Res = 0;\r
+ Head->Wnd = TcpComputeWnd (Tcb, Syn);\r
+ Head->Checksum = 0;\r
+\r
+ //\r
+ // Check whether to set the PSH flag.\r
+ //\r
+ TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_PSH);\r
+\r
+ if (DataLen != 0) {\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_PSH) &&\r
+ TCP_SEQ_BETWEEN (Seg->Seq, Tcb->SndPsh, Seg->End)) {\r
+\r
+ TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH);\r
+ TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);\r
+\r
+ } else if ((Seg->End == Tcb->SndNxt) &&\r
+ (GET_SND_DATASIZE (Tcb->Sk) == 0)) {\r
+\r
+ TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check whether to set the URG flag and the urgent pointer.\r
+ //\r
+ TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);\r
+\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
+ TCP_SEQ_LEQ (Seg->Seq, Tcb->SndUp)) {\r
+\r
+ TCP_SET_FLG (Seg->Flag, TCP_FLG_URG);\r
+\r
+ if (TCP_SEQ_LT (Tcb->SndUp, Seg->End)) {\r
+\r
+ Seg->Urg = (UINT16) TCP_SUB_SEQ (Tcb->SndUp, Seg->Seq);\r
+ } else {\r
+\r
+ Seg->Urg = (UINT16) NET_MIN (\r
+ TCP_SUB_SEQ (Tcb->SndUp,\r
+ Seg->Seq),\r
+ 0xffff\r
+ );\r
+ }\r
+ }\r
+\r
+ Head->Flag = Seg->Flag;\r
+ Head->Urg = NTOHS (Seg->Urg);\r
+ Head->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);\r
+\r
+ //\r
+ // update the TCP session's control information\r
+ //\r
+ Tcb->RcvWl2 = Tcb->RcvNxt;\r
+ if (Syn) {\r
+ Tcb->RcvWnd = NTOHS (Head->Wnd);\r
+ }\r
+\r
+ //\r
+ // clear delayedack flag\r
+ //\r
+ Tcb->DelayedAck = 0;\r
+\r
+ return TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);\r
+}\r
+\r
+\r
+/**\r
+ Get a segment from the Tcb's SndQue.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Seq The sequence number of the segment.\r
+ @param Len The maximum length of the segment.\r
+\r
+ @return Pointer to the segment, if NULL some error occurred.\r
+\r
+**/\r
+NET_BUF *\r
+TcpGetSegmentSndQue (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP_SEQNO Seq,\r
+ IN UINT32 Len\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Head;\r
+ NET_LIST_ENTRY *Cur;\r
+ NET_BUF *Node;\r
+ TCP_SEG *Seg;\r
+ NET_BUF *Nbuf;\r
+ TCP_SEQNO End;\r
+ UINT8 *Data;\r
+ UINT8 Flag;\r
+ INT32 Offset;\r
+ INT32 CopyLen;\r
+\r
+ ASSERT (Tcb && TCP_SEQ_LEQ (Seq, Tcb->SndNxt) && (Len > 0));\r
+\r
+ //\r
+ // Find the segment that contains the Seq.\r
+ //\r
+ Head = &Tcb->SndQue;\r
+\r
+ Node = NULL;\r
+ Seg = NULL;\r
+\r
+ NET_LIST_FOR_EACH (Cur, Head) {\r
+ Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
+ Seg = TCPSEG_NETBUF (Node);\r
+\r
+ if (TCP_SEQ_LT (Seq, Seg->End) && TCP_SEQ_LEQ (Seg->Seq, Seq)) {\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ ASSERT (Cur != Head);\r
+\r
+ //\r
+ // Return the buffer if it can be returned without\r
+ // adjustment:\r
+ //\r
+ if ((Seg->Seq == Seq) &&\r
+ TCP_SEQ_LEQ (Seg->End, Seg->Seq + Len) &&\r
+ !NET_BUF_SHARED (Node)) {\r
+\r
+ NET_GET_REF (Node);\r
+ return Node;\r
+ }\r
+\r
+ //\r
+ // Create a new buffer and copy data there.\r
+ //\r
+ Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);\r
+\r
+ if (Nbuf == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
+\r
+ Flag = Seg->Flag;\r
+ End = Seg->End;\r
+\r
+ if (TCP_SEQ_LT (Seq + Len, Seg->End)) {\r
+ End = Seq + Len;\r
+ }\r
+\r
+ CopyLen = TCP_SUB_SEQ (End, Seq);\r
+ Offset = TCP_SUB_SEQ (Seq, Seg->Seq);\r
+\r
+ //\r
+ // If SYN is set and out of the range, clear the flag.\r
+ // Becuase the sequence of the first byte is SEG.SEQ+1,\r
+ // adjust Offset by -1. If SYN is in the range, copy\r
+ // one byte less.\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+\r
+ if (TCP_SEQ_LT (Seg->Seq, Seq)) {\r
+\r
+ TCP_CLEAR_FLG (Flag, TCP_FLG_SYN);\r
+ Offset--;\r
+ } else {\r
+\r
+ CopyLen--;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If FIN is set and in the range, copy one byte less,\r
+ // and if it is out of the range, clear the flag.\r
+ //\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
+\r
+ if (Seg->End == End) {\r
+\r
+ CopyLen--;\r
+ } else {\r
+\r
+ TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);\r
+ }\r
+ }\r
+\r
+ ASSERT (CopyLen >= 0);\r
+\r
+ //\r
+ // copy data to the segment\r
+ //\r
+ if (CopyLen) {\r
+ Data = NetbufAllocSpace (Nbuf, CopyLen, NET_BUF_TAIL);\r
+ ASSERT (Data);\r
+\r
+ if ((INT32) NetbufCopy (Node, Offset, CopyLen, Data) != CopyLen) {\r
+ goto OnError;\r
+ }\r
+ }\r
+\r
+ NetCopyMem (TCPSEG_NETBUF (Nbuf), Seg, sizeof (TCP_SEG));\r
+\r
+ TCPSEG_NETBUF (Nbuf)->Seq = Seq;\r
+ TCPSEG_NETBUF (Nbuf)->End = End;\r
+ TCPSEG_NETBUF (Nbuf)->Flag = Flag;\r
+\r
+ return Nbuf;\r
+\r
+OnError:\r
+ NetbufFree (Nbuf);\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Get a segment from the Tcb's socket buffer.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Seq The sequence number of the segment.\r
+ @param Len The maximum length of the segment.\r
+\r
+ @return Pointer to the segment, if NULL some error occurred.\r
+\r
+**/\r
+NET_BUF *\r
+TcpGetSegmentSock (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP_SEQNO Seq,\r
+ IN UINT32 Len\r
+ )\r
+{\r
+ NET_BUF *Nbuf;\r
+ UINT8 *Data;\r
+ UINT32 DataGet;\r
+\r
+ ASSERT (Tcb && Tcb->Sk);\r
+\r
+ Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);\r
+\r
+ if (Nbuf == NULL) {\r
+ TCP4_DEBUG_ERROR (("TcpGetSegmentSock: failed to allocate "\r
+ "a netbuf for TCB %x\n",Tcb));\r
+\r
+ return NULL;\r
+ }\r
+\r
+ NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
+\r
+ DataGet = 0;\r
+\r
+ if (Len) {\r
+ //\r
+ // copy data to the segment.\r
+ //\r
+ Data = NetbufAllocSpace (Nbuf, Len, NET_BUF_TAIL);\r
+ ASSERT (Data);\r
+\r
+ DataGet = SockGetDataToSend (Tcb->Sk, 0, Len, Data);\r
+ }\r
+\r
+ NET_GET_REF (Nbuf);\r
+\r
+ TCPSEG_NETBUF (Nbuf)->Seq = Seq;\r
+ TCPSEG_NETBUF (Nbuf)->End = Seq + Len;\r
+\r
+ NetListInsertTail (&(Tcb->SndQue), &(Nbuf->List));\r
+\r
+ if (DataGet != 0) {\r
+\r
+ SockDataSent (Tcb->Sk, DataGet);\r
+ }\r
+\r
+ return Nbuf;\r
+}\r
+\r
+\r
+/**\r
+ Get a segment starting from sequence Seq of a maximum\r
+ length of Len.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Seq The sequence number of the segment.\r
+ @param Len The maximum length of the segment.\r
+\r
+ @return Pointer to the segment, if NULL some error occurred.\r
+\r
+**/\r
+NET_BUF *\r
+TcpGetSegment (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP_SEQNO Seq,\r
+ IN UINT32 Len\r
+ )\r
+{\r
+ NET_BUF *Nbuf;\r
+\r
+ ASSERT (Tcb);\r
+\r
+ //\r
+ // Compare the SndNxt with the max sequence number sent.\r
+ //\r
+ if ((Len != 0) && TCP_SEQ_LT (Seq, TcpGetMaxSndNxt (Tcb))) {\r
+\r
+ Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len);\r
+ } else {\r
+\r
+ Nbuf = TcpGetSegmentSock (Tcb, Seq, Len);\r
+ }\r
+\r
+ ASSERT (TcpVerifySegment (Nbuf));\r
+ return Nbuf;\r
+}\r
+\r
+\r
+/**\r
+ Retransmit the segment from sequence Seq.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Seq The sequence number of the segment to be retransmitted.\r
+\r
+ @retval 0 Retransmission succeeded.\r
+ @retval -1 Error condition occurred.\r
+\r
+**/\r
+INTN\r
+TcpRetransmit (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP_SEQNO Seq\r
+ )\r
+{\r
+ NET_BUF *Nbuf;\r
+ UINT32 Len;\r
+\r
+ //\r
+ // Compute the maxium length of retransmission. It is\r
+ // limited by three factors:\r
+ // 1. Less than SndMss\r
+ // 2. must in the current send window\r
+ // 3. will not change the boundaries of queued segments.\r
+ //\r
+ if (TCP_SEQ_LT (Tcb->SndWl2 + Tcb->SndWnd, Seq)) {\r
+ TCP4_DEBUG_WARN (("TcpRetransmit: retransmission cancelled "\r
+ "because send window too small for TCB %x\n", Tcb));\r
+\r
+ return 0;\r
+ }\r
+\r
+ Len = TCP_SUB_SEQ (Tcb->SndWl2 + Tcb->SndWnd, Seq);\r
+ Len = NET_MIN (Len, Tcb->SndMss);\r
+\r
+ Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len);\r
+ if (Nbuf == NULL) {\r
+ return -1;\r
+ }\r
+\r
+ ASSERT (TcpVerifySegment (Nbuf));\r
+\r
+ if (TcpTransmitSegment (Tcb, Nbuf) != 0) {\r
+ goto OnError;\r
+ }\r
+\r
+ //\r
+ // The retransmitted buffer may be on the SndQue,\r
+ // trim TCP head because all the buffer on SndQue\r
+ // are headless.\r
+ //\r
+ ASSERT (Nbuf->Tcp);\r
+ NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);\r
+ Nbuf->Tcp = NULL;\r
+\r
+ NetbufFree (Nbuf);\r
+ return 0;\r
+\r
+OnError:\r
+ if (Nbuf != NULL) {\r
+ NetbufFree (Nbuf);\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+\r
+/**\r
+ Check whether to send data/SYN/FIN and piggy back an ACK.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Force Whether to ignore the sender's SWS avoidance algorithm and send\r
+ out data by force.\r
+\r
+ @return The number of bytes sent.\r
+\r
+**/\r
+INTN\r
+TcpToSendData (\r
+ IN TCP_CB *Tcb,\r
+ IN INTN Force\r
+ )\r
+{\r
+ UINT32 Len;\r
+ INTN Sent;\r
+ UINT8 Flag;\r
+ NET_BUF *Nbuf;\r
+ TCP_SEG *Seg;\r
+ TCP_SEQNO Seq;\r
+ TCP_SEQNO End;\r
+\r
+ ASSERT (Tcb && Tcb->Sk && (Tcb->State != TCP_LISTEN));\r
+\r
+ Sent = 0;\r
+\r
+ if ((Tcb->State == TCP_CLOSED) ||\r
+ TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT)) {\r
+\r
+ return 0;\r
+ }\r
+\r
+SEND_AGAIN:\r
+ //\r
+ // compute how much data can be sent\r
+ //\r
+ Len = TcpDataToSend (Tcb, Force);\r
+ Seq = Tcb->SndNxt;\r
+\r
+ Flag = mTcpOutFlag[Tcb->State];\r
+\r
+ if (Flag & TCP_FLG_SYN) {\r
+\r
+ Seq = Tcb->Iss;\r
+ Len = 0;\r
+ }\r
+\r
+ //\r
+ // only send a segment without data if SYN or\r
+ // FIN is set.\r
+ //\r
+ if ((Len == 0) && !(Flag & (TCP_FLG_SYN | TCP_FLG_FIN))) {\r
+ return Sent;\r
+ }\r
+\r
+ Nbuf = TcpGetSegment (Tcb, Seq, Len);\r
+\r
+ if (Nbuf == NULL) {\r
+ TCP4_DEBUG_ERROR (\r
+ ("TcpToSendData: failed to get a segment for TCB %x\n",\r
+ Tcb)\r
+ );\r
+\r
+ goto OnError;\r
+ }\r
+\r
+ Seg = TCPSEG_NETBUF (Nbuf);\r
+\r
+ //\r
+ // Set the TcpSeg in Nbuf.\r
+ //\r
+ Len = Nbuf->TotalSize;\r
+ End = Seq + Len;\r
+ if (TCP_FLG_ON (Flag, TCP_FLG_SYN)) {\r
+ End++;\r
+ }\r
+\r
+ if (Flag & TCP_FLG_FIN) {\r
+ //\r
+ // Send FIN if all data is sent, and FIN is\r
+ // in the window\r
+ //\r
+ if ((TcpGetMaxSndNxt (Tcb) == Tcb->SndNxt) &&\r
+ (GET_SND_DATASIZE (Tcb->Sk) == 0) &&\r
+ TCP_SEQ_LT (End + 1, Tcb->SndWnd + Tcb->SndWl2)\r
+ ) {\r
+\r
+ TCP4_DEBUG_TRACE (("TcpToSendData: send FIN "\r
+ "to peer for TCB %x in state %d\n", Tcb, Tcb->State));\r
+\r
+ End++;\r
+ } else {\r
+ TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);\r
+ }\r
+ }\r
+\r
+ Seg->Seq = Seq;\r
+ Seg->End = End;\r
+ Seg->Flag = Flag;\r
+\r
+ ASSERT (TcpVerifySegment (Nbuf));\r
+ ASSERT (TcpCheckSndQue (&Tcb->SndQue));\r
+\r
+ //\r
+ // don't send an empty segment here.\r
+ //\r
+ if (Seg->End == Seg->Seq) {\r
+ TCP4_DEBUG_WARN (("TcpToSendData: created a empty"\r
+ " segment for TCB %x, free it now\n", Tcb));\r
+\r
+ NetbufFree (Nbuf);\r
+ return Sent;\r
+ }\r
+\r
+ if (TcpTransmitSegment (Tcb, Nbuf) != 0) {\r
+ //\r
+ // TODO: double check this\r
+ //\r
+ NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);\r
+ Nbuf->Tcp = NULL;\r
+\r
+ if (Flag & TCP_FLG_FIN) {\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);\r
+ }\r
+\r
+ goto OnError;\r
+ }\r
+\r
+ Sent += TCP_SUB_SEQ (End, Seq);\r
+\r
+ //\r
+ // All the buffer in the SndQue is headless\r
+ //\r
+ ASSERT (Nbuf->Tcp);\r
+\r
+ NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);\r
+ Nbuf->Tcp = NULL;\r
+\r
+ NetbufFree (Nbuf);\r
+\r
+ //\r
+ // update status in TCB\r
+ //\r
+ Tcb->DelayedAck = 0;\r
+\r
+ if (Flag & TCP_FLG_FIN) {\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);\r
+ }\r
+\r
+ if (TCP_SEQ_GT (End, Tcb->SndNxt)) {\r
+ Tcb->SndNxt = End;\r
+ }\r
+\r
+ if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {\r
+ TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
+ }\r
+\r
+ //\r
+ // Enable RTT measurement only if not in retransmit.\r
+ // Karn's algorithm reqires not to update RTT when in loss.\r
+ //\r
+ if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&\r
+ !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
+\r
+ TCP4_DEBUG_TRACE (("TcpToSendData: set RTT measure "\r
+ "sequence %d for TCB %x\n", Seq, Tcb));\r
+\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
+ Tcb->RttSeq = Seq;\r
+ Tcb->RttMeasure = 0;\r
+ }\r
+\r
+ if (Len == Tcb->SndMss) {\r
+ goto SEND_AGAIN;\r
+ }\r
+\r
+ return Sent;\r
+\r
+OnError:\r
+ if (Nbuf != NULL) {\r
+ NetbufFree (Nbuf);\r
+ }\r
+\r
+ return Sent;\r
+}\r
+\r
+\r
+/**\r
+ Send an ACK immediately.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpSendAck (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ NET_BUF *Nbuf;\r
+ TCP_SEG *Seg;\r
+\r
+ Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
+\r
+ if (Nbuf == NULL) {\r
+ return;\r
+ }\r
+\r
+ NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
+\r
+ Seg = TCPSEG_NETBUF (Nbuf);\r
+ Seg->Seq = Tcb->SndNxt;\r
+ Seg->End = Tcb->SndNxt;\r
+ Seg->Flag = TCP_FLG_ACK;\r
+\r
+ if (TcpTransmitSegment (Tcb, Nbuf) == 0) {\r
+ TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
+ Tcb->DelayedAck = 0;\r
+ }\r
+\r
+ NetbufFree (Nbuf);\r
+}\r
+\r
+\r
+/**\r
+ Send a zero probe segment. It can be used by keepalive\r
+ and zero window probe.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @retval 0 The zero probe segment was sent out successfully.\r
+ @retval other Error condition occurred.\r
+\r
+**/\r
+INTN\r
+TcpSendZeroProbe (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ NET_BUF *Nbuf;\r
+ TCP_SEG *Seg;\r
+ INTN Result;\r
+\r
+ Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
+\r
+ if (Nbuf == NULL) {\r
+ return -1;\r
+ }\r
+\r
+ NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
+\r
+ //\r
+ // SndNxt-1 is out of window. The peer should respond\r
+ // with an ACK.\r
+ //\r
+ Seg = TCPSEG_NETBUF (Nbuf);\r
+ Seg->Seq = Tcb->SndNxt - 1;\r
+ Seg->End = Tcb->SndNxt - 1;\r
+ Seg->Flag = TCP_FLG_ACK;\r
+\r
+ Result = TcpTransmitSegment (Tcb, Nbuf);\r
+ NetbufFree (Nbuf);\r
+\r
+ return Result;\r
+}\r
+\r
+\r
+/**\r
+ Check whether to send an ACK or delayed ACK.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpToSendAck (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ //\r
+ // Generally, TCP should send a delayed ACK unless:\r
+ // 1. ACK at least every other FULL sized segment received,\r
+ // 2. Packets received out of order\r
+ // 3. Receiving window is open\r
+ //\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) ||\r
+ (Tcb->DelayedAck >= 1) ||\r
+ (TcpRcvWinNow (Tcb) > TcpRcvWinOld (Tcb))\r
+ ) {\r
+ TcpSendAck (Tcb);\r
+ return;\r
+ }\r
+\r
+ TCP4_DEBUG_TRACE (("TcpToSendAck: scheduled a delayed"\r
+ " ACK for TCB %x\n", Tcb));\r
+\r
+ //\r
+ // schedule a delayed ACK\r
+ //\r
+ Tcb->DelayedAck++;\r
+}\r
+\r
+\r
+/**\r
+ Send a RESET segment in response to the segment received.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance, may be NULL.\r
+ @param Head TCP header of the segment that triggers the reset.\r
+ @param Len Length of the segment that triggers the reset.\r
+ @param Local Local IP address.\r
+ @param Remote Remote peer's IP address.\r
+\r
+ @retval 0 A reset is sent or no need to send it.\r
+ @retval -1 No reset is sent.\r
+\r
+**/\r
+INTN\r
+TcpSendReset (\r
+ IN TCP_CB *Tcb,\r
+ IN TCP_HEAD *Head,\r
+ IN INT32 Len,\r
+ IN UINT32 Local,\r
+ IN UINT32 Remote\r
+ )\r
+{\r
+ NET_BUF *Nbuf;\r
+ TCP_HEAD *Nhead;\r
+ UINT16 HeadSum;\r
+\r
+ //\r
+ // Don't respond to a Reset with reset\r
+ //\r
+ if (Head->Flag & TCP_FLG_RST) {\r
+ return 0;\r
+ }\r
+\r
+ Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
+\r
+ if (Nbuf == NULL) {\r
+ return -1;\r
+ }\r
+\r
+ Nhead = (TCP_HEAD *) NetbufAllocSpace (\r
+ Nbuf,\r
+ sizeof (TCP_HEAD),\r
+ NET_BUF_TAIL\r
+ );\r
+\r
+ ASSERT (Nhead != NULL);\r
+\r
+ Nbuf->Tcp = Nhead;\r
+ Nhead->Flag = TCP_FLG_RST;\r
+\r
+ //\r
+ // Derive Seq/ACK from the segment if no TCB\r
+ // associated with it, otherwise from the Tcb\r
+ //\r
+ if (Tcb == NULL) {\r
+\r
+ if (TCP_FLG_ON (Head->Flag, TCP_FLG_ACK)) {\r
+ Nhead->Seq = Head->Ack;\r
+ Nhead->Ack = 0;\r
+ } else {\r
+ Nhead->Seq = 0;\r
+ TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);\r
+ Nhead->Ack = HTONL (NTOHL (Head->Seq) + Len);\r
+ }\r
+ } else {\r
+\r
+ Nhead->Seq = HTONL (Tcb->SndNxt);\r
+ Nhead->Ack = HTONL (Tcb->RcvNxt);\r
+ TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);\r
+ }\r
+\r
+ Nhead->SrcPort = Head->DstPort;\r
+ Nhead->DstPort = Head->SrcPort;\r
+ Nhead->HeadLen = (sizeof (TCP_HEAD) >> 2);\r
+ Nhead->Res = 0;\r
+ Nhead->Wnd = HTONS (0xFFFF);\r
+ Nhead->Checksum = 0;\r
+ Nhead->Urg = 0;\r
+\r
+ HeadSum = NetPseudoHeadChecksum (Local, Remote, 6, 0);\r
+ Nhead->Checksum = TcpChecksum (Nbuf, HeadSum);\r
+\r
+ TcpSendIpPacket (Tcb, Nbuf, Local, Remote);\r
+\r
+ NetbufFree (Nbuf);\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ Verify that the segment is in good shape.\r
+\r
+ @param Nbuf Buffer that contains the segment to be checked.\r
+\r
+ @retval 0 The segment is broken.\r
+ @retval 1 The segment is in good shape.\r
+\r
+**/\r
+INTN\r
+TcpVerifySegment (\r
+ IN NET_BUF *Nbuf\r
+ )\r
+{\r
+ TCP_HEAD *Head;\r
+ TCP_SEG *Seg;\r
+ UINT32 Len;\r
+\r
+ if (Nbuf == NULL) {\r
+ return 1;\r
+ }\r
+\r
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
+\r
+ Seg = TCPSEG_NETBUF (Nbuf);\r
+ Len = Nbuf->TotalSize;\r
+ Head = Nbuf->Tcp;\r
+\r
+ if (Head != NULL) {\r
+ if (Head->Flag != Seg->Flag) {\r
+ return 0;\r
+ }\r
+\r
+ Len -= (Head->HeadLen << 2);\r
+ }\r
+\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
+ Len++;\r
+ }\r
+\r
+ if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
+ Len++;\r
+ }\r
+\r
+ if (Seg->Seq + Len != Seg->End) {\r
+ return 0;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+\r
+/**\r
+ Verify that all the segments in SndQue are in good shape.\r
+\r
+ @param Head Pointer to the head node of the SndQue.\r
+\r
+ @retval 0 At least one segment is broken.\r
+ @retval 1 All segments in the specific queue are in good shape.\r
+\r
+**/\r
+INTN\r
+TcpCheckSndQue (\r
+ IN NET_LIST_ENTRY *Head\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_BUF *Nbuf;\r
+ TCP_SEQNO Seq;\r
+\r
+ if (NetListIsEmpty (Head)) {\r
+ return 1;\r
+ }\r
+ //\r
+ // Initialize the Seq\r
+ //\r
+ Entry = Head->ForwardLink;\r
+ Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+ Seq = TCPSEG_NETBUF (Nbuf)->Seq;\r
+\r
+ NET_LIST_FOR_EACH (Entry, Head) {\r
+ Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+\r
+ if (TcpVerifySegment (Nbuf) == 0) {\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // All the node in the SndQue should has:\r
+ // SEG.SEQ = LAST_SEG.END\r
+ //\r
+ if (Seq != TCPSEG_NETBUF (Nbuf)->Seq) {\r
+ return 0;\r
+ }\r
+\r
+ Seq = TCPSEG_NETBUF (Nbuf)->End;\r
+ }\r
+\r
+ return 1;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 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:
+
+ Tcp4Proto.h
+
+Abstract:
+
+
+**/
+
+#ifndef _TCP4_PROTO_H_
+#define _TCP4_PROTO_H_
+
+typedef struct _TCP_CB TCP_CB;
+
+#include "Tcp4Driver.h"
+#include "Socket.h"
+#include "Tcp4Option.h"
+
+//
+// tcp states, Don't change their order, it is used as
+// index to mTcpOutFlag and other macros
+//
+enum {
+ TCP_CLOSED = 0,
+ TCP_LISTEN,
+ TCP_SYN_SENT,
+ TCP_SYN_RCVD,
+ TCP_ESTABLISHED,
+ TCP_FIN_WAIT_1,
+ TCP_FIN_WAIT_2,
+ TCP_CLOSING,
+ TCP_TIME_WAIT,
+ TCP_CLOSE_WAIT,
+ TCP_LAST_ACK,
+};
+
+//
+// flags in the TCP header
+//
+enum {
+
+ TCP_FLG_FIN = 0x01,
+ TCP_FLG_SYN = 0x02,
+ TCP_FLG_RST = 0x04,
+ TCP_FLG_PSH = 0x08,
+ TCP_FLG_ACK = 0x10,
+ TCP_FLG_URG = 0x20,
+ TCP_FLG_FLAG = 0x3F, // mask for all the flags
+};
+
+enum {
+
+ //
+ // TCP error status
+ //
+ TCP_CONNECT_REFUSED = -1,
+ TCP_CONNECT_RESET = -2,
+ TCP_CONNECT_CLOSED = -3,
+
+ //
+ // Current congestion status as suggested by RFC3782.
+ //
+ TCP_CONGEST_RECOVER = 1, // during the NewReno fast recovery
+ TCP_CONGEST_LOSS = 2, // retxmit because of retxmit time out
+ TCP_CONGEST_OPEN = 3, // TCP is opening its congestion window
+
+ //
+ // TCP control flags
+ //
+ TCP_CTRL_NO_NAGLE = 0x0001, // disable Nagle algorithm
+ TCP_CTRL_NO_KEEPALIVE = 0x0002, // disable keepalive timer
+ TCP_CTRL_NO_WS = 0x0004, // disable window scale option
+ TCP_CTRL_RCVD_WS = 0x0008, // rcvd a wnd scale option in syn
+ TCP_CTRL_NO_TS = 0x0010, // disable Timestamp option
+ TCP_CTRL_RCVD_TS = 0x0020, // rcvd a Timestamp option in syn
+ TCP_CTRL_SND_TS = 0x0040, // Send Timestamp option to remote
+ TCP_CTRL_SND_URG = 0x0080, // in urgent send mode
+ TCP_CTRL_RCVD_URG = 0x0100, // in urgent receive mode
+ TCP_CTRL_SND_PSH = 0x0200, // in PUSH send mode
+ TCP_CTRL_FIN_SENT = 0x0400, // FIN is sent
+ TCP_CTRL_FIN_ACKED = 0x0800, // FIN is ACKed.
+ TCP_CTRL_TIMER_ON = 0x1000, // At least one of the timer is on
+ TCP_CTRL_RTT_ON = 0x2000, // The RTT measurement is on
+ TCP_CTRL_ACK_NOW = 0x4000, // Send the ACK now, don't delay
+
+ //
+ // Timer related values
+ //
+ TCP_TIMER_CONNECT = 0, // Connection establishment timer
+ TCP_TIMER_REXMIT = 1, // retransmit timer
+ TCP_TIMER_PROBE = 2, // Window probe timer
+ TCP_TIMER_KEEPALIVE = 3, // Keepalive timer
+ TCP_TIMER_FINWAIT2 = 4, // FIN_WAIT_2 timer
+ TCP_TIMER_2MSL = 5, // TIME_WAIT tiemr
+ TCP_TIMER_NUMBER = 6, // the total number of TCP timer.
+ TCP_TICK = 200, // every TCP tick is 200ms
+ TCP_TICK_HZ = 5, // the frequence of TCP tick
+ TCP_RTT_SHIFT = 3, // SRTT & RTTVAR scaled by 8
+ TCP_RTO_MIN = TCP_TICK_HZ, // the minium value of RTO
+ TCP_RTO_MAX = TCP_TICK_HZ *60, // the maxium value of RTO
+ TCP_FOLD_RTT = 4, // timeout threshod to fold RTT
+
+ //
+ // default values for some timers
+ //
+ TCP_MAX_LOSS = 12, // default max times to retxmit
+ TCP_KEEPALIVE_IDLE_MIN = TCP_TICK_HZ *60 *60 *2, // First keep alive
+ TCP_KEEPALIVE_PERIOD = TCP_TICK_HZ *60,
+ TCP_MAX_KEEPALIVE = 8,
+ TCP_FIN_WAIT2_TIME = 2 *TCP_TICK_HZ, // * 60,
+ TCP_TIME_WAIT_TIME = 2 *TCP_TICK_HZ,
+ TCP_PAWS_24DAY = 24 *24 *60 *60 *TCP_TICK_HZ,
+ TCP_CONNECT_TIME = 75 *TCP_TICK_HZ,
+
+ //
+ // The header space to be reserved before TCP data to accomodate :
+ // 60byte IP head + 60byte TCP head + link layer head
+ //
+ TCP_MAX_HEAD = 192,
+
+ //
+ // value ranges for some control option
+ //
+ TCP_RCV_BUF_SIZE = 2 *1024 *1024,
+ TCP_RCV_BUF_SIZE_MIN = 8 *1024,
+ TCP_SND_BUF_SIZE = 2 *1024 *1024,
+ TCP_SND_BUF_SIZE_MIN = 8 *1024,
+ TCP_BACKLOG = 10,
+ TCP_BACKLOG_MIN = 5,
+ TCP_MAX_LOSS_MIN = 6,
+ TCP_CONNECT_TIME_MIN = 60 *TCP_TICK_HZ,
+ TCP_MAX_KEEPALIVE_MIN = 4,
+ TCP_KEEPALIVE_IDLE_MAX = TCP_TICK_HZ *60 *60 *4,
+ TCP_KEEPALIVE_PERIOD_MIN= TCP_TICK_HZ *30,
+ TCP_FIN_WAIT2_TIME_MAX = 4 *TCP_TICK_HZ,
+ TCP_TIME_WAIT_TIME_MAX = 60 *TCP_TICK_HZ,
+};
+
+typedef struct _TCP_SEG {
+ TCP_SEQNO Seq; // Starting sequence number
+ TCP_SEQNO End; // The sequence of the last byte + 1,
+ // include SYN/FIN. End-Seq = SEG.LEN
+ TCP_SEQNO Ack; // ACK fild in the segment
+ UINT8 Flag; // TCP header flags
+ UINT16 Urg; // Valid if URG flag is set.
+ UINT32 Wnd; // TCP window size field
+} TCP_SEG;
+
+typedef struct _TCP_PEER {
+ UINT32 Ip; // Network byte order
+ TCP_PORTNO Port; // Network byte order
+} TCP_PEER;
+
+//
+// tcp control block, it includes various states
+//
+typedef struct _TCP_CB {
+ NET_LIST_ENTRY List;
+ TCP_CB *Parent;
+
+ SOCKET *Sk;
+ TCP_PEER LocalEnd;
+ TCP_PEER RemoteEnd;
+
+ NET_LIST_ENTRY SndQue; // retxmission queue
+ NET_LIST_ENTRY RcvQue; // reassemble queue
+ UINT32 CtrlFlag; // control flags, such as NO_NAGLE
+ INT32 Error; // soft error status,TCP_CONNECT_RESET...
+
+ //
+ // RFC793 and RFC1122 defined variables
+ //
+ UINT8 State; // TCP state, such as SYN_SENT, LISTEN
+ UINT8 DelayedAck; // number of delayed ACKs
+ UINT16 HeadSum; // checksum of the fixed parts of pesudo
+ // header: Src IP, Dst IP, 0, Protocol,
+ // not include the TCP length.
+
+ TCP_SEQNO Iss; // Initial Sending Sequence
+ TCP_SEQNO SndUna; // first unacknowledged data
+ TCP_SEQNO SndNxt; // next data sequence to send.
+ TCP_SEQNO SndPsh; // Send PUSH point
+ TCP_SEQNO SndUp; // Send urgent point
+ UINT32 SndWnd; // Window advertised by the remote peer
+ UINT32 SndWndMax; // max send window advertised by the peer
+ TCP_SEQNO SndWl1; // Seq number used for last window update
+ TCP_SEQNO SndWl2; // ack no of last window update
+ UINT16 SndMss; // Max send segment size
+ TCP_SEQNO RcvNxt; // Next sequence no to receive
+ UINT32 RcvWnd; // Window advertised by the local peer
+ TCP_SEQNO RcvWl2; // The RcvNxt (or ACK) of last window update.
+ // It is necessary because of delayed ACK
+
+ TCP_SEQNO RcvUp; // urgent point;
+ TCP_SEQNO Irs; // Initial Receiving Sequence
+ UINT16 RcvMss; // Max receive segment size
+ UINT16 EnabledTimer; // which timer is currently enabled
+ UINT32 Timer[TCP_TIMER_NUMBER]; // when the timer will expire
+ INT32 NextExpire; // count down offset for the nearest timer
+ UINT32 Idle; // How long the connection is in idle
+ UINT32 ProbeTime; // the time out value for current window prober
+
+ //
+ // RFC1323 defined variables, about window scale,
+ // timestamp and PAWS
+ //
+ UINT8 SndWndScale; // Wndscale received from the peer
+ UINT8 RcvWndScale; // Wndscale used to scale local buffer
+ UINT32 TsRecent; // TsRecent to echo to the remote peer
+ UINT32 TsRecentAge; // When this TsRecent is updated
+
+ // TCP_SEQNO LastAckSent;
+ // It isn't necessary to add LastAckSent here,
+ // since it is the same as RcvWl2
+
+ //
+ // RFC2988 defined variables. about RTT measurement
+ //
+ TCP_SEQNO RttSeq; // the seq of measured segment now
+ UINT32 RttMeasure; // currently measured RTT in heart beats
+ UINT32 SRtt; // Smoothed RTT, scaled by 8
+ UINT32 RttVar; // RTT variance, scaled by 8
+ UINT32 Rto; // Current RTO, not scaled
+
+ //
+ // RFC2581, and 3782 variables.
+ // Congestion control + NewReno fast recovery.
+ //
+ UINT32 CWnd; // Sender's congestion window
+ UINT32 Ssthresh; // Slow start threshold.
+ TCP_SEQNO Recover; // recover point for NewReno
+ UINT16 DupAck; // number of duplicate ACKs
+ UINT8 CongestState; // the current congestion state(RFC3782)
+ UINT8 LossTimes; // number of retxmit timeouts in a row
+ TCP_SEQNO LossRecover; // recover point for retxmit
+
+ //
+ // configuration parameters, for EFI_TCP4_PROTOCOL specification
+ //
+ UINT32 KeepAliveIdle; // idle time before sending first probe
+ UINT32 KeepAlivePeriod; // interval for subsequent keep alive probe
+ UINT8 MaxKeepAlive; // Maxium keep alive probe times.
+ UINT8 KeepAliveProbes; // the number of keep alive probe.
+ UINT16 MaxRexmit; // The maxium number of retxmit before abort
+ UINT32 FinWait2Timeout; // The FIN_WAIT_2 time out
+ UINT32 TimeWaitTimeout; // The TIME_WAIT time out
+ UINT32 ConnectTimeout;
+
+ //
+ // configuration for tcp provided by user
+ //
+ BOOLEAN UseDefaultAddr;
+ UINT8 TOS;
+ UINT8 TTL;
+ EFI_IPv4_ADDRESS SubnetMask;
+
+ //
+ // pointer reference to Ip used to send pkt
+ //
+ IP_IO_IP_INFO *IpInfo;
+} TCP_CB;
+
+extern NET_LIST_ENTRY mTcpRunQue;
+extern NET_LIST_ENTRY mTcpListenQue;
+extern TCP_SEQNO mTcpGlobalIss;
+extern UINT32 mTcpTick;
+
+//
+// TCP_CONNECTED: both ends have synchronized their ISN.
+//
+#define TCP_CONNECTED(state) ((state) > TCP_SYN_RCVD)
+
+#define TCP_FIN_RCVD(State) \
+ (((State) == TCP_CLOSE_WAIT) || \
+ ((State) == TCP_LAST_ACK) || \
+ ((State) == TCP_CLOSING) || \
+ ((State) == TCP_TIME_WAIT))
+
+#define TCP_LOCAL_CLOSED(State) \
+ (((State) == TCP_FIN_WAIT_1) || \
+ ((State) == TCP_FIN_WAIT_2) || \
+ ((State) == TCP_CLOSING) || \
+ ((State) == TCP_TIME_WAIT) || \
+ ((State) == TCP_LAST_ACK))
+
+//
+// Get the TCP_SEG point from a net buffer's ProtoData
+//
+#define TCPSEG_NETBUF(NBuf) ((TCP_SEG *) ((NBuf)->ProtoData))
+
+//
+// macros to compare sequence no
+//
+#define TCP_SEQ_LT(SeqA, SeqB) ((INT32) ((SeqA) - (SeqB)) < 0)
+#define TCP_SEQ_LEQ(SeqA, SeqB) ((INT32) ((SeqA) - (SeqB)) <= 0)
+#define TCP_SEQ_GT(SeqA, SeqB) ((INT32) ((SeqB) - (SeqA)) < 0)
+#define TCP_SEQ_GEQ(SeqA, SeqB) ((INT32) ((SeqB) - (SeqA)) <= 0)
+
+//
+// TCP_SEQ_BETWEEN return whether b <= m <= e
+//
+#define TCP_SEQ_BETWEEN(b, m, e) ((e) - (b) >= (m) - (b))
+
+//
+// TCP_SUB_SEQ returns Seq1 - Seq2. Make sure Seq1 >= Seq2
+//
+#define TCP_SUB_SEQ(Seq1, Seq2) ((UINT32) ((Seq1) - (Seq2)))
+
+#define TCP_FLG_ON(Value, Flag) ((BOOLEAN) (((Value) & (Flag)) != 0))
+#define TCP_SET_FLG(Value, Flag) ((Value) |= (Flag))
+#define TCP_CLEAR_FLG(Value, Flag) ((Value) &= ~(Flag))
+
+//
+// test whether two peers are equal
+//
+#define TCP_PEER_EQUAL(Pa, Pb) \
+ (((Pa)->Ip == (Pb)->Ip) && ((Pa)->Port == (Pb)->Port))
+
+//
+// test whether Pa matches Pb, or Pa is more specific
+// than pb. Zero means wildcard.
+//
+#define TCP_PEER_MATCH(Pa, Pb) \
+ ((((Pb)->Ip == 0) || ((Pb)->Ip == (Pa)->Ip)) && \
+ (((Pb)->Port == 0) || ((Pb)->Port == (Pa)->Port)))
+
+#define TCP_TIMER_ON(Flag, Timer) ((Flag) & (1 << (Timer)))
+#define TCP_SET_TIMER(Flag, Timer) ((Flag) |= (1 << (Timer)))
+#define TCP_CLEAR_TIMER(Flag, Timer) ((Flag) &= ~(1 << (Timer)))
+
+#define TCP_TIME_LT(Ta, Tb) ((INT32) ((Ta) - (Tb)) < 0)
+#define TCP_TIME_LEQ(Ta, Tb) ((INT32) ((Ta) - (Tb)) <= 0)
+#define TCP_SUB_TIME(Ta, Tb) ((UINT32) ((Ta) - (Tb)))
+
+#define TCP_MAX_WIN 0xFFFFU
+
+typedef
+VOID
+(*TCP_TIMER_HANDLER) (
+ IN TCP_CB * Tcb
+ );
+
+#include "Tcp4Func.h"
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Tcp4Timer.c\r
+\r
+Abstract:\r
+\r
+ TCP timer related functions.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+UINT32 mTcpTick = 1000;\r
+\r
+STATIC\r
+VOID\r
+TcpConnectTimeout (\r
+ IN TCP_CB *Tcb\r
+ );\r
+\r
+STATIC\r
+VOID\r
+TcpRexmitTimeout (\r
+ IN TCP_CB *Tcb\r
+ );\r
+\r
+STATIC\r
+VOID\r
+TcpProbeTimeout (\r
+ IN TCP_CB *Tcb\r
+ );\r
+\r
+STATIC\r
+VOID\r
+TcpKeepaliveTimeout (\r
+ IN TCP_CB *Tcb\r
+ );\r
+\r
+STATIC\r
+VOID\r
+TcpFinwait2Timeout (\r
+ IN TCP_CB *Tcb\r
+ );\r
+\r
+STATIC\r
+VOID\r
+Tcp2MSLTimeout (\r
+ IN TCP_CB *Tcb\r
+ );\r
+\r
+TCP_TIMER_HANDLER mTcpTimerHandler[TCP_TIMER_NUMBER] = {\r
+ TcpConnectTimeout,\r
+ TcpRexmitTimeout,\r
+ TcpProbeTimeout,\r
+ TcpKeepaliveTimeout,\r
+ TcpFinwait2Timeout,\r
+ Tcp2MSLTimeout,\r
+};\r
+\r
+\r
+/**\r
+ Close the TCP connection.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpClose (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ NetbufFreeList (&Tcb->SndQue);\r
+ NetbufFreeList (&Tcb->RcvQue);\r
+\r
+ TcpSetState (Tcb, TCP_CLOSED);\r
+}\r
+\r
+\r
+/**\r
+ Connect timeout handler.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpConnectTimeout (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ if (!TCP_CONNECTED (Tcb->State)) {\r
+ TCP4_DEBUG_ERROR (("TcpConnectTimeout: connection closed "\r
+ "because conenction timer timeout for TCB %x\n", Tcb));\r
+\r
+ if (EFI_ABORTED == Tcb->Sk->SockError) {\r
+ SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);\r
+ }\r
+\r
+ if (TCP_SYN_RCVD == Tcb->State) {\r
+ TCP4_DEBUG_WARN (("TcpConnectTimeout: send reset because "\r
+ "connection timer timeout for TCB %x\n", Tcb));\r
+\r
+ TcpResetConnection (Tcb);\r
+\r
+ }\r
+\r
+ TcpClose (Tcb);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Timeout handler for TCP retransmission timer.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpRexmitTimeout (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ UINT32 FlightSize;\r
+\r
+ TCP4_DEBUG_WARN (("TcpRexmitTimeout: transmission "\r
+ "timeout for TCB %x\n", Tcb));\r
+\r
+ //\r
+ // Set the congestion window. FlightSize is the\r
+ // amount of data that has been sent but not\r
+ // yet ACKed.\r
+ //\r
+ FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
+ Tcb->Ssthresh = NET_MAX ((UINT32) (2 * Tcb->SndMss), FlightSize / 2);\r
+\r
+ Tcb->CWnd = Tcb->SndMss;\r
+ Tcb->LossRecover = Tcb->SndNxt;\r
+\r
+ Tcb->LossTimes++;\r
+ if (Tcb->LossTimes > Tcb->MaxRexmit &&\r
+ !TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_CONNECT)) {\r
+\r
+ TCP4_DEBUG_ERROR (("TcpRexmitTimeout: connection closed "\r
+ "because too many timeouts for TCB %x\n", Tcb));\r
+\r
+ if (EFI_ABORTED == Tcb->Sk->SockError) {\r
+ SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);\r
+ }\r
+\r
+ TcpClose (Tcb);\r
+ return ;\r
+ }\r
+\r
+ TcpBackoffRto (Tcb);\r
+ TcpRetransmit (Tcb, Tcb->SndUna);\r
+ TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
+\r
+ Tcb->CongestState = TCP_CONGEST_LOSS;\r
+\r
+ TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
+}\r
+\r
+\r
+/**\r
+ Timeout handler for window probe timer.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpProbeTimeout (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ //\r
+ // This is the timer for sender's SWSA. RFC1122 requires\r
+ // a timer set for sender's SWSA, and suggest combine it\r
+ // with window probe timer. If data is sent, don't set\r
+ // the probe timer, since retransmit timer is on.\r
+ //\r
+ if ((TcpDataToSend (Tcb, 1) != 0) && (TcpToSendData (Tcb, 1) > 0)) {\r
+\r
+ ASSERT (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT));\r
+ return ;\r
+ }\r
+\r
+ TcpSendZeroProbe (Tcb);\r
+ TcpSetProbeTimer (Tcb);\r
+}\r
+\r
+\r
+/**\r
+ Timeout handler for keepalive timer.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpKeepaliveTimeout (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ Tcb->KeepAliveProbes++;\r
+\r
+ //\r
+ // Too many Keep-alive probes, drop the connection\r
+ //\r
+ if (Tcb->KeepAliveProbes > Tcb->MaxKeepAlive) {\r
+\r
+ if (EFI_ABORTED == Tcb->Sk->SockError) {\r
+ SOCK_ERROR (Tcb->Sk, EFI_TIMEOUT);\r
+ }\r
+\r
+ TcpClose (Tcb);\r
+ return ;\r
+ }\r
+\r
+ TcpSendZeroProbe (Tcb);\r
+ TcpSetKeepaliveTimer (Tcb);\r
+}\r
+\r
+\r
+/**\r
+ Timeout handler for FIN_WAIT_2 timer.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpFinwait2Timeout (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ TCP4_DEBUG_WARN (("TcpFinwait2Timeout: connection closed "\r
+ "because FIN_WAIT2 timer timeouts for TCB %x\n", Tcb));\r
+\r
+ TcpClose (Tcb);\r
+}\r
+\r
+\r
+/**\r
+ Timeout handler for 2MSL timer.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Tcp2MSLTimeout (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ TCP4_DEBUG_WARN (("Tcp2MSLTimeout: connection closed "\r
+ "because TIME_WAIT timer timeouts for TCB %x\n", Tcb));\r
+\r
+ TcpClose (Tcb);\r
+}\r
+\r
+\r
+/**\r
+ Update the timer status and the next expire time\r
+ according to the timers to expire in a specific\r
+ future time slot.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+TcpUpdateTimer (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ UINT16 Index;\r
+\r
+ //\r
+ // Don't use a too large value to init NextExpire\r
+ // since mTcpTick wraps around as sequence no does.\r
+ //\r
+ Tcb->NextExpire = 65535;\r
+ TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);\r
+\r
+ for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {\r
+\r
+ if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&\r
+ TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire)) {\r
+\r
+ Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick);\r
+ TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Enable a TCP timer.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Timer The index of the timer to be enabled.\r
+ @param TimeOut The timeout value of this timer.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpSetTimer (\r
+ IN TCP_CB *Tcb,\r
+ IN UINT16 Timer,\r
+ IN UINT32 TimeOut\r
+ )\r
+{\r
+ TCP_SET_TIMER (Tcb->EnabledTimer, Timer);\r
+ Tcb->Timer[Timer] = mTcpTick + TimeOut;\r
+\r
+ TcpUpdateTimer (Tcb);\r
+}\r
+\r
+\r
+/**\r
+ Clear one TCP timer.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+ @param Timer The index of the timer to be cleared.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpClearTimer (\r
+ IN TCP_CB *Tcb,\r
+ IN UINT16 Timer\r
+ )\r
+{\r
+ TCP_CLEAR_TIMER (Tcb->EnabledTimer, Timer);\r
+ TcpUpdateTimer (Tcb);\r
+}\r
+\r
+\r
+/**\r
+ Clear all TCP timers.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpClearAllTimer (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ Tcb->EnabledTimer = 0;\r
+ TcpUpdateTimer (Tcb);\r
+}\r
+\r
+\r
+/**\r
+ Enable the window prober timer and set the timeout value.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpSetProbeTimer (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_PROBE)) {\r
+ Tcb->ProbeTime = Tcb->Rto;\r
+\r
+ } else {\r
+ Tcb->ProbeTime <<= 1;\r
+ }\r
+\r
+ if (Tcb->ProbeTime < TCP_RTO_MIN) {\r
+\r
+ Tcb->ProbeTime = TCP_RTO_MIN;\r
+ } else if (Tcb->ProbeTime > TCP_RTO_MAX) {\r
+\r
+ Tcb->ProbeTime = TCP_RTO_MAX;\r
+ }\r
+\r
+ TcpSetTimer (Tcb, TCP_TIMER_PROBE, Tcb->ProbeTime);\r
+}\r
+\r
+\r
+/**\r
+ Enable the keepalive timer and set the timeout value.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpSetKeepaliveTimer (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE)) {\r
+ return ;\r
+\r
+ }\r
+\r
+ //\r
+ // Set the timer to KeepAliveIdle if either\r
+ // 1. the keepalive timer is off\r
+ // 2. The keepalive timer is on, but the idle\r
+ // is less than KeepAliveIdle, that means the\r
+ // connection is alive since our last probe.\r
+ //\r
+ if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_KEEPALIVE) ||\r
+ (Tcb->Idle < Tcb->KeepAliveIdle)) {\r
+\r
+ TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAliveIdle);\r
+ Tcb->KeepAliveProbes = 0;\r
+\r
+ } else {\r
+\r
+ TcpSetTimer (Tcb, TCP_TIMER_KEEPALIVE, Tcb->KeepAlivePeriod);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Backoff the RTO.\r
+\r
+ @param Tcb Pointer to the TCP_CB of this TCP instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+TcpBackoffRto (\r
+ IN TCP_CB *Tcb\r
+ )\r
+{\r
+ //\r
+ // Fold the RTT estimate if too many times, the estimate\r
+ // may be wrong, fold it. So the next time a valid\r
+ // measurement is sampled, we can start fresh.\r
+ //\r
+ if ((Tcb->LossTimes >= TCP_FOLD_RTT) && Tcb->SRtt) {\r
+ Tcb->RttVar += Tcb->SRtt >> 2;\r
+ Tcb->SRtt = 0;\r
+ }\r
+\r
+ Tcb->Rto <<= 1;\r
+\r
+ if (Tcb->Rto < TCP_RTO_MIN) {\r
+\r
+ Tcb->Rto = TCP_RTO_MIN;\r
+ } else if (Tcb->Rto > TCP_RTO_MAX) {\r
+\r
+ Tcb->Rto = TCP_RTO_MAX;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Heart beat timer handler.\r
+\r
+ @param Event Timer event signaled, ignored.\r
+ @param Context Context of the timer event, ignored.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TcpTicking (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ TCP_CB *Tcb;\r
+ INT16 Index;\r
+\r
+ mTcpTick++;\r
+ mTcpGlobalIss += 100;\r
+\r
+ //\r
+ // Don't use LIST_FOR_EACH, which isn't delete safe.\r
+ //\r
+ for (Entry = mTcpRunQue.ForwardLink; Entry != &mTcpRunQue; Entry = Next) {\r
+\r
+ Next = Entry->ForwardLink;\r
+\r
+ Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
+\r
+ if (Tcb->State == TCP_CLOSED) {\r
+ continue;\r
+ }\r
+ //\r
+ // The connection is doing RTT measurement.\r
+ //\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
+ Tcb->RttMeasure++;\r
+ }\r
+\r
+ Tcb->Idle++;\r
+\r
+ if (Tcb->DelayedAck) {\r
+ TcpSendAck (Tcb);\r
+ }\r
+\r
+ //\r
+ // No timer is active or no timer expired\r
+ //\r
+ if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON) ||\r
+ ((--Tcb->NextExpire) > 0)) {\r
+\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Call the timeout handler for each expired timer.\r
+ //\r
+ for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) {\r
+\r
+ if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) &&\r
+ TCP_TIME_LEQ (Tcb->Timer[Index], mTcpTick)) {\r
+ //\r
+ // disable the timer before calling the handler\r
+ // in case the handler enables it again.\r
+ //\r
+ TCP_CLEAR_TIMER (Tcb->EnabledTimer, Index);\r
+ mTcpTimerHandler[Index](Tcb);\r
+\r
+ //\r
+ // The Tcb may have been deleted by the timer, or\r
+ // no other timer is set.\r
+ //\r
+ if ((Next->BackLink != Entry) ||\r
+ (Tcb->EnabledTimer == 0)) {\r
+\r
+ goto NextConnection;\r
+ }\r
+ }\r
+ }\r
+\r
+ TcpUpdateTimer (Tcb);\r
+NextConnection:\r
+ ;\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Udp4Impl.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+UdpComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UdpComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL gUdp4ComponentName = {\r
+ UdpComponentNameGetDriverName,\r
+ UdpComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mUdpDriverNameTable[] = {\r
+ {\r
+ "eng",\r
+ L"UDP Network Service Driver"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UdpComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ Language - A pointer to a three character ISO 639-2 language identifier.\r
+ This is the language of the driver name that that the caller\r
+ is requesting, and it must match one of the languages specified\r
+ in SupportedLanguages. The number of languages supported by a\r
+ driver is up to the driver writer.\r
+ DriverName - A pointer to the Unicode string to return. This Unicode string\r
+ is the name of the driver specified by This in the language\r
+ specified by Language.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCES - The Unicode string for the Driver specified by This\r
+ and the language specified by Language was returned\r
+ in DriverName.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - DriverName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gUdp4ComponentName.SupportedLanguages,\r
+ mUdpDriverNameTable,\r
+ DriverName\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UdpComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by an EFI Driver.\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ ControllerHandle - The handle of a controller that the driver specified by\r
+ This is managing. This handle specifies the controller\r
+ whose name is to be returned.\r
+ ChildHandle - The handle of the child controller to retrieve the name\r
+ of. This is an optional parameter that may be NULL. It\r
+ will be NULL for device drivers. It will also be NULL\r
+ for a bus drivers that wish to retrieve the name of the\r
+ bus controller. It will not be NULL for a bus driver\r
+ that wishes to retrieve the name of a child controller.\r
+ Language - A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language of the controller name\r
+ that that the caller is requesting, and it must match one\r
+ of the languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up to the\r
+ driver writer.\r
+ ControllerName - A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the controller specified by\r
+ ControllerHandle and ChildHandle in the language specified\r
+ by Language from the point of view of the driver specified\r
+ by This.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The Unicode string for the user readable name in the\r
+ language specified by Language for the driver\r
+ specified by This was returned in DriverName.\r
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This is not currently managing\r
+ the controller specified by ControllerHandle and\r
+ ChildHandle.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Udp4Driver.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Udp4Impl.h"\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gUdp4DriverBinding = {\r
+ Udp4DriverBindingSupported,\r
+ Udp4DriverBindingStart,\r
+ Udp4DriverBindingStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+EFI_SERVICE_BINDING_PROTOCOL mUdp4ServiceBinding = {\r
+ Udp4ServiceBindingCreateChild,\r
+ Udp4ServiceBindingDestroyChild\r
+};\r
+\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to test.\r
+ @param RemainingDevicePath Optional parameter use to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCES This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4DriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Test for the Udp4ServiceBinding Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiUdp4ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ //\r
+ // Test for the Ip4 Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Start this driver on ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to bind driver to\r
+ @param RemainingDevicePath Optional parameter use to pick a specific child\r
+ device to start.\r
+\r
+ @retval EFI_SUCCES This driver is added to ControllerHandle\r
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
+ @retval other This driver does not support this device\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4DriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UDP4_SERVICE_DATA *Udp4Service;\r
+\r
+ //\r
+ // Allocate Private Context Data Structure.\r
+ //\r
+ Udp4Service = NetAllocatePool (sizeof (UDP4_SERVICE_DATA));\r
+ if (Udp4Service == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = Udp4CreateService (Udp4Service, This->DriverBindingHandle, ControllerHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_SERVICE;\r
+ }\r
+\r
+ //\r
+ // Install the Udp4ServiceBindingProtocol on the ControllerHandle.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ControllerHandle,\r
+ &gEfiUdp4ServiceBindingProtocolGuid,\r
+ &Udp4Service->ServiceBinding,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto CLEAN_SERVICE;\r
+ }\r
+\r
+ Udp4SetVariableData (Udp4Service);\r
+\r
+ return Status;\r
+\r
+CLEAN_SERVICE:\r
+\r
+ Udp4CleanService (Udp4Service);\r
+\r
+FREE_SERVICE:\r
+\r
+ NetFreePool (Udp4Service);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop this driver on ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to stop driver on\r
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number\r
+ of children is zero stop the entire bus driver.\r
+ @param ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+ @retval EFI_SUCCES This driver is removed ControllerHandle.\r
+ @retval other This driver was not removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4DriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE NicHandle;\r
+ EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
+ UDP4_SERVICE_DATA *Udp4Service;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+\r
+ //\r
+ // Find the NicHandle where UDP4 ServiceBinding Protocol is installed.\r
+ //\r
+ NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGuid);\r
+ if (NicHandle == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Retrieve the UDP4 ServiceBinding Protocol.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ NicHandle,\r
+ &gEfiUdp4ServiceBindingProtocolGuid,\r
+ (VOID **) &ServiceBinding,\r
+ This->DriverBindingHandle,\r
+ NicHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (ServiceBinding);\r
+\r
+ //\r
+ // Uninstall the UDP4 ServiceBinding Protocol.\r
+ //\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ NicHandle,\r
+ &gEfiUdp4ServiceBindingProtocolGuid,\r
+ &Udp4Service->ServiceBinding,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ while (!NetListIsEmpty (&Udp4Service->ChildrenList)) {\r
+ //\r
+ // Destroy all instances.\r
+ //\r
+ Instance = NET_LIST_HEAD (&Udp4Service->ChildrenList, UDP4_INSTANCE_DATA, Link);\r
+\r
+ ServiceBinding->DestroyChild (ServiceBinding, Instance->ChildHandle);\r
+ }\r
+\r
+ Udp4ClearVariableData (Udp4Service);\r
+\r
+ Udp4CleanService (Udp4Service);\r
+\r
+ NetFreePool (Udp4Service);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Creates a child handle with a set of I/O services.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ChildHandle Pointer to the handle of the child to create. If\r
+ it is NULL, then a new handle is created. If it\r
+ is not NULL, then the I/O services are added to\r
+ the existing child handle.\r
+\r
+ @retval EFI_SUCCES The child handle was created with the I/O services\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
+ the child\r
+ @retval other The child handle was not created\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4ServiceBindingCreateChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE *ChildHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UDP4_SERVICE_DATA *Udp4Service;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_TPL OldTpl;\r
+ VOID *Ip4;\r
+\r
+ if ((This == NULL) || (ChildHandle == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Allocate the instance private data structure.\r
+ //\r
+ Instance = NetAllocatePool (sizeof (UDP4_INSTANCE_DATA));\r
+ if (Instance == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Udp4InitInstance (Udp4Service, Instance);\r
+\r
+ //\r
+ // Add an IpInfo for this instance.\r
+ //\r
+ Instance->IpInfo = IpIoAddIp (Udp4Service->IpIo);\r
+ if (Instance->IpInfo == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FREE_INSTANCE;\r
+ }\r
+\r
+ //\r
+ // Install the Udp4Protocol for this instance.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ ChildHandle,\r
+ &gEfiUdp4ProtocolGuid,\r
+ &Instance->Udp4Proto,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto REMOVE_IPINFO;\r
+ }\r
+\r
+ Instance->ChildHandle = *ChildHandle;\r
+\r
+ //\r
+ // Open the default Ip4 protocol in the IP_IO BY_CHILD.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Udp4Service->IpIo->ChildHandle,\r
+ &gEfiIp4ProtocolGuid,\r
+ (VOID **) &Ip4,\r
+ gUdp4DriverBinding.DriverBindingHandle,\r
+ Instance->ChildHandle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto UNINSTALL_PROTOCOL;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ //\r
+ // Link this instance into the service context data and increase the ChildrenNumber.\r
+ //\r
+ NetListInsertTail (&Udp4Service->ChildrenList, &Instance->Link);\r
+ Udp4Service->ChildrenNumber++;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+\r
+UNINSTALL_PROTOCOL:\r
+\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ Instance->ChildHandle,\r
+ &gEfiUdp4ProtocolGuid,\r
+ &Instance->Udp4Proto,\r
+ NULL\r
+ );\r
+\r
+REMOVE_IPINFO:\r
+\r
+ IpIoRemoveIp (Udp4Service->IpIo, Instance->IpInfo);\r
+\r
+FREE_INSTANCE:\r
+\r
+ Udp4CleanInstance (Instance);\r
+\r
+ NetFreePool (Instance);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Destroys a child handle with a set of I/O services.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ChildHandle Handle of the child to destroy\r
+\r
+ @retval EFI_SUCCES The I/O services were removed from the child\r
+ handle\r
+ @retval EFI_UNSUPPORTED The child handle does not support the I/O services\r
+ that are being removed\r
+ @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.\r
+ @retval EFI_ACCESS_DENIED The child handle could not be destroyed because\r
+ its I/O services are being used.\r
+ @retval other The child handle was not destroyed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4ServiceBindingDestroyChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ChildHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UDP4_SERVICE_DATA *Udp4Service;\r
+ EFI_UDP4_PROTOCOL *Udp4Proto;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((This == NULL) || (ChildHandle == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Udp4Service = UDP4_SERVICE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Try to get the Udp4 protocol from the ChildHandle.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiUdp4ProtocolGuid,\r
+ (VOID **) &Udp4Proto,\r
+ gUdp4DriverBinding.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Instance = UDP4_INSTANCE_DATA_FROM_THIS (Udp4Proto);\r
+\r
+ if (Instance->Destroyed) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Use the Destroyed flag to avoid the re-entering of the following code.\r
+ //\r
+ Instance->Destroyed = TRUE;\r
+\r
+ //\r
+ // Close the Ip4 protocol.\r
+ //\r
+ gBS->CloseProtocol (\r
+ Udp4Service->IpIo->ChildHandle,\r
+ &gEfiIp4ProtocolGuid,\r
+ gUdp4DriverBinding.DriverBindingHandle,\r
+ Instance->ChildHandle\r
+ );\r
+\r
+ //\r
+ // Uninstall the Udp4Protocol previously installed on the ChildHandle.\r
+ //\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandle,\r
+ &gEfiUdp4ProtocolGuid,\r
+ (VOID *) &Instance->Udp4Proto,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Instance->Destroyed = FALSE;\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Reset the configuration in case the instance's consumer forgets to do this.\r
+ //\r
+ Udp4Proto->Configure (Udp4Proto, NULL);\r
+\r
+ //\r
+ // Remove the IpInfo this instance consumes.\r
+ //\r
+ IpIoRemoveIp (Udp4Service->IpIo, Instance->IpInfo);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ //\r
+ // Remove this instance from the service context data's ChildrenList.\r
+ //\r
+ NetListRemoveEntry (&Instance->Link);\r
+ Udp4Service->ChildrenNumber--;\r
+\r
+ //\r
+ // Clean the instance.\r
+ //\r
+ Udp4CleanInstance (Instance);\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ NetFreePool (Instance);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (Udp4DriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4DriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The entry point for Udp4 driver which installs the driver binding\r
+ and component name protocol on its ImageHandle.\r
+\r
+Arguments:\r
+\r
+ ImageHandle - The image handle of the driver.\r
+ SystemTable - The system table.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - if the driver binding and component name protocols are\r
+ successfully installed, otherwise if failed.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Install the Udp4DriverBinding and Udp4ComponentName protocols.\r
+ //\r
+ Status = NetLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gUdp4DriverBinding,\r
+ ImageHandle,\r
+ &gUdp4ComponentName,\r
+ NULL,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Initialize the UDP random port.\r
+ //\r
+ mUdp4RandomPort = ((UINT16) NetRandomInitSeed ()) % UDP4_PORT_KNOWN + UDP4_PORT_KNOWN;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file
+
+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:
+
+ Udp4Driver.h
+
+Abstract:
+
+
+**/
+
+#ifndef _UDP4_DRIVER_H_
+#define _UDP4_DRIVER_H_
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/NetLib.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ServiceBinding.h>
+
+EFI_STATUS
+EFIAPI
+Udp4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4ServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE *ChildHandle
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4ServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ );
+
+#endif
+
--- /dev/null
+#/** @file\r
+# Component name for module Udp4\r
+#\r
+# FIX ME!\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+# All rights reserved. This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = Udp4\r
+ FILE_GUID = 6d6963ab-906d-4a65-a7ca-bd40e5d6af2b\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ EDK_RELEASE_VERSION = 0x00020000\r
+ EFI_SPECIFICATION_VERSION = 0x00020000\r
+\r
+ ENTRY_POINT = Udp4DriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+ Udp4Impl.h\r
+ Udp4Main.c\r
+ ComponentName.c\r
+ Udp4Impl.c\r
+ Udp4Driver.h\r
+ Udp4Driver.c\r
+ CommonHeader.h\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ UefiLib\r
+ BaseLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ UefiRuntimeServicesTableLib\r
+ DebugLib\r
+ IpIoLib\r
+ NetLib\r
+\r
+\r
+[Protocols]\r
+ gEfiIp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiUdp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiIp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+\r
--- /dev/null
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+ <MsaHeader>\r
+ <ModuleName>Udp4</ModuleName>\r
+ <ModuleType>DXE_DRIVER</ModuleType>\r
+ <GuidValue>6d6963ab-906d-4a65-a7ca-bd40e5d6af2b</GuidValue>\r
+ <Version>1.0</Version>\r
+ <Abstract>Component name for module Udp4</Abstract>\r
+ <Description>FIX ME!</Description>\r
+ <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+ <License>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.</License>\r
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>\r
+ </MsaHeader>\r
+ <ModuleDefinitions>\r
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+ <BinaryModule>false</BinaryModule>\r
+ <OutputFileBasename>Udp4</OutputFileBasename>\r
+ </ModuleDefinitions>\r
+ <LibraryClassDefinitions>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>DebugLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiDriverEntryPoint</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiBootServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>BaseLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiLib</Keyword>\r
+ </LibraryClass>\r
+ </LibraryClassDefinitions>\r
+ <SourceFiles>\r
+ <Filename>Udp4Driver.c</Filename>\r
+ <Filename>Udp4Driver.h</Filename>\r
+ <Filename>Udp4Impl.c</Filename>\r
+ <Filename>ComponentName.c</Filename>\r
+ <Filename>Udp4Main.c</Filename>\r
+ <Filename>Udp4Impl.h</Filename>\r
+ </SourceFiles>\r
+ <PackageDependencies>\r
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+ </PackageDependencies>\r
+ <Protocols>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiUdp4ProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiIp4ServiceBindingProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiUdp4ServiceBindingProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiIp4ProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ </Protocols>\r
+ <Externs>\r
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+ <Extern>\r
+ <ModuleEntryPoint>Udp4DriverEntryPoint</ModuleEntryPoint>\r
+ </Extern>\r
+ </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Udp4Impl.c\r
+\r
+Abstract:\r
+\r
+ The implementation of the Udp4 protocol.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Udp4Impl.h"\r
+\r
+UINT16 mUdp4RandomPort;\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Udp4CheckTimeout (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+STATIC\r
+BOOLEAN\r
+Udp4FindInstanceByPort (\r
+ IN NET_LIST_ENTRY *InstanceList,\r
+ IN EFI_IPv4_ADDRESS *Address,\r
+ IN UINT16 Port\r
+ );\r
+\r
+STATIC\r
+VOID\r
+Udp4DgramSent (\r
+ IN EFI_STATUS Status,\r
+ IN VOID *Context,\r
+ IN VOID *Sender,\r
+ IN VOID *NotifyData\r
+ );\r
+\r
+STATIC\r
+VOID\r
+Udp4DgramRcvd (\r
+ IN EFI_STATUS Status,\r
+ IN ICMP_ERROR IcmpError,\r
+ IN EFI_NET_SESSION_DATA *NetSession,\r
+ IN NET_BUF *Packet,\r
+ IN VOID *Context\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+Udp4CancelTokens (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Arg OPTIONAL\r
+ );\r
+\r
+STATIC\r
+BOOLEAN\r
+Udp4MatchDgram (\r
+ IN UDP4_INSTANCE_DATA *Instance,\r
+ IN EFI_UDP4_SESSION_DATA *Udp4Session\r
+ );\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Udp4RecycleRxDataWrap (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+STATIC\r
+UDP4_RXDATA_WRAP *\r
+Udp4WrapRxData (\r
+ IN UDP4_INSTANCE_DATA *Instance,\r
+ IN NET_BUF *Packet,\r
+ IN EFI_UDP4_RECEIVE_DATA *RxData\r
+ );\r
+\r
+STATIC\r
+UINTN\r
+Udp4EnqueueDgram (\r
+ IN UDP4_SERVICE_DATA *Udp4Service,\r
+ IN NET_BUF *Packet,\r
+ IN EFI_UDP4_RECEIVE_DATA *RxData\r
+ );\r
+\r
+STATIC\r
+VOID\r
+Udp4DeliverDgram (\r
+ IN UDP4_SERVICE_DATA *Udp4Service\r
+ );\r
+\r
+STATIC\r
+VOID\r
+Udp4Demultiplex (\r
+ IN UDP4_SERVICE_DATA *Udp4Service,\r
+ IN EFI_NET_SESSION_DATA *NetSession,\r
+ IN NET_BUF *Packet\r
+ );\r
+\r
+STATIC\r
+VOID\r
+Udp4IcmpHandler (\r
+ IN UDP4_SERVICE_DATA *Udp4Service,\r
+ IN ICMP_ERROR IcmpError,\r
+ IN EFI_NET_SESSION_DATA *NetSession,\r
+ IN NET_BUF *Packet\r
+ );\r
+\r
+STATIC\r
+VOID\r
+Udp4SendPortUnreach (\r
+ IN IP_IO *IpIo,\r
+ IN EFI_NET_SESSION_DATA *NetSession,\r
+ IN VOID *Udp4Header\r
+ );\r
+\r
+\r
+/**\r
+ Create the Udp service context data.\r
+\r
+ @param Udp4Service Pointer to the UDP4_SERVICE_DATA.\r
+ @param ImageHandle The image handle of this udp4 driver.\r
+ @param ControllerHandle The controller handle this udp4 driver binds on.\r
+\r
+ @retval EFI_SUCCESS The udp4 service context data is created and\r
+ initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate memory.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4CreateService (\r
+ IN UDP4_SERVICE_DATA *Udp4Service,\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_HANDLE ControllerHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ IP_IO_OPEN_DATA OpenData;\r
+\r
+ Udp4Service->Signature = UDP4_SERVICE_DATA_SIGNATURE;\r
+ Udp4Service->ServiceBinding = mUdp4ServiceBinding;\r
+ Udp4Service->ImageHandle = ImageHandle;\r
+ Udp4Service->ControllerHandle = ControllerHandle;\r
+ Udp4Service->ChildrenNumber = 0;\r
+\r
+ NetListInit (&Udp4Service->ChildrenList);\r
+\r
+ //\r
+ // Create the IpIo for this service context.\r
+ //\r
+ Udp4Service->IpIo = IpIoCreate (ImageHandle, ControllerHandle);\r
+ if (Udp4Service->IpIo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Set the OpenData used to open the IpIo.\r
+ //\r
+ OpenData.IpConfigData = mIpIoDefaultIpConfigData;\r
+ OpenData.IpConfigData.AcceptBroadcast = TRUE;\r
+ OpenData.RcvdContext = (VOID *) Udp4Service;\r
+ OpenData.SndContext = NULL;\r
+ OpenData.PktRcvdNotify = Udp4DgramRcvd;\r
+ OpenData.PktSentNotify = Udp4DgramSent;\r
+\r
+ //\r
+ // Configure and start the IpIo.\r
+ //\r
+ Status = IpIoOpen (Udp4Service->IpIo, &OpenData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto RELEASE_IPIO;\r
+ }\r
+\r
+ //\r
+ // Create the event for Udp timeout checking.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ NET_TPL_FAST_TIMER,\r
+ Udp4CheckTimeout,\r
+ Udp4Service,\r
+ &Udp4Service->TimeoutEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto RELEASE_IPIO;\r
+ }\r
+\r
+ //\r
+ // Start the timeout timer event.\r
+ //\r
+ Status = gBS->SetTimer (\r
+ Udp4Service->TimeoutEvent,\r
+ TimerPeriodic,\r
+ UDP4_TIMEOUT_INTERVAL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto RELEASE_ALL;\r
+ }\r
+\r
+ Udp4Service->MacString = NULL;\r
+\r
+ return EFI_SUCCESS;\r
+\r
+RELEASE_ALL:\r
+\r
+ gBS->CloseEvent (Udp4Service->TimeoutEvent);\r
+\r
+RELEASE_IPIO:\r
+\r
+ IpIoDestroy (Udp4Service->IpIo);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Clean the Udp service context data.\r
+\r
+ @param Udp4Service Pointer to the UDP4_SERVICE_DATA.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+Udp4CleanService (\r
+ IN UDP4_SERVICE_DATA *Udp4Service\r
+ )\r
+{\r
+ //\r
+ // Cancel the TimeoutEvent timer.\r
+ //\r
+ gBS->SetTimer (Udp4Service->TimeoutEvent, TimerCancel, 0);\r
+\r
+ //\r
+ // Close the TimeoutEvent timer.\r
+ //\r
+ gBS->CloseEvent (Udp4Service->TimeoutEvent);\r
+\r
+ //\r
+ // Destroy the IpIo.\r
+ //\r
+ IpIoDestroy (Udp4Service->IpIo);\r
+}\r
+\r
+\r
+/**\r
+ This function checks and timeouts the I/O datagrams holding by the corresponding\r
+ service context.\r
+\r
+ @param Event The event this function registered to.\r
+ @param Conext The context data registered during the creation of\r
+ the Event.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Udp4CheckTimeout (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ UDP4_SERVICE_DATA *Udp4Service;\r
+ NET_LIST_ENTRY *Entry;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ NET_LIST_ENTRY *WrapEntry;\r
+ NET_LIST_ENTRY *NextEntry;\r
+ UDP4_RXDATA_WRAP *Wrap;\r
+\r
+ Udp4Service = (UDP4_SERVICE_DATA *) Context;\r
+ NET_CHECK_SIGNATURE (Udp4Service, UDP4_SERVICE_DATA_SIGNATURE);\r
+\r
+ NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+ //\r
+ // Iterate all the instances belonging to this service context.\r
+ //\r
+ Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);\r
+ NET_CHECK_SIGNATURE (Instance, UDP4_INSTANCE_DATA_SIGNATURE);\r
+\r
+ if (!Instance->Configured || (Instance->ConfigData.ReceiveTimeout == 0)) {\r
+ //\r
+ // Skip this instance if it's not configured or no receive timeout.\r
+ //\r
+ continue;\r
+ }\r
+\r
+ NET_LIST_FOR_EACH_SAFE (WrapEntry, NextEntry, &Instance->RcvdDgramQue) {\r
+ //\r
+ // Iterate all the rxdatas belonging to this udp instance.\r
+ //\r
+ Wrap = NET_LIST_USER_STRUCT (Entry, UDP4_RXDATA_WRAP, Link);\r
+\r
+ if (Wrap->TimeoutTick <= UDP4_TIMEOUT_INTERVAL / 1000) {\r
+ //\r
+ // Remove this RxData if it timeouts.\r
+ //\r
+ Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap);\r
+ } else {\r
+ Wrap->TimeoutTick -= UDP4_TIMEOUT_INTERVAL / 1000;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function intializes the new created udp instance.\r
+\r
+ @param Udp4Service Pointer to the UDP4_SERVICE_DATA.\r
+ @param Instance Pointer to the un-initialized UDP4_INSTANCE_DATA.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+Udp4InitInstance (\r
+ IN UDP4_SERVICE_DATA *Udp4Service,\r
+ IN UDP4_INSTANCE_DATA *Instance\r
+ )\r
+{\r
+ //\r
+ // Set the signature.\r
+ //\r
+ Instance->Signature = UDP4_INSTANCE_DATA_SIGNATURE;\r
+\r
+ //\r
+ // Init the lists.\r
+ //\r
+ NetListInit (&Instance->Link);\r
+ NetListInit (&Instance->RcvdDgramQue);\r
+ NetListInit (&Instance->DeliveredDgramQue);\r
+\r
+ //\r
+ // Init the NET_MAPs.\r
+ //\r
+ NetMapInit (&Instance->TxTokens);\r
+ NetMapInit (&Instance->RxTokens);\r
+ NetMapInit (&Instance->McastIps);\r
+\r
+ //\r
+ // Save the pointer to the UDP4_SERVICE_DATA, and initialize other members.\r
+ //\r
+ Instance->Udp4Service = Udp4Service;\r
+ Instance->Udp4Proto = mUdp4Protocol;\r
+ Instance->IcmpError = EFI_SUCCESS;\r
+ Instance->Configured = FALSE;\r
+ Instance->IsNoMapping = FALSE;\r
+ Instance->Destroyed = FALSE;\r
+}\r
+\r
+\r
+/**\r
+ This function cleans the udp instance.\r
+\r
+ @param Instance Pointer to the UDP4_INSTANCE_DATA to clean.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+Udp4CleanInstance (\r
+ IN UDP4_INSTANCE_DATA *Instance\r
+ )\r
+{\r
+ NetMapClean (&Instance->McastIps);\r
+ NetMapClean (&Instance->RxTokens);\r
+ NetMapClean (&Instance->TxTokens);\r
+}\r
+\r
+\r
+/**\r
+ This function finds the udp instance by the specified <Address, Port> pair.\r
+\r
+ @param InstanceList Pointer to the head of the list linking the udp\r
+ instances.\r
+ @param Address Pointer to the specified IPv4 address.\r
+ @param Port The udp port number.\r
+\r
+ @return Is the specified <Address, Port> pair found or not.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+Udp4FindInstanceByPort (\r
+ IN NET_LIST_ENTRY *InstanceList,\r
+ IN EFI_IPv4_ADDRESS *Address,\r
+ IN UINT16 Port\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_UDP4_CONFIG_DATA *ConfigData;\r
+\r
+ NET_LIST_FOR_EACH (Entry, InstanceList) {\r
+ //\r
+ // Iterate all the udp instances.\r
+ //\r
+ Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);\r
+ ConfigData = &Instance->ConfigData;\r
+\r
+ if (!Instance->Configured || ConfigData->AcceptAnyPort) {\r
+ //\r
+ // If the instance is not configured or the configdata of the instance indicates\r
+ // this instance accepts any port, skip it.\r
+ //\r
+ continue;\r
+ }\r
+\r
+ if (EFI_IP_EQUAL (ConfigData->StationAddress, *Address) &&\r
+ (ConfigData->StationPort == Port)) {\r
+ //\r
+ // if both the address and the port are the same, return TRUE.\r
+ //\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // return FALSE when matching fails.\r
+ //\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ This function tries to bind the udp instance according to the configured port\r
+ allocation stragety.\r
+\r
+ @param InstanceList Pointer to the head of the list linking the udp\r
+ instances.\r
+ @param ConfigData Pointer to the ConfigData of the instance to be\r
+ bound.\r
+\r
+ @retval EFI_SUCCESS The bound operation is completed successfully.\r
+ @retval EFI_ACCESS_DENIED The <Address, Port> specified by the ConfigData is\r
+ already used by other instance.\r
+ @retval EFI_OUT_OF_RESOURCES No available port resources.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4Bind (\r
+ IN NET_LIST_ENTRY *InstanceList,\r
+ IN EFI_UDP4_CONFIG_DATA *ConfigData\r
+ )\r
+{\r
+ EFI_IPv4_ADDRESS *StationAddress;\r
+ UINT16 StartPort;\r
+\r
+ if (ConfigData->AcceptAnyPort) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ StationAddress = &ConfigData->StationAddress;\r
+\r
+ if (ConfigData->StationPort != 0) {\r
+\r
+ if (!ConfigData->AllowDuplicatePort &&\r
+ Udp4FindInstanceByPort (InstanceList, StationAddress, ConfigData->StationPort)) {\r
+ //\r
+ // Do not allow duplicate port and the port is already used by other instance.\r
+ //\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ } else {\r
+ //\r
+ // select a random port for this instance;\r
+ //\r
+\r
+ if (ConfigData->AllowDuplicatePort) {\r
+ //\r
+ // Just pick up the random port if the instance allows duplicate port.\r
+ //\r
+ ConfigData->StationPort = mUdp4RandomPort;\r
+ } else {\r
+\r
+ StartPort = mUdp4RandomPort;\r
+\r
+ while (Udp4FindInstanceByPort(InstanceList, StationAddress, mUdp4RandomPort)) {\r
+\r
+ mUdp4RandomPort++;\r
+ if (mUdp4RandomPort == 0) {\r
+ mUdp4RandomPort = UDP4_PORT_KNOWN;\r
+ }\r
+\r
+ if (mUdp4RandomPort == StartPort) {\r
+ //\r
+ // No available port.\r
+ //\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+ ConfigData->StationPort = mUdp4RandomPort;\r
+ }\r
+\r
+ mUdp4RandomPort++;\r
+ if (mUdp4RandomPort == 0) {\r
+ mUdp4RandomPort = UDP4_PORT_KNOWN;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function is used to check whether the NewConfigData has any un-reconfigurable\r
+ parameters changed compared to the OldConfigData.\r
+\r
+ @param OldConfigData Pointer to the current ConfigData the udp instance\r
+ uses.\r
+ @param NewConfigData Pointer to the new ConfigData.\r
+\r
+ @return The instance is reconfigurable or not according to the NewConfigData.\r
+\r
+**/\r
+BOOLEAN\r
+Udp4IsReconfigurable (\r
+ IN EFI_UDP4_CONFIG_DATA *OldConfigData,\r
+ IN EFI_UDP4_CONFIG_DATA *NewConfigData\r
+ )\r
+{\r
+ if ((NewConfigData->AcceptAnyPort != OldConfigData->AcceptAnyPort) ||\r
+ (NewConfigData->AcceptBroadcast != OldConfigData->AcceptBroadcast) ||\r
+ (NewConfigData->AcceptPromiscuous != OldConfigData->AcceptPromiscuous) ||\r
+ (NewConfigData->AllowDuplicatePort != OldConfigData->AllowDuplicatePort)) {\r
+ //\r
+ // The receiving filter parameters cannot be changed.\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ if ((!NewConfigData->AcceptAnyPort) &&\r
+ (NewConfigData->StationPort != OldConfigData->StationPort)) {\r
+ //\r
+ // The port is not changeable.\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ if (!NewConfigData->AcceptPromiscuous) {\r
+\r
+ if (NewConfigData->UseDefaultAddress != OldConfigData->UseDefaultAddress) {\r
+ //\r
+ // The NewConfigData differs to the old one on the UseDefaultAddress.\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ if (!NewConfigData->UseDefaultAddress &&\r
+ (!EFI_IP_EQUAL (NewConfigData->StationAddress, OldConfigData->StationAddress) ||\r
+ !EFI_IP_EQUAL (NewConfigData->SubnetMask, OldConfigData->SubnetMask))) {\r
+ //\r
+ // If the instance doesn't use the default address, and the new address or\r
+ // new subnet mask is different from the old values.\r
+ //\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ if (!EFI_IP_EQUAL (NewConfigData->RemoteAddress, OldConfigData->RemoteAddress)) {\r
+ //\r
+ // The remoteaddress is not the same.\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ if ((EFI_IP4 (NewConfigData->RemoteAddress) != 0) &&\r
+ (NewConfigData->RemotePort != OldConfigData->RemotePort)) {\r
+ //\r
+ // The RemotePort differs if it's designated in the configdata.\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // All checks pass, return TRUE.\r
+ //\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ This function builds the Ip4 configdata from the Udp4ConfigData.\r
+\r
+ @param Udp4ConfigData Pointer to the EFI_UDP4_CONFIG_DATA.\r
+ @param Ip4ConfigData Pointer to the EFI_IP4_CONFIG_DATA.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+Udp4BuildIp4ConfigData (\r
+ IN EFI_UDP4_CONFIG_DATA *Udp4ConfigData,\r
+ IN EFI_IP4_CONFIG_DATA *Ip4ConfigData\r
+ )\r
+{\r
+ *Ip4ConfigData = mIpIoDefaultIpConfigData;\r
+ Ip4ConfigData->DefaultProtocol = EFI_IP_PROTO_UDP;\r
+ Ip4ConfigData->AcceptBroadcast = Udp4ConfigData->AcceptBroadcast;\r
+ Ip4ConfigData->AcceptPromiscuous = Udp4ConfigData->AcceptPromiscuous;\r
+ Ip4ConfigData->UseDefaultAddress = Udp4ConfigData->UseDefaultAddress;\r
+ Ip4ConfigData->StationAddress = Udp4ConfigData->StationAddress;\r
+ Ip4ConfigData->SubnetMask = Udp4ConfigData->SubnetMask;\r
+\r
+ //\r
+ // use the -1 magic number to disable the receiving process of the ip instance.\r
+ //\r
+ Ip4ConfigData->ReceiveTimeout = (UINT32) (-1);\r
+}\r
+\r
+\r
+/**\r
+ This function validates the TxToken, it returns the error code according to the spec.\r
+\r
+ @param Instance Pointer to the udp instance context data.\r
+ @param TxToken Pointer to the token to be checked.\r
+\r
+ @retval EFI_SUCCESS The TxToken is valid.\r
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: This is\r
+ NULL. Token is NULL. Token.Event is NULL.\r
+ Token.Packet.TxData is NULL.\r
+ Token.Packet.TxData.FragmentCount is zero.\r
+ Token.Packet.TxData.DataLength is not equal to the\r
+ sum of fragment lengths. One or more of the\r
+ Token.Packet.TxData.FragmentTable[].\r
+ FragmentLength fields is zero. One or more of the\r
+ Token.Packet.TxData.FragmentTable[].\r
+ FragmentBuffer fields is NULL.\r
+ Token.Packet.TxData. GatewayAddress is not a\r
+ unicast IPv4 address if it is not NULL. One or\r
+ more IPv4 addresses in Token.Packet.TxData.\r
+ UdpSessionData are not valid unicast IPv4\r
+ addresses if the UdpSessionData is not NULL.\r
+ @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP\r
+ packet size.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4ValidateTxToken (\r
+ IN UDP4_INSTANCE_DATA *Instance,\r
+ IN EFI_UDP4_COMPLETION_TOKEN *TxToken\r
+ )\r
+{\r
+ EFI_UDP4_TRANSMIT_DATA *TxData;\r
+ UINT32 Index;\r
+ UINT32 TotalLen;\r
+ EFI_UDP4_CONFIG_DATA *ConfigData;\r
+ EFI_UDP4_SESSION_DATA *UdpSessionData;\r
+ IP4_ADDR SourceAddress;\r
+\r
+ if (TxToken->Event == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ TxData = TxToken->Packet.TxData;\r
+\r
+ if ((TxData == NULL) || (TxData->FragmentCount == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ TotalLen = 0;\r
+ for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
+\r
+ if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||\r
+ (TxData->FragmentTable[Index].FragmentLength == 0)) {\r
+ //\r
+ // if the FragmentBuffer is NULL or the FragmentLeng is zero.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ TotalLen += TxData->FragmentTable[Index].FragmentLength;\r
+ }\r
+\r
+ if (TotalLen != TxData->DataLength) {\r
+ //\r
+ // The TotalLen calculated by adding all the FragmentLeng doesn't equal to the\r
+ // DataLength.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TxData->GatewayAddress != NULL) &&\r
+ !Ip4IsUnicast(EFI_NTOHL (*(TxData->GatewayAddress)), 0)) {\r
+ //\r
+ // The specified GatewayAddress is not a unicast IPv4 address while it's not 0.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ConfigData = &Instance->ConfigData;\r
+ UdpSessionData = TxData->UdpSessionData;\r
+\r
+ if (UdpSessionData != NULL) {\r
+\r
+ SourceAddress = EFI_NTOHL (UdpSessionData->SourceAddress);\r
+\r
+ if ((SourceAddress != 0) && !Ip4IsUnicast (SourceAddress, 0)) {\r
+ //\r
+ // Check whether SourceAddress is a valid IPv4 address in case it's not zero.\r
+ // The configured station address is used if SourceAddress is zero.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((UdpSessionData->DestinationPort == 0) && (ConfigData->RemotePort == 0)) {\r
+ //\r
+ // Ambiguous, no avalaible DestinationPort for this token.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (EFI_IP4 (UdpSessionData->DestinationAddress) == 0) {\r
+ //\r
+ // The DestinationAddress specified in the UdpSessionData is 0.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else if (EFI_IP4 (ConfigData->RemoteAddress) == 0) {\r
+ //\r
+ // the configured RemoteAddress is all zero, and the user doens't override the\r
+ // destination address.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (TxData->DataLength > UDP4_MAX_DATA_SIZE) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function checks whether the specified Token duplicates with the one in the Map.\r
+\r
+ @param Map Pointer to the NET_MAP.\r
+ @param Item Pointer to the NET_MAP_ITEM contain the pointer to\r
+ the Token.\r
+ @param Context Pointer to the Token to be checked.\r
+\r
+ @retval EFI_SUCCESS The Token specified by Context differs from the\r
+ one in the Item.\r
+ @retval EFI_ACCESS_DENIED The Token duplicates with the one in the Item.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4TokenExist (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_UDP4_COMPLETION_TOKEN *Token;\r
+ EFI_UDP4_COMPLETION_TOKEN *TokenInItem;\r
+\r
+ Token = (EFI_UDP4_COMPLETION_TOKEN*) Context;\r
+ TokenInItem = (EFI_UDP4_COMPLETION_TOKEN*) Item->Key;\r
+\r
+ if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {\r
+ //\r
+ // The Token duplicates with the TokenInItem in case either the two pointers are the\r
+ // same or the Events of these two tokens are the same.\r
+ //\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function calculates the checksum for the Packet, utilizing the pre-calculated\r
+ pseudo HeadSum to reduce some overhead.\r
+\r
+ @param Packet Pointer to the NET_BUF contains the udp datagram.\r
+ @param HeadSum Checksum of the pseudo header execpt the length\r
+ field.\r
+\r
+ @return The 16-bit checksum of this udp datagram.\r
+\r
+**/\r
+UINT16\r
+Udp4Checksum (\r
+ IN NET_BUF *Packet,\r
+ IN UINT16 HeadSum\r
+ )\r
+{\r
+ UINT16 Checksum;\r
+\r
+ Checksum = NetbufChecksum (Packet);\r
+ Checksum = NetAddChecksum (Checksum, HeadSum);\r
+\r
+ Checksum = NetAddChecksum (Checksum, HTONS ((UINT16) Packet->TotalSize));\r
+\r
+ return ~Checksum;\r
+}\r
+\r
+\r
+/**\r
+ This function removes the specified Token from the TokenMap.\r
+\r
+ @param TokenMap Pointer to the NET_MAP containing the tokens.\r
+ @param Token Pointer to the Token to be removed.\r
+\r
+ @retval EFI_SUCCESS The specified Token is removed from the TokenMap.\r
+ @retval EFI_NOT_FOUND The specified Token is not found in the TokenMap.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4RemoveToken (\r
+ IN NET_MAP *TokenMap,\r
+ IN EFI_UDP4_COMPLETION_TOKEN *Token\r
+ )\r
+{\r
+ NET_MAP_ITEM *Item;\r
+\r
+ //\r
+ // Find the Token first.\r
+ //\r
+ Item = NetMapFindKey (TokenMap, (VOID *) Token);\r
+\r
+ if (Item != NULL) {\r
+ //\r
+ // Remove the token if it's found in the map.\r
+ //\r
+ NetMapRemoveItem (TokenMap, Item, NULL);\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ This function is the packet transmitting notify function registered to the IpIo\r
+ interface. It's called to signal the udp TxToken when IpIo layer completes the\r
+ transmitting of the udp datagram.\r
+\r
+ @param Status The completion status of the output udp datagram.\r
+ @param Context Pointer to the context data.\r
+ @param Sender Pointer to the Ip sender of the udp datagram.\r
+ @param NotifyData Pointer to the notify data.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4DgramSent (\r
+ IN EFI_STATUS Status,\r
+ IN VOID *Context,\r
+ IN VOID *Sender,\r
+ IN VOID *NotifyData\r
+ )\r
+{\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_UDP4_COMPLETION_TOKEN *Token;\r
+\r
+ Instance = (UDP4_INSTANCE_DATA *) Context;\r
+ Token = (EFI_UDP4_COMPLETION_TOKEN *) NotifyData;\r
+\r
+ if (Udp4RemoveToken (&Instance->TxTokens, Token) == EFI_SUCCESS) {\r
+ //\r
+ // The token may be cancelled. Only signal it if the remove operation succeeds.\r
+ //\r
+ Token->Status = Status;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function processes the received datagram passed up by the IpIo layer.\r
+\r
+ @param Status The status of this udp datagram.\r
+ @param IcmpError The IcmpError code, only available when Status is\r
+ EFI_ICMP_ERROR.\r
+ @param NetSession Pointer to the EFI_NET_SESSION_DATA.\r
+ @param Packet Pointer to the NET_BUF containing the received udp\r
+ datagram.\r
+ @param Context Pointer to the context data.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4DgramRcvd (\r
+ IN EFI_STATUS Status,\r
+ IN ICMP_ERROR IcmpError,\r
+ IN EFI_NET_SESSION_DATA *NetSession,\r
+ IN NET_BUF *Packet,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE);\r
+\r
+ //\r
+ // IpIo only passes received packets with Status EFI_SUCCESS or EFI_ICMP_ERROR.\r
+ //\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // Demultiplex the received datagram.\r
+ //\r
+ Udp4Demultiplex ((UDP4_SERVICE_DATA *) Context, NetSession, Packet);\r
+ } else {\r
+ //\r
+ // Handle the ICMP_ERROR packet.\r
+ //\r
+ Udp4IcmpHandler ((UDP4_SERVICE_DATA *) Context, IcmpError, NetSession, Packet);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function removes the multicast group specified by Arg from the Map.\r
+\r
+ @param Map Pointer to the NET_MAP.\r
+ @param Item Pointer to the NET_MAP_ITEM.\r
+ @param Arg Pointer to the Arg, it's the pointer to a\r
+ multicast IPv4 Address.\r
+\r
+ @retval EFI_SUCCESS The multicast address is removed.\r
+ @retval EFI_ABORTED The specified multicast address is removed and the\r
+ Arg is not NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4LeaveGroup (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Arg OPTIONAL\r
+ )\r
+{\r
+ EFI_IPv4_ADDRESS *McastIp;\r
+\r
+ McastIp = Arg;\r
+\r
+ if ((McastIp != NULL) && ((UINTN) EFI_IP4 (*McastIp) != (UINTN) (Item->Key))) {\r
+ //\r
+ // McastIp is not NULL and the multicast address contained in the Item\r
+ // is not the same as McastIp.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Remove this Item.\r
+ //\r
+ NetMapRemoveItem (Map, Item, NULL);\r
+\r
+ if (McastIp != NULL) {\r
+ //\r
+ // Return EFI_ABORTED in case McastIp is not NULL to terminate the iteration.\r
+ //\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function cancle the token specified by Arg in the Map.\r
+\r
+ @param Map Pointer to the NET_MAP.\r
+ @param Item Pointer to the NET_MAP_ITEM.\r
+ @param Arg Pointer to the token to be cancelled, if NULL, all\r
+ the tokens in this Map will be cancelled.\r
+\r
+ @retval EFI_SUCCESS The token is cancelled if Arg is NULL or the token\r
+ is not the same as that in the Item if Arg is not\r
+ NULL.\r
+ @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is\r
+ cancelled.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Udp4CancelTokens (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Arg OPTIONAL\r
+ )\r
+{\r
+ EFI_UDP4_COMPLETION_TOKEN *TokenToCancel;\r
+ NET_BUF *Packet;\r
+ IP_IO *IpIo;\r
+\r
+ if ((Arg != NULL) && (Item->Key != Arg)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (Item->Value != NULL) {\r
+ //\r
+ // If the token is a transmit token, the corresponding Packet is recorded in\r
+ // Item->Value, invoke IpIo to cancel this packet first. The IpIoCancelTxToken\r
+ // will invoke Udp4DgramSent, the token will be signaled and this Item will\r
+ // be removed from the Map there.\r
+ //\r
+ Packet = (NET_BUF *) (Item->Value);\r
+ IpIo = (IP_IO *) (*((UINTN *) &Packet->ProtoData[0]));\r
+\r
+ IpIoCancelTxToken (IpIo, Packet);\r
+ } else {\r
+ //\r
+ // The token is a receive token. Abort it and remove it from the Map.\r
+ //\r
+ TokenToCancel = (EFI_UDP4_COMPLETION_TOKEN *) Item->Key;\r
+\r
+ TokenToCancel->Status = EFI_ABORTED;\r
+ gBS->SignalEvent (TokenToCancel->Event);\r
+\r
+ NetMapRemoveItem (Map, Item, NULL);\r
+ }\r
+\r
+ if (Arg != NULL) {\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function removes all the Wrap datas in the RcvdDgramQue.\r
+\r
+ @param RcvdDgramQue Pointer to the list containing all the Wrap datas.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+Udp4FlushRxData (\r
+ IN NET_LIST_ENTRY *RcvdDgramQue\r
+ )\r
+{\r
+ UDP4_RXDATA_WRAP *Wrap;\r
+ EFI_TPL OldTpl;\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
+\r
+ while (!NetListIsEmpty (RcvdDgramQue)) {\r
+ //\r
+ // Iterate all the Wraps in the RcvdDgramQue.\r
+ //\r
+ Wrap = NET_LIST_HEAD (RcvdDgramQue, UDP4_RXDATA_WRAP, Link);\r
+\r
+ //\r
+ // The Wrap will be removed from the RcvdDgramQue by this function call.\r
+ //\r
+ Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap);\r
+ }\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+}\r
+\r
+\r
+\r
+/**\r
+\r
+ @param Instance Pointer to the udp instance context data.\r
+ @param Token Pointer to the token to be canceled, if NULL, all\r
+ tokens in this instance will be cancelled.\r
+\r
+ @retval EFI_SUCCESS The Token is cancelled.\r
+ @retval EFI_NOT_FOUND The Token is not found.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4InstanceCancelToken (\r
+ IN UDP4_INSTANCE_DATA *Instance,\r
+ IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Cancle this token from the TxTokens map.\r
+ //\r
+ Status = NetMapIterate (&Instance->TxTokens, Udp4CancelTokens, Token);\r
+\r
+ if ((Token != NULL) && (Status == EFI_ABORTED)) {\r
+ //\r
+ // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from\r
+ // the TxTokens, just return success.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Try to cancel this token from the RxTokens map in condition either the Token\r
+ // is NULL or the specified Token is not in TxTokens.\r
+ //\r
+ Status = NetMapIterate (&Instance->RxTokens, Udp4CancelTokens, Token);\r
+\r
+ if ((Token != NULL) && (Status == EFI_SUCCESS)) {\r
+ //\r
+ // If Token isn't NULL and Status is EFI_SUCCESS, the token is neither in the\r
+ // TxTokens nor the RxTokens, or say, it's not found.\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ ASSERT ((Token != NULL) || ((0 == NetMapGetCount (&Instance->TxTokens))\r
+ && (0 == NetMapGetCount (&Instance->RxTokens))));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function matches the received udp datagram with the Instance.\r
+\r
+ @param Instance Pointer to the udp instance context data.\r
+ @param Udp4Session Pointer to the EFI_UDP4_SESSION_DATA abstracted\r
+ from the received udp datagram.\r
+\r
+ @return The udp datagram matches the receiving requirments of the Instance or not.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+Udp4MatchDgram (\r
+ IN UDP4_INSTANCE_DATA *Instance,\r
+ IN EFI_UDP4_SESSION_DATA *Udp4Session\r
+ )\r
+{\r
+ EFI_UDP4_CONFIG_DATA *ConfigData;\r
+ IP4_ADDR Destination;\r
+\r
+ ConfigData = &Instance->ConfigData;\r
+\r
+ if (ConfigData->AcceptPromiscuous) {\r
+ //\r
+ // Always matches if this instance is in the promiscuous state.\r
+ //\r
+ return TRUE;\r
+ }\r
+\r
+ if ((!ConfigData->AcceptAnyPort && (Udp4Session->DestinationPort != ConfigData->StationPort)) ||\r
+ ((ConfigData->RemotePort != 0) && (Udp4Session->SourcePort != ConfigData->RemotePort))) {\r
+ //\r
+ // The local port or the remote port doesn't match.\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ if ((EFI_IP4 (ConfigData->RemoteAddress) != 0) &&\r
+ !EFI_IP_EQUAL (ConfigData->RemoteAddress, Udp4Session->SourceAddress)) {\r
+ //\r
+ // This datagram doesn't come from the instance's specified sender.\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ if ((EFI_IP4 (ConfigData->StationAddress) == 0) ||\r
+ EFI_IP_EQUAL (Udp4Session->DestinationAddress, ConfigData->StationAddress)) {\r
+ //\r
+ // The instance is configured to receive datagrams destinated to any station IP or\r
+ // the destination address of this datagram matches the configured station IP.\r
+ //\r
+ return TRUE;\r
+ }\r
+\r
+ Destination = EFI_IP4 (Udp4Session->DestinationAddress);\r
+\r
+ if (IP4_IS_LOCAL_BROADCAST (Destination) && ConfigData->AcceptBroadcast) {\r
+ //\r
+ // The instance is configured to receive broadcast and this is a broadcast packet.\r
+ //\r
+ return TRUE;\r
+ }\r
+\r
+ if (IP4_IS_MULTICAST (NTOHL (Destination)) &&\r
+ (NULL != NetMapFindKey (&Instance->McastIps, (VOID *) (UINTN) Destination))) {\r
+ //\r
+ // It's a multicast packet and the multicast address is accepted by this instance.\r
+ //\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ This function removes the Wrap specified by Context and release relevant resources.\r
+\r
+ @param Event The Event this notify function registered to.\r
+ @param Context Pointer to the context data.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Udp4RecycleRxDataWrap (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ UDP4_RXDATA_WRAP *Wrap;\r
+\r
+ Wrap = (UDP4_RXDATA_WRAP *) Context;\r
+\r
+ //\r
+ // Remove the Wrap from the list it belongs to.\r
+ //\r
+ NetListRemoveEntry (&Wrap->Link);\r
+\r
+ //\r
+ // Free the Packet associated with this Wrap.\r
+ //\r
+ NetbufFree (Wrap->Packet);\r
+\r
+ //\r
+ // Close the event.\r
+ //\r
+ gBS->CloseEvent (Wrap->RxData.RecycleSignal);\r
+\r
+ NetFreePool (Wrap);\r
+}\r
+\r
+\r
+/**\r
+ This function wraps the Packet and the RxData.\r
+\r
+ @param Instance Pointer to the instance context data.\r
+ @param Packet Pointer to the buffer containing the received\r
+ datagram.\r
+ @param RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this\r
+ datagram.\r
+\r
+ @return Pointer to the structure wrapping the RxData and the Packet.\r
+\r
+**/\r
+STATIC\r
+UDP4_RXDATA_WRAP *\r
+Udp4WrapRxData (\r
+ IN UDP4_INSTANCE_DATA *Instance,\r
+ IN NET_BUF *Packet,\r
+ IN EFI_UDP4_RECEIVE_DATA *RxData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UDP4_RXDATA_WRAP *Wrap;\r
+\r
+ //\r
+ // Allocate buffer for the Wrap.\r
+ //\r
+ Wrap = NetAllocatePool (sizeof (UDP4_RXDATA_WRAP) +\r
+ (Packet->BlockOpNum - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA));\r
+ if (Wrap == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetListInit (&Wrap->Link);\r
+\r
+ Wrap->RxData = *RxData;\r
+\r
+ //\r
+ // Create the Recycle event.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ NET_TPL_RECYCLE,\r
+ Udp4RecycleRxDataWrap,\r
+ Wrap,\r
+ &Wrap->RxData.RecycleSignal\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ NetFreePool (Wrap);\r
+ return NULL;\r
+ }\r
+\r
+ Wrap->Packet = Packet;\r
+ Wrap->TimeoutTick = Instance->ConfigData.ReceiveTimeout;\r
+\r
+ return Wrap;\r
+}\r
+\r
+\r
+/**\r
+ This function enqueues the received datagram into the instances' receiving queues.\r
+\r
+ @param Udp4Service Pointer to the udp service context data.\r
+ @param Packet Pointer to the buffer containing the received\r
+ datagram.\r
+ @param RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this\r
+ datagram.\r
+\r
+ @return The times this datagram is enqueued.\r
+\r
+**/\r
+STATIC\r
+UINTN\r
+Udp4EnqueueDgram (\r
+ IN UDP4_SERVICE_DATA *Udp4Service,\r
+ IN NET_BUF *Packet,\r
+ IN EFI_UDP4_RECEIVE_DATA *RxData\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ UDP4_RXDATA_WRAP *Wrap;\r
+ UINTN Enqueued;\r
+\r
+ Enqueued = 0;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+ //\r
+ // Iterate the instances.\r
+ //\r
+ Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);\r
+\r
+ if (!Instance->Configured) {\r
+ continue;\r
+ }\r
+\r
+ if (Udp4MatchDgram (Instance, &RxData->UdpSession)) {\r
+ //\r
+ // Wrap the RxData and put this Wrap into the instances RcvdDgramQue.\r
+ //\r
+ Wrap = Udp4WrapRxData (Instance, Packet, RxData);\r
+ if (Wrap == NULL) {\r
+ continue;\r
+ }\r
+\r
+ NET_GET_REF (Packet);\r
+\r
+ NetListInsertTail (&Instance->RcvdDgramQue, &Wrap->Link);\r
+\r
+ Enqueued++;\r
+ }\r
+ }\r
+\r
+ return Enqueued;\r
+}\r
+\r
+\r
+/**\r
+ This function delivers the received datagrams for the specified instance.\r
+\r
+ @param Instance Pointer to the instance context data.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+Udp4InstanceDeliverDgram (\r
+ IN UDP4_INSTANCE_DATA *Instance\r
+ )\r
+{\r
+ UDP4_RXDATA_WRAP *Wrap;\r
+ EFI_UDP4_COMPLETION_TOKEN *Token;\r
+ NET_BUF *Dup;\r
+ EFI_UDP4_RECEIVE_DATA *RxData;\r
+\r
+ if (!NetListIsEmpty (&Instance->RcvdDgramQue) &&\r
+ !NetMapIsEmpty (&Instance->RxTokens)) {\r
+\r
+ Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP4_RXDATA_WRAP, Link);\r
+\r
+ if (NET_BUF_SHARED (Wrap->Packet)) {\r
+ //\r
+ // Duplicate the Packet if it is shared between instances.\r
+ //\r
+ Dup = NetbufDuplicate (Wrap->Packet, NULL, 0);\r
+ if (Dup == NULL) {\r
+ return;\r
+ }\r
+\r
+ NetbufFree (Wrap->Packet);\r
+\r
+ Wrap->Packet = Dup;\r
+ }\r
+\r
+ NetListRemoveHead (&Instance->RcvdDgramQue);\r
+\r
+ Token = (EFI_UDP4_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);\r
+\r
+ //\r
+ // Build the FragmentTable and set the FragmentCount in RxData.\r
+ //\r
+ RxData = &Wrap->RxData;\r
+ RxData->FragmentCount = Wrap->Packet->BlockOpNum;\r
+\r
+ NetbufBuildExt (\r
+ Wrap->Packet,\r
+ (NET_FRAGMENT *) RxData->FragmentTable,\r
+ &RxData->FragmentCount\r
+ );\r
+\r
+ Token->Status = EFI_SUCCESS;\r
+ Token->Packet.RxData = &Wrap->RxData;\r
+\r
+ gBS->SignalEvent (Token->Event);\r
+\r
+ NetListInsertTail (&Instance->DeliveredDgramQue, &Wrap->Link);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function delivers the datagrams enqueued in the instances.\r
+\r
+ @param Udp4Service Pointer to the udp service context data.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4DeliverDgram (\r
+ IN UDP4_SERVICE_DATA *Udp4Service\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+ //\r
+ // Iterate the instances.\r
+ //\r
+ Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);\r
+\r
+ if (!Instance->Configured) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Deliver the datagrams of this instance.\r
+ //\r
+ Udp4InstanceDeliverDgram (Instance);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function demultiplexes the received udp datagram to the apropriate instances.\r
+\r
+ @param Udp4Service Pointer to the udp service context data.\r
+ @param NetSession Pointer to the EFI_NET_SESSION_DATA abstrated from\r
+ the received datagram.\r
+ @param Packet Pointer to the buffer containing the received udp\r
+ datagram.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4Demultiplex (\r
+ IN UDP4_SERVICE_DATA *Udp4Service,\r
+ IN EFI_NET_SESSION_DATA *NetSession,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ EFI_UDP4_HEADER *Udp4Header;\r
+ UINT16 HeadSum;\r
+ EFI_UDP4_RECEIVE_DATA RxData;\r
+ EFI_UDP4_SESSION_DATA *Udp4Session;\r
+ UINTN Enqueued;\r
+\r
+ //\r
+ // Get the datagram header from the packet buffer.\r
+ //\r
+ Udp4Header = (EFI_UDP4_HEADER *) NetbufGetByte (Packet, 0, NULL);\r
+\r
+ if (Udp4Header->Checksum != 0) {\r
+ //\r
+ // check the checksum.\r
+ //\r
+ HeadSum = NetPseudoHeadChecksum (\r
+ NetSession->Source,\r
+ NetSession->Dest,\r
+ EFI_IP_PROTO_UDP,\r
+ 0\r
+ );\r
+\r
+ if (Udp4Checksum (Packet, HeadSum) != 0) {\r
+ //\r
+ // Wrong checksum.\r
+ //\r
+ return;\r
+ }\r
+ }\r
+\r
+ gRT->GetTime (&RxData.TimeStamp, NULL);\r
+\r
+ Udp4Session = &RxData.UdpSession;\r
+ EFI_IP4 (Udp4Session->SourceAddress) = NetSession->Source;\r
+ EFI_IP4 (Udp4Session->DestinationAddress) = NetSession->Dest;\r
+ Udp4Session->SourcePort = NTOHS (Udp4Header->SrcPort);\r
+ Udp4Session->DestinationPort = NTOHS (Udp4Header->DstPort);\r
+\r
+ //\r
+ // Trim the UDP header.\r
+ //\r
+ NetbufTrim (Packet, UDP4_HEADER_SIZE, TRUE);\r
+\r
+ RxData.DataLength = (UINT32) Packet->TotalSize;\r
+\r
+ //\r
+ // Try to enqueue this datagram into the instances.\r
+ //\r
+ Enqueued = Udp4EnqueueDgram (Udp4Service, Packet, &RxData);\r
+\r
+ if (Enqueued == 0) {\r
+ //\r
+ // Send the port unreachable ICMP packet before we free this NET_BUF\r
+ //\r
+ Udp4SendPortUnreach (Udp4Service->IpIo, NetSession, Udp4Header);\r
+ }\r
+\r
+ //\r
+ // Try to free the packet before deliver it.\r
+ //\r
+ NetbufFree (Packet);\r
+\r
+ if (Enqueued > 0) {\r
+ //\r
+ // Deliver the datagram.\r
+ //\r
+ Udp4DeliverDgram (Udp4Service);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function builds and sends out a icmp port unreachable message.\r
+\r
+ @param IpIo Pointer to the IP_IO instance.\r
+ @param NetSession Pointer to the EFI_NET_SESSION_DATA of the packet\r
+ causes this icmp error message.\r
+ @param Udp4Header Pointer to the udp header of the datagram causes\r
+ this icmp error message.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4SendPortUnreach (\r
+ IN IP_IO *IpIo,\r
+ IN EFI_NET_SESSION_DATA *NetSession,\r
+ IN VOID *Udp4Header\r
+ )\r
+{\r
+ NET_BUF *Packet;\r
+ UINT32 Len;\r
+ IP4_ICMP_ERROR_HEAD *IcmpErrHdr;\r
+ EFI_IP4_HEADER *IpHdr;\r
+ UINT8 *Ptr;\r
+ IP_IO_OVERRIDE Override;\r
+ IP_IO_IP_INFO *IpSender;\r
+\r
+ IpSender = IpIoFindSender (&IpIo, NetSession->Dest);\r
+ if (IpSender == NULL) {\r
+ //\r
+ // No apropriate sender, since we cannot send out the ICMP message through\r
+ // the default zero station address IP instance, abort.\r
+ //\r
+ return;\r
+ }\r
+\r
+ IpHdr = NetSession->IpHdr;\r
+\r
+ //\r
+ // Calculate the requried length of the icmp error message.\r
+ //\r
+ Len = sizeof (IP4_ICMP_ERROR_HEAD) + (EFI_IP4_HEADER_LEN (IpHdr) -\r
+ sizeof (IP4_HEAD)) + ICMP_ERROR_PACKET_LENGTH;\r
+\r
+ //\r
+ // Allocate buffer for the icmp error message.\r
+ //\r
+ Packet = NetbufAlloc (Len);\r
+ if (Packet == NULL) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Allocate space for the IP4_ICMP_ERROR_HEAD.\r
+ //\r
+ IcmpErrHdr = (IP4_ICMP_ERROR_HEAD *) NetbufAllocSpace (Packet, Len, FALSE);\r
+\r
+ //\r
+ // Set the required fields for the icmp port unreachable message.\r
+ //\r
+ IcmpErrHdr->Head.Type = ICMP_TYPE_UNREACH;\r
+ IcmpErrHdr->Head.Code = ICMP_CODE_UNREACH_PORT;\r
+ IcmpErrHdr->Head.Checksum = 0;\r
+ IcmpErrHdr->Fourth = 0;\r
+\r
+ //\r
+ // Copy the IP header of the datagram tragged the error.\r
+ //\r
+ NetCopyMem (&IcmpErrHdr->IpHead, IpHdr, EFI_IP4_HEADER_LEN (IpHdr));\r
+\r
+ //\r
+ // Copy the UDP header.\r
+ //\r
+ Ptr = (UINT8 *) &IcmpErrHdr->IpHead + EFI_IP4_HEADER_LEN (IpHdr);\r
+ NetCopyMem (Ptr, Udp4Header, ICMP_ERROR_PACKET_LENGTH);\r
+\r
+ //\r
+ // Calculate the checksum.\r
+ //\r
+ IcmpErrHdr->Head.Checksum = ~(NetbufChecksum (Packet));\r
+\r
+ //\r
+ // Fill the override data.\r
+ //\r
+ Override.DoNotFragment = FALSE;\r
+ Override.TypeOfService = 0;\r
+ Override.TimeToLive = 255;\r
+ Override.Protocol = EFI_IP_PROTO_ICMP;\r
+ EFI_IP4 (Override.SourceAddress) = NetSession->Dest;\r
+ EFI_IP4 (Override.GatewayAddress) = 0;\r
+\r
+ //\r
+ // Send out this icmp packet.\r
+ //\r
+ IpIoSend (IpIo, Packet, IpSender, NULL, NULL, NetSession->Source, &Override);\r
+\r
+ NetbufFree (Packet);\r
+}\r
+\r
+\r
+/**\r
+ This function handles the received Icmp Error message and demultiplexes it to the\r
+ instance.\r
+\r
+ @param Udp4Service Pointer to the udp service context data.\r
+ @param IcmpError The icmp error code.\r
+ @param NetSession Pointer to the EFI_NET_SESSION_DATA abstracted\r
+ from the received Icmp Error packet.\r
+ @param Packet Pointer to the Icmp Error packet.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Udp4IcmpHandler (\r
+ IN UDP4_SERVICE_DATA *Udp4Service,\r
+ IN ICMP_ERROR IcmpError,\r
+ IN EFI_NET_SESSION_DATA *NetSession,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ EFI_UDP4_HEADER *Udp4Header;\r
+ EFI_UDP4_SESSION_DATA Udp4Session;\r
+ NET_LIST_ENTRY *Entry;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+\r
+ Udp4Header = (EFI_UDP4_HEADER *) NetbufGetByte (Packet, 0, NULL);\r
+\r
+ EFI_IP4 (Udp4Session.SourceAddress) = NetSession->Source;\r
+ EFI_IP4 (Udp4Session.DestinationAddress) = NetSession->Dest;\r
+ Udp4Session.SourcePort = NTOHS (Udp4Header->DstPort);\r
+ Udp4Session.DestinationPort = NTOHS (Udp4Header->SrcPort);\r
+\r
+ NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+ //\r
+ // Iterate all the instances.\r
+ //\r
+ Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);\r
+\r
+ if (!Instance->Configured ||\r
+ Instance->ConfigData.AcceptPromiscuous ||\r
+ Instance->ConfigData.AcceptAnyPort ||\r
+ (EFI_IP4 (Instance->ConfigData.StationAddress) == 0)) {\r
+ //\r
+ // Don't try to deliver the ICMP error to this instance if it is not configured,\r
+ // or it's configured to be promiscuous or accept any port or accept all the\r
+ // datagrams.\r
+ //\r
+ continue;\r
+ }\r
+\r
+ if (Udp4MatchDgram (Instance, &Udp4Session)) {\r
+ //\r
+ // Translate the Icmp Error code according to the udp spec.\r
+ //\r
+ Instance->IcmpError = IpIoGetIcmpErrStatus (IcmpError, NULL, NULL);\r
+\r
+ if (IcmpError > ICMP_ERR_UNREACH_PORT) {\r
+ Instance->IcmpError = EFI_ICMP_ERROR;\r
+ }\r
+\r
+ //\r
+ // Notify the instance with the received Icmp Error.\r
+ //\r
+ Udp4ReportIcmpError (Instance);\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ NetbufFree (Packet);\r
+}\r
+\r
+\r
+/**\r
+ This function reports the received ICMP error.\r
+\r
+ @param Instance Pointer to the udp instance context data.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+Udp4ReportIcmpError (\r
+ IN UDP4_INSTANCE_DATA *Instance\r
+ )\r
+{\r
+ EFI_UDP4_COMPLETION_TOKEN *Token;\r
+\r
+ if (NetMapIsEmpty (&Instance->RxTokens)) {\r
+ //\r
+ // There are no receive tokens to deliver the ICMP error.\r
+ //\r
+ return;\r
+ }\r
+\r
+ if (EFI_ERROR (Instance->IcmpError)) {\r
+ //\r
+ // Try to get a RxToken from the RxTokens map.\r
+ //\r
+ Token = (EFI_UDP4_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);\r
+\r
+ if (Token != NULL) {\r
+ //\r
+ // Report the error through the Token.\r
+ //\r
+ Token->Status = Instance->IcmpError;\r
+ gBS->SignalEvent (Token->Event);\r
+\r
+ //\r
+ // Clear the IcmpError.\r
+ //\r
+ Instance->IcmpError = EFI_SUCCESS;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function is a dummy ext-free function for the NET_BUF created for the output\r
+ udp datagram.\r
+\r
+ @param Context Pointer to the context data.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+Udp4NetVectorExtFree (\r
+ VOID *Context\r
+ )\r
+{\r
+}\r
+\r
+\r
+/**\r
+ Set the Udp4 variable data.\r
+\r
+ @param Udp4Service Udp4 service data.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the\r
+ variable.\r
+ @retval other Set variable failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Udp4SetVariableData (\r
+ IN UDP4_SERVICE_DATA *Udp4Service\r
+ )\r
+{\r
+ UINT32 NumConfiguredInstance;\r
+ NET_LIST_ENTRY *Entry;\r
+ UINTN VariableDataSize;\r
+ EFI_UDP4_VARIABLE_DATA *Udp4VariableData;\r
+ EFI_UDP4_SERVICE_POINT *Udp4ServicePoint;\r
+ UDP4_INSTANCE_DATA *Udp4Instance;\r
+ CHAR16 *NewMacString;\r
+ EFI_STATUS Status;\r
+\r
+ NumConfiguredInstance = 0;\r
+\r
+ //\r
+ // Go through the children list to count the configured children.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+ Udp4Instance = NET_LIST_USER_STRUCT_S (\r
+ Entry,\r
+ UDP4_INSTANCE_DATA,\r
+ Link,\r
+ UDP4_INSTANCE_DATA_SIGNATURE\r
+ );\r
+\r
+ if (Udp4Instance->Configured) {\r
+ NumConfiguredInstance++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Calculate the size of the Udp4VariableData. As there may be no Udp4 child,\r
+ // we should add extra buffer for the service points only if the number of configured\r
+ // children is more than 1.\r
+ //\r
+ VariableDataSize = sizeof (EFI_UDP4_VARIABLE_DATA);\r
+\r
+ if (NumConfiguredInstance > 1) {\r
+ VariableDataSize += sizeof (EFI_UDP4_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
+ }\r
+\r
+ Udp4VariableData = NetAllocatePool (VariableDataSize);\r
+ if (Udp4VariableData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Udp4VariableData->DriverHandle = Udp4Service->ImageHandle;\r
+ Udp4VariableData->ServiceCount = NumConfiguredInstance;\r
+\r
+ Udp4ServicePoint = &Udp4VariableData->Services[0];\r
+\r
+ //\r
+ // Go through the children list to fill the configured children's address pairs.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
+ Udp4Instance = NET_LIST_USER_STRUCT_S (\r
+ Entry,\r
+ UDP4_INSTANCE_DATA,\r
+ Link,\r
+ UDP4_INSTANCE_DATA_SIGNATURE\r
+ );\r
+\r
+ if (Udp4Instance->Configured) {\r
+ Udp4ServicePoint->InstanceHandle = Udp4Instance->ChildHandle;\r
+ Udp4ServicePoint->LocalAddress = Udp4Instance->ConfigData.StationAddress;\r
+ Udp4ServicePoint->LocalPort = Udp4Instance->ConfigData.StationPort;\r
+ Udp4ServicePoint->RemoteAddress = Udp4Instance->ConfigData.RemoteAddress;\r
+ Udp4ServicePoint->RemotePort = Udp4Instance->ConfigData.RemotePort;\r
+\r
+ Udp4ServicePoint++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get the mac string.\r
+ //\r
+ Status = NetLibGetMacString (\r
+ Udp4Service->ControllerHandle,\r
+ Udp4Service->ImageHandle,\r
+ &NewMacString\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ if (Udp4Service->MacString != NULL) {\r
+ //\r
+ // The variable is set already, we're going to update it.\r
+ //\r
+ if (StrCmp (Udp4Service->MacString, NewMacString) != 0) {\r
+ //\r
+ // The mac address is changed, delete the previous variable first.\r
+ //\r
+ gRT->SetVariable (\r
+ Udp4Service->MacString,\r
+ &gEfiUdp4ServiceBindingProtocolGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ NetFreePool (Udp4Service->MacString);\r
+ }\r
+\r
+ Udp4Service->MacString = NewMacString;\r
+\r
+ Status = gRT->SetVariable (\r
+ Udp4Service->MacString,\r
+ &gEfiUdp4ServiceBindingProtocolGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ VariableDataSize,\r
+ (VOID *) Udp4VariableData\r
+ );\r
+\r
+ON_ERROR:\r
+\r
+ NetFreePool (Udp4VariableData);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Clear the variable and free the resource.\r
+\r
+ @param Udp4Service Udp4 service data.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+Udp4ClearVariableData (\r
+ IN UDP4_SERVICE_DATA *Udp4Service\r
+ )\r
+{\r
+ ASSERT (Udp4Service->MacString != NULL);\r
+\r
+ gRT->SetVariable (\r
+ Udp4Service->MacString,\r
+ &gEfiUdp4ServiceBindingProtocolGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ NetFreePool (Udp4Service->MacString);\r
+ Udp4Service->MacString = NULL;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2006 - 2007, 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:
+
+ Udp4Impl.h
+
+Abstract:
+
+ EFI UDPv4 protocol implementation
+
+
+**/
+
+#ifndef _UDP4_IMPL_H_
+#define _UDP4_IMPL_H_
+
+#include <PiDxe.h>\r
+\r
+#include <Protocol/IP4.h>\r
+#include <Protocol/Udp4.h>\r
+
+#include <Library/IpIoLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "Udp4Driver.h"
+
+
+extern EFI_COMPONENT_NAME_PROTOCOL gUdp4ComponentName;
+extern EFI_SERVICE_BINDING_PROTOCOL mUdp4ServiceBinding;
+extern EFI_UDP4_PROTOCOL mUdp4Protocol;
+extern UINT16 mUdp4RandomPort;
+
+#define ICMP_ERROR_PACKET_LENGTH 8
+
+#define UDP4_TIMEOUT_INTERVAL (50 * TICKS_PER_MS) // 50 milliseconds
+
+#define UDP4_HEADER_SIZE sizeof (EFI_UDP4_HEADER)
+#define UDP4_MAX_DATA_SIZE 65507
+
+#define UDP4_PORT_KNOWN 1024
+
+#define UDP4_SERVICE_DATA_SIGNATURE EFI_SIGNATURE_32('U', 'd', 'p', '4')
+
+#define UDP4_SERVICE_DATA_FROM_THIS(a) \
+ CR ( \
+ (a), \
+ UDP4_SERVICE_DATA, \
+ ServiceBinding, \
+ UDP4_SERVICE_DATA_SIGNATURE \
+ )
+
+typedef struct _UDP4_SERVICE_DATA_ {
+ UINT32 Signature;
+ EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE ControllerHandle;
+ NET_LIST_ENTRY ChildrenList;
+ UINTN ChildrenNumber;
+ IP_IO *IpIo;
+
+ EFI_EVENT TimeoutEvent;
+
+ CHAR16 *MacString;
+} UDP4_SERVICE_DATA;
+
+#define UDP4_INSTANCE_DATA_SIGNATURE EFI_SIGNATURE_32('U', 'd', 'p', 'I')
+
+#define UDP4_INSTANCE_DATA_FROM_THIS(a) \
+ CR ( \
+ (a), \
+ UDP4_INSTANCE_DATA, \
+ Udp4Proto, \
+ UDP4_INSTANCE_DATA_SIGNATURE \
+ )
+
+typedef struct _UDP4_INSTANCE_DATA_ {
+ UINT32 Signature;
+ NET_LIST_ENTRY Link;
+
+ UDP4_SERVICE_DATA *Udp4Service;
+ EFI_UDP4_PROTOCOL Udp4Proto;
+ EFI_UDP4_CONFIG_DATA ConfigData;
+ EFI_HANDLE ChildHandle;
+ BOOLEAN Configured;
+ BOOLEAN IsNoMapping;
+
+ NET_MAP TxTokens;
+ NET_MAP RxTokens;
+
+ NET_MAP McastIps;
+
+ NET_LIST_ENTRY RcvdDgramQue;
+ NET_LIST_ENTRY DeliveredDgramQue;
+
+ UINT16 HeadSum;
+
+ EFI_STATUS IcmpError;
+
+ IP_IO_IP_INFO *IpInfo;
+
+ BOOLEAN Destroyed;
+} UDP4_INSTANCE_DATA;
+
+typedef struct _UDP4_RXDATA_WRAP_ {
+ NET_LIST_ENTRY Link;
+ NET_BUF *Packet;
+ UINT32 TimeoutTick;
+ EFI_UDP4_RECEIVE_DATA RxData;
+} UDP4_RXDATA_WRAP;
+
+EFI_STATUS
+EFIAPI
+Udp4GetModeData (
+ IN EFI_UDP4_PROTOCOL *This,
+ OUT EFI_UDP4_CONFIG_DATA *Udp4ConfigData OPTIONAL,
+ OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL,
+ OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,
+ OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Configure (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN EFI_UDP4_CONFIG_DATA *UdpConfigData OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Groups (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN BOOLEAN JoinFlag,
+ IN EFI_IPv4_ADDRESS *MulticastAddress OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Routes (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN BOOLEAN DeleteRoute,
+ IN EFI_IPv4_ADDRESS *SubnetAddress,
+ IN EFI_IPv4_ADDRESS *SubnetMask,
+ IN EFI_IPv4_ADDRESS *GatewayAddress
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Transmit (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN EFI_UDP4_COMPLETION_TOKEN *Token
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Receive (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN EFI_UDP4_COMPLETION_TOKEN *Token
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Cancel (
+ IN EFI_UDP4_PROTOCOL *This,
+ IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Udp4Poll (
+ IN EFI_UDP4_PROTOCOL *This
+ );
+
+EFI_STATUS
+Udp4CreateService (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ControllerHandle
+ );
+
+VOID
+Udp4CleanService (
+ IN UDP4_SERVICE_DATA *Udp4Service
+ );
+
+VOID
+Udp4InitInstance (
+ IN UDP4_SERVICE_DATA *Udp4Service,
+ IN UDP4_INSTANCE_DATA *Instance
+ );
+
+VOID
+Udp4CleanInstance (
+ IN UDP4_INSTANCE_DATA *Instance
+ );
+
+EFI_STATUS
+Udp4Bind (
+ IN NET_LIST_ENTRY *InstanceList,
+ IN EFI_UDP4_CONFIG_DATA *ConfigData
+ );
+
+BOOLEAN
+Udp4IsReconfigurable (
+ IN EFI_UDP4_CONFIG_DATA *OldConfigData,
+ IN EFI_UDP4_CONFIG_DATA *NewConfigData
+ );
+
+VOID
+Udp4BuildIp4ConfigData (
+ IN EFI_UDP4_CONFIG_DATA *Udp4ConfigData,
+ IN EFI_IP4_CONFIG_DATA *Ip4ConfigData
+ );
+
+EFI_STATUS
+Udp4ValidateTxToken (
+ IN UDP4_INSTANCE_DATA *Instance,
+ IN EFI_UDP4_COMPLETION_TOKEN *TxToken
+ );
+
+EFI_STATUS
+Udp4TokenExist (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ );
+
+UINT16
+Udp4Checksum (
+ IN NET_BUF *Packet,
+ IN UINT16 HeadSum
+ );
+
+EFI_STATUS
+Udp4RemoveToken (
+ IN NET_MAP *TokenMap,
+ IN EFI_UDP4_COMPLETION_TOKEN *Token
+ );
+
+EFI_STATUS
+Udp4LeaveGroup (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Arg OPTIONAL
+ );
+
+VOID
+Udp4FlushRxData (
+ IN NET_LIST_ENTRY *RcvdDgramQue
+ );
+
+EFI_STATUS
+Udp4InstanceCancelToken (
+ IN UDP4_INSTANCE_DATA *Instance,
+ IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL
+ );
+
+VOID
+Udp4InstanceDeliverDgram (
+ IN UDP4_INSTANCE_DATA *Instance
+ );
+
+VOID
+Udp4ReportIcmpError (
+ IN UDP4_INSTANCE_DATA *Instance
+ );
+
+VOID
+Udp4NetVectorExtFree (
+ VOID *Context
+ );
+
+EFI_STATUS
+Udp4SetVariableData (
+ IN UDP4_SERVICE_DATA *Udp4Service
+ );
+
+VOID
+Udp4ClearVariableData (
+ IN UDP4_SERVICE_DATA *Udp4Service
+ );
+
+#endif
+
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Udp4Main.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Udp4Impl.h"\r
+\r
+#include <Protocol/Ip4.h>\r
+\r
+EFI_UDP4_PROTOCOL mUdp4Protocol = {\r
+ Udp4GetModeData,\r
+ Udp4Configure,\r
+ Udp4Groups,\r
+ Udp4Routes,\r
+ Udp4Transmit,\r
+ Udp4Receive,\r
+ Udp4Cancel,\r
+ Udp4Poll\r
+};\r
+\r
+\r
+/**\r
+ This function copies the current operational settings of this EFI UDPv4 Protocol\r
+ instance into user-supplied buffers. This function is used optionally to retrieve\r
+ the operational mode data of underlying networks or drivers.\r
+\r
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.\r
+ @param Udp4ConfigData Pointer to the buffer to receive the current\r
+ configuration data.\r
+ @param Ip4ModeData Pointer to the EFI IPv4 Protocol mode data\r
+ structure.\r
+ @param MnpConfigData Pointer to the managed network configuration data\r
+ structure.\r
+ @param SnpModeData Pointer to the simple network mode data structure.\r
+\r
+ @retval EFI_SUCCESS The mode data was read.\r
+ @retval EFI_NOT_STARTED When Udp4ConfigData is queried, no configuration\r
+ data is available because this instance has not\r
+ been started.\r
+ @retval EFI_INVALID_PARAMETER This is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4GetModeData (\r
+ IN EFI_UDP4_PROTOCOL *This,\r
+ OUT EFI_UDP4_CONFIG_DATA *Udp4ConfigData OPTIONAL,\r
+ OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL,\r
+ OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL,\r
+ OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL\r
+ )\r
+{\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_IP4_PROTOCOL *Ip;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ if (!Instance->Configured && (Udp4ConfigData != NULL)) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (Udp4ConfigData != NULL) {\r
+ //\r
+ // Set the Udp4ConfigData.\r
+ //\r
+ *Udp4ConfigData = Instance->ConfigData;\r
+ }\r
+\r
+ Ip = Instance->IpInfo->Ip;\r
+\r
+ //\r
+ // Get the underlying Ip4ModeData, MnpConfigData and SnpModeData.\r
+ //\r
+ Status = Ip->GetModeData (Ip, Ip4ModeData, MnpConfigData, SnpModeData);\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This function is used to do the following:\r
+ Initialize and start this instance of the EFI UDPv4 Protocol.\r
+ Change the filtering rules and operational parameters.\r
+ Reset this instance of the EFI UDPv4 Protocol.\r
+\r
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.\r
+ @param UdpConfigData Pointer to the buffer to receive the current mode\r
+ data.\r
+\r
+ @retval EFI_SUCCESS The configuration settings were set, changed, or\r
+ reset successfully.\r
+ @retval EFI_NO_MAPPING When using a default address, configuration (DHCP,\r
+ BOOTP, RARP, etc.) is not finished yet.\r
+ @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE: This is\r
+ NULL. UdpConfigData.StationAddress is not a valid\r
+ unicast IPv4 address. UdpConfigData.SubnetMask is\r
+ not a valid IPv4 address mask.\r
+ UdpConfigData.RemoteAddress is not a valid unicast\r
+ IPv4 address if it is not zero.\r
+ @retval EFI_ALREADY_STARTED The EFI UDPv4 Protocol instance is already\r
+ started/configured and must be stopped/reset\r
+ before it can be reconfigured. Only TypeOfService,\r
+ TimeToLive, DoNotFragment, ReceiveTimeout, and\r
+ TransmitTimeout can be reconfigured without\r
+ stopping the current instance of the EFI UDPv4\r
+ Protocol.\r
+ @retval EFI_ACCESS_DENIED UdpConfigData.AllowDuplicatePort is FALSE and\r
+ UdpConfigData.StationPort is already used by other\r
+ instance.\r
+ @retval EFI_OUT_OF_RESOURCES The EFI UDPv4 Protocol driver cannot allocate\r
+ memory for this EFI UDPv4 Protocol instance.\r
+ @retval EFI_DEVICE_ERROR An unexpected network or system error occurred and\r
+ this instance was not opened.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Configure (\r
+ IN EFI_UDP4_PROTOCOL *This,\r
+ IN EFI_UDP4_CONFIG_DATA *UdpConfigData OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ UDP4_SERVICE_DATA *Udp4Service;\r
+ EFI_TPL OldTpl;\r
+ IP4_ADDR StationAddress;\r
+ IP4_ADDR SubnetMask;\r
+ IP4_ADDR RemoteAddress;\r
+ EFI_IP4_CONFIG_DATA Ip4ConfigData;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ if (!Instance->Configured && (UdpConfigData == NULL)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Udp4Service = Instance->Udp4Service;\r
+ Status = EFI_SUCCESS;\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (UdpConfigData != NULL) {\r
+\r
+ StationAddress = EFI_NTOHL (UdpConfigData->StationAddress);\r
+ SubnetMask = EFI_NTOHL (UdpConfigData->SubnetMask);\r
+ RemoteAddress = EFI_NTOHL (UdpConfigData->RemoteAddress);\r
+\r
+ if (!UdpConfigData->UseDefaultAddress &&\r
+ (!IP4_IS_VALID_NETMASK (SubnetMask) ||\r
+ !((StationAddress == 0) || Ip4IsUnicast (StationAddress, SubnetMask)) ||\r
+ !((RemoteAddress == 0) || Ip4IsUnicast (RemoteAddress, 0)))) {\r
+ //\r
+ // Don't use default address, and subnet mask is invalid or StationAddress is not\r
+ // a valid unicast IPv4 address or RemoteAddress is not a valid unicast IPv4 address\r
+ // if it is not 0.\r
+ //\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (Instance->Configured) {\r
+ //\r
+ // The instance is already configured, try to do the re-configuration.\r
+ //\r
+ if (!Udp4IsReconfigurable (&Instance->ConfigData, UdpConfigData)) {\r
+ //\r
+ // If the new configuration data wants to change some unreconfigurable\r
+ // settings, return EFI_ALREADY_STARTED.\r
+ //\r
+ Status = EFI_ALREADY_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Save the reconfigurable parameters.\r
+ //\r
+ Instance->ConfigData.TypeOfService = UdpConfigData->TypeOfService;\r
+ Instance->ConfigData.TimeToLive = UdpConfigData->TimeToLive;\r
+ Instance->ConfigData.DoNotFragment = UdpConfigData->DoNotFragment;\r
+ Instance->ConfigData.ReceiveTimeout = UdpConfigData->ReceiveTimeout;\r
+ Instance->ConfigData.TransmitTimeout = UdpConfigData->TransmitTimeout;\r
+ } else {\r
+ //\r
+ // Construct the Ip configuration data from the UdpConfigData.\r
+ //\r
+ Udp4BuildIp4ConfigData (UdpConfigData, &Ip4ConfigData);\r
+\r
+ //\r
+ // Configure the Ip instance wrapped in the IpInfo.\r
+ //\r
+ Status = IpIoConfigIp (Instance->IpInfo, &Ip4ConfigData);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Status == EFI_NO_MAPPING) {\r
+ Instance->IsNoMapping = TRUE;\r
+ }\r
+\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Instance->IsNoMapping = FALSE;\r
+\r
+ //\r
+ // Save the configuration data.\r
+ //\r
+ Instance->ConfigData = *UdpConfigData;\r
+ Instance->ConfigData.StationAddress = Ip4ConfigData.StationAddress;\r
+ Instance->ConfigData.SubnetMask = Ip4ConfigData.SubnetMask;\r
+\r
+ //\r
+ // Try to allocate the required port resource.\r
+ //\r
+ Status = Udp4Bind (&Udp4Service->ChildrenList, &Instance->ConfigData);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Reset the ip instance if bind fails.\r
+ //\r
+ IpIoConfigIp (Instance->IpInfo, NULL);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Pre calculate the checksum for the pseudo head, ignore the UDP length first.\r
+ //\r
+ Instance->HeadSum = NetPseudoHeadChecksum (\r
+ EFI_IP4 (Instance->ConfigData.StationAddress),\r
+ EFI_IP4 (Instance->ConfigData.RemoteAddress),\r
+ EFI_IP_PROTO_UDP,\r
+ 0\r
+ );\r
+\r
+ Instance->Configured = TRUE;\r
+ }\r
+ } else {\r
+ //\r
+ // UdpConfigData is NULL, reset the instance.\r
+ //\r
+ Instance->Configured = FALSE;\r
+ Instance->IsNoMapping = FALSE;\r
+\r
+ //\r
+ // Reset the Ip instance wrapped in the IpInfo.\r
+ //\r
+ IpIoConfigIp (Instance->IpInfo, NULL);\r
+\r
+ //\r
+ // Cancel all the user tokens.\r
+ //\r
+ Udp4InstanceCancelToken (Instance, NULL);\r
+\r
+ //\r
+ // Remove the buffered RxData for this instance.\r
+ //\r
+ Udp4FlushRxData (&Instance->RcvdDgramQue);\r
+ }\r
+\r
+ Udp4SetVariableData (Instance->Udp4Service);\r
+\r
+ON_EXIT:\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This function is used to enable and disable the multicast group filtering.\r
+\r
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.\r
+ @param JoinFlag Set to TRUE to join a multicast group. Set to\r
+ FALSE to leave one or all multicast groups.\r
+ @param MulticastAddress Pointer to multicast group address to join or\r
+ leave.\r
+\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+ @retval EFI_NOT_STARTED The EFI UDPv4 Protocol instance has not been\r
+ started.\r
+ @retval EFI_NO_MAPPING When using a default address, configuration (DHCP,\r
+ BOOTP, RARP, etc.) is not finished yet.\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate resources to join the group.\r
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
+ This is NULL. JoinFlag is TRUE and\r
+ MulticastAddress is NULL. JoinFlag is TRUE and\r
+ *MulticastAddress is not a valid multicast\r
+ address.\r
+ @retval EFI_ALREADY_STARTED The group address is already in the group table\r
+ (when JoinFlag is TRUE).\r
+ @retval EFI_NOT_FOUND The group address is not in the group table (when\r
+ JoinFlag is FALSE).\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Groups (\r
+ IN EFI_UDP4_PROTOCOL *This,\r
+ IN BOOLEAN JoinFlag,\r
+ IN EFI_IPv4_ADDRESS *MulticastAddress OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_IP4_PROTOCOL *Ip;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((This == NULL) ||\r
+ (JoinFlag && (MulticastAddress == NULL)) ||\r
+ (JoinFlag && !IP4_IS_MULTICAST (EFI_NTOHL (*MulticastAddress)))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ if (Instance->IsNoMapping) {\r
+ return EFI_NO_MAPPING;\r
+ }\r
+\r
+ if (!Instance->Configured) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ Ip = Instance->IpInfo->Ip;\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ //\r
+ // Invoke the Ip instance the Udp4 instance consumes to do the group operation.\r
+ //\r
+ Status = Ip->Groups (Ip, JoinFlag, MulticastAddress);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Keep a local copy of the configured multicast IPs because IpIo receives\r
+ // datagrams from the 0 station address IP instance and then UDP delivers to\r
+ // the matched instance. This copy of multicast IPs is used to avoid receive\r
+ // the mutlicast datagrams destinated to multicast IPs the other instances configured.\r
+ //\r
+ if (JoinFlag) {\r
+\r
+ NetMapInsertTail (\r
+ &Instance->McastIps,\r
+ (VOID *) (UINTN) EFI_IP4 (*MulticastAddress),\r
+ NULL\r
+ );\r
+ } else {\r
+\r
+ NetMapIterate (&Instance->McastIps, Udp4LeaveGroup, MulticastAddress);\r
+ }\r
+\r
+ON_EXIT:\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This function adds a route to or deletes a route from the routing table.\r
+\r
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.\r
+ @param DeleteRoute Set to TRUE to delete this route from the routing\r
+ table. Set to FALSE to add this route to the\r
+ routing table.\r
+ @param SubnetAddress The destination network address that needs to be\r
+ routed.\r
+ @param SubnetMask The subnet mask of SubnetAddress.\r
+ @param GatewayAddress The gateway IP address for this route.\r
+\r
+ @retval EFI_SUCCESS The operation completed successfully.\r
+ @retval EFI_NOT_STARTED The EFI UDPv4 Protocol instance has not been\r
+ started.\r
+ @retval EFI_NO_MAPPING When using a default address, configuration (DHCP,\r
+ BOOTP, RARP, etc.) is not finished yet.\r
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
+ This is NULL. SubnetAddress is NULL. SubnetMask is\r
+ NULL. GatewayAddress is NULL. SubnetAddress is not\r
+ a valid subnet address. SubnetMask is not a valid\r
+ subnet mask. GatewayAddress is not a valid unicast\r
+ IP address.\r
+ @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.\r
+ @retval EFI_NOT_FOUND This route is not in the routing table.\r
+ @retval EFI_ACCESS_DENIED The route is already defined in the routing table.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Routes (\r
+ IN EFI_UDP4_PROTOCOL *This,\r
+ IN BOOLEAN DeleteRoute,\r
+ IN EFI_IPv4_ADDRESS *SubnetAddress,\r
+ IN EFI_IPv4_ADDRESS *SubnetMask,\r
+ IN EFI_IPv4_ADDRESS *GatewayAddress\r
+ )\r
+{\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_IP4_PROTOCOL *Ip;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ if (Instance->IsNoMapping) {\r
+ return EFI_NO_MAPPING;\r
+ }\r
+\r
+ if (!Instance->Configured) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ Ip = Instance->IpInfo->Ip;\r
+\r
+ //\r
+ // Invoke the Ip instance the Udp4 instance consumes to do the actual operation.\r
+ //\r
+ return Ip->Routes (Ip, DeleteRoute, SubnetAddress, SubnetMask, GatewayAddress);\r
+}\r
+\r
+\r
+/**\r
+ This function places a sending request to this instance of the EFI UDPv4 Protocol,\r
+ alongside the transmit data that was filled by the user.\r
+\r
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.\r
+ @param Token Pointer to the completion token that will be\r
+ placed into the transmit queue.\r
+\r
+ @retval EFI_SUCCESS The data has been queued for transmission.\r
+ @retval EFI_NOT_STARTED This EFI UDPv4 Protocol instance has not been\r
+ started.\r
+ @retval EFI_NO_MAPPING When using a default address, configuration (DHCP,\r
+ BOOTP, RARP, etc.) is not finished yet.\r
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: This is\r
+ NULL. Token is NULL. Token.Event is NULL.\r
+ Token.Packet.TxData is NULL.\r
+ Token.Packet.TxData.FragmentCount is zero.\r
+ Token.Packet.TxData.DataLength is not equal to the\r
+ sum of fragment lengths. One or more of the\r
+ Token.Packet.TxData.FragmentTable[].\r
+ FragmentLength fields is zero. One or more of the\r
+ Token.Packet.TxData.FragmentTable[].\r
+ FragmentBuffer fields is NULL.\r
+ Token.Packet.TxData. GatewayAddress is not a\r
+ unicast IPv4 address if it is not NULL. One or\r
+ more IPv4 addresses in Token.Packet.TxData.\r
+ UdpSessionData are not valid unicast IPv4\r
+ addresses if the UdpSessionData is not NULL.\r
+ @retval EFI_ACCESS_DENIED The transmit completion token with the same\r
+ Token.Event is already in the transmit queue.\r
+ @retval EFI_NOT_READY The completion token could not be queued because\r
+ the transmit queue is full.\r
+ @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data.\r
+ @retval EFI_NOT_FOUND There is no route to the destination network or\r
+ address.\r
+ @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP\r
+ packet size. Or the length of the IP header + UDP\r
+ header + data length is greater than MTU if\r
+ DoNotFragment is TRUE.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Transmit (\r
+ IN EFI_UDP4_PROTOCOL *This,\r
+ IN EFI_UDP4_COMPLETION_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_TPL OldTpl;\r
+ NET_BUF *Packet;\r
+ EFI_UDP4_HEADER *Udp4Header;\r
+ EFI_UDP4_CONFIG_DATA *ConfigData;\r
+ IP4_ADDR Destination;\r
+ EFI_UDP4_TRANSMIT_DATA *TxData;\r
+ EFI_UDP4_SESSION_DATA *UdpSessionData;\r
+ UDP4_SERVICE_DATA *Udp4Service;\r
+ IP_IO_OVERRIDE Override;\r
+ UINT16 HeadSum;\r
+\r
+ if ((This == NULL) || (Token == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ if (Instance->IsNoMapping) {\r
+ return EFI_NO_MAPPING;\r
+ }\r
+\r
+ if (!Instance->Configured) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ //\r
+ // Validate the Token, if the token is invalid return the error code.\r
+ //\r
+ Status = Udp4ValidateTxToken (Instance, Token);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token)) ||\r
+ EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token))) {\r
+ //\r
+ // Try to find a duplicate token in the two token maps, if found, return\r
+ // EFI_ACCESS_DENIED.\r
+ //\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ TxData = Token->Packet.TxData;\r
+\r
+ //\r
+ // Create a net buffer to hold the user buffer and the udp header.\r
+ //\r
+ Packet = NetbufFromExt (\r
+ (NET_FRAGMENT *)TxData->FragmentTable,\r
+ TxData->FragmentCount,\r
+ UDP4_HEADER_SIZE,\r
+ 0,\r
+ Udp4NetVectorExtFree,\r
+ NULL\r
+ );\r
+ if (Packet == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Store the IpIo in ProtoData.\r
+ //\r
+ Udp4Service = Instance->Udp4Service;\r
+ *((UINTN *) &Packet->ProtoData[0]) = (UINTN) (Udp4Service->IpIo);\r
+\r
+ Udp4Header = (EFI_UDP4_HEADER *) NetbufAllocSpace (Packet, UDP4_HEADER_SIZE, TRUE);\r
+ ConfigData = &Instance->ConfigData;\r
+\r
+ //\r
+ // Fill the udp header.\r
+ //\r
+ Udp4Header->SrcPort = HTONS (ConfigData->StationPort);\r
+ Udp4Header->DstPort = HTONS (ConfigData->RemotePort);\r
+ Udp4Header->Length = HTONS (Packet->TotalSize);\r
+ Udp4Header->Checksum = 0;\r
+\r
+ UdpSessionData = TxData->UdpSessionData;\r
+ Override.SourceAddress = ConfigData->StationAddress;\r
+\r
+ if (UdpSessionData != NULL) {\r
+ //\r
+ // Set the SourceAddress, SrcPort and Destination according to the specified\r
+ // UdpSessionData.\r
+ //\r
+ if (EFI_IP4 (UdpSessionData->SourceAddress) != 0) {\r
+ Override.SourceAddress = UdpSessionData->SourceAddress;\r
+ }\r
+\r
+ if (UdpSessionData->SourcePort != 0) {\r
+ Udp4Header->SrcPort = HTONS (UdpSessionData->SourcePort);\r
+ }\r
+\r
+ Destination = EFI_IP4 (UdpSessionData->DestinationAddress);\r
+\r
+ if (UdpSessionData->DestinationPort != 0) {\r
+ Udp4Header->DstPort = HTONS (UdpSessionData->DestinationPort);\r
+ }\r
+\r
+ //\r
+ // calculate the pseudo head checksum using the overridden parameters.\r
+ //\r
+ HeadSum = NetPseudoHeadChecksum (\r
+ EFI_IP4 (Override.SourceAddress),\r
+ Destination,\r
+ EFI_IP_PROTO_UDP,\r
+ 0\r
+ );\r
+ } else {\r
+ //\r
+ // UdpSessionData is NULL, use the address and port information previously configured.\r
+ //\r
+ Destination = EFI_IP4 (ConfigData->RemoteAddress);\r
+ HeadSum = Instance->HeadSum;\r
+ }\r
+\r
+ //\r
+ // calculate the checksum.\r
+ //\r
+ Udp4Header->Checksum = Udp4Checksum (Packet, HeadSum);\r
+ if (Udp4Header->Checksum == 0) {\r
+ //\r
+ // If the calculated checksum is 0, fill the Checksum field with all ones.\r
+ //\r
+ Udp4Header->Checksum = 0xffff;\r
+ }\r
+\r
+ //\r
+ // Fill the IpIo Override data.\r
+ //\r
+ EFI_IP4 (Override.GatewayAddress) = (TxData->GatewayAddress != NULL) ?\r
+ EFI_IP4 (*(TxData->GatewayAddress)) : 0;\r
+ Override.Protocol = EFI_IP_PROTO_UDP;\r
+ Override.TypeOfService = ConfigData->TypeOfService;\r
+ Override.TimeToLive = ConfigData->TimeToLive;\r
+ Override.DoNotFragment = ConfigData->DoNotFragment;\r
+\r
+ //\r
+ // Save the token into the TxToken map.\r
+ //\r
+ Status = NetMapInsertTail (&Instance->TxTokens, Token, Packet);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_PACKET;\r
+ }\r
+\r
+ //\r
+ // Send out this datagram through IpIo.\r
+ //\r
+ Status = IpIoSend (\r
+ Udp4Service->IpIo,\r
+ Packet,\r
+ Instance->IpInfo,\r
+ Instance,\r
+ Token,\r
+ Destination,\r
+ &Override\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Remove this token from the TxTokens.\r
+ //\r
+ Udp4RemoveToken (&Instance->TxTokens, Token);\r
+ }\r
+\r
+FREE_PACKET:\r
+\r
+ NetbufFree (Packet);\r
+\r
+ON_EXIT:\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This function places a completion token into the receive packet queue. This function\r
+ is always asynchronous.\r
+\r
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.\r
+ @param Token Pointer to a token that is associated with the\r
+ receive data descriptor.\r
+\r
+ @retval EFI_SUCCESS The receive completion token is cached.\r
+ @retval EFI_NOT_STARTED This EFI UDPv4 Protocol instance has not been\r
+ started.\r
+ @retval EFI_NO_MAPPING When using a default address, configuration (DHCP,\r
+ BOOTP, RARP, etc.) is not finished yet.\r
+ @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
+ This is NULL. Token is NULL. Token.Event is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued\r
+ due to a lack of system resources (usually\r
+ memory).\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
+ The EFI UDPv4 Protocol instance has been reset to\r
+ startup defaults.\r
+ @retval EFI_ACCESS_DENIED A receive completion token with the same\r
+ Token.Event is already in the receive queue.\r
+ @retval EFI_NOT_READY The receive request could not be queued because\r
+ the receive queue is full.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Receive (\r
+ IN EFI_UDP4_PROTOCOL *This,\r
+ IN EFI_UDP4_COMPLETION_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ if (Instance->IsNoMapping) {\r
+ return EFI_NO_MAPPING;\r
+ }\r
+\r
+ if (!Instance->Configured) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token))||\r
+ EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token))) {\r
+ //\r
+ // Return EFI_ACCESS_DENIED if the specified token is already in the TxTokens or\r
+ // RxTokens map.\r
+ //\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Token->Packet.RxData = NULL;\r
+\r
+ //\r
+ // Save the token into the RxTokens map.\r
+ //\r
+ Status = NetMapInsertTail (&Instance->RxTokens, Token, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ //\r
+ // If there is an icmp error, report it.\r
+ //\r
+ Udp4ReportIcmpError (Instance);\r
+\r
+ //\r
+ // Try to delivered the received datagrams.\r
+ //\r
+ Udp4InstanceDeliverDgram (Instance);\r
+\r
+ON_EXIT:\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This function is used to abort a pending transmit or receive request.\r
+\r
+ @param This Pointer to the EFI_UDP4_PROTOCOL instance.\r
+ @param Token Pointer to a token that has been issued by\r
+ EFI_UDP4_PROTOCOL.Transmit() or\r
+ EFI_UDP4_PROTOCOL.Receive().\r
+\r
+ @retval EFI_SUCCESS The asynchronous I/O request is aborted and\r
+ Token.Event is signaled. When Token is NULL, all\r
+ pending requests are aborted and their events are\r
+ signaled.\r
+ @retval EFI_INVALID_PARAMETER This is NULL.\r
+ @retval EFI_NOT_STARTED This instance has not been started.\r
+ @retval EFI_NO_MAPPING When using the default address, configuration\r
+ (DHCP, BOOTP, RARP, etc.) is not finished yet.\r
+ @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O\r
+ request is not found in the transmit or receive\r
+ queue. It is either completed or not issued by\r
+ Transmit() or Receive().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Cancel (\r
+ IN EFI_UDP4_PROTOCOL *This,\r
+ IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+ if (Instance->IsNoMapping) {\r
+ return EFI_NO_MAPPING;\r
+ }\r
+\r
+ if (!Instance->Configured) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ //\r
+ // Cancle the tokens specified by Token for this instance.\r
+ //\r
+ Status = Udp4InstanceCancelToken (Instance, Token);\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This function can be used by network drivers and applications to increase the rate that\r
+ data packets are moved between the communications device and the transmit/receive queues.\r
+ Argumens:\r
+ This - Pointer to the EFI_UDP4_PROTOCOL instance.\r
+\r
+ @retval EFI_SUCCESS Incoming or outgoing data was processed.\r
+ @retval EFI_INVALID_PARAMETER This is NULL.\r
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
+ @retval EFI_TIMEOUT Data was dropped out of the transmit and/or\r
+ receive queue.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Udp4Poll (\r
+ IN EFI_UDP4_PROTOCOL *This\r
+ )\r
+{\r
+ UDP4_INSTANCE_DATA *Instance;\r
+ EFI_IP4_PROTOCOL *Ip;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
+ Ip = Instance->IpInfo->Ip;\r
+\r
+ //\r
+ // Invode the Ip instance consumed by the udp instance to do the poll operation.\r
+ //\r
+ return Ip->Poll (Ip);\r
+}\r