Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
authorvanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 30 Jul 2007 02:37:10 +0000 (02:37 +0000)
committervanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 30 Jul 2007 02:37:10 +0000 (02:37 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3492 6f19259b-4bc3-4df7-8a09-765794883524

113 files changed:
MdeModulePkg/Include/Library/IpIoLib.h
MdeModulePkg/Include/Library/NetLib.h
MdeModulePkg/Include/Protocol/PxeDhcp4.h [new file with mode: 0644]
MdeModulePkg/Include/Protocol/PxeDhcp4CallBack.h [new file with mode: 0644]
MdeModulePkg/Include/Protocol/Tcp.h [new file with mode: 0644]
MdeModulePkg/Library/DxeNetLib/DxeNetLib.c
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc
MdeModulePkg/Universal/Network/ArpDxe/ArpDebug.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.msa [new file with mode: 0644]
MdeModulePkg/Universal/Network/ArpDxe/ArpImpl.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/ArpDxe/ArpImpl.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/ArpDxe/ArpMain.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/ArpDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Driver.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Driver.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.msa [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Impl.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Impl.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Io.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Io.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Option.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Option.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4Config.c
MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDriver.c
MdeModulePkg/Universal/Network/Ip4Dxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Common.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Common.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.msa [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Icmp.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Icmp.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4If.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4If.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Igmp.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Igmp.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Impl.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Input.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Option.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Option.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Output.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Output.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Route.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Route.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c
MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.c
MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h
MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c
MdeModulePkg/Universal/Network/Mtftp4Dxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Driver.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.msa [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Impl.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Impl.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Option.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Option.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Rrq.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Support.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Wrq.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Bc.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Bc.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Dhcp.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Ebc/PxeArch.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Ebc/PxeArch.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Hton.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Ia32/PxeArch.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Ip.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Ipf/PxeArch.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/PxeBcDxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/PxeBcDxe.msa [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_arp.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_dhcp.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_igmp.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_ip.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_mtftp.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_udp.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_loadfile.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/Tftp.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeBcDxe/X64/PxeArch.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4.h [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.msa [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4InitSelect.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Release.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4RenewRebind.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Run.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Setup.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/Support.c [new file with mode: 0644]
MdeModulePkg/Universal/Network/SnpDxe/snp.h
MdeModulePkg/Universal/Network/SnpDxe/start.c
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dispatcher.c
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Driver.c
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Io.c
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Main.c
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Main.h
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Misc.c
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Driver.c
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.c
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Main.c

index 894e07bed4f08cabff6480931b45a24d49935ee7..e2c9f67559ef81631efbd9b7fc510bbd9c648da0 100644 (file)
@@ -73,11 +73,6 @@ typedef struct _ICMP_ERROR_INFO {
   BOOLEAN     Notify;\r
 } ICMP_ERROR_INFO;\r
 
-//
-// Driver Consumed Protocol Prototypes
-//
-//@MT:#include EFI_PROTOCOL_CONSUMER (Ip4)
-//@MT:#include EFI_PROTOCOL_CONSUMER (Udp4)
 
 #define EFI_IP4_HEADER_LEN(HdrPtr) ((HdrPtr)->HeaderLength << 2)
 
index 150b97936ea26a0337a1b5910b4175ecf5d28e2d..fe240442ae812410e1c38948e329ad11f1acb8c4 100644 (file)
@@ -29,189 +29,189 @@ Abstract:
 #include <Protocol/DriverConfiguration.h>
 #include <Protocol/DriverDiagnostics.h>
 
-#define EFI_NET_LITTLE_ENDIAN
-
-typedef UINT32          IP4_ADDR;
-typedef UINT32          TCP_SEQNO;
-typedef UINT16          TCP_PORTNO;
-
-enum {
-  NET_ETHER_ADDR_LEN    = 6,
-  NET_IFTYPE_ETHERNET   = 0x01,
-
-  EFI_IP_PROTO_UDP      = 0x11,
-  EFI_IP_PROTO_TCP      = 0x06,
-  EFI_IP_PROTO_ICMP     = 0x01,
-
-  //
-  // The address classfication
-  //
-  IP4_ADDR_CLASSA       = 1,
-  IP4_ADDR_CLASSB,
-  IP4_ADDR_CLASSC,
-  IP4_ADDR_CLASSD,
-  IP4_ADDR_CLASSE,
-
-  IP4_MASK_NUM          = 33,
-};
-
-#pragma pack(1)
-
-//
-// Ethernet head definition
-//
-typedef struct {
-  UINT8                 DstMac [NET_ETHER_ADDR_LEN];
-  UINT8                 SrcMac [NET_ETHER_ADDR_LEN];
-  UINT16                EtherType;
-} ETHER_HEAD;
-
-
-//
-// The EFI_IP4_HEADER is hard to use because the source and
-// destination address are defined as EFI_IPv4_ADDRESS, which
-// is a structure. Two structures can't be compared or masked
-// directly. This is why there is an internal representation.
-//
-typedef struct {
-#ifdef EFI_NET_LITTLE_ENDIAN
-  UINT8                 HeadLen : 4;
-  UINT8                 Ver     : 4;
-#else
-  UINT8                 Ver     : 4;
-  UINT8                 HeadLen : 4;
-#endif
-  UINT8                 Tos;
-  UINT16                TotalLen;
-  UINT16                Id;
-  UINT16                Fragment;
-  UINT8                 Ttl;
-  UINT8                 Protocol;
-  UINT16                Checksum;
-  IP4_ADDR              Src;
-  IP4_ADDR              Dst;
-} IP4_HEAD;
-
-
-//
-// ICMP head definition. ICMP message is categoried as either an error
-// message or query message. Two message types have their own head format.
-//
-typedef struct {
-  UINT8                 Type;
-  UINT8                 Code;
-  UINT16                Checksum;
-} IP4_ICMP_HEAD;
-
-typedef struct {
-  IP4_ICMP_HEAD         Head;
-  UINT32                Fourth; // 4th filed of the head, it depends on Type.
-  IP4_HEAD              IpHead;
-} IP4_ICMP_ERROR_HEAD;
-
-typedef struct {
-  IP4_ICMP_HEAD         Head;
-  UINT16                Id;
-  UINT16                Seq;
-} IP4_ICMP_QUERY_HEAD;
-
-
-//
-// UDP header definition
-//
-typedef struct {
-  UINT16                SrcPort;
-  UINT16                DstPort;
-  UINT16                Length;
-  UINT16                Checksum;
-} EFI_UDP4_HEADER;
-
-
-//
-// TCP header definition
-//
-typedef struct {
-  TCP_PORTNO            SrcPort;
-  TCP_PORTNO            DstPort;
-  TCP_SEQNO             Seq;
-  TCP_SEQNO             Ack;
-#ifdef EFI_NET_LITTLE_ENDIAN
-  UINT8                 Res     : 4;
-  UINT8                 HeadLen : 4;
-#else
-  UINT8                 HeadLen : 4;
-  UINT8                 Res     : 4;
-#endif
-  UINT8                 Flag;
-  UINT16                Wnd;
-  UINT16                Checksum;
-  UINT16                Urg;
-} TCP_HEAD;
-
-#pragma pack()
-
-#define NET_MAC_EQUAL(pMac1, pMac2, Len)     \
-    (NetCompareMem ((pMac1), (pMac2), Len) == 0)
-
-#define NET_MAC_IS_MULTICAST(Mac, BMac, Len) \
-    (((*((UINT8 *) Mac) & 0x01) == 0x01) && (!NET_MAC_EQUAL (Mac, BMac, Len)))
-
-#ifdef EFI_NET_LITTLE_ENDIAN
-#define NTOHL(x) (UINT32)((((UINT32) (x) & 0xff)     << 24) | \
-                          (((UINT32) (x) & 0xff00)   << 8)  | \
-                          (((UINT32) (x) & 0xff0000) >> 8)  | \
-                          (((UINT32) (x) & 0xff000000) >> 24))
-
-#define HTONL(x)  NTOHL(x)
-
-#define NTOHS(x)  (UINT16)((((UINT16) (x) & 0xff) << 8) | \
-                           (((UINT16) (x) & 0xff00) >> 8))
-
-#define HTONS(x)  NTOHS(x)
-#else
-#define NTOHL(x)  (UINT32)(x)
-#define HTONL(x)  (UINT32)(x)
-#define NTOHS(x)  (UINT16)(x)
-#define HTONS(x)  (UINT16)(x)
-#endif
-
-//
-// Test the IP's attribute, All the IPs are in host byte order.
-//
-#define IP4_IS_MULTICAST(Ip)              (((Ip) & 0xF0000000) == 0xE0000000)
-#define IP4_IS_LOCAL_BROADCAST(Ip)        ((Ip) == 0xFFFFFFFF)
-#define IP4_NET_EQUAL(Ip1, Ip2, NetMask)  (((Ip1) & (NetMask)) == ((Ip2) & (NetMask)))
-#define IP4_IS_VALID_NETMASK(Ip)          (NetGetMaskLength (Ip) != IP4_MASK_NUM)
-
-//
-// Convert the EFI_IP4_ADDRESS to plain UINT32 IP4 address.
-//
-#define EFI_IP4(EfiIpAddr)                (*(IP4_ADDR *) ((EfiIpAddr).Addr))
-#define EFI_NTOHL(EfiIp)                  (NTOHL (EFI_IP4 ((EfiIp))))
-#define EFI_IP_EQUAL(Ip1, Ip2)            (EFI_IP4 (Ip1) == EFI_IP4 (Ip2))
-
-INTN
-NetGetMaskLength (
-  IN IP4_ADDR               Mask
-  );
-
-INTN
-NetGetIpClass (
-  IN IP4_ADDR               Addr
-  );
-
-BOOLEAN
-Ip4IsUnicast (
-  IN IP4_ADDR               Ip,
-  IN IP4_ADDR               NetMask
-  );
-
+#define EFI_NET_LITTLE_ENDIAN\r
+\r
+typedef UINT32          IP4_ADDR;\r
+typedef UINT32          TCP_SEQNO;\r
+typedef UINT16          TCP_PORTNO;\r
+\r
+enum {\r
+  NET_ETHER_ADDR_LEN    = 6,\r
+  NET_IFTYPE_ETHERNET   = 0x01,\r
+\r
+  EFI_IP_PROTO_UDP      = 0x11,\r
+  EFI_IP_PROTO_TCP      = 0x06,\r
+  EFI_IP_PROTO_ICMP     = 0x01,\r
+\r
+  //\r
+  // The address classfication\r
+  //\r
+  IP4_ADDR_CLASSA       = 1,\r
+  IP4_ADDR_CLASSB,\r
+  IP4_ADDR_CLASSC,\r
+  IP4_ADDR_CLASSD,\r
+  IP4_ADDR_CLASSE,\r
+\r
+  IP4_MASK_NUM          = 33,\r
+};\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+// Ethernet head definition\r
+//\r
+typedef struct {\r
+  UINT8                 DstMac [NET_ETHER_ADDR_LEN];\r
+  UINT8                 SrcMac [NET_ETHER_ADDR_LEN];\r
+  UINT16                EtherType;\r
+} ETHER_HEAD;\r
+\r
+\r
+//\r
+// The EFI_IP4_HEADER is hard to use because the source and\r
+// destination address are defined as EFI_IPv4_ADDRESS, which\r
+// is a structure. Two structures can't be compared or masked\r
+// directly. This is why there is an internal representation.\r
+//\r
+typedef struct {\r
+#ifdef EFI_NET_LITTLE_ENDIAN\r
+  UINT8                 HeadLen : 4;\r
+  UINT8                 Ver     : 4;\r
+#else\r
+  UINT8                 Ver     : 4;\r
+  UINT8                 HeadLen : 4;\r
+#endif\r
+  UINT8                 Tos;\r
+  UINT16                TotalLen;\r
+  UINT16                Id;\r
+  UINT16                Fragment;\r
+  UINT8                 Ttl;\r
+  UINT8                 Protocol;\r
+  UINT16                Checksum;\r
+  IP4_ADDR              Src;\r
+  IP4_ADDR              Dst;\r
+} IP4_HEAD;\r
+\r
+\r
+//\r
+// ICMP head definition. ICMP message is categoried as either an error\r
+// message or query message. Two message types have their own head format.\r
+//\r
+typedef struct {\r
+  UINT8                 Type;\r
+  UINT8                 Code;\r
+  UINT16                Checksum;\r
+} IP4_ICMP_HEAD;\r
+\r
+typedef struct {\r
+  IP4_ICMP_HEAD         Head;\r
+  UINT32                Fourth; // 4th filed of the head, it depends on Type.\r
+  IP4_HEAD              IpHead;\r
+} IP4_ICMP_ERROR_HEAD;\r
+\r
+typedef struct {\r
+  IP4_ICMP_HEAD         Head;\r
+  UINT16                Id;\r
+  UINT16                Seq;\r
+} IP4_ICMP_QUERY_HEAD;\r
+\r
+\r
+//\r
+// UDP header definition\r
+//\r
+typedef struct {\r
+  UINT16                SrcPort;\r
+  UINT16                DstPort;\r
+  UINT16                Length;\r
+  UINT16                Checksum;\r
+} EFI_UDP4_HEADER;\r
+\r
+\r
+//\r
+// TCP header definition\r
+//\r
+typedef struct {\r
+  TCP_PORTNO            SrcPort;\r
+  TCP_PORTNO            DstPort;\r
+  TCP_SEQNO             Seq;\r
+  TCP_SEQNO             Ack;\r
+#ifdef EFI_NET_LITTLE_ENDIAN\r
+  UINT8                 Res     : 4;\r
+  UINT8                 HeadLen : 4;\r
+#else\r
+  UINT8                 HeadLen : 4;\r
+  UINT8                 Res     : 4;\r
+#endif\r
+  UINT8                 Flag;\r
+  UINT16                Wnd;\r
+  UINT16                Checksum;\r
+  UINT16                Urg;\r
+} TCP_HEAD;\r
+\r
+#pragma pack()\r
+\r
+#define NET_MAC_EQUAL(pMac1, pMac2, Len)     \\r
+    (NetCompareMem ((pMac1), (pMac2), Len) == 0)\r
+\r
+#define NET_MAC_IS_MULTICAST(Mac, BMac, Len) \\r
+    (((*((UINT8 *) Mac) & 0x01) == 0x01) && (!NET_MAC_EQUAL (Mac, BMac, Len)))\r
+\r
+#ifdef EFI_NET_LITTLE_ENDIAN\r
+#define NTOHL(x) (UINT32)((((UINT32) (x) & 0xff)     << 24) | \\r
+                          (((UINT32) (x) & 0xff00)   << 8)  | \\r
+                          (((UINT32) (x) & 0xff0000) >> 8)  | \\r
+                          (((UINT32) (x) & 0xff000000) >> 24))\r
+\r
+#define HTONL(x)  NTOHL(x)\r
+\r
+#define NTOHS(x)  (UINT16)((((UINT16) (x) & 0xff) << 8) | \\r
+                           (((UINT16) (x) & 0xff00) >> 8))\r
+\r
+#define HTONS(x)  NTOHS(x)\r
+#else\r
+#define NTOHL(x)  (UINT32)(x)\r
+#define HTONL(x)  (UINT32)(x)\r
+#define NTOHS(x)  (UINT16)(x)\r
+#define HTONS(x)  (UINT16)(x)\r
+#endif\r
+\r
+//\r
+// Test the IP's attribute, All the IPs are in host byte order.\r
+//\r
+#define IP4_IS_MULTICAST(Ip)              (((Ip) & 0xF0000000) == 0xE0000000)\r
+#define IP4_IS_LOCAL_BROADCAST(Ip)        ((Ip) == 0xFFFFFFFF)\r
+#define IP4_NET_EQUAL(Ip1, Ip2, NetMask)  (((Ip1) & (NetMask)) == ((Ip2) & (NetMask)))\r
+#define IP4_IS_VALID_NETMASK(Ip)          (NetGetMaskLength (Ip) != IP4_MASK_NUM)\r
+\r
+//\r
+// Convert the EFI_IP4_ADDRESS to plain UINT32 IP4 address.\r
+//\r
+#define EFI_IP4(EfiIpAddr)       (*(IP4_ADDR *) ((EfiIpAddr).Addr))\r
+#define EFI_NTOHL(EfiIp)         (NTOHL (EFI_IP4 ((EfiIp))))\r
+#define EFI_IP4_EQUAL(Ip1, Ip2)  (NetCompareMem (&(Ip1), &(Ip2), sizeof (EFI_IPv4_ADDRESS)) == 0)\r
+\r
+INTN\r
+NetGetMaskLength (\r
+  IN IP4_ADDR               Mask\r
+  );\r
+\r
+INTN\r
+NetGetIpClass (\r
+  IN IP4_ADDR               Addr\r
+  );\r
+\r
+BOOLEAN\r
+Ip4IsUnicast (\r
+  IN IP4_ADDR               Ip,\r
+  IN IP4_ADDR               NetMask\r
+  );\r
+\r
 extern IP4_ADDR mIp4AllMasks [IP4_MASK_NUM];
 
-//@MT:#include EFI_PROTOCOL_CONSUMER (LoadedImage)
-//@MT:#include EFI_PROTOCOL_CONSUMER (ServiceBinding)
-//@MT:#include EFI_PROTOCOL_CONSUMER (SimpleNetwork)
 
+extern EFI_IPv4_ADDRESS  mZeroIp4Addr;
+
+#define NET_IS_DIGIT(Ch)  (('0' <= (Ch)) && ((Ch) <= '9'))
 //
 // Wrap functions to ease the impact of EFI library changes.
 //
diff --git a/MdeModulePkg/Include/Protocol/PxeDhcp4.h b/MdeModulePkg/Include/Protocol/PxeDhcp4.h
new file mode 100644 (file)
index 0000000..53fe743
--- /dev/null
@@ -0,0 +1,350 @@
+/*++\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
+  PxeDhcp4.h\r
+\r
+Abstract:\r
+  EFI PXE DHCPv4 protocol definition\r
+\r
+--*/\r
+\r
+#ifndef _PXEDHCP4_H_\r
+#define _PXEDHCP4_H_\r
+\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+//\r
+// PXE DHCPv4 GUID definition\r
+//\r
+\r
+#define EFI_PXE_DHCP4_PROTOCOL_GUID \\r
+  { 0x03c4e624, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x29, 0x3f, 0xc1, 0x4d } }\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+//\r
+// Interface definition\r
+//\r
+\r
+typedef struct _EFI_PXE_DHCP4_PROTOCOL EFI_PXE_DHCP4_PROTOCOL;\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+//\r
+// Descriptions of the DHCP version 4 header and options can be found\r
+// in RFC-2131 and RFC-2132 at www.ietf.org\r
+//\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+\r
+  UINT8 op;\r
+#define BOOTP_REQUEST   1\r
+#define BOOTP_REPLY   2\r
+\r
+  UINT8 htype;\r
+\r
+  UINT8 hlen;\r
+\r
+  UINT8 hops;\r
+\r
+  UINT32 xid;\r
+\r
+  UINT16 secs;\r
+#define DHCP4_INITIAL_SECONDS 4\r
+\r
+  UINT16 flags;\r
+#define DHCP4_BROADCAST_FLAG  0x8000\r
+\r
+  UINT32 ciaddr;\r
+\r
+  UINT32 yiaddr;\r
+\r
+  UINT32 siaddr;\r
+\r
+  UINT32 giaddr;\r
+\r
+  UINT8 chaddr[16];\r
+\r
+  UINT8 sname[64];\r
+\r
+  UINT8 fname[128];\r
+\r
+//\r
+// This is the minimum option length as specified in RFC-2131.\r
+// The packet must be padded out this far with DHCP4_PAD.\r
+// DHCPv4 packets are usually 576 bytes in length.  This length\r
+// includes the IPv4 and UDPv4 headers but not the media header.\r
+// Note: Not all DHCP relay agents will forward DHCPv4 packets\r
+// if they are less than 384 bytes or exceed 576 bytes.  Even if\r
+// the underlying hardware can handle smaller and larger packets,\r
+// many older relay agents will not accept them.\r
+//\r
+  UINT32 magik;\r
+#define DHCP4_MAGIK_NUMBER  0x63825363\r
+\r
+  UINT8 options[308];\r
+\r
+} DHCP4_HEADER;\r
+#pragma pack()\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+//\r
+// DHCPv4 packet definition.  Room for 576 bytes including IP and\r
+// UDP header.\r
+//\r
+\r
+#define DHCP4_MAX_PACKET_SIZE     576\r
+#define DHCP4_UDP_HEADER_SIZE     8\r
+#define DHCP4_IP_HEADER_SIZE      20\r
+\r
+#pragma pack(1)\r
+typedef union _DHCP4_PACKET {\r
+  UINT32 _force_data_alignment;\r
+\r
+  UINT8 raw[1500];\r
+\r
+  DHCP4_HEADER dhcp4;\r
+} DHCP4_PACKET;\r
+#pragma pack()\r
+\r
+#define DHCP4_SERVER_PORT 67\r
+#define DHCP4_CLIENT_PORT 68\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+//\r
+// DHCPv4 and PXE option numbers.\r
+//\r
+\r
+#define DHCP4_PAD                             0\r
+#define DHCP4_END                             255\r
+#define DHCP4_SUBNET_MASK                     1\r
+#define DHCP4_TIME_OFFSET                     2\r
+#define DHCP4_ROUTER_LIST                     3\r
+#define DHCP4_TIME_SERVERS                    4\r
+#define DHCP4_NAME_SERVERS                    5\r
+#define DHCP4_DNS_SERVERS                     6\r
+#define DHCP4_LOG_SERVERS                     7\r
+#define DHCP4_COOKIE_SERVERS                  8\r
+#define DHCP4_LPR_SREVERS                     9\r
+#define DHCP4_IMPRESS_SERVERS                 10\r
+#define DHCP4_RESOURCE_LOCATION_SERVERS       11\r
+#define DHCP4_HOST_NAME                       12\r
+#define DHCP4_BOOT_FILE_SIZE                  13\r
+#define DHCP4_DUMP_FILE                       14\r
+#define DHCP4_DOMAIN_NAME                     15\r
+#define DHCP4_SWAP_SERVER                     16\r
+#define DHCP4_ROOT_PATH                       17\r
+#define DHCP4_EXTENSION_PATH                  18\r
+#define DHCP4_IP_FORWARDING                   19\r
+#define DHCP4_NON_LOCAL_SOURCE_ROUTE          20\r
+#define DHCP4_POLICY_FILTER                   21\r
+#define DHCP4_MAX_DATAGRAM_SIZE               22\r
+#define DHCP4_DEFAULT_TTL                     23\r
+#define DHCP4_MTU_AGING_TIMEOUT               24\r
+#define DHCP4_MTU_SIZES                       25\r
+#define DHCP4_MTU_TO_USE                      26\r
+#define DHCP4_ALL_SUBNETS_LOCAL               27\r
+#define DHCP4_BROADCAST_ADDRESS               28\r
+#define DHCP4_PERFORM_MASK_DISCOVERY          29\r
+#define DHCP4_RESPOND_TO_MASK_REQ             30\r
+#define DHCP4_PERFORM_ROUTER_DISCOVERY        31\r
+#define DHCP4_ROUTER_SOLICIT_ADDRESS          32\r
+#define DHCP4_STATIC_ROUTER_LIST              33\r
+#define DHCP4_USE_ARP_TRAILERS                34\r
+#define DHCP4_ARP_CACHE_TIMEOUT               35\r
+#define DHCP4_ETHERNET_ENCAPSULATION          36\r
+#define DHCP4_TCP_DEFAULT_TTL                 37\r
+#define DHCP4_TCP_KEEP_ALIVE_INT              38\r
+#define DHCP4_KEEP_ALIVE_GARBAGE              39\r
+#define DHCP4_NIS_DOMAIN_NAME                 40\r
+#define DHCP4_NIS_SERVERS                     41\r
+#define DHCP4_NTP_SERVERS                     42\r
+#define DHCP4_VENDOR_SPECIFIC                 43\r
+# define PXE_MTFTP_IP                         1\r
+# define PXE_MTFTP_CPORT                      2\r
+# define PXE_MTFTP_SPORT                      3\r
+# define PXE_MTFTP_TMOUT                      4\r
+# define PXE_MTFTP_DELAY                      5\r
+# define PXE_DISCOVERY_CONTROL                6\r
+#  define PXE_DISABLE_BROADCAST_DISCOVERY     0x01\r
+#  define PXE_DISABLE_MULTICAST_DISCOVERY     0x02\r
+#  define PXE_ACCEPT_ONLY_PXE_BOOT_SERVERS    0x04\r
+#  define PXE_DO_NOT_PROMPT                   0x08\r
+# define PXE_DISCOVERY_MCAST_ADDR             7\r
+# define PXE_BOOT_SERVERS                     8\r
+# define PXE_BOOT_MENU                        9\r
+# define PXE_BOOT_PROMPT                      10\r
+# define PXE_MCAST_ADDRS_ALLOC                11\r
+# define PXE_CREDENTIAL_TYPES                 12\r
+# define PXE_BOOT_ITEM                        71\r
+#define DHCP4_NBNS_SERVERS                    44\r
+#define DHCP4_NBDD_SERVERS                    45\r
+#define DHCP4_NETBIOS_NODE_TYPE               46\r
+#define DHCP4_NETBIOS_SCOPE                   47\r
+#define DHCP4_XWINDOW_SYSTEM_FONT_SERVERS     48\r
+#define DHCP4_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49\r
+#define DHCP4_REQUESTED_IP_ADDRESS            50\r
+#define DHCP4_LEASE_TIME                      51\r
+#define DHCP4_OPTION_OVERLOAD                 52\r
+# define DHCP4_OVERLOAD_FNAME                 1\r
+# define DHCP4_OVERLOAD_SNAME                 2\r
+# define DHCP4_OVERLOAD_FNAME_AND_SNAME       3\r
+#define DHCP4_MESSAGE_TYPE                    53\r
+# define DHCP4_MESSAGE_TYPE_DISCOVER          1\r
+# define DHCP4_MESSAGE_TYPE_OFFER             2\r
+# define DHCP4_MESSAGE_TYPE_REQUEST           3\r
+# define DHCP4_MESSAGE_TYPE_DECLINE           4\r
+# define DHCP4_MESSAGE_TYPE_ACK               5\r
+# define DHCP4_MESSAGE_TYPE_NAK               6\r
+# define DHCP4_MESSAGE_TYPE_RELEASE           7\r
+# define DHCP4_MESSAGE_TYPE_INFORM            8\r
+#define DHCP4_SERVER_IDENTIFIER               54\r
+#define DHCP4_PARAMETER_REQUEST_LIST          55\r
+#define DHCP4_ERROR_MESSAGE                   56\r
+#define DHCP4_MAX_MESSAGE_SIZE                57\r
+# define DHCP4_DEFAULT_MAX_MESSAGE_SIZE       576\r
+#define DHCP4_RENEWAL_TIME                    58\r
+#define DHCP4_REBINDING_TIME                  59\r
+#define DHCP4_CLASS_IDENTIFIER                60\r
+#define DHCP4_CLIENT_IDENTIFIER               61\r
+#define DHCP4_NISPLUS_DOMAIN_NAME             64\r
+#define DHCP4_NISPLUS_SERVERS                 65\r
+#define DHCP4_TFTP_SERVER_NAME                66\r
+#define DHCP4_BOOTFILE                        67\r
+#define DHCP4_MOBILE_IP_HOME_AGENTS           68\r
+#define DHCP4_SMPT_SERVERS                    69\r
+#define DHCP4_POP3_SERVERS                    70\r
+#define DHCP4_NNTP_SERVERS                    71\r
+#define DHCP4_WWW_SERVERS                     72\r
+#define DHCP4_FINGER_SERVERS                  73\r
+#define DHCP4_IRC_SERVERS                     74\r
+#define DHCP4_STREET_TALK_SERVERS             75\r
+#define DHCP4_STREET_TALK_DIR_ASSIST_SERVERS  76\r
+#define DHCP4_NDS_SERVERS                     85\r
+#define DHCP4_NDS_TREE_NAME                   86\r
+#define DHCP4_NDS_CONTEXT                     87\r
+#define DHCP4_SYSTEM_ARCHITECTURE             93\r
+#define DHCP4_NETWORK_ARCHITECTURE            94\r
+#define DHCP4_PLATFORM_ID                     97\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+//\r
+// DHCP4 option format.\r
+//\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8 op;\r
+  UINT8 len;\r
+  UINT8 data[1];\r
+} DHCP4_OP;\r
+#pragma pack()\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+typedef struct {\r
+  DHCP4_PACKET Discover;\r
+  DHCP4_PACKET Offer;\r
+  DHCP4_PACKET Request;\r
+  DHCP4_PACKET AckNak;\r
+  BOOLEAN SetupCompleted;\r
+  BOOLEAN InitCompleted;\r
+  BOOLEAN SelectCompleted;\r
+  BOOLEAN IsBootp;\r
+  BOOLEAN IsAck;\r
+} EFI_PXE_DHCP4_DATA;\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_PXE_DHCP4_RUN) (\r
+  IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+  IN OPTIONAL UINTN         OpLen,\r
+  IN OPTIONAL VOID          *OpList\r
+  );\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_PXE_DHCP4_SETUP) (\r
+  IN EFI_PXE_DHCP4_PROTOCOL          *This,\r
+  IN OPTIONAL EFI_PXE_DHCP4_DATA     * NewData\r
+  );\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_PXE_DHCP4_INIT) (\r
+  IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+  IN UINTN                  SecondsTimeout,\r
+  OUT UINTN                 *Offers,\r
+  OUT DHCP4_PACKET          **OfferList\r
+  );\r
+\r
+#define DHCP4_MIN_SECONDS   1\r
+#define DHCP4_MAX_SECONDS   60\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_PXE_DHCP4_SELECT) (\r
+  IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+  IN UINTN                  SecondsTimeout,\r
+  IN DHCP4_PACKET           * offer\r
+  );\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_PXE_DHCP4_RENEW) (\r
+  IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+  UINTN                     seconds_timeout\r
+  );\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_PXE_DHCP4_REBIND) (\r
+  IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+  UINTN                     seconds_timeout\r
+  );\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_PXE_DHCP4_RELEASE) (\r
+  IN EFI_PXE_DHCP4_PROTOCOL * This\r
+  );\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+#define EFI_PXE_DHCP4_PROTOCOL_REVISION    0x00010000\r
+\r
+struct _EFI_PXE_DHCP4_PROTOCOL {\r
+  UINT64 Revision;\r
+  EFI_PXE_DHCP4_RUN Run;\r
+  EFI_PXE_DHCP4_SETUP Setup;\r
+  EFI_PXE_DHCP4_INIT Init;\r
+  EFI_PXE_DHCP4_SELECT Select;\r
+  EFI_PXE_DHCP4_RENEW Renew;\r
+  EFI_PXE_DHCP4_REBIND Rebind;\r
+  EFI_PXE_DHCP4_RELEASE Release;\r
+  EFI_PXE_DHCP4_DATA *Data;\r
+};\r
+\r
+//\r
+//\r
+//\r
+\r
+extern EFI_GUID gEfiPxeDhcp4ProtocolGuid;\r
+\r
+#endif /* _PXEDHCP4_H_ */\r
+/* EOF - PxeDhcp4.h */\r
diff --git a/MdeModulePkg/Include/Protocol/PxeDhcp4CallBack.h b/MdeModulePkg/Include/Protocol/PxeDhcp4CallBack.h
new file mode 100644 (file)
index 0000000..cfba380
--- /dev/null
@@ -0,0 +1,85 @@
+/*++\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
+  PxeDhcp4Callback.h\r
+\r
+Abstract:\r
+  EFI PXE DHCP4 Callback protocol definition.\r
+\r
+--*/\r
+\r
+#ifndef _PXE_DHCP4CALLBACK_H\r
+#define _PXE_DHCP4CALLBACK_H\r
+\r
+#include <Protocol/PxeDhcp4.h>\r
+//\r
+// GUID definition\r
+//\r
+\r
+#define EFI_PXE_DHCP4_CALLBACK_PROTOCOL_GUID \\r
+{ 0xc1544c01, 0x92a4, 0x4198, {0x8a, 0x84, 0x77, 0x85, 0x83, 0xc2, 0x36, 0x21 } }\r
+\r
+\r
+//\r
+// Revision number\r
+//\r
+\r
+#define EFI_PXE_DHCP4_CALLBACK_INTERFACE_REVISION   0x00010000\r
+\r
+//\r
+// Interface definition\r
+//\r
+\r
+typedef struct _EFI_PXE_DHCP4_CALLBACK_PROTOCOL EFI_PXE_DHCP4_CALLBACK_PROTOCOL;\r
+\r
+typedef enum {\r
+  EFI_PXE_DHCP4_FUNCTION_FIRST,\r
+  EFI_PXE_DHCP4_FUNCTION_INIT,\r
+  EFI_PXE_DHCP4_FUNCTION_SELECT,\r
+  EFI_PXE_DHCP4_FUNCTION_RENEW,\r
+  EFI_PXE_DHCP4_FUNCTION_REBIND,\r
+  EFI_PXE_DHCP4_FUNCTION_LAST\r
+} EFI_PXE_DHCP4_FUNCTION;\r
+\r
+typedef enum {\r
+  EFI_PXE_DHCP4_CALLBACK_STATUS_FIRST,\r
+  EFI_PXE_DHCP4_CALLBACK_STATUS_ABORT,\r
+  EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_ABORT,\r
+  EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_ABORT,\r
+  EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE,\r
+  EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_CONTINUE,\r
+  EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE,\r
+  EFI_PXE_DHCP4_CALLBACK_STATUS_LAST\r
+} EFI_PXE_DHCP4_CALLBACK_STATUS;\r
+\r
+typedef\r
+EFI_PXE_DHCP4_CALLBACK_STATUS\r
+(EFIAPI *EFI_PXE_DHCP4_CALLBACK) (\r
+  IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+  IN EFI_PXE_DHCP4_FUNCTION Function,\r
+  IN UINT32                 PacketLen,\r
+  IN DHCP4_PACKET           *Packet OPTIONAL\r
+  );\r
+\r
+struct _EFI_PXE_DHCP4_CALLBACK_PROTOCOL {\r
+  UINT64                      Revision;\r
+  EFI_PXE_DHCP4_CALLBACK      Callback;\r
+};\r
+\r
+//\r
+// GUID declaration\r
+//\r
+\r
+extern EFI_GUID gEfiPxeDhcp4CallbackProtocolGuid;\r
+\r
+#endif /* _PXE_DHCP4CALLBACK_H */\r
+/* EOF - PxeDhcp4Callback.h */\r
diff --git a/MdeModulePkg/Include/Protocol/Tcp.h b/MdeModulePkg/Include/Protocol/Tcp.h
new file mode 100644 (file)
index 0000000..f49915c
--- /dev/null
@@ -0,0 +1,108 @@
+/*++\r
+\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
+\r
+    tcp.h\r
+\r
+Abstract:\r
+\r
+    EFI Transmission Control Protocol\r
+\r
+\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+\r
+#ifndef _EFITCP_H\r
+#define _EFITCP_H\r
+\r
+\r
+#include <Protocol/PxeBaseCode.h>\r
+\r
+//\r
+// PXE Base Code protocol\r
+//\r
+\r
+#define EFI_TCP_PROTOCOL_GUID \\r
+    { 0x02b3d5f2, 0xac28, 0x11d3, { 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}\r
+\r
+\r
+typedef UINT16 EFI_PXE_BASE_CODE_TCP_PORT;\r
+\r
+//\r
+// Port Receive Filter definitions\r
+//\r
+#define EFI_PXE_BASE_CODE_MAX_PORTCNT             8\r
+typedef struct {\r
+    UINT8                       Filters;\r
+    UINT8                       IpCnt;\r
+    UINT16                      reserved;\r
+    EFI_IP_ADDRESS              IpList[EFI_PXE_BASE_CODE_MAX_PORTCNT];\r
+} EFI_TCP_PORT_FILTER;\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_TCP_WRITE) (\r
+    IN EFI_PXE_BASE_CODE_PROTOCOL        *This,\r
+    IN UINT16                                    OpFlags,\r
+    IN UINT16                                    *UrgentPointer,\r
+    IN UINT32                                    *SequenceNumber,\r
+    IN UINT32                                    *AckNumber,\r
+    IN UINT16                                    *HlenResCode,\r
+    IN UINT16                                    *Window,\r
+    IN EFI_IP_ADDRESS                            *DestIp,\r
+    IN UINT16                                    *DestPort,\r
+    IN EFI_IP_ADDRESS                            *GatewayIp,  OPTIONAL\r
+    IN EFI_IP_ADDRESS                            *SrcIp,      OPTIONAL\r
+    IN UINT16                                    *SrcPort,    OPTIONAL\r
+    IN UINTN                                     *HeaderSize, OPTIONAL\r
+    IN VOID                                      *HeaderPtr,  OPTIONAL\r
+    IN UINTN                                     *BufferSize,\r
+    IN VOID                                      *BufferPtr\r
+    );\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_TCP_READ) (\r
+    IN EFI_PXE_BASE_CODE_PROTOCOL        *This,\r
+    IN UINT16                                    OpFlags,\r
+    IN OUT EFI_IP_ADDRESS                        *DestIp,      OPTIONAL\r
+    IN OUT UINT16                                *DestPort,    OPTIONAL\r
+    IN OUT EFI_IP_ADDRESS                        *SrcIp,       OPTIONAL\r
+    IN OUT UINT16                                *SrcPort,     OPTIONAL\r
+    IN UINTN                                     *HeaderSize,  OPTIONAL\r
+    IN VOID                                      *HeaderPtr,   OPTIONAL\r
+    IN OUT UINTN                                 *BufferSize,\r
+    IN VOID                                      *BufferPtr\r
+    );\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_TCP_SET_PORT_FILTER) (\r
+    IN EFI_PXE_BASE_CODE_PROTOCOL    *This,\r
+    IN EFI_TCP_PORT_FILTER                   *NewFilter\r
+    );\r
+\r
+//\r
+// TCP Protocol structure\r
+//\r
+typedef struct _EFI_TCP_PROTOCOL {\r
+    EFI_TCP_WRITE             TcpWrite;\r
+    EFI_TCP_READ              TcpRead;\r
+    EFI_TCP_SET_PORT_FILTER   SetPortFilter;\r
+} EFI_TCP_PROTOCOL;\r
+\r
+extern EFI_GUID gEfiTcpProtocolGuid;\r
+\r
+#endif /* _EFITCP_H */\r
index dcf2309c71c4d470364df9d1cb226870e9464cb8..9057a03a67a91de5c225fe463491caeb706a3f49 100644 (file)
@@ -77,6 +77,7 @@ IP4_ADDR  mIp4AllMasks[IP4_MASK_NUM] = {
   0xFFFFFFFF,
 };
 
+EFI_IPv4_ADDRESS  mZeroIp4Addr = {0, 0, 0, 0};
 
 /**\r
   Converts the low nibble of a byte  to hex unicode character.\r
index 72f58a1fb68c25e78aa9443720e9f55500a451d6..e6a93479694714f92dd8ed7eb49ae49747ce5fac 100644 (file)
   gEfiNicIp4ConfigProtocolGuid = {0xdca3d4d, 0x12da, 0x4728, { 0xbf, 0x7e, 0x86, 0xce, 0xb9, 0x28, 0xd0, 0x67 }}\r
   gEfiNicIp4ConfigVariableGuid = {0xd8944553, 0xc4dd, 0x41f4, { 0x9b, 0x30, 0xe1, 0x39, 0x7c, 0xfb, 0x26, 0x7b }}\r
 \r
+  gEfiTcpProtocolGuid = { 0x02b3d5f2, 0xac28, 0x11d3, { 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}\r
+  gEfiPxeDhcp4CallbackProtocolGuid = { 0xc1544c01, 0x92a4, 0x4198, {0x8a, 0x84, 0x77, 0x85, 0x83, 0xc2, 0x36, 0x21 } }\r
+  gEfiPxeDhcp4ProtocolGuid = { 0x03c4e624, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x29, 0x3f, 0xc1, 0x4d } }\r
+\r
 [Ppis.common]\r
   gPeiBaseMemoryTestPpiGuid      = { 0xB6EC423C, 0x21D2, 0x490D, { 0x85, 0xC6, 0xDD, 0x58, 0x64, 0xEA, 0xA6, 0x74 }}\r
 \r
index be390f443f66d2f46fd6cdc4fcb437fbc6f88398..90a97c18a65b61917fa2a84e0817cdb2289ef7d5 100644 (file)
@@ -55,7 +55,7 @@
 [LibraryClasses.IPF]\r
   IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf\r
 \r
-[LibraryClasses.EBC.DXE_RUNTIME_DRIVER]\r
+[LibraryClasses.EBC]\r
   IoLib|IntelFrameworkPkg/Library/DxeIoLibCpuIo/DxeIoLibCpuIo.inf\r
 \r
 [LibraryClasses.common.PEI_CORE]\r
   UsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf\r
   NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf\r
   IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf\r
+  UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf\r
 \r
 [LibraryClasses.common.DXE_RUNTIME_DRIVER]\r
   HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf\r
   MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf\r
   MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf\r
 \r
+  MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf\r
+  MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf\r
   MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf\r
+  MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf\r
   MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf\r
+  MdeModulePkg/Universal/Network/PxeBcDxe/PxeBcDxe.inf\r
+  MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.inf\r
   MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf\r
   MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf\r
   MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf\r
diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ArpDebug.h b/MdeModulePkg/Universal/Network/ArpDxe/ArpDebug.h
new file mode 100644 (file)
index 0000000..05f542d
--- /dev/null
@@ -0,0 +1,30 @@
+/** @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:
+
+  ArpDebug.h
+
+Abstract:
+
+
+**/
+
+#ifndef _ARP_DEBUG_H_
+#define _ARP_DEBUG_H_
+
+
+#define ARP_DEBUG_TRACE(PrintArg) NET_DEBUG_TRACE   ("Arp", PrintArg)
+#define ARP_DEBUG_WARN(PrintArg)  NET_DEBUG_WARNING ("Arp", PrintArg)
+#define ARP_DEBUG_ERROR(PrintArg) NET_DEBUG_ERROR   ("Arp", PrintArg)
+
+#endif
+
diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c b/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.c
new file mode 100644 (file)
index 0000000..2c10857
--- /dev/null
@@ -0,0 +1,763 @@
+/** @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
+  ArpDriver.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "ArpDriver.h"\r
+#include "ArpImpl.h"\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gArpDriverBinding = {\r
+  ArpDriverBindingSupported,\r
+  ArpDriverBindingStart,\r
+  ArpDriverBindingStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+\r
+/**\r
+  Create and initialize the arp service context data.\r
+\r
+  @param  ImageHandle            The image handle representing the loaded driver\r
+                                 image.\r
+  @param  ControllerHandle       The controller handle the driver binds to.\r
+  @param  ArpService             Pointer to the buffer containing the arp service\r
+                                 context data.\r
+\r
+  @retval EFI_SUCCESS            The arp service context is initialized.\r
+  @retval other                  Failed to initialize the arp service context.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+ArpCreateService (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_HANDLE        ControllerHandle,\r
+  IN ARP_SERVICE_DATA  *ArpService\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT (ArpService != NULL);\r
+\r
+  ArpService->Signature = ARP_SERVICE_DATA_SIGNATURE;\r
+\r
+  //\r
+  // Init the servicebinding protocol members.\r
+  //\r
+  ArpService->ServiceBinding.CreateChild  = ArpServiceBindingCreateChild;\r
+  ArpService->ServiceBinding.DestroyChild = ArpServiceBindingDestroyChild;\r
+\r
+  //\r
+  // Save the handles.\r
+  //\r
+  ArpService->ImageHandle      = ImageHandle;\r
+  ArpService->ControllerHandle = ControllerHandle;\r
+\r
+  //\r
+  // Create a MNP child instance.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+             ControllerHandle,\r
+             ImageHandle,\r
+             &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+             &ArpService->MnpChildHandle\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Open the MNP protocol.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ArpService->MnpChildHandle,\r
+                  &gEfiManagedNetworkProtocolGuid,\r
+                  (VOID **)&ArpService->Mnp,\r
+                  ImageHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ERROR_EXIT;\r
+  }\r
+\r
+  //\r
+  // Get the underlayer Snp mode data.\r
+  //\r
+  Status = ArpService->Mnp->GetModeData (ArpService->Mnp, NULL, &ArpService->SnpMode);\r
+  if ((Status != EFI_NOT_STARTED) && EFI_ERROR (Status)) {\r
+    goto ERROR_EXIT;\r
+  }\r
+\r
+  if (ArpService->SnpMode.IfType != NET_IFTYPE_ETHERNET) {\r
+    //\r
+    // Only support the ethernet.\r
+    //\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ERROR_EXIT;\r
+  }\r
+\r
+  //\r
+  // Set the Mnp config parameters.\r
+  //\r
+  ArpService->MnpConfigData.ReceivedQueueTimeoutValue = 0;\r
+  ArpService->MnpConfigData.TransmitQueueTimeoutValue = 0;\r
+  ArpService->MnpConfigData.ProtocolTypeFilter        = ARP_ETHER_PROTO_TYPE;\r
+  ArpService->MnpConfigData.EnableUnicastReceive      = TRUE;\r
+  ArpService->MnpConfigData.EnableMulticastReceive    = FALSE;\r
+  ArpService->MnpConfigData.EnableBroadcastReceive    = TRUE;\r
+  ArpService->MnpConfigData.EnablePromiscuousReceive  = FALSE;\r
+  ArpService->MnpConfigData.FlushQueuesOnReset        = TRUE;\r
+  ArpService->MnpConfigData.EnableReceiveTimestamps   = FALSE;\r
+  ArpService->MnpConfigData.DisableBackgroundPolling  = FALSE;\r
+\r
+  //\r
+  // Configure the Mnp child.\r
+  //\r
+  Status = ArpService->Mnp->Configure (ArpService->Mnp, &ArpService->MnpConfigData);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ERROR_EXIT;\r
+  }\r
+\r
+  //\r
+  // Create the event used in the RxToken.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  NET_TPL_EVENT,\r
+                  ArpOnFrameRcvd,\r
+                  ArpService,\r
+                  &ArpService->RxToken.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ERROR_EXIT;\r
+  }\r
+\r
+  //\r
+  // Create the Arp heartbeat timer.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
+                  NET_TPL_TIMER,\r
+                  ArpTimerHandler,\r
+                  ArpService,\r
+                  &ArpService->PeriodicTimer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ERROR_EXIT;\r
+  }\r
+\r
+  //\r
+  // Start the heartbeat timer.\r
+  //\r
+  Status = gBS->SetTimer (\r
+                  ArpService->PeriodicTimer,\r
+                  TimerPeriodic,\r
+                  ARP_PERIODIC_TIMER_INTERVAL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ERROR_EXIT;\r
+  }\r
+\r
+  //\r
+  // Init the lock.\r
+  //\r
+  NET_LOCK_INIT (&ArpService->Lock);\r
+\r
+  //\r
+  // Init the lists.\r
+  //\r
+  NetListInit (&ArpService->ChildrenList);\r
+  NetListInit (&ArpService->PendingRequestTable);\r
+  NetListInit (&ArpService->DeniedCacheTable);\r
+  NetListInit (&ArpService->ResolvedCacheTable);\r
+\r
+ERROR_EXIT:\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clean the arp service context data.\r
+\r
+  @param  ArpService             Pointer to the buffer containing the arp service\r
+                                 context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+ArpCleanService (\r
+  IN ARP_SERVICE_DATA  *ArpService\r
+  )\r
+{\r
+  NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);\r
+\r
+  if (ArpService->PeriodicTimer != NULL) {\r
+    //\r
+    // Cancle and close the PeriodicTimer.\r
+    //\r
+    gBS->SetTimer (ArpService->PeriodicTimer, TimerCancel, 0);\r
+    gBS->CloseEvent (ArpService->PeriodicTimer);\r
+  }\r
+\r
+  if (ArpService->RxToken.Event != NULL) {\r
+    //\r
+    // Cancle the RxToken and close the event in the RxToken.\r
+    //\r
+    ArpService->Mnp->Cancel (ArpService->Mnp, NULL);\r
+    gBS->CloseEvent (ArpService->RxToken.Event);\r
+  }\r
+\r
+  if (ArpService->Mnp != NULL) {\r
+    //\r
+    // Reset the Mnp child and close the Mnp protocol.\r
+    //\r
+    ArpService->Mnp->Configure (ArpService->Mnp, NULL);\r
+    gBS->CloseProtocol (\r
+           ArpService->MnpChildHandle,\r
+           &gEfiManagedNetworkProtocolGuid,\r
+           ArpService->ImageHandle,\r
+           ArpService->ControllerHandle\r
+           );\r
+  }\r
+\r
+  if (ArpService->MnpChildHandle != NULL) {\r
+    //\r
+    // Destroy the mnp child.\r
+    //\r
+    NetLibDestroyServiceChild(\r
+      ArpService->ControllerHandle,\r
+      ArpService->ImageHandle,\r
+      &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+      ArpService->MnpChildHandle\r
+      );\r
+  }\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
+ArpDriverBindingSupported (\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 Arp SB is already installed.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiArpServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (Status == EFI_SUCCESS) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  //\r
+  // Test to see if MNP SB is 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
+\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
+ArpDriverBindingStart (\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
+  ARP_SERVICE_DATA  *ArpService;\r
+\r
+  //\r
+  // Allocate a zero pool for ArpService.\r
+  //\r
+  ArpService = NetAllocateZeroPool (sizeof(ARP_SERVICE_DATA));\r
+  if (ArpService == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Initialize the arp service context data.\r
+  //\r
+  Status = ArpCreateService (This->DriverBindingHandle, ControllerHandle, ArpService);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ERROR;\r
+  }\r
+\r
+  //\r
+  // Install the ARP service binding protocol.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &ControllerHandle,\r
+                  &gEfiArpServiceBindingProtocolGuid,\r
+                  &ArpService->ServiceBinding,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ERROR;\r
+  }\r
+\r
+  //\r
+  // OK, start to receive arp packets from Mnp.\r
+  //\r
+  Status = ArpService->Mnp->Receive (ArpService->Mnp, &ArpService->RxToken);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ERROR;\r
+  }\r
+\r
+  return Status;\r
+\r
+ERROR:\r
+\r
+  //\r
+  // On error, clean the arp service context data, and free the memory allocated.\r
+  //\r
+  ArpCleanService (ArpService);\r
+  NetFreePool (ArpService);\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
+ArpDriverBindingStop (\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
+  ARP_SERVICE_DATA              *ArpService;\r
+  ARP_INSTANCE_DATA             *Instance;\r
+\r
+  //\r
+  // Get the NicHandle which the arp servicebinding is installed on.\r
+  //\r
+  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);\r
+  if (NicHandle == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Try to get the arp servicebinding protocol on the NicHandle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  NicHandle,\r
+                  &gEfiArpServiceBindingProtocolGuid,\r
+                  (VOID **)&ServiceBinding,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    ARP_DEBUG_ERROR (("ArpDriverBindingStop: Open ArpSb failed, %r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  ArpService = ARP_SERVICE_DATA_FROM_THIS (ServiceBinding);\r
+\r
+  while (!NetListIsEmpty (&ArpService->ChildrenList)) {\r
+    //\r
+    // Iterate all the instances.\r
+    //\r
+    Instance = NET_LIST_HEAD (&ArpService->ChildrenList, ARP_INSTANCE_DATA, List);\r
+\r
+    //\r
+    // Destroy this arp child.\r
+    //\r
+    ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);\r
+  }\r
+\r
+  ASSERT (NetListIsEmpty (&ArpService->PendingRequestTable));\r
+  ASSERT (NetListIsEmpty (&ArpService->DeniedCacheTable));\r
+  ASSERT (NetListIsEmpty (&ArpService->ResolvedCacheTable));\r
+\r
+  //\r
+  // Uninstall the ARP ServiceBinding protocol.\r
+  //\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  NicHandle,\r
+                  &gEfiArpServiceBindingProtocolGuid,\r
+                  &ArpService->ServiceBinding,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    ARP_DEBUG_ERROR (("ArpDriverBindingStop: Failed to uninstall ArpSb, %r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Clean the arp servicebinding context data and free the memory allocated.\r
+  //\r
+  ArpCleanService (ArpService);\r
+  NetFreePool (ArpService);\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
+ArpServiceBindingCreateChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    *ChildHandle\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  ARP_SERVICE_DATA   *ArpService;\r
+  ARP_INSTANCE_DATA  *Instance;\r
+  VOID               *Mnp;\r
+\r
+  if ((This == NULL) || (ChildHandle == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ArpService = ARP_SERVICE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Allocate memory for the instance context data.\r
+  //\r
+  Instance = NetAllocateZeroPool (sizeof(ARP_INSTANCE_DATA));\r
+  if (Instance == NULL) {\r
+    ARP_DEBUG_ERROR (("ArpSBCreateChild: Failed to allocate memory for Instance.\n"));\r
+\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Init the instance context data.\r
+  //\r
+  ArpInitInstance (ArpService, Instance);\r
+\r
+  //\r
+  // Install the ARP protocol onto the ChildHandle.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  ChildHandle,\r
+                  &gEfiArpProtocolGuid,\r
+                  (VOID *)&Instance->ArpProto,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    ARP_DEBUG_ERROR (("ArpSBCreateChild: faild to install ARP protocol, %r.\n", Status));\r
+\r
+    NetFreePool (Instance);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Save the ChildHandle.\r
+  //\r
+  Instance->Handle = *ChildHandle;\r
+\r
+  //\r
+  // Open the Managed Network protocol BY_CHILD.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ArpService->MnpChildHandle,\r
+                  &gEfiManagedNetworkProtocolGuid,\r
+                  (VOID **) &Mnp,\r
+                  gArpDriverBinding.DriverBindingHandle,\r
+                  Instance->Handle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ERROR;\r
+  }\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {\r
+\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto ERROR;\r
+  }\r
+\r
+  //\r
+  // Insert the instance into children list managed by the arp service context data.\r
+  //\r
+  NetListInsertTail (&ArpService->ChildrenList, &Instance->List);\r
+  ArpService->ChildrenNumber++;\r
+\r
+  NET_UNLOCK (&ArpService->Lock);\r
+\r
+ERROR:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    gBS->CloseProtocol (\r
+           ArpService->MnpChildHandle,\r
+           &gEfiManagedNetworkProtocolGuid,\r
+           gArpDriverBinding.DriverBindingHandle,\r
+           Instance->Handle\r
+           );\r
+\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+           Instance->Handle,\r
+           &gEfiArpProtocolGuid,\r
+           &Instance->ArpProto,\r
+           NULL\r
+           );\r
+\r
+    //\r
+    // Free the allocated memory.\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
+ArpServiceBindingDestroyChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    ChildHandle\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  ARP_SERVICE_DATA   *ArpService;\r
+  ARP_INSTANCE_DATA  *Instance;\r
+  EFI_ARP_PROTOCOL   *Arp;\r
+\r
+  if ((This == NULL) || (ChildHandle == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ArpService = ARP_SERVICE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Get the arp protocol.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ChildHandle,\r
+                  &gEfiArpProtocolGuid,\r
+                  (VOID **)&Arp,\r
+                  ArpService->ImageHandle,\r
+                  ChildHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Instance = ARP_INSTANCE_DATA_FROM_THIS (Arp);\r
+\r
+  if (Instance->Destroyed) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Use the Destroyed as a flag to avoid re-entrance.\r
+  //\r
+  Instance->Destroyed = TRUE;\r
+\r
+  //\r
+  // Close the Managed Network protocol.\r
+  //\r
+  gBS->CloseProtocol (\r
+         ArpService->MnpChildHandle,\r
+         &gEfiManagedNetworkProtocolGuid,\r
+         gArpDriverBinding.DriverBindingHandle,\r
+         ChildHandle\r
+         );\r
+\r
+  //\r
+  // Uninstall the ARP protocol.\r
+  //\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  ChildHandle,\r
+                  &gEfiArpProtocolGuid,\r
+                  &Instance->ArpProto,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    ARP_DEBUG_ERROR (("ArpSBDestroyChild: Failed to uninstall the arp protocol, %r.\n",\r
+      Status));\r
+\r
+    Instance->Destroyed = FALSE;\r
+    return Status;\r
+  }\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {\r
+    Instance->Destroyed = FALSE;\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (Instance->Configured) {\r
+    //\r
+    // Delete the related cache entry.\r
+    //\r
+    ArpDeleteCacheEntry (Instance, FALSE, NULL, TRUE);\r
+\r
+    //\r
+    // Reset the instance configuration.\r
+    //\r
+    ArpConfigureInstance (Instance, NULL);\r
+  }\r
+\r
+  //\r
+  // Remove this instance from the ChildrenList.\r
+  //\r
+  NetListRemoveEntry (&Instance->List);\r
+  ArpService->ChildrenNumber--;\r
+\r
+  NET_UNLOCK (&ArpService->Lock);\r
+\r
+  NetFreePool (Instance);\r
+\r
+  return Status;\r
+}\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (ArpDriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+ArpDriverEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The entry point for Arp 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
+           &gArpDriverBinding,\r
+           ImageHandle,\r
+           &gArpComponentName,\r
+           NULL,\r
+           NULL\r
+           );\r
+}\r
+\r
diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.h b/MdeModulePkg/Universal/Network/ArpDxe/ArpDriver.h
new file mode 100644 (file)
index 0000000..93526c7
--- /dev/null
@@ -0,0 +1,84 @@
+/** @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:
+
+  ArpDriver.c
+
+Abstract:
+
+
+**/
+
+#ifndef _ARP_DRIVER_H_
+#define _ARP_DRIVER_H_
+
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/Arp.h>\r
+#include <Protocol/ManagedNetwork.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 "ArpDebug.h"
+
+//
+// Global variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL   gArpDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gArpComponentName;
+
+EFI_STATUS
+EFIAPI
+ArpDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+ArpDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+ArpDriverBindingStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN UINTN                        NumberOfChildren,
+  IN EFI_HANDLE                   *ChildHandleBuffer
+  );
+
+EFI_STATUS
+EFIAPI
+ArpServiceBindingCreateChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    *ChildHandle
+  );
+
+EFI_STATUS
+EFIAPI
+ArpServiceBindingDestroyChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    ChildHandle
+  );
+
+#endif
+
diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf b/MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
new file mode 100644 (file)
index 0000000..4cc9b2e
--- /dev/null
@@ -0,0 +1,59 @@
+#/** @file\r
+# Component description file for ARP module\r
+#\r
+# Copyright (c) 2006, Intel Corporation\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
+#\r
+#**/\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = ArpDxe\r
+  FILE_GUID                      = 529D3F93-E8E9-4e73-B1E1-BDF6A9D50113\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = ArpDriverEntryPoint\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
+  ArpMain.c\r
+  ArpDriver.h\r
+  ComponentName.c\r
+  ArpImpl.h\r
+  ArpImpl.c\r
+  ArpDebug.h\r
+  ArpDriver.c\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
+  gEfiArpServiceBindingProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiManagedNetworkProtocolGuid                # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiArpProtocolGuid                           # PROTOCOL ALWAYS_CONSUMED\r
+\r
diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.msa b/MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.msa
new file mode 100644 (file)
index 0000000..89178fa
--- /dev/null
@@ -0,0 +1,72 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+  <MsaHeader>\r
+    <ModuleName>Arp</ModuleName>\r
+    <ModuleType>DXE_DRIVER</ModuleType>\r
+    <GuidValue>529D3F93-E8E9-4e73-B1E1-BDF6A9D50113</GuidValue>\r
+    <Version>1.0</Version>\r
+    <Abstract>Component name for module Arp</Abstract>\r
+    <Description>FIX ME!</Description>\r
+    <Copyright>Copyright (c) 2007, Intel Corporation. All rights 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>Arp</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>ArpDriver.c</Filename>\r
+    <Filename>ArpDebug.h</Filename>\r
+    <Filename>ArpImpl.c</Filename>\r
+    <Filename>ArpImpl.h</Filename>\r
+    <Filename>ComponentName.c</Filename>\r
+    <Filename>ArpDriver.h</Filename>\r
+    <Filename>ArpMain.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>gEfiArpProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiManagedNetworkProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiArpServiceBindingProtocolGuid</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>ArpDriverEntryPoint</ModuleEntryPoint>\r
+    </Extern>\r
+  </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ArpImpl.c b/MdeModulePkg/Universal/Network/ArpDxe/ArpImpl.c
new file mode 100644 (file)
index 0000000..93b4c10
--- /dev/null
@@ -0,0 +1,1628 @@
+/** @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
+  ArpImpl.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "ArpImpl.h"\r
+#include "ArpDebug.h"\r
+\r
+EFI_ARP_PROTOCOL  mEfiArpProtocolTemplate = {\r
+  ArpConfigure,\r
+  ArpAdd,\r
+  ArpFind,\r
+  ArpDelete,\r
+  ArpFlush,\r
+  ArpRequest,\r
+  ArpCancel\r
+};\r
+\r
+\r
+/**\r
+  Initialize the instance context data.\r
+\r
+  @param  ArpService             Pointer to the arp service context data this\r
+                                 instance belongs to.\r
+  @param  Instance               Pointer to the instance context data.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+ArpInitInstance (\r
+  IN ARP_SERVICE_DATA   *ArpService,\r
+  IN ARP_INSTANCE_DATA  *Instance\r
+  )\r
+{\r
+  NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);\r
+\r
+  Instance->Signature  = ARP_INSTANCE_DATA_SIGNATURE;\r
+  Instance->ArpService = ArpService;\r
+\r
+  CopyMem (&Instance->ArpProto, &mEfiArpProtocolTemplate, sizeof (ARP_SERVICE_DATA));\r
+\r
+  Instance->Configured = FALSE;\r
+  Instance->Destroyed  = FALSE;\r
+\r
+  NetListInit (&Instance->List);\r
+}\r
+\r
+\r
+/**\r
+  Process the Arp packets received from Mnp, the procedure conforms to RFC826.\r
+\r
+  @param  Event                  The Event this notify function registered to.\r
+  @param  Context                Pointer to the context data registerd to the\r
+                                 Event.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ArpOnFrameRcvd (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  ARP_SERVICE_DATA                      *ArpService;\r
+  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *RxToken;\r
+  EFI_MANAGED_NETWORK_RECEIVE_DATA      *RxData;\r
+  ARP_HEAD                              *Head;\r
+  ARP_ADDRESS                           ArpAddress;\r
+  ARP_CACHE_ENTRY                       *CacheEntry;\r
+  NET_LIST_ENTRY                        *Entry;\r
+  ARP_INSTANCE_DATA                     *Instance;\r
+  EFI_ARP_CONFIG_DATA                   *ConfigData;\r
+  NET_ARP_ADDRESS                       SenderAddress[2];\r
+  BOOLEAN                               ProtoMatched;\r
+  BOOLEAN                               IsTarget;\r
+  BOOLEAN                               MergeFlag;\r
+\r
+  ArpService = (ARP_SERVICE_DATA *)Context;\r
+  NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);\r
+\r
+  RxToken = &ArpService->RxToken;\r
+\r
+  if (RxToken->Status == EFI_ABORTED) {\r
+    //\r
+    // The Token is aborted, possibly by arp itself, just return and the receiving\r
+    // process is stopped.\r
+    //\r
+    return;\r
+  }\r
+\r
+  if (EFI_ERROR (RxToken->Status)) {\r
+    //\r
+    // Restart the receiving if any other error Status occurs.\r
+    //\r
+    goto RESTART_RECEIVE;\r
+  }\r
+\r
+  //\r
+  // Status is EFI_SUCCESS, process the received frame.\r
+  //\r
+  RxData = RxToken->Packet.RxData;\r
+  Head   = (ARP_HEAD *) RxData->PacketData;\r
+\r
+  //\r
+  // Convert the byte order of the multi-byte fields.\r
+  //\r
+  Head->HwType    = NTOHS (Head->HwType);\r
+  Head->ProtoType = NTOHS (Head->ProtoType);\r
+  Head->OpCode    = NTOHS (Head->OpCode);\r
+\r
+  if ((Head->HwType != ArpService->SnpMode.IfType) ||\r
+    (Head->HwAddrLen != ArpService->SnpMode.HwAddressSize) ||\r
+    (RxData->ProtocolType != ARP_ETHER_PROTO_TYPE)) {\r
+    //\r
+    // The hardware type or the hardware address length doesn't match.\r
+    // There is a sanity check for the protocol type too.\r
+    //\r
+    goto RECYCLE_RXDATA;\r
+  }\r
+\r
+  //\r
+  // Set the pointers to the addresses contained in the arp packet.\r
+  //\r
+  ArpAddress.SenderHwAddr    = (UINT8 *)(Head + 1);\r
+  ArpAddress.SenderProtoAddr = ArpAddress.SenderHwAddr + Head->HwAddrLen;\r
+  ArpAddress.TargetHwAddr    = ArpAddress.SenderProtoAddr + Head->ProtoAddrLen;\r
+  ArpAddress.TargetProtoAddr = ArpAddress.TargetHwAddr + Head->HwAddrLen;\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {\r
+    ARP_DEBUG_ERROR (("ArpOnFrameRcvd: Faild to acquire the CacheTableLock.\n"));\r
+    goto RECYCLE_RXDATA;\r
+  }\r
+\r
+  SenderAddress[Hardware].Type       = Head->HwType;\r
+  SenderAddress[Hardware].Length     = Head->HwAddrLen;\r
+  SenderAddress[Hardware].AddressPtr = ArpAddress.SenderHwAddr;\r
+\r
+  SenderAddress[Protocol].Type       = Head->ProtoType;\r
+  SenderAddress[Protocol].Length     = Head->ProtoAddrLen;\r
+  SenderAddress[Protocol].AddressPtr = ArpAddress.SenderProtoAddr;\r
+\r
+  //\r
+  // First, check the denied cache table.\r
+  //\r
+  CacheEntry = ArpFindDeniedCacheEntry (\r
+                 ArpService,\r
+                 &SenderAddress[Protocol],\r
+                 &SenderAddress[Hardware]\r
+                 );\r
+  if (CacheEntry != NULL) {\r
+    //\r
+    // This address (either hardware or protocol address, or both) is configured to\r
+    // be a deny entry, silently skip the normal process.\r
+    //\r
+    goto UNLOCK_EXIT;\r
+  }\r
+\r
+  ProtoMatched = FALSE;\r
+  IsTarget     = FALSE;\r
+  Instance     = NULL;\r
+  NET_LIST_FOR_EACH (Entry, &ArpService->ChildrenList) {\r
+    //\r
+    // Iterate all the children.\r
+    //\r
+    Instance = NET_LIST_USER_STRUCT (Entry, ARP_INSTANCE_DATA, List);\r
+    NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);\r
+    ConfigData = &Instance->ConfigData;\r
+\r
+    if ((Instance->Configured) &&\r
+      (Head->ProtoType == ConfigData->SwAddressType) &&\r
+      (Head->ProtoAddrLen == ConfigData->SwAddressLength)) {\r
+      //\r
+      // The protocol type is matched for the received arp packet.\r
+      //\r
+      ProtoMatched = TRUE;\r
+      if (0 == NetCompareMem (\r
+                 (VOID *)ArpAddress.TargetProtoAddr,\r
+                 ConfigData->StationAddress,\r
+                 ConfigData->SwAddressLength\r
+                 )) {\r
+        //\r
+        // The arp driver has the target address required by the received arp packet.\r
+        //\r
+        IsTarget = TRUE;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (!ProtoMatched) {\r
+    //\r
+    // Protocol type unmatchable, skip.\r
+    //\r
+    goto UNLOCK_EXIT;\r
+  }\r
+\r
+  //\r
+  // Check whether the sender's address information is already in the cache.\r
+  //\r
+  MergeFlag  = FALSE;\r
+  CacheEntry = ArpFindNextCacheEntryInTable (\r
+                 &ArpService->ResolvedCacheTable,\r
+                 NULL,\r
+                 ByProtoAddress,\r
+                 &SenderAddress[Protocol],\r
+                 NULL\r
+                 );\r
+  if (CacheEntry != NULL) {\r
+    //\r
+    // Update the entry with the new information.\r
+    //\r
+    ArpFillAddressInCacheEntry (CacheEntry, &SenderAddress[Hardware], NULL);\r
+    CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;\r
+    MergeFlag = TRUE;\r
+  }\r
+\r
+  if (!IsTarget) {\r
+    //\r
+    // This arp packet isn't targeted to us, skip now.\r
+    //\r
+    goto UNLOCK_EXIT;\r
+  }\r
+\r
+  if (!MergeFlag) {\r
+    //\r
+    // Add the triplet <protocol type, sender protocol address, sender hardware address>\r
+    // to the translation table.\r
+    //\r
+    CacheEntry = ArpFindNextCacheEntryInTable (\r
+                   &ArpService->PendingRequestTable,\r
+                   NULL,\r
+                   ByProtoAddress,\r
+                   &SenderAddress[Protocol],\r
+                   NULL\r
+                   );\r
+    if (CacheEntry == NULL) {\r
+      //\r
+      // Allocate a new CacheEntry.\r
+      //\r
+      CacheEntry = ArpAllocCacheEntry (NULL);\r
+      if (CacheEntry == NULL) {\r
+        goto UNLOCK_EXIT;\r
+      }\r
+    }\r
+\r
+    NetListRemoveEntry (&CacheEntry->List);\r
+\r
+    //\r
+    // Fill the addresses into the CacheEntry.\r
+    //\r
+    ArpFillAddressInCacheEntry (\r
+      CacheEntry,\r
+      &SenderAddress[Hardware],\r
+      &SenderAddress[Protocol]\r
+      );\r
+\r
+    //\r
+    // Inform the user.\r
+    //\r
+    ArpAddressResolved (CacheEntry, NULL, NULL);\r
+\r
+    //\r
+    // Add this entry into the ResolvedCacheTable\r
+    //\r
+    NetListInsertHead (&ArpService->ResolvedCacheTable, &CacheEntry->List);\r
+  }\r
+\r
+  if (Head->OpCode == ARP_OPCODE_REQUEST) {\r
+    //\r
+    // Send back the ARP Reply. If we reach here, Instance is not NULL and CacheEntry\r
+    // is not NULL.\r
+    //\r
+    ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REPLY);\r
+  }\r
+\r
+UNLOCK_EXIT:\r
+\r
+  NET_UNLOCK (&ArpService->Lock);\r
+\r
+RECYCLE_RXDATA:\r
+\r
+  //\r
+  // Signal Mnp to recycle the RxData.\r
+  //\r
+  gBS->SignalEvent (RxData->RecycleEvent);\r
+\r
+RESTART_RECEIVE:\r
+\r
+  //\r
+  // Continue to receive packets from Mnp.\r
+  //\r
+  Status = ArpService->Mnp->Receive (ArpService->Mnp, RxToken);\r
+\r
+  DEBUG_CODE (\r
+    if (EFI_ERROR (Status)) {\r
+      ARP_DEBUG_ERROR (("ArpOnFrameRcvd: ArpService->Mnp->Receive "\r
+        "failed, %r\n.", Status));\r
+    }\r
+  );\r
+}\r
+\r
+\r
+/**\r
+  Process the already sent arp packets.\r
+\r
+  @param  Event                  The Event this notify function registered to.\r
+  @param  Context                Pointer to the context data registerd to the\r
+                                 Event.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ArpOnFrameSent (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TxToken;\r
+  EFI_MANAGED_NETWORK_TRANSMIT_DATA     *TxData;\r
+\r
+  ASSERT (Context != NULL);\r
+\r
+  TxToken = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *)Context;\r
+  TxData  = TxToken->Packet.TxData;\r
+\r
+  DEBUG_CODE (\r
+    if (EFI_ERROR (TxToken->Status)) {\r
+      ARP_DEBUG_ERROR (("ArpOnFrameSent: TxToken->Status, %r.\n", TxToken->Status));\r
+    }\r
+  );\r
+\r
+  //\r
+  // Free the allocated memory and close the event.\r
+  //\r
+  NetFreePool (TxData->FragmentTable[0].FragmentBuffer);\r
+  NetFreePool (TxData);\r
+  gBS->CloseEvent (TxToken->Event);\r
+  NetFreePool (TxToken);\r
+}\r
+\r
+\r
+/**\r
+  Process the arp cache olding and drive the retrying arp requests.\r
+\r
+  @param  Event                  The Event this notify function registered to.\r
+  @param  Context                Pointer to the context data registerd to the\r
+                                 Event.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ArpTimerHandler (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  ARP_SERVICE_DATA      *ArpService;\r
+  NET_LIST_ENTRY        *Entry;\r
+  NET_LIST_ENTRY        *NextEntry;\r
+  NET_LIST_ENTRY        *ContextEntry;\r
+  ARP_CACHE_ENTRY       *CacheEntry;\r
+  USER_REQUEST_CONTEXT  *RequestContext;\r
+\r
+  ASSERT (Context != NULL);\r
+  ArpService = (ARP_SERVICE_DATA *)Context;\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Iterate all the pending requests to see whether a retry is needed to send out\r
+  // or the request finally fails because the retry time reaches the limitation.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {\r
+    CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
+\r
+    if (CacheEntry->NextRetryTime <= ARP_PERIODIC_TIMER_INTERVAL) {\r
+      //\r
+      // Timeout, if we can retry more, send out the request again, otherwise abort\r
+      // this request.\r
+      //\r
+      if (CacheEntry->RetryCount == 0) {\r
+        //\r
+        // Abort this request.\r
+        //\r
+        ArpAddressResolved (CacheEntry, NULL, NULL);\r
+        ASSERT (NetListIsEmpty (&CacheEntry->UserRequestList));\r
+\r
+        NetListRemoveEntry (&CacheEntry->List);\r
+        NetFreePool (CacheEntry);\r
+      } else {\r
+        //\r
+        // resend the ARP request.\r
+        //\r
+        ASSERT (!NetListIsEmpty(&CacheEntry->UserRequestList));\r
+\r
+        ContextEntry   = CacheEntry->UserRequestList.ForwardLink;\r
+        RequestContext = NET_LIST_USER_STRUCT (ContextEntry, USER_REQUEST_CONTEXT, List);\r
+\r
+        ArpSendFrame (RequestContext->Instance, CacheEntry, ARP_OPCODE_REQUEST);\r
+\r
+        CacheEntry->RetryCount--;\r
+        CacheEntry->NextRetryTime = RequestContext->Instance->ConfigData.RetryTimeOut;\r
+      }\r
+    } else {\r
+      //\r
+      // Update the NextRetryTime.\r
+      //\r
+      CacheEntry->NextRetryTime -= ARP_PERIODIC_TIMER_INTERVAL;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check the timeouts for the DeniedCacheTable.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->DeniedCacheTable) {\r
+    CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
+    ASSERT (NetListIsEmpty (&CacheEntry->UserRequestList));\r
+\r
+    if (CacheEntry->DefaultDecayTime == 0) {\r
+      //\r
+      // It's a static entry, skip it.\r
+      //\r
+      continue;\r
+    }\r
+\r
+    if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {\r
+      //\r
+      // Time out, remove it.\r
+      //\r
+      NetListRemoveEntry (&CacheEntry->List);\r
+      NetFreePool (CacheEntry);\r
+    } else {\r
+      //\r
+      // Update the DecayTime.\r
+      //\r
+      CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check the timeouts for the ResolvedCacheTable.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->ResolvedCacheTable) {\r
+    CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
+    ASSERT (NetListIsEmpty (&CacheEntry->UserRequestList));\r
+\r
+    if (CacheEntry->DefaultDecayTime == 0) {\r
+      //\r
+      // It's a static entry, skip it.\r
+      //\r
+      continue;\r
+    }\r
+\r
+    if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {\r
+      //\r
+      // Time out, remove it.\r
+      //\r
+      NetListRemoveEntry (&CacheEntry->List);\r
+      NetFreePool (CacheEntry);\r
+    } else {\r
+      //\r
+      // Update the DecayTime.\r
+      //\r
+      CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;\r
+    }\r
+  }\r
+\r
+  NET_UNLOCK (&ArpService->Lock);\r
+}\r
+\r
+\r
+/**\r
+  Match the two NET_ARP_ADDRESSes.\r
+\r
+  @param  AddressOne             Pointer to the first address to match.\r
+  @param  AddressTwo             Pointer to the second address to match.\r
+\r
+  @return The two addresses match or not.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+ArpMatchAddress (\r
+  IN NET_ARP_ADDRESS  *AddressOne,\r
+  IN NET_ARP_ADDRESS  *AddressTwo\r
+  )\r
+{\r
+  if ((AddressOne->Type != AddressTwo->Type) ||\r
+    (AddressOne->Length != AddressTwo->Length)) {\r
+    //\r
+    // Either Type or Length doesn't match.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  if ((AddressOne->AddressPtr != NULL) &&\r
+    (NetCompareMem (\r
+      AddressOne->AddressPtr,\r
+      AddressTwo->AddressPtr,\r
+      AddressOne->Length\r
+      ) != 0)) {\r
+    //\r
+    // The address is not the same.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Find the CacheEntry which matches the requirements in the specified CacheTable.\r
+\r
+  @param  CacheTable             Pointer to the arp cache table.\r
+  @param  StartEntry             Pointer to the start entry this search begins with\r
+                                 in the cache table.\r
+  @param  FindOpType             The search type.\r
+  @param  ProtocolAddress        Pointer to the protocol address to match.\r
+  @param  HardwareAddress        Pointer to the hardware address to match.\r
+\r
+  @return Pointer to the matched arp cache entry, if NULL, no match is found.\r
+\r
+**/\r
+ARP_CACHE_ENTRY *\r
+ArpFindNextCacheEntryInTable (\r
+  IN NET_LIST_ENTRY    *CacheTable,\r
+  IN NET_LIST_ENTRY    *StartEntry,\r
+  IN FIND_OPTYPE       FindOpType,\r
+  IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,\r
+  IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL\r
+  )\r
+{\r
+  NET_LIST_ENTRY   *Entry;\r
+  ARP_CACHE_ENTRY  *CacheEntry;\r
+\r
+  if (StartEntry == NULL) {\r
+    //\r
+    // Start from the beginning of the table if no StartEntry is specified.\r
+    //\r
+    StartEntry = CacheTable;\r
+  }\r
+\r
+  for (Entry = StartEntry->ForwardLink; Entry != CacheTable; Entry = Entry->ForwardLink) {\r
+    CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
+\r
+    if (FindOpType & MATCH_SW_ADDRESS) {\r
+      //\r
+      // Find by the software address.\r
+      //\r
+      if (!ArpMatchAddress (ProtocolAddress, &CacheEntry->Addresses[Protocol])) {\r
+        //\r
+        // The ProtocolAddress doesn't match, continue to the next cache entry.\r
+        //\r
+        continue;\r
+      }\r
+    }\r
+\r
+    if (FindOpType & MATCH_HW_ADDRESS) {\r
+      //\r
+      // Find by the hardware address.\r
+      //\r
+      if (!ArpMatchAddress (HardwareAddress, &CacheEntry->Addresses[Hardware])) {\r
+        //\r
+        // The HardwareAddress doesn't match, continue to the next cache entry.\r
+        //\r
+        continue;\r
+      }\r
+    }\r
+\r
+    //\r
+    // The CacheEntry meets the requirements now, return this entry.\r
+    //\r
+    return CacheEntry;\r
+  }\r
+\r
+  //\r
+  // No matching.\r
+  //\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Find the CacheEntry, using ProtocolAddress or HardwareAddress or both, as the keyword,\r
+  in the DeniedCacheTable.\r
+\r
+  @param  ArpService             Pointer to the arp service context data.\r
+  @param  ProtocolAddress        Pointer to the protocol address.\r
+  @param  HardwareAddress        Pointer to the hardware address.\r
+\r
+  @return Pointer to the matched cache entry, if NULL no match is found.\r
+\r
+**/\r
+ARP_CACHE_ENTRY *\r
+ArpFindDeniedCacheEntry (\r
+  IN ARP_SERVICE_DATA  *ArpService,\r
+  IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,\r
+  IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL\r
+  )\r
+{\r
+  ARP_CACHE_ENTRY  *CacheEntry;\r
+\r
+  ASSERT ((ProtocolAddress != NULL) || (HardwareAddress != NULL));\r
+  NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);\r
+\r
+  CacheEntry = NULL;\r
+\r
+  if ((ProtocolAddress != NULL) && (ProtocolAddress->AddressPtr != NULL)) {\r
+    //\r
+    // Find the cache entry in the DeniedCacheTable by the protocol address.\r
+    //\r
+    CacheEntry = ArpFindNextCacheEntryInTable (\r
+                   &ArpService->DeniedCacheTable,\r
+                   NULL,\r
+                   ByProtoAddress,\r
+                   ProtocolAddress,\r
+                   NULL\r
+                   );\r
+    if (CacheEntry != NULL) {\r
+      //\r
+      // There is a match.\r
+      //\r
+      return CacheEntry;\r
+    }\r
+  }\r
+\r
+  if ((HardwareAddress != NULL) && (HardwareAddress->AddressPtr != NULL)) {\r
+    //\r
+    // Find the cache entry in the DeniedCacheTable by the hardware address.\r
+    //\r
+    CacheEntry = ArpFindNextCacheEntryInTable (\r
+                   &ArpService->DeniedCacheTable,\r
+                   NULL,\r
+                   ByHwAddress,\r
+                   NULL,\r
+                   HardwareAddress\r
+                   );\r
+  }\r
+\r
+  return CacheEntry;\r
+}\r
+\r
+\r
+/**\r
+  Allocate a cache entry and initialize it.\r
+\r
+  @param  Instance               Pointer to the instance context data.\r
+\r
+  @return Pointer to the new created cache entry.\r
+\r
+**/\r
+ARP_CACHE_ENTRY *\r
+ArpAllocCacheEntry (\r
+  IN ARP_INSTANCE_DATA  *Instance\r
+  )\r
+{\r
+  ARP_CACHE_ENTRY  *CacheEntry;\r
+  NET_ARP_ADDRESS  *Address;\r
+  UINT16           Index;\r
+\r
+  //\r
+  // Allocate memory for the cache entry.\r
+  //\r
+  CacheEntry = NetAllocatePool (sizeof (ARP_CACHE_ENTRY));\r
+  if (CacheEntry == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Init the lists.\r
+  //\r
+  NetListInit (&CacheEntry->List);\r
+  NetListInit (&CacheEntry->UserRequestList);\r
+\r
+  for (Index = 0; Index < 2; Index++) {\r
+    //\r
+    // Init the address pointers to point to the concrete buffer.\r
+    //\r
+    Address = &CacheEntry->Addresses[Index];\r
+    Address->AddressPtr = Address->Buffer.ProtoAddress;\r
+  }\r
+\r
+  //\r
+  // Zero the hardware address first.\r
+  //\r
+  NetZeroMem (CacheEntry->Addresses[Hardware].AddressPtr, ARP_MAX_HARDWARE_ADDRESS_LEN);\r
+\r
+  if (Instance != NULL) {\r
+    //\r
+    // Inherit the parameters from the instance configuration.\r
+    //\r
+    CacheEntry->RetryCount       = Instance->ConfigData.RetryCount;\r
+    CacheEntry->NextRetryTime    = Instance->ConfigData.RetryTimeOut;\r
+    CacheEntry->DefaultDecayTime = Instance->ConfigData.EntryTimeOut;\r
+    CacheEntry->DecayTime        = Instance->ConfigData.EntryTimeOut;\r
+  } else {\r
+    //\r
+    // Use the default parameters if this cache entry isn't allocate in a\r
+    // instance's  scope.\r
+    //\r
+    CacheEntry->RetryCount       = ARP_DEFAULT_RETRY_COUNT;\r
+    CacheEntry->NextRetryTime    = ARP_DEFAULT_RETRY_INTERVAL;\r
+    CacheEntry->DefaultDecayTime = ARP_DEFAULT_TIMEOUT_VALUE;\r
+    CacheEntry->DecayTime        = ARP_DEFAULT_TIMEOUT_VALUE;\r
+  }\r
+\r
+  return CacheEntry;\r
+}\r
+\r
+\r
+/**\r
+  Turn the CacheEntry into the resolved status.\r
+\r
+  @param  CacheEntry             Pointer to the resolved cache entry.\r
+  @param  Instance               Pointer to the instance context data.\r
+  @param  UserEvent              Pointer to the UserEvent to notify.\r
+\r
+  @return The count of notifications sent to the instance.\r
+\r
+**/\r
+UINTN\r
+ArpAddressResolved (\r
+  IN ARP_CACHE_ENTRY    *CacheEntry,\r
+  IN ARP_INSTANCE_DATA  *Instance OPTIONAL,\r
+  IN EFI_EVENT          UserEvent OPTIONAL\r
+  )\r
+{\r
+  NET_LIST_ENTRY        *Entry;\r
+  NET_LIST_ENTRY        *NextEntry;\r
+  USER_REQUEST_CONTEXT  *Context;\r
+  UINTN                 Count;\r
+\r
+  Count = 0;\r
+\r
+  //\r
+  // Iterate all the linked user requests to notify them.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &CacheEntry->UserRequestList) {\r
+    Context = NET_LIST_USER_STRUCT (Entry, USER_REQUEST_CONTEXT, List);\r
+\r
+    if (((Instance == NULL) || (Context->Instance == Instance)) &&\r
+      ((UserEvent == NULL) || (Context->UserRequestEvent == UserEvent))) {\r
+      //\r
+      // Copy the address to the user-provided buffer and notify the user.\r
+      //\r
+      NetCopyMem (\r
+        Context->UserHwAddrBuffer,\r
+        CacheEntry->Addresses[Hardware].AddressPtr,\r
+        CacheEntry->Addresses[Hardware].Length\r
+        );\r
+      gBS->SignalEvent (Context->UserRequestEvent);\r
+\r
+      //\r
+      // Remove this user request and free the context data.\r
+      //\r
+      NetListRemoveEntry (&Context->List);\r
+      NetFreePool (Context);\r
+\r
+      Count++;\r
+    }\r
+  }\r
+\r
+  return Count;\r
+}\r
+\r
+\r
+/**\r
+  Fill the addresses in the CacheEntry using the information passed in by\r
+  HwAddr and SwAddr.\r
+\r
+  @param  CacheEntry             Pointer to the cache entry.\r
+  @param  HwAddr                 Pointer to the software address.\r
+  @param  SwAddr                 Pointer to the hardware address.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+ArpFillAddressInCacheEntry (\r
+  IN ARP_CACHE_ENTRY  *CacheEntry,\r
+  IN NET_ARP_ADDRESS  *HwAddr OPTIONAL,\r
+  IN NET_ARP_ADDRESS  *SwAddr OPTIONAL\r
+  )\r
+{\r
+  NET_ARP_ADDRESS  *Address[2];\r
+  NET_ARP_ADDRESS  *CacheAddress;\r
+  UINT32           Index;\r
+\r
+  Address[Hardware] = HwAddr;\r
+  Address[Protocol] = SwAddr;\r
+\r
+  for (Index = 0; Index < 2; Index++) {\r
+    if (Address[Index] != NULL) {\r
+      //\r
+      // Fill the address if the passed in pointer is not NULL.\r
+      //\r
+      CacheAddress = &CacheEntry->Addresses[Index];\r
+\r
+      CacheAddress->Type   = Address[Index]->Type;\r
+      CacheAddress->Length = Address[Index]->Length;\r
+\r
+      if (Address[Index]->AddressPtr != NULL) {\r
+        //\r
+        // Copy it if the AddressPtr points to some buffer.\r
+        //\r
+        NetCopyMem (\r
+          CacheAddress->AddressPtr,\r
+          Address[Index]->AddressPtr,\r
+          CacheAddress->Length\r
+          );\r
+      } else {\r
+        //\r
+        // Zero the corresponding address buffer in the CacheEntry.\r
+        //\r
+        NetZeroMem (CacheAddress->AddressPtr, CacheAddress->Length);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Configure the instance using the ConfigData. ConfigData is already validated.\r
+\r
+  @param  Instance               Pointer to the instance context data to be\r
+                                 configured.\r
+  @param  ConfigData             Pointer to the configuration data used to\r
+                                 configure the instance.\r
+\r
+  @retval EFI_SUCCESS            The instance is configured with the ConfigData.\r
+  @retval EFI_ACCESS_DENIED      The instance is already configured and the\r
+                                 ConfigData tries to reset some unchangeable\r
+                                 fields.\r
+  @retval EFI_INVALID_PARAMETER  The ConfigData provides a non-unicast IPv4 address\r
+                                 when the SwAddressType is IPv4.\r
+  @retval EFI_OUT_OF_RESOURCES   The instance fails to configure due to memory\r
+                                 limitation.\r
+\r
+**/\r
+EFI_STATUS\r
+ArpConfigureInstance (\r
+  IN ARP_INSTANCE_DATA    *Instance,\r
+  IN EFI_ARP_CONFIG_DATA  *ConfigData OPTIONAL\r
+  )\r
+{\r
+  EFI_ARP_CONFIG_DATA  *OldConfigData;\r
+  IP4_ADDR             Ip;\r
+\r
+  OldConfigData = &Instance->ConfigData;\r
+\r
+  if (ConfigData != NULL) {\r
+\r
+    if (Instance->Configured) {\r
+      //\r
+      // The instance is configured, check the unchangeable fields.\r
+      //\r
+      if ((OldConfigData->SwAddressType != ConfigData->SwAddressType) ||\r
+        (OldConfigData->SwAddressLength != ConfigData->SwAddressLength) ||\r
+        (NetCompareMem (\r
+           OldConfigData->StationAddress,\r
+           ConfigData->StationAddress,\r
+           OldConfigData->SwAddressLength\r
+           ) != 0)) {\r
+        //\r
+        // Deny the unallowed changes.\r
+        //\r
+        return EFI_ACCESS_DENIED;\r
+      }\r
+    } else {\r
+      //\r
+      // The instance is not configured.\r
+      //\r
+\r
+      if (ConfigData->SwAddressType == IPv4_ETHER_PROTO_TYPE) {\r
+        NetCopyMem (&Ip, ConfigData->StationAddress, sizeof (IP4_ADDR));\r
+\r
+        if (!Ip4IsUnicast (NTOHL (Ip), 0)) {\r
+          //\r
+          // The station address is not a valid IPv4 unicast address.\r
+          //\r
+          return EFI_INVALID_PARAMETER;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Save the configuration.\r
+      //\r
+      CopyMem (OldConfigData, ConfigData, sizeof (EFI_ARP_CONFIG_DATA));\r
+\r
+      OldConfigData->StationAddress = NetAllocatePool (OldConfigData->SwAddressLength);\r
+      if (OldConfigData->StationAddress == NULL) {\r
+        ARP_DEBUG_ERROR (("ArpConfigInstance: NetAllocatePool for the StationAddress "\r
+          "failed.\n"));\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      //\r
+      // Save the StationAddress.\r
+      //\r
+      NetCopyMem (\r
+        OldConfigData->StationAddress,\r
+        ConfigData->StationAddress,\r
+        OldConfigData->SwAddressLength\r
+        );\r
+\r
+      //\r
+      // Set the state to configured.\r
+      //\r
+      Instance->Configured = TRUE;\r
+    }\r
+\r
+    //\r
+    // Use the implementation specific values if the following field is zero.\r
+    //\r
+    OldConfigData->EntryTimeOut = (ConfigData->EntryTimeOut == 0) ?\r
+      ARP_DEFAULT_TIMEOUT_VALUE : ConfigData->EntryTimeOut;\r
+\r
+    OldConfigData->RetryCount   = (ConfigData->RetryCount == 0) ?\r
+      ARP_DEFAULT_RETRY_COUNT : ConfigData->RetryCount;\r
+\r
+    OldConfigData->RetryTimeOut = (ConfigData->RetryTimeOut == 0) ?\r
+      ARP_DEFAULT_RETRY_INTERVAL : ConfigData->RetryTimeOut;\r
+  } else {\r
+    //\r
+    // Reset the configuration.\r
+    //\r
+\r
+    if (Instance->Configured) {\r
+      //\r
+      // Cancel the arp requests issued by this instance.\r
+      //\r
+      ArpCancelRequest (Instance, NULL, NULL);\r
+\r
+      //\r
+      // Free the buffer previously allocated to hold the station address.\r
+      //\r
+      NetFreePool (OldConfigData->StationAddress);\r
+    }\r
+\r
+    Instance->Configured = FALSE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Send out an arp frame using the CachEntry and the ArpOpCode.\r
+\r
+  @param  Instance               Pointer to the instance context data.\r
+  @param  CacheEntry             Pointer to the configuration data used to\r
+                                 configure the instance.\r
+  @param  ArpOpCode              The opcode used to send out this Arp frame, either\r
+                                 request or reply.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+ArpSendFrame (\r
+  IN ARP_INSTANCE_DATA  *Instance,\r
+  IN ARP_CACHE_ENTRY    *CacheEntry,\r
+  IN UINT16             ArpOpCode\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TxToken;\r
+  EFI_MANAGED_NETWORK_TRANSMIT_DATA     *TxData;\r
+  UINT32                                TotalLength;\r
+  UINT8                                 *Packet;\r
+  ARP_SERVICE_DATA                      *ArpService;\r
+  EFI_SIMPLE_NETWORK_MODE               *SnpMode;\r
+  EFI_ARP_CONFIG_DATA                   *ConfigData;\r
+  UINT8                                 *TmpPtr;\r
+  ARP_HEAD                              *ArpHead;\r
+\r
+  ASSERT ((Instance != NULL) && (CacheEntry != NULL));\r
+\r
+  //\r
+  // Allocate memory for the TxToken.\r
+  //\r
+  TxToken = NetAllocatePool (sizeof(EFI_MANAGED_NETWORK_COMPLETION_TOKEN));\r
+  if (TxToken == NULL) {\r
+    ARP_DEBUG_ERROR (("ArpSendFrame: Allocate memory for TxToken failed.\n"));\r
+    return;\r
+  }\r
+\r
+  TxToken->Event = NULL;\r
+  TxData         = NULL;\r
+  Packet         = NULL;\r
+\r
+  //\r
+  // Create the event for this TxToken.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  NET_TPL_EVENT,\r
+                  ArpOnFrameSent,\r
+                  (VOID *)TxToken,\r
+                  &TxToken->Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    ARP_DEBUG_ERROR (("ArpSendFrame: CreateEvent failed for TxToken->Event.\n"));\r
+    goto CLEAN_EXIT;\r
+  }\r
+\r
+  //\r
+  // Allocate memory for the TxData used in the TxToken.\r
+  //\r
+  TxData = NetAllocatePool (sizeof(EFI_MANAGED_NETWORK_TRANSMIT_DATA));\r
+  if (TxData == NULL) {\r
+    ARP_DEBUG_ERROR (("ArpSendFrame: Allocate memory for TxData failed.\n"));\r
+    goto CLEAN_EXIT;\r
+  }\r
+\r
+  ArpService = Instance->ArpService;\r
+  SnpMode    = &ArpService->SnpMode;\r
+  ConfigData = &Instance->ConfigData;\r
+\r
+  //\r
+  // Calculate the buffer length for this arp frame.\r
+  //\r
+  TotalLength = SnpMode->MediaHeaderSize + sizeof (ARP_HEAD) +\r
+                2 * (ConfigData->SwAddressLength + SnpMode->HwAddressSize);\r
+\r
+  //\r
+  // Allocate buffer for the arp frame.\r
+  //\r
+  Packet = NetAllocatePool (TotalLength);\r
+  if (Packet == NULL) {\r
+    ARP_DEBUG_ERROR (("ArpSendFrame: Allocate memory for Packet failed.\n"));\r
+  }\r
+\r
+  TmpPtr = Packet;\r
+\r
+  //\r
+  // The destination MAC address.\r
+  //\r
+  if (ArpOpCode == ARP_OPCODE_REQUEST) {\r
+    NetCopyMem (TmpPtr, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);\r
+  } else {\r
+    NetCopyMem (\r
+      TmpPtr,\r
+      CacheEntry->Addresses[Hardware].AddressPtr,\r
+      SnpMode->HwAddressSize\r
+      );\r
+  }\r
+  TmpPtr += SnpMode->HwAddressSize;\r
+\r
+  //\r
+  // The source MAC address.\r
+  //\r
+  NetCopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);\r
+  TmpPtr += SnpMode->HwAddressSize;\r
+\r
+  //\r
+  // The ethernet protocol type.\r
+  //\r
+  *(UINT16 *)TmpPtr = HTONS (ARP_ETHER_PROTO_TYPE);\r
+  TmpPtr            += 2;\r
+\r
+  //\r
+  // The ARP Head.\r
+  //\r
+  ArpHead               = (ARP_HEAD *) TmpPtr;\r
+  ArpHead->HwType       = HTONS ((UINT16)SnpMode->IfType);\r
+  ArpHead->ProtoType    = HTONS (ConfigData->SwAddressType);\r
+  ArpHead->HwAddrLen    = (UINT8)SnpMode->HwAddressSize;\r
+  ArpHead->ProtoAddrLen = ConfigData->SwAddressLength;\r
+  ArpHead->OpCode       = HTONS (ArpOpCode);\r
+  TmpPtr                += sizeof (ARP_HEAD);\r
+\r
+  //\r
+  // The sender hardware address.\r
+  //\r
+  NetCopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);\r
+  TmpPtr += SnpMode->HwAddressSize;\r
+\r
+  //\r
+  // The sender protocol address.\r
+  //\r
+  NetCopyMem (TmpPtr, ConfigData->StationAddress, ConfigData->SwAddressLength);\r
+  TmpPtr += ConfigData->SwAddressLength;\r
+\r
+  //\r
+  // The target hardware address.\r
+  //\r
+  NetCopyMem (\r
+    TmpPtr,\r
+    CacheEntry->Addresses[Hardware].AddressPtr,\r
+    SnpMode->HwAddressSize\r
+    );\r
+  TmpPtr += SnpMode->HwAddressSize;\r
+\r
+  //\r
+  // The target protocol address.\r
+  //\r
+  NetCopyMem (\r
+    TmpPtr,\r
+    CacheEntry->Addresses[Protocol].AddressPtr,\r
+    ConfigData->SwAddressLength\r
+    );\r
+\r
+  //\r
+  // Set all the fields of the TxData.\r
+  //\r
+  TxData->DestinationAddress = NULL;\r
+  TxData->SourceAddress      = NULL;\r
+  TxData->ProtocolType       = 0;\r
+  TxData->DataLength         = TotalLength - SnpMode->MediaHeaderSize;\r
+  TxData->HeaderLength       = (UINT16) SnpMode->MediaHeaderSize;\r
+  TxData->FragmentCount      = 1;\r
+\r
+  TxData->FragmentTable[0].FragmentBuffer = Packet;\r
+  TxData->FragmentTable[0].FragmentLength = TotalLength;\r
+\r
+  //\r
+  // Associate the TxData with the TxToken.\r
+  //\r
+  TxToken->Packet.TxData = TxData;\r
+  TxToken->Status        = EFI_NOT_READY;\r
+\r
+  //\r
+  // Send out this arp packet by Mnp.\r
+  //\r
+  Status = ArpService->Mnp->Transmit (ArpService->Mnp, TxToken);\r
+  if (EFI_ERROR (Status)) {\r
+    ARP_DEBUG_ERROR (("Mnp->Transmit failed, %r.\n", Status));\r
+    goto CLEAN_EXIT;\r
+  }\r
+\r
+  return;\r
+\r
+CLEAN_EXIT:\r
+\r
+  if (Packet != NULL) {\r
+    NetFreePool (Packet);\r
+  }\r
+\r
+  if (TxData != NULL) {\r
+    NetFreePool (TxData);\r
+  }\r
+\r
+  if (TxToken->Event != NULL) {\r
+    gBS->CloseEvent (TxToken->Event);\r
+  }\r
+\r
+  NetFreePool (TxToken);\r
+}\r
+\r
+\r
+/**\r
+  Delete the cache entries in the specified CacheTable, using the BySwAddress,\r
+  SwAddressType, AddressBuffer combination as the matching key, if Force is TRUE,\r
+  the cache is deleted event it's a static entry.\r
+\r
+  @param  CacheTable             Pointer to the cache table to do the deletion.\r
+  @param  BySwAddress            Delete the cache entry by software address or by\r
+                                 hardware address.\r
+  @param  SwAddressType          The software address used to do the deletion.\r
+  @param  AddressBuffer          Pointer to the buffer containing the address to\r
+                                 match for the deletion.\r
+  @param  Force                  This deletion is forced or not.\r
+\r
+  @return The count of the deleted cache entries.\r
+\r
+**/\r
+STATIC\r
+UINTN\r
+ArpDeleteCacheEntryInTable (\r
+  IN NET_LIST_ENTRY  *CacheTable,\r
+  IN BOOLEAN         BySwAddress,\r
+  IN UINT16          SwAddressType,\r
+  IN UINT8           *AddressBuffer OPTIONAL,\r
+  IN BOOLEAN         Force\r
+  )\r
+{\r
+  NET_LIST_ENTRY   *Entry;\r
+  NET_LIST_ENTRY   *NextEntry;\r
+  ARP_CACHE_ENTRY  *CacheEntry;\r
+  UINTN            Count;\r
+\r
+  Count = 0;\r
+\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, CacheTable) {\r
+    CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
+\r
+    if ((CacheEntry->DefaultDecayTime == 0) && !Force) {\r
+      //\r
+      // It's a static entry and we are not forced to delete it, skip.\r
+      //\r
+      continue;\r
+    }\r
+\r
+    if (BySwAddress) {\r
+      if (SwAddressType == CacheEntry->Addresses[Protocol].Type) {\r
+        //\r
+        // Protocol address type matched. Check the address.\r
+        //\r
+        if ((AddressBuffer == NULL) ||\r
+          (NetCompareMem (\r
+             AddressBuffer,\r
+             CacheEntry->Addresses[Protocol].AddressPtr,\r
+             CacheEntry->Addresses[Protocol].Length\r
+             ) == 0)) {\r
+          //\r
+          // Address matched.\r
+          //\r
+          goto MATCHED;\r
+        }\r
+      }\r
+    } else {\r
+      if ((AddressBuffer == NULL) ||\r
+        (NetCompareMem (\r
+           AddressBuffer,\r
+           CacheEntry->Addresses[Hardware].AddressPtr,\r
+           CacheEntry->Addresses[Hardware].Length\r
+           ) == 0)) {\r
+        //\r
+        // Address matched.\r
+        //\r
+        goto MATCHED;\r
+      }\r
+    }\r
+\r
+    continue;\r
+\r
+MATCHED:\r
+\r
+    //\r
+    // Delete this entry.\r
+    //\r
+    NetListRemoveEntry (&CacheEntry->List);\r
+    ASSERT (NetListIsEmpty (&CacheEntry->UserRequestList));\r
+    NetFreePool (CacheEntry);\r
+\r
+    Count++;\r
+  }\r
+\r
+  return Count;\r
+}\r
+\r
+\r
+/**\r
+  Delete cache entries in all the cache tables.\r
+\r
+  @param  Instance               Pointer to the instance context data.\r
+  @param  BySwAddress            Delete the cache entry by software address or by\r
+                                 hardware address.\r
+  @param  AddressBuffer          Pointer to the buffer containing the address to\r
+                                 match for the deletion.\r
+  @param  Force                  This deletion is forced or not.\r
+\r
+  @return The count of the deleted cache entries.\r
+\r
+**/\r
+UINTN\r
+ArpDeleteCacheEntry (\r
+  IN ARP_INSTANCE_DATA  *Instance,\r
+  IN BOOLEAN            BySwAddress,\r
+  IN UINT8              *AddressBuffer OPTIONAL,\r
+  IN BOOLEAN            Force\r
+  )\r
+{\r
+  ARP_SERVICE_DATA  *ArpService;\r
+  UINTN             Count;\r
+\r
+  NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);\r
+\r
+  ArpService = Instance->ArpService;\r
+\r
+  //\r
+  // Delete the cache entries in the DeniedCacheTable.\r
+  //\r
+  Count = ArpDeleteCacheEntryInTable (\r
+            &ArpService->DeniedCacheTable,\r
+            BySwAddress,\r
+            Instance->ConfigData.SwAddressType,\r
+            AddressBuffer,\r
+            Force\r
+            );\r
+\r
+  //\r
+  // Delete the cache entries inthe ResolvedCacheTable.\r
+  //\r
+  Count += ArpDeleteCacheEntryInTable (\r
+             &ArpService->ResolvedCacheTable,\r
+             BySwAddress,\r
+             Instance->ConfigData.SwAddressType,\r
+             AddressBuffer,\r
+             Force\r
+             );\r
+\r
+  return Count;\r
+}\r
+\r
+\r
+/**\r
+  Cancel the arp request.\r
+\r
+  @param  Instance               Pointer to the instance context data.\r
+  @param  TargetSwAddress        Pointer to the buffer containing the target\r
+                                 software address to match the arp request.\r
+  @param  UserEvent              The user event used to notify this request\r
+                                 cancellation.\r
+\r
+  @return The count of the cancelled requests.\r
+\r
+**/\r
+UINTN\r
+ArpCancelRequest (\r
+  IN ARP_INSTANCE_DATA  *Instance,\r
+  IN VOID               *TargetSwAddress OPTIONAL,\r
+  IN EFI_EVENT          UserEvent        OPTIONAL\r
+  )\r
+{\r
+  ARP_SERVICE_DATA  *ArpService;\r
+  NET_LIST_ENTRY    *Entry;\r
+  NET_LIST_ENTRY    *NextEntry;\r
+  ARP_CACHE_ENTRY   *CacheEntry;\r
+  UINTN             Count;\r
+\r
+  NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);\r
+\r
+  ArpService = Instance->ArpService;\r
+\r
+  Count = 0;\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {\r
+    CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
+\r
+    if ((TargetSwAddress == NULL) ||\r
+      (NetCompareMem (\r
+         TargetSwAddress,\r
+         CacheEntry->Addresses[Protocol].AddressPtr,\r
+         CacheEntry->Addresses[Protocol].Length\r
+         ) == 0)) {\r
+      //\r
+      // This request entry matches the TargetSwAddress or all requests are to be\r
+      // cancelled as TargetSwAddress is NULL.\r
+      //\r
+      Count += ArpAddressResolved (CacheEntry, Instance, UserEvent);\r
+\r
+      if (NetListIsEmpty (&CacheEntry->UserRequestList)) {\r
+        //\r
+        // No user requests any more, remove this request cache entry.\r
+        //\r
+        NetListRemoveEntry (&CacheEntry->List);\r
+        NetFreePool (CacheEntry);\r
+      }\r
+    }\r
+  }\r
+\r
+  return Count;\r
+}\r
+\r
+\r
+/**\r
+  Find the cache entry in the cache table.\r
+\r
+  @param  Instance               Pointer to the instance context data.\r
+  @param  BySwAddress            Set to TRUE to look for matching software protocol\r
+                                 addresses. Set to FALSE to look for matching\r
+                                 hardware protocol addresses.\r
+  @param  AddressBuffer          Pointer to address buffer. Set to NULL to match\r
+                                 all addresses.\r
+  @param  EntryLength            The size of an entry in the entries buffer.\r
+  @param  EntryCount             The number of ARP cache entries that are found by\r
+                                 the specified criteria.\r
+  @param  Entries                Pointer to the buffer that will receive the ARP\r
+                                 cache entries.\r
+  @param  Refresh                Set to TRUE to refresh the timeout value of the\r
+                                 matching ARP cache entry.\r
+\r
+  @retval EFI_SUCCESS            The requested ARP cache entries are copied into\r
+                                 the buffer.\r
+  @retval EFI_NOT_FOUND          No matching entries found.\r
+  @retval EFI_OUT_OF_RESOURCE    There is a memory allocation failure.\r
+\r
+**/\r
+EFI_STATUS\r
+ArpFindCacheEntry (\r
+  IN ARP_INSTANCE_DATA   *Instance,\r
+  IN BOOLEAN             BySwAddress,\r
+  IN VOID                *AddressBuffer OPTIONAL,\r
+  OUT UINT32             *EntryLength   OPTIONAL,\r
+  OUT UINT32             *EntryCount    OPTIONAL,\r
+  OUT EFI_ARP_FIND_DATA  **Entries      OPTIONAL,\r
+  IN BOOLEAN             Refresh\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  ARP_SERVICE_DATA   *ArpService;\r
+  NET_ARP_ADDRESS    MatchAddress;\r
+  FIND_OPTYPE        FindOpType;\r
+  NET_LIST_ENTRY     *StartEntry;\r
+  ARP_CACHE_ENTRY    *CacheEntry;\r
+  NET_MAP            FoundEntries;\r
+  UINT32             FoundCount;\r
+  EFI_ARP_FIND_DATA  *FindData;\r
+  NET_LIST_ENTRY     *CacheTable;\r
+\r
+  ArpService = Instance->ArpService;\r
+\r
+  //\r
+  // Init the FounEntries used to hold the found cache entries.\r
+  //\r
+  NetMapInit (&FoundEntries);\r
+\r
+  //\r
+  // Set the MatchAddress.\r
+  //\r
+  if (BySwAddress) {\r
+    MatchAddress.Type   = Instance->ConfigData.SwAddressType;\r
+    MatchAddress.Length = Instance->ConfigData.SwAddressLength;\r
+    FindOpType          = ByProtoAddress;\r
+  } else {\r
+    MatchAddress.Type   = ArpService->SnpMode.IfType;\r
+    MatchAddress.Length = (UINT8)ArpService->SnpMode.HwAddressSize;\r
+    FindOpType          = ByHwAddress;\r
+  }\r
+\r
+  MatchAddress.AddressPtr = AddressBuffer;\r
+\r
+  //\r
+  // Search the DeniedCacheTable\r
+  //\r
+  StartEntry = NULL;\r
+  while (TRUE) {\r
+    //\r
+    // Try to find the matched entries in the DeniedCacheTable.\r
+    //\r
+    CacheEntry = ArpFindNextCacheEntryInTable (\r
+                   &ArpService->DeniedCacheTable,\r
+                   StartEntry,\r
+                   FindOpType,\r
+                   &MatchAddress,\r
+                   &MatchAddress\r
+                   );\r
+    if (CacheEntry == NULL) {\r
+      //\r
+      // Once the CacheEntry is NULL, there are no more matches.\r
+      //\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Insert the found entry into the map.\r
+    //\r
+    NetMapInsertTail (\r
+      &FoundEntries,\r
+      (VOID *)CacheEntry,\r
+      (VOID *)&ArpService->DeniedCacheTable\r
+      );\r
+\r
+    //\r
+    // Let the next search start from this cache entry.\r
+    //\r
+    StartEntry = &CacheEntry->List;\r
+\r
+    if (Refresh) {\r
+      //\r
+      // Refresh the DecayTime if needed.\r
+      //\r
+      CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Search the ResolvedCacheTable\r
+  //\r
+  StartEntry = NULL;\r
+  while (TRUE) {\r
+    CacheEntry = ArpFindNextCacheEntryInTable (\r
+                   &ArpService->ResolvedCacheTable,\r
+                   StartEntry,\r
+                   FindOpType,\r
+                   &MatchAddress,\r
+                   &MatchAddress\r
+                   );\r
+    if (CacheEntry == NULL) {\r
+      //\r
+      // Once the CacheEntry is NULL, there are no more matches.\r
+      //\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Insert the found entry into the map.\r
+    //\r
+    NetMapInsertTail (\r
+      &FoundEntries,\r
+      (VOID *)CacheEntry,\r
+      (VOID *)&ArpService->ResolvedCacheTable\r
+      );\r
+\r
+    //\r
+    // Let the next search start from this cache entry.\r
+    //\r
+    StartEntry = &CacheEntry->List;\r
+\r
+    if (Refresh) {\r
+      //\r
+      // Refresh the DecayTime if needed.\r
+      //\r
+      CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;\r
+    }\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  FoundCount = (UINT32) NetMapGetCount (&FoundEntries);\r
+  if (FoundCount == 0) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto CLEAN_EXIT;\r
+  }\r
+\r
+  if (EntryLength != NULL) {\r
+    //\r
+    // Return the entry length.\r
+    //\r
+    *EntryLength = sizeof (EFI_ARP_FIND_DATA) + Instance->ConfigData.SwAddressLength +\r
+                   ArpService->SnpMode.HwAddressSize;\r
+  }\r
+\r
+  if (EntryCount != NULL) {\r
+    //\r
+    // Return the found entry count.\r
+    //\r
+    *EntryCount = FoundCount;\r
+  }\r
+\r
+  if (Entries == NULL) {\r
+    goto CLEAN_EXIT;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer to copy the found entries.\r
+  //\r
+  FindData = NetAllocatePool (FoundCount * (*EntryLength));\r
+  if (FindData == NULL) {\r
+    ARP_DEBUG_ERROR (("ArpFindCacheEntry: Failed to allocate memory.\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto CLEAN_EXIT;\r
+  }\r
+\r
+  //\r
+  // Return the address to the user.\r
+  //\r
+  *Entries = FindData;\r
+\r
+  //\r
+  // Dump the entries.\r
+  //\r
+  while (!NetMapIsEmpty (&FoundEntries)) {\r
+    //\r
+    // Get a cache entry from the map.\r
+    //\r
+    CacheEntry = NetMapRemoveHead (&FoundEntries, (VOID **)&CacheTable);\r
+\r
+    //\r
+    // Set the fields in FindData.\r
+    //\r
+    FindData->Size            = *EntryLength;\r
+    FindData->DenyFlag        = (BOOLEAN)(CacheTable == &ArpService->DeniedCacheTable);\r
+    FindData->StaticFlag      = (BOOLEAN)(CacheEntry->DefaultDecayTime == 0);\r
+    FindData->HwAddressType   = ArpService->SnpMode.IfType;\r
+    FindData->SwAddressType   = Instance->ConfigData.SwAddressType;\r
+    FindData->HwAddressLength = (UINT8)ArpService->SnpMode.HwAddressSize;\r
+    FindData->SwAddressLength = Instance->ConfigData.SwAddressLength;\r
+\r
+    //\r
+    // Copy the software address.\r
+    //\r
+    NetCopyMem (\r
+      FindData + 1,\r
+      CacheEntry->Addresses[Protocol].AddressPtr,\r
+      FindData->SwAddressLength\r
+      );\r
+\r
+    //\r
+    // Copy the hardware address.\r
+    //\r
+    NetCopyMem (\r
+      (UINT8 *)(FindData + 1) + FindData->SwAddressLength,\r
+      CacheEntry->Addresses[Hardware].AddressPtr,\r
+      FindData->HwAddressLength\r
+      );\r
+\r
+    //\r
+    // Slip to the next FindData.\r
+    //\r
+    FindData = (EFI_ARP_FIND_DATA *)((UINT8 *)FindData + *EntryLength);\r
+  }\r
+\r
+CLEAN_EXIT:\r
+\r
+  NetMapClean (&FoundEntries);\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ArpImpl.h b/MdeModulePkg/Universal/Network/ArpDxe/ArpImpl.h
new file mode 100644 (file)
index 0000000..607443a
--- /dev/null
@@ -0,0 +1,341 @@
+/** @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:
+
+  ArpImpl.h
+
+Abstract:
+
+
+**/
+
+#ifndef _ARP_IMPL_H_
+#define _ARP_IMPL_H_
+
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/Arp.h>\r
+#include <Protocol/ManagedNetwork.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>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "ArpDebug.h"
+
+#define ARP_ETHER_PROTO_TYPE         0x0806
+#define IPv4_ETHER_PROTO_TYPE        0x0800
+#define IPv6_ETHER_PROTO_TYPE        0x86DD
+
+#define ARP_OPCODE_REQUEST           0x0001
+#define ARP_OPCODE_REPLY             0x0002
+
+#define ARP_DEFAULT_TIMEOUT_VALUE    (400 * TICKS_PER_SECOND)
+#define ARP_DEFAULT_RETRY_COUNT      2
+#define ARP_DEFAULT_RETRY_INTERVAL   (5   * TICKS_PER_MS)
+#define ARP_PERIODIC_TIMER_INTERVAL  (500 * TICKS_PER_MS)
+
+#pragma pack(1)
+typedef struct _ARP_HEAD {
+  UINT16  HwType;
+  UINT16  ProtoType;
+  UINT8   HwAddrLen;
+  UINT8   ProtoAddrLen;
+  UINT16  OpCode;
+} ARP_HEAD;
+#pragma pack()
+
+typedef struct _ARP_ADDRESS {
+  UINT8  *SenderHwAddr;
+  UINT8  *SenderProtoAddr;
+  UINT8  *TargetHwAddr;
+  UINT8  *TargetProtoAddr;
+} ARP_ADDRESS;
+
+#define MATCH_SW_ADDRESS  0x1
+#define MATCH_HW_ADDRESS  0x2
+
+typedef enum {
+  ByNone         = 0,
+  ByProtoAddress = MATCH_SW_ADDRESS,
+  ByHwAddress    = MATCH_HW_ADDRESS,
+  ByBoth         = MATCH_SW_ADDRESS | MATCH_HW_ADDRESS
+} FIND_OPTYPE;
+
+#define ARP_INSTANCE_DATA_SIGNATURE  EFI_SIGNATURE_32('A', 'R', 'P', 'I')
+
+#define ARP_INSTANCE_DATA_FROM_THIS(a) \
+  CR ( \
+  (a), \
+  ARP_INSTANCE_DATA, \
+  ArpProto, \
+  ARP_INSTANCE_DATA_SIGNATURE \
+  )
+
+typedef struct _ARP_SERVICE_DATA  ARP_SERVICE_DATA;
+
+typedef struct _ARP_INSTANCE_DATA {
+  UINT32               Signature;
+  ARP_SERVICE_DATA     *ArpService;
+  EFI_HANDLE           Handle;
+  EFI_ARP_PROTOCOL     ArpProto;
+  NET_LIST_ENTRY       List;
+  EFI_ARP_CONFIG_DATA  ConfigData;
+  BOOLEAN              Configured;
+  BOOLEAN              Destroyed;
+} ARP_INSTANCE_DATA;
+
+#define ARP_SERVICE_DATA_SIGNATURE  EFI_SIGNATURE_32('A', 'R', 'P', 'S')
+
+#define ARP_SERVICE_DATA_FROM_THIS(a) \
+  CR ( \
+  (a), \
+  ARP_SERVICE_DATA, \
+  ServiceBinding, \
+  ARP_SERVICE_DATA_SIGNATURE \
+  )
+
+struct _ARP_SERVICE_DATA {
+  UINT32                           Signature;
+  EFI_SERVICE_BINDING_PROTOCOL     ServiceBinding;
+
+  EFI_HANDLE                       MnpChildHandle;
+  EFI_HANDLE                       ImageHandle;
+  EFI_HANDLE                       ControllerHandle;
+
+  EFI_MANAGED_NETWORK_PROTOCOL          *Mnp;
+  EFI_MANAGED_NETWORK_CONFIG_DATA       MnpConfigData;
+  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  RxToken;
+
+  EFI_SIMPLE_NETWORK_MODE          SnpMode;
+
+  NET_LOCK                         Lock;
+
+  UINTN                            ChildrenNumber;
+  NET_LIST_ENTRY                   ChildrenList;
+
+  NET_LIST_ENTRY                   PendingRequestTable;
+  NET_LIST_ENTRY                   DeniedCacheTable;
+  NET_LIST_ENTRY                   ResolvedCacheTable;
+
+  EFI_EVENT                        PeriodicTimer;
+};
+
+typedef struct _USER_REQUEST_CONTEXT {
+  NET_LIST_ENTRY     List;
+  ARP_INSTANCE_DATA  *Instance;
+  EFI_EVENT          UserRequestEvent;
+  VOID               *UserHwAddrBuffer;
+} USER_REQUEST_CONTEXT;
+
+#define ARP_MAX_PROTOCOL_ADDRESS_LEN  sizeof(EFI_IP_ADDRESS)
+#define ARP_MAX_HARDWARE_ADDRESS_LEN  sizeof(EFI_MAC_ADDRESS)
+
+typedef struct _NET_ARP_ADDRESS {
+  UINT16  Type;
+  UINT8   Length;
+  UINT8   *AddressPtr;
+  union {
+    UINT8  ProtoAddress[ARP_MAX_PROTOCOL_ADDRESS_LEN];
+    UINT8  HwAddress[ARP_MAX_HARDWARE_ADDRESS_LEN];
+  } Buffer;
+} NET_ARP_ADDRESS;
+
+typedef enum {
+  Hardware,
+  Protocol
+} ARP_ADDRESS_TYPE;
+
+typedef struct _ARP_CACHE_ENTRY {
+  NET_LIST_ENTRY  List;
+
+  UINT32          RetryCount;
+  UINT32          DefaultDecayTime;
+  UINT32          DecayTime;
+  UINT32          NextRetryTime;
+
+  NET_ARP_ADDRESS  Addresses[2];
+
+  NET_LIST_ENTRY  UserRequestList;
+} ARP_CACHE_ENTRY;
+
+EFI_STATUS
+EFIAPI
+ArpConfigure (
+  IN EFI_ARP_PROTOCOL     *This,
+  IN EFI_ARP_CONFIG_DATA  *ConfigData OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+ArpAdd (
+  IN EFI_ARP_PROTOCOL  *This,
+  IN BOOLEAN           DenyFlag,
+  IN VOID              *TargetSwAddress OPTIONAL,
+  IN VOID              *TargetHwAddress OPTIONAL,
+  IN UINT32            TimeoutValue,
+  IN BOOLEAN           Overwrite
+  );
+
+EFI_STATUS
+EFIAPI
+ArpFind (
+  IN EFI_ARP_PROTOCOL    *This,
+  IN BOOLEAN             BySwAddress,
+  IN VOID                *AddressBuffer OPTIONAL,
+  OUT UINT32             *EntryLength   OPTIONAL,
+  OUT UINT32             *EntryCount    OPTIONAL,
+  OUT EFI_ARP_FIND_DATA  **Entries      OPTIONAL,
+  IN BOOLEAN             Refresh
+  );
+
+EFI_STATUS
+EFIAPI
+ArpDelete (
+  IN EFI_ARP_PROTOCOL  *This,
+  IN BOOLEAN           BySwAddress,
+  IN VOID              *AddressBuffer OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+ArpFlush (
+  IN EFI_ARP_PROTOCOL  *This
+  );
+
+EFI_STATUS
+EFIAPI
+ArpRequest (
+  IN EFI_ARP_PROTOCOL  *This,
+  IN VOID              *TargetSwAddress OPTIONAL,
+  IN EFI_EVENT         ResolvedEvent    OPTIONAL,
+  OUT VOID             *TargetHwAddress
+  );
+
+EFI_STATUS
+EFIAPI
+ArpCancel (
+  IN EFI_ARP_PROTOCOL  *This,
+  IN VOID              *TargetSwAddress OPTIONAL,
+  IN EFI_EVENT         ResolvedEvent    OPTIONAL
+  );
+
+EFI_STATUS
+ArpConfigureInstance (
+  IN ARP_INSTANCE_DATA    *Instance,
+  IN EFI_ARP_CONFIG_DATA  *ConfigData OPTIONAL
+  );
+
+ARP_CACHE_ENTRY *
+ArpFindDeniedCacheEntry (
+  IN ARP_SERVICE_DATA  *ArpService,
+  IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,
+  IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL
+  );
+
+ARP_CACHE_ENTRY *
+ArpFindNextCacheEntryInTable (
+  IN NET_LIST_ENTRY    *CacheTable,
+  IN NET_LIST_ENTRY    *StartEntry,
+  IN FIND_OPTYPE       FindOpType,
+  IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,
+  IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL
+  );
+
+ARP_CACHE_ENTRY *
+ArpAllocCacheEntry (
+  IN ARP_INSTANCE_DATA  *Instance
+  );
+
+VOID
+ArpFillAddressInCacheEntry (
+  IN ARP_CACHE_ENTRY  *CacheEntry,
+  IN NET_ARP_ADDRESS  *HwAddr OPTIONAL,
+  IN NET_ARP_ADDRESS  *SwAddr OPTIONAL
+  );
+
+UINTN
+ArpAddressResolved (
+  IN ARP_CACHE_ENTRY    *CacheEntry,
+  IN ARP_INSTANCE_DATA  *Instance OPTIONAL,
+  IN EFI_EVENT          UserEvent OPTIONAL
+  );
+
+UINTN
+ArpDeleteCacheEntry (
+  IN ARP_INSTANCE_DATA  *Instance,
+  IN BOOLEAN            BySwAddress,
+  IN UINT8              *AddressBuffer OPTIONAL,
+  IN BOOLEAN            Force
+  );
+
+VOID
+ArpSendFrame (
+  IN ARP_INSTANCE_DATA  *Instance,
+  IN ARP_CACHE_ENTRY    *CacheEntry,
+  IN UINT16             ArpOpCode
+  );
+
+VOID
+ArpInitInstance (
+  IN ARP_SERVICE_DATA   *ArpService,
+  IN ARP_INSTANCE_DATA  *Instance
+  );
+
+VOID
+EFIAPI
+ArpOnFrameRcvd (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
+VOID
+EFIAPI
+ArpOnFrameSent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
+VOID
+EFIAPI
+ArpTimerHandler (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
+UINTN
+ArpCancelRequest (
+  IN ARP_INSTANCE_DATA  *Instance,
+  IN VOID               *TargetSwAddress OPTIONAL,
+  IN EFI_EVENT          UserEvent        OPTIONAL
+  );
+
+EFI_STATUS
+ArpFindCacheEntry (
+  IN ARP_INSTANCE_DATA   *Instance,
+  IN BOOLEAN             BySwAddress,
+  IN VOID                *AddressBuffer OPTIONAL,
+  OUT UINT32             *EntryLength   OPTIONAL,
+  OUT UINT32             *EntryCount    OPTIONAL,
+  OUT EFI_ARP_FIND_DATA  **Entries      OPTIONAL,
+  IN BOOLEAN             Refresh
+  );
+
+#endif
+
diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ArpMain.c b/MdeModulePkg/Universal/Network/ArpDxe/ArpMain.c
new file mode 100644 (file)
index 0000000..eb1b082
--- /dev/null
@@ -0,0 +1,727 @@
+/** @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
+  ArpMain.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "ArpImpl.h"\r
+\r
+\r
+/**\r
+  This function is used to assign a station address to the ARP cache for this instance\r
+  of the ARP driver. A call to this function with the ConfigData field set to NULL\r
+  will reset this ARP instance.\r
+\r
+  @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.\r
+  @param  ConfigData             Pointer to the EFI_ARP_CONFIG_DATA structure.\r
+\r
+  @retval EFI_SUCCESS            The new station address was successfully\r
+                                 registered.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:\r
+                                 This is NULL. SwAddressLength is zero when\r
+                                 ConfigData is not NULL. StationAddress is NULL\r
+                                 when ConfigData is not NULL.\r
+  @retval EFI_ACCESS_DENIED      The SwAddressType, SwAddressLength, or\r
+                                 StationAddress is different from the one that is\r
+                                 already registered.\r
+  @retval EFI_OUT_OF_RESOURCES   Storage for the new StationAddress could not be\r
+                                 allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ArpConfigure (\r
+  IN EFI_ARP_PROTOCOL     *This,\r
+  IN EFI_ARP_CONFIG_DATA  *ConfigData OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  ARP_INSTANCE_DATA  *Instance;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((ConfigData != NULL) &&\r
+    ((ConfigData->SwAddressLength == 0) ||\r
+    (ConfigData->StationAddress == NULL) ||\r
+    (ConfigData->SwAddressType <= 1500))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = ARP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&Instance->ArpService->Lock))) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // Configure this instance, the ConfigData has already passed the basic checks.\r
+  //\r
+  Status = ArpConfigureInstance (Instance, ConfigData);\r
+\r
+  NET_UNLOCK (&Instance->ArpService->Lock);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function is used to insert entries into the ARP cache.\r
+\r
+  @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.\r
+  @param  DenyFlag               Set to TRUE if this entry is a deny entry. Set to\r
+                                 FALSE if this  entry is a normal entry.\r
+  @param  TargetSwAddress        Pointer to a protocol address to add (or deny).\r
+                                 May be set to NULL if DenyFlag is TRUE.\r
+  @param  TargetHwAddress        Pointer to a hardware address to add (or deny).\r
+                                 May be set to NULL if DenyFlag is TRUE.\r
+  @param  TimeoutValue           Time in 100-ns units that this entry will remain\r
+                                 in the ARP cache. A value of zero means that the\r
+                                 entry is permanent. A nonzero value will override\r
+                                 the one given by Configure() if the entry to be\r
+                                 added is a dynamic entry.\r
+  @param  Overwrite              If TRUE, the matching cache entry will be\r
+                                 overwritten with the supplied parameters. If\r
+                                 FALSE, EFI_ACCESS_DENIED is returned if the\r
+                                 corresponding cache entry already exists.\r
+\r
+  @retval EFI_SUCCESS            The entry has been added or updated.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:\r
+                                 This is NULL. DenyFlag is FALSE and\r
+                                 TargetHwAddress is NULL. DenyFlag is FALSE and\r
+                                 TargetSwAddress is NULL. TargetHwAddress is NULL\r
+                                 and TargetSwAddress is NULL. Both TargetSwAddress\r
+                                 and TargetHwAddress are not NULL when DenyFlag is\r
+                                 TRUE.\r
+  @retval EFI_OUT_OF_RESOURCES   The new ARP cache entry could not be allocated.\r
+  @retval EFI_ACCESS_DENIED      The ARP cache entry already exists and Overwrite\r
+                                 is not true.\r
+  @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ArpAdd (\r
+  IN EFI_ARP_PROTOCOL  *This,\r
+  IN BOOLEAN           DenyFlag,\r
+  IN VOID              *TargetSwAddress OPTIONAL,\r
+  IN VOID              *TargetHwAddress OPTIONAL,\r
+  IN UINT32            TimeoutValue,\r
+  IN BOOLEAN           Overwrite\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  ARP_INSTANCE_DATA        *Instance;\r
+  ARP_SERVICE_DATA         *ArpService;\r
+  ARP_CACHE_ENTRY          *CacheEntry;\r
+  EFI_SIMPLE_NETWORK_MODE  *SnpMode;\r
+  NET_ARP_ADDRESS          MatchAddress[2];\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (((!DenyFlag) && ((TargetHwAddress == NULL) || (TargetSwAddress == NULL))) ||\r
+    (DenyFlag && (TargetHwAddress != NULL) && (TargetSwAddress != NULL)) ||\r
+    ((TargetHwAddress == NULL) && (TargetSwAddress == NULL))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = ARP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  Status     = EFI_SUCCESS;\r
+  ArpService = Instance->ArpService;\r
+  SnpMode    = &Instance->ArpService->SnpMode;\r
+\r
+  //\r
+  // Fill the hardware address part in the MatchAddress.\r
+  //\r
+  MatchAddress[Hardware].Type       = SnpMode->IfType;\r
+  MatchAddress[Hardware].Length     = (UINT8) SnpMode->HwAddressSize;\r
+  MatchAddress[Hardware].AddressPtr = TargetHwAddress;\r
+\r
+  //\r
+  // Fill the software address part in the MatchAddress.\r
+  //\r
+  MatchAddress[Protocol].Type       = Instance->ConfigData.SwAddressType;\r
+  MatchAddress[Protocol].Length     = Instance->ConfigData.SwAddressLength;\r
+  MatchAddress[Protocol].AddressPtr = TargetSwAddress;\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // See whether the entry to add exists. Check the DeinedCacheTable first.\r
+  //\r
+  CacheEntry = ArpFindDeniedCacheEntry (\r
+                 ArpService,\r
+                 &MatchAddress[Protocol],\r
+                 &MatchAddress[Hardware]\r
+                 );\r
+\r
+  if (CacheEntry == NULL) {\r
+    //\r
+    // Check the ResolvedCacheTable\r
+    //\r
+    CacheEntry = ArpFindNextCacheEntryInTable (\r
+                   &ArpService->ResolvedCacheTable,\r
+                   NULL,\r
+                   ByBoth,\r
+                   &MatchAddress[Protocol],\r
+                   &MatchAddress[Hardware]\r
+                   );\r
+  }\r
+\r
+  if ((CacheEntry != NULL) && !Overwrite) {\r
+    //\r
+    // The entry to add exists, if not Overwirte, deny this add request.\r
+    //\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto UNLOCK_EXIT;\r
+  }\r
+\r
+  if ((CacheEntry == NULL) && (TargetSwAddress != NULL)) {\r
+    //\r
+    // Check whether there are pending requests matching the entry to be added.\r
+    //\r
+    CacheEntry = ArpFindNextCacheEntryInTable (\r
+                   &ArpService->PendingRequestTable,\r
+                   NULL,\r
+                   ByProtoAddress,\r
+                   &MatchAddress[Protocol],\r
+                   NULL\r
+                   );\r
+  }\r
+\r
+  if (CacheEntry != NULL) {\r
+    //\r
+    // Remove it from the Table.\r
+    //\r
+    NetListRemoveEntry (&CacheEntry->List);\r
+  } else {\r
+    //\r
+    // It's a new entry, allocate memory for the entry.\r
+    //\r
+    CacheEntry = ArpAllocCacheEntry (Instance);\r
+\r
+    if (CacheEntry == NULL) {\r
+      ARP_DEBUG_ERROR (("ArpAdd: Failed to allocate pool for CacheEntry.\n"));\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto UNLOCK_EXIT;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Overwrite these parameters.\r
+  //\r
+  CacheEntry->DefaultDecayTime = TimeoutValue;\r
+  CacheEntry->DecayTime        = TimeoutValue;\r
+\r
+  //\r
+  // Fill in the addresses.\r
+  //\r
+  ArpFillAddressInCacheEntry (\r
+    CacheEntry,\r
+    &MatchAddress[Hardware],\r
+    &MatchAddress[Protocol]\r
+    );\r
+\r
+  //\r
+  // Inform the user if there is any.\r
+  //\r
+  ArpAddressResolved (CacheEntry, NULL, NULL);\r
+\r
+  //\r
+  // Add this CacheEntry to the corresponding CacheTable.\r
+  //\r
+  if (DenyFlag) {\r
+    NetListInsertHead (&ArpService->DeniedCacheTable, &CacheEntry->List);\r
+  } else {\r
+    NetListInsertHead (&ArpService->ResolvedCacheTable, &CacheEntry->List);\r
+  }\r
+\r
+UNLOCK_EXIT:\r
+\r
+  NET_UNLOCK (&ArpService->Lock);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function searches the ARP cache for matching entries and allocates a buffer into\r
+  which those entries are copied.\r
+\r
+  @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.\r
+  @param  BySwAddress            Set to TRUE to look for matching software protocol\r
+                                 addresses. Set to FALSE to look for matching\r
+                                 hardware protocol addresses.\r
+  @param  AddressBuffer          Pointer to address buffer. Set to NULL to match\r
+                                 all addresses.\r
+  @param  EntryLength            The size of an entry in the entries buffer.\r
+  @param  EntryCount             The number of ARP cache entries that are found by\r
+                                 the specified criteria.\r
+  @param  Entries                Pointer to the buffer that will receive the ARP\r
+                                 cache entries.\r
+  @param  Refresh                Set to TRUE to refresh the timeout value of the\r
+                                 matching ARP cache entry.\r
+\r
+  @retval EFI_SUCCESS            The requested ARP cache entries were copied into\r
+                                 the buffer.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:\r
+                                 This is NULL. Both EntryCount and EntryLength are\r
+                                 NULL, when Refresh is FALSE.\r
+  @retval EFI_NOT_FOUND          No matching entries were found.\r
+  @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ArpFind (\r
+  IN EFI_ARP_PROTOCOL    *This,\r
+  IN BOOLEAN             BySwAddress,\r
+  IN VOID                *AddressBuffer OPTIONAL,\r
+  OUT UINT32             *EntryLength   OPTIONAL,\r
+  OUT UINT32             *EntryCount    OPTIONAL,\r
+  OUT EFI_ARP_FIND_DATA  **Entries      OPTIONAL,\r
+  IN BOOLEAN             Refresh\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  ARP_INSTANCE_DATA  *Instance;\r
+  ARP_SERVICE_DATA   *ArpService;\r
+\r
+  if ((This == NULL) ||\r
+    (!Refresh && (EntryCount == NULL) && (EntryLength == NULL)) ||\r
+    ((Entries != NULL) && ((EntryLength == NULL) || (EntryCount == NULL)))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance   = ARP_INSTANCE_DATA_FROM_THIS (This);\r
+  ArpService = Instance->ArpService;\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // All the check passed, find the cache entries now.\r
+  //\r
+  Status = ArpFindCacheEntry (\r
+             Instance,\r
+             BySwAddress,\r
+             AddressBuffer,\r
+             EntryLength,\r
+             EntryCount,\r
+             Entries,\r
+             Refresh\r
+             );\r
+\r
+  NET_UNLOCK (&ArpService->Lock);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function removes specified ARP cache entries.\r
+\r
+  @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.\r
+  @param  BySwAddress            Set to TRUE to delete matching protocol addresses.\r
+                                 Set to FALSE to delete matching hardware\r
+                                 addresses.\r
+  @param  AddressBuffer          Pointer to the address buffer that is used as a\r
+                                 key to look for the cache entry. Set to NULL to\r
+                                 delete all entries.\r
+\r
+  @retval EFI_SUCCESS            The entry was removed from the ARP cache.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL.\r
+  @retval EFI_NOT_FOUND          The specified deletion key was not found.\r
+  @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ArpDelete (\r
+  IN EFI_ARP_PROTOCOL  *This,\r
+  IN BOOLEAN           BySwAddress,\r
+  IN VOID              *AddressBuffer OPTIONAL\r
+  )\r
+{\r
+  ARP_INSTANCE_DATA  *Instance;\r
+  ARP_SERVICE_DATA   *ArpService;\r
+  UINTN              Count;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = ARP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  ArpService = Instance->ArpService;\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // Delete the specified cache entries.\r
+  //\r
+  Count = ArpDeleteCacheEntry (Instance, BySwAddress, AddressBuffer, TRUE);\r
+\r
+  NET_UNLOCK (&ArpService->Lock);\r
+\r
+  return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function delete all dynamic entries from the ARP cache that match the specified\r
+  software protocol type.\r
+\r
+  @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.\r
+\r
+  @retval EFI_SUCCESS            The cache has been flushed.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL.\r
+  @retval EFI_NOT_FOUND          There are no matching dynamic cache entries.\r
+  @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ArpFlush (\r
+  IN EFI_ARP_PROTOCOL  *This\r
+  )\r
+{\r
+  ARP_INSTANCE_DATA  *Instance;\r
+  ARP_SERVICE_DATA   *ArpService;\r
+  UINTN              Count;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = ARP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  ArpService = Instance->ArpService;\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // Delete the dynamic entries from the cache table.\r
+  //\r
+  Count = ArpDeleteCacheEntry (Instance, FALSE, NULL, FALSE);\r
+\r
+  NET_UNLOCK (&ArpService->Lock);\r
+\r
+  return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function tries to resolve the TargetSwAddress and optionally returns a\r
+  TargetHwAddress if it already exists in the ARP cache.\r
+\r
+  @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.\r
+  @param  TargetSwAddress        Pointer to the protocol address to resolve.\r
+  @param  ResolvedEvent          Pointer to the event that will be signaled when\r
+                                 the address is resolved or some error occurs.\r
+  @param  TargetHwAddress        Pointer to the buffer for the resolved hardware\r
+                                 address in network byte order.\r
+\r
+  @retval EFI_SUCCESS            The data is copied from the ARP cache into the\r
+                                 TargetHwAddress buffer.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:\r
+                                 This is NULL. TargetHwAddress is NULL.\r
+  @retval EFI_ACCESS_DENIED      The requested address is not present in the normal\r
+                                 ARP cache but is present in the deny address list.\r
+                                 Outgoing traffic to that address is forbidden.\r
+  @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.\r
+  @retval EFI_NOT_READY          The request has been started and is not finished.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ArpRequest (\r
+  IN EFI_ARP_PROTOCOL  *This,\r
+  IN VOID              *TargetSwAddress OPTIONAL,\r
+  IN EFI_EVENT         ResolvedEvent    OPTIONAL,\r
+  OUT VOID             *TargetHwAddress\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  ARP_INSTANCE_DATA        *Instance;\r
+  ARP_SERVICE_DATA         *ArpService;\r
+  EFI_SIMPLE_NETWORK_MODE  *SnpMode;\r
+  ARP_CACHE_ENTRY          *CacheEntry;\r
+  NET_ARP_ADDRESS          HardwareAddress;\r
+  NET_ARP_ADDRESS          ProtocolAddress;\r
+  USER_REQUEST_CONTEXT     *RequestContext;\r
+\r
+  if ((This == NULL) || (TargetHwAddress == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = ARP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  Status     = EFI_SUCCESS;\r
+  ArpService = Instance->ArpService;\r
+  SnpMode    = &ArpService->SnpMode;\r
+\r
+  if ((TargetSwAddress == NULL) ||\r
+    ((Instance->ConfigData.SwAddressType == IPv4_ETHER_PROTO_TYPE) &&\r
+    IP4_IS_LOCAL_BROADCAST (*((UINT32 *)TargetSwAddress)))) {\r
+    //\r
+    // Return the hardware broadcast address.\r
+    //\r
+    NetCopyMem (TargetHwAddress, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);\r
+\r
+    goto SIGNAL_USER;\r
+  }\r
+\r
+  if ((Instance->ConfigData.SwAddressType == IPv4_ETHER_PROTO_TYPE) &&\r
+    IP4_IS_MULTICAST (NTOHL (*((UINT32 *)TargetSwAddress)))) {\r
+    //\r
+    // If the software address is an IPv4 multicast address, invoke Mnp to\r
+    // resolve the address.\r
+    //\r
+    Status = ArpService->Mnp->McastIpToMac (\r
+                                ArpService->Mnp,\r
+                                FALSE,\r
+                                TargetSwAddress,\r
+                                TargetHwAddress\r
+                                );\r
+    goto SIGNAL_USER;\r
+  }\r
+\r
+  HardwareAddress.Type       = SnpMode->IfType;\r
+  HardwareAddress.Length     = (UINT8)SnpMode->HwAddressSize;\r
+  HardwareAddress.AddressPtr = NULL;\r
+\r
+  ProtocolAddress.Type       = Instance->ConfigData.SwAddressType;\r
+  ProtocolAddress.Length     = Instance->ConfigData.SwAddressLength;\r
+  ProtocolAddress.AddressPtr = TargetSwAddress;\r
+\r
+  //\r
+  // Initialize the TargetHwAddrss to a zero address.\r
+  //\r
+  NetZeroMem (TargetHwAddress, SnpMode->HwAddressSize);\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // Check whether the software address is in the denied table.\r
+  //\r
+  CacheEntry = ArpFindDeniedCacheEntry (ArpService, &ProtocolAddress, NULL);\r
+  if (CacheEntry != NULL) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto UNLOCK_EXIT;\r
+  }\r
+\r
+  //\r
+  // Check whether the software address is already resolved.\r
+  //\r
+  CacheEntry = ArpFindNextCacheEntryInTable (\r
+                 &ArpService->ResolvedCacheTable,\r
+                 NULL,\r
+                 ByProtoAddress,\r
+                 &ProtocolAddress,\r
+                 NULL\r
+                 );\r
+  if (CacheEntry != NULL) {\r
+    //\r
+    // Resolved, copy the address into the user buffer.\r
+    //\r
+    NetCopyMem (\r
+      TargetHwAddress,\r
+      CacheEntry->Addresses[Hardware].AddressPtr,\r
+      CacheEntry->Addresses[Hardware].Length\r
+      );\r
+\r
+    goto UNLOCK_EXIT;\r
+  }\r
+\r
+  if (ResolvedEvent == NULL) {\r
+    Status = EFI_NOT_READY;\r
+    goto UNLOCK_EXIT;\r
+  }\r
+\r
+  //\r
+  // Create a request context for this arp request.\r
+  //\r
+  RequestContext = NetAllocatePool (sizeof(USER_REQUEST_CONTEXT));\r
+  if (RequestContext == NULL) {\r
+    ARP_DEBUG_ERROR (("ArpRequest: Allocate memory for RequestContext failed.\n"));\r
+\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto UNLOCK_EXIT;\r
+  }\r
+\r
+  RequestContext->Instance         = Instance;\r
+  RequestContext->UserRequestEvent = ResolvedEvent;\r
+  RequestContext->UserHwAddrBuffer = TargetHwAddress;\r
+  NetListInit (&RequestContext->List);\r
+\r
+  //\r
+  // Check whether there is a same request.\r
+  //\r
+  CacheEntry = ArpFindNextCacheEntryInTable (\r
+                 &ArpService->PendingRequestTable,\r
+                 NULL,\r
+                 ByProtoAddress,\r
+                 &ProtocolAddress,\r
+                 NULL\r
+                 );\r
+  if (CacheEntry != NULL) {\r
+\r
+    CacheEntry->NextRetryTime = Instance->ConfigData.RetryTimeOut;\r
+    CacheEntry->RetryCount    = Instance->ConfigData.RetryCount;\r
+  } else {\r
+    //\r
+    // Allocate a cache entry for this request.\r
+    //\r
+    CacheEntry = ArpAllocCacheEntry (Instance);\r
+    if (CacheEntry == NULL) {\r
+      ARP_DEBUG_ERROR (("ArpRequest: Allocate memory for CacheEntry failed.\n"));\r
+      NetFreePool (RequestContext);\r
+\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto UNLOCK_EXIT;\r
+    }\r
+\r
+    //\r
+    // Fill the software address.\r
+    //\r
+    ArpFillAddressInCacheEntry (CacheEntry, &HardwareAddress, &ProtocolAddress);\r
+\r
+    //\r
+    // Add this entry into the PendingRequestTable.\r
+    //\r
+    NetListInsertTail (&ArpService->PendingRequestTable, &CacheEntry->List);\r
+  }\r
+\r
+  //\r
+  // Link this request context into the cache entry.\r
+  //\r
+  NetListInsertHead (&CacheEntry->UserRequestList, &RequestContext->List);\r
+\r
+  //\r
+  // Send out the ARP Request frame.\r
+  //\r
+  ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REQUEST);\r
+  Status = EFI_NOT_READY;\r
+\r
+UNLOCK_EXIT:\r
+\r
+  NET_UNLOCK (&ArpService->Lock);\r
+\r
+SIGNAL_USER:\r
+\r
+  if ((ResolvedEvent != NULL) && (Status == EFI_SUCCESS)) {\r
+    gBS->SignalEvent (ResolvedEvent);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function aborts the previous ARP request (identified by This,  TargetSwAddress\r
+  and ResolvedEvent) that is issued by EFI_ARP_PROTOCOL.Request().\r
+\r
+  @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.\r
+  @param  TargetSwAddress        Pointer to the protocol address in previous\r
+                                 request session.\r
+  @param  ResolvedEvent          Pointer to the event that is used as the\r
+                                 notification event in previous request session.\r
+\r
+  @retval EFI_SUCCESS            The pending request session(s) is/are aborted and\r
+                                 corresponding event(s) is/are signaled.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:\r
+                                 This is NULL. TargetSwAddress is not NULL and\r
+                                 ResolvedEvent is NULL. TargetSwAddress is NULL and\r
+                                 ResolvedEvent is not NULL.\r
+  @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.\r
+  @retval EFI_NOT_FOUND          The request is not issued by\r
+                                 EFI_ARP_PROTOCOL.Request().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ArpCancel (\r
+  IN EFI_ARP_PROTOCOL  *This,\r
+  IN VOID              *TargetSwAddress OPTIONAL,\r
+  IN EFI_EVENT         ResolvedEvent    OPTIONAL\r
+  )\r
+{\r
+  ARP_INSTANCE_DATA  *Instance;\r
+  ARP_SERVICE_DATA   *ArpService;\r
+  UINTN              Count;\r
+\r
+  if ((This == NULL) ||\r
+    ((TargetSwAddress != NULL) && (ResolvedEvent == NULL)) ||\r
+    ((TargetSwAddress == NULL) && (ResolvedEvent != NULL))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = ARP_INSTANCE_DATA_FROM_THIS (This);\r
+\r
+  if (!Instance->Configured) {\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  ArpService = Instance->ArpService;\r
+\r
+  if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // Cancel the specified request.\r
+  //\r
+  Count = ArpCancelRequest (Instance, TargetSwAddress, ResolvedEvent);\r
+\r
+  NET_UNLOCK (&ArpService->Lock);\r
+\r
+  return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/ArpDxe/ComponentName.c b/MdeModulePkg/Universal/Network/ArpDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..ad92f3c
--- /dev/null
@@ -0,0 +1,156 @@
+/** @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
+#include "ArpDriver.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+ArpComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+ArpComponentNameGetControllerName (\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  gArpComponentName = {\r
+  ArpComponentNameGetDriverName,\r
+  ArpComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+STATIC EFI_UNICODE_STRING_TABLE mArpDriverNameTable[] = {\r
+  { "eng", L"ARP Network Service Driver" },\r
+  { NULL, NULL }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+ArpComponentNameGetDriverName (\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
+           gArpComponentName.SupportedLanguages,\r
+           mArpDriverNameTable,\r
+           DriverName\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+ArpComponentNameGetControllerName (\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
+\r
diff --git a/MdeModulePkg/Universal/Network/Dhcp4Dxe/ComponentName.c b/MdeModulePkg/Universal/Network/Dhcp4Dxe/ComponentName.c
new file mode 100644 (file)
index 0000000..6808e77
--- /dev/null
@@ -0,0 +1,162 @@
+/** @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 "Dhcp4Impl.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+DhcpComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+DhcpComponentNameGetControllerName (\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     gDhcp4ComponentName = {\r
+  DhcpComponentNameGetDriverName,\r
+  DhcpComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mDhcpDriverNameTable[] = {\r
+  {\r
+    "eng",\r
+    L"DHCP Protocol Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+DhcpComponentNameGetDriverName (\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
+          gDhcp4ComponentName.SupportedLanguages,\r
+          mDhcpDriverNameTable,\r
+          DriverName\r
+          );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+DhcpComponentNameGetControllerName (\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\r
+                       specified by Language from the point of view of the\r
+                       driver specified 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 isn't NULL and isn't 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\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
diff --git a/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Driver.c b/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Driver.c
new file mode 100644 (file)
index 0000000..08d6076
--- /dev/null
@@ -0,0 +1,665 @@
+/** @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
+\r
+Module Name:\r
+\r
+  Dhcp4Driver.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Dhcp4Impl.h"\r
+#include "Dhcp4Driver.h"\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gDhcp4DriverBinding = {\r
+  Dhcp4DriverBindingSupported,\r
+  Dhcp4DriverBindingStart,\r
+  Dhcp4DriverBindingStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+EFI_SERVICE_BINDING_PROTOCOL mDhcp4ServiceBindingTemplete = {\r
+  Dhcp4ServiceBindingCreateChild,\r
+  Dhcp4ServiceBindingDestroyChild\r
+};\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (Dhcp4DriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Dhcp4DriverEntryPoint (\r
+  IN EFI_HANDLE             ImageHandle,\r
+  IN EFI_SYSTEM_TABLE       *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Entry point of the DHCP driver to install various protocols.\r
+\r
+Arguments:\r
+\r
+  ImageHandle - The driver's image handle\r
+  SystemTable - The system table\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - All the related protocols are installed.\r
+  Others      - Failed to install the protocols.\r
+\r
+--*/\r
+{\r
+  return NetLibInstallAllDriverProtocols (\r
+           ImageHandle,\r
+           SystemTable,\r
+           &gDhcp4DriverBinding,\r
+           ImageHandle,\r
+           &gDhcp4ComponentName,\r
+           NULL,\r
+           NULL\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Test to see if DHCP driver supports the 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 other                  This driver does not support this device\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Dhcp4DriverBindingSupported (\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
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiUdp4ServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Configure the default UDP child to receive all the DHCP traffics\r
+  on this network interface.\r
+\r
+  @param  UdpIo                  The UDP IO port to configure\r
+  @param  Context                The context to the function\r
+\r
+  @retval EFI_SUCCESS            The UDP IO port is successfully configured.\r
+  @retval Others                 Failed to configure the UDP child.\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpConfigUdpIo (\r
+  IN UDP_IO_PORT            *UdpIo,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  EFI_UDP4_CONFIG_DATA      UdpConfigData;\r
+\r
+  UdpConfigData.AcceptBroadcast           = TRUE;\r
+  UdpConfigData.AcceptPromiscuous         = FALSE;\r
+  UdpConfigData.AcceptAnyPort             = FALSE;\r
+  UdpConfigData.AllowDuplicatePort        = TRUE;\r
+  UdpConfigData.TypeOfService             = 0;\r
+  UdpConfigData.TimeToLive                = 64;\r
+  UdpConfigData.DoNotFragment             = FALSE;\r
+  UdpConfigData.ReceiveTimeout            = 0;\r
+  UdpConfigData.TransmitTimeout           = 0;\r
+\r
+  UdpConfigData.UseDefaultAddress         = FALSE;\r
+  UdpConfigData.StationPort               = DHCP_CLIENT_PORT;\r
+  UdpConfigData.RemotePort                = DHCP_SERVER_PORT;\r
+\r
+  NetZeroMem (&UdpConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));\r
+  NetZeroMem (&UdpConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+  NetZeroMem (&UdpConfigData.RemoteAddress, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  return UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Destory the DHCP service. The Dhcp4 service may be partly initialized,\r
+  or partly destoried. If a resource is destoried, it is marked as so in\r
+  case the destory failed and being called again later.\r
+\r
+  @param  DhcpSb                 The DHCP service instance to destory.\r
+\r
+  @retval EFI_SUCCESS            The DHCP service is successfully closed.\r
+\r
+**/\r
+EFI_STATUS\r
+Dhcp4CloseService (\r
+  IN DHCP_SERVICE           *DhcpSb\r
+  )\r
+{\r
+  DhcpCleanLease (DhcpSb);\r
+\r
+  if (DhcpSb->UdpIo != NULL) {\r
+    UdpIoFreePort (DhcpSb->UdpIo);\r
+    DhcpSb->UdpIo = NULL;\r
+  }\r
+\r
+  if (DhcpSb->Timer != NULL) {\r
+    gBS->SetTimer (DhcpSb->Timer, TimerCancel, 0);\r
+    gBS->CloseEvent (DhcpSb->Timer);\r
+\r
+    DhcpSb->Timer = NULL;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Create a new DHCP service binding instance for the controller.\r
+\r
+  @param  Controller             The controller to install DHCP service binding\r
+                                 protocol onto\r
+  @param  ImageHandle            The driver's image handle\r
+  @param  Service                The variable to receive the created DHCP service\r
+                                 instance.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource .\r
+  @retval EFI_SUCCESS            The DHCP service instance is created.\r
+\r
+**/\r
+EFI_STATUS\r
+Dhcp4CreateService (\r
+  IN  EFI_HANDLE            Controller,\r
+  IN  EFI_HANDLE            ImageHandle,\r
+  OUT DHCP_SERVICE          **Service\r
+  )\r
+{\r
+  DHCP_SERVICE              *DhcpSb;\r
+  EFI_STATUS                Status;\r
+\r
+  *Service  = NULL;\r
+  DhcpSb    = NetAllocateZeroPool (sizeof (DHCP_SERVICE));\r
+\r
+  if (DhcpSb == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  DhcpSb->Signature       = DHCP_SERVICE_SIGNATURE;\r
+  DhcpSb->ServiceBinding  = mDhcp4ServiceBindingTemplete;\r
+  DhcpSb->ServiceState    = DHCP_UNCONFIGED;\r
+  DhcpSb->InDestory       = FALSE;\r
+  DhcpSb->Controller      = Controller;\r
+  DhcpSb->Image           = ImageHandle;\r
+  NetListInit (&DhcpSb->Children);\r
+  DhcpSb->DhcpState       = Dhcp4Stopped;\r
+  DhcpSb->Xid             = NET_RANDOM (NetRandomInitSeed ());\r
+\r
+  //\r
+  // Create various resources, UdpIo, Timer, and get Mac address\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
+                  TPL_CALLBACK,\r
+                  DhcpOnTimerTick,\r
+                  DhcpSb,\r
+                  &DhcpSb->Timer\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  DhcpSb->UdpIo = UdpIoCreatePort (Controller, ImageHandle, DhcpConfigUdpIo, NULL);\r
+\r
+  if (DhcpSb->UdpIo == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  DhcpSb->HwLen  = (UINT8) DhcpSb->UdpIo->SnpMode.HwAddressSize;\r
+  DhcpSb->HwType = DhcpSb->UdpIo->SnpMode.IfType;\r
+  CopyMem (&DhcpSb->Mac, &DhcpSb->UdpIo->SnpMode.CurrentAddress, sizeof (EFI_MAC_ADDRESS));\r
+\r
+  *Service       = DhcpSb;\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  Dhcp4CloseService (DhcpSb);\r
+  NetFreePool (DhcpSb);\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
+Dhcp4DriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  )\r
+{\r
+  DHCP_SERVICE              *DhcpSb;\r
+  EFI_STATUS                Status;\r
+\r
+  //\r
+  // First: test for the DHCP4 Protocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDhcp4ServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+\r
+  if (Status == EFI_SUCCESS) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  Status = Dhcp4CreateService (ControllerHandle, This->DriverBindingHandle, &DhcpSb);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->SetTimer (DhcpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Install the Dhcp4ServiceBinding Protocol onto ControlerHandle\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &ControllerHandle,\r
+                  &gEfiDhcp4ServiceBindingProtocolGuid,\r
+                  &DhcpSb->ServiceBinding,\r
+                  NULL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  return Status;\r
+\r
+ON_ERROR:\r
+  Dhcp4CloseService (DhcpSb);\r
+  NetFreePool (DhcpSb);\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
+Dhcp4DriverBindingStop (\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_SERVICE_BINDING_PROTOCOL  *ServiceBinding;\r
+  DHCP_SERVICE                  *DhcpSb;\r
+  DHCP_PROTOCOL                 *Instance;\r
+  EFI_HANDLE                    NicHandle;\r
+  EFI_STATUS                    Status;\r
+  EFI_TPL                       OldTpl;\r
+\r
+  //\r
+  // DHCP driver opens UDP child, So, the ControllerHandle is the\r
+  // UDP child handle. locate the Nic handle first.\r
+  //\r
+  NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);\r
+\r
+  if (NicHandle == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+   Status = gBS->OpenProtocol (\r
+                  NicHandle,\r
+                  &gEfiDhcp4ServiceBindingProtocolGuid,\r
+                  (VOID **) &ServiceBinding,\r
+                  This->DriverBindingHandle,\r
+                  NicHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  DhcpSb = DHCP_SERVICE_FROM_THIS (ServiceBinding);\r
+\r
+  if (DhcpSb->InDestory) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  OldTpl            = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  DhcpSb->InDestory = TRUE;\r
+\r
+  //\r
+  // Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild\r
+  // may cause other child to be deleted.\r
+  //\r
+  while (!NetListIsEmpty (&DhcpSb->Children)) {\r
+    Instance = NET_LIST_HEAD (&DhcpSb->Children, DHCP_PROTOCOL, Link);\r
+    Dhcp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);\r
+  }\r
+\r
+  if (DhcpSb->NumChildren != 0) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  DhcpSb->ServiceState  = DHCP_DESTORY;\r
+\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  NicHandle,\r
+                  &gEfiDhcp4ServiceBindingProtocolGuid,\r
+                  ServiceBinding\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Dhcp4CloseService (DhcpSb);\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  NetFreePool (DhcpSb);\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  DhcpSb->InDestory = FALSE;\r
+  NET_RESTORE_TPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Initialize a new DHCP child\r
+\r
+  @param  DhcpSb                 The dhcp service instance\r
+  @param  Instance               The dhcp instance to initialize\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+DhcpInitProtocol (\r
+  IN DHCP_SERVICE           *DhcpSb,\r
+  IN DHCP_PROTOCOL          *Instance\r
+  )\r
+{\r
+  Instance->Signature         = DHCP_PROTOCOL_SIGNATURE;\r
+  CopyMem (&Instance->Dhcp4Protocol, &mDhcp4ProtocolTemplate, sizeof (EFI_DHCP4_PROTOCOL));\r
+  NetListInit (&Instance->Link);\r
+  Instance->Handle            = NULL;\r
+  Instance->Service           = DhcpSb;\r
+  Instance->InDestory         = FALSE;\r
+  Instance->CompletionEvent   = NULL;\r
+  Instance->RenewRebindEvent  = NULL;\r
+  Instance->Token             = NULL;\r
+}\r
+\r
+\r
+/**\r
+  Creates a child handle with a set of DHCP4 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 DHCP4 services are added to\r
+                                 the existing  child handle.\r
+\r
+  @retval EFI_SUCCES             The child handle was created with the DHCP4\r
+                                 services\r
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources to create the child\r
+  @retval other                  The child handle was not created\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Dhcp4ServiceBindingCreateChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    *ChildHandle\r
+  )\r
+{\r
+  DHCP_SERVICE              *DhcpSb;\r
+  DHCP_PROTOCOL             *Instance;\r
+  EFI_STATUS                Status;\r
+  EFI_TPL                   OldTpl;\r
+  VOID                      *Udp4;\r
+\r
+  if ((This == NULL) || (ChildHandle == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = NetAllocatePool (sizeof (*Instance));\r
+\r
+  if (Instance == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  DhcpSb = DHCP_SERVICE_FROM_THIS (This);\r
+  DhcpInitProtocol (DhcpSb, Instance);\r
+\r
+  //\r
+  // Install DHCP4 onto ChildHandle\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  ChildHandle,\r
+                  &gEfiDhcp4ProtocolGuid,\r
+                  &Instance->Dhcp4Protocol,\r
+                  NULL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    NetFreePool (Instance);\r
+    return Status;\r
+  }\r
+\r
+  Instance->Handle  = *ChildHandle;\r
+\r
+  //\r
+  // Open the Udp4 protocol BY_CHILD.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  DhcpSb->UdpIo->UdpHandle,\r
+                  &gEfiUdp4ProtocolGuid,\r
+                  (VOID **) &Udp4,\r
+                  gDhcp4DriverBinding.DriverBindingHandle,\r
+                  Instance->Handle,\r
+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+           Instance->Handle,\r
+           &gEfiDhcp4ProtocolGuid,\r
+           &Instance->Dhcp4Protocol,\r
+           NULL\r
+           );\r
+\r
+    NetFreePool (Instance);\r
+    return Status;\r
+  }\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  NetListInsertTail (&DhcpSb->Children, &Instance->Link);\r
+  DhcpSb->NumChildren++;\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Destroys a child handle with a set of DHCP4 services.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  ChildHandle            Handle of the child to destroy\r
+\r
+  @retval EFI_SUCCES             The DHCP4 service is removed from the child handle\r
+  @retval EFI_UNSUPPORTED        The child handle does not support the DHCP4\r
+                                 service\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  DHCP4 services are being used.\r
+  @retval other                  The child handle was not destroyed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Dhcp4ServiceBindingDestroyChild (\r
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                    ChildHandle\r
+  )\r
+{\r
+  DHCP_SERVICE              *DhcpSb;\r
+  DHCP_PROTOCOL             *Instance;\r
+  EFI_DHCP4_PROTOCOL        *Dhcp;\r
+  EFI_TPL                   OldTpl;\r
+  EFI_STATUS                Status;\r
+\r
+  if ((This == NULL) || (ChildHandle == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Retrieve the private context data structures\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ChildHandle,\r
+                  &gEfiDhcp4ProtocolGuid,\r
+                  (VOID **) &Dhcp,\r
+                  gDhcp4DriverBinding.DriverBindingHandle,\r
+                  ChildHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Instance  = DHCP_INSTANCE_FROM_THIS (Dhcp);\r
+  DhcpSb    = DHCP_SERVICE_FROM_THIS (This);\r
+\r
+  if (Instance->Service != DhcpSb) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // A child can be destoried more than once. For example,\r
+  // Dhcp4DriverBindingStop will destory all of its children.\r
+  // when caller driver is being stopped, it will destory the\r
+  // dhcp child it opens.\r
+  //\r
+  if (Instance->InDestory) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  Instance->InDestory = TRUE;\r
+\r
+  //\r
+  // Close the Udp4 protocol.\r
+  //\r
+  gBS->CloseProtocol (\r
+         DhcpSb->UdpIo->UdpHandle,\r
+         &gEfiUdp4ProtocolGuid,\r
+         gDhcp4DriverBinding.DriverBindingHandle,\r
+         ChildHandle\r
+         );\r
+\r
+  //\r
+  // Uninstall the DHCP4 protocol first to enable a top down destruction.\r
+  //\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  ChildHandle,\r
+                  &gEfiDhcp4ProtocolGuid,\r
+                  Dhcp\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Instance->InDestory = FALSE;\r
+\r
+    NET_RESTORE_TPL (OldTpl);\r
+    return Status;\r
+  }\r
+\r
+  if (DhcpSb->ActiveChild == Instance) {\r
+    DhcpYieldControl (DhcpSb);\r
+  }\r
+\r
+  NetListRemoveEntry (&Instance->Link);\r
+  DhcpSb->NumChildren--;\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  NetFreePool (Instance);\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Driver.h b/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Driver.h
new file mode 100644 (file)
index 0000000..100bf56
--- /dev/null
@@ -0,0 +1,67 @@
+/** @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:
+
+  Dhcp4Driver.h
+
+Abstract:
+
+  Header for the DHCP4 driver
+
+
+**/
+
+#ifndef __EFI_DHCP4_DRIVER_H__
+#define __EFI_DHCP4_DRIVER_H__
+
+extern EFI_COMPONENT_NAME_PROTOCOL gDhcp4ComponentName;
+
+EFI_STATUS
+EFIAPI
+Dhcp4DriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+Dhcp4DriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+Dhcp4DriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   ControllerHandle,
+  IN  UINTN                        NumberOfChildren,
+  IN  EFI_HANDLE                   *ChildHandleBuffer
+  );
+
+EFI_STATUS
+EFIAPI
+Dhcp4ServiceBindingCreateChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    *ChildHandle
+  );
+
+EFI_STATUS
+EFIAPI
+Dhcp4ServiceBindingDestroyChild (
+  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                    ChildHandle
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf b/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
new file mode 100644 (file)
index 0000000..2c35be1
--- /dev/null
@@ -0,0 +1,65 @@
+#/** @file\r
+# Component name for module Dhcp4\r
+#\r
+# Copyright (c) 2007, Intel Corporation\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                      = Dhcp4Dxe\r
+  FILE_GUID                      = 94734718-0BBC-47fb-96A5-EE7A5AE6A2AD\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = Dhcp4DriverEntryPoint\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
+  Dhcp4Impl.c\r
+  Dhcp4Io.c\r
+  Dhcp4Io.h\r
+  ComponentName.c\r
+  Dhcp4Driver.h\r
+  Dhcp4Driver.c\r
+  Dhcp4Option.c\r
+  Dhcp4Option.h\r
+  Dhcp4Impl.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+  NetLib\r
+  UdpIoLib\r
+\r
+\r
+[Protocols]\r
+  gEfiUdp4ServiceBindingProtocolGuid            # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiDhcp4ServiceBindingProtocolGuid           # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUdp4ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiDhcp4ProtocolGuid                         # PROTOCOL ALWAYS_CONSUMED\r
+\r
diff --git a/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.msa b/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.msa
new file mode 100644 (file)
index 0000000..6bde71a
--- /dev/null
@@ -0,0 +1,77 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+  <MsaHeader>\r
+    <ModuleName>Dhcp4Dxe</ModuleName>\r
+    <ModuleType>DXE_DRIVER</ModuleType>\r
+    <GuidValue>94734718-0BBC-47fb-96A5-EE7A5AE6A2AD</GuidValue>\r
+    <Version>1.0</Version>\r
+    <Abstract>Component name for module Dhcp4</Abstract>\r
+    <Description>FIX ME!</Description>\r
+    <Copyright>Copyright (c) 2007, Intel Corporation. All rights 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>Dhcp4Dxe</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
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseLib</Keyword>\r
+    </LibraryClass>\r
+  </LibraryClassDefinitions>\r
+  <SourceFiles>\r
+    <Filename>Dhcp4Impl.h</Filename>\r
+    <Filename>Dhcp4Option.h</Filename>\r
+    <Filename>Dhcp4Option.c</Filename>\r
+    <Filename>Dhcp4Driver.c</Filename>\r
+    <Filename>Dhcp4Driver.h</Filename>\r
+    <Filename>ComponentName.c</Filename>\r
+    <Filename>Dhcp4Io.h</Filename>\r
+    <Filename>Dhcp4Io.c</Filename>\r
+    <Filename>Dhcp4Impl.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>gEfiDhcp4ProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUdp4ProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiDhcp4ServiceBindingProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUdp4ServiceBindingProtocolGuid</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>Dhcp4DriverEntryPoint</ModuleEntryPoint>\r
+    </Extern>\r
+  </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
diff --git a/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Impl.c b/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Impl.c
new file mode 100644 (file)
index 0000000..68da959
--- /dev/null
@@ -0,0 +1,914 @@
+/** @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
+  Dhcp4Impl.c\r
+\r
+Abstract:\r
+\r
+  This file implement the EFI_DHCP4_PROTOCOL interface.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Dhcp4Impl.h"\r
+\r
+\r
+/**\r
+  Get the current operation parameter and lease for the network interface.\r
+\r
+  @param  This                   The DHCP protocol instance\r
+  @param  Dhcp4ModeData          The variable to save the DHCP mode data.\r
+\r
+  @retval EFI_INVALID_PARAMETER  The parameter is invalid\r
+  @retval EFI_SUCCESS            The Dhcp4ModeData is updated with the current\r
+                                 operation parameter.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDhcp4GetModeData (\r
+  IN  EFI_DHCP4_PROTOCOL    *This,\r
+  OUT EFI_DHCP4_MODE_DATA   *Dhcp4ModeData\r
+  )\r
+{\r
+  DHCP_PROTOCOL             *Instance;\r
+  DHCP_SERVICE              *DhcpSb;\r
+  DHCP_PARAMETER            *Para;\r
+  EFI_TPL                   OldTpl;\r
+  IP4_ADDR                  Ip;\r
+\r
+  //\r
+  // First validate the parameters.\r
+  //\r
+  if ((This == NULL) || (Dhcp4ModeData == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = DHCP_INSTANCE_FROM_THIS (This);\r
+\r
+  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  DhcpSb  = Instance->Service;\r
+\r
+  //\r
+  // Caller can use GetModeData to retrieve current DHCP states\r
+  // no matter whether it is the active child or not.\r
+  //\r
+  Dhcp4ModeData->State                     = DhcpSb->DhcpState;\r
+  CopyMem (&Dhcp4ModeData->ConfigData, &DhcpSb->ActiveConfig, sizeof (EFI_DHCP4_CONFIG_DATA));\r
+  CopyMem (&Dhcp4ModeData->ClientMacAddress, &DhcpSb->Mac, sizeof (EFI_MAC_ADDRESS));\r
+\r
+  Ip = HTONL (DhcpSb->ClientAddr);\r
+  NetCopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  Ip = HTONL (DhcpSb->Netmask);\r
+  NetCopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  Ip = HTONL (DhcpSb->ServerAddr);\r
+  NetCopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  Para = DhcpSb->Para;\r
+\r
+  if (Para != NULL) {\r
+    Ip = HTONL (Para->Router);\r
+    NetCopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+    Dhcp4ModeData->LeaseTime               = Para->Lease;\r
+  } else {\r
+    NetZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
+    Dhcp4ModeData->LeaseTime               = 0xffffffff;\r
+  }\r
+\r
+  Dhcp4ModeData->ReplyPacket = DhcpSb->Selected;\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Free the resource related to the configure parameters.\r
+  DHCP driver will make a copy of the user's configure\r
+  such as the time out value.\r
+\r
+  @param  Config                 The DHCP configure data\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+DhcpCleanConfigure (\r
+  IN EFI_DHCP4_CONFIG_DATA  *Config\r
+  )\r
+{\r
+  UINT32                    Index;\r
+\r
+  if (Config->DiscoverTimeout != NULL) {\r
+    NetFreePool (Config->DiscoverTimeout);\r
+  }\r
+\r
+  if (Config->RequestTimeout != NULL) {\r
+    NetFreePool (Config->RequestTimeout);\r
+  }\r
+\r
+  if (Config->OptionList != NULL) {\r
+    for (Index = 0; Index < Config->OptionCount; Index++) {\r
+      if (Config->OptionList[Index] != NULL) {\r
+        NetFreePool (Config->OptionList[Index]);\r
+      }\r
+    }\r
+\r
+    NetFreePool (Config->OptionList);\r
+  }\r
+\r
+  NetZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
+}\r
+\r
+\r
+/**\r
+  Allocate memory for configure parameter such as timeout value for Dst,\r
+  then copy the configure parameter from Src to Dst.\r
+\r
+  @param  Dst                    The destination DHCP configure data.\r
+  @param  Src                    The source DHCP configure data.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.\r
+  @retval EFI_SUCCESS            The configure is copied.\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpCopyConfigure (\r
+  IN EFI_DHCP4_CONFIG_DATA  *Dst,\r
+  IN EFI_DHCP4_CONFIG_DATA  *Src\r
+  )\r
+{\r
+  EFI_DHCP4_PACKET_OPTION   **DstOptions;\r
+  EFI_DHCP4_PACKET_OPTION   **SrcOptions;\r
+  INTN                      Len;\r
+  UINT32                    Index;\r
+\r
+  CopyMem (Dst, Src, sizeof (EFI_DHCP4_CONFIG_DATA));\r
+  Dst->DiscoverTimeout  = NULL;\r
+  Dst->RequestTimeout   = NULL;\r
+  Dst->OptionList       = NULL;\r
+\r
+  //\r
+  // Allocate a memory then copy DiscoverTimeout to it\r
+  //\r
+  if (Src->DiscoverTimeout != NULL) {\r
+    Len                   = Src->DiscoverTryCount * sizeof (UINT32);\r
+    Dst->DiscoverTimeout  = NetAllocatePool (Len);\r
+\r
+    if (Dst->DiscoverTimeout == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    for (Index = 0; Index < Src->DiscoverTryCount; Index++) {\r
+      Dst->DiscoverTimeout[Index] = NET_MAX (Src->DiscoverTimeout[Index], 1);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Allocate a memory then copy RequestTimeout to it\r
+  //\r
+  if (Src->RequestTimeout != NULL) {\r
+    Len                 = Src->RequestTryCount * sizeof (UINT32);\r
+    Dst->RequestTimeout = NetAllocatePool (Len);\r
+\r
+    if (Dst->RequestTimeout == NULL) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    for (Index = 0; Index < Src->RequestTryCount; Index++) {\r
+      Dst->RequestTimeout[Index] = NET_MAX (Src->RequestTimeout[Index], 1);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Allocate an array of dhcp option point, then allocate memory\r
+  // for each option and copy the source option to it\r
+  //\r
+  if (Src->OptionList != NULL) {\r
+    Len             = Src->OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *);\r
+    Dst->OptionList = NetAllocateZeroPool (Len);\r
+\r
+    if (Dst->OptionList == NULL) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    DstOptions  = Dst->OptionList;\r
+    SrcOptions  = Src->OptionList;\r
+\r
+    for (Index = 0; Index < Src->OptionCount; Index++) {\r
+      Len = sizeof (EFI_DHCP4_PACKET_OPTION) + NET_MAX (SrcOptions[Index]->Length - 1, 0);\r
+\r
+      DstOptions[Index] = NetAllocatePool (Len);\r
+\r
+      if (DstOptions[Index] == NULL) {\r
+        goto ON_ERROR;\r
+      }\r
+\r
+      NetCopyMem (DstOptions[Index], SrcOptions[Index], Len);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  DhcpCleanConfigure (Dst);\r
+  return EFI_OUT_OF_RESOURCES;\r
+}\r
+\r
+\r
+/**\r
+  Give up the control of the DHCP service to let other child\r
+  resume. Don't change the service's DHCP state and the Client\r
+  address and option list configure as required by RFC2131.\r
+\r
+  @param  DhcpSb                 The DHCP service instance.\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+DhcpYieldControl (\r
+  IN DHCP_SERVICE           *DhcpSb\r
+  )\r
+{\r
+  EFI_DHCP4_CONFIG_DATA     *Config;\r
+  DHCP_PROTOCOL             *Instance;\r
+\r
+  Instance  = DhcpSb->ActiveChild;\r
+  Config    = &DhcpSb->ActiveConfig;\r
+\r
+  DhcpSb->ServiceState  = DHCP_UNCONFIGED;\r
+  DhcpSb->ActiveChild   = NULL;\r
+\r
+  if (Config->DiscoverTimeout != NULL) {\r
+    NetFreePool (Config->DiscoverTimeout);\r
+\r
+    Config->DiscoverTryCount  = 0;\r
+    Config->DiscoverTimeout   = NULL;\r
+  }\r
+\r
+  if (Config->RequestTimeout != NULL) {\r
+    NetFreePool (Config->RequestTimeout);\r
+\r
+    Config->RequestTryCount = 0;\r
+    Config->RequestTimeout  = NULL;\r
+  }\r
+\r
+  Config->Dhcp4Callback   = NULL;\r
+  Config->CallbackContext = NULL;\r
+}\r
+\r
+\r
+/**\r
+  Configure the DHCP protocol instance and its underlying DHCP service\r
+  for operation. If Dhcp4CfgData is NULL and the child is currently\r
+  controlling the DHCP service, release the control.\r
+\r
+  @param  This                   The DHCP protocol instance\r
+  @param  Dhcp4CfgData           The DHCP configure data.\r
+\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+  @retval EFI_ACCESS_DENIED      The service isn't in one of configurable states,\r
+                                 or there is already an active child.\r
+  @retval EFI_OUT_OF_RESOURCE    Failed to allocate some resources.\r
+  @retval EFI_SUCCESS            The child is configured.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDhcp4Configure (\r
+  IN EFI_DHCP4_PROTOCOL     *This,\r
+  IN EFI_DHCP4_CONFIG_DATA  *Dhcp4CfgData       OPTIONAL\r
+  )\r
+{\r
+  EFI_DHCP4_CONFIG_DATA     *Config;\r
+  DHCP_PROTOCOL             *Instance;\r
+  DHCP_SERVICE              *DhcpSb;\r
+  EFI_STATUS                Status;\r
+  EFI_TPL                   OldTpl;\r
+  UINT32                    Index;\r
+  IP4_ADDR                  Ip;\r
+\r
+  //\r
+  // First validate the parameters\r
+  //\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Dhcp4CfgData != NULL) {\r
+    if (Dhcp4CfgData->DiscoverTryCount && (Dhcp4CfgData->DiscoverTimeout == NULL)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (Dhcp4CfgData->RequestTryCount && (Dhcp4CfgData->RequestTimeout == NULL)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (Dhcp4CfgData->OptionCount && (Dhcp4CfgData->OptionList == NULL)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    NetCopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR));\r
+\r
+    if ((Ip != 0) && !Ip4IsUnicast (NTOHL (Ip), 0)) {\r
+\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  Instance = DHCP_INSTANCE_FROM_THIS (This);\r
+\r
+  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+  DhcpSb  = Instance->Service;\r
+  Config  = &DhcpSb->ActiveConfig;\r
+\r
+  Status  = EFI_ACCESS_DENIED;\r
+\r
+  if ((DhcpSb->DhcpState != Dhcp4Stopped) &&\r
+      (DhcpSb->DhcpState != Dhcp4Init) &&\r
+      (DhcpSb->DhcpState != Dhcp4InitReboot) &&\r
+      (DhcpSb->DhcpState != Dhcp4Bound)) {\r
+\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if ((DhcpSb->ActiveChild != NULL) && (DhcpSb->ActiveChild != Instance)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (Dhcp4CfgData != NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    DhcpCleanConfigure (Config);\r
+\r
+    if (EFI_ERROR (DhcpCopyConfigure (Config, Dhcp4CfgData))) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    DhcpSb->UserOptionLen = 0;\r
+\r
+    for (Index = 0; Index < Dhcp4CfgData->OptionCount; Index++) {\r
+      DhcpSb->UserOptionLen += Dhcp4CfgData->OptionList[Index]->Length + 2;\r
+    }\r
+\r
+    DhcpSb->ActiveChild = Instance;\r
+\r
+    if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
+      DhcpSb->ClientAddr = EFI_NTOHL (Dhcp4CfgData->ClientAddress);\r
+\r
+      if (DhcpSb->ClientAddr != 0) {\r
+        DhcpSb->DhcpState = Dhcp4InitReboot;\r
+      } else {\r
+        DhcpSb->DhcpState = Dhcp4Init;\r
+      }\r
+    }\r
+\r
+    DhcpSb->ServiceState  = DHCP_CONFIGED;\r
+    Status                = EFI_SUCCESS;\r
+\r
+  } else if (DhcpSb->ActiveChild == Instance) {\r
+    Status = EFI_SUCCESS;\r
+    DhcpYieldControl (DhcpSb);\r
+  }\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Start the DHCP process.\r
+\r
+  @param  This                   The DHCP protocol instance\r
+  @param  CompletionEvent        The event to signal is address is acquired.\r
+\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+  @retval EFI_NOT_STARTED        The protocol hasn't been configured.\r
+  @retval EFI_ALREADY_STARTED    The DHCP process has already been started.\r
+  @retval EFI_SUCCESS            The DHCP process is started.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDhcp4Start (\r
+  IN EFI_DHCP4_PROTOCOL     *This,\r
+  IN EFI_EVENT              CompletionEvent   OPTIONAL\r
+  )\r
+{\r
+  DHCP_PROTOCOL             *Instance;\r
+  DHCP_SERVICE              *DhcpSb;\r
+  EFI_STATUS                Status;\r
+  EFI_TPL                   OldTpl;\r
+\r
+  //\r
+  // First validate the parameters\r
+  //\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = DHCP_INSTANCE_FROM_THIS (This);\r
+\r
+  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  DhcpSb  = Instance->Service;\r
+\r
+  if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  if ((DhcpSb->DhcpState != Dhcp4Init) && (DhcpSb->DhcpState != Dhcp4InitReboot)) {\r
+    Status = EFI_ALREADY_STARTED;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  DhcpSb->IoStatus = EFI_ALREADY_STARTED;\r
+\r
+  if (EFI_ERROR (Status = DhcpInitRequest (DhcpSb))) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Start/Restart the receiving.\r
+  //\r
+  Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);\r
+\r
+  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Instance->CompletionEvent = CompletionEvent;\r
+\r
+  //\r
+  // Restore the TPL now, don't call poll function at NET_TPL_LOCK.\r
+  //\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  if (CompletionEvent == NULL) {\r
+    while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {\r
+      DhcpSb->UdpIo->Udp->Poll (DhcpSb->UdpIo->Udp);\r
+    }\r
+\r
+    return DhcpSb->IoStatus;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  NET_RESTORE_TPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Request an extra manual renew/rebind.\r
+\r
+  @param  This                   The DHCP protocol instance\r
+  @param  RebindRequest          TRUE if request a rebind, otherwise renew it\r
+  @param  CompletionEvent        Event to signal when complete\r
+\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid\r
+  @retval EFI_NOT_STARTED        The DHCP protocol hasn't been started.\r
+  @retval EFI_ACCESS_DENIED      The DHCP protocol isn't in Bound state.\r
+  @retval EFI_SUCCESS            The DHCP is renewed/rebound.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDhcp4RenewRebind (\r
+  IN EFI_DHCP4_PROTOCOL     *This,\r
+  IN BOOLEAN                RebindRequest,\r
+  IN EFI_EVENT              CompletionEvent   OPTIONAL\r
+  )\r
+{\r
+  DHCP_PROTOCOL             *Instance;\r
+  DHCP_SERVICE              *DhcpSb;\r
+  EFI_STATUS                Status;\r
+  EFI_TPL                   OldTpl;\r
+\r
+  //\r
+  // First validate the parameters\r
+  //\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = DHCP_INSTANCE_FROM_THIS (This);\r
+\r
+  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  DhcpSb  = Instance->Service;\r
+\r
+  if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
+    Status = EFI_NOT_STARTED;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  if (DhcpSb->DhcpState != Dhcp4Bound) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  if (DHCP_IS_BOOTP (DhcpSb->Para)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Transit the states then send a extra DHCP request\r
+  //\r
+  if (!RebindRequest) {\r
+    DhcpSetState (DhcpSb, Dhcp4Renewing, FALSE);\r
+  } else {\r
+    DhcpSetState (DhcpSb, Dhcp4Rebinding, FALSE);\r
+  }\r
+\r
+  Status = DhcpSendMessage (\r
+             DhcpSb,\r
+             DhcpSb->Selected,\r
+             DhcpSb->Para,\r
+             DHCP_MSG_REQUEST,\r
+             "Extra renew/rebind by the application"\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DhcpSetState (DhcpSb, Dhcp4Bound, FALSE);\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  DhcpSb->ExtraRefresh        = TRUE;\r
+  DhcpSb->IoStatus            = EFI_ALREADY_STARTED;\r
+  Instance->RenewRebindEvent  = CompletionEvent;\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+\r
+  if (CompletionEvent == NULL) {\r
+    while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {\r
+      DhcpSb->UdpIo->Udp->Poll (DhcpSb->UdpIo->Udp);\r
+    }\r
+\r
+    return DhcpSb->IoStatus;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  NET_RESTORE_TPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Release the current acquired lease.\r
+\r
+  @param  This                   The DHCP protocol instance\r
+\r
+  @retval EFI_INVALID_PARAMETER  The parameter is invalid\r
+  @retval EFI_DEVICE_ERROR       Failed to transmit the DHCP release packet\r
+  @retval EFI_ACCESS_DENIED      The DHCP service isn't in one of the connected\r
+                                 state.\r
+  @retval EFI_SUCCESS            The lease is released.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDhcp4Release (\r
+  IN EFI_DHCP4_PROTOCOL     *This\r
+  )\r
+{\r
+  DHCP_PROTOCOL             *Instance;\r
+  DHCP_SERVICE              *DhcpSb;\r
+  EFI_STATUS                Status;\r
+  EFI_TPL                   OldTpl;\r
+\r
+  //\r
+  // First validate the parameters\r
+  //\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = DHCP_INSTANCE_FROM_THIS (This);\r
+\r
+  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status  = EFI_SUCCESS;\r
+  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  DhcpSb  = Instance->Service;\r
+\r
+  if ((DhcpSb->DhcpState != Dhcp4InitReboot) && (DhcpSb->DhcpState != Dhcp4Bound)) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (!DHCP_IS_BOOTP (DhcpSb->Para) && (DhcpSb->DhcpState == Dhcp4Bound)) {\r
+    Status = DhcpSendMessage (\r
+               DhcpSb,\r
+               DhcpSb->Selected,\r
+               DhcpSb->Para,\r
+               DHCP_MSG_RELEASE,\r
+               NULL\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  DhcpCleanLease (DhcpSb);\r
+\r
+ON_EXIT:\r
+  NET_RESTORE_TPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop the current DHCP process. After this, other DHCP child\r
+  can gain control of the service, configure and use it.\r
+\r
+  @param  This                   The DHCP protocol instance\r
+\r
+  @retval EFI_INVALID_PARAMETER  The parameter is invalid.\r
+  @retval EFI_SUCCESS            The DHCP process is stopped.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDhcp4Stop (\r
+  IN EFI_DHCP4_PROTOCOL     *This\r
+  )\r
+{\r
+  DHCP_PROTOCOL             *Instance;\r
+  DHCP_SERVICE              *DhcpSb;\r
+  EFI_TPL                   OldTpl;\r
+\r
+  //\r
+  // First validate the parameters\r
+  //\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Instance = DHCP_INSTANCE_FROM_THIS (This);\r
+\r
+  if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
+  DhcpSb  = Instance->Service;\r
+\r
+  DhcpCleanLease (DhcpSb);\r
+\r
+  DhcpSb->DhcpState     = Dhcp4Stopped;\r
+  DhcpSb->ServiceState  = DHCP_UNCONFIGED;\r
+\r
+  NET_RESTORE_TPL (OldTpl);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Build a new DHCP packet from the seed packet. Options may be deleted or\r
+  appended. The caller should free the NewPacket when finished using it.\r
+\r
+  @param  This                   The DHCP protocol instance.\r
+  @param  SeedPacket             The seed packet to start with\r
+  @param  DeleteCount            The number of options to delete\r
+  @param  DeleteList             The options to delete from the packet\r
+  @param  AppendCount            The number of options to append\r
+  @param  AppendList             The options to append to the packet\r
+  @param  NewPacket              The new packet, allocated and built by this\r
+                                 function.\r
+\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory\r
+  @retval EFI_SUCCESS            The packet is build.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDhcp4Build (\r
+  IN EFI_DHCP4_PROTOCOL       *This,\r
+  IN EFI_DHCP4_PACKET         *SeedPacket,\r
+  IN UINT32                   DeleteCount,\r
+  IN UINT8                    *DeleteList OPTIONAL,\r
+  IN UINT32                   AppendCount,\r
+  IN EFI_DHCP4_PACKET_OPTION  *AppendList[] OPTIONAL,\r
+  OUT EFI_DHCP4_PACKET        **NewPacket\r
+  )\r
+{\r
+  //\r
+  // First validate the parameters\r
+  //\r
+  if ((This == NULL) || (NewPacket == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((SeedPacket == NULL) || (SeedPacket->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
+      EFI_ERROR (DhcpValidateOptions (SeedPacket, NULL))) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (((DeleteCount == 0) && (AppendCount == 0)) ||\r
+      ((DeleteCount != 0) && (DeleteList == NULL)) ||\r
+      ((AppendCount != 0) && (AppendList == NULL))) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return DhcpBuild (\r
+           SeedPacket,\r
+           DeleteCount,\r
+           DeleteList,\r
+           AppendCount,\r
+           AppendList,\r
+           NewPacket\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Transmit and receive a packet through this DHCP service.\r
+  This is unsupported.\r
+\r
+  @param  This                   The DHCP protocol instance\r
+  @param  Token                  The transmit and receive instance\r
+\r
+  @retval EFI_UNSUPPORTED        It always returns unsupported.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDhcp4TransmitReceive (\r
+  IN EFI_DHCP4_PROTOCOL                *This,\r
+  IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token\r
+  )\r
+{\r
+  //\r
+  // This function is for PXE, leave it for now\r
+  //\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Callback function for DhcpIterateOptions. This callback sets the\r
+  EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point\r
+  the individual DHCP option in the packet.\r
+\r
+  @param  Tag                    The DHCP option type\r
+  @param  Len                    length of the DHCP option data\r
+  @param  Data                   The DHCP option data\r
+  @param  Context                The context, to pass several parameters in.\r
+\r
+  @retval EFI_SUCCESS            It always returns EFI_SUCCESS\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Dhcp4ParseCheckOption (\r
+  IN UINT8                  Tag,\r
+  IN UINT8                  Len,\r
+  IN UINT8                  *Data,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  DHCP_PARSE_CONTEXT        *Parse;\r
+\r
+  Parse = (DHCP_PARSE_CONTEXT *) Context;\r
+  Parse->Index++;\r
+\r
+  if (Parse->Index < Parse->OptionCount) {\r
+    //\r
+    // Use _CR to get the memory position of EFI_DHCP4_PACKET_OPTION for\r
+    // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only\r
+    // pass in the point to option data.\r
+    //\r
+    Parse->Option[Parse->Index - 1] = _CR (Data, EFI_DHCP4_PACKET_OPTION, Data);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Parse the DHCP options in the Packet into the PacketOptionList.\r
+  User should allocate this array of EFI_DHCP4_PACKET_OPTION points.\r
+\r
+  @param  This                   The DHCP protocol instance\r
+  @param  Packet                 The DHCP packet to parse\r
+  @param  OptionCount            On input, the size of the PacketOptionList; On\r
+                                 output,  the actual number of options processed.\r
+  @param  PacketOptionList       The array of EFI_DHCP4_PACKET_OPTION points\r
+\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+  @retval EFI_BUFFER_TOO_SMALL   A bigger array of points is needed.\r
+  @retval EFI_SUCCESS            The options are parsed.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiDhcp4Parse (\r
+  IN EFI_DHCP4_PROTOCOL       *This,\r
+  IN EFI_DHCP4_PACKET         *Packet,\r
+  IN OUT UINT32               *OptionCount,\r
+  OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL\r
+  )\r
+{\r
+  DHCP_PARSE_CONTEXT        Context;\r
+  EFI_STATUS                Status;\r
+\r
+  //\r
+  // First validate the parameters\r
+  //\r
+  if ((This == NULL) || (Packet == NULL) || (OptionCount == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->Size < Packet->Length + 2 * sizeof (UINT32)) ||\r
+      (Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
+      EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*OptionCount != 0) && (PacketOptionList == NULL)) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  NetZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
+\r
+  Context.Option      = PacketOptionList;\r
+  Context.OptionCount = *OptionCount;\r
+  Context.Index       = 0;\r
+\r
+  Status              = DhcpIterateOptions (Packet, Dhcp4ParseCheckOption, &Context);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  *OptionCount = Context.Index;\r
+\r
+  if (Context.Index > Context.OptionCount) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_DHCP4_PROTOCOL  mDhcp4ProtocolTemplate = {\r
+  EfiDhcp4GetModeData,\r
+  EfiDhcp4Configure,\r
+  EfiDhcp4Start,\r
+  EfiDhcp4RenewRebind,\r
+  EfiDhcp4Release,\r
+  EfiDhcp4Stop,\r
+  EfiDhcp4Build,\r
+  EfiDhcp4TransmitReceive,\r
+  EfiDhcp4Parse\r
+};\r
diff --git a/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Impl.h b/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Impl.h
new file mode 100644 (file)
index 0000000..7f44941
--- /dev/null
@@ -0,0 +1,159 @@
+/** @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:
+
+  Dhcp4Impl.h
+
+Abstract:
+
+  EFI DHCP protocol implementation
+  RFCs supported are:
+  RFC 2131: Dynamic Host Configuration Protocol
+  RFC 2132: DHCP Options and BOOTP Vendor Extensions
+  RFC 1534: Interoperation Between DHCP and BOOTP
+  RFC 3396: Encoding Long Options in DHCP
+
+
+**/
+
+#ifndef __EFI_DHCP4_IMPL_H__
+#define __EFI_DHCP4_IMPL_H__
+
+
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/Dhcp4.h>\r
+#include <Protocol/Udp4.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>
+#include <Library/NetLib.h>
+
+typedef struct _DHCP_SERVICE  DHCP_SERVICE;
+typedef struct _DHCP_PROTOCOL DHCP_PROTOCOL;
+
+#include "Dhcp4Option.h"
+#include "Dhcp4Io.h"
+
+enum {
+  DHCP_SERVICE_SIGNATURE  = EFI_SIGNATURE_32 ('D', 'H', 'C', 'P'),
+  DHCP_PROTOCOL_SIGNATURE = EFI_SIGNATURE_32 ('d', 'h', 'c', 'p'),
+
+  //
+  // The state of the DHCP service. It starts as UNCONFIGED. If
+  // and active child configures the service successfully, it
+  // goes to CONFIGED. If the active child configures NULL, it
+  // goes back to UNCONFIGED. It becomes DESTORY if it is (partly)
+  // destoried.
+  //
+  DHCP_UNCONFIGED         = 0,
+  DHCP_CONFIGED,
+  DHCP_DESTORY,
+};
+
+typedef struct _DHCP_PROTOCOL {
+  UINT32                            Signature;
+  EFI_DHCP4_PROTOCOL                Dhcp4Protocol;
+  NET_LIST_ENTRY                    Link;
+  EFI_HANDLE                        Handle;
+  DHCP_SERVICE                      *Service;
+
+  BOOLEAN                           InDestory;
+
+  EFI_EVENT                         CompletionEvent;
+  EFI_EVENT                         RenewRebindEvent;
+
+  EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token;
+};
+
+//
+// DHCP driver is specical in that it is a singleton. Although it
+// has a service binding, there can be only one active child.
+//
+typedef struct _DHCP_SERVICE {
+  UINT32                        Signature;
+  EFI_SERVICE_BINDING_PROTOCOL  ServiceBinding;
+
+  INTN                          ServiceState; // CONFIGED, UNCONFIGED, and DESTORY
+  BOOLEAN                       InDestory;
+
+  EFI_HANDLE                    Controller;
+  EFI_HANDLE                    Image;
+
+  NET_LIST_ENTRY                Children;
+  UINTN                         NumChildren;
+
+  INTN                          DhcpState;
+  EFI_STATUS                    IoStatus;     // the result of last user operation
+  UINT32                        Xid;
+
+  IP4_ADDR                      ClientAddr;   // lease IP or configured client address
+  IP4_ADDR                      Netmask;
+  IP4_ADDR                      ServerAddr;
+
+  EFI_DHCP4_PACKET              *LastOffer;   // The last received offer
+  EFI_DHCP4_PACKET              *Selected;
+  DHCP_PARAMETER                *Para;
+
+  UINT32                        Lease;
+  UINT32                        T1;
+  UINT32                        T2;
+  INTN                          ExtraRefresh; // This refresh is reqested by user
+
+  UDP_IO_PORT                   *UdpIo;       // Udp child receiving all DHCP message
+  UDP_IO_PORT                   *LeaseIoPort; // Udp child with lease IP
+  NET_BUF                       *LastPacket;  // The last sent packet for retransmission
+  EFI_MAC_ADDRESS               Mac;
+  UINT8                         HwType;
+  UINT8                         HwLen;
+
+  DHCP_PROTOCOL                 *ActiveChild;
+  EFI_DHCP4_CONFIG_DATA         ActiveConfig;
+  UINT32                        UserOptionLen;
+
+  //
+  // Timer event and various timer
+  //
+  EFI_EVENT                     Timer;
+
+  UINT32                        PacketToLive; // Retransmission timer for our packets
+  INTN                          CurRetry;
+  INTN                          MaxRetries;
+
+  UINT32                        WaitOffer;    // Time to collect the offers
+  UINT32                        LeaseLife;
+};
+
+typedef struct {
+  EFI_DHCP4_PACKET_OPTION       **Option;
+  UINT32                        OptionCount;
+  UINT32                        Index;
+} DHCP_PARSE_CONTEXT;
+
+#define DHCP_INSTANCE_FROM_THIS(Proto)  \
+  CR ((Proto), DHCP_PROTOCOL, Dhcp4Protocol, DHCP_PROTOCOL_SIGNATURE)
+
+#define DHCP_SERVICE_FROM_THIS(Sb)      \
+  CR ((Sb), DHCP_SERVICE, ServiceBinding, DHCP_SERVICE_SIGNATURE)
+
+extern EFI_DHCP4_PROTOCOL mDhcp4ProtocolTemplate;
+
+VOID
+DhcpYieldControl (
+  IN DHCP_SERVICE         *DhcpSb
+  );
+
+#endif
diff --git a/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Io.c b/MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Io.c
new file mode 100644 (file)
index 0000000..e0fdcd3
--- /dev/null
@@ -0,0 +1,1631 @@
+/** @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
+  Dhcp4Io.c\r
+\r
+Abstract:\r
+\r
+  EFI DHCP protocol implementation\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Dhcp4Impl.h"\r
+\r
+UINT32  mDhcp4DefaultTimeout[4] = { 4, 8, 16, 32 };\r
+\r
+\r
+/**\r
+  Send an initial DISCOVER or REQUEST message according to the\r
+  DHCP service's current state.\r
+\r
+  @param  DhcpSb                The DHCP service instance\r
+\r
+  @retval EFI_SUCCESS           The request has been sent\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpInitRequest (\r
+  IN DHCP_SERVICE           *DhcpSb\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+\r
+  ASSERT ((DhcpSb->DhcpState == Dhcp4Init) || (DhcpSb->DhcpState == Dhcp4InitReboot));\r
+\r
+  if (DhcpSb->DhcpState == Dhcp4Init) {\r
+    DhcpSetState (DhcpSb, Dhcp4Selecting, FALSE);\r
+    Status = DhcpSendMessage (DhcpSb, NULL, NULL, DHCP_MSG_DISCOVER, NULL);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      DhcpSb->DhcpState = Dhcp4Init;\r
+      return Status;\r
+    }\r
+\r
+    DhcpSb->WaitOffer = DHCP_WAIT_OFFER;\r
+  } else {\r
+    DhcpSetState (DhcpSb, Dhcp4Rebooting, FALSE);\r
+    Status = DhcpSendMessage (DhcpSb, NULL, NULL, DHCP_MSG_REQUEST, NULL);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      DhcpSb->DhcpState = Dhcp4InitReboot;\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Call user provided callback function, and return the value the\r
+  function returns. If the user doesn't provide a callback, a\r
+  proper return value is selected to let the caller continue the\r
+  normal process.\r
+\r
+  @param  DhcpSb                The DHCP service instance\r
+  @param  Event                 The event as defined in the spec\r
+  @param  Packet                The current packet trigger the event\r
+  @param  NewPacket             The user's return new packet\r
+\r
+  @retval EFI_NOT_READY         Direct the caller to continue collecting the offer.\r
+  @retval EFI_SUCCESS           The user function returns success.\r
+  @retval EFI_ABORTED           The user function ask it to abort.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DhcpCallUser (\r
+  IN  DHCP_SERVICE          *DhcpSb,\r
+  IN  EFI_DHCP4_EVENT       Event,\r
+  IN  EFI_DHCP4_PACKET      *Packet,      OPTIONAL\r
+  OUT EFI_DHCP4_PACKET      **NewPacket   OPTIONAL\r
+  )\r
+{\r
+  EFI_DHCP4_CONFIG_DATA     *Config;\r
+  EFI_STATUS                Status;\r
+\r
+  if (NewPacket != NULL) {\r
+    *NewPacket = NULL;\r
+  }\r
+\r
+  //\r
+  // If user doesn't provide the call back function, return the value\r
+  // that directs the client to continue the normal process.\r
+  // In Dhcp4Selecting EFI_SUCCESS tells the client to stop collecting\r
+  // the offers and select a offer, EFI_NOT_READY tells the client to\r
+  // collect more offers.\r
+  //\r
+  Config = &DhcpSb->ActiveConfig;\r
+\r
+  if (Config->Dhcp4Callback == NULL) {\r
+    if (Event == Dhcp4RcvdOffer) {\r
+      return EFI_NOT_READY;\r
+    }\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = Config->Dhcp4Callback (\r
+                     &DhcpSb->ActiveChild->Dhcp4Protocol,\r
+                     Config->CallbackContext,\r
+                     DhcpSb->DhcpState,\r
+                     Event,\r
+                     Packet,\r
+                     NewPacket\r
+                     );\r
+\r
+  //\r
+  // User's callback should only return EFI_SUCCESS, EFI_NOT_READY,\r
+  // and EFI_ABORTED. If it returns values other than those, assume\r
+  // it to be EFI_ABORTED.\r
+  //\r
+  if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_READY)) {\r
+    return Status;\r
+  }\r
+\r
+  return EFI_ABORTED;\r
+}\r
+\r
+\r
+/**\r
+  Notify the user about the operation result.\r
+\r
+  @param  DhcpSb                DHCP service instance\r
+  @param  Which                 which notify function to signal\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+DhcpNotifyUser (\r
+  IN DHCP_SERVICE           *DhcpSb,\r
+  IN INTN                   Which\r
+  )\r
+{\r
+  DHCP_PROTOCOL             *Child;\r
+\r
+  if ((Child = DhcpSb->ActiveChild) == NULL) {\r
+    return ;\r
+  }\r
+\r
+  if ((Child->CompletionEvent != NULL) &&\r
+     ((Which == DHCP_NOTIFY_COMPLETION) || (Which == DHCP_NOTIFY_ALL))) {\r
+\r
+    gBS->SignalEvent (Child->CompletionEvent);\r
+    Child->CompletionEvent = NULL;\r
+  }\r
+\r
+  if ((Child->RenewRebindEvent != NULL) &&\r
+     ((Which == DHCP_NOTIFY_RENEWREBIND) || (Which == DHCP_NOTIFY_ALL))) {\r
+\r
+    gBS->SignalEvent (Child->RenewRebindEvent);\r
+    Child->RenewRebindEvent = NULL;\r
+  }\r
+}\r
+\r
+\r
+\r
+/**\r
+  Set the DHCP state. If CallUser is true, it will try to notify\r
+  the user before change the state by DhcpNotifyUser. It returns\r
+  EFI_ABORTED if the user return EFI_ABORTED, otherwise, it returns\r
+  EFI_SUCCESS. If CallUser is FALSE, it isn't necessary to test\r
+  the return value of this function.\r
+\r
+  @param  DhcpSb                The DHCP service instance\r
+  @param  State                 The new DHCP state to change to\r
+  @param  CallUser              Whether we need to call user\r
+\r
+  @retval EFI_SUCCESS           The state is changed\r
+  @retval EFI_ABORTED           The user asks to abort the DHCP process.\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpSetState (\r
+  IN DHCP_SERVICE           *DhcpSb,\r
+  IN INTN                   State,\r
+  IN BOOLEAN                CallUser\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+\r
+  if (CallUser) {\r
+    Status = EFI_SUCCESS;\r
+\r
+    if (State == Dhcp4Renewing) {\r
+      Status = DhcpCallUser (DhcpSb, Dhcp4EnterRenewing, NULL, NULL);\r
+\r
+    } else if (State == Dhcp4Rebinding) {\r
+      Status = DhcpCallUser (DhcpSb, Dhcp4EnterRebinding, NULL, NULL);\r
+\r
+    } else if (State == Dhcp4Bound) {\r
+      Status = DhcpCallUser (DhcpSb, Dhcp4BoundCompleted, NULL, NULL);\r
+\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Update the retransmission timer during the state transition.\r
+  // This will clear the retry count. This is also why the rule\r
+  // first transit the state, then send packets.\r
+  //\r
+  if (State == Dhcp4Init) {\r
+    DhcpSb->MaxRetries = DhcpSb->ActiveConfig.DiscoverTryCount;\r
+  } else {\r
+    DhcpSb->MaxRetries = DhcpSb->ActiveConfig.RequestTryCount;\r
+  }\r
+\r
+  if (DhcpSb->MaxRetries == 0) {\r
+    DhcpSb->MaxRetries = 4;\r
+  }\r
+\r
+  DhcpSb->CurRetry      = 0;\r
+  DhcpSb->PacketToLive  = 0;\r
+\r
+  DhcpSb->DhcpState     = State;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Set the retransmit timer for the packet. It will select from either\r
+  the discover timeouts/request timeouts or the default timeout values.\r
+\r
+  @param  DhcpSb                The DHCP service instance.\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+DhcpSetTransmitTimer (\r
+  IN DHCP_SERVICE           *DhcpSb\r
+  )\r
+{\r
+  UINT32                    *Times;\r
+\r
+  ASSERT (DhcpSb->MaxRetries > DhcpSb->CurRetry);\r
+\r
+  if (DhcpSb->DhcpState == Dhcp4Init) {\r
+    Times = DhcpSb->ActiveConfig.DiscoverTimeout;\r
+  } else {\r
+    Times = DhcpSb->ActiveConfig.RequestTimeout;\r
+  }\r
+\r
+  if (Times == NULL) {\r
+    Times = mDhcp4DefaultTimeout;\r
+  }\r
+\r
+  DhcpSb->PacketToLive = Times[DhcpSb->CurRetry];\r
+}\r
+\r
+\r
+/**\r
+  Compute the lease. If the server grants a permanent lease, just\r
+  process it as a normal timeout value since the lease will last\r
+  more than 100 years.\r
+\r
+  @param  DhcpSb                The DHCP service instance\r
+  @param  Para                  The DHCP parameter extracted from the server's\r
+                                response.\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+DhcpComputeLease (\r
+  IN DHCP_SERVICE           *DhcpSb,\r
+  IN DHCP_PARAMETER         *Para\r
+  )\r
+{\r
+  ASSERT (Para != NULL);\r
+\r
+  DhcpSb->Lease = Para->Lease;\r
+  DhcpSb->T2    = Para->T2;\r
+  DhcpSb->T1    = Para->T1;\r
+\r
+  if (DhcpSb->Lease == 0) {\r
+    DhcpSb->Lease = DHCP_DEFAULT_LEASE;\r
+  }\r
+\r
+  if ((DhcpSb->T2 == 0) || (DhcpSb->T2 >= Para->Lease)) {\r
+    DhcpSb->T2 = Para->Lease - (Para->Lease >> 3);\r
+  }\r
+\r
+  if ((DhcpSb->T1 == 0) || (DhcpSb->T1 >= Para->T2)) {\r
+    DhcpSb->T1 = DhcpSb->Lease >> 1;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Configure a UDP IO port to use the acquired lease address.\r
+  DHCP driver needs this port to unicast packet to the server\r
+  such as DHCP release.\r
+\r
+  @param  UdpIo                 The UDP IO port to configure\r
+  @param  Context               The opaque parameter to the function.\r
+\r
+  @retval EFI_SUCCESS           The UDP IO port is successfully configured.\r
+  @retval Others                It failed to configure the port.\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpConfigLeaseIoPort (\r
+  IN UDP_IO_PORT            *UdpIo,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  EFI_UDP4_CONFIG_DATA      UdpConfigData;\r
+  EFI_IPv4_ADDRESS          Subnet;\r
+  EFI_IPv4_ADDRESS          Gateway;\r
+  DHCP_SERVICE              *DhcpSb;\r
+  EFI_STATUS                Status;\r
+  IP4_ADDR                  Ip;\r
+\r
+  DhcpSb = (DHCP_SERVICE *) Context;\r
+\r
+  UdpConfigData.AcceptBroadcast     = FALSE;\r
+  UdpConfigData.AcceptPromiscuous   = FALSE;\r
+  UdpConfigData.AcceptAnyPort       = FALSE;\r
+  UdpConfigData.AllowDuplicatePort  = TRUE;\r
+  UdpConfigData.TypeOfService       = 0;\r
+  UdpConfigData.TimeToLive          = 64;\r
+  UdpConfigData.DoNotFragment       = FALSE;\r
+  UdpConfigData.ReceiveTimeout      = 1;\r
+  UdpConfigData.TransmitTimeout     = 0;\r
+\r
+  UdpConfigData.UseDefaultAddress   = FALSE;\r
+  UdpConfigData.StationPort         = DHCP_CLIENT_PORT;\r
+  UdpConfigData.RemotePort          = DHCP_SERVER_PORT;\r
+\r
+  Ip = HTONL (DhcpSb->ClientAddr);\r
+  NetCopyMem (&UdpConfigData.StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  Ip = HTONL (DhcpSb->Netmask);\r
+  NetCopyMem (&UdpConfigData.SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  NetZeroMem (&UdpConfigData.RemoteAddress, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  Status = UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Add a default route if received from the server.\r
+  //\r
+  if ((DhcpSb->Para != NULL) && (DhcpSb->Para->Router != 0)) {\r
+    NetZeroMem (&Subnet, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+    Ip = HTONL (DhcpSb->Para->Router);\r
+    NetCopyMem (&Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+    UdpIo->Udp->Routes (UdpIo->Udp, FALSE, &Subnet, &Subnet, &Gateway);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Update the lease states when a new lease is acquired. It will not only\r
+  save the acquired the address and lease time, it will also create a UDP\r
+  child to provide address resolution for the address.\r
+\r
+  @param  DhcpSb                The DHCP service instance\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resources.\r
+  @retval EFI_SUCCESS           The lease is recorded.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DhcpLeaseAcquired (\r
+  IN DHCP_SERVICE           *DhcpSb\r
+  )\r
+{\r
+  INTN                      Class;\r
+\r
+  DhcpSb->ClientAddr = EFI_NTOHL (DhcpSb->Selected->Dhcp4.Header.YourAddr);\r
+\r
+  if (DhcpSb->Para != NULL) {\r
+    DhcpSb->Netmask     = DhcpSb->Para->NetMask;\r
+    DhcpSb->ServerAddr  = DhcpSb->Para->ServerId;\r
+  }\r
+\r
+  if (DhcpSb->Netmask == 0) {\r
+    Class           = NetGetIpClass (DhcpSb->ClientAddr);\r
+    DhcpSb->Netmask = mIp4AllMasks[Class << 3];\r
+  }\r
+\r
+  if (DhcpSb->LeaseIoPort != NULL) {\r
+    UdpIoFreePort (DhcpSb->LeaseIoPort);\r
+  }\r
+\r
+  //\r
+  // Create a UDP/IP child to provide ARP service for the Leased IP,\r
+  // and transmit unicast packet with it as source address. Don't\r
+  // start receive on this port, the queued packet will be timeout.\r
+  //\r
+  DhcpSb->LeaseIoPort = UdpIoCreatePort (\r
+                          DhcpSb->Controller,\r
+                          DhcpSb->Image,\r
+                          DhcpConfigLeaseIoPort,\r
+                          DhcpSb\r
+                          );\r
+\r
+  if (DhcpSb->LeaseIoPort == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (!DHCP_IS_BOOTP (DhcpSb->Para)) {\r
+    DhcpComputeLease (DhcpSb, DhcpSb->Para);\r
+  }\r
+\r
+  return DhcpSetState (DhcpSb, Dhcp4Bound, TRUE);\r
+}\r
+\r
+\r
+/**\r
+  Clean up the DHCP related states, IoStatus isn't reset.\r
+\r
+  @param  DhcpSb                The DHCP instance service.\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+DhcpCleanLease (\r
+  IN DHCP_SERVICE           *DhcpSb\r
+  )\r
+{\r
+  DhcpSb->DhcpState   = Dhcp4Init;\r
+  DhcpSb->Xid         = DhcpSb->Xid + 1;\r
+  DhcpSb->ClientAddr  = 0;\r
+  DhcpSb->ServerAddr  = 0;\r
+\r
+  if (DhcpSb->LastOffer != NULL) {\r
+    NetFreePool (DhcpSb->LastOffer);\r
+    DhcpSb->LastOffer = NULL;\r
+  }\r
+\r
+  if (DhcpSb->Selected != NULL) {\r
+    NetFreePool (DhcpSb->Selected);\r
+    DhcpSb->Selected = NULL;\r
+  }\r
+\r
+  if (DhcpSb->Para != NULL) {\r
+    NetFreePool (DhcpSb->Para);\r
+    DhcpSb->Para = NULL;\r
+  }\r
+\r
+  DhcpSb->Lease         = 0;\r
+  DhcpSb->T1            = 0;\r
+  DhcpSb->T2            = 0;\r
+  DhcpSb->ExtraRefresh  = FALSE;\r
+\r
+  if (DhcpSb->LeaseIoPort != NULL) {\r
+    UdpIoFreePort (DhcpSb->LeaseIoPort);\r
+    DhcpSb->LeaseIoPort = NULL;\r
+  }\r
+\r
+  if (DhcpSb->LastPacket != NULL) {\r
+    NetbufFree (DhcpSb->LastPacket);\r
+    DhcpSb->LastPacket = NULL;\r
+  }\r
+\r
+  DhcpSb->PacketToLive  = 0;\r
+  DhcpSb->CurRetry      = 0;\r
+  DhcpSb->MaxRetries    = 0;\r
+  DhcpSb->WaitOffer     = 0;\r
+  DhcpSb->LeaseLife     = 0;\r
+}\r
+\r
+\r
+/**\r
+  Select a offer among all the offers collected. If the offer selected is\r
+  of BOOTP, the lease is recorded and user notified. If the offer is of\r
+  DHCP, it will request the offer from the server.\r
+\r
+  @param  DhcpSb                The DHCP service instance.\r
+\r
+  @retval EFI_SUCCESS           One of the offer is selected.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DhcpChooseOffer (\r
+  IN DHCP_SERVICE           *DhcpSb\r
+  )\r
+{\r
+  EFI_DHCP4_PACKET          *Selected;\r
+  EFI_DHCP4_PACKET          *NewPacket;\r
+  EFI_STATUS                Status;\r
+\r
+  ASSERT (DhcpSb->LastOffer != NULL);\r
+\r
+  //\r
+  // Stop waiting more offers\r
+  //\r
+  DhcpSb->WaitOffer = 0;\r
+\r
+  //\r
+  // User will cache previous offers if he wants to select\r
+  // from multiple offers. If user provides an invalid packet,\r
+  // use the last offer, otherwise use the provided packet.\r
+  //\r
+  NewPacket = NULL;\r
+  Status    = DhcpCallUser (DhcpSb, Dhcp4SelectOffer, DhcpSb->LastOffer, &NewPacket);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Selected = DhcpSb->LastOffer;\r
+\r
+  if (NewPacket != NULL) {\r
+    if (EFI_ERROR (DhcpValidateOptions (NewPacket, NULL))) {\r
+      NetFreePool (NewPacket);\r
+    } else {\r
+      NetFreePool (Selected);\r
+      Selected = NewPacket;\r
+    }\r
+  }\r
+\r
+  DhcpSb->Selected  = Selected;\r
+  DhcpSb->LastOffer = NULL;\r
+  DhcpSb->Para      = NULL;\r
+  DhcpValidateOptions (Selected, &DhcpSb->Para);\r
+\r
+  //\r
+  // A bootp offer has been selected, save the lease status,\r
+  // enter bound state then notify the user.\r
+  //\r
+  if (DHCP_IS_BOOTP (DhcpSb->Para)) {\r
+    Status = DhcpLeaseAcquired (DhcpSb);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    DhcpSb->IoStatus = EFI_SUCCESS;\r
+    DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_ALL);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Send a DHCP requests\r
+  //\r
+  Status = DhcpSetState (DhcpSb, Dhcp4Requesting, TRUE);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return DhcpSendMessage (DhcpSb, Selected, DhcpSb->Para, DHCP_MSG_REQUEST, NULL);\r
+}\r
+\r
+\r
+/**\r
+  Terminate the current address acquire. All the allocated resources\r
+  are released. Be careful when calling this function. A rule related\r
+  to this is: only call DhcpEndSession at the highest level, such as\r
+  DhcpInput, DhcpOnTimerTick...At the other level, just return error.\r
+\r
+  @param  DhcpSb                The DHCP service instance\r
+  @param  Status                The result of the DHCP process.\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+DhcpEndSession (\r
+  IN DHCP_SERVICE           *DhcpSb,\r
+  IN EFI_STATUS             Status\r
+  )\r
+{\r
+  if (DHCP_CONNECTED (DhcpSb->DhcpState)) {\r
+    DhcpCallUser (DhcpSb, Dhcp4AddressLost, NULL, NULL);\r
+  } else {\r
+    DhcpCallUser (DhcpSb, Dhcp4Fail, NULL, NULL);\r
+  }\r
+\r
+  DhcpCleanLease (DhcpSb);\r
+\r
+  DhcpSb->IoStatus = Status;\r
+  DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_ALL);\r
+}\r
+\r
+\r
+/**\r
+  Handle packets in DHCP select state.\r
+\r
+  @param  DhcpSb                The DHCP service instance\r
+  @param  Packet                The DHCP packet received\r
+  @param  Para                  The DHCP parameter extracted from the packet. That\r
+                                is, all the option value that we care.\r
+\r
+  @retval EFI_SUCCESS           The packet is successfully processed.\r
+  @retval Others                Some error occured.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DhcpHandleSelect (\r
+  IN DHCP_SERVICE           *DhcpSb,\r
+  IN EFI_DHCP4_PACKET       *Packet,\r
+  IN DHCP_PARAMETER         *Para\r
+  )\r
+{\r
+  EFI_DHCP4_HEADER          *Head;\r
+  EFI_STATUS                Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // First validate the message:\r
+  // 1. the offer is a unicast\r
+  // 2. if it is a DHCP message, it must contains a server ID.\r
+  // Don't return a error for these two case otherwise the session is ended.\r
+  //\r
+  Head = &Packet->Dhcp4.Header;\r
+\r
+  if (!Ip4IsUnicast (EFI_NTOHL (Head->YourAddr), (Para == NULL ? 0 : Para->NetMask))) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (!DHCP_IS_BOOTP (Para) &&\r
+     ((Para->DhcpType != DHCP_MSG_OFFER) || (Para->ServerId == 0))) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Call the user's callback. The action according to the return is as:\r
+  // 1. EFI_SUCESS: stop waiting for more offers, select the offer now\r
+  // 2. EFI_NOT_READY: wait for more offers\r
+  // 3. EFI_ABORTED: abort the address acquiring.\r
+  //\r
+  Status = DhcpCallUser (DhcpSb, Dhcp4RcvdOffer, Packet, NULL);\r
+\r
+  if (Status == EFI_SUCCESS) {\r
+    if (DhcpSb->LastOffer != NULL) {\r
+      NetFreePool (DhcpSb->LastOffer);\r
+    }\r
+\r
+    DhcpSb->LastOffer = Packet;\r
+\r
+    return DhcpChooseOffer (DhcpSb);\r
+\r
+  } else if (Status == EFI_NOT_READY) {\r
+    if (DhcpSb->LastOffer != NULL) {\r
+      NetFreePool (DhcpSb->LastOffer);\r
+    }\r
+\r
+    DhcpSb->LastOffer = Packet;\r
+\r
+  } else if (Status == EFI_ABORTED) {\r
+    //\r
+    // DhcpInput will end the session upon error return. Remember\r
+    // only to call DhcpEndSession at the top level call.\r
+    //\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_EXIT:\r
+  NetFreePool (Packet);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Handle packets in DHCP request state.\r
+\r
+  @param  DhcpSb                The DHCP service instance\r
+  @param  Packet                The DHCP packet received\r
+  @param  Para                  The DHCP parameter extracted from the packet. That\r
+                                is, all the option value that we care.\r
+\r
+  @retval EFI_SUCCESS           The packet is successfully processed.\r
+  @retval Others                Some error occured.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DhcpHandleRequest (\r
+  IN DHCP_SERVICE           *DhcpSb,\r
+  IN EFI_DHCP4_PACKET       *Packet,\r
+  IN DHCP_PARAMETER         *Para\r
+  )\r
+{\r
+  EFI_DHCP4_HEADER          *Head;\r
+  EFI_DHCP4_HEADER          *Selected;\r
+  EFI_STATUS                Status;\r
+  UINT8                     *Message;\r
+\r
+  ASSERT (!DHCP_IS_BOOTP (DhcpSb->Para));\r
+\r
+  Head      = &Packet->Dhcp4.Header;\r
+  Selected  = &DhcpSb->Selected->Dhcp4.Header;\r
+\r
+  //\r
+  // Ignore the BOOTP message and DHCP messages other than DHCP ACK/NACK.\r
+  //\r
+  if (DHCP_IS_BOOTP (Para) ||\r
+     (Para->ServerId != DhcpSb->Para->ServerId) ||\r
+     ((Para->DhcpType != DHCP_MSG_ACK) && (Para->DhcpType != DHCP_MSG_NAK))) {\r
+\r
+    Status = EFI_SUCCESS;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Received a NAK, end the session no matter what the user returns\r
+  //\r
+  Status = EFI_DEVICE_ERROR;\r
+\r
+  if (Para->DhcpType == DHCP_MSG_NAK) {\r
+    DhcpCallUser (DhcpSb, Dhcp4RcvdNak, Packet, NULL);\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Check whether the ACK matches the selected offer\r
+  //\r
+  Message = NULL;\r
+\r
+  if (!EFI_IP4_EQUAL (Head->YourAddr, Selected->YourAddr)) {\r
+    Message = "Lease confirmed isn't the same as that in the offer";\r
+    goto REJECT;\r
+  }\r
+\r
+  Status = DhcpCallUser (DhcpSb, Dhcp4RcvdAck, Packet, NULL);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Message = "Lease is denied upon received ACK";\r
+    goto REJECT;\r
+  }\r
+\r
+  //\r
+  // Record the lease, transit to BOUND state, then notify the user\r
+  //\r
+  Status = DhcpLeaseAcquired (DhcpSb);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Message = "Lease is denied upon entering bound";\r
+    goto REJECT;\r
+  }\r
+\r
+  DhcpSb->IoStatus = EFI_SUCCESS;\r
+  DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_COMPLETION);\r
+\r
+  NetFreePool (Packet);\r
+  return EFI_SUCCESS;\r
+\r
+REJECT:\r
+  DhcpSendMessage (DhcpSb, DhcpSb->Selected, DhcpSb->Para, DHCP_MSG_DECLINE, Message);\r
+\r
+ON_EXIT:\r
+  NetFreePool (Packet);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Handle packets in DHCP renew/rebound state.\r
+\r
+  @param  DhcpSb                The DHCP service instance\r
+  @param  Packet                The DHCP packet received\r
+  @param  Para                  The DHCP parameter extracted from the packet. That\r
+                                is, all the option value that we care.\r
+\r
+  @retval EFI_SUCCESS           The packet is successfully processed.\r
+  @retval Others                Some error occured.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DhcpHandleRenewRebind (\r
+  IN DHCP_SERVICE           *DhcpSb,\r
+  IN EFI_DHCP4_PACKET       *Packet,\r
+  IN DHCP_PARAMETER         *Para\r
+  )\r
+{\r
+  EFI_DHCP4_HEADER          *Head;\r
+  EFI_DHCP4_HEADER          *Selected;\r
+  EFI_STATUS                Status;\r
+\r
+  ASSERT (!DHCP_IS_BOOTP (DhcpSb->Para));\r
+\r
+  Head      = &Packet->Dhcp4.Header;\r
+  Selected  = &DhcpSb->Selected->Dhcp4.Header;\r
+\r
+  //\r
+  // Ignore the BOOTP message and DHCP messages other than DHCP ACK/NACK\r
+  //\r
+  if (DHCP_IS_BOOTP (Para) ||\r
+     (Para->ServerId != DhcpSb->Para->ServerId) ||\r
+     ((Para->DhcpType != DHCP_MSG_ACK) && (Para->DhcpType != DHCP_MSG_NAK))) {\r
+\r
+    Status = EFI_SUCCESS;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Received a NAK, ignore the user's return then terminate the process\r
+  //\r
+  Status = EFI_DEVICE_ERROR;\r
+\r
+  if (Para->DhcpType == DHCP_MSG_NAK) {\r
+    DhcpCallUser (DhcpSb, Dhcp4RcvdNak, Packet, NULL);\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // The lease is different from the selected. Don't send a DECLINE\r
+  // since it isn't existed in the client's FSM.\r
+  //\r
+  if (!EFI_IP4_EQUAL (Head->YourAddr, Selected->YourAddr)) {\r
+    goto ON_EXIT;\r</