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)
#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.
//
--- /dev/null
+/*++\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
--- /dev/null
+/*++\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
--- /dev/null
+/*++\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
0xFFFFFFFF,
};
+EFI_IPv4_ADDRESS mZeroIp4Addr = {0, 0, 0, 0};
/**\r
Converts the low nibble of a byte to hex unicode character.\r
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
[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
--- /dev/null
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ 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
+
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ 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
--- /dev/null
+/** @file
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ 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
+
--- /dev/null
+#/** @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
--- /dev/null
+<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
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ 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
--- /dev/null
+/** @file
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ 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
+
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ 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
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#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
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "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
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\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
--- /dev/null
+/** @file
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ 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
--- /dev/null
+#/** @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
--- /dev/null
+<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
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ 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
--- /dev/null
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ 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
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ 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
+ }\r
+\r
+ Status = DhcpCallUser (DhcpSb, Dhcp4RcvdAck, Packet, NULL);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Record the lease, start timer for T1 and T2,\r
+ //\r
+ DhcpComputeLease (DhcpSb, Para);\r
+ DhcpSb->LeaseLife = 0;\r
+ DhcpSetState (DhcpSb, Dhcp4Bound, TRUE);\r
+\r
+ if (DhcpSb->ExtraRefresh) {\r
+ DhcpSb->ExtraRefresh = FALSE;\r
+\r
+ DhcpSb->IoStatus = EFI_SUCCESS;\r
+ DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_RENEWREBIND);\r
+ }\r
+\r
+ON_EXIT:\r
+ NetFreePool (Packet);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Handle packets in DHCP reboot 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
+DhcpHandleReboot (\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
+ Head = &Packet->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->DhcpType != DHCP_MSG_ACK) && (Para->DhcpType != DHCP_MSG_NAK))) {\r
+\r
+ Status = EFI_SUCCESS;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // If a NAK is received, transit to INIT and try again.\r
+ //\r
+ if (Para->DhcpType == DHCP_MSG_NAK) {\r
+ DhcpCallUser (DhcpSb, Dhcp4RcvdNak, Packet, NULL);\r
+\r
+ DhcpSb->ClientAddr = 0;\r
+ DhcpSb->DhcpState = Dhcp4Init;\r
+\r
+ Status = DhcpInitRequest (DhcpSb);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Check whether the ACK matches the selected offer\r
+ //\r
+ if (EFI_NTOHL (Head->YourAddr) != DhcpSb->ClientAddr) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = DhcpCallUser (DhcpSb, Dhcp4RcvdAck, Packet, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // OK, get the parameter from server, record the lease\r
+ //\r
+ DhcpSb->Para = NetAllocatePool (sizeof (DHCP_PARAMETER));\r
+\r
+ if (DhcpSb->Para == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ DhcpSb->Selected = Packet;\r
+ CopyMem (DhcpSb->Para, Para, sizeof (DHCP_PARAMETER));\r
+\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_COMPLETION);\r
+ return EFI_SUCCESS;\r
+\r
+ON_EXIT:\r
+ NetFreePool (Packet);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Handle the received DHCP packets. This function drivers the DHCP\r
+ state machine.\r
+\r
+ @param UdpPacket The UDP packets received.\r
+ @param Points The local/remote UDP access points\r
+ @param IoStatus The status of the UDP receive\r
+ @param Context The opaque parameter to the function.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+DhcpInput (\r
+ NET_BUF *UdpPacket,\r
+ UDP_POINTS *Points,\r
+ EFI_STATUS IoStatus,\r
+ VOID *Context\r
+ )\r
+{\r
+ DHCP_SERVICE *DhcpSb;\r
+ EFI_DHCP4_HEADER *Head;\r
+ EFI_DHCP4_PACKET *Packet;\r
+ DHCP_PARAMETER *Para;\r
+ EFI_STATUS Status;\r
+ UINT32 Len;\r
+\r
+ Packet = NULL;\r
+ DhcpSb = (DHCP_SERVICE *) Context;\r
+\r
+ //\r
+ // Don't restart receive if error occurs or DHCP is destoried.\r
+ //\r
+ if (EFI_ERROR (IoStatus)) {\r
+ return ;\r
+ } else if (DhcpSb->ServiceState == DHCP_DESTORY) {\r
+ NetbufFree (UdpPacket);\r
+ return ;\r
+ }\r
+\r
+ ASSERT (UdpPacket != NULL);\r
+\r
+ if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // Validate the packet received\r
+ //\r
+ if (UdpPacket->TotalSize < sizeof (EFI_DHCP4_HEADER)) {\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // Copy the DHCP message to a continuous memory block\r
+ //\r
+ Len = sizeof (EFI_DHCP4_PACKET) + UdpPacket->TotalSize - sizeof (EFI_DHCP4_HEADER);\r
+ Packet = (EFI_DHCP4_PACKET *) NetAllocatePool (Len);\r
+\r
+ if (Packet == NULL) {\r
+ goto RESTART;\r
+ }\r
+\r
+ Packet->Size = Len;\r
+ Head = &Packet->Dhcp4.Header;\r
+ Packet->Length = NetbufCopy (UdpPacket, 0, UdpPacket->TotalSize, (UINT8 *) Head);\r
+\r
+ if (Packet->Length != UdpPacket->TotalSize) {\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // Is this packet the answer to our packet?\r
+ //\r
+ if ((Head->OpCode != BOOTP_REPLY) ||\r
+ (NTOHL (Head->Xid) != DhcpSb->Xid) ||\r
+ !NET_MAC_EQUAL (&DhcpSb->Mac, Head->ClientHwAddr, DhcpSb->HwLen)) {\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // Validate the options and retrieve the interested options\r
+ //\r
+ Para = NULL;\r
+ if ((Packet->Length > sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)) &&\r
+ (Packet->Dhcp4.Magik == DHCP_OPTION_MAGIC) &&\r
+ EFI_ERROR (DhcpValidateOptions (Packet, &Para))) {\r
+\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // Call the handler for each state. The handler should return\r
+ // EFI_SUCCESS if the process can go on no matter whether the\r
+ // packet is ignored or not. If the return is EFI_ERROR, the\r
+ // session will be terminated. Packet's ownership is handled\r
+ // over to the handlers. If operation succeeds, the handler\r
+ // must notify the user. It isn't necessary to do if EFI_ERROR\r
+ // is returned because the DhcpEndSession will notify the user.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ switch (DhcpSb->DhcpState) {\r
+ case Dhcp4Selecting:\r
+ Status = DhcpHandleSelect (DhcpSb, Packet, Para);\r
+ break;\r
+\r
+ case Dhcp4Requesting:\r
+ Status = DhcpHandleRequest (DhcpSb, Packet, Para);\r
+ break;\r
+\r
+ case Dhcp4InitReboot:\r
+ case Dhcp4Init:\r
+ case Dhcp4Bound:\r
+ //\r
+ // Ignore the packet in INITREBOOT, INIT and BOUND states\r
+ //\r
+ NetFreePool (Packet);\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+\r
+ case Dhcp4Renewing:\r
+ case Dhcp4Rebinding:\r
+ Status = DhcpHandleRenewRebind (DhcpSb, Packet, Para);\r
+ break;\r
+\r
+ case Dhcp4Rebooting:\r
+ Status = DhcpHandleReboot (DhcpSb, Packet, Para);\r
+ break;\r
+ }\r
+\r
+ if (Para != NULL) {\r
+ NetFreePool (Para);\r
+ }\r
+\r
+ Packet = NULL;\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetbufFree (UdpPacket);\r
+ DhcpEndSession (DhcpSb, Status);\r
+ return ;\r
+ }\r
+\r
+RESTART:\r
+ NetbufFree (UdpPacket);\r
+\r
+ if (Packet != NULL) {\r
+ NetFreePool (Packet);\r
+ }\r
+\r
+ Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DhcpEndSession (DhcpSb, EFI_DEVICE_ERROR);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Release the packet.\r
+\r
+ @param Arg The packet to release\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+DhcpReleasePacket (\r
+ IN VOID *Arg\r
+ )\r
+{\r
+ NetFreePool (Arg);\r
+}\r
+\r
+\r
+/**\r
+ Release the net buffer when packet is sent.\r
+\r
+ @param UdpPacket The UDP packets received.\r
+ @param Points The local/remote UDP access points\r
+ @param IoStatus The status of the UDP receive\r
+ @param Context The opaque parameter to the function.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+DhcpOnPacketSent (\r
+ NET_BUF *Packet,\r
+ UDP_POINTS *Points,\r
+ EFI_STATUS IoStatus,\r
+ VOID *Context\r
+ )\r
+{\r
+ NetbufFree (Packet);\r
+}\r
+\r
+\r
+\r
+/**\r
+ Build and transmit a DHCP message according to the current states.\r
+ This function implement the Table 5. of RFC 2131. Always transits\r
+ the state (as defined in Figure 5. of the same RFC) before sending\r
+ a DHCP message. The table is adjusted accordingly.\r
+\r
+ @param DhcpSb The DHCP service instance\r
+ @param Seed The seed packet which the new packet is based on\r
+ @param Para The DHCP parameter of the Seed packet\r
+ @param Type The message type to send\r
+ @param Msg The human readable message to include in the packet\r
+ sent.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources for the packet\r
+ @retval EFI_ACCESS_DENIED Failed to transmit the packet through UDP\r
+ @retval EFI_SUCCESS The message is sent\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpSendMessage (\r
+ IN DHCP_SERVICE *DhcpSb,\r
+ IN EFI_DHCP4_PACKET *Seed,\r
+ IN DHCP_PARAMETER *Para,\r
+ IN UINT8 Type,\r
+ IN UINT8 *Msg\r
+ )\r
+{\r
+ EFI_DHCP4_CONFIG_DATA *Config;\r
+ EFI_DHCP4_PACKET *Packet;\r
+ EFI_DHCP4_PACKET *NewPacket;\r
+ EFI_DHCP4_HEADER *Head;\r
+ EFI_DHCP4_HEADER *SeedHead;\r
+ UDP_IO_PORT *UdpIo;\r
+ UDP_POINTS EndPoint;\r
+ NET_BUF *Wrap;\r
+ NET_FRAGMENT Frag;\r
+ EFI_STATUS Status;\r
+ IP4_ADDR IpAddr;\r
+ UINT8 *Buf;\r
+ UINT16 MaxMsg;\r
+ UINT32 Len;\r
+ UINT32 Index;\r
+\r
+ //\r
+ // Allocate a big enough memory block to hold the DHCP packet\r
+ //\r
+ Len = sizeof (EFI_DHCP4_PACKET) + 128 + DhcpSb->UserOptionLen;\r
+\r
+ if (Msg != NULL) {\r
+ Len += (UINT32)AsciiStrLen (Msg);\r
+ }\r
+\r
+ Packet = NetAllocatePool (Len);\r
+\r
+ if (Packet == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Packet->Size = Len;\r
+ Packet->Length = sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32);\r
+\r
+ //\r
+ // Fill in the DHCP header fields\r
+ //\r
+ Config = &DhcpSb->ActiveConfig;\r
+ SeedHead = NULL;\r
+\r
+ if (Seed != NULL) {\r
+ SeedHead = &Seed->Dhcp4.Header;\r
+ }\r
+\r
+ Head = &Packet->Dhcp4.Header;\r
+ NetZeroMem (Head, sizeof (EFI_DHCP4_HEADER));\r
+\r
+ Head->OpCode = BOOTP_REQUEST;\r
+ Head->HwType = DhcpSb->HwType;\r
+ Head->HwAddrLen = DhcpSb->HwLen;\r
+ Head->Xid = HTONL (DhcpSb->Xid);\r
+ Head->Reserved = HTONS (0x8000); //Server, broadcast the message please.\r
+\r
+ EFI_IP4 (Head->ClientAddr) = HTONL (DhcpSb->ClientAddr);\r
+ NetCopyMem (Head->ClientHwAddr, DhcpSb->Mac.Addr, DhcpSb->HwLen);\r
+\r
+ //\r
+ // Append the DHCP message type\r
+ //\r
+ Packet->Dhcp4.Magik = DHCP_OPTION_MAGIC;\r
+ Buf = Packet->Dhcp4.Option;\r
+ Buf = DhcpAppendOption (Buf, DHCP_TAG_TYPE, 1, &Type);\r
+\r
+ //\r
+ // Append the serverid option if necessary:\r
+ // 1. DHCP decline message\r
+ // 2. DHCP release message\r
+ // 3. DHCP request to confirm one lease.\r
+ //\r
+ if ((Type == DHCP_MSG_DECLINE) || (Type == DHCP_MSG_RELEASE) ||\r
+ ((Type == DHCP_MSG_REQUEST) && (DhcpSb->DhcpState == Dhcp4Requesting))) {\r
+\r
+ ASSERT ((Para != NULL) && (Para->ServerId != 0));\r
+\r
+ IpAddr = HTONL (Para->ServerId);\r
+ Buf = DhcpAppendOption (Buf, DHCP_TAG_SERVER_ID, 4, (UINT8 *) &IpAddr);\r
+ }\r
+\r
+ //\r
+ // Append the requested IP option if necessary:\r
+ // 1. DHCP request to use the previously allocated address\r
+ // 2. DHCP request to confirm one lease\r
+ // 3. DHCP decline to decline one lease\r
+ //\r
+ IpAddr = 0;\r
+\r
+ if (Type == DHCP_MSG_REQUEST) {\r
+ if (DhcpSb->DhcpState == Dhcp4Rebooting) {\r
+ IpAddr = EFI_IP4 (Config->ClientAddress);\r
+\r
+ } else if (DhcpSb->DhcpState == Dhcp4Requesting) {\r
+ ASSERT (SeedHead != NULL);\r
+ IpAddr = EFI_IP4 (SeedHead->YourAddr);\r
+ }\r
+\r
+ } else if (Type == DHCP_MSG_DECLINE) {\r
+ ASSERT (SeedHead != NULL);\r
+ IpAddr = EFI_IP4 (SeedHead->YourAddr);\r
+ }\r
+\r
+ if (IpAddr != 0) {\r
+ Buf = DhcpAppendOption (Buf, DHCP_TAG_REQUEST_IP, 4, (UINT8 *) &IpAddr);\r
+ }\r
+\r
+ //\r
+ // Append the Max Message Length option if it isn't a DECLINE\r
+ // or RELEASE to direct the server use large messages instead of\r
+ // override the BOOTFILE and SERVER fields in the message head.\r
+ //\r
+ if ((Type != DHCP_MSG_DECLINE) && (Type != DHCP_MSG_RELEASE)) {\r
+ MaxMsg = HTONS (0xFF00);\r
+ Buf = DhcpAppendOption (Buf, DHCP_TAG_MAXMSG, 2, (UINT8 *) &MaxMsg);\r
+ }\r
+\r
+ //\r
+ // Append the user's message if it isn't NULL\r
+ //\r
+ if (Msg != NULL) {\r
+ Len = NET_MIN ((UINT32) AsciiStrLen (Msg), 255);\r
+ Buf = DhcpAppendOption (Buf, DHCP_TAG_MESSAGE, (UINT16) Len, Msg);\r
+ }\r
+\r
+ //\r
+ // Append the user configured options\r
+ //\r
+ if (DhcpSb->UserOptionLen != 0) {\r
+ for (Index = 0; Index < Config->OptionCount; Index++) {\r
+ //\r
+ // We can't use any option other than the client ID from user\r
+ // if it is a DHCP decline or DHCP release .\r
+ //\r
+ if (((Type == DHCP_MSG_DECLINE) || (Type == DHCP_MSG_RELEASE)) &&\r
+ (Config->OptionList[Index]->OpCode != DHCP_TAG_CLIENT_ID)) {\r
+ continue;\r
+ }\r
+\r
+ Buf = DhcpAppendOption (\r
+ Buf,\r
+ Config->OptionList[Index]->OpCode,\r
+ Config->OptionList[Index]->Length,\r
+ Config->OptionList[Index]->Data\r
+ );\r
+ }\r
+ }\r
+\r
+ *(Buf++) = DHCP_TAG_EOP;\r
+ Packet->Length += (UINT32) (Buf - Packet->Dhcp4.Option);\r
+\r
+ //\r
+ // OK, the message is built, call the user to override it.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ NewPacket = NULL;\r
+\r
+ if (Type == DHCP_MSG_DISCOVER) {\r
+ Status = DhcpCallUser (DhcpSb, Dhcp4SendDiscover, Packet, &NewPacket);\r
+\r
+ } else if (Type == DHCP_MSG_REQUEST) {\r
+ Status = DhcpCallUser (DhcpSb, Dhcp4SendRequest, Packet, &NewPacket);\r
+\r
+ } else if (Type == DHCP_MSG_DECLINE) {\r
+ Status = DhcpCallUser (DhcpSb, Dhcp4SendDecline, Packet, &NewPacket);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetFreePool (Packet);\r
+ return Status;\r
+ }\r
+\r
+ if (NewPacket != NULL) {\r
+ NetFreePool (Packet);\r
+ Packet = NewPacket;\r
+ }\r
+\r
+ //\r
+ // Wrap it into a netbuf then send it.\r
+ //\r
+ Frag.Bulk = (UINT8 *) &Packet->Dhcp4.Header;\r
+ Frag.Len = Packet->Length;\r
+ Wrap = NetbufFromExt (&Frag, 1, 0, 0, DhcpReleasePacket, Packet);\r
+\r
+ if (Wrap == NULL) {\r
+ NetFreePool (Packet);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Save it as the last sent packet for retransmission\r
+ //\r
+ if (DhcpSb->LastPacket != NULL) {\r
+ NetbufFree (DhcpSb->LastPacket);\r
+ }\r
+\r
+ NET_GET_REF (Wrap);\r
+ DhcpSb->LastPacket = Wrap;\r
+ DhcpSetTransmitTimer (DhcpSb);\r
+\r
+ //\r
+ // Broadcast the message, unless we know the server address.\r
+ // Use the lease UdpIo port to send the unicast packet.\r
+ //\r
+ EndPoint.RemoteAddr = 0xffffffff;\r
+ EndPoint.LocalAddr = 0;\r
+ EndPoint.RemotePort = DHCP_SERVER_PORT;\r
+ EndPoint.LocalPort = DHCP_CLIENT_PORT;\r
+ UdpIo = DhcpSb->UdpIo;\r
+\r
+ if ((DhcpSb->DhcpState == Dhcp4Renewing) || (Type == DHCP_MSG_RELEASE)) {\r
+ EndPoint.RemoteAddr = DhcpSb->ServerAddr;\r
+ EndPoint.LocalAddr = DhcpSb->ClientAddr;\r
+ UdpIo = DhcpSb->LeaseIoPort;\r
+ }\r
+\r
+ ASSERT (UdpIo != NULL);\r
+ Status = UdpIoSendDatagram (UdpIo, Wrap, &EndPoint, 0, DhcpOnPacketSent, DhcpSb);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetbufFree (Wrap);\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Retransmit a saved packet. Only DISCOVER and REQUEST messages\r
+ will be retransmitted.\r
+\r
+ @param DhcpSb The DHCP service instance\r
+\r
+ @retval EFI_ACCESS_DENIED Failed to transmit packet through UDP port\r
+ @retval EFI_SUCCESS The packet is retransmitted.\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpRetransmit (\r
+ IN DHCP_SERVICE *DhcpSb\r
+ )\r
+{\r
+ UDP_IO_PORT *UdpIo;\r
+ UDP_POINTS EndPoint;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (DhcpSb->LastPacket != NULL);\r
+\r
+ //\r
+ // Broadcast the message, unless we know the server address.\r
+ //\r
+ EndPoint.RemotePort = DHCP_SERVER_PORT;\r
+ EndPoint.LocalPort = DHCP_CLIENT_PORT;\r
+ EndPoint.RemoteAddr = 0xffffffff;\r
+ EndPoint.LocalAddr = 0;\r
+ UdpIo = DhcpSb->UdpIo;\r
+\r
+ if (DhcpSb->DhcpState == Dhcp4Renewing) {\r
+ EndPoint.RemoteAddr = DhcpSb->ServerAddr;\r
+ EndPoint.LocalAddr = DhcpSb->ClientAddr;\r
+ UdpIo = DhcpSb->LeaseIoPort;\r
+ }\r
+\r
+ ASSERT (UdpIo != NULL);\r
+\r
+ NET_GET_REF (DhcpSb->LastPacket);\r
+ Status = UdpIoSendDatagram (\r
+ UdpIo,\r
+ DhcpSb->LastPacket,\r
+ &EndPoint,\r
+ 0,\r
+ DhcpOnPacketSent,\r
+ DhcpSb\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NET_PUT_REF (DhcpSb->LastPacket);\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Each DHCP service has three timer. Two of them are count down timer.\r
+ One for the packet retransmission. The other is to collect the offers.\r
+ The third timer increaments the lease life which is compared to T1, T2,\r
+ and lease to determine the time to renew and rebind the lease.\r
+ DhcpOnTimerTick will be called once every second.\r
+\r
+ @param Event The timer event\r
+ @param Context The context, which is the DHCP service instance.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DhcpOnTimerTick (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ DHCP_SERVICE *DhcpSb;\r
+ EFI_STATUS Status;\r
+\r
+ DhcpSb = (DHCP_SERVICE *) Context;\r
+\r
+ //\r
+ // Check the retransmit timer first\r
+ //\r
+ if ((DhcpSb->PacketToLive > 0) && (--DhcpSb->PacketToLive == 0)) {\r
+\r
+ if (++DhcpSb->CurRetry < DhcpSb->MaxRetries) {\r
+ //\r
+ // Still has another try\r
+ //\r
+ DhcpRetransmit (DhcpSb);\r
+ DhcpSetTransmitTimer (DhcpSb);\r
+\r
+ } else {\r
+ if (!DHCP_CONNECTED (DhcpSb->DhcpState)) {\r
+ goto END_SESSION;\r
+ }\r
+\r
+ //\r
+ // Retransmission failed, if the DHCP request is initiated by\r
+ // user, adjust the current state according to the lease life.\r
+ // Otherwise do nothing to wait the lease to timeout\r
+ //\r
+ if (DhcpSb->ExtraRefresh) {\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (DhcpSb->LeaseLife < DhcpSb->T1) {\r
+ Status = DhcpSetState (DhcpSb, Dhcp4Bound, FALSE);\r
+\r
+ } else if (DhcpSb->LeaseLife < DhcpSb->T2) {\r
+ Status = DhcpSetState (DhcpSb, Dhcp4Renewing, FALSE);\r
+\r
+ } else if (DhcpSb->LeaseLife < DhcpSb->Lease) {\r
+ Status = DhcpSetState (DhcpSb, Dhcp4Rebinding, FALSE);\r
+\r
+ } else {\r
+ goto END_SESSION;\r
+\r
+ }\r
+\r
+ DhcpSb->IoStatus = EFI_TIMEOUT;\r
+ DhcpNotifyUser (DhcpSb, DHCP_NOTIFY_RENEWREBIND);\r
+ }\r
+ }\r
+ }\r
+\r
+ if ((DhcpSb->WaitOffer > 0) && (--DhcpSb->WaitOffer == 0)) {\r
+ //\r
+ // OK, offer collection finished, select a offer\r
+ //\r
+ ASSERT (DhcpSb->DhcpState == Dhcp4Selecting);\r
+\r
+ if (DhcpSb->LastOffer == NULL) {\r
+ goto END_SESSION;\r
+ }\r
+\r
+ if (EFI_ERROR (DhcpChooseOffer (DhcpSb))) {\r
+ goto END_SESSION;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If an address has been acquired, check whether need to\r
+ // refresh or whether it has expired.\r
+ //\r
+ if (DHCP_CONNECTED (DhcpSb->DhcpState)) {\r
+ DhcpSb->LeaseLife++;\r
+\r
+ //\r
+ // Don't timeout the lease, only count the life if user is\r
+ // requesting extra renew/rebind. Adjust the state after that.\r
+ //\r
+ if (DhcpSb->ExtraRefresh) {\r
+ return ;\r
+ }\r
+\r
+ if (DhcpSb->LeaseLife == DhcpSb->Lease) {\r
+ //\r
+ // Lease expires, end the session\r
+ //\r
+ goto END_SESSION;\r
+\r
+ } else if (DhcpSb->LeaseLife == DhcpSb->T2) {\r
+ //\r
+ // T2 expires, transit to rebinding then send a REQUEST to any server\r
+ //\r
+ if (EFI_ERROR (DhcpSetState (DhcpSb, Dhcp4Rebinding, TRUE))) {\r
+ goto END_SESSION;\r
+ }\r
+\r
+ Status = DhcpSendMessage (\r
+ DhcpSb,\r
+ DhcpSb->Selected,\r
+ DhcpSb->Para,\r
+ DHCP_MSG_REQUEST,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto END_SESSION;\r
+ }\r
+\r
+ } else if (DhcpSb->LeaseLife == DhcpSb->T1) {\r
+ //\r
+ // T1 expires, transit to renewing, then send a REQUEST to the server\r
+ //\r
+ if (EFI_ERROR (DhcpSetState (DhcpSb, Dhcp4Renewing, TRUE))) {\r
+ goto END_SESSION;\r
+ }\r
+\r
+ Status = DhcpSendMessage (\r
+ DhcpSb,\r
+ DhcpSb->Selected,\r
+ DhcpSb->Para,\r
+ DHCP_MSG_REQUEST,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto END_SESSION;\r
+ }\r
+ }\r
+ }\r
+\r
+ return ;\r
+\r
+END_SESSION:\r
+ DhcpEndSession (DhcpSb, EFI_TIMEOUT);\r
+\r
+ return ;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Dhcp4Io.h
+
+Abstract:
+
+ The DHCP4 protocol implementation.
+
+
+**/
+
+#ifndef __EFI_DHCP4_IO_H__
+#define __EFI_DHCP4_IO_H__
+
+#include <PiDxe.h>
+
+#include <Protocol/ServiceBinding.h>
+
+#include <Library/NetLib.h>
+#include <Library/UdpIoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+
+enum {
+ DHCP_WAIT_OFFER = 3, // Time to wait the offers
+ DHCP_DEFAULT_LEASE = 7 *24 *60 *60, // Seven days as default.
+ DHCP_SERVER_PORT = 67,
+ DHCP_CLIENT_PORT = 68,
+
+ //
+ // BOOTP header "op" field
+ //
+ BOOTP_REQUEST = 1,
+ BOOTP_REPLY = 2,
+
+ //
+ // DHCP message types
+ //
+ DHCP_MSG_DISCOVER = 1,
+ DHCP_MSG_OFFER = 2,
+ DHCP_MSG_REQUEST = 3,
+ DHCP_MSG_DECLINE = 4,
+ DHCP_MSG_ACK = 5,
+ DHCP_MSG_NAK = 6,
+ DHCP_MSG_RELEASE = 7,
+ DHCP_MSG_INFORM = 8,
+
+ //
+ // DHCP notify user type
+ //
+ DHCP_NOTIFY_COMPLETION = 1,
+ DHCP_NOTIFY_RENEWREBIND,
+ DHCP_NOTIFY_ALL,
+};
+
+#define DHCP_IS_BOOTP(Parameter) (((Parameter) == NULL) || ((Parameter)->DhcpType == 0))
+
+#define DHCP_CONNECTED(State) \
+ (((State) == Dhcp4Bound) || ((State) == (Dhcp4Renewing)) || ((State) == Dhcp4Rebinding))
+
+EFI_STATUS
+DhcpSetState (
+ IN DHCP_SERVICE *DhcpSb,
+ IN INTN State,
+ IN BOOLEAN CallUser
+ );
+
+EFI_STATUS
+DhcpSendMessage (
+ IN DHCP_SERVICE *DhcpSb,
+ IN EFI_DHCP4_PACKET *Seed,
+ IN DHCP_PARAMETER *Para,
+ IN UINT8 Type,
+ IN UINT8 *Msg
+ );
+
+VOID
+EFIAPI
+DhcpOnTimerTick (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+VOID
+DhcpInput (
+ NET_BUF *UdpPacket,
+ UDP_POINTS *Points,
+ EFI_STATUS IoStatus,
+ VOID *Context
+ );
+
+EFI_STATUS
+DhcpInitRequest (
+ IN DHCP_SERVICE *DhcpSb
+ );
+
+VOID
+DhcpCleanLease (
+ IN DHCP_SERVICE *DhcpSb
+ );
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Dhcp4Option.c\r
+\r
+Abstract:\r
+\r
+ Function to validate, parse, process the DHCP options\r
+\r
+\r
+**/\r
+\r
+#include "Dhcp4Impl.h"\r
+\r
+//\r
+// A list of the format of DHCP Options sorted by option tag\r
+// to validate a dhcp message. Refere the comments of the\r
+// DHCP_OPTION_FORMAT structure.\r
+//\r
+STATIC\r
+DHCP_OPTION_FORMAT\r
+DhcpOptionFormats [] = {\r
+ {DHCP_TAG_NETMASK, DHCP_OPTION_IP, 1, 1 , TRUE},\r
+ {DHCP_TAG_TIME_OFFSET, DHCP_OPTION_INT32, 1, 1 , FALSE},\r
+ {DHCP_TAG_ROUTER, DHCP_OPTION_IP, 1, -1 , TRUE},\r
+ {DHCP_TAG_TIME_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_NAME_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_DNS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_LOG_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_COOKIE_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_LPR_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_IMPRESS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_RL_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_HOSTNAME, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_BOOTFILE_LEN, DHCP_OPTION_INT16, 1, 1 , FALSE},\r
+ {DHCP_TAG_DUMP, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_DOMAINNAME, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_SWAP_SERVER, DHCP_OPTION_IP, 1, 1 , FALSE},\r
+ {DHCP_TAG_ROOTPATH, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_EXTEND_PATH, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+\r
+ {DHCP_TAG_IPFORWARD, DHCP_OPTION_SWITCH, 1, 1 , FALSE},\r
+ {DHCP_TAG_NONLOCAL_SRR, DHCP_OPTION_SWITCH, 1, 1 , FALSE},\r
+ {DHCP_TAG_POLICY_SRR, DHCP_OPTION_IPPAIR, 1, -1 , FALSE},\r
+ {DHCP_TAG_EMTU, DHCP_OPTION_INT16, 1, 1 , FALSE},\r
+ {DHCP_TAG_TTL, DHCP_OPTION_INT8, 1, 1 , FALSE},\r
+ {DHCP_TAG_PATHMTU_AGE, DHCP_OPTION_INT32, 1, 1 , FALSE},\r
+ {DHCP_TAG_PATHMTU_PLATEAU,DHCP_OPTION_INT16, 1, -1 , FALSE},\r
+\r
+ {DHCP_TAG_IFMTU, DHCP_OPTION_INT16, 1, 1 , FALSE},\r
+ {DHCP_TAG_SUBNET_LOCAL, DHCP_OPTION_SWITCH, 1, 1 , FALSE},\r
+ {DHCP_TAG_BROADCAST, DHCP_OPTION_IP, 1, 1 , FALSE},\r
+ {DHCP_TAG_DISCOVER_MASK, DHCP_OPTION_SWITCH, 1, 1 , FALSE},\r
+ {DHCP_TAG_SUPPLY_MASK, DHCP_OPTION_SWITCH, 1, 1 , FALSE},\r
+ {DHCP_TAG_DISCOVER_ROUTE, DHCP_OPTION_SWITCH, 1, 1 , FALSE},\r
+ {DHCP_TAG_ROUTER_SOLICIT, DHCP_OPTION_IP, 1, 1 , FALSE},\r
+ {DHCP_TAG_STATIC_ROUTE, DHCP_OPTION_IPPAIR, 1, -1 , FALSE},\r
+\r
+ {DHCP_TAG_TRAILER, DHCP_OPTION_SWITCH, 1, 1 , FALSE},\r
+ {DHCP_TAG_ARPAGE, DHCP_OPTION_INT32, 1, 1 , FALSE},\r
+ {DHCP_TAG_ETHER_ENCAP, DHCP_OPTION_SWITCH, 1, 1 , FALSE},\r
+\r
+ {DHCP_TAG_TCP_TTL, DHCP_OPTION_INT8, 1, 1 , FALSE},\r
+ {DHCP_TAG_KEEP_INTERVAL, DHCP_OPTION_INT32, 1, 1 , FALSE},\r
+ {DHCP_TAG_KEEP_GARBAGE, DHCP_OPTION_SWITCH, 1, 1 , FALSE},\r
+\r
+ {DHCP_TAG_NIS_DOMAIN, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_NIS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_NTP_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_VENDOR, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_NBNS, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_NBDD, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_NBTYPE, DHCP_OPTION_INT8, 1, 1 , FALSE},\r
+ {DHCP_TAG_NBSCOPE, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_XFONT, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_XDM, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+\r
+ {DHCP_TAG_REQUEST_IP, DHCP_OPTION_IP, 1, 1 , FALSE},\r
+ {DHCP_TAG_LEASE, DHCP_OPTION_INT32, 1, 1 , TRUE},\r
+ {DHCP_TAG_OVERLOAD, DHCP_OPTION_INT8, 1, 1 , TRUE},\r
+ {DHCP_TAG_TYPE, DHCP_OPTION_INT8, 1, 1 , TRUE},\r
+ {DHCP_TAG_SERVER_ID, DHCP_OPTION_IP, 1, 1 , TRUE},\r
+ {DHCP_TAG_PARA_LIST, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_MESSAGE, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_MAXMSG, DHCP_OPTION_INT16, 1, 1 , FALSE},\r
+ {DHCP_TAG_T1, DHCP_OPTION_INT32, 1, 1 , TRUE},\r
+ {DHCP_TAG_T2, DHCP_OPTION_INT32, 1, 1 , TRUE},\r
+ {DHCP_TAG_VENDOR_CLASS, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_CLIENT_ID, DHCP_OPTION_INT8, 2, -1 , FALSE},\r
+\r
+ {DHCP_TAG_NISPLUS, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_NISPLUS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+\r
+ {DHCP_TAG_TFTP, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+ {DHCP_TAG_BOOTFILE, DHCP_OPTION_INT8, 1, -1 , FALSE},\r
+\r
+ {DHCP_TAG_MOBILEIP, DHCP_OPTION_IP, 0, -1 , FALSE},\r
+ {DHCP_TAG_SMTP, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_POP3, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_NNTP, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_WWW, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_FINGER, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_IRC, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_STTALK, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+ {DHCP_TAG_STDA, DHCP_OPTION_IP, 1, -1 , FALSE},\r
+\r
+ {DHCP_TAG_CLASSLESS_ROUTE,DHCP_OPTION_INT8, 5, -1 , FALSE},\r
+};\r
+\r
+\r
+/**\r
+ Binary search the DhcpOptionFormats array to find the format\r
+ information about a specific option.\r
+\r
+ @param Tag The option's tag.\r
+\r
+ @return The point to the option's format, NULL if not found.\r
+\r
+**/\r
+STATIC\r
+DHCP_OPTION_FORMAT *\r
+DhcpFindOptionFormat (\r
+ IN UINT8 Tag\r
+ )\r
+{\r
+ INTN Left;\r
+ INTN Right;\r
+ INTN Middle;\r
+\r
+ Left = 0;\r
+ Right = sizeof (DhcpOptionFormats) / sizeof (DHCP_OPTION_FORMAT) - 1;\r
+\r
+ while (Right >= Left) {\r
+ Middle = (Left + Right) / 2;\r
+\r
+ if (Tag == DhcpOptionFormats[Middle].Tag) {\r
+ return &DhcpOptionFormats[Middle];\r
+ }\r
+\r
+ if (Tag < DhcpOptionFormats[Middle].Tag) {\r
+ Right = Middle - 1;\r
+ } else {\r
+ Left = Middle + 1;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Validate whether a single DHCP option is valid according to its format.\r
+\r
+ @param Format The option's format\r
+ @param OptValue The value of the option\r
+ @param Len The length of the option value\r
+\r
+ @return TRUE is the option is valid, otherwise FALSE.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+DhcpOptionIsValid (\r
+ IN DHCP_OPTION_FORMAT *Format,\r
+ IN UINT8 *OptValue,\r
+ IN INTN Len\r
+ )\r
+{\r
+ INTN Unit;\r
+ INTN Occur;\r
+ INTN Index;\r
+\r
+ Unit = 0;\r
+\r
+ switch (Format->Type) {\r
+ case DHCP_OPTION_SWITCH:\r
+ case DHCP_OPTION_INT8:\r
+ Unit = 1;\r
+ break;\r
+\r
+ case DHCP_OPTION_INT16:\r
+ Unit = 2;\r
+ break;\r
+\r
+ case DHCP_OPTION_INT32:\r
+ case DHCP_OPTION_IP:\r
+ Unit = 4;\r
+ break;\r
+\r
+ case DHCP_OPTION_IPPAIR:\r
+ Unit = 8;\r
+ break;\r
+ }\r
+\r
+ ASSERT (Unit != 0);\r
+\r
+ //\r
+ // Validate that the option appears in the full units.\r
+ //\r
+ if ((Len % Unit) != 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Validate the occurance of the option unit is with in [MinOccur, MaxOccur]\r
+ //\r
+ Occur = Len / Unit;\r
+\r
+ if (((Format->MinOccur != -1) && (Occur < Format->MinOccur)) ||\r
+ ((Format->MaxOccur != -1) && (Occur > Format->MaxOccur))) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // If the option is of type switch, only 0/1 are valid values.\r
+ //\r
+ if (Format->Type == DHCP_OPTION_SWITCH) {\r
+ for (Index = 0; Index < Occur; Index++) {\r
+ if ((OptValue[Index] != 0) && (OptValue[Index] != 1)) {\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Extract the client interested options, all the parameters are\r
+ converted to host byte order.\r
+\r
+ @param Tag The DHCP option tag\r
+ @param Len The length of the option\r
+ @param Data The value of the DHCP option\r
+ @param Para The variable to save the interested parameter\r
+\r
+ @retval EFI_SUCCESS The DHCP option is successfully extracted.\r
+ @retval EFI_INVALID_PARAMETER The DHCP option is mal-formated\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DhcpGetParameter (\r
+ IN UINT8 Tag,\r
+ IN INTN Len,\r
+ IN UINT8 *Data,\r
+ IN DHCP_PARAMETER *Para\r
+ )\r
+{\r
+ switch (Tag) {\r
+ case DHCP_TAG_NETMASK:\r
+ Para->NetMask = NetGetUint32 (Data);\r
+ break;\r
+\r
+ case DHCP_TAG_ROUTER:\r
+ //\r
+ // Return the first router to consumer which is the preferred one\r
+ //\r
+ Para->Router = NetGetUint32 (Data);\r
+ break;\r
+\r
+ case DHCP_TAG_LEASE:\r
+ Para->Lease = NetGetUint32 (Data);\r
+ break;\r
+\r
+ case DHCP_TAG_OVERLOAD:\r
+ Para->Overload = *Data;\r
+\r
+ if ((Para->Overload < 1) || (Para->Overload > 3)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ break;\r
+\r
+ case DHCP_TAG_TYPE:\r
+ Para->DhcpType = *Data;\r
+\r
+ if ((Para->DhcpType < 1) || (Para->DhcpType > 9)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ break;\r
+\r
+ case DHCP_TAG_SERVER_ID:\r
+ Para->ServerId = NetGetUint32 (Data);\r
+ break;\r
+\r
+ case DHCP_TAG_T1:\r
+ Para->T1 = NetGetUint32 (Data);\r
+ break;\r
+\r
+ case DHCP_TAG_T2:\r
+ Para->T2 = NetGetUint32 (Data);\r
+ break;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Inspect all the options in a single buffer. DHCP options may be contained\r
+ in several buffers, such as the BOOTP options filed, boot file or server\r
+ name. Each option buffer is required to end with DHCP_TAG_EOP.\r
+\r
+ @param Buffer The buffer which contains DHCP options\r
+ @param BufLen The length of the buffer\r
+ @param Check The callback function for each option found\r
+ @param Context The opaque parameter for the Check\r
+ @param Overload variable to save the value of DHCP_TAG_OVERLOAD\r
+ option.\r
+\r
+ @retval EFI_SUCCESS All the options are valid\r
+ @retval EFI_INVALID_PARAMETER The options are mal-formated.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DhcpIterateBufferOptions (\r
+ IN UINT8 *Buffer,\r
+ IN INTN BufLen,\r
+ IN DHCP_CHECK_OPTION Check, OPTIONAL\r
+ IN VOID *Context,\r
+ OUT UINT8 *Overload OPTIONAL\r
+ )\r
+{\r
+ INTN Cur;\r
+ UINT8 Tag;\r
+ UINT8 Len;\r
+\r
+ Cur = 0;\r
+\r
+ while (Cur < BufLen) {\r
+ Tag = Buffer[Cur];\r
+\r
+ if (Tag == DHCP_TAG_PAD) {\r
+ Cur++;\r
+ continue;\r
+ } else if (Tag == DHCP_TAG_EOP) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Cur++;\r
+\r
+ if (Cur == BufLen) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Len = Buffer[Cur++];\r
+\r
+ if (Cur + Len > BufLen) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Tag == DHCP_TAG_OVERLOAD) && (Overload != NULL)) {\r
+ if (Len != 1) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Overload = Buffer[Cur];\r
+ }\r
+\r
+ if ((Check != NULL) && EFI_ERROR (Check (Tag, Len, Buffer + Cur, Context))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Cur += Len;\r
+ }\r
+\r
+ //\r
+ // Each option buffer is expected to end with an EOP\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+\r
+/**\r
+ Iterate through a DHCP message to visit each option. First inspect\r
+ all the options in the OPTION field. Then if overloaded, inspect\r
+ the options in FILENAME and SERVERNAME fields. One option may be\r
+ encoded in several places. See RFC 3396 Encoding Long Options in DHCP\r
+\r
+ @param Packet The DHCP packet to check the options for\r
+ @param Check The callback function to be called for each option\r
+ found\r
+ @param Context The opaque parameter for Check\r
+\r
+ @retval EFI_SUCCESS The DHCP packet's options are well formated\r
+ @retval Others The DHCP packet's options are not well formated\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpIterateOptions (\r
+ IN EFI_DHCP4_PACKET *Packet,\r
+ IN DHCP_CHECK_OPTION Check, OPTIONAL\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Overload;\r
+\r
+ Overload = 0;\r
+\r
+ Status = DhcpIterateBufferOptions (\r
+ Packet->Dhcp4.Option,\r
+ Packet->Length - sizeof (EFI_DHCP4_HEADER) - sizeof (UINT32),\r
+ Check,\r
+ Context,\r
+ &Overload\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((Overload == DHCP_OVERLOAD_FILENAME) || (Overload == DHCP_OVERLOAD_BOTH)) {\r
+ Status = DhcpIterateBufferOptions (\r
+ Packet->Dhcp4.Header.BootFileName,\r
+ 128,\r
+ Check,\r
+ Context,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if ((Overload == DHCP_OVERLOAD_SVRNAME) || (Overload == DHCP_OVERLOAD_BOTH)) {\r
+ Status = DhcpIterateBufferOptions (\r
+ Packet->Dhcp4.Header.ServerName,\r
+ 64,\r
+ Check,\r
+ Context,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Call back function to DhcpiterateOptions to compute each option's\r
+ length. It just adds the data length of all the occurances of this\r
+ Tag. Context is an array of 256 DHCP_OPTION_COUNT.\r
+\r
+ @param Tag The current option to check\r
+ @param Len The length of the option data\r
+ @param Data The option data\r
+ @param Context The context, which is a array of 256\r
+ DHCP_OPTION_COUNT.\r
+\r
+ @retval EFI_SUCCESS It always returns EFI_SUCCESS.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DhcpGetOptionLen (\r
+ IN UINT8 Tag,\r
+ IN UINT8 Len,\r
+ IN UINT8 *Data,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ DHCP_OPTION_COUNT *OpCount;\r
+\r
+ OpCount = (DHCP_OPTION_COUNT *) Context;\r
+ OpCount[Tag].Offset = OpCount[Tag].Offset + Len;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Call back function to DhcpiterateOptions to consolidate each option's\r
+ data. There are maybe several occurance of the same option.\r
+\r
+ @param Tag The option to consolidate its data\r
+ @param Len The length of option data\r
+ @param Data The data of the option's current occurance\r
+ @param Context The context, which is DHCP_OPTION_CONTEXT. This\r
+ array is just a wrap to pass THREE parameters.\r
+\r
+ @retval EFI_SUCCESS It always returns EFI_SUCCESS\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DhcpFillOption (\r
+ IN UINT8 Tag,\r
+ IN UINT8 Len,\r
+ IN UINT8 *Data,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ DHCP_OPTION_CONTEXT *OptContext;\r
+ DHCP_OPTION_COUNT *OptCount;\r
+ DHCP_OPTION *Options;\r
+ UINT8 *Buf;\r
+ UINT8 Index;\r
+\r
+ OptContext = (DHCP_OPTION_CONTEXT *) Context;\r
+\r
+ OptCount = OptContext->OpCount;\r
+ Index = OptCount[Tag].Index;\r
+ Options = OptContext->Options;\r
+ Buf = OptContext->Buf;\r
+\r
+ if (Options[Index].Data == NULL) {\r
+ Options[Index].Tag = Tag;\r
+ Options[Index].Data = Buf + OptCount[Tag].Offset;\r
+ }\r
+\r
+ NetCopyMem (Buf + OptCount[Tag].Offset, Data, Len);\r
+\r
+ OptCount[Tag].Offset = OptCount[Tag].Offset + Len;\r
+ Options[Index].Len = Options[Index].Len + Len;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Parse the options of a DHCP packet. It supports RFC 3396: Encoding\r
+ Long Options in DHCP. That is, it will combine all the option value\r
+ of all the occurances of each option.\r
+ A little bit of implemenation:\r
+ It adopts the "Key indexed counting" algorithm. First, it allocates\r
+ an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded\r
+ as a UINT8. It then iterates the DHCP packet to get data length of\r
+ each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it\r
+ knows the number of present options and their length. It allocates a\r
+ array of DHCP_OPTION and a continous buffer after the array to put\r
+ all the options' data. Each option's data is pointed to by the Data\r
+ field in DHCP_OPTION structure. At last, it call DhcpIterateOptions\r
+ with DhcpFillOption to fill each option's data to its position in the\r
+ buffer.\r
+\r
+ @param Packet The DHCP packet to parse the options\r
+ @param Count The number of valid dhcp options present in the\r
+ packet\r
+ @param OptionPoint The array that contains the DHCP options. Caller\r
+ should free it.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to parse the packet.\r
+ @retval EFI_INVALID_PARAMETER The options are mal-formated\r
+ @retval EFI_SUCCESS The options are parsed into OptionPoint\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpParseOption (\r
+ IN EFI_DHCP4_PACKET *Packet,\r
+ OUT INTN *Count,\r
+ OUT DHCP_OPTION **OptionPoint\r
+ )\r
+{\r
+ DHCP_OPTION_CONTEXT Context;\r
+ DHCP_OPTION *Options;\r
+ DHCP_OPTION_COUNT *OptCount;\r
+ EFI_STATUS Status;\r
+ UINT16 TotalLen;\r
+ INTN OptNum;\r
+ INTN Index;\r
+\r
+ ASSERT ((Count != NULL) && (OptionPoint != NULL));\r
+\r
+ //\r
+ // First compute how many options and how long each option is\r
+ // with the "Key indexed counting" algorithms.\r
+ //\r
+ OptCount = NetAllocateZeroPool (DHCP_MAX_OPTIONS * sizeof (DHCP_OPTION_COUNT));\r
+\r
+ if (OptCount == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = DhcpIterateOptions (Packet, DhcpGetOptionLen, OptCount);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Before the loop, Offset is the length of the option. After loop,\r
+ // OptCount[Index].Offset specifies the offset into the continuous\r
+ // option value buffer to put the data.\r
+ //\r
+ TotalLen = 0;\r
+ OptNum = 0;\r
+\r
+ for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {\r
+ if (OptCount[Index].Offset != 0) {\r
+ OptCount[Index].Index = (UINT8) OptNum;\r
+\r
+ TotalLen = TotalLen + OptCount[Index].Offset;\r
+ OptCount[Index].Offset = TotalLen - OptCount[Index].Offset;\r
+\r
+ OptNum++;\r
+ }\r
+ }\r
+\r
+ *Count = OptNum;\r
+ *OptionPoint = NULL;\r
+\r
+ if (OptNum == 0) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Allocate a buffer to hold the DHCP options, and after that, a\r
+ // continuous buffer to put all the options' data.\r
+ //\r
+ Options = NetAllocateZeroPool (OptNum * sizeof (DHCP_OPTION) + TotalLen);\r
+\r
+ if (Options == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Context.OpCount = OptCount;\r
+ Context.Options = Options;\r
+ Context.Buf = (UINT8 *) (Options + OptNum);\r
+\r
+ Status = DhcpIterateOptions (Packet, DhcpFillOption, &Context);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetFreePool (Options);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ *OptionPoint = Options;\r
+\r
+ON_EXIT:\r
+ NetFreePool (OptCount);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Validate the packet's options. If necessary, allocate\r
+ and fill in the interested parameters.\r
+\r
+ @param Packet The packet to validate the options\r
+ @param Para The variable to save the DHCP parameters.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to validate the packet.\r
+ @retval EFI_INVALID_PARAMETER The options are mal-formated\r
+ @retval EFI_SUCCESS The options are parsed into OptionPoint\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpValidateOptions (\r
+ IN EFI_DHCP4_PACKET *Packet,\r
+ OUT DHCP_PARAMETER **Para OPTIONAL\r
+ )\r
+{\r
+ DHCP_PARAMETER Parameter;\r
+ DHCP_OPTION_FORMAT *Format;\r
+ DHCP_OPTION *AllOption;\r
+ DHCP_OPTION *Option;\r
+ EFI_STATUS Status;\r
+ BOOLEAN Updated;\r
+ INTN Count;\r
+ INTN Index;\r
+\r
+ if (Para != NULL) {\r
+ *Para = NULL;\r
+ }\r
+\r
+ AllOption = NULL;\r
+ Status = DhcpParseOption (Packet, &Count, &AllOption);\r
+\r
+ if (EFI_ERROR (Status) || (Count == 0)) {\r
+ return Status;\r
+ }\r
+\r
+ Updated = FALSE;\r
+ NetZeroMem (&Parameter, sizeof (Parameter));\r
+\r
+ for (Index = 0; Index < Count; Index++) {\r
+ Option = &AllOption[Index];\r
+\r
+ //\r
+ // Find the format of the option then validate it.\r
+ //\r
+ Format = DhcpFindOptionFormat (Option->Tag);\r
+\r
+ if (Format == NULL) {\r
+ continue;\r
+ }\r
+\r
+ if (!DhcpOptionIsValid (Format, Option->Data, Option->Len)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Get the client interested parameters\r
+ //\r
+ if (Format->Alert && (Para != NULL)) {\r
+ Updated = TRUE;\r
+ Status = DhcpGetParameter (Option->Tag, Option->Len, Option->Data, &Parameter);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Updated && (Para != NULL)) {\r
+ if ((*Para = NetAllocatePool (sizeof (DHCP_PARAMETER))) == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ CopyMem (*Para, &Parameter, sizeof (DHCP_PARAMETER));\r
+ }\r
+\r
+ON_EXIT:\r
+ NetFreePool (AllOption);\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Append an option to the memory, if the option is longer than\r
+ 255 bytes, splits it into several options.\r
+\r
+ @param Buf The buffer to append the option to\r
+ @param Tag The option's tag\r
+ @param DataLen The length of the option's data\r
+ @param Data The option's data\r
+\r
+ @return The position to append the next option\r
+\r
+**/\r
+UINT8 *\r
+DhcpAppendOption (\r
+ IN UINT8 *Buf,\r
+ IN UINT8 Tag,\r
+ IN UINT16 DataLen,\r
+ IN UINT8 *Data\r
+ )\r
+{\r
+ INTN Index;\r
+ INTN Len;\r
+\r
+ ASSERT (DataLen != 0);\r
+\r
+ for (Index = 0; Index < (DataLen + 254) / 255; Index++) {\r
+ Len = NET_MIN (255, DataLen - Index * 255);\r
+\r
+ *(Buf++) = Tag;\r
+ *(Buf++) = (UINT8) Len;\r
+ NetCopyMem (Buf, Data + Index * 255, Len);\r
+\r
+ Buf += Len;\r
+ }\r
+\r
+ return Buf;\r
+}\r
+\r
+\r
+/**\r
+ Build a new DHCP packet from a seed packet. Options may be deleted or\r
+ appended. The caller should free the NewPacket when finished using it.\r
+\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_OUT_OF_RESOURCES Failed to allocate memory\r
+ @retval EFI_SUCCESS The packet is build.\r
+\r
+**/\r
+EFI_STATUS\r
+DhcpBuild (\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
+ DHCP_OPTION *Mark;\r
+ DHCP_OPTION *SeedOptions;\r
+ EFI_DHCP4_PACKET *Packet;\r
+ EFI_STATUS Status;\r
+ INTN Count;\r
+ UINT32 Index;\r
+ UINT32 Len;\r
+ UINT8 *Buf;\r
+\r
+ //\r
+ // Use an array of DHCP_OPTION to mark the existance\r
+ // and position of each valid options.\r
+ //\r
+ Mark = NetAllocatePool (sizeof (DHCP_OPTION) * DHCP_MAX_OPTIONS);\r
+\r
+ if (Mark == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {\r
+ Mark[Index].Tag = (UINT8) Index;\r
+ Mark[Index].Len = 0;\r
+ }\r
+\r
+ //\r
+ // Get list of the options from the seed packet, then put\r
+ // them to the mark array according to their tags.\r
+ //\r
+ SeedOptions = NULL;\r
+ Status = DhcpParseOption (SeedPacket, &Count, &SeedOptions);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ for (Index = 0; Index < (UINT32) Count; Index++) {\r
+ Mark[SeedOptions[Index].Tag] = SeedOptions[Index];\r
+ }\r
+\r
+ //\r
+ // Mark the option's length is zero if it is in the DeleteList.\r
+ //\r
+ for (Index = 0; Index < DeleteCount; Index++) {\r
+ Mark[DeleteList[Index]].Len = 0;\r
+ }\r
+\r
+ //\r
+ // Add or replace the option if it is in the append list.\r
+ //\r
+ for (Index = 0; Index < AppendCount; Index++) {\r
+ Mark[AppendList[Index]->OpCode].Len = AppendList[Index]->Length;\r
+ Mark[AppendList[Index]->OpCode].Data = AppendList[Index]->Data;\r
+ }\r
+\r
+ //\r
+ // compute the new packet length. No need to add 1 byte for\r
+ // EOP option since EFI_DHCP4_PACKET includes one extra byte\r
+ // for option. It is necessary to split the option if it is\r
+ // longer than 255 bytes.\r
+ //\r
+ Len = sizeof (EFI_DHCP4_PACKET);\r
+\r
+ for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {\r
+ if (Mark[Index].Len != 0) {\r
+ Len += ((Mark[Index].Len + 254) / 255) * 2 + Mark[Index].Len;\r
+ }\r
+ }\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ Packet = (EFI_DHCP4_PACKET *) NetAllocatePool (Len);\r
+\r
+ if (Packet == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Packet->Size = Len;\r
+ Packet->Length = 0;\r
+ CopyMem (&Packet->Dhcp4.Header, &SeedPacket->Dhcp4.Header, sizeof (EFI_DHCP4_HEADER));\r
+ Packet->Dhcp4.Magik = DHCP_OPTION_MAGIC;\r
+ Buf = Packet->Dhcp4.Option;\r
+\r
+ for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {\r
+ if (Mark[Index].Len != 0) {\r
+ Buf = DhcpAppendOption (Buf, Mark[Index].Tag, Mark[Index].Len, Mark[Index].Data);\r
+ }\r
+ }\r
+\r
+ *(Buf++) = DHCP_TAG_EOP;\r
+ Packet->Length = sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)\r
+ + (UINT32) (Buf - Packet->Dhcp4.Option);\r
+\r
+ *NewPacket = Packet;\r
+ Status = EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ if (SeedOptions != NULL) {\r
+ NetFreePool (SeedOptions);\r
+ }\r
+\r
+ NetFreePool (Mark);\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Dhcp4Option.h
+
+Abstract:
+
+ To validate, parse and process the DHCP options
+
+
+**/
+
+#ifndef __EFI_DHCP4_OPTION_H__
+#define __EFI_DHCP4_OPTION_H__
+
+//
+// DHCP option tags (types)
+//
+enum {
+ //
+ // RFC1497 vendor extensions
+ //
+ DHCP_TAG_PAD = 0, // Pad Option
+ DHCP_TAG_EOP = 255, // End Option
+ DHCP_TAG_NETMASK = 1, // Subnet Mask
+ DHCP_TAG_TIME_OFFSET = 2, // Time Offset from UTC
+ DHCP_TAG_ROUTER = 3, // Router option,
+ DHCP_TAG_TIME_SERVER = 4, // Time Server
+ DHCP_TAG_NAME_SERVER = 5, // Name Server
+ DHCP_TAG_DNS_SERVER = 6, // Domain Name Server
+ DHCP_TAG_LOG_SERVER = 7, // Log Server
+ DHCP_TAG_COOKIE_SERVER = 8, // Cookie Server
+ DHCP_TAG_LPR_SERVER = 9, // LPR Print Server
+ DHCP_TAG_IMPRESS_SERVER = 10, // Impress Server
+ DHCP_TAG_RL_SERVER = 11, // Resource Location Server
+ DHCP_TAG_HOSTNAME = 12, // Host Name
+ DHCP_TAG_BOOTFILE_LEN = 13, // Boot File Size
+ DHCP_TAG_DUMP = 14, // Merit Dump File
+ DHCP_TAG_DOMAINNAME = 15, // Domain Name
+ DHCP_TAG_SWAP_SERVER = 16, // Swap Server
+ DHCP_TAG_ROOTPATH = 17, // Root path
+ DHCP_TAG_EXTEND_PATH = 18, // Extensions Path
+
+ //
+ // IP Layer Parameters per Host
+ //
+ DHCP_TAG_IPFORWARD = 19, // IP Forwarding Enable/Disable
+ DHCP_TAG_NONLOCAL_SRR = 20, // on-Local Source Routing Enable/Disable
+ DHCP_TAG_POLICY_SRR = 21, // Policy Filter
+ DHCP_TAG_EMTU = 22, // Maximum Datagram Reassembly Size
+ DHCP_TAG_TTL = 23, // Default IP Time-to-live
+ DHCP_TAG_PATHMTU_AGE = 24, // Path MTU Aging Timeout
+ DHCP_TAG_PATHMTU_PLATEAU = 25, // Path MTU Plateau Table
+
+ //
+ // IP Layer Parameters per Interface
+ //
+ DHCP_TAG_IFMTU = 26, // Interface MTU
+ DHCP_TAG_SUBNET_LOCAL = 27, // All Subnets are Local
+ DHCP_TAG_BROADCAST = 28, // Broadcast Address
+ DHCP_TAG_DISCOVER_MASK = 29, // Perform Mask Discovery
+ DHCP_TAG_SUPPLY_MASK = 30, // Mask Supplier
+ DHCP_TAG_DISCOVER_ROUTE = 31, // Perform Router Discovery
+ DHCP_TAG_ROUTER_SOLICIT = 32, // Router Solicitation Address
+ DHCP_TAG_STATIC_ROUTE = 33, // Static Route
+
+ //
+ // Link Layer Parameters per Interface
+ //
+ DHCP_TAG_TRAILER = 34, // Trailer Encapsulation
+ DHCP_TAG_ARPAGE = 35, // ARP Cache Timeout
+ DHCP_TAG_ETHER_ENCAP = 36, // Ethernet Encapsulation
+
+ //
+ // TCP Parameters
+ //
+ DHCP_TAG_TCP_TTL = 37, // TCP Default TTL
+ DHCP_TAG_KEEP_INTERVAL = 38, // TCP Keepalive Interval
+ DHCP_TAG_KEEP_GARBAGE = 39, // TCP Keepalive Garbage
+
+ //
+ // Application and Service Parameters
+ //
+ DHCP_TAG_NIS_DOMAIN = 40, // Network Information Service Domain
+ DHCP_TAG_NIS_SERVER = 41, // Network Information Servers
+ DHCP_TAG_NTP_SERVER = 42, // Network Time Protocol Servers
+ DHCP_TAG_VENDOR = 43, // Vendor Specific Information
+ DHCP_TAG_NBNS = 44, // NetBIOS over TCP/IP Name Server
+ DHCP_TAG_NBDD = 45, // NetBIOS Datagram Distribution Server
+ DHCP_TAG_NBTYPE = 46, // NetBIOS over TCP/IP Node Type
+ DHCP_TAG_NBSCOPE = 47, // NetBIOS over TCP/IP Scope
+ DHCP_TAG_XFONT = 48, // X Window System Font Server
+ DHCP_TAG_XDM = 49, // X Window System Display Manager
+ DHCP_TAG_NISPLUS = 64, // Network Information Service+ Domain
+ DHCP_TAG_NISPLUS_SERVER = 65, // Network Information Service+ Servers
+ DHCP_TAG_MOBILEIP = 68, // Mobile IP Home Agent
+ DHCP_TAG_SMTP = 69, // Simple Mail Transport Protocol Server
+ DHCP_TAG_POP3 = 70, // Post Office Protocol (POP3) Server
+ DHCP_TAG_NNTP = 71, // Network News Transport Protocol Server
+ DHCP_TAG_WWW = 72, // Default World Wide Web (WWW) Server
+ DHCP_TAG_FINGER = 73, // Default Finger Server
+ DHCP_TAG_IRC = 74, // Default Internet Relay Chat (IRC) Server
+ DHCP_TAG_STTALK = 75, // StreetTalk Server
+ DHCP_TAG_STDA = 76, // StreetTalk Directory Assistance Server
+ DHCP_TAG_CLASSLESS_ROUTE = 121, // Classless Route
+
+ //
+ // DHCP Extensions
+ //
+ DHCP_TAG_REQUEST_IP = 50, // Requested IP Address
+ DHCP_TAG_LEASE = 51, // IP Address Lease Time
+ DHCP_TAG_OVERLOAD = 52, // Option Overload
+ DHCP_TAG_TFTP = 66, // TFTP server name
+ DHCP_TAG_BOOTFILE = 67, // Bootfile name
+ DHCP_TAG_TYPE = 53, // DHCP Message Type
+ DHCP_TAG_SERVER_ID = 54, // Server Identifier
+ DHCP_TAG_PARA_LIST = 55, // Parameter Request List
+ DHCP_TAG_MESSAGE = 56, // Message
+ DHCP_TAG_MAXMSG = 57, // Maximum DHCP Message Size
+ DHCP_TAG_T1 = 58, // Renewal (T1) Time Value
+ DHCP_TAG_T2 = 59, // Rebinding (T2) Time Value
+ DHCP_TAG_VENDOR_CLASS = 60, // Vendor class identifier
+ DHCP_TAG_CLIENT_ID = 61, // Client-identifier
+};
+
+enum {
+ DHCP_OPTION_MAGIC = 0x63538263, // Network byte order
+ DHCP_MAX_OPTIONS = 256,
+
+ //
+ // DHCP option types, this is used to validate the DHCP options.
+ //
+ DHCP_OPTION_SWITCH = 1,
+ DHCP_OPTION_INT8,
+ DHCP_OPTION_INT16,
+ DHCP_OPTION_INT32,
+ DHCP_OPTION_IP,
+ DHCP_OPTION_IPPAIR,
+
+ //
+ // Value of DHCP overload option
+ //
+ DHCP_OVERLOAD_FILENAME = 1,
+ DHCP_OVERLOAD_SVRNAME = 2,
+ DHCP_OVERLOAD_BOTH = 3,
+};
+
+//
+// The DHCP option structure. This structure extends the EFI_DHCP_OPTION
+// structure to support options longer than 255 bytes, such as classless route.
+//
+typedef struct {
+ UINT8 Tag;
+ UINT16 Len;
+ UINT8 *Data;
+} DHCP_OPTION;
+
+//
+// Structures used to parse the DHCP options with RFC3396 support.
+//
+typedef struct {
+ UINT8 Index;
+ UINT16 Offset;
+} DHCP_OPTION_COUNT;
+
+typedef struct {
+ DHCP_OPTION_COUNT *OpCount;
+ DHCP_OPTION *Options;
+ UINT8 *Buf;
+} DHCP_OPTION_CONTEXT;
+
+//
+// The options that matters to DHCP driver itself. The user of
+// DHCP clients may be interested in other options, such as
+// classless route, who can parse the DHCP offer to get them.
+//
+typedef struct {
+ IP4_ADDR NetMask; // DHCP_TAG_NETMASK
+ IP4_ADDR Router; // DHCP_TAG_ROUTER, only the first router is used
+
+ //
+ // DHCP specific options
+ //
+ UINT8 DhcpType; // DHCP_TAG_TYPE
+ UINT8 Overload; // DHCP_TAG_OVERLOAD
+ IP4_ADDR ServerId; // DHCP_TAG_SERVER_ID
+ UINT32 Lease; // DHCP_TAG_LEASE
+ UINT32 T1; // DHCP_TAG_T1
+ UINT32 T2; // DHCP_TAG_T2
+} DHCP_PARAMETER;
+
+//
+// Structure used to describe and validate the format of DHCP options.
+// Type is the options' data type, such as DHCP_OPTION_INT8. MinOccur
+// is the minium occurance of this data type. MaxOccur is defined
+// similarly. If MaxOccur is -1, it means that there is no limit on the
+// maximum occurance. Alert tells whether DHCP client should further
+// inspect the option to parse DHCP_PARAMETER.
+//
+typedef struct {
+ UINT8 Tag;
+ INTN Type;
+ INTN MinOccur;
+ INTN MaxOccur;
+ BOOLEAN Alert;
+} DHCP_OPTION_FORMAT;
+
+typedef
+EFI_STATUS
+(*DHCP_CHECK_OPTION) (
+ IN UINT8 Tag,
+ IN UINT8 Len,
+ IN UINT8 *Data,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+DhcpIterateOptions (
+ IN EFI_DHCP4_PACKET *Packet,
+ IN DHCP_CHECK_OPTION Check, OPTIONAL
+ IN VOID *Context
+ );
+
+EFI_STATUS
+DhcpValidateOptions (
+ IN EFI_DHCP4_PACKET *Packet,
+ OUT DHCP_PARAMETER **Para OPTIONAL
+ );
+
+EFI_STATUS
+DhcpParseOption (
+ IN EFI_DHCP4_PACKET *Packet,
+ OUT INTN *Count,
+ OUT DHCP_OPTION **OptionPoint
+ );
+
+UINT8 *
+DhcpAppendOption (
+ IN UINT8 *Buf,
+ IN UINT8 Tag,
+ IN UINT16 DataLen,
+ IN UINT8 *Data
+ );
+
+EFI_STATUS
+DhcpBuild (
+ IN EFI_DHCP4_PACKET *SeedPacket,
+ IN UINT32 DeleteCount,
+ IN UINT8 *DeleteList OPTIONAL,
+ IN UINT32 AppendCount,
+ IN EFI_DHCP4_PACKET_OPTION *AppendList[] OPTIONAL,
+ OUT EFI_DHCP4_PACKET **NewPacket
+ );
+
+#endif
EFI_STATUS Status;\r
BOOLEAN Perment;\r
IP4_ADDR Subnet;\r
+ IP4_ADDR Ip1;\r
+ IP4_ADDR Ip2;\r
\r
Instance = (IP4_CONFIG_INSTANCE *) Context;\r
ASSERT (Instance->Dhcp4 != NULL);\r
//\r
Ip4Config->RouteTableSize = 1;\r
\r
- Subnet = EFI_NTOHL (Dhcp4Mode.ClientAddress) & EFI_NTOHL (Dhcp4Mode.SubnetMask);\r
+ NetCopyMem (&Ip1, &Dhcp4Mode.ClientAddress, sizeof (IP4_ADDR));\r
+ NetCopyMem (&Ip2, &Dhcp4Mode.SubnetMask, sizeof (IP4_ADDR));\r
+ \r
+ Subnet = Ip1 & Ip2;\r
\r
- EFI_IP4 (Ip4Config->RouteTable[0].SubnetAddress) = HTONL (Subnet);\r
- Ip4Config->RouteTable[0].SubnetMask = Dhcp4Mode.SubnetMask;\r
- EFI_IP4 (Ip4Config->RouteTable[0].GatewayAddress) = 0;\r
+ NetCopyMem (&Ip4Config->RouteTable[0].SubnetAddress, &Subnet, sizeof (EFI_IPv4_ADDRESS));\r
+ NetCopyMem (&Ip4Config->RouteTable[0].SubnetMask, &Dhcp4Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+ NetZeroMem (&Ip4Config->RouteTable[0].GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
\r
//\r
// Create a route if there is a default router.\r
//\r
- if (EFI_IP4 (Dhcp4Mode.RouterAddress) != 0) {\r
- Ip4Config->RouteTableSize = 2;\r
- EFI_IP4 (Ip4Config->RouteTable[1].SubnetAddress) = 0;\r
- EFI_IP4 (Ip4Config->RouteTable[1].SubnetMask) = 0;\r
- Ip4Config->RouteTable[1].GatewayAddress = Dhcp4Mode.RouterAddress;\r
+ if (!EFI_IP4_EQUAL (Dhcp4Mode.RouterAddress, mZeroIp4Addr)) {\r
+ Ip4Config->RouteTableSize = 2;\r
+\r
+ NetZeroMem (&Ip4Config->RouteTable[1].SubnetAddress, sizeof (EFI_IPv4_ADDRESS));\r
+ NetZeroMem (&Ip4Config->RouteTable[1].SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+ NetCopyMem (&Ip4Config->RouteTable[1].GatewayAddress, &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
}\r
\r
Instance->Result = EFI_SUCCESS;\r
return NetLibDefaultUnload (ImageHandle);\r
}\r
\r
-//@MT: EFI_DRIVER_ENTRY_POINT (Ip4ConfigDriverEntryPoint)\r
\r
EFI_STATUS\r
Ip4ConfigDriverEntryPoint (\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+Ip4ComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Ip4ComponentNameGetControllerName (\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 gIp4ComponentName = {\r
+ Ip4ComponentNameGetDriverName,\r
+ Ip4ComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mIp4DriverNameTable[] = {\r
+ {\r
+ "eng",\r
+ L"IP4 Network Service Driver"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Ip4ComponentNameGetDriverName (\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\r
+ 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\r
+ identifier. This is the language of the driver name\r
+ that that the caller is requesting, and it must match\r
+ one of the languages specified in SupportedLanguages.\r
+ The number of languages supported by a driver is up to\r
+ the driver writer.\r
+ DriverName - A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the driver specified by This in the\r
+ language specified by Language.\r
+\r
+ Returns:\r
+ 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
+ gIp4ComponentName.SupportedLanguages,\r
+ mIp4DriverNameTable,\r
+ DriverName\r
+ );\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Ip4ComponentNameGetControllerName (\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\r
+ the controller 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 is not NULL and it is not\r
+ 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
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Ip4Common.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+\r
+/**\r
+ Return the cast type (Unicast/Boradcast) specific to a\r
+ interface. All the addresses are host byte ordered.\r
+\r
+ @param IpAddr The IP address to classify in host byte order\r
+ @param IpIf The interface that IpAddr received from\r
+\r
+ @return The cast type of this IP address specific to the interface.\r
+ @retval IP4_LOCAL_HOST The IpAddr equals to the interface's address\r
+ @retval IP4_SUBNET_BROADCAST The IpAddr is a directed subnet boradcast to the\r
+ interface\r
+ @retval IP4_NET_BROADCAST The IpAddr is a network broadcast to the interface\r
+\r
+**/\r
+INTN\r
+Ip4GetNetCast (\r
+ IN IP4_ADDR IpAddr,\r
+ IN IP4_INTERFACE *IpIf\r
+ )\r
+{\r
+ if (IpAddr == IpIf->Ip) {\r
+ return IP4_LOCAL_HOST;\r
+\r
+ } else if (IpAddr == IpIf->SubnetBrdcast) {\r
+ return IP4_SUBNET_BROADCAST;\r
+\r
+ } else if (IpAddr == IpIf->NetBrdcast) {\r
+ return IP4_NET_BROADCAST;\r
+\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ Find the cast type of the packet related to the local host.\r
+ This isn't the same as link layer cast type. For example, DHCP\r
+ server may send local broadcast to the local unicast MAC.\r
+\r
+ @param IpSb The IP4 service binding instance that received the\r
+ packet\r
+ @param Dst The destination address in the packet (host byte\r
+ order)\r
+ @param Src The source address in the packet (host byte order)\r
+\r
+ @return The cast type for the Dst, it will return on the first non-promiscuous\r
+ @return cast type to a configured interface. If the packet doesn't match any of\r
+ @return the interface, multicast address and local broadcast address are checked.\r
+\r
+**/\r
+INTN\r
+Ip4GetHostCast (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Dst,\r
+ IN IP4_ADDR Src\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_INTERFACE *IpIf;\r
+ INTN Type;\r
+ INTN Class;\r
+\r
+ Type = 0;\r
+\r
+ if (IpSb->MnpConfigData.EnablePromiscuousReceive) {\r
+ Type = IP4_PROMISCUOUS;\r
+ }\r
+\r
+ //\r
+ // Go through the interface list of the IP service, most likely.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ //\r
+ // Skip the unconfigured interface and invalid source address:\r
+ // source address can't be broadcast.\r
+ //\r
+ if (!IpIf->Configured || IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {\r
+ continue;\r
+ }\r
+\r
+ if ((Class = Ip4GetNetCast (Dst, IpIf)) > Type) {\r
+ return Class;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If it is local broadcast address. The source address must\r
+ // be a unicast address on one of the direct connected network.\r
+ // If it is a multicast address, accept it only if we are in\r
+ // the group.\r
+ //\r
+ if (Dst == IP4_ALLONE_ADDRESS) {\r
+ IpIf = Ip4FindNet (IpSb, Src);\r
+\r
+ if (IpIf && !IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {\r
+ return IP4_LOCAL_BROADCAST;\r
+ }\r
+\r
+ } else if (IP4_IS_MULTICAST (Dst) && Ip4FindGroup (&IpSb->IgmpCtrl, Dst)) {\r
+ return IP4_MULTICAST;\r
+ }\r
+\r
+ return Type;\r
+}\r
+\r
+\r
+/**\r
+ Find an interface whose configured IP address is Ip\r
+\r
+ @param IpSb The IP4 service binding instance\r
+ @param Ip The Ip address (host byte order) to find\r
+\r
+ @return The IP4_INTERFACE point if found, otherwise NULL\r
+\r
+**/\r
+IP4_INTERFACE *\r
+Ip4FindInterface (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Ip\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_INTERFACE *IpIf;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ if (IpIf->Configured && (IpIf->Ip == Ip)) {\r
+ return IpIf;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Find an interface that Ip is on that connected network.\r
+\r
+ @param IpSb The IP4 service binding instance\r
+ @param Ip The Ip address (host byte order) to find\r
+\r
+ @return The IP4_INTERFACE point if found, otherwise NULL\r
+\r
+**/\r
+IP4_INTERFACE *\r
+Ip4FindNet (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Ip\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_INTERFACE *IpIf;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ if (IpIf->Configured && IP4_NET_EQUAL (Ip, IpIf->Ip, IpIf->SubnetMask)) {\r
+ return IpIf;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Find an interface of the service with the same Ip/Netmask pair.\r
+\r
+ @param IpSb Ip4 service binding instance\r
+ @param Ip The Ip adress to find (host byte order)\r
+ @param Netmask The network to find (host byte order)\r
+\r
+ @return The IP4_INTERFACE point if found, otherwise NULL\r
+\r
+**/\r
+IP4_INTERFACE *\r
+Ip4FindStationAddress (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Ip,\r
+ IN IP4_ADDR Netmask\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_INTERFACE *IpIf;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ if (IpIf->Configured && (IpIf->Ip == Ip) && (IpIf->SubnetMask == Netmask)) {\r
+ return IpIf;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Get the MAC address for a multicast IP address. Call\r
+ Mnp's McastIpToMac to find the MAC address in stead of\r
+ hard code the NIC to be Ethernet.\r
+\r
+ @param Mnp The Mnp instance to get the MAC address.\r
+ @param Multicast The multicast IP address to translate.\r
+ @param Mac The buffer to hold the translated address.\r
+\r
+ @return Returns EFI_SUCCESS if the multicast IP is successfully\r
+ @return translated to a multicast MAC address. Otherwise some error.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4GetMulticastMac (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,\r
+ IN IP4_ADDR Multicast,\r
+ OUT EFI_MAC_ADDRESS *Mac\r
+ )\r
+{\r
+ EFI_IP_ADDRESS EfiIp;\r
+\r
+ EFI_IP4 (EfiIp.v4) = HTONL (Multicast);\r
+ return Mnp->McastIpToMac (Mnp, FALSE, &EfiIp, Mac);\r
+}\r
+\r
+\r
+/**\r
+ Convert the multibyte field in IP header's byter order.\r
+ In spite of its name, it can also be used to convert from\r
+ host to network byte order.\r
+\r
+ @param Head The IP head to convert\r
+\r
+ @return Point to the converted IP head\r
+\r
+**/\r
+IP4_HEAD *\r
+Ip4NtohHead (\r
+ IN IP4_HEAD *Head\r
+ )\r
+{\r
+ Head->TotalLen = NTOHS (Head->TotalLen);\r
+ Head->Id = NTOHS (Head->Id);\r
+ Head->Fragment = NTOHS (Head->Fragment);\r
+ Head->Src = NTOHL (Head->Src);\r
+ Head->Dst = NTOHL (Head->Dst);\r
+\r
+ return Head;\r
+}\r
+\r
+\r
+/**\r
+ Set the Ip4 variable data.\r
+\r
+ @param IpSb Ip4 service binding instance\r
+\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.\r
+ @retval other Set variable failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4SetVariableData (\r
+ IN IP4_SERVICE *IpSb\r
+ )\r
+{\r
+ UINT32 NumConfiguredInstance;\r
+ NET_LIST_ENTRY *Entry;\r
+ UINTN VariableDataSize;\r
+ EFI_IP4_VARIABLE_DATA *Ip4VariableData;\r
+ EFI_IP4_ADDRESS_PAIR *Ip4AddressPair;\r
+ IP4_PROTOCOL *IpInstance;\r
+ CHAR16 *NewMacString;\r
+ EFI_STATUS Status;\r
+\r
+ NumConfiguredInstance = 0;\r
+\r
+ //\r
+ // Go through the children list to count the configured children.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Children) {\r
+ IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);\r
+\r
+ if (IpInstance->State == IP4_STATE_CONFIGED) {\r
+ NumConfiguredInstance++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Calculate the size of the Ip4VariableData. As there may be no IP child,\r
+ // we should add extra buffer for the address paris only if the number of configured\r
+ // children is more than 1.\r
+ //\r
+ VariableDataSize = sizeof (EFI_IP4_VARIABLE_DATA);\r
+\r
+ if (NumConfiguredInstance > 1) {\r
+ VariableDataSize += sizeof (EFI_IP4_ADDRESS_PAIR) * (NumConfiguredInstance - 1);\r
+ }\r
+\r
+ Ip4VariableData = NetAllocatePool (VariableDataSize);\r
+ if (Ip4VariableData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Ip4VariableData->DriverHandle = IpSb->Image;\r
+ Ip4VariableData->AddressCount = NumConfiguredInstance;\r
+\r
+ Ip4AddressPair = &Ip4VariableData->AddressPairs[0];\r
+\r
+ //\r
+ // Go through the children list to fill the configured children's address pairs.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Children) {\r
+ IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);\r
+\r
+ if (IpInstance->State == IP4_STATE_CONFIGED) {\r
+ Ip4AddressPair->InstanceHandle = IpInstance->Handle;\r
+ EFI_IP4 (Ip4AddressPair->Ip4Address) = NTOHL (IpInstance->Interface->Ip);\r
+ EFI_IP4 (Ip4AddressPair->SubnetMask) = NTOHL (IpInstance->Interface->SubnetMask);\r
+\r
+ Ip4AddressPair++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get the mac string.\r
+ //\r
+ Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &NewMacString);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ if (IpSb->MacString != NULL) {\r
+ //\r
+ // The variable is set already, we're going to update it.\r
+ //\r
+ if (StrCmp (IpSb->MacString, NewMacString) != 0) {\r
+ //\r
+ // The mac address is changed, delete the previous variable first.\r
+ //\r
+ gRT->SetVariable (\r
+ IpSb->MacString,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ NetFreePool (IpSb->MacString);\r
+ }\r
+\r
+ IpSb->MacString = NewMacString;\r
+\r
+ Status = gRT->SetVariable (\r
+ IpSb->MacString,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ VariableDataSize,\r
+ (VOID *) Ip4VariableData\r
+ );\r
+\r
+ON_ERROR:\r
+\r
+ NetFreePool (Ip4VariableData);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Clear the variable and free the resource.\r
+\r
+ @param IpSb Ip4 service binding instance\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+Ip4ClearVariableData (\r
+ IN IP4_SERVICE *IpSb\r
+ )\r
+{\r
+ ASSERT (IpSb->MacString != NULL);\r
+\r
+ gRT->SetVariable (\r
+ IpSb->MacString,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ NetFreePool (IpSb->MacString);\r
+ IpSb->MacString = NULL;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Ip4Common.h
+
+Abstract:
+
+ Common definition for IP4.
+
+
+**/
+
+#ifndef __EFI_IP4_COMMON_H__
+#define __EFI_IP4_COMMON_H__
+
+typedef struct _IP4_INTERFACE IP4_INTERFACE;
+typedef struct _IP4_PROTOCOL IP4_PROTOCOL;
+typedef struct _IP4_SERVICE IP4_SERVICE;
+
+
+enum {
+ IP4_ETHER_PROTO = 0x0800,
+
+ IP4_PROTO_ICMP = 0x01,
+ IP4_PROTO_IGMP = 0x02,
+
+ //
+ // The packet is received as link level broadcast/multicast/promiscuous.
+ //
+ IP4_LINK_BROADCAST = 0x00000001,
+ IP4_LINK_MULTICAST = 0x00000002,
+ IP4_LINK_PROMISC = 0x00000004,
+
+ //
+ // IP4 address cast type classfication. Keep it true that any
+ // type bigger than or equal to LOCAL_BROADCAST is broadcast.
+ //
+ IP4_PROMISCUOUS = 1,
+ IP4_LOCAL_HOST,
+ IP4_MULTICAST,
+ IP4_LOCAL_BROADCAST, // Destination is 255.255.255.255
+ IP4_SUBNET_BROADCAST,
+ IP4_NET_BROADCAST,
+
+ //
+ // IP4 header flags
+ //
+ IP4_HEAD_DF_MASK = 0x4000,
+ IP4_HEAD_MF_MASK = 0x2000,
+ IP4_HEAD_OFFSET_MASK = 0x1fff,
+};
+
+#define IP4_ALLZERO_ADDRESS 0x00000000u
+#define IP4_ALLONE_ADDRESS 0xFFFFFFFFu
+#define IP4_ALLSYSTEM_ADDRESS 0xE0000001u
+#define IP4_ALLROUTER_ADDRESS 0xE0000002u
+
+//
+// Compose the fragment field to be used in the IP4 header.
+//
+#define IP4_HEAD_FRAGMENT_FIELD(Df, Mf, Offset) \
+ ((UINT16)(((Df) ? 0x4000 : 0) | ((Mf) ? 0x2000 : 0) | (((Offset) >> 3) & 0x1fff)))
+
+#define IP4_LAST_FRAGMENT(FragmentField) \
+ (((FragmentField) & IP4_HEAD_MF_MASK) == 0)
+
+#define IP4_FIRST_FRAGMENT(FragmentField) \
+ ((BOOLEAN)(((FragmentField) & IP4_HEAD_OFFSET_MASK) == 0))
+
+#define IP4_IS_BROADCAST(CastType) ((CastType) >= IP4_LOCAL_BROADCAST)
+
+//
+// Conver the Microsecond to second. IP transmit/receive time is
+// in the unit of microsecond. IP ticks once per second.
+//
+#define IP4_US_TO_SEC(Us) (((Us) + 999999) / 1000000)
+
+INTN
+Ip4GetNetCast (
+ IN IP4_ADDR IpAddr,
+ IN IP4_INTERFACE *IpIf
+ );
+
+INTN
+Ip4GetHostCast (
+ IN IP4_SERVICE *IpSb,
+ IN IP4_ADDR Dst,
+ IN IP4_ADDR Src
+ );
+
+IP4_INTERFACE *
+Ip4FindInterface (
+ IN IP4_SERVICE *IpService,
+ IN IP4_ADDR Addr
+ );
+
+IP4_INTERFACE *
+Ip4FindNet (
+ IN IP4_SERVICE *IpService,
+ IN IP4_ADDR Addr
+ );
+
+IP4_INTERFACE *
+Ip4FindStationAddress (
+ IN IP4_SERVICE *IpSb,
+ IN IP4_ADDR Ip,
+ IN IP4_ADDR Netmask
+ );
+
+EFI_STATUS
+Ip4GetMulticastMac (
+ IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
+ IN IP4_ADDR Multicast,
+ OUT EFI_MAC_ADDRESS *Mac
+ );
+
+IP4_HEAD *
+Ip4NtohHead (
+ IN IP4_HEAD *Head
+ );
+
+EFI_STATUS
+Ip4SetVariableData (
+ IN IP4_SERVICE *IpSb
+ );
+
+VOID
+Ip4ClearVariableData (
+ IN IP4_SERVICE *IpSb
+ );
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Ip4Driver.c\r
+\r
+Abstract:\r
+\r
+ The driver binding and service binding protocol for IP4 driver.\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gIp4DriverBinding = {\r
+ Ip4DriverBindingSupported,\r
+ Ip4DriverBindingStart,\r
+ Ip4DriverBindingStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (Ip4DriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Ip4DriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The entry point for IP4 driver which install the driver\r
+ binding and component name protocol on its image.\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\r
+ are successfully installed, otherwise if failed.\r
+\r
+--*/\r
+{\r
+ return NetLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gIp4DriverBinding,\r
+ ImageHandle,\r
+ &gIp4ComponentName,\r
+ NULL,\r
+ NULL\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
+Ip4DriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Test for the MNP service binding Protocol\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
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Test for the Arp service binding Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiArpServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+Ip4CleanService (\r
+ IN IP4_SERVICE *IpSb\r
+ );\r
+\r
+\r
+/**\r
+ Create a new IP4 driver service binding protocol\r
+\r
+ @param Controller The controller that has MNP service binding\r
+ installed\r
+ @param ImageHandle The IP4 driver's image handle\r
+ @param Service The variable to receive the newly created IP4\r
+ service.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource\r
+ @retval EFI_SUCCESS A new IP4 service binding private is created.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Ip4CreateService (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_HANDLE ImageHandle,\r
+ OUT IP4_SERVICE **Service\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Service != NULL);\r
+\r
+ *Service = NULL;\r
+\r
+ //\r
+ // allocate a service private data then initialize all the filed to\r
+ // empty resources, so if any thing goes wrong when allocating\r
+ // resources, Ip4CleanService can be called to clean it up.\r
+ //\r
+ IpSb = NetAllocatePool (sizeof (IP4_SERVICE));\r
+\r
+ if (IpSb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ IpSb->Signature = IP4_SERVICE_SIGNATURE;\r
+ IpSb->ServiceBinding.CreateChild = Ip4ServiceBindingCreateChild;\r
+ IpSb->ServiceBinding.DestroyChild = Ip4ServiceBindingDestroyChild;\r
+ IpSb->State = IP4_SERVICE_UNSTARTED;\r
+ IpSb->InDestory = FALSE;\r
+\r
+ IpSb->NumChildren = 0;\r
+ NetListInit (&IpSb->Children);\r
+\r
+ NetListInit (&IpSb->Interfaces);\r
+ IpSb->DefaultInterface = NULL;\r
+ IpSb->DefaultRouteTable = NULL;\r
+\r
+ Ip4InitAssembleTable (&IpSb->Assemble);\r
+\r
+ IpSb->IgmpCtrl.Igmpv1QuerySeen = 0;\r
+ NetListInit (&IpSb->IgmpCtrl.Groups);\r
+\r
+ IpSb->Image = ImageHandle;\r
+ IpSb->Controller = Controller;\r
+\r
+ IpSb->MnpChildHandle = NULL;\r
+ IpSb->Mnp = NULL;\r
+\r
+ IpSb->MnpConfigData.ReceivedQueueTimeoutValue = 0;\r
+ IpSb->MnpConfigData.TransmitQueueTimeoutValue = 0;\r
+ IpSb->MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO;\r
+ IpSb->MnpConfigData.EnableUnicastReceive = TRUE;\r
+ IpSb->MnpConfigData.EnableMulticastReceive = TRUE;\r
+ IpSb->MnpConfigData.EnableBroadcastReceive = TRUE;\r
+ IpSb->MnpConfigData.EnablePromiscuousReceive = FALSE;\r
+ IpSb->MnpConfigData.FlushQueuesOnReset = TRUE;\r
+ IpSb->MnpConfigData.EnableReceiveTimestamps = FALSE;\r
+ IpSb->MnpConfigData.DisableBackgroundPolling = FALSE;\r
+\r
+ NetZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));\r
+\r
+ IpSb->Timer = NULL;\r
+ IpSb->Ip4Config = NULL;\r
+ IpSb->DoneEvent = NULL;\r
+ IpSb->ReconfigEvent = NULL;\r
+\r
+ //\r
+ // Create various resources. First create the route table, timer\r
+ // event and MNP child. IGMP, interface's initialization depend\r
+ // on the MNP child.\r
+ //\r
+ IpSb->DefaultRouteTable = Ip4CreateRouteTable ();\r
+\r
+ if (IpSb->DefaultRouteTable == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ Ip4TimerTicking,\r
+ IpSb,\r
+ &IpSb->Timer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = NetLibCreateServiceChild (\r
+ Controller,\r
+ ImageHandle,\r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ &IpSb->MnpChildHandle\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ IpSb->MnpChildHandle,\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ (VOID **) &IpSb->Mnp,\r
+ ImageHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = Ip4ServiceConfigMnp (IpSb, TRUE);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = Ip4InitIgmp (IpSb);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ IpSb->DefaultInterface = Ip4CreateInterface (IpSb->Mnp, Controller, ImageHandle);\r
+\r
+ if (IpSb->DefaultInterface == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NetListInsertHead (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);\r
+\r
+ IpSb->MacString = NULL;\r
+\r
+ *Service = IpSb;\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ Ip4CleanService (IpSb);\r
+ NetFreePool (IpSb);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Clean up a IP4 service binding instance. It will release all\r
+ the resource allocated by the instance. The instance may be\r
+ partly initialized, or partly destoried. If a resource is\r
+ destoried, it is marked as that in case the destory failed and\r
+ being called again later.\r
+\r
+ @param IpSb The IP4 serviceing binding instance to clean up\r
+\r
+ @retval EFI_SUCCESS The resource used by the instance are cleaned up\r
+ @retval Others Failed to clean up some of the resources.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4CleanService (\r
+ IN IP4_SERVICE *IpSb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (IpSb->DefaultInterface != NULL) {\r
+ Status = Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ IpSb->DefaultInterface = NULL;\r
+ }\r
+\r
+ if (IpSb->DefaultRouteTable != NULL) {\r
+ Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
+ IpSb->DefaultRouteTable = NULL;\r
+ }\r
+\r
+ Ip4CleanAssembleTable (&IpSb->Assemble);\r
+\r
+ if (IpSb->MnpChildHandle != NULL) {\r
+ if (IpSb->Mnp) {\r
+ gBS->CloseProtocol (\r
+ IpSb->MnpChildHandle,\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ IpSb->Image,\r
+ IpSb->Controller\r
+ );\r
+\r
+ IpSb->Mnp = NULL;\r
+ }\r
+\r
+ NetLibDestroyServiceChild (\r
+ IpSb->Controller,\r
+ IpSb->Image,\r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ IpSb->MnpChildHandle\r
+ );\r
+\r
+ IpSb->MnpChildHandle = NULL;\r
+ }\r
+\r
+ if (IpSb->Timer != NULL) {\r
+ gBS->SetTimer (IpSb->Timer, TimerCancel, 0);\r
+ gBS->CloseEvent (IpSb->Timer);\r
+\r
+ IpSb->Timer = NULL;\r
+ }\r
+\r
+ if (IpSb->Ip4Config != NULL) {\r
+ IpSb->Ip4Config->Stop (IpSb->Ip4Config);\r
+\r
+ gBS->CloseProtocol (\r
+ IpSb->Controller,\r
+ &gEfiIp4ConfigProtocolGuid,\r
+ IpSb->Image,\r
+ IpSb->Controller\r
+ );\r
+\r
+ gBS->CloseEvent (IpSb->DoneEvent);\r
+ gBS->CloseEvent (IpSb->ReconfigEvent);\r
+ IpSb->Ip4Config = NULL;\r
+ }\r
+\r
+ return EFI_SUCCESS;\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
+Ip4DriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Test for the Ip4 service binding protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ Status = Ip4CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Install the Ip4ServiceBinding Protocol onto ControlerHandle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ControllerHandle,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ &IpSb->ServiceBinding,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_SERVICE;\r
+ }\r
+\r
+ //\r
+ // ready to go: start the receiving and timer\r
+ //\r
+ Status = Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto UNINSTALL_PROTOCOL;\r
+ }\r
+\r
+ Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto UNINSTALL_PROTOCOL;\r
+ }\r
+\r
+ //\r
+ // Initialize the IP4 ID\r
+ //\r
+ mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());\r
+\r
+ Ip4SetVariableData (IpSb);\r
+\r
+ return Status;\r
+\r
+UNINSTALL_PROTOCOL:\r
+ gBS->UninstallProtocolInterface (\r
+ ControllerHandle,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ &IpSb->ServiceBinding\r
+ );\r
+\r
+FREE_SERVICE:\r
+ Ip4CleanService (IpSb);\r
+ NetFreePool (IpSb);\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
+Ip4DriverBindingStop (\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
+ IP4_SERVICE *IpSb;\r
+ IP4_PROTOCOL *IpInstance;\r
+ EFI_HANDLE NicHandle;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+ INTN State;\r
+\r
+ //\r
+ // IP4 driver opens the MNP child, ARP children or the IP4_CONFIG protocol\r
+ // by driver. So the ControllerHandle may be the MNP child handle, ARP child\r
+ // handle, or the NIC (UNDI) handle because IP4_CONFIG protocol is installed\r
+ // in the NIC handle.\r
+ //\r
+ //\r
+ // First, check whether it is the IP4_CONFIG protocol being uninstalled.\r
+ // IP4_CONFIG protocol is installed on the NIC handle. It isn't necessary\r
+ // to clean up the default configuration if IP4_CONFIG is being stopped.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiIp4ConfigProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // Retrieve the IP4 service binding protocol. If failed, it is\r
+ // likely that Ip4 ServiceBinding is uninstalled already. In this\r
+ // case, return immediately.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ (VOID **) &ServiceBinding,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (IpSb->Ip4Config && (IpSb->State != IP4_SERVICE_DESTORY)) {\r
+\r
+ IpSb->Ip4Config->Stop (IpSb->Ip4Config);\r
+\r
+ Status = gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiIp4ConfigProtocolGuid,\r
+ IpSb->Image,\r
+ ControllerHandle\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // If the auto configure hasn't complete, mark it as not started.\r
+ //\r
+ if (IpSb->State == IP4_SERVICE_STARTED) {\r
+ IpSb->State = IP4_SERVICE_UNSTARTED;\r
+ }\r
+\r
+ IpSb->Ip4Config = NULL;\r
+ gBS->CloseEvent (IpSb->DoneEvent);\r
+ gBS->CloseEvent (IpSb->ReconfigEvent);\r
+ }\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Either MNP or ARP protocol is being uninstalled. The controller\r
+ // handle is either the MNP child or ARP child. But, the IP4's\r
+ // service binding is installed on the NIC handle. So, need to open\r
+ // the protocol info to find the NIC handle.\r
+ //\r
+ NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);\r
+\r
+ if (NicHandle == NULL) {\r
+ NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);\r
+ }\r
+\r
+ if (NicHandle == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Retrieve the IP4 service binding protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ NicHandle,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\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
+ IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (IpSb->InDestory) {\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ IpSb->InDestory = TRUE;\r
+\r
+ State = IpSb->State;\r
+ IpSb->State = IP4_SERVICE_DESTORY;\r
+\r
+ //\r
+ // Destory all the children first. If not all children are destoried,\r
+ // the IP driver can operate correctly, so restore it state. Don't\r
+ // use NET_LIST_FOR_EACH_SAFE here, because it will cache the next\r
+ // pointer, which may point to the child that has already been destoried.\r
+ // For example, if there are two child in the list, the first is UDP\r
+ // listen child, the send is the MTFTP's child. When Udp child is\r
+ // destoried, it will destory the MTFTP's child. Then Next point to\r
+ // a invalid child.\r
+ //\r
+ while (!NetListIsEmpty (&IpSb->Children)) {\r
+ IpInstance = NET_LIST_HEAD (&IpSb->Children, IP4_PROTOCOL, Link);\r
+ Ip4ServiceBindingDestroyChild (ServiceBinding, IpInstance->Handle);\r
+ }\r
+\r
+ if (IpSb->NumChildren != 0) {\r
+ IpSb->State = State;\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Clear the variable data.\r
+ //\r
+ Ip4ClearVariableData (IpSb);\r
+\r
+ //\r
+ // OK, clean other resources then uninstall the service binding protocol.\r
+ //\r
+ Status = Ip4CleanService (IpSb);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = gBS->UninstallProtocolInterface (\r
+ NicHandle,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ ServiceBinding\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+ NetFreePool (IpSb);\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ IpSb->InDestory = FALSE;\r
+ NET_RESTORE_TPL (OldTpl);\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\r
+ is not NULL, then the I/O services are added to\r
+ the existing child handle.\r
+\r
+ @retval EFI_SUCCES The child handle was created with the I/O services\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
+ the child\r
+ @retval other The child handle was not created\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Ip4ServiceBindingCreateChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE *ChildHandle\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ IP4_PROTOCOL *IpInstance;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ VOID *Mnp;\r
+\r
+ if ((This == NULL) || (ChildHandle == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IpSb = IP4_SERVICE_FROM_PROTOCOL (This);\r
+ IpInstance = NetAllocatePool (sizeof (IP4_PROTOCOL));\r
+\r
+ if (IpInstance == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Ip4InitProtocol (IpSb, IpInstance);\r
+\r
+ //\r
+ // Install Ip4 onto ChildHandle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ ChildHandle,\r
+ &gEfiIp4ProtocolGuid,\r
+ &IpInstance->Ip4Proto,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ IpInstance->Handle = *ChildHandle;\r
+\r
+ //\r
+ // Open the Managed Network protocol BY_CHILD.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ IpSb->MnpChildHandle,\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ (VOID **) &Mnp,\r
+ gIp4DriverBinding.DriverBindingHandle,\r
+ IpInstance->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandle,\r
+ &gEfiIp4ProtocolGuid,\r
+ &IpInstance->Ip4Proto,\r
+ NULL\r
+ );\r
+\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Insert it into the service binding instance.\r
+ //\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ NetListInsertTail (&IpSb->Children, &IpInstance->Link);\r
+ IpSb->NumChildren++;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ON_ERROR:\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ Ip4CleanProtocol (IpInstance);\r
+\r
+ NetFreePool (IpInstance);\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
+Ip4ServiceBindingDestroyChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ChildHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ IP4_SERVICE *IpSb;\r
+ IP4_PROTOCOL *IpInstance;\r
+ EFI_IP4_PROTOCOL *Ip4;\r
+ EFI_TPL OldTpl;\r
+ INTN State;\r
+\r
+ if ((This == NULL) || (ChildHandle == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Retrieve the private context data structures\r
+ //\r
+ IpSb = IP4_SERVICE_FROM_PROTOCOL (This);\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiIp4ProtocolGuid,\r
+ (VOID **) &Ip4,\r
+ gIp4DriverBinding.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);\r
+\r
+ if (IpInstance->Service != IpSb) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ //\r
+ // A child can be destoried more than once. For example,\r
+ // Ip4DriverBindingStop will destory all of its children.\r
+ // when UDP driver is being stopped, it will destory all\r
+ // the IP child it opens.\r
+ //\r
+ if (IpInstance->State == IP4_STATE_DESTORY) {\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ State = IpInstance->State;\r
+ IpInstance->State = IP4_STATE_DESTORY;\r
+\r
+ //\r
+ // Close the Managed Network protocol.\r
+ //\r
+ gBS->CloseProtocol (\r
+ IpSb->MnpChildHandle,\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ gIp4DriverBinding.DriverBindingHandle,\r
+ ChildHandle\r
+ );\r
+\r
+ //\r
+ // Uninstall the IP4 protocol first. Many thing happens during\r
+ // this:\r
+ // 1. The consumer of the IP4 protocol will be stopped if it\r
+ // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is\r
+ // stopped, IP driver's stop function will be called, and uninstall\r
+ // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This\r
+ // makes it possible to create the network stack bottom up, and\r
+ // stop it top down.\r
+ // 2. the upper layer will recycle the received packet. The recycle\r
+ // event's TPL is higher than this function. The recycle events\r
+ // will be called back before preceeding. If any packets not recycled,\r
+ // that means there is a resource leak.\r
+ //\r
+ Status = gBS->UninstallProtocolInterface (\r
+ ChildHandle,\r
+ &gEfiIp4ProtocolGuid,\r
+ &IpInstance->Ip4Proto\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = Ip4CleanProtocol (IpInstance);\r
+\r
+ Ip4SetVariableData (IpSb);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->InstallMultipleProtocolInterfaces (\r
+ &ChildHandle,\r
+ &gEfiIp4ProtocolGuid,\r
+ Ip4,\r
+ NULL\r
+ );\r
+\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NetListRemoveEntry (&IpInstance->Link);\r
+ IpSb->NumChildren--;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ NetFreePool (IpInstance);\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ IpInstance->State = State;\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Ip4Driver.h
+
+Abstract:
+
+
+**/
+
+#ifndef __EFI_IP4_DRIVER_H__
+#define __EFI_IP4_DRIVER_H__
+
+#include <Protocol/ServiceBinding.h>
+
+extern EFI_DRIVER_BINDING_PROTOCOL gIp4DriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gIp4ComponentName;
+
+//
+// Function prototype for the driver's entry point
+//
+EFI_STATUS
+EFIAPI
+Ip4DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+//
+// Function prototypes for the Drivr Binding Protocol
+//
+EFI_STATUS
+EFIAPI
+Ip4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Ip4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+Ip4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Function ptototypes for the ServiceBinding Prococol
+//
+EFI_STATUS
+EFIAPI
+Ip4ServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE *ChildHandle
+ );
+
+EFI_STATUS
+EFIAPI
+Ip4ServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ );
+#endif
--- /dev/null
+#/** @file\r
+# Component name for module Ip4\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 = Ip4Dxe\r
+ FILE_GUID = 9FB1A1F3-3B71-4324-B39A-745CBB015FFF\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ EDK_RELEASE_VERSION = 0x00020000\r
+ EFI_SPECIFICATION_VERSION = 0x00020000\r
+\r
+ ENTRY_POINT = Ip4DriverEntryPoint\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
+ Ip4Driver.c\r
+ Ip4Option.h\r
+ Ip4Route.h\r
+ Ip4If.c\r
+ Ip4Igmp.h\r
+ Ip4Output.c\r
+ Ip4Icmp.c\r
+ Ip4Igmp.c\r
+ Ip4Impl.c\r
+ Ip4Common.h\r
+ Ip4Impl.h\r
+ Ip4Driver.h\r
+ Ip4Common.c\r
+ Ip4If.h\r
+ Ip4Option.c\r
+ Ip4Output.h\r
+ ComponentName.c\r
+ Ip4Input.h\r
+ Ip4Route.c\r
+ Ip4Icmp.h\r
+ Ip4Input.c\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ UefiLib\r
+ BaseLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ UefiRuntimeServicesTableLib\r
+ DebugLib\r
+ NetLib\r
+\r
+\r
+[Protocols]\r
+ gEfiIp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiManagedNetworkServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiIp4ConfigProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiArpServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiIp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiManagedNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiArpProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+\r
--- /dev/null
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+ <MsaHeader>\r
+ <ModuleName>Ip4Dxe</ModuleName>\r
+ <ModuleType>DXE_DRIVER</ModuleType>\r
+ <GuidValue>9FB1A1F3-3B71-4324-B39A-745CBB015FFF</GuidValue>\r
+ <Version>1.0</Version>\r
+ <Abstract>Component name for module Ip4</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>Ip4Dxe</OutputFileBasename>\r
+ </ModuleDefinitions>\r
+ <LibraryClassDefinitions>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>DebugLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiDriverEntryPoint</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiBootServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>BaseLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiLib</Keyword>\r
+ </LibraryClass>\r
+ </LibraryClassDefinitions>\r
+ <SourceFiles>\r
+ <Filename>Ip4Input.c</Filename>\r
+ <Filename>Ip4Icmp.h</Filename>\r
+ <Filename>Ip4Route.c</Filename>\r
+ <Filename>Ip4Input.h</Filename>\r
+ <Filename>ComponentName.c</Filename>\r
+ <Filename>Ip4Output.h</Filename>\r
+ <Filename>Ip4Option.c</Filename>\r
+ <Filename>Ip4If.h</Filename>\r
+ <Filename>Ip4Common.c</Filename>\r
+ <Filename>Ip4Driver.h</Filename>\r
+ <Filename>Ip4Impl.h</Filename>\r
+ <Filename>Ip4Common.h</Filename>\r
+ <Filename>Ip4Impl.c</Filename>\r
+ <Filename>Ip4Igmp.c</Filename>\r
+ <Filename>Ip4Icmp.c</Filename>\r
+ <Filename>Ip4Output.c</Filename>\r
+ <Filename>Ip4Igmp.h</Filename>\r
+ <Filename>Ip4If.c</Filename>\r
+ <Filename>Ip4Route.h</Filename>\r
+ <Filename>Ip4Option.h</Filename>\r
+ <Filename>Ip4Driver.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>gEfiIp4ServiceBindingProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiArpServiceBindingProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiIp4ConfigProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiManagedNetworkServiceBindingProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiIp4ProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ </Protocols>\r
+ <Externs>\r
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+ <Extern>\r
+ <ModuleEntryPoint>Ip4DriverEntryPoint</ModuleEntryPoint>\r
+ </Extern>\r
+ </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Ip4Icmp.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+IP4_ICMP_CLASS\r
+mIcmpClass[] = {\r
+ {ICMP_ECHO_REPLY, ICMP_QUERY_MESSAGE },\r
+ {1, ICMP_INVALID_MESSAGE},\r
+ {2, ICMP_INVALID_MESSAGE},\r
+ {ICMP_DEST_UNREACHABLE, ICMP_ERROR_MESSAGE },\r
+ {ICMP_SOURCE_QUENCH, ICMP_ERROR_MESSAGE },\r
+ {ICMP_REDIRECT, ICMP_ERROR_MESSAGE },\r
+ {6, ICMP_INVALID_MESSAGE},\r
+ {7, ICMP_INVALID_MESSAGE},\r
+ {ICMP_ECHO_REQUEST, ICMP_QUERY_MESSAGE },\r
+ {9, ICMP_INVALID_MESSAGE},\r
+ {10, ICMP_INVALID_MESSAGE},\r
+ {ICMP_TIME_EXCEEDED, ICMP_ERROR_MESSAGE },\r
+ {ICMP_PARAMETER_PROBLEM, ICMP_ERROR_MESSAGE },\r
+ {ICMP_TIMESTAMP , ICMP_QUERY_MESSAGE },\r
+ {14, ICMP_INVALID_MESSAGE},\r
+ {ICMP_INFO_REQUEST , ICMP_QUERY_MESSAGE },\r
+ {ICMP_INFO_REPLY , ICMP_QUERY_MESSAGE },\r
+};\r
+\r
+EFI_IP4_ICMP_TYPE\r
+mIp4SupportedIcmp [23] = {\r
+ {ICMP_ECHO_REPLY, ICMP_DEFAULT_CODE },\r
+\r
+ {ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_PROTO_UNREACHABLE },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_PORT_UNREACHABLE },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_FRAGMENT_FAILED },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_SOURCEROUTE_FAILED},\r
+ {ICMP_DEST_UNREACHABLE, ICMP_NET_UNKNOWN },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNKNOWN },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_SOURCE_ISOLATED },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_NET_PROHIBITED },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_HOST_PROHIBITED },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE_TOS },\r
+ {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE_TOS},\r
+\r
+ {ICMP_SOURCE_QUENCH, ICMP_DEFAULT_CODE },\r
+\r
+ {ICMP_REDIRECT, ICMP_NET_REDIRECT },\r
+ {ICMP_REDIRECT, ICMP_HOST_REDIRECT },\r
+ {ICMP_REDIRECT, ICMP_NET_TOS_REDIRECT },\r
+ {ICMP_REDIRECT, ICMP_HOST_TOS_REDIRECT },\r
+\r
+ {ICMP_ECHO_REQUEST, ICMP_DEFAULT_CODE },\r
+\r
+ {ICMP_TIME_EXCEEDED, ICMP_TIMEOUT_IN_TRANSIT},\r
+ {ICMP_TIME_EXCEEDED, ICMp_TIMEOUT_REASSEMBLE},\r
+\r
+ {ICMP_PARAMETER_PROBLEM, ICMP_DEFAULT_CODE },\r
+};\r
+\r
+\r
+\r
+/**\r
+ Process the ICMP redirect. Find the instance then update\r
+ its route cache.\r
+ All kinds of redirect is treated as host redirect as\r
+ specified by RFC1122 3.3.1.2:\r
+ "Since the subnet mask appropriate to the destination\r
+ address is generally not known, a Network Redirect\r
+ message SHOULD be treated identically to a Host Redirect\r
+ message;"\r
+\r
+ @param IpSb The IP4 service binding instance that received the\r
+ packet\r
+ @param Head The IP head of the received ICMPpacket.\r
+ @param Packet The content of the ICMP redirect packet with IP\r
+ head removed.\r
+ @param Icmp The buffer to store the ICMP error message if\r
+ something is wrong.\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameter is invalid\r
+ @retval EFI_SUCCESS Successfully updated the route caches\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Ip4ProcessIcmpRedirect (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_HEAD *Head,\r
+ IN NET_BUF *Packet,\r
+ IN IP4_ICMP_ERROR_HEAD *Icmp\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_PROTOCOL *Ip4Instance;\r
+ IP4_ROUTE_CACHE_ENTRY *CacheEntry;\r
+ IP4_INTERFACE *IpIf;\r
+ IP4_ADDR Gateway;\r
+\r
+ //\r
+ // Find the interface whose IP address is the source of the\r
+ // orgianl IP packet.\r
+ //\r
+ IpIf = Ip4FindInterface (IpSb, NTOHL (Icmp->IpHead.Src));\r
+ Gateway = NTOHL (Icmp->Fourth);\r
+\r
+ //\r
+ // discard the packet if the new gateway address it specifies\r
+ // is not on the same connected net through which the Redirect\r
+ // arrived. (RFC1122 3.2.2.2).\r
+ //\r
+ if ((IpIf == NULL) || !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask)) {\r
+ NetbufFree (Packet);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Update each IP child's route cache on the interface.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
+ Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);\r
+\r
+ if (Ip4Instance->RouteTable == NULL) {\r
+ continue;\r
+ }\r
+\r
+ CacheEntry = Ip4FindRouteCache (\r
+ Ip4Instance->RouteTable,\r
+ NTOHL (Icmp->IpHead.Dst),\r
+ NTOHL (Icmp->IpHead.Src)\r
+ );\r
+\r
+ //\r
+ // Only update the route cache's gateway if the source of the\r
+ // Redirect is the current first-hop gateway\r
+ //\r
+ if ((CacheEntry != NULL) && (NTOHL (Head->Src) == CacheEntry->NextHop)) {\r
+ CacheEntry->NextHop = Gateway;\r
+ }\r
+ }\r
+\r
+ NetbufFree (Packet);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Process the ICMP error packet. If it is an ICMP redirect packet,\r
+ update call Ip4ProcessIcmpRedirect to update the IP instance's\r
+ route cache, otherwise, deliver the packet to upper layer.\r
+\r
+ @param IpSb The IP service that received the packet.\r
+ @param Head The IP head of the ICMP error packet\r
+ @param Packet The content of the ICMP error with IP head\r
+ removed.\r
+\r
+ @retval EFI_INVALID_PARAMETER The packet is invalid\r
+ @retval Others Failed to process the packet.\r
+ @retval EFI_SUCCESS The ICMP error is processed successfully.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Ip4ProcessIcmpError (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_HEAD *Head,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ IP4_ICMP_ERROR_HEAD Icmp;\r
+\r
+ if (Packet->TotalSize < sizeof (Icmp)) {\r
+ NetbufFree (Packet);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
+\r
+ //\r
+ // If it is an ICMP redirect error, update the route cache\r
+ // as RFC1122. Otherwise, demultiplex it to IP instances.\r
+ //\r
+ if (Icmp.Head.Type == ICMP_REDIRECT) {\r
+ return Ip4ProcessIcmpRedirect (IpSb, Head, Packet, &Icmp);\r
+ }\r
+\r
+ IP4_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;\r
+ return Ip4Demultiplex (IpSb, Head, Packet);\r
+}\r
+\r
+\r
+/**\r
+ Replay an ICMP echo request.\r
+\r
+ @param IpSb The IP service that receivd the packet\r
+ @param Head The IP head of the ICMP error packet\r
+ @param Packet The content of the ICMP error with IP head\r
+ removed.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.\r
+ @retval EFI_SUCCESS The ICMP Echo request is successfully answered.\r
+ @retval Others Failed to answer the ICMP echo request.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4IcmpReplyEcho (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_HEAD *Head,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ IP4_ICMP_QUERY_HEAD *Icmp;\r
+ NET_BUF *Data;\r
+ EFI_STATUS Status;\r
+ IP4_HEAD ReplyHead;\r
+\r
+ //\r
+ // make a copy the packet, it is really a bad idea to\r
+ // send the MNP's buffer back to MNP.\r
+ //\r
+ Data = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN);\r
+\r
+ if (Data == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Change the ICMP type to echo reply, exchange the source\r
+ // and destination, then send it. The source is updated to\r
+ // use specific destination. See RFC1122. SRR/RR option\r
+ // update is omitted.\r
+ //\r
+ Icmp = (IP4_ICMP_QUERY_HEAD *) NetbufGetByte (Data, 0, NULL);\r
+ Icmp->Head.Type = ICMP_ECHO_REPLY;\r
+ Icmp->Head.Checksum = 0;\r
+ Icmp->Head.Checksum = ~NetblockChecksum ((UINT8 *) Icmp, Data->TotalSize);\r
+\r
+ ReplyHead.Tos = 0;\r
+ ReplyHead.Fragment = 0;\r
+ ReplyHead.Ttl = 64;\r
+ ReplyHead.Protocol = IP4_PROTO_ICMP;\r
+ ReplyHead.Src = 0;\r
+\r
+ //\r
+ // Ip4Output will select a source for us\r
+ //\r
+ ReplyHead.Dst = Head->Src;\r
+\r
+ Status = Ip4Output (\r
+ IpSb,\r
+ NULL,\r
+ Data,\r
+ &ReplyHead,\r
+ NULL,\r
+ 0,\r
+ IP4_ALLZERO_ADDRESS,\r
+ Ip4SysPacketSent,\r
+ NULL\r
+ );\r
+\r
+ON_EXIT:\r
+ NetbufFree (Packet);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Process the ICMP query message. If it is an ICMP echo\r
+ request, answer it. Otherwise deliver it to upper layer.\r
+\r
+ @param IpSb The IP service that receivd the packet\r
+ @param Head The IP head of the ICMP query packet\r
+ @param Packet The content of the ICMP query with IP head\r
+ removed.\r
+\r
+ @retval EFI_INVALID_PARAMETER The packet is invalid\r
+ @retval EFI_SUCCESS The ICMP query message is processed\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4ProcessIcmpQuery (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_HEAD *Head,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ IP4_ICMP_QUERY_HEAD Icmp;\r
+\r
+ if (Packet->TotalSize < sizeof (Icmp)) {\r
+ NetbufFree (Packet);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
+\r
+ if (Icmp.Head.Type == ICMP_ECHO_REQUEST) {\r
+ return Ip4IcmpReplyEcho (IpSb, Head, Packet);\r
+ }\r
+\r
+ return Ip4Demultiplex (IpSb, Head, Packet);\r
+}\r
+\r
+\r
+/**\r
+ Handle the ICMP packet. First validate the message format,\r
+ then according to the message types, process it as query or\r
+ error packet.\r
+\r
+ @param IpSb The IP service that receivd the packet\r
+ @param Head The IP head of the ICMP query packet\r
+ @param Packet The content of the ICMP query with IP head\r
+ removed.\r
+\r
+ @retval EFI_INVALID_PARAMETER The packet is malformated.\r
+ @retval EFI_SUCCESS The ICMP message is successfully processed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4IcmpHandle (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_HEAD *Head,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ IP4_ICMP_HEAD Icmp;\r
+ UINT16 Checksum;\r
+\r
+ if (Packet->TotalSize < sizeof (Icmp)) {\r
+ goto DROP;\r
+ }\r
+\r
+ NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
+\r
+ if (Icmp.Type > ICMP_TYPE_MAX) {\r
+ goto DROP;\r
+ }\r
+\r
+ Checksum = ~NetbufChecksum (Packet);\r
+ if ((Icmp.Checksum != 0) && (Checksum != 0)) {\r
+ goto DROP;\r
+ }\r
+\r
+ if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_ERROR_MESSAGE) {\r
+ return Ip4ProcessIcmpError (IpSb, Head, Packet);\r
+\r
+ } else if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_QUERY_MESSAGE) {\r
+ return Ip4ProcessIcmpQuery (IpSb, Head, Packet);\r
+\r
+ }\r
+\r
+DROP:\r
+ NetbufFree (Packet);\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Ip4Icmp.h
+
+Abstract:
+
+ Header file for ICMP protocol.
+
+
+**/
+
+#ifndef __EFI_IP4_ICMP_H__
+#define __EFI_IP4_ICMP_H__
+
+enum {
+ //
+ // ICMP type definations
+ //
+ ICMP_ECHO_REPLY = 0,
+ ICMP_DEST_UNREACHABLE = 3,
+ ICMP_SOURCE_QUENCH = 4,
+ ICMP_REDIRECT = 5,
+ ICMP_ECHO_REQUEST = 8,
+ ICMP_TIME_EXCEEDED = 11,
+ ICMP_PARAMETER_PROBLEM = 12,
+ ICMP_TIMESTAMP = 13,
+ ICMP_INFO_REQUEST = 15,
+ ICMP_INFO_REPLY = 16,
+ ICMP_TYPE_MAX = ICMP_INFO_REPLY,
+
+ ICMP_DEFAULT_CODE = 0,
+
+ //
+ // ICMP code definations for ICMP_DEST_UNREACHABLE
+ //
+ ICMP_NET_UNREACHABLE = 0,
+ ICMP_HOST_UNREACHABLE = 1,
+ ICMP_PROTO_UNREACHABLE = 2, // Host may generate
+ ICMP_PORT_UNREACHABLE = 3, // Host may generate
+ ICMP_FRAGMENT_FAILED = 4,
+ ICMP_SOURCEROUTE_FAILED = 5, // Host may generate
+ ICMP_NET_UNKNOWN = 6,
+ ICMP_HOST_UNKNOWN = 7,
+ ICMP_SOURCE_ISOLATED = 8,
+ ICMP_NET_PROHIBITED = 9,
+ ICMP_HOST_PROHIBITED = 10,
+ ICMP_NET_UNREACHABLE_TOS = 11,
+ ICMP_HOST_UNREACHABLE_TOS = 12,
+
+ //
+ // ICMP code definations for ICMP_TIME_EXCEEDED
+ //
+ ICMP_TIMEOUT_IN_TRANSIT = 0,
+ ICMp_TIMEOUT_REASSEMBLE = 1, // Host may generate
+
+ //
+ // ICMP code definations for ICMP_TIME_EXCEEDED
+ //
+ ICMP_NET_REDIRECT = 0,
+ ICMP_HOST_REDIRECT = 1,
+ ICMP_NET_TOS_REDIRECT = 2,
+ ICMP_HOST_TOS_REDIRECT = 3,
+
+ //
+ // ICMP message classes, each class of ICMP message shares
+ // a common message format. INVALID_MESSAGE is only a flag.
+ //
+ ICMP_INVALID_MESSAGE = 0,
+ ICMP_ERROR_MESSAGE = 1,
+ ICMP_QUERY_MESSAGE = 2,
+};
+
+typedef struct {
+ UINT8 IcmpType;
+ UINT8 IcmpClass;
+} IP4_ICMP_CLASS;
+
+extern IP4_ICMP_CLASS mIcmpClass[];
+extern EFI_IP4_ICMP_TYPE mIp4SupportedIcmp[];
+
+EFI_STATUS
+Ip4IcmpHandle (
+ IN IP4_SERVICE *IpSb,
+ IN IP4_HEAD *Header,
+ IN NET_BUF *Packet
+ );
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Ip4If.c\r
+\r
+Abstract:\r
+\r
+ Implement IP4 pesudo interface.\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+//\r
+// Mac address with all zero, used to determine whethter the ARP\r
+// resolve succeeded. Failed ARP requests zero the MAC address buffer.\r
+//\r
+STATIC EFI_MAC_ADDRESS mZeroMacAddress;\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Ip4OnFrameSent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Ip4OnArpResolved (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Ip4OnFrameReceived (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+STATIC\r
+VOID\r
+Ip4CancelFrameArp (\r
+ IN IP4_ARP_QUE *ArpQue,\r
+ IN EFI_STATUS IoStatus,\r
+ IN IP4_FRAME_TO_CANCEL FrameToCancel, OPTIONAL\r
+ IN VOID *Context\r
+ );\r
+\r
+\r
+/**\r
+ Wrap a transmit request into a newly allocated IP4_LINK_TX_TOKEN.\r
+\r
+ @param Interface The interface to send out from\r
+ @param IpInstance The IpInstance that transmit the packet. NULL if\r
+ the packet is sent by the IP4 driver itself.\r
+ @param Packet The packet to transmit\r
+ @param CallBack Call back function to execute if transmission\r
+ finished.\r
+ @param Context Opaque parameter to the call back.\r
+\r
+ @return The wrapped token if succeed or NULL\r
+\r
+**/\r
+STATIC\r
+IP4_LINK_TX_TOKEN *\r
+Ip4WrapLinkTxToken (\r
+ IN IP4_INTERFACE *Interface,\r
+ IN IP4_PROTOCOL *IpInstance, OPTIONAL\r
+ IN NET_BUF *Packet,\r
+ IN IP4_FRAME_CALLBACK CallBack,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;\r
+ EFI_MANAGED_NETWORK_TRANSMIT_DATA *MnpTxData;\r
+ IP4_LINK_TX_TOKEN *Token;\r
+ EFI_STATUS Status;\r
+ UINT32 Count;\r
+\r
+ Token = NetAllocatePool (sizeof (IP4_LINK_TX_TOKEN) + \\r
+ (Packet->BlockOpNum - 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA));\r
+\r
+ if (Token == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Token->Signature = IP4_FRAME_TX_SIGNATURE;\r
+ NetListInit (&Token->Link);\r
+\r
+ Token->Interface = Interface;\r
+ Token->IpInstance = IpInstance;\r
+ Token->CallBack = CallBack;\r
+ Token->Packet = Packet;\r
+ Token->Context = Context;\r
+ CopyMem (&Token->DstMac, &mZeroMacAddress, sizeof (EFI_MAC_ADDRESS));\r
+ CopyMem (&Token->SrcMac, &Interface->Mac, sizeof (EFI_MAC_ADDRESS));\r
+\r
+ MnpToken = &(Token->MnpToken);\r
+ MnpToken->Status = EFI_NOT_READY;\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ Ip4OnFrameSent,\r
+ Token,\r
+ &MnpToken->Event\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetFreePool (Token);\r
+ return NULL;\r
+ }\r
+\r
+ MnpTxData = &Token->MnpTxData;\r
+ MnpToken->Packet.TxData = MnpTxData;\r
+\r
+ MnpTxData->DestinationAddress = &Token->DstMac;\r
+ MnpTxData->SourceAddress = &Token->SrcMac;\r
+ MnpTxData->ProtocolType = IP4_ETHER_PROTO;\r
+ MnpTxData->DataLength = Packet->TotalSize;\r
+ MnpTxData->HeaderLength = 0;\r
+\r
+ Count = Packet->BlockOpNum;\r
+\r
+ NetbufBuildExt (Packet, (NET_FRAGMENT *) MnpTxData->FragmentTable, &Count);\r
+ MnpTxData->FragmentCount = (UINT16)Count;\r
+\r
+ return Token;\r
+}\r
+\r
+\r
+/**\r
+ Free the link layer transmit token. It will close the event\r
+ then free the memory used.\r
+\r
+ @param Token Token to free\r
+\r
+ @return NONE\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4FreeLinkTxToken (\r
+ IN IP4_LINK_TX_TOKEN *Token\r
+ )\r
+{\r
+ NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);\r
+\r
+ gBS->CloseEvent (Token->MnpToken.Event);\r
+ NetFreePool (Token);\r
+}\r
+\r
+\r
+/**\r
+ Create an IP_ARP_QUE structure to request ARP service.\r
+\r
+ @param Interface The interface to send ARP from.\r
+ @param DestIp The destination IP (host byte order) to request MAC\r
+ for\r
+\r
+ @return Point to newly created IP4_ARP_QUE if succeed, otherwise NULL.\r
+\r
+**/\r
+STATIC\r
+IP4_ARP_QUE *\r
+Ip4CreateArpQue (\r
+ IN IP4_INTERFACE *Interface,\r
+ IN IP4_ADDR DestIp\r
+ )\r
+{\r
+ IP4_ARP_QUE *ArpQue;\r
+ EFI_STATUS Status;\r
+\r
+ ArpQue = NetAllocatePool (sizeof (IP4_ARP_QUE));\r
+\r
+ if (ArpQue == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ ArpQue->Signature = IP4_FRAME_ARP_SIGNATURE;\r
+ NetListInit (&ArpQue->Link);\r
+\r
+ NetListInit (&ArpQue->Frames);\r
+ ArpQue->Interface = Interface;\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ Ip4OnArpResolved,\r
+ ArpQue,\r
+ &ArpQue->OnResolved\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetFreePool (ArpQue);\r
+ return NULL;\r
+ }\r
+\r
+ ArpQue->Ip = DestIp;\r
+ CopyMem (&ArpQue->Mac, &mZeroMacAddress, sizeof (EFI_MAC_ADDRESS));\r
+\r
+ return ArpQue;\r
+}\r
+\r
+\r
+/**\r
+ Remove all the transmit requests queued on the ARP queue, then free it.\r
+\r
+ @param ArpQue Arp queue to free\r
+ @param IoStatus The transmit status returned to transmit requests'\r
+ callback.\r
+\r
+ @return NONE\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4FreeArpQue (\r
+ IN IP4_ARP_QUE *ArpQue,\r
+ IN EFI_STATUS IoStatus\r
+ )\r
+{\r
+ NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);\r
+\r
+ //\r
+ // Remove all the frame waiting the ARP response\r
+ //\r
+ Ip4CancelFrameArp (ArpQue, IoStatus, NULL, NULL);\r
+\r
+ gBS->CloseEvent (ArpQue->OnResolved);\r
+ NetFreePool (ArpQue);\r
+}\r
+\r
+\r
+/**\r
+ Create a link layer receive token to wrap the receive request\r
+\r
+ @param Interface The interface to receive from\r
+ @param IpInstance The instance that request the receive (NULL for IP4\r
+ driver itself)\r
+ @param CallBack Call back function to execute when finished.\r
+ @param Context Opaque parameters to the callback\r
+\r
+ @return Point to created IP4_LINK_RX_TOKEN if succeed, otherwise NULL.\r
+\r
+**/\r
+STATIC\r
+IP4_LINK_RX_TOKEN *\r
+Ip4CreateLinkRxToken (\r
+ IN IP4_INTERFACE *Interface,\r
+ IN IP4_PROTOCOL *IpInstance,\r
+ IN IP4_FRAME_CALLBACK CallBack,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;\r
+ IP4_LINK_RX_TOKEN *Token;\r
+ EFI_STATUS Status;\r
+\r
+ Token = NetAllocatePool (sizeof (IP4_LINK_RX_TOKEN));\r
+ if (Token == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Token->Signature = IP4_FRAME_RX_SIGNATURE;\r
+ Token->Interface = Interface;\r
+ Token->IpInstance = IpInstance;\r
+ Token->CallBack = CallBack;\r
+ Token->Context = Context;\r
+\r
+ MnpToken = &Token->MnpToken;\r
+ MnpToken->Status = EFI_NOT_READY;\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ Ip4OnFrameReceived,\r
+ Token,\r
+ &MnpToken->Event\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetFreePool (Token);\r
+ return NULL;\r
+ }\r
+\r
+ MnpToken->Packet.RxData = NULL;\r
+ return Token;\r
+}\r
+\r
+\r
+/**\r
+ Free the link layer request token. It will close the event\r
+ then free the memory used.\r
+\r
+ @param Token Request token to free\r
+\r
+ @return NONE\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4FreeFrameRxToken (\r
+ IN IP4_LINK_RX_TOKEN *Token\r
+ )\r
+{\r
+\r
+ NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);\r
+\r
+ gBS->CloseEvent (Token->MnpToken.Event);\r
+ NetFreePool (Token);\r
+}\r
+\r
+\r
+/**\r
+ Remove all the frames on the ARP queue that pass the FrameToCancel,\r
+ that is, either FrameToCancel is NULL or it returns true for the frame.\r
+\r
+ @param ArpQue ARP frame to remove the frames from.\r
+ @param IoStatus The status returned to the cancelled frames'\r
+ callback function.\r
+ @param FrameToCancel Function to select which frame to cancel.\r
+ @param Context Opaque parameter to the FrameToCancel.\r
+\r
+ @return NONE\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4CancelFrameArp (\r
+ IN IP4_ARP_QUE *ArpQue,\r
+ IN EFI_STATUS IoStatus,\r
+ IN IP4_FRAME_TO_CANCEL FrameToCancel, OPTIONAL\r
+ IN VOID *Context\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_LINK_TX_TOKEN *Token;\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {\r
+ Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);\r
+\r
+ if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {\r
+ NetListRemoveEntry (Entry);\r
+\r
+ Token->CallBack (Token->IpInstance, Token->Packet, IoStatus, 0, Token->Context);\r
+ Ip4FreeLinkTxToken (Token);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Remove all the frames on the interface that pass the FrameToCancel,\r
+ either queued on ARP queues or that have already been delivered to\r
+ MNP and not yet recycled.\r
+\r
+ @param Interface Interface to remove the frames from\r
+ @param IoStatus The transmit status returned to the frames'\r
+ callback\r
+ @param FrameToCancel Function to select the frame to cancel, NULL to\r
+ select all\r
+ @param Context Opaque parameters passed to FrameToCancel\r
+\r
+ @return NONE\r
+\r
+**/\r
+VOID\r
+Ip4CancelFrames (\r
+ IN IP4_INTERFACE *Interface,\r
+ IN EFI_STATUS IoStatus,\r
+ IN IP4_FRAME_TO_CANCEL FrameToCancel, OPTIONAL\r
+ IN VOID *Context\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ARP_QUE *ArpQue;\r
+ IP4_LINK_TX_TOKEN *Token;\r
+\r
+ //\r
+ // Cancel all the pending frames on ARP requests\r
+ //\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->ArpQues) {\r
+ ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);\r
+\r
+ Ip4CancelFrameArp (ArpQue, IoStatus, FrameToCancel, Context);\r
+\r
+ if (NetListIsEmpty (&ArpQue->Frames)) {\r
+ NetListRemoveEntry (Entry);\r
+\r
+ Interface->Arp->Cancel (Interface->Arp, &ArpQue->Ip, ArpQue->OnResolved);\r
+ Ip4FreeArpQue (ArpQue, EFI_ABORTED);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Cancel all the frames that have been delivered to MNP\r
+ // but not yet recycled.\r
+ //\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->SentFrames) {\r
+ Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);\r
+\r
+ if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {\r
+ NetListRemoveEntry (Entry);\r
+\r
+ Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);\r
+ Token->CallBack (Token->IpInstance, Token->Packet, IoStatus, 0, Token->Context);\r
+ Ip4FreeLinkTxToken (Token);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Create an IP4_INTERFACE. Delay the creation of ARP instance until\r
+ the interface is configured.\r
+\r
+ @param Mnp The shared MNP child of this IP4 service binding\r
+ instance\r
+ @param Controller The controller this IP4 service binding instance\r
+ is installed. Most like the UNDI handle.\r
+ @param ImageHandle This driver's image handle\r
+\r
+ @return Point to the created IP4_INTERFACE, otherwise NULL.\r
+\r
+**/\r
+IP4_INTERFACE *\r
+Ip4CreateInterface (\r
+ IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_HANDLE ImageHandle\r
+ )\r
+{\r
+ IP4_INTERFACE *Interface;\r
+ EFI_SIMPLE_NETWORK_MODE SnpMode;\r
+\r
+ Interface = NetAllocatePool (sizeof (IP4_INTERFACE));\r
+\r
+ if ((Interface == NULL) || (Mnp == NULL)) {\r
+ return NULL;\r
+ }\r
+\r
+ Interface->Signature = IP4_INTERFACE_SIGNATURE;\r
+ NetListInit (&Interface->Link);\r
+ Interface->RefCnt = 1;\r
+\r
+ Interface->Ip = IP4_ALLZERO_ADDRESS;\r
+ Interface->SubnetMask = IP4_ALLZERO_ADDRESS;\r
+ Interface->Configured = FALSE;\r
+\r
+ Interface->Controller = Controller;\r
+ Interface->Image = ImageHandle;\r
+ Interface->Mnp = Mnp;\r
+ Interface->Arp = NULL;\r
+ Interface->ArpHandle = NULL;\r
+\r
+ NetListInit (&Interface->ArpQues);\r
+ NetListInit (&Interface->SentFrames);\r
+\r
+ Interface->RecvRequest = NULL;\r
+\r
+ //\r
+ // Get the interface's Mac address and broadcast mac address from SNP\r
+ //\r
+ if (EFI_ERROR (Mnp->GetModeData (Mnp, NULL, &SnpMode))) {\r
+ NetFreePool (Interface);\r
+ return NULL;\r
+ }\r
+\r
+ CopyMem (&Interface->Mac, &SnpMode.CurrentAddress, sizeof (EFI_MAC_ADDRESS));\r
+ CopyMem (&Interface->BroadcastMac, &SnpMode.BroadcastAddress, sizeof (EFI_MAC_ADDRESS));\r
+ Interface->HwaddrLen = SnpMode.HwAddressSize;\r
+\r
+ NetListInit (&Interface->IpInstances);\r
+ Interface->PromiscRecv = FALSE;\r
+\r
+ return Interface;\r
+}\r
+\r
+\r
+/**\r
+ Set the interface's address, create and configure\r
+ the ARP child if necessary.\r
+\r
+ @param Interface The interface to set the address\r
+ @param IpAddr The interface's IP address\r
+ @param SubnetMask The interface's netmask\r
+\r
+ @retval EFI_SUCCESS The interface is configured with Ip/netmask pair,\r
+ and a ARP is created for it.\r
+ @retval Others Failed to set the interface's address.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4SetAddress (\r
+ IN IP4_INTERFACE *Interface,\r
+ IN IP4_ADDR IpAddr,\r
+ IN IP4_ADDR SubnetMask\r
+ )\r
+{\r
+ EFI_ARP_CONFIG_DATA ArpConfig;\r
+ EFI_STATUS Status;\r
+ INTN Type;\r
+ INTN Len;\r
+ IP4_ADDR Netmask;\r
+\r
+ NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);\r
+\r
+ ASSERT (!Interface->Configured);\r
+\r
+ //\r
+ // Set the ip/netmask, then compute the subnet broadcast\r
+ // and network broadcast for easy access. When computing\r
+ // nework broadcast, the subnet mask is most like longer\r
+ // than the default netmask (not subneted) as defined in\r
+ // RFC793. If that isn't the case, we are aggregating the\r
+ // networks, use the subnet's mask instead.\r
+ //\r
+ Interface->Ip = IpAddr;\r
+ Interface->SubnetMask = SubnetMask;\r
+ Interface->SubnetBrdcast = (IpAddr | ~SubnetMask);\r
+\r
+ Type = NetGetIpClass (IpAddr);\r
+ Len = NetGetMaskLength (SubnetMask);\r
+ Netmask = mIp4AllMasks[NET_MIN (Len, Type << 3)];\r
+ Interface->NetBrdcast = (IpAddr | ~Netmask);\r
+\r
+ //\r
+ // If the address is NOT all zero, create then configure an ARP child.\r
+ // Pay attention: DHCP configures its station address as 0.0.0.0/0\r
+ //\r
+ Interface->Arp = NULL;\r
+ Interface->ArpHandle = NULL;\r
+\r
+ if (IpAddr != IP4_ALLZERO_ADDRESS) {\r
+ Status = NetLibCreateServiceChild (\r
+ Interface->Controller,\r
+ Interface->Image,\r
+ &gEfiArpServiceBindingProtocolGuid,\r
+ &Interface->ArpHandle\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Interface->ArpHandle,\r
+ &gEfiArpProtocolGuid,\r
+ (VOID **) &Interface->Arp,\r
+ Interface->Image,\r
+ Interface->Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ IpAddr = HTONL (IpAddr);\r
+ ArpConfig.SwAddressType = IP4_ETHER_PROTO;\r
+ ArpConfig.SwAddressLength = 4;\r
+ ArpConfig.StationAddress = &IpAddr;\r
+ ArpConfig.EntryTimeOut = 0;\r
+ ArpConfig.RetryCount = 0;\r
+ ArpConfig.RetryTimeOut = 0;\r
+\r
+ Status = Interface->Arp->Configure (Interface->Arp, &ArpConfig);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseProtocol (\r
+ Interface->ArpHandle,\r
+ &gEfiArpProtocolGuid,\r
+ Interface->Image,\r
+ Interface->Controller\r
+ );\r
+\r
+ goto ON_ERROR;\r
+ }\r
+ }\r
+\r
+ Interface->Configured = TRUE;\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ NetLibDestroyServiceChild (\r
+ Interface->Controller,\r
+ Interface->Image,\r
+ &gEfiArpServiceBindingProtocolGuid,\r
+ &Interface->ArpHandle\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Fileter function to cancel all the frame related to an IP instance.\r
+\r
+ @param Frame The transmit request to test whether to cancel\r
+ @param Context The context which is the Ip instance that issued\r
+ the transmit.\r
+\r
+ @retval TRUE The frame belongs to this instance and is to be\r
+ removed\r
+ @retval FALSE The frame doesn't belong to this instance.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+Ip4CancelInstanceFrame (\r
+ IN IP4_LINK_TX_TOKEN *Frame,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ if (Frame->IpInstance == (IP4_PROTOCOL *) Context) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+\r
+/**\r
+ If there is a pending receive request, cancel it. Don't call\r
+ the receive request's callback because this function can be only\r
+ called if the instance or driver is tearing itself down. It\r
+ doesn't make sense to call it back. But it is necessary to call\r
+ the transmit token's callback to give it a chance to free the\r
+ packet and update the upper layer's transmit request status, say\r
+ that from the UDP.\r
+\r
+ @param Interface The interface used by the IpInstance\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4CancelReceive (\r
+ IN IP4_INTERFACE *Interface\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+ IP4_LINK_RX_TOKEN *Token;\r
+\r
+ if ((Token = Interface->RecvRequest) != NULL) {\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ Interface->RecvRequest = NULL;\r
+ Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);\r
+ Ip4FreeFrameRxToken (Token);\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Free the interface used by IpInstance. All the IP instance with\r
+ the same Ip/Netmask pair share the same interface. It is reference\r
+ counted. All the frames haven't been sent will be cancelled.\r
+ Because the IpInstance is optional, the caller must remove\r
+ IpInstance from the interface's instance list itself.\r
+\r
+ @param Interface The interface used by the IpInstance\r
+ @param IpInstance The Ip instance that free the interface. NULL if\r
+ the Ip driver is releasing the default interface.\r
+\r
+ @retval EFI_SUCCESS The interface use IpInstance is freed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4FreeInterface (\r
+ IN IP4_INTERFACE *Interface,\r
+ IN IP4_PROTOCOL *IpInstance OPTIONAL\r
+ )\r
+{\r
+ NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);\r
+ ASSERT (Interface->RefCnt > 0);\r
+\r
+ //\r
+ // Remove all the pending transmit token related to this IP instance.\r
+ //\r
+ Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);\r
+\r
+ if (--Interface->RefCnt > 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Destory the interface if this is the last IP instance that\r
+ // has the address. Remove all the system transmitted packets\r
+ // from this interface, cancel the receive request if there is\r
+ // one, and destory the ARP requests.\r
+ //\r
+ Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);\r
+ Ip4CancelReceive (Interface);\r
+\r
+ ASSERT (NetListIsEmpty (&Interface->IpInstances));\r
+ ASSERT (NetListIsEmpty (&Interface->ArpQues));\r
+ ASSERT (NetListIsEmpty (&Interface->SentFrames));\r
+\r
+ if (Interface->Arp != NULL) {\r
+ gBS->CloseProtocol (\r
+ Interface->ArpHandle,\r
+ &gEfiArpProtocolGuid,\r
+ Interface->Image,\r
+ Interface->Controller\r
+ );\r
+\r
+ NetLibDestroyServiceChild (\r
+ Interface->Controller,\r
+ Interface->Image,\r
+ &gEfiArpServiceBindingProtocolGuid,\r
+ Interface->ArpHandle\r
+ );\r
+ }\r
+\r
+ NetListRemoveEntry (&Interface->Link);\r
+ NetFreePool (Interface);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Callback function when ARP request are finished. It will cancelled\r
+ all the queued frame if the ARP requests failed. Or transmit them\r
+ if the request succeed.\r
+\r
+ @param Event The Arp request event\r
+ @param Context The context of the callback, a point to the ARP\r
+ queue\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Ip4OnArpResolved (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ARP_QUE *ArpQue;\r
+ IP4_INTERFACE *Interface;\r
+ IP4_LINK_TX_TOKEN *Token;\r
+ EFI_STATUS Status;\r
+\r
+ ArpQue = (IP4_ARP_QUE *) Context;\r
+ NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);\r
+\r
+ NetListRemoveEntry (&ArpQue->Link);\r
+\r
+ //\r
+ // ARP resolve failed for some reason. Release all the frame\r
+ // and ARP queue itself. Ip4FreeArpQue will call the frame's\r
+ // owner back.\r
+ //\r
+ if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {\r
+ Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);\r
+\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // ARP resolve succeeded, Transmit all the frame. Release the ARP\r
+ // queue. It isn't necessary for us to cache the ARP binding because\r
+ // we always check the ARP cache first before transmit.\r
+ //\r
+ Interface = ArpQue->Interface;\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {\r
+ NetListRemoveEntry (Entry);\r
+\r
+ Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);\r
+ CopyMem (&Token->DstMac, &ArpQue->Mac, sizeof (EFI_MAC_ADDRESS));\r
+\r
+ Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);\r
+\r
+ Ip4FreeLinkTxToken (Token);\r
+ continue;\r
+ }\r
+\r
+ NetListInsertTail (&Interface->SentFrames, &Token->Link);\r
+ }\r
+\r
+ Ip4FreeArpQue (ArpQue, EFI_SUCCESS);\r
+}\r
+\r
+\r
+/**\r
+ Callback funtion when frame transmission is finished. It will\r
+ call the frame owner's callback function to tell it the result.\r
+\r
+ @param Event The transmit token's event\r
+ @param Context Context which is point to the token.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Ip4OnFrameSent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_LINK_TX_TOKEN *Token;\r
+\r
+ Token = (IP4_LINK_TX_TOKEN *) Context;\r
+ NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);\r
+\r
+ NetListRemoveEntry (&Token->Link);\r
+\r
+ Token->CallBack (\r
+ Token->IpInstance,\r
+ Token->Packet,\r
+ Token->MnpToken.Status,\r
+ 0,\r
+ Token->Context\r
+ );\r
+\r
+ Ip4FreeLinkTxToken (Token);\r
+}\r
+\r
+\r
+\r
+/**\r
+ Send a frame from the interface. If the next hop is broadcast or\r
+ multicast address, it is transmitted immediately. If the next hop\r
+ is a unicast, it will consult ARP to resolve the NextHop's MAC.\r
+ If some error happened, the CallBack won't be called. So, the caller\r
+ must test the return value, and take action when there is an error.\r
+\r
+ @param Interface The interface to send the frame from\r
+ @param IpInstance The IP child that request the transmission. NULL\r
+ if it is the IP4 driver itself.\r
+ @param Packet The packet to transmit.\r
+ @param NextHop The immediate destination to transmit the packet\r
+ to.\r
+ @param CallBack Function to call back when transmit finished.\r
+ @param Context Opaque parameter to the call back.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame\r
+ @retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop\r
+ @retval EFI_SUCCESS The packet is successfully transmitted.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4SendFrame (\r
+ IN IP4_INTERFACE *Interface,\r
+ IN IP4_PROTOCOL *IpInstance, OPTIONAL\r
+ IN NET_BUF *Packet,\r
+ IN IP4_ADDR NextHop,\r
+ IN IP4_FRAME_CALLBACK CallBack,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_LINK_TX_TOKEN *Token;\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_ARP_QUE *ArpQue;\r
+ EFI_ARP_PROTOCOL *Arp;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Interface->Configured);\r
+\r
+ Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);\r
+\r
+ if (Token == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Get the destination MAC address for multicast and broadcasts.\r
+ // Don't depend on ARP to solve the address since there maybe no\r
+ // ARP at all. Ip4Output has set NextHop to 255.255.255.255 for\r
+ // all the broadcasts.\r
+ //\r
+ if (NextHop == IP4_ALLONE_ADDRESS) {\r
+ CopyMem (&Token->DstMac, &Interface->BroadcastMac, sizeof (EFI_MAC_ADDRESS));\r
+ goto SEND_NOW;\r
+\r
+ } else if (IP4_IS_MULTICAST (NextHop)) {\r
+\r
+ Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ goto SEND_NOW;\r
+ }\r
+\r
+ //\r
+ // Can only send out multicast/broadcast if the IP address is zero\r
+ //\r
+ if ((Arp = Interface->Arp) == NULL) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // First check whether this binding is in the ARP cache.\r
+ //\r
+ NextHop = HTONL (NextHop);\r
+ Status = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ goto SEND_NOW;\r
+\r
+ } else if (Status != EFI_NOT_READY) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Have to do asynchronous ARP resolution. First check\r
+ // whether there is already a pending request.\r
+ //\r
+ ArpQue = NULL;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {\r
+ ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);\r
+\r
+ if (ArpQue->Ip == NextHop) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Found a pending ARP request, enqueue the frame then return\r
+ //\r
+ if (Entry != &Interface->ArpQues) {\r
+ NetListInsertTail (&ArpQue->Frames, &Token->Link);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // First frame to NextHop, issue an asynchronous ARP requests\r
+ //\r
+ ArpQue = Ip4CreateArpQue (Interface, NextHop);\r
+\r
+ if (ArpQue == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);\r
+\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
+ Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NetListInsertHead (&ArpQue->Frames, &Token->Link);\r
+ NetListInsertHead (&Interface->ArpQues, &ArpQue->Link);\r
+ return EFI_SUCCESS;\r
+\r
+SEND_NOW:\r
+ Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NetListInsertTail (&Interface->SentFrames, &Token->Link);\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ Ip4FreeLinkTxToken (Token);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Call back function when the received packet is freed.\r
+ Check Ip4OnFrameReceived for information.\r
+\r
+ @param Context Context, which is the IP4_LINK_RX_TOKEN.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4RecycleFrame (\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_LINK_RX_TOKEN *Frame;\r
+\r
+ Frame = (IP4_LINK_RX_TOKEN *) Context;\r
+ NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);\r
+\r
+ gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);\r
+ Ip4FreeFrameRxToken (Frame);\r
+}\r
+\r
+\r
+/**\r
+ Received a frame from MNP, wrap it in net buffer then deliver\r
+ it to IP's input function. The ownship of the packet also\r
+ transferred to IP. When Ip is finished with this packet, it\r
+ will call NetbufFree to release the packet, NetbufFree will\r
+ again call the Ip4RecycleFrame to signal MNP's event and free\r
+ the token used.\r
+\r
+ @param Event The receive event delivered to MNP for receive.\r
+ @param Context Context for the callback.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Ip4OnFrameReceived (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;\r
+ EFI_MANAGED_NETWORK_RECEIVE_DATA *MnpRxData;\r
+ IP4_LINK_RX_TOKEN *Token;\r
+ NET_FRAGMENT Netfrag;\r
+ NET_BUF *Packet;\r
+ UINT32 Flag;\r
+\r
+ Token = (IP4_LINK_RX_TOKEN *) Context;\r
+ NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);\r
+\r
+ //\r
+ // First clear the interface's receive request in case the\r
+ // caller wants to call Ip4ReceiveFrame in the callback.\r
+ //\r
+ Token->Interface->RecvRequest = NULL;\r
+\r
+ MnpToken = &Token->MnpToken;\r
+ MnpRxData = MnpToken->Packet.RxData;\r
+\r
+ if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {\r
+ Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);\r
+ Ip4FreeFrameRxToken (Token);\r
+\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Wrap the frame in a net buffer then deliever it to IP input.\r
+ // IP will reassemble the packet, and deliver it to upper layer\r
+ //\r
+ Netfrag.Len = MnpRxData->DataLength;\r
+ Netfrag.Bulk = MnpRxData->PacketData;\r
+\r
+ Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);\r
+\r
+ if (Packet == NULL) {\r
+ gBS->SignalEvent (MnpRxData->RecycleEvent);\r
+\r
+ Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);\r
+ Ip4FreeFrameRxToken (Token);\r
+\r
+ return ;\r
+ }\r
+\r
+ Flag = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);\r
+ Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);\r
+ Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);\r
+\r
+ Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);\r
+}\r
+\r
+\r
+/**\r
+ Request to receive the packet from the interface.\r
+\r
+ @param Interface The interface to receive the frames from\r
+ @param IpInstance The instance that requests the receive. NULL for\r
+ the driver itself.\r
+ @param CallBack Function to call when receive finished.\r
+ @param Context Opaque parameter to the callback\r
+\r
+ @retval EFI_ALREADY_STARTED There is already a pending receive request.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to receive\r
+ @retval EFI_SUCCESS The recieve request has been started.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4ReceiveFrame (\r
+ IN IP4_INTERFACE *Interface,\r
+ IN IP4_PROTOCOL *IpInstance, OPTIONAL\r
+ IN IP4_FRAME_CALLBACK CallBack,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_LINK_RX_TOKEN *Token;\r
+ EFI_STATUS Status;\r
+\r
+ NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);\r
+\r
+ if (Interface->RecvRequest != NULL) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);\r
+\r
+ if (Token == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Ip4FreeFrameRxToken (Token);\r
+ return Status;\r
+ }\r
+\r
+ Interface->RecvRequest = Token;\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Ip4If.h
+
+Abstract:
+
+ Definition for IP4 pesudo interface structure.
+
+
+**/
+
+#ifndef __EFI_IP4_IF_H__
+#define __EFI_IP4_IF_H__
+
+enum {
+ IP4_FRAME_RX_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', 'F', 'R'),
+ IP4_FRAME_TX_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', 'F', 'T'),
+ IP4_FRAME_ARP_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', 'F', 'A'),
+ IP4_INTERFACE_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', 'I', 'F'),
+};
+
+//
+// This prototype is used by both receive and transmission.
+// When receiving Netbuf is allocated by IP4_INTERFACE, and
+// released by IP4. Flag shows whether the frame is received
+// as link broadcast/multicast...
+//
+// When transmitting, the Netbuf is from IP4, and provided
+// to the callback as a reference. Flag isn't used.
+//
+// IpInstance can be NULL which means that it is the IP4 driver
+// itself sending the packets. IP4 driver may send packets that
+// don't belong to any instance, such as ICMP errors, ICMP echo
+// responses, or IGMP packets. IpInstance is used as a tag in
+// this module.
+//
+typedef
+VOID
+(*IP4_FRAME_CALLBACK) (
+ IP4_PROTOCOL *IpInstance, OPTIONAL
+ NET_BUF *Packet,
+ EFI_STATUS IoStatus,
+ UINT32 LinkFlag,
+ VOID *Context
+ );
+
+//
+// Each receive request is wrapped in an IP4_LINK_RX_TOKEN.
+// Upon completion, the Callback will be called. Only one
+// receive request is send to MNP. IpInstance is always NULL.
+// Reference MNP's spec for information.
+//
+typedef struct {
+ UINT32 Signature;
+ IP4_INTERFACE *Interface;
+
+ IP4_PROTOCOL *IpInstance;
+ IP4_FRAME_CALLBACK CallBack;
+ VOID *Context;
+
+ EFI_MANAGED_NETWORK_COMPLETION_TOKEN MnpToken;
+} IP4_LINK_RX_TOKEN;
+
+//
+// Each transmit request is wrapped in an IP4_LINK_TX_TOKEN.
+// Upon completion, the Callback will be called.
+//
+typedef struct {
+ UINT32 Signature;
+ NET_LIST_ENTRY Link;
+
+ IP4_INTERFACE *Interface;
+
+ IP4_PROTOCOL *IpInstance;
+ IP4_FRAME_CALLBACK CallBack;
+ NET_BUF *Packet;
+ VOID *Context;
+
+ EFI_MAC_ADDRESS DstMac;
+ EFI_MAC_ADDRESS SrcMac;
+
+ EFI_MANAGED_NETWORK_COMPLETION_TOKEN MnpToken;
+ EFI_MANAGED_NETWORK_TRANSMIT_DATA MnpTxData;
+} IP4_LINK_TX_TOKEN;
+
+//
+// Only one ARP request is requested for all the frames in
+// a time. It is started for the first frames to the Ip. Any
+// subsequent transmission frame will be linked to Frames, and
+// be sent all at once the ARP requests succeed.
+//
+typedef struct {
+ UINT32 Signature;
+ NET_LIST_ENTRY Link;
+
+ NET_LIST_ENTRY Frames;
+ IP4_INTERFACE *Interface;
+
+ //
+ // ARP requesting staffs
+ //
+ EFI_EVENT OnResolved;
+ IP4_ADDR Ip;
+ EFI_MAC_ADDRESS Mac;
+} IP4_ARP_QUE;
+
+//
+// Callback to select which frame to cancel. Caller can cancel a
+// single frame, or all the frame from an IP instance.
+//
+typedef
+BOOLEAN
+(*IP4_FRAME_TO_CANCEL) (
+ IP4_LINK_TX_TOKEN *Frame,
+ VOID *Context
+ );
+
+//
+// Each IP4 instance has its own station address. All the instances
+// with the same station address share a single interface structure.
+// Each interface has its own ARP child, and shares one MNP child.
+// Notice the special cases that DHCP can configure the interface
+// with 0.0.0.0/0.0.0.0.
+//
+typedef struct _IP4_INTERFACE {
+ UINT32 Signature;
+ NET_LIST_ENTRY Link;
+ INTN RefCnt;
+
+ //
+ // IP address and subnet mask of the interface. It also contains
+ // the subnet/net broadcast address for quick access. The fileds
+ // are invalid if (Configured == FALSE)
+ //
+ IP4_ADDR Ip;
+ IP4_ADDR SubnetMask;
+ IP4_ADDR SubnetBrdcast;
+ IP4_ADDR NetBrdcast;
+ BOOLEAN Configured;
+
+ //
+ // Handle used to create/destory ARP child. All the IP children
+ // share one MNP which is owned by IP service binding.
+ //
+ EFI_HANDLE Controller;
+ EFI_HANDLE Image;
+
+ EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
+ EFI_ARP_PROTOCOL *Arp;
+ EFI_HANDLE ArpHandle;
+
+ //
+ // Queues to keep the frames sent and waiting ARP request.
+ //
+ NET_LIST_ENTRY ArpQues;
+ NET_LIST_ENTRY SentFrames;
+ IP4_LINK_RX_TOKEN *RecvRequest;
+
+ //
+ // The interface's MAC and broadcast MAC address.
+ //
+ EFI_MAC_ADDRESS Mac;
+ EFI_MAC_ADDRESS BroadcastMac;
+ UINT32 HwaddrLen;
+
+ //
+ // All the IP instances that have the same IP/SubnetMask are linked
+ // together through IpInstances. If any of the instance enables
+ // promiscuous receive, PromiscRecv is true.
+ //
+ NET_LIST_ENTRY IpInstances;
+ BOOLEAN PromiscRecv;
+} IP4_INTERFACE;
+
+IP4_INTERFACE *
+Ip4CreateInterface (
+ IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ImageHandle
+ );
+
+EFI_STATUS
+Ip4SetAddress (
+ IN IP4_INTERFACE *Interface,
+ IN IP4_ADDR IpAddr,
+ IN IP4_ADDR SubnetMask
+ );
+
+EFI_STATUS
+Ip4FreeInterface (
+ IN IP4_INTERFACE *Interface,
+ IN IP4_PROTOCOL *IpInstance OPTIONAL
+ );
+
+EFI_STATUS
+Ip4SendFrame (
+ IN IP4_INTERFACE *Interface,
+ IN IP4_PROTOCOL *IpInstance, OPTIONAL
+ IN NET_BUF *Packet,
+ IN IP4_ADDR NextHop,
+ IN IP4_FRAME_CALLBACK CallBack,
+ IN VOID *Context
+ );
+
+VOID
+Ip4CancelFrames (
+ IN IP4_INTERFACE *Interface,
+ IN EFI_STATUS IoStatus,
+ IN IP4_FRAME_TO_CANCEL FrameToCancel, OPTIONAL
+ IN VOID *Context
+ );
+
+VOID
+Ip4CancelReceive (
+ IN IP4_INTERFACE *Interface
+ );
+
+EFI_STATUS
+Ip4ReceiveFrame (
+ IN IP4_INTERFACE *Interface,
+ IN IP4_PROTOCOL *IpInstance, OPTIONAL
+ IN IP4_FRAME_CALLBACK CallBack,
+ IN VOID *Context
+ );
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Ip4Igmp.c\r
+\r
+Abstract:\r
+\r
+ This file implements the RFC2236: IGMP v2\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+//\r
+// Route Alert option in IGMP report to direct routers to\r
+// examine the packet more closely.\r
+//\r
+UINT32 mRouteAlertOption = 0x00000494;\r
+\r
+\r
+/**\r
+ Init the IGMP control data of the IP4 service instance, configure\r
+ MNP to receive ALL SYSTEM multicast.\r
+\r
+ @param IpSb The IP4 service whose IGMP is to be initialized.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to initialize IGMP.\r
+ @retval Others Failed to initialize the IGMP of IpSb.\r
+ @retval EFI_SUCCESS IGMP of the IpSb is successfully initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4InitIgmp (\r
+ IN IP4_SERVICE *IpSb\r
+ )\r
+{\r
+ IGMP_SERVICE_DATA *IgmpCtrl;\r
+ EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
+ IGMP_GROUP *Group;\r
+ EFI_STATUS Status;\r
+\r
+ IgmpCtrl = &IpSb->IgmpCtrl;\r
+\r
+ //\r
+ // Configure MNP to receive ALL_SYSTEM multicast\r
+ //\r
+ Group = NetAllocatePool (sizeof (IGMP_GROUP));\r
+\r
+ if (Group == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Mnp = IpSb->Mnp;\r
+\r
+ Group->Address = IP4_ALLSYSTEM_ADDRESS;\r
+ Group->RefCnt = 1;\r
+ Group->DelayTime = 0;\r
+ Group->ReportByUs = FALSE;\r
+\r
+ Status = Ip4GetMulticastMac (Mnp, IP4_ALLSYSTEM_ADDRESS, &Group->Mac);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = Mnp->Groups (Mnp, TRUE, &Group->Mac);\r
+\r
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NetListInsertHead (&IgmpCtrl->Groups, &Group->Link);\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ NetFreePool (Group);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Find the IGMP_GROUP structure which contains the status of multicast\r
+ group Address in this IGMP control block\r
+\r
+ @param IgmpCtrl The IGMP control block to search from\r
+ @param Address The multicast address to search\r
+\r
+ @return NULL if the multicast address isn't in the IGMP control block. Otherwise\r
+ @return the point to the IGMP_GROUP which contains the status of multicast group\r
+ @return for Address.\r
+\r
+**/\r
+IGMP_GROUP *\r
+Ip4FindGroup (\r
+ IN IGMP_SERVICE_DATA *IgmpCtrl,\r
+ IN IP4_ADDR Address\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IGMP_GROUP *Group;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {\r
+ Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);\r
+\r
+ if (Group->Address == Address) {\r
+ return Group;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Count the number of IP4 multicast groups that are mapped to the\r
+ same MAC address. Several IP4 multicast address may be mapped to\r
+ the same MAC address.\r
+\r
+ @param IgmpCtrl The IGMP control block to search in\r
+ @param Mac The MAC address to search\r
+\r
+ @return The number of the IP4 multicast group that mapped to the same\r
+ @return multicast group Mac.\r
+\r
+**/\r
+INTN\r
+Ip4FindMac (\r
+ IN IGMP_SERVICE_DATA *IgmpCtrl,\r
+ IN EFI_MAC_ADDRESS *Mac\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IGMP_GROUP *Group;\r
+ INTN Count;\r
+\r
+ Count = 0;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {\r
+ Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);\r
+\r
+ if (NET_MAC_EQUAL (&Group->Mac, Mac, sizeof (EFI_MAC_ADDRESS))) {\r
+ Count++;\r
+ }\r
+ }\r
+\r
+ return Count;\r
+}\r
+\r
+\r
+/**\r
+ Send an IGMP protocol message to the Dst, such as IGMP v1 membership report.\r
+\r
+ @param IpSb The IP4 service instance that requests the\r
+ transmission\r
+ @param Dst The destinaton to send to\r
+ @param Type The IGMP message type, such as IGMP v2 membership\r
+ report\r
+ @param Group The group address in the IGMP message head.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to build the message\r
+ @retval EFI_SUCCESS The IGMP message is successfully send\r
+ @retval Others Failed to send the IGMP message.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4SendIgmpMessage (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Dst,\r
+ IN UINT8 Type,\r
+ IN IP4_ADDR Group\r
+ )\r
+{\r
+ IP4_HEAD Head;\r
+ NET_BUF *Packet;\r
+ IGMP_HEAD *Igmp;\r
+\r
+ //\r
+ // Allocate a net buffer to hold the message\r
+ //\r
+ Packet = NetbufAlloc (IP4_MAX_HEADLEN + sizeof (IGMP_HEAD));\r
+\r
+ if (Packet == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Fill in the IGMP and IP header, then transmit the message\r
+ //\r
+ NetbufReserve (Packet, IP4_MAX_HEADLEN);\r
+\r
+ Igmp = (IGMP_HEAD *) NetbufAllocSpace (Packet, sizeof (IGMP_HEAD), FALSE);\r
+\r
+ Igmp->Type = Type;\r
+ Igmp->MaxRespTime = 0;\r
+ Igmp->Checksum = 0;\r
+ Igmp->Group = HTONL (Group);\r
+ Igmp->Checksum = ~NetblockChecksum ((UINT8 *) Igmp, sizeof (IGMP_HEAD));\r
+\r
+ Head.Tos = 0;\r
+ Head.Protocol = IP4_PROTO_IGMP;\r
+ Head.Ttl = 1;\r
+ Head.Fragment = 0;\r
+ Head.Dst = Dst;\r
+ Head.Src = IP4_ALLZERO_ADDRESS;\r
+\r
+ return Ip4Output (\r
+ IpSb,\r
+ NULL,\r
+ Packet,\r
+ &Head,\r
+ (UINT8 *) &mRouteAlertOption,\r
+ sizeof (UINT32),\r
+ IP4_ALLZERO_ADDRESS,\r
+ Ip4SysPacketSent,\r
+ NULL\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Send an IGMP membership report. Depends on whether the server is\r
+ v1 or v2, it will send either a V1 or V2 membership report.\r
+\r
+ @param IpSb The IP4 service instance that requests the\r
+ transmission.\r
+ @param Group The group address to report\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to build the message\r
+ @retval EFI_SUCCESS The IGMP report message is successfully send\r
+ @retval Others Failed to send the report.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4SendIgmpReport (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Group\r
+ )\r
+{\r
+ if (IpSb->IgmpCtrl.Igmpv1QuerySeen != 0) {\r
+ return Ip4SendIgmpMessage (IpSb, Group, IGMP_V1_MEMBERSHIP_REPORT, Group);\r
+ } else {\r
+ return Ip4SendIgmpMessage (IpSb, Group, IGMP_V2_MEMBERSHIP_REPORT, Group);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Join the multicast group on behavior of this IP4 child\r
+\r
+ @param IpInstance The IP4 child that wants to join the group\r
+ @param Address The group to join\r
+\r
+ @retval EFI_SUCCESS Successfully join the multicast group\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources\r
+ @retval Others Failed to join the multicast group.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4JoinGroup (\r
+ IN IP4_PROTOCOL *IpInstance,\r
+ IN IP4_ADDR Address\r
+ )\r
+{\r
+ EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
+ IP4_SERVICE *IpSb;\r
+ IGMP_SERVICE_DATA *IgmpCtrl;\r
+ IGMP_GROUP *Group;\r
+ EFI_STATUS Status;\r
+\r
+ IpSb = IpInstance->Service;\r
+ IgmpCtrl = &IpSb->IgmpCtrl;\r
+ Mnp = IpSb->Mnp;\r
+\r
+ //\r
+ // If the IP service already is a member in the group, just\r
+ // increase the refernce count and return.\r
+ //\r
+ Group = Ip4FindGroup (IgmpCtrl, Address);\r
+\r
+ if (Group != NULL) {\r
+ Group->RefCnt++;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Otherwise, create a new IGMP_GROUP, Get the multicast's MAC address,\r
+ // send a report, then direct MNP to receive the multicast.\r
+ //\r
+ Group = NetAllocatePool (sizeof (IGMP_GROUP));\r
+\r
+ if (Group == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Group->Address = Address;\r
+ Group->RefCnt = 1;\r
+ Group->DelayTime = IGMP_UNSOLICIATED_REPORT;\r
+ Group->ReportByUs = TRUE;\r
+\r
+ Status = Ip4GetMulticastMac (Mnp, Address, &Group->Mac);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = Ip4SendIgmpReport (IpSb, Address);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = Mnp->Groups (Mnp, TRUE, &Group->Mac);\r
+\r
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NetListInsertHead (&IgmpCtrl->Groups, &Group->Link);\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ NetFreePool (Group);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Leave the IP4 multicast group on behavior of IpInstance.\r
+\r
+ @param IpInstance The IP4 child that wants to leave the group\r
+ address\r
+ @param Address The group address to leave\r
+\r
+ @retval EFI_NOT_FOUND The IP4 service instance isn't in the group\r
+ @retval EFI_SUCCESS Successfully leave the multicast group.\r
+ @retval Others Failed to leave the multicast group.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4LeaveGroup (\r
+ IN IP4_PROTOCOL *IpInstance,\r
+ IN IP4_ADDR Address\r
+ )\r
+{\r
+ EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
+ IP4_SERVICE *IpSb;\r
+ IGMP_SERVICE_DATA *IgmpCtrl;\r
+ IGMP_GROUP *Group;\r
+ EFI_STATUS Status;\r
+\r
+ IpSb = IpInstance->Service;\r
+ IgmpCtrl = &IpSb->IgmpCtrl;\r
+ Mnp = IpSb->Mnp;\r
+\r
+ Group = Ip4FindGroup (IgmpCtrl, Address);\r
+\r
+ if (Group == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // If more than one instance is in the group, decrease\r
+ // the RefCnt then return.\r
+ //\r
+ if (--Group->RefCnt > 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // If multiple IP4 group addresses are mapped to the same\r
+ // multicast MAC address, don't configure the MNP to leave\r
+ // the MAC.\r
+ //\r
+ if (Ip4FindMac (IgmpCtrl, &Group->Mac) == 1) {\r
+ Status = Mnp->Groups (Mnp, FALSE, &Group->Mac);\r
+\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Send a leave report if the membership is reported by us\r
+ // and we are talking IGMPv2.\r
+ //\r
+ if (Group->ReportByUs && !IgmpCtrl->Igmpv1QuerySeen) {\r
+ Ip4SendIgmpMessage (IpSb, IP4_ALLROUTER_ADDRESS, IGMP_LEAVE_GROUP, Group->Address);\r
+ }\r
+\r
+ NetListRemoveEntry (&Group->Link);\r
+ NetFreePool (Group);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Handle the received IGMP message for the IP4 service instance.\r
+\r
+ @param IpSb The IP4 service instance that received the message\r
+ @param Head The IP4 header of the received message\r
+ @param Packet The IGMP message, without IP4 header\r
+\r
+ @retval EFI_INVALID_PARAMETER The IGMP message is malformated.\r
+ @retval EFI_SUCCESS The IGMP message is successfully processed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4IgmpHandle (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_HEAD *Head,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ IGMP_SERVICE_DATA *IgmpCtrl;\r
+ IGMP_HEAD Igmp;\r
+ IGMP_GROUP *Group;\r
+ IP4_ADDR Address;\r
+ NET_LIST_ENTRY *Entry;\r
+\r
+ IgmpCtrl = &IpSb->IgmpCtrl;\r
+\r
+ //\r
+ // Must checksum over the whole packet, later IGMP version\r
+ // may employ message longer than 8 bytes. IP's header has\r
+ // already been trimmed off.\r
+ //\r
+ if ((Packet->TotalSize < sizeof (Igmp)) || (NetbufChecksum (Packet) != 0)) {\r
+ NetbufFree (Packet);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Copy the packet in case it is fragmented\r
+ //\r
+ NetbufCopy (Packet, 0, sizeof (IGMP_HEAD), (UINT8 *)&Igmp);\r
+\r
+ switch (Igmp.Type) {\r
+ case IGMP_MEMBERSHIP_QUERY:\r
+ //\r
+ // If MaxRespTIme is zero, it is most likely that we are\r
+ // talking to a V1 router\r
+ //\r
+ if (Igmp.MaxRespTime == 0) {\r
+ IgmpCtrl->Igmpv1QuerySeen = IGMP_V1ROUTER_PRESENT;\r
+ Igmp.MaxRespTime = 100;\r
+ }\r
+\r
+ //\r
+ // Igmp is ticking once per second but MaxRespTime is in\r
+ // the unit of 100ms.\r
+ //\r
+ Igmp.MaxRespTime /= 10;\r
+ Address = NTOHL (Igmp.Group);\r
+\r
+ if (Address == IP4_ALLSYSTEM_ADDRESS) {\r
+ break;\r
+ }\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {\r
+ Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);\r
+\r
+ //\r
+ // If address is all zero, all the memberships will be reported.\r
+ // otherwise only one is reported.\r
+ //\r
+ if ((Address == IP4_ALLZERO_ADDRESS) || (Address == Group->Address)) {\r
+ //\r
+ // If the timer is pending, only update it if the time left\r
+ // is longer than the MaxRespTime. TODO: randomize the DelayTime.\r
+ //\r
+ if ((Group->DelayTime == 0) || (Group->DelayTime > Igmp.MaxRespTime)) {\r
+ Group->DelayTime = NET_MAX (1, Igmp.MaxRespTime);\r
+ }\r
+ }\r
+ }\r
+\r
+ break;\r
+\r
+ case IGMP_V1_MEMBERSHIP_REPORT:\r
+ case IGMP_V2_MEMBERSHIP_REPORT:\r
+ Address = NTOHL (Igmp.Group);\r
+ Group = Ip4FindGroup (IgmpCtrl, Address);\r
+\r
+ if ((Group != NULL) && (Group->DelayTime > 0)) {\r
+ Group->DelayTime = 0;\r
+ Group->ReportByUs = FALSE;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ NetbufFree (Packet);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ The periodical timer function for IGMP. It does the following\r
+ things:\r
+ 1. Decrease the Igmpv1QuerySeen to make it possible to refresh\r
+ the IGMP server type.\r
+ 2. Decrease the report timer for each IGMP group in "delaying\r
+ member" state.\r
+\r
+ @param IpSb The IP4 service instance that is ticking\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4IgmpTicking (\r
+ IN IP4_SERVICE *IpSb\r
+ )\r
+{\r
+ IGMP_SERVICE_DATA *IgmpCtrl;\r
+ NET_LIST_ENTRY *Entry;\r
+ IGMP_GROUP *Group;\r
+\r
+ IgmpCtrl = &IpSb->IgmpCtrl;\r
+\r
+ if (IgmpCtrl->Igmpv1QuerySeen > 0) {\r
+ IgmpCtrl->Igmpv1QuerySeen--;\r
+ }\r
+\r
+ //\r
+ // Decrease the report timer for each IGMP group in "delaying member"\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {\r
+ Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);\r
+ ASSERT (Group->DelayTime >= 0);\r
+\r
+ if (Group->DelayTime > 0) {\r
+ Group->DelayTime--;\r
+\r
+ if (Group->DelayTime == 0) {\r
+ Ip4SendIgmpReport (IpSb, Group->Address);\r
+ Group->ReportByUs = TRUE;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Add a group address to the array of group addresses.\r
+ The caller should make sure that no duplicated address\r
+ existed in the array. Although the function doesn't\r
+ assume the byte order of the both Source and Addr, the\r
+ network byte order is used by the caller.\r
+\r
+ @param Source The array of group addresses to add to\r
+ @param Count The number of group addresses in the Source\r
+ @param Addr The IP4 multicast address to add\r
+\r
+ @return NULL if failed to allocate memory for the new groups,\r
+ @return otherwise the new combined group addresses.\r
+\r
+**/\r
+IP4_ADDR *\r
+Ip4CombineGroups (\r
+ IN IP4_ADDR *Source,\r
+ IN UINT32 Count,\r
+ IN IP4_ADDR Addr\r
+ )\r
+{\r
+ IP4_ADDR *Groups;\r
+\r
+ Groups = NetAllocatePool (sizeof (IP4_ADDR) * (Count + 1));\r
+\r
+ if (Groups == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetCopyMem (Groups, Source, Count * sizeof (IP4_ADDR));\r
+ Groups[Count] = Addr;\r
+\r
+ return Groups;\r
+}\r
+\r
+\r
+/**\r
+ Remove a group address frome the array of group addresses.\r
+ Although the function doesn't assume the byte order of the\r
+ both Groups and Addr, the network byte order is used by\r
+ the caller.\r
+\r
+ @param Groups The array of group addresses to remove from\r
+ @param Count The number of group addresses in the Groups\r
+ @param Addr The IP4 multicast address to remove\r
+\r
+ @return The nubmer of group addresses in the Groups after remove.\r
+ @return It is Count if the Addr isn't in the Groups.\r
+\r
+**/\r
+INTN\r
+Ip4RemoveGroupAddr (\r
+ IN IP4_ADDR *Groups,\r
+ IN UINT32 Count,\r
+ IN IP4_ADDR Addr\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < Count; Index++) {\r
+ if (Groups[Index] == Addr) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ while (Index < Count - 1) {\r
+ Groups[Index] = Groups[Index + 1];\r
+ Index++;\r
+ }\r
+\r
+ return Index;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Ip4Igmp.h
+
+Abstract:
+
+
+**/
+
+#ifndef __EFI_IP4_IGMP_H__
+#define __EFI_IP4_IGMP_H__
+
+#pragma pack(1)
+typedef struct {
+ UINT8 Type;
+ UINT8 MaxRespTime;
+ UINT16 Checksum;
+ IP4_ADDR Group;
+} IGMP_HEAD;
+#pragma pack()
+
+//
+// The status of multicast group. It isn't necessary to maintain
+// explicit state of host state diagram. A group with non-zero
+// DelayTime is in "delaying member" state. otherwise, it is in
+// "idle member" state.
+//
+typedef struct {
+ NET_LIST_ENTRY Link;
+ INTN RefCnt;
+ IP4_ADDR Address;
+ INTN DelayTime;
+ BOOLEAN ReportByUs;
+ EFI_MAC_ADDRESS Mac;
+} IGMP_GROUP;
+
+//
+// The IGMP status. Each IP4 service instance has a IGMP_SERVICE_DATA
+// attached. The Igmpv1QuerySeen remember whether the server on this
+// connected network is v1 or v2.
+//
+typedef struct {
+ INTN Igmpv1QuerySeen;
+ NET_LIST_ENTRY Groups;
+} IGMP_SERVICE_DATA;
+
+enum {
+ //
+ // IGMP message type
+ //
+ IGMP_MEMBERSHIP_QUERY = 0x11,
+ IGMP_V1_MEMBERSHIP_REPORT = 0x12,
+ IGMP_V2_MEMBERSHIP_REPORT = 0x16,
+ IGMP_LEAVE_GROUP = 0x17,
+
+ IGMP_V1ROUTER_PRESENT = 400,
+ IGMP_UNSOLICIATED_REPORT = 10,
+};
+
+EFI_STATUS
+Ip4InitIgmp (
+ IN IP4_SERVICE *IpService
+ );
+
+EFI_STATUS
+Ip4JoinGroup (
+ IN IP4_PROTOCOL *IpInstance,
+ IN IP4_ADDR Address
+ );
+
+EFI_STATUS
+Ip4LeaveGroup (
+ IN IP4_PROTOCOL *IpInstance,
+ IN IP4_ADDR Address
+ );
+
+EFI_STATUS
+Ip4IgmpHandle (
+ IN IP4_SERVICE *IpService,
+ IN IP4_HEAD *Head,
+ IN NET_BUF *Packet
+ );
+
+VOID
+Ip4IgmpTicking (
+ IN IP4_SERVICE *IpService
+ );
+
+IP4_ADDR *
+Ip4CombineGroups (
+ IN IP4_ADDR *SourceGroups,
+ IN UINT32 Count,
+ IN IP4_ADDR Addr
+ );
+
+INTN
+Ip4RemoveGroupAddr (
+ IN IP4_ADDR *Group,
+ IN UINT32 GroupCnt,
+ IN IP4_ADDR Addr
+ );
+
+IGMP_GROUP *
+Ip4FindGroup (
+ IN IGMP_SERVICE_DATA *IgmpCtrl,
+ IN IP4_ADDR Address
+ );
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Ip4Impl.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+\r
+/**\r
+ Get the IP child's current operational data. This can\r
+ all be used to get the underlying MNP and SNP data.\r
+\r
+ @param This The IP4 protocol instance\r
+ @param Ip4ModeData The IP4 operation data\r
+ @param MnpConfigData The MNP configure data\r
+ @param SnpModeData The SNP operation data\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameter is invalid because This == NULL\r
+ @retval EFI_SUCCESS The operational parameter is returned.\r
+ @retval Others Failed to retrieve the IP4 route table.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4GetModeData (\r
+ IN CONST EFI_IP4_PROTOCOL *This,\r
+ OUT EFI_IP4_MODE_DATA *Ip4ModeData, OPTIONAL\r
+ OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData, OPTIONAL\r
+ OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL\r
+ )\r
+{\r
+ IP4_PROTOCOL *IpInstance;\r
+ IP4_SERVICE *IpSb;\r
+ EFI_IP4_CONFIG_DATA *Config;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+ IP4_ADDR Ip;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
+ IpSb = IpInstance->Service;\r
+\r
+ if (Ip4ModeData != NULL) {\r
+ //\r
+ // IsStarted is "whether the EfiIp4Configure has been called".\r
+ // IsConfigured is "whether the station address has been configured"\r
+ //\r
+ Ip4ModeData->IsStarted = (BOOLEAN)(IpInstance->State == IP4_STATE_CONFIGED);\r
+ CopyMem (&Ip4ModeData->ConfigData, &IpInstance->ConfigData, sizeof (EFI_IP4_CONFIG_DATA));\r
+ Ip4ModeData->IsConfigured = FALSE;\r
+\r
+ Ip4ModeData->GroupCount = IpInstance->GroupCount;\r
+ Ip4ModeData->GroupTable = (EFI_IPv4_ADDRESS *) IpInstance->Groups;\r
+\r
+ Ip4ModeData->IcmpTypeCount = 23;\r
+ Ip4ModeData->IcmpTypeList = mIp4SupportedIcmp;\r
+\r
+ Ip4ModeData->RouteTable = NULL;\r
+ Ip4ModeData->RouteCount = 0;\r
+\r
+ //\r
+ // return the current station address for this IP child. So,\r
+ // the user can get the default address through this. Some\r
+ // application wants to know it station address even it is\r
+ // using the default one, such as a ftp server.\r
+ //\r
+ if (Ip4ModeData->IsStarted) {\r
+ Config = &Ip4ModeData->ConfigData;\r
+\r
+ Ip = HTONL (IpInstance->Interface->Ip);\r
+ NetCopyMem (&Config->StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ Ip = HTONL (IpInstance->Interface->SubnetMask);\r
+ NetCopyMem (&Config->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ Ip4ModeData->IsConfigured = IpInstance->Interface->Configured;\r
+\r
+ //\r
+ // Build a EFI route table for user from the internal route table.\r
+ //\r
+ Status = Ip4BuildEfiRouteTable (IpInstance);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+ }\r
+\r
+ Ip4ModeData->RouteTable = IpInstance->EfiRouteTable;\r
+ Ip4ModeData->RouteCount = IpInstance->EfiRouteCount;\r
+ }\r
+ }\r
+\r
+ if (MnpConfigData != NULL) {\r
+ CopyMem (MnpConfigData, &IpSb->MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA));\r
+ }\r
+\r
+ if (SnpModeData != NULL) {\r
+ CopyMem (SnpModeData, &IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));\r
+ }\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Config the MNP parameter used by IP. The IP driver use one MNP\r
+ child to transmit/receive frames. By default, it configures MNP\r
+ to receive unicast/multicast/broadcast. And it will enable/disable\r
+ the promiscous receive according to whether there is IP child\r
+ enable that or not. If Force isn't false, it will iterate through\r
+ all the IP children to check whether the promiscuous receive\r
+ setting has been changed. If it hasn't been changed, it won't\r
+ reconfigure the MNP. If Force is true, the MNP is configured no\r
+ matter whether that is changed or not.\r
+\r
+ @param IpSb The IP4 service instance that is to be changed.\r
+ @param Force Force the configuration or not.\r
+\r
+ @retval EFI_SUCCESS The MNP is successfully configured/reconfigured.\r
+ @retval Others Configuration failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4ServiceConfigMnp (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN BOOLEAN Force\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *ProtoEntry;\r
+ IP4_INTERFACE *IpIf;\r
+ IP4_PROTOCOL *IpInstance;\r
+ BOOLEAN Reconfig;\r
+ BOOLEAN PromiscReceive;\r
+ EFI_STATUS Status;\r
+\r
+ Reconfig = FALSE;\r
+ PromiscReceive = FALSE;\r
+\r
+ if (!Force) {\r
+ //\r
+ // Iterate through the IP children to check whether promiscuous\r
+ // receive setting has been changed. Update the interface's receive\r
+ // filter also.\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+ IpIf->PromiscRecv = FALSE;\r
+\r
+ NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {\r
+ IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP4_PROTOCOL, AddrLink);\r
+\r
+ if (IpInstance->ConfigData.AcceptPromiscuous) {\r
+ IpIf->PromiscRecv = TRUE;\r
+ PromiscReceive = TRUE;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // If promiscuous receive isn't changed, it isn't necessary to reconfigure.\r
+ //\r
+ if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Reconfig = TRUE;\r
+ IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;\r
+ }\r
+\r
+ Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);\r
+\r
+ //\r
+ // recover the original configuration if failed to set the configure.\r
+ //\r
+ if (EFI_ERROR (Status) && Reconfig) {\r
+ IpSb->MnpConfigData.EnablePromiscuousReceive = !PromiscReceive;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ The event handle for IP4 auto configuration. If IP is asked\r
+ to reconfigure the default address. The original default\r
+ interface and route table are removed as the default. If there\r
+ is active IP children using the default address, the interface\r
+ will remain valid until all the children have freed their\r
+ references. If IP is signalled when auto configuration is done,\r
+ it will configure the default interface and default route table\r
+ with the configuration information retrieved by IP4_CONFIGURE.\r
+\r
+ @param Event The event that is signalled.\r
+ @param Context The IP4 service binding instance.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ip4AutoConfigCallBack (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_IP4_CONFIG_PROTOCOL *Ip4Config;\r
+ EFI_IP4_IPCONFIG_DATA *Data;\r
+ EFI_IP4_ROUTE_TABLE *RouteEntry;\r
+ IP4_SERVICE *IpSb;\r
+ IP4_ROUTE_TABLE *RouteTable;\r
+ IP4_INTERFACE *IpIf;\r
+ EFI_STATUS Status;\r
+ UINTN Len;\r
+ UINT32 Index;\r
+\r
+ IpSb = (IP4_SERVICE *) Context;\r
+ NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
+\r
+ Ip4Config = IpSb->Ip4Config;\r
+\r
+ //\r
+ // IP is asked to do the reconfiguration. If the default interface\r
+ // has been configured, release the default interface and route\r
+ // table, then create a new one. If there are some IP children\r
+ // using it, the interface won't be physically freed until all the\r
+ // children have released their reference to it. Also remember to\r
+ // restart the receive on the default address. IP4 driver only receive\r
+ // frames on the default address, and when the default interface is\r
+ // freed, Ip4AcceptFrame won't be informed.\r
+ //\r
+ if (Event == IpSb->ReconfigEvent) {\r
+\r
+ if (IpSb->DefaultInterface->Configured) {\r
+ IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
+\r
+ if (IpIf == NULL) {\r
+ return;\r
+ }\r
+\r
+ RouteTable = Ip4CreateRouteTable ();\r
+\r
+ if (RouteTable == NULL) {\r
+ Ip4FreeInterface (IpIf, NULL);\r
+ return;\r
+ }\r
+\r
+ Ip4CancelReceive (IpSb->DefaultInterface);\r
+ Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
+ Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
+\r
+ IpSb->DefaultInterface = IpIf;\r
+ NetListInsertHead (&IpSb->Interfaces, &IpIf->Link);\r
+\r
+ IpSb->DefaultRouteTable = RouteTable;\r
+ Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);\r
+ }\r
+\r
+ Ip4Config->Stop (Ip4Config);\r
+ Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Get the configure data in two steps: get the length then the data.\r
+ //\r
+ Len = 0;\r
+\r
+ if (Ip4Config->GetData (Ip4Config, &Len, NULL) != EFI_BUFFER_TOO_SMALL) {\r
+ return ;\r
+ }\r
+\r
+ Data = NetAllocatePool (Len);\r
+\r
+ if (Data == NULL) {\r
+ return ;\r
+ }\r
+\r
+ Status = Ip4Config->GetData (Ip4Config, &Len, Data);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ IpIf = IpSb->DefaultInterface;\r
+\r
+ //\r
+ // If the default address has been configured don't change it.\r
+ // This is unlikely to happen if EFI_IP4_CONFIG protocol has\r
+ // informed us to reconfigure each time it wants to change the\r
+ // configuration parameters.\r
+ //\r
+ if (IpIf->Configured) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Set the default interface's address, then add a directed\r
+ // route for it, that is, the route whose nexthop is zero.\r
+ //\r
+ Status = Ip4SetAddress (\r
+ IpIf,\r
+ EFI_NTOHL (Data->StationAddress),\r
+ EFI_NTOHL (Data->SubnetMask)\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Ip4AddRoute (\r
+ IpSb->DefaultRouteTable,\r
+ EFI_NTOHL (Data->StationAddress),\r
+ EFI_NTOHL (Data->SubnetMask),\r
+ IP4_ALLZERO_ADDRESS\r
+ );\r
+\r
+ //\r
+ // Add routes returned by EFI_IP4_CONFIG protocol.\r
+ //\r
+ for (Index = 0; Index < Data->RouteTableSize; Index++) {\r
+ RouteEntry = &Data->RouteTable[Index];\r
+\r
+ Ip4AddRoute (\r
+ IpSb->DefaultRouteTable,\r
+ EFI_NTOHL (RouteEntry->SubnetAddress),\r
+ EFI_NTOHL (RouteEntry->SubnetMask),\r
+ EFI_NTOHL (RouteEntry->GatewayAddress)\r
+ );\r
+ }\r
+\r
+ IpSb->State = IP4_SERVICE_CONFIGED;\r
+\r
+ Ip4SetVariableData (IpSb);\r
+\r
+ON_EXIT:\r
+ NetFreePool (Data);\r
+}\r
+\r
+\r
+/**\r
+ Start the auto configuration for this IP service instance.\r
+ It will locates the EFI_IP4_CONFIG_PROTOCOL, then start the\r
+ auto configuration.\r
+\r
+ @param IpSb The IP4 service instance to configure\r
+\r
+ @retval EFI_SUCCESS The auto configuration is successfull started\r
+ @retval Others Failed to start auto configuration.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4StartAutoConfig (\r
+ IN IP4_SERVICE *IpSb\r
+ )\r
+{\r
+ EFI_IP4_CONFIG_PROTOCOL *Ip4Config;\r
+ EFI_STATUS Status;\r
+\r
+ if (IpSb->State > IP4_SERVICE_UNSTARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Create the DoneEvent and ReconfigEvent to call EFI_IP4_CONFIG\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ NET_TPL_LOCK,\r
+ Ip4AutoConfigCallBack,\r
+ IpSb,\r
+ &IpSb->DoneEvent\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ Ip4AutoConfigCallBack,\r
+ IpSb,\r
+ &IpSb->ReconfigEvent\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto CLOSE_DONE_EVENT;\r
+ }\r
+\r
+ //\r
+ // Open the EFI_IP4_CONFIG protocol then start auto configure\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ IpSb->Controller,\r
+ &gEfiIp4ConfigProtocolGuid,\r
+ (VOID **) &Ip4Config,\r
+ IpSb->Image,\r
+ IpSb->Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto CLOSE_RECONFIG_EVENT;\r
+ }\r
+\r
+ Status = Ip4Config->Start (Ip4Config, IpSb->DoneEvent, IpSb->ReconfigEvent);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseProtocol (\r
+ IpSb->Controller,\r
+ &gEfiIp4ConfigProtocolGuid,\r
+ IpSb->Image,\r
+ IpSb->Controller\r
+ );\r
+\r
+ goto CLOSE_RECONFIG_EVENT;\r
+ }\r
+\r
+ IpSb->Ip4Config = Ip4Config;\r
+ IpSb->State = IP4_SERVICE_STARTED;\r
+ return Status;\r
+\r
+CLOSE_RECONFIG_EVENT:\r
+ gBS->CloseEvent (IpSb->ReconfigEvent);\r
+ IpSb->ReconfigEvent = NULL;\r
+\r
+CLOSE_DONE_EVENT:\r
+ gBS->CloseEvent (IpSb->DoneEvent);\r
+ IpSb->DoneEvent = NULL;\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Intiialize the IP4_PROTOCOL structure to the unconfigured states.\r
+\r
+ @param IpSb The IP4 service instance.\r
+ @param IpInstance The IP4 child instance.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4InitProtocol (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_PROTOCOL *IpInstance\r
+ )\r
+{\r
+ ASSERT ((IpSb != NULL) && (IpInstance != NULL));\r
+\r
+ NetZeroMem (IpInstance, sizeof (IP4_PROTOCOL));\r
+\r
+ IpInstance->Signature = IP4_PROTOCOL_SIGNATURE;\r
+ CopyMem (&IpInstance->Ip4Proto, &mEfiIp4ProtocolTemplete, sizeof (EFI_IP4_PROTOCOL));\r
+ IpInstance->State = IP4_STATE_UNCONFIGED;\r
+ IpInstance->Service = IpSb;\r
+\r
+ NetListInit (&IpInstance->Link);\r
+ NetMapInit (&IpInstance->RxTokens);\r
+ NetMapInit (&IpInstance->TxTokens);\r
+ NetListInit (&IpInstance->Received);\r
+ NetListInit (&IpInstance->Delivered);\r
+ NetListInit (&IpInstance->AddrLink);\r
+\r
+ NET_RECYCLE_LOCK_INIT (&IpInstance->RecycleLock);\r
+}\r
+\r
+\r
+/**\r
+ Configure the IP4 child. If the child is already configured,\r
+ change the configuration parameter. Otherwise configure it\r
+ for the first time. The caller should validate the configuration\r
+ before deliver them to it. It also don't do configure NULL.\r
+\r
+ @param IpInstance The IP4 child to configure.\r
+ @param Config The configure data.\r
+\r
+ @retval EFI_SUCCESS The IP4 child is successfully configured.\r
+ @retval EFI_DEVICE_ERROR Failed to free the pending transive or to\r
+ configure underlying MNP or other errors.\r
+ @retval EFI_NO_MAPPING The IP4 child is configured to use default\r
+ address, but the default address hasn't been\r
+ configured. The IP4 child doesn't need to be\r
+ reconfigured when default address is configured.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4ConfigProtocol (\r
+ IN IP4_PROTOCOL *IpInstance,\r
+ IN EFI_IP4_CONFIG_DATA *Config\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ IP4_INTERFACE *IpIf;\r
+ EFI_STATUS Status;\r
+ IP4_ADDR Ip;\r
+ IP4_ADDR Netmask;\r
+\r
+ IpSb = IpInstance->Service;\r
+\r
+ //\r
+ // User is changing packet filters. It must be stopped\r
+ // before the station address can be changed.\r
+ //\r
+ if (IpInstance->State == IP4_STATE_CONFIGED) {\r
+ //\r
+ // Cancel all the pending transmit/receive from upper layer\r
+ //\r
+ Status = Ip4Cancel (IpInstance, NULL);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CopyMem (&IpInstance->ConfigData, Config, sizeof (EFI_IP4_CONFIG_DATA));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Configure a fresh IP4 protocol instance. Create a route table.\r
+ // Each IP child has its own route table, which may point to the\r
+ // default table if it is using default address.\r
+ //\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ IpInstance->RouteTable = Ip4CreateRouteTable ();\r
+\r
+ if (IpInstance->RouteTable == NULL) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set up the interface.\r
+ //\r
+ NetCopyMem (&Ip, &Config->StationAddress, sizeof (IP4_ADDR));\r
+ NetCopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));\r
+\r
+ Ip = NTOHL (Ip);\r
+ Netmask = NTOHL (Netmask);\r
+\r
+ if (!Config->UseDefaultAddress) {\r
+ //\r
+ // Find whether there is already an interface with the same\r
+ // station address. All the instances with the same station\r
+ // address shares one interface.\r
+ //\r
+ IpIf = Ip4FindStationAddress (IpSb, Ip, Netmask);\r
+\r
+ if (IpIf != NULL) {\r
+ NET_GET_REF (IpIf);\r
+\r
+ } else {\r
+ IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
+\r
+ if (IpIf == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = Ip4SetAddress (IpIf, Ip, Netmask);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ Ip4FreeInterface (IpIf, IpInstance);\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ NetListInsertTail (&IpSb->Interfaces, &IpIf->Link);\r
+ }\r
+\r
+ //\r
+ // Add a route to this connected network in the route table\r
+ //\r
+ Ip4AddRoute (IpInstance->RouteTable, Ip, Netmask, IP4_ALLZERO_ADDRESS);\r
+\r
+ } else {\r
+ //\r
+ // Use the default address. If the default configuration hasn't\r
+ // been started, start it.\r
+ //\r
+ if (IpSb->State == IP4_SERVICE_UNSTARTED) {\r
+ Status = Ip4StartAutoConfig (IpSb);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+ }\r
+\r
+ IpIf = IpSb->DefaultInterface;\r
+ NET_GET_REF (IpSb->DefaultInterface);\r
+\r
+ //\r
+ // If default address is used, so is the default route table.\r
+ // Any route set by the instance has the precedence over the\r
+ // routes in the default route table. Link the default table\r
+ // after the instance's table. Routing will search the local\r
+ // table first.\r
+ //\r
+ NET_GET_REF (IpSb->DefaultRouteTable);\r
+ IpInstance->RouteTable->Next = IpSb->DefaultRouteTable;\r
+ }\r
+\r
+ IpInstance->Interface = IpIf;\r
+ NetListInsertTail (&IpIf->IpInstances, &IpInstance->AddrLink);\r
+\r
+ CopyMem (&IpInstance->ConfigData, Config, sizeof (EFI_IP4_CONFIG_DATA));\r
+ IpInstance->State = IP4_STATE_CONFIGED;\r
+\r
+ //\r
+ // Although EFI_NO_MAPPING is an error code, the IP child has been\r
+ // successfully configured and doesn't need reconfiguration when\r
+ // default address is acquired.\r
+ //\r
+ if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
+ return EFI_NO_MAPPING;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ Ip4FreeRouteTable (IpInstance->RouteTable);\r
+ IpInstance->RouteTable = NULL;\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Clean up the IP4 child, release all the resources used by it.\r
+\r
+ @param IpInstance The IP4 child to clean up.\r
+\r
+ @retval EFI_SUCCESS The IP4 child is cleaned up\r
+ @retval EFI_DEVICE_ERROR Some resources failed to be released\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4CleanProtocol (\r
+ IN IP4_PROTOCOL *IpInstance\r
+ )\r
+{\r
+ if (EFI_ERROR (Ip4Cancel (IpInstance, NULL))) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (EFI_ERROR (Ip4Groups (IpInstance, FALSE, NULL))) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Some packets haven't been recycled. It is because either the\r
+ // user forgets to recycle the packets, or because the callback\r
+ // hasn't been called. Just leave it alone.\r
+ //\r
+ if (!NetListIsEmpty (&IpInstance->Delivered)) {\r
+ ;\r
+ }\r
+\r
+ if (IpInstance->Interface != NULL) {\r
+ NetListRemoveEntry (&IpInstance->AddrLink);\r
+ Ip4FreeInterface (IpInstance->Interface, IpInstance);\r
+ IpInstance->Interface = NULL;\r
+ }\r
+\r
+ if (IpInstance->RouteTable != NULL) {\r
+ if (IpInstance->RouteTable->Next != NULL) {\r
+ Ip4FreeRouteTable (IpInstance->RouteTable->Next);\r
+ }\r
+\r
+ Ip4FreeRouteTable (IpInstance->RouteTable);\r
+ IpInstance->RouteTable = NULL;\r
+ }\r
+\r
+ if (IpInstance->EfiRouteTable != NULL) {\r
+ NetFreePool (IpInstance->EfiRouteTable);\r
+ IpInstance->EfiRouteTable = NULL;\r
+ IpInstance->EfiRouteCount = 0;\r
+ }\r
+\r
+ if (IpInstance->Groups != NULL) {\r
+ NetFreePool (IpInstance->Groups);\r
+ IpInstance->Groups = NULL;\r
+ IpInstance->GroupCount = 0;\r
+ }\r
+\r
+ NetMapClean (&IpInstance->TxTokens);\r
+\r
+ NetMapClean (&IpInstance->RxTokens);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Validate that Ip/Netmask pair is OK to be used as station\r
+ address. Only continuous netmasks are supported. and check\r
+ that StationAddress is a unicast address on the newtwork.\r
+\r
+ @param Ip The IP address to validate\r
+ @param Netmask The netmaks of the IP\r
+\r
+ @retval TRUE The Ip/Netmask pair is valid\r
+ @retval FALSE The\r
+\r
+**/\r
+BOOLEAN\r
+Ip4StationAddressValid (\r
+ IN IP4_ADDR Ip,\r
+ IN IP4_ADDR Netmask\r
+ )\r
+{\r
+ IP4_ADDR NetBrdcastMask;\r
+ INTN Len;\r
+ INTN Type;\r
+\r
+ //\r
+ // Only support the station address with 0.0.0.0/0 to enable DHCP client.\r
+ //\r
+ if (Netmask == IP4_ALLZERO_ADDRESS) {\r
+ return (BOOLEAN) (Ip == IP4_ALLZERO_ADDRESS);\r
+ }\r
+\r
+ //\r
+ // Only support the continuous net masks\r
+ //\r
+ if ((Len = NetGetMaskLength (Netmask)) == IP4_MASK_NUM) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Station address can't be class D or class E address\r
+ //\r
+ if ((Type = NetGetIpClass (Ip)) > IP4_ADDR_CLASSC) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Station address can't be subnet broadcast/net broadcast address\r
+ //\r
+ if ((Ip == (Ip & Netmask)) || (Ip == (Ip | ~Netmask))) {\r
+ return FALSE;\r
+ }\r
+\r
+ NetBrdcastMask = mIp4AllMasks[NET_MIN (Len, Type << 3)];\r
+\r
+ if (Ip == (Ip | ~NetBrdcastMask)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Configure the EFI_IP4_PROTOCOL instance. If IpConfigData is NULL,\r
+ the instance is cleaned up. If the instance hasn't been configure\r
+ before, it will be initialized. Otherwise, the filter setting of\r
+ the instance is updated.\r
+\r
+ @param This The IP4 child to configure\r
+ @param IpConfigData The configuration to apply. If NULL, clean it up.\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameter is invalid\r
+ @retval EFI_NO_MAPPING The default address hasn't been configured and the\r
+ instance wants to use it.\r
+ @retval EFI_SUCCESS The instance is configured.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Configure (\r
+ IN EFI_IP4_PROTOCOL *This,\r
+ IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL\r
+ )\r
+{\r
+ IP4_PROTOCOL *IpInstance;\r
+ EFI_IP4_CONFIG_DATA *Current;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ BOOLEAN AddrOk;\r
+ IP4_ADDR IpAddress;\r
+ IP4_ADDR SubnetMask;\r
+\r
+ //\r
+ // First, validate the parameters\r
+ //\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ //\r
+ // Validate the configuration first.\r
+ //\r
+ if (IpConfigData != NULL) {\r
+ //\r
+ // This implementation doesn't support RawData\r
+ //\r
+ if (IpConfigData->RawData) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+\r
+ NetCopyMem (&IpAddress, &IpConfigData->StationAddress, sizeof (IP4_ADDR));\r
+ NetCopyMem (&SubnetMask, &IpConfigData->SubnetMask, sizeof (IP4_ADDR));\r
+\r
+ IpAddress = NTOHL (IpAddress);\r
+ SubnetMask = NTOHL (SubnetMask);\r
+\r
+ //\r
+ // Check whether the station address is a valid unicast address\r
+ //\r
+ if (!IpConfigData->UseDefaultAddress) {\r
+ AddrOk = Ip4StationAddressValid (IpAddress, SubnetMask);\r
+\r
+ if (!AddrOk) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+\r
+ //\r
+ // User can only update packet filters when already configured.\r
+ // If it wants to change the station address, it must configure(NULL)\r
+ // the instance first.\r
+ //\r
+ if (IpInstance->State == IP4_STATE_CONFIGED) {\r
+ Current = &IpInstance->ConfigData;\r
+\r
+ if (Current->UseDefaultAddress != IpConfigData->UseDefaultAddress) {\r
+ Status = EFI_ALREADY_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (!Current->UseDefaultAddress &&\r
+ (!EFI_IP4_EQUAL (Current->StationAddress, IpConfigData->StationAddress) ||\r
+ !EFI_IP4_EQUAL (Current->SubnetMask, IpConfigData->SubnetMask))) {\r
+ Status = EFI_ALREADY_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (Current->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
+ return EFI_NO_MAPPING;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Configure the instance or clean it up.\r
+ //\r
+ if (IpConfigData != NULL) {\r
+ Status = Ip4ConfigProtocol (IpInstance, IpConfigData);\r
+ } else {\r
+ Status = Ip4CleanProtocol (IpInstance);\r
+\r
+ //\r
+ // Don't change the state if it is DESTORY, consider the following\r
+ // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,\r
+ // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,\r
+ // the unload fails miserably.\r
+ //\r
+ if (IpInstance->State == IP4_STATE_CONFIGED) {\r
+ IpInstance->State = IP4_STATE_UNCONFIGED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Update the MNP's configure data. Ip4ServiceConfigMnp will check\r
+ // whether it is necessary to reconfigure the MNP.\r
+ //\r
+ Ip4ServiceConfigMnp (IpInstance->Service, FALSE);\r
+\r
+ //\r
+ // Update the variable data.\r
+ //\r
+ Ip4SetVariableData (IpInstance->Service);\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+\r
+}\r
+\r
+\r
+/**\r
+ Change the IP4 child's multicast setting. The caller\r
+ should make sure that the parameters is valid.\r
+\r
+ @param IpInstance The IP4 child to change the setting.\r
+ @param JoinFlag TRUE to join the group, otherwise leave it\r
+ @param GroupAddress The target group address\r
+\r
+ @retval EFI_ALREADY_STARTED Want to join the group, but already a member of it\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.\r
+ @retval EFI_DEVICE_ERROR Failed to set the group configuraton\r
+ @retval EFI_SUCCESS Successfully updated the group setting.\r
+ @retval EFI_NOT_FOUND Try to leave the group which it isn't a member.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Groups (\r
+ IN IP4_PROTOCOL *IpInstance,\r
+ IN BOOLEAN JoinFlag,\r
+ IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL\r
+ )\r
+{\r
+ IP4_ADDR *Members;\r
+ IP4_ADDR Group;\r
+ UINT32 Index;\r
+\r
+ //\r
+ // Add it to the instance's Groups, and join the group by IGMP.\r
+ // IpInstance->Groups is in network byte order. IGMP operates in\r
+ // host byte order\r
+ //\r
+ if (JoinFlag) {\r
+ NetCopyMem (&Group, GroupAddress, sizeof (IP4_ADDR));\r
+\r
+ for (Index = 0; Index < IpInstance->GroupCount; Index++) {\r
+ if (IpInstance->Groups[Index] == Group) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+ }\r
+\r
+ Members = Ip4CombineGroups (IpInstance->Groups, IpInstance->GroupCount, Group);\r
+\r
+ if (Members == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (EFI_ERROR (Ip4JoinGroup (IpInstance, NTOHL (Group)))) {\r
+ NetFreePool (Members);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (IpInstance->Groups != NULL) {\r
+ NetFreePool (IpInstance->Groups);\r
+ }\r
+\r
+ IpInstance->Groups = Members;\r
+ IpInstance->GroupCount++;\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Leave the group. Leave all the groups if GroupAddress is NULL.\r
+ // Must iterate from the end to the beginning because the GroupCount\r
+ // is decreamented each time an address is removed..\r
+ //\r
+ for (Index = IpInstance->GroupCount; Index > 0 ; Index--) {\r
+ Group = IpInstance->Groups[Index - 1];\r
+\r
+ if ((GroupAddress == NULL) || EFI_IP4_EQUAL (Group, *GroupAddress)) {\r
+ if (EFI_ERROR (Ip4LeaveGroup (IpInstance, NTOHL (Group)))) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Ip4RemoveGroupAddr (IpInstance->Groups, IpInstance->GroupCount, Group);\r
+ IpInstance->GroupCount--;\r
+\r
+ if (IpInstance->GroupCount == 0) {\r
+ ASSERT (Index == 1);\r
+\r
+ NetFreePool (IpInstance->Groups);\r
+ IpInstance->Groups = NULL;\r
+ }\r
+\r
+ if (GroupAddress != NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ return ((GroupAddress != NULL) ? EFI_NOT_FOUND : EFI_SUCCESS);\r
+}\r
+\r
+\r
+/**\r
+ Change the IP4 child's multicast setting. If JoinFlag is true,\r
+ the child wants to join the group. Otherwise it wants to leave\r
+ the group. If JoinFlag is false, and GroupAddress is NULL,\r
+ it will leave all the groups which is a member.\r
+\r
+ @param This The IP4 child to change the setting.\r
+ @param JoinFlag TRUE to join the group, otherwise leave it.\r
+ @param GroupAddress The target group address\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameters are invalid\r
+ @retval EFI_SUCCESS The group setting has been changed.\r
+ @retval Otherwise It failed to change the setting.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Groups (\r
+ IN EFI_IP4_PROTOCOL *This,\r
+ IN BOOLEAN JoinFlag,\r
+ IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL\r
+ )\r
+{\r
+ IP4_PROTOCOL *IpInstance;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+ IP4_ADDR McastIp;\r
+\r
+ if ((This == NULL) || (JoinFlag && (GroupAddress == NULL))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (GroupAddress != NULL) {\r
+ NetCopyMem (&McastIp, GroupAddress, sizeof (IP4_ADDR));\r
+\r
+ if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (IpInstance->State != IP4_STATE_CONFIGED) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Ip4Groups (IpInstance, JoinFlag, GroupAddress);\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Modify the IP child's route table. Each instance has its own\r
+ route table.\r
+\r
+ @param This The IP4 child to modify the route\r
+ @param DeleteRoute TRUE to delete the route, otherwise add it\r
+ @param SubnetAddress The destination network\r
+ @param SubnetMask The destination network's mask\r
+ @param GatewayAddress The next hop address.\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
+ @retval EFI_SUCCESS The route table is successfully modified.\r
+ @retval Others Failed to modify the route table\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Routes (\r
+ IN EFI_IP4_PROTOCOL *This,\r
+ IN BOOLEAN DeleteRoute,\r
+ IN EFI_IPv4_ADDRESS *SubnetAddress,\r
+ IN EFI_IPv4_ADDRESS *SubnetMask,\r
+ IN EFI_IPv4_ADDRESS *GatewayAddress\r
+ )\r
+{\r
+ IP4_PROTOCOL *IpInstance;\r
+ IP4_INTERFACE *IpIf;\r
+ IP4_ADDR Dest;\r
+ IP4_ADDR Netmask;\r
+ IP4_ADDR Nexthop;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // First, validate the parameters\r
+ //\r
+ if ((This == NULL) || (SubnetAddress == NULL) ||\r
+ (SubnetMask == NULL) || (GatewayAddress == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (IpInstance->State != IP4_STATE_CONFIGED) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ NetCopyMem (&Dest, SubnetAddress, sizeof (IP4_ADDR));\r
+ NetCopyMem (&Netmask, SubnetMask, sizeof (IP4_ADDR));\r
+ NetCopyMem (&Nexthop, GatewayAddress, sizeof (IP4_ADDR));\r
+\r
+ Dest = NTOHL (Dest);\r
+ Netmask = NTOHL (Netmask);\r
+ Nexthop = NTOHL (Nexthop);\r
+\r
+ IpIf = IpInstance->Interface;\r
+\r
+ if (!IP4_IS_VALID_NETMASK (Netmask)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // the gateway address must be a unicast on the connected network if not zero.\r
+ //\r
+ if ((Nexthop != IP4_ALLZERO_ADDRESS) &&\r
+ (!IP4_NET_EQUAL (Nexthop, IpIf->Ip, IpIf->SubnetMask) ||\r
+ IP4_IS_BROADCAST (Ip4GetNetCast (Nexthop, IpIf)))) {\r
+\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (DeleteRoute) {\r
+ Status = Ip4DelRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);\r
+ } else {\r
+ Status = Ip4AddRoute (IpInstance->RouteTable, Dest, Netmask, Nexthop);\r
+ }\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Check whether the user's token or event has already\r
+ been enqueue on IP4's list.\r
+\r
+ @param Map The container of either user's transmit or receive\r
+ token.\r
+ @param Item Current item to check against\r
+ @param Context The Token to check againist.\r
+\r
+ @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP\r
+ @retval EFI_SUCCESS The current item isn't the same token/event as the\r
+ context.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Ip4TokenExist (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_IP4_COMPLETION_TOKEN *Token;\r
+ EFI_IP4_COMPLETION_TOKEN *TokenInItem;\r
+\r
+ Token = (EFI_IP4_COMPLETION_TOKEN *) Context;\r
+ TokenInItem = (EFI_IP4_COMPLETION_TOKEN *) Item->Key;\r
+\r
+ if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Validate the user's token against current station address.\r
+\r
+ @param Token User's token to validate\r
+ @param IpIf The IP4 child's interface.\r
+\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid\r
+ @retval EFI_BAD_BUFFER_SIZE The user's option/data is too long.\r
+ @retval EFI_SUCCESS The token is OK\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Ip4TxTokenValid (\r
+ IN EFI_IP4_COMPLETION_TOKEN *Token,\r
+ IN IP4_INTERFACE *IpIf\r
+ )\r
+{\r
+ EFI_IP4_TRANSMIT_DATA *TxData;\r
+ EFI_IP4_OVERRIDE_DATA *Override;\r
+ IP4_ADDR Src;\r
+ IP4_ADDR Gateway;\r
+ UINT32 Offset;\r
+ UINT32 Index;\r
+ UINT32 HeadLen;\r
+\r
+ if ((Token == NULL) || (Token->Event == NULL) || (Token->Packet.TxData == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ TxData = Token->Packet.TxData;\r
+\r
+ //\r
+ // Check the IP options: no more than 40 bytes and format is OK\r
+ //\r
+ if (TxData->OptionsLength != 0) {\r
+ if ((TxData->OptionsLength > 40) || (TxData->OptionsBuffer == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!Ip4OptionIsValid (TxData->OptionsBuffer, TxData->OptionsLength, FALSE)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check the fragment table: no empty fragment, and length isn't bogus\r
+ //\r
+ if ((TxData->TotalDataLength == 0) || (TxData->FragmentCount == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Offset = TxData->TotalDataLength;\r
+\r
+ for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
+ if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||\r
+ (TxData->FragmentTable[Index].FragmentLength == 0)) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Offset -= TxData->FragmentTable[Index].FragmentLength;\r
+ }\r
+\r
+ if (Offset != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check the source and gateway: they must be a valid unicast.\r
+ // Gateway must also be on the connected network.\r
+ //\r
+ if (TxData->OverrideData) {\r
+ Override = TxData->OverrideData;\r
+\r
+ NetCopyMem (&Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
+ NetCopyMem (&Gateway, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
+\r
+ Src = NTOHL (Src);\r
+ Gateway = NTOHL (Gateway);\r
+\r
+ if ((NetGetIpClass (Src) > IP4_ADDR_CLASSC) ||\r
+ (Src == IP4_ALLONE_ADDRESS) ||\r
+ IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // If gateway isn't zero, it must be a unicast address, and\r
+ // on the connected network.\r
+ //\r
+ if ((Gateway != IP4_ALLZERO_ADDRESS) &&\r
+ ((NetGetIpClass (Gateway) > IP4_ADDR_CLASSC) ||\r
+ !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask) ||\r
+ IP4_IS_BROADCAST (Ip4GetNetCast (Gateway, IpIf)))) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check the packet length: Head length and packet length all has a limit\r
+ //\r
+ HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);\r
+\r
+ if ((HeadLen > IP4_MAX_HEADLEN) ||\r
+ (TxData->TotalDataLength + HeadLen > IP4_MAX_PACKET_SIZE)) {\r
+\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ The callback function for the net buffer which wraps the user's\r
+ transmit token. Although it seems this function is pretty simple,\r
+ there are some subtle things.\r
+ When user requests the IP to transmit a packet by passing it a\r
+ token, the token is wrapped in an IP4_TXTOKEN_WRAP and the data\r
+ is wrapped in an net buffer. the net buffer's Free function is\r
+ set to Ip4FreeTxToken. The Token and token wrap are added to the\r
+ IP child's TxToken map. Then the buffer is passed to Ip4Output for\r
+ transmission. If something error happened before that, the buffer\r
+ is freed, which in turn will free the token wrap. The wrap may\r
+ have been added to the TxToken map or not, and the user's event\r
+ shouldn't be fired because we are still in the EfiIp4Transmit. If\r
+ the buffer has been sent by Ip4Output, it should be removed from\r
+ the TxToken map and user's event signaled. The token wrap and buffer\r
+ are bound together. Check the comments in Ip4Output for information\r
+ about IP fragmentation.\r
+\r
+ @param Context The token's wrap\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4FreeTxToken (\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_TXTOKEN_WRAP *Wrap;\r
+ NET_MAP_ITEM *Item;\r
+\r
+ Wrap = (IP4_TXTOKEN_WRAP *) Context;\r
+\r
+ //\r
+ // Find the token in the instance's map. EfiIp4Transmit put the\r
+ // token to the map. If that failed, NetMapFindKey will return NULL.\r
+ //\r
+ Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);\r
+\r
+ if (Item != NULL) {\r
+ NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);\r
+ }\r
+\r
+ if (Wrap->Sent) {\r
+ gBS->SignalEvent (Wrap->Token->Event);\r
+ }\r
+\r
+ NetFreePool (Wrap);\r
+}\r
+\r
+\r
+/**\r
+ The callback function to Ip4Output to update the transmit status.\r
+\r
+ @param Ip4Instance The Ip4Instance that request the transmit.\r
+ @param Packet The user's transmit request\r
+ @param IoStatus The result of the transmission\r
+ @param Flag Not used during transmission\r
+ @param Context The token's wrap.\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4OnPacketSent (\r
+ IP4_PROTOCOL *Ip4Instance,\r
+ NET_BUF *Packet,\r
+ EFI_STATUS IoStatus,\r
+ UINT32 Flag,\r
+ VOID *Context\r
+ )\r
+{\r
+ IP4_TXTOKEN_WRAP *Wrap;\r
+\r
+ //\r
+ // This is the transmission request from upper layer,\r
+ // not the IP4 driver itself.\r
+ //\r
+ ASSERT (Ip4Instance != NULL);\r
+\r
+ //\r
+ // The first fragment of the packet has been sent. Update\r
+ // the token's status. That is, if fragmented, the transmit's\r
+ // status is the first fragment's status. The Wrap will be\r
+ // release when all the fragments are release. Check the comments\r
+ // in Ip4FreeTxToken and Ip4Output for information.\r
+ //\r
+ Wrap = (IP4_TXTOKEN_WRAP *) Context;\r
+ Wrap->Token->Status = IoStatus;\r
+\r
+ NetbufFree (Wrap->Packet);\r
+}\r
+\r
+\r
+/**\r
+ Transmit the user's data asynchronously. When transmission\r
+ completed,the Token's status is updated and its event signalled.\r
+\r
+ @param This The IP4 child instance\r
+ @param Token The user's transmit token, which contains user's\r
+ data, the result and an event to signal when\r
+ completed.\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
+ @retval EFI_NOT_STARTED The IP4 child hasn't been started.\r
+ @retval EFI_SUCCESS The user's data has been successfully enqueued\r
+ for transmission.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Transmit (\r
+ IN EFI_IP4_PROTOCOL *This,\r
+ IN EFI_IP4_COMPLETION_TOKEN *Token\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ IP4_PROTOCOL *IpInstance;\r
+ IP4_INTERFACE *IpIf;\r
+ IP4_TXTOKEN_WRAP *Wrap;\r
+ EFI_IP4_TRANSMIT_DATA *TxData;\r
+ EFI_IP4_CONFIG_DATA *Config;\r
+ EFI_IP4_OVERRIDE_DATA *Override;\r
+ IP4_HEAD Head;\r
+ IP4_ADDR GateWay;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+ BOOLEAN DontFragment;\r
+ UINT32 HeadLen;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
+\r
+ if (IpInstance->State != IP4_STATE_CONFIGED) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ IpSb = IpInstance->Service;\r
+ IpIf = IpInstance->Interface;\r
+ Config = &IpInstance->ConfigData;\r
+\r
+ if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // make sure that token is properly formated\r
+ //\r
+ Status = Ip4TxTokenValid (Token, IpIf);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Check whether the token or signal already existed.\r
+ //\r
+ if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip4TokenExist, Token))) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Build the IP header, need to fill in the Tos, TotalLen, Id,\r
+ // fragment, Ttl, protocol, Src, and Dst.\r
+ //\r
+ TxData = Token->Packet.TxData;\r
+\r
+ NetCopyMem (&Head.Dst, &TxData->DestinationAddress, sizeof (IP4_ADDR));\r
+ Head.Dst = NTOHL (Head.Dst);\r
+\r
+ if (TxData->OverrideData) {\r
+ Override = TxData->OverrideData;\r
+ Head.Protocol = Override->Protocol;\r
+ Head.Tos = Override->TypeOfService;\r
+ Head.Ttl = Override->TimeToLive;\r
+ DontFragment = Override->DoNotFragment;\r
+\r
+ NetCopyMem (&Head.Src, &Override->SourceAddress, sizeof (IP4_ADDR));\r
+ NetCopyMem (&GateWay, &Override->GatewayAddress, sizeof (IP4_ADDR));\r
+\r
+ Head.Src = NTOHL (Head.Src);\r
+ GateWay = NTOHL (GateWay);\r
+ } else {\r
+ Head.Src = IpIf->Ip;\r
+ GateWay = IP4_ALLZERO_ADDRESS;\r
+ Head.Protocol = Config->DefaultProtocol;\r
+ Head.Tos = Config->TypeOfService;\r
+ Head.Ttl = Config->TimeToLive;\r
+ DontFragment = Config->DoNotFragment;\r
+ }\r
+\r
+ Head.Fragment = IP4_HEAD_FRAGMENT_FIELD (DontFragment, FALSE, 0);\r
+ HeadLen = sizeof (IP4_HEAD) + ((TxData->OptionsLength + 3) &~0x03);\r
+\r
+ //\r
+ // If don't fragment and fragment needed, return error\r
+ //\r
+ if (DontFragment && (TxData->TotalDataLength + HeadLen > IpSb->SnpMode.MaxPacketSize)) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // OK, it survives all the validation check. Wrap the token in\r
+ // a IP4_TXTOKEN_WRAP and the data in a netbuf\r
+ //\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ Wrap = NetAllocatePool (sizeof (IP4_TXTOKEN_WRAP));\r
+ if (Wrap == NULL) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Wrap->IpInstance = IpInstance;\r
+ Wrap->Token = Token;\r
+ Wrap->Sent = FALSE;\r
+ Wrap->Life = IP4_US_TO_SEC (Config->TransmitTimeout);\r
+ Wrap->Packet = NetbufFromExt (\r
+ (NET_FRAGMENT *) TxData->FragmentTable,\r
+ TxData->FragmentCount,\r
+ IP4_MAX_HEADLEN,\r
+ 0,\r
+ Ip4FreeTxToken,\r
+ Wrap\r
+ );\r
+\r
+ if (Wrap->Packet == NULL) {\r
+ NetFreePool (Wrap);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Token->Status = EFI_NOT_READY;\r
+\r
+ if (EFI_ERROR (NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap))) {\r
+ //\r
+ // NetbufFree will call Ip4FreeTxToken, which in turn will\r
+ // free the IP4_TXTOKEN_WRAP. Now, the token wrap hasn't been\r
+ // enqueued.\r
+ //\r
+ NetbufFree (Wrap->Packet);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Ip4Output (\r
+ IpSb,\r
+ IpInstance,\r
+ Wrap->Packet,\r
+ &Head,\r
+ TxData->OptionsBuffer,\r
+ TxData->OptionsLength,\r
+ GateWay,\r
+ Ip4OnPacketSent,\r
+ Wrap\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetbufFree (Wrap->Packet);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Mark the packet sent, so when Ip4FreeTxToken is called, it\r
+ // will signal the upper layer.\r
+ //\r
+ Wrap->Sent = TRUE;\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Receive a packet for the upper layer. If there are packets\r
+ pending on the child's receive queue, the receive request\r
+ will be fulfilled immediately. Otherwise, the request is\r
+ enqueued. When receive request is completed, the status in\r
+ the Token is updated and its event is signalled.\r
+\r
+ @param This The IP4 child to receive packet.\r
+ @param Token The user's receive token\r
+\r
+ @retval EFI_INVALID_PARAMETER The token is invalid.\r
+ @retval EFI_NOT_STARTED The IP4 child hasn't been started\r
+ @retval EFI_ACCESS_DENIED The token or event is already queued.\r
+ @retval EFI_SUCCESS The receive request has been issued.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Receive (\r
+ IN EFI_IP4_PROTOCOL *This,\r
+ IN EFI_IP4_COMPLETION_TOKEN *Token\r
+ )\r
+{\r
+ IP4_PROTOCOL *IpInstance;\r
+ EFI_IP4_CONFIG_DATA *Config;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // First validate the parameters\r
+ //\r
+ if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (IpInstance->State != IP4_STATE_CONFIGED) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Config = &IpInstance->ConfigData;\r
+\r
+ //\r
+ // Current Udp implementation creates an IP child for each Udp child.\r
+ // It initates a asynchronous receive immediately no matter whether\r
+ // there is no mapping or not. Disable this for now.\r
+ //\r
+#if 0\r
+ if (Config->UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto ON_EXIT;\r
+ }\r
+#endif\r
+\r
+ //\r
+ // Check whether the toke is already on the receive queue.\r
+ //\r
+ Status = NetMapIterate (&IpInstance->RxTokens, Ip4TokenExist, Token);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Queue the token then check whether there is pending received packet.\r
+ //\r
+ Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Ip4InstanceDeliverPacket (IpInstance);\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Cancel the transmitted but not recycled packet. If a matching\r
+ token is found, it will call Ip4CancelPacket to cancel the\r
+ packet. Ip4CancelPacket will cancel all the fragments of the\r
+ packet. When all the fragments are freed, the IP4_TXTOKEN_WRAP\r
+ will be deleted from the Map, and user's event signalled.\r
+ Because Ip4CancelPacket and other functions are all called in\r
+ line, so, after Ip4CancelPacket returns, the Item has been freed.\r
+\r
+ @param Map The IP4 child's transmit queue\r
+ @param Item The current transmitted packet to test.\r
+ @param Context The user's token to cancel.\r
+\r
+ @retval EFI_SUCCESS Continue to check the next Item.\r
+ @retval EFI_ABORTED The user's Token (Token != NULL) is cancelled.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Ip4CancelTxTokens (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_IP4_COMPLETION_TOKEN *Token;\r
+ IP4_TXTOKEN_WRAP *Wrap;\r
+\r
+ Token = (EFI_IP4_COMPLETION_TOKEN *) Context;\r
+\r
+ //\r
+ // Return EFI_SUCCESS to check the next item in the map if\r
+ // this one doesn't match.\r
+ //\r
+ if ((Token != NULL) && (Token != Item->Key)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;\r
+ ASSERT (Wrap != NULL);\r
+\r
+ //\r
+ // Don't access the Item, Wrap and Token's members after this point.\r
+ // Item and wrap has been freed. And we no longer own the Token.\r
+ //\r
+ Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);\r
+\r
+ //\r
+ // If only one item is to be cancel, return EFI_ABORTED to stop\r
+ // iterating the map any more.\r
+ //\r
+ if (Token != NULL) {\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Cancel the receive request. This is quiet simple, because\r
+ it is only enqueued in our local receive map.\r
+\r
+ @param Map The IP4 child's receive queue\r
+ @param Item Current receive request to cancel.\r
+ @param Context The user's token to cancel\r
+\r
+ @retval EFI_SUCCESS Continue to check the next receive request on the\r
+ queue.\r
+ @retval EFI_ABORTED The user's token (token != NULL) has been\r
+ cancelled.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Ip4CancelRxTokens (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_IP4_COMPLETION_TOKEN *Token;\r
+ EFI_IP4_COMPLETION_TOKEN *This;\r
+\r
+ Token = (EFI_IP4_COMPLETION_TOKEN *) Context;\r
+ This = Item->Key;\r
+\r
+ if ((Token != NULL) && (Token != This)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ NetMapRemoveItem (Map, Item, NULL);\r
+\r
+ This->Status = EFI_ABORTED;\r
+ This->Packet.RxData = NULL;\r
+ gBS->SignalEvent (This->Event);\r
+\r
+ if (Token != NULL) {\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Cancel the user's receive/transmit request.\r
+\r
+ @param IpInstance The IP4 child\r
+ @param Token The token to cancel. If NULL, all token will be\r
+ cancelled.\r
+\r
+ @retval EFI_SUCCESS The token is cancelled\r
+ @retval EFI_NOT_FOUND The token isn't found on either the\r
+ transmit/receive queue\r
+ @retval EFI_DEVICE_ERROR Not all token is cancelled when Token is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Cancel (\r
+ IN IP4_PROTOCOL *IpInstance,\r
+ IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // First check the transmitted packet. Ip4CancelTxTokens returns\r
+ // EFI_ABORTED to mean that the token has been cancelled when\r
+ // token != NULL. So, return EFI_SUCCESS for this condition.\r
+ //\r
+ Status = NetMapIterate (&IpInstance->TxTokens, Ip4CancelTxTokens, Token);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if ((Token != NULL) && (Status == EFI_ABORTED)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check the receive queue. Ip4CancelRxTokens also returns EFI_ABORT\r
+ // for Token!=NULL and it is cancelled.\r
+ //\r
+ Status = NetMapIterate (&IpInstance->RxTokens, Ip4CancelRxTokens, Token);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if ((Token != NULL) && (Status == EFI_ABORTED)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // OK, if the Token is found when Token != NULL, the NetMapIterate\r
+ // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.\r
+ //\r
+ if (Token != NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // If Token == NULL, cancel all the tokens. return error if no\r
+ // all of them are cancelled.\r
+ //\r
+ if (!NetMapIsEmpty (&IpInstance->TxTokens) ||\r
+ !NetMapIsEmpty (&IpInstance->RxTokens)) {\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Cancel the queued receive/transmit requests. If Token is NULL,\r
+ all the queued requests will be cancelled. It just validate\r
+ the parameter then pass them to Ip4Cancel.\r
+\r
+ @param This The IP4 child to cancel the request\r
+ @param Token The token to cancel, if NULL, cancel all.\r
+\r
+ @retval EFI_INVALID_PARAMETER This is NULL\r
+ @retval EFI_NOT_STARTED The IP4 child hasn't been configured.\r
+ @retval EFI_NO_MAPPING The IP4 child is configured to use the default,\r
+ but the default address hasn't been acquired.\r
+ @retval EFI_SUCCESS The Token is cancelled.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Cancel (\r
+ IN EFI_IP4_PROTOCOL *This,\r
+ IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL\r
+ )\r
+{\r
+ IP4_PROTOCOL *IpInstance;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (IpInstance->State != IP4_STATE_CONFIGED) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (IpInstance->ConfigData.UseDefaultAddress && IP4_NO_MAPPING (IpInstance)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Ip4Cancel (IpInstance, Token);\r
+\r
+ON_EXIT:\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Poll the network stack. The EFI network stack is poll based. There\r
+ is no interrupt support for the network interface card.\r
+\r
+ @param This The IP4 child to poll through\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameter is invalid\r
+ @retval EFI_NOT_STARTED The IP4 child hasn't been configured.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Poll (\r
+ IN EFI_IP4_PROTOCOL *This\r
+ )\r
+{\r
+ IP4_PROTOCOL *IpInstance;\r
+ EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IpInstance = IP4_INSTANCE_FROM_PROTOCOL (This);\r
+\r
+ if (IpInstance->State == IP4_STATE_UNCONFIGED) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ Mnp = IpInstance->Service->Mnp;\r
+\r
+ //\r
+ // Don't lock the Poll function to enable the deliver of\r
+ // the packet polled up.\r
+ //\r
+ return Mnp->Poll (Mnp);\r
+}\r
+\r
+EFI_IP4_PROTOCOL\r
+mEfiIp4ProtocolTemplete = {\r
+ EfiIp4GetModeData,\r
+ EfiIp4Configure,\r
+ EfiIp4Groups,\r
+ EfiIp4Routes,\r
+ EfiIp4Transmit,\r
+ EfiIp4Receive,\r
+ EfiIp4Cancel,\r
+ EfiIp4Poll\r
+};\r
+\r
+\r
+/**\r
+ Decrease the life of the transmitted packets. If it is\r
+ decreased to zero, cancel the packet. This function is\r
+ called by Ip4packetTimerTicking which time out both the\r
+ received-but-not-delivered and transmitted-but-not-recycle\r
+ packets.\r
+\r
+ @param Map The IP4 child's transmit map.\r
+ @param Item Current transmitted packet\r
+ @param Context Not used.\r
+\r
+ @retval EFI_SUCCESS Always returns EFI_SUCCESS\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4SentPacketTicking (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_TXTOKEN_WRAP *Wrap;\r
+\r
+ Wrap = (IP4_TXTOKEN_WRAP *) Item->Value;\r
+ ASSERT (Wrap != NULL);\r
+\r
+ if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {\r
+ Ip4CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ The heart beat timer of IP4 service instance. It times out\r
+ all of its IP4 children's received-but-not-delivered and\r
+ transmitted-but-not-recycle packets, and provides time input\r
+ for its IGMP protocol.\r
+\r
+ @param Event The IP4 service instance's heart beat timer.\r
+ @param Context The IP4 service instance.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ip4TimerTicking (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+\r
+ IpSb = (IP4_SERVICE *) Context;\r
+ NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
+\r
+ Ip4PacketTimerTicking (IpSb);\r
+ Ip4IgmpTicking (IpSb);\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Ip4Impl.h
+
+Abstract:
+
+ Ip4 internal functions and type defintions.
+
+
+**/
+
+#ifndef __EFI_IP4_IMPL_H__
+#define __EFI_IP4_IMPL_H__
+
+#include <PiDxe.h>\r
+\r
+#include <Protocol/IP4.h>\r
+#include <Protocol/IP4Config.h>\r
+#include <Protocol/Arp.h>\r
+#include <Protocol/ManagedNetwork.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>
+#include <Library/NetLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "IP4Common.h"
+#include "IP4Driver.h"
+#include "IP4If.h"
+#include "Ip4Icmp.h"
+#include "IP4Option.h"
+#include "Ip4Igmp.h"
+#include "IP4Route.h"
+#include "IP4Input.h"
+#include "IP4Output.h"
+
+enum {
+ IP4_PROTOCOL_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', '4', 'P'),
+ IP4_SERVICE_SIGNATURE = EFI_SIGNATURE_32 ('I', 'P', '4', 'S'),
+
+ //
+ // The state of IP4 protocol. It starts from UNCONFIGED. if it is
+ // successfully configured, it goes to CONFIGED. if configure NULL
+ // is called, it becomes UNCONFIGED again. If (partly) destoried, it
+ // becomes DESTORY.
+ //
+ IP4_STATE_UNCONFIGED = 0,
+ IP4_STATE_CONFIGED,
+ IP4_STATE_DESTORY,
+
+ //
+ // The state of IP4 service. It starts from UNSTARTED. It transits
+ // to STARTED if autoconfigure is started. If default address is
+ // configured, it becomes CONFIGED. and if partly destoried, it goes
+ // to DESTORY.
+ //
+ IP4_SERVICE_UNSTARTED = 0,
+ IP4_SERVICE_STARTED,
+ IP4_SERVICE_CONFIGED,
+ IP4_SERVICE_DESTORY,
+};
+
+//
+// IP4_TXTOKEN_WRAP wraps the upper layer's transmit token.
+// The user's data is kept in the Packet. When fragment is
+// needed, each fragment of the Packet has a reference to the
+// Packet, no data is actually copied. The Packet will be
+// released when all the fragments of it have been recycled by
+// MNP. Upon then, the IP4_TXTOKEN_WRAP will be released, and
+// user's event signalled.
+//
+typedef struct {
+ IP4_PROTOCOL *IpInstance;
+ EFI_IP4_COMPLETION_TOKEN *Token;
+ NET_BUF *Packet;
+ BOOLEAN Sent;
+ INTN Life;
+} IP4_TXTOKEN_WRAP;
+
+//
+// IP4_RXDATA_WRAP wraps the data IP4 child delivers to the
+// upper layers. The received packet is kept in the Packet.
+// The Packet itself may be constructured from some fragments.
+// All the fragments of the Packet is organized by a
+// IP4_ASSEMBLE_ENTRY structure. If the Packet is recycled by
+// the upper layer, the assemble entry and its associated
+// fragments will be freed at last.
+//
+typedef struct {
+ NET_LIST_ENTRY Link;
+ IP4_PROTOCOL *IpInstance;
+ NET_BUF *Packet;
+ EFI_IP4_RECEIVE_DATA RxData;
+} IP4_RXDATA_WRAP;
+
+typedef struct _IP4_PROTOCOL {
+ UINT32 Signature;
+
+ EFI_IP4_PROTOCOL Ip4Proto;
+ EFI_HANDLE Handle;
+ INTN State;
+
+ IP4_SERVICE *Service;
+ NET_LIST_ENTRY Link; // Link to all the IP protocol from the service
+
+ //
+ // User's transmit/receive tokens, and received/deliverd packets
+ //
+ NET_MAP RxTokens;
+ NET_MAP TxTokens; // map between (User's Token, IP4_TXTOKE_WRAP)
+ NET_LIST_ENTRY Received; // Received but not delivered packet
+ NET_LIST_ENTRY Delivered; // Delivered and to be recycled packets
+ EFI_LOCK RecycleLock;
+
+ //
+ // Instance's address and route tables. There are two route tables.
+ // RouteTable is used by the IP4 driver to route packet. EfiRouteTable
+ // is used to communicate the current route info to the upper layer.
+ //
+ IP4_INTERFACE *Interface;
+ NET_LIST_ENTRY AddrLink; // Ip instances with the same IP address.
+ IP4_ROUTE_TABLE *RouteTable;
+
+ EFI_IP4_ROUTE_TABLE *EfiRouteTable;
+ UINT32 EfiRouteCount;
+
+ //
+ // IGMP data for this instance
+ //
+ IP4_ADDR *Groups; // stored in network byte order
+ UINT32 GroupCount;
+
+ EFI_IP4_CONFIG_DATA ConfigData;
+
+} IP4_PROTOCOL;
+
+typedef struct _IP4_SERVICE {
+ UINT32 Signature;
+ EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
+ INTN State;
+ BOOLEAN InDestory;
+
+ //
+ // List of all the IP instances and interfaces, and default
+ // interface and route table and caches.
+ //
+ UINTN NumChildren;
+ NET_LIST_ENTRY Children;
+
+ NET_LIST_ENTRY Interfaces;
+
+ IP4_INTERFACE *DefaultInterface;
+ IP4_ROUTE_TABLE *DefaultRouteTable;
+
+ //
+ // Ip reassemble utilities, and IGMP data
+ //
+ IP4_ASSEMBLE_TABLE Assemble;
+ IGMP_SERVICE_DATA IgmpCtrl;
+
+ //
+ // Low level protocol used by this service instance
+ //
+ EFI_HANDLE Image;
+ EFI_HANDLE Controller;
+
+ EFI_HANDLE MnpChildHandle;
+ EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
+
+ EFI_MANAGED_NETWORK_CONFIG_DATA MnpConfigData;
+ EFI_SIMPLE_NETWORK_MODE SnpMode;
+
+ EFI_EVENT Timer;
+
+ //
+ // Auto configure staff
+ //
+ EFI_IP4_CONFIG_PROTOCOL *Ip4Config;
+ EFI_EVENT DoneEvent;
+ EFI_EVENT ReconfigEvent;
+
+ //
+ // The string representation of the current mac address of the
+ // NIC this IP4_SERVICE works on.
+ //
+ CHAR16 *MacString;
+} IP4_SERVICE;
+
+#define IP4_INSTANCE_FROM_PROTOCOL(Ip4) \
+ CR ((Ip4), IP4_PROTOCOL, Ip4Proto, IP4_PROTOCOL_SIGNATURE)
+
+#define IP4_SERVICE_FROM_PROTOCOL(Sb) \
+ CR ((Sb), IP4_SERVICE, ServiceBinding, IP4_SERVICE_SIGNATURE)
+
+#define IP4_NO_MAPPING(IpInstance) (!(IpInstance)->Interface->Configured)
+
+extern EFI_IP4_PROTOCOL mEfiIp4ProtocolTemplete;
+
+EFI_STATUS
+Ip4ServiceConfigMnp (
+ IN IP4_SERVICE *IpSb,
+ IN BOOLEAN Force
+ );
+
+VOID
+Ip4InitProtocol (
+ IN IP4_SERVICE *IpSb,
+ IN IP4_PROTOCOL *IpInstance
+ );
+
+EFI_STATUS
+Ip4CleanProtocol (
+ IN IP4_PROTOCOL *IpInstance
+ );
+
+EFI_STATUS
+Ip4Cancel (
+ IN IP4_PROTOCOL *IpInstance,
+ IN EFI_IP4_COMPLETION_TOKEN *Token
+ );
+
+EFI_STATUS
+Ip4Groups (
+ IN IP4_PROTOCOL *IpInstance,
+ IN BOOLEAN JoinFlag,
+ IN EFI_IPv4_ADDRESS *GroupAddress
+ );
+
+VOID
+EFIAPI
+Ip4TimerTicking (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+Ip4SentPacketTicking (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item,
+ IN VOID *Context
+ );
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Ip4Input.c\r
+\r
+Abstract:\r
+\r
+ IP4 input process.\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+\r
+/**\r
+ Create a empty assemble entry for the packet identified by\r
+ (Dst, Src, Id, Protocol). The default life for the packet is\r
+ 120 seconds.\r
+\r
+ @param Dst The destination address\r
+ @param Src The source address\r
+ @param Id The ID field in IP header\r
+ @param Protocol The protocol field in IP header\r
+\r
+ @return NULL if failed to allocate memory for the entry, otherwise\r
+ @return the point to just created reassemble entry.\r
+\r
+**/\r
+STATIC\r
+IP4_ASSEMBLE_ENTRY *\r
+Ip4CreateAssembleEntry (\r
+ IN IP4_ADDR Dst,\r
+ IN IP4_ADDR Src,\r
+ IN UINT16 Id,\r
+ IN UINT8 Protocol\r
+ )\r
+{\r
+\r
+ IP4_ASSEMBLE_ENTRY *Assemble;\r
+\r
+ Assemble = NetAllocatePool (sizeof (IP4_ASSEMBLE_ENTRY));\r
+\r
+ if (Assemble == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetListInit (&Assemble->Link);\r
+ NetListInit (&Assemble->Fragments);\r
+\r
+ Assemble->Dst = Dst;\r
+ Assemble->Src = Src;\r
+ Assemble->Id = Id;\r
+ Assemble->Protocol = Protocol;\r
+ Assemble->TotalLen = 0;\r
+ Assemble->CurLen = 0;\r
+ Assemble->Head = NULL;\r
+ Assemble->Info = NULL;\r
+ Assemble->Life = IP4_FRAGMENT_LIFE;\r
+\r
+ return Assemble;\r
+}\r
+\r
+\r
+/**\r
+ Release all the fragments of a packet, then free the assemble entry\r
+\r
+ @param Assemble The assemble entry to free\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4FreeAssembleEntry (\r
+ IN IP4_ASSEMBLE_ENTRY *Assemble\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ NET_BUF *Fragment;\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Assemble->Fragments) {\r
+ Fragment = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+\r
+ NetListRemoveEntry (Entry);\r
+ NetbufFree (Fragment);\r
+ }\r
+\r
+ NetFreePool (Assemble);\r
+}\r
+\r
+\r
+/**\r
+ Initialize an already allocated assemble table. This is generally\r
+ the assemble table embedded in the IP4 service instance.\r
+\r
+ @param Table The assemble table to initialize.\r
+\r
+ @return NONE\r
+\r
+**/\r
+VOID\r
+Ip4InitAssembleTable (\r
+ IN IP4_ASSEMBLE_TABLE *Table\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {\r
+ NetListInit (&Table->Bucket[Index]);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Clean up the assemble table: remove all the fragments\r
+ and assemble entries.\r
+\r
+ @param Table The assemble table to clean up\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4CleanAssembleTable (\r
+ IN IP4_ASSEMBLE_TABLE *Table\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ASSEMBLE_ENTRY *Assemble;\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Table->Bucket[Index]) {\r
+ Assemble = NET_LIST_USER_STRUCT (Entry, IP4_ASSEMBLE_ENTRY, Link);\r
+\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeAssembleEntry (Assemble);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Trim the packet to fit in [Start, End), and update the per\r
+ packet information.\r
+\r
+ @param Packet Packet to trim\r
+ @param Start The sequence of the first byte to fit in\r
+ @param End One beyond the sequence of last byte to fit in.\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4TrimPacket (\r
+ IN NET_BUF *Packet,\r
+ IN INTN Start,\r
+ IN INTN End\r
+ )\r
+{\r
+ IP4_CLIP_INFO *Info;\r
+ INTN Len;\r
+\r
+ Info = IP4_GET_CLIP_INFO (Packet);\r
+\r
+ ASSERT (Info->Start + Info->Length == Info->End);\r
+ ASSERT ((Info->Start < End) && (Start < Info->End));\r
+\r
+ if (Info->Start < Start) {\r
+ Len = Start - Info->Start;\r
+\r
+ NetbufTrim (Packet, (UINT32) Len, NET_BUF_HEAD);\r
+ Info->Start = Start;\r
+ Info->Length -= Len;\r
+ }\r
+\r
+ if (End < Info->End) {\r
+ Len = End - Info->End;\r
+\r
+ NetbufTrim (Packet, (UINT32) Len, NET_BUF_TAIL);\r
+ Info->End = End;\r
+ Info->Length -= Len;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Release all the fragments of the packet. This is the callback for\r
+ the assembled packet's OnFree. It will free the assemble entry,\r
+ which in turn will free all the fragments of the packet.\r
+\r
+ @param Arg The assemble entry to free\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4OnFreeFragments (\r
+ IN VOID *Arg\r
+ )\r
+{\r
+ Ip4FreeAssembleEntry ((IP4_ASSEMBLE_ENTRY *) Arg);\r
+}\r
+\r
+\r
+/**\r
+ Reassemble the IP fragments. If all the fragments of the packet\r
+ have been received, it will wrap the packet in a net buffer then\r
+ return it to caller. If the packet can't be assembled, NULL is\r
+ return.\r
+\r
+ @param Table The assemble table used.\r
+ @param Packet The fragment to assemble\r
+\r
+ @return NULL if the packet can't be reassemble. The point to just assembled\r
+ @return packet if all the fragments of the packet have arrived.\r
+\r
+**/\r
+STATIC\r
+NET_BUF *\r
+Ip4Reassemble (\r
+ IN IP4_ASSEMBLE_TABLE *Table,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ IP4_HEAD *IpHead;\r
+ IP4_CLIP_INFO *This;\r
+ IP4_CLIP_INFO *Node;\r
+ IP4_ASSEMBLE_ENTRY *Assemble;\r
+ NET_LIST_ENTRY *Head;\r
+ NET_LIST_ENTRY *Prev;\r
+ NET_LIST_ENTRY *Cur;\r
+ NET_BUF *Fragment;\r
+ NET_BUF *NewPacket;\r
+ INTN Index;\r
+\r
+ IpHead = Packet->Ip;\r
+ This = IP4_GET_CLIP_INFO (Packet);\r
+\r
+ ASSERT (IpHead != NULL);\r
+\r
+ //\r
+ // First: find the related assemble entry\r
+ //\r
+ Assemble = NULL;\r
+ Index = IP4_ASSEMBLE_HASH (IpHead->Dst, IpHead->Src, IpHead->Id, IpHead->Protocol);\r
+\r
+ NET_LIST_FOR_EACH (Cur, &Table->Bucket[Index]) {\r
+ Assemble = NET_LIST_USER_STRUCT (Cur, IP4_ASSEMBLE_ENTRY, Link);\r
+\r
+ if ((Assemble->Dst == IpHead->Dst) && (Assemble->Src == IpHead->Src) &&\r
+ (Assemble->Id == IpHead->Id) && (Assemble->Protocol == IpHead->Protocol)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Create a new assemble entry if no assemble entry is related to this packet\r
+ //\r
+ if (Cur == &Table->Bucket[Index]) {\r
+ Assemble = Ip4CreateAssembleEntry (\r
+ IpHead->Dst,\r
+ IpHead->Src,\r
+ IpHead->Id,\r
+ IpHead->Protocol\r
+ );\r
+\r
+ if (Assemble == NULL) {\r
+ goto DROP;\r
+ }\r
+\r
+ NetListInsertHead (&Table->Bucket[Index], &Assemble->Link);\r
+ }\r
+\r
+ //\r
+ // Find the point to insert the packet: before the first\r
+ // fragment with THIS.Start < CUR.Start. the previous one\r
+ // has PREV.Start <= THIS.Start < CUR.Start.\r
+ //\r
+ Head = &Assemble->Fragments;\r
+\r
+ NET_LIST_FOR_EACH (Cur, Head) {\r
+ Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
+\r
+ if (This->Start < IP4_GET_CLIP_INFO (Fragment)->Start) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check whether the current fragment overlaps with the previous one.\r
+ // It holds that: PREV.Start <= THIS.Start < THIS.End. Only need to\r
+ // check whether THIS.Start < PREV.End for overlap. If two fragments\r
+ // overlaps, trim the overlapped part off THIS fragment.\r
+ //\r
+ if ((Prev = Cur->ForwardLink) != Head) {\r
+ Fragment = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);\r
+ Node = IP4_GET_CLIP_INFO (Fragment);\r
+\r
+ if (This->Start < Node->End) {\r
+ if (This->End <= Node->End) {\r
+ NetbufFree (Packet);\r
+ return NULL;\r
+ }\r
+\r
+ Ip4TrimPacket (Packet, Node->End, This->End);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Insert the fragment into the packet. The fragment may be removed\r
+ // from the list by the following checks.\r
+ //\r
+ NetListInsertBefore (Cur, &Packet->List);\r
+\r
+ //\r
+ // Check the packets after the insert point. It holds that:\r
+ // THIS.Start <= NODE.Start < NODE.End. The equality holds\r
+ // if PREV and NEXT are continuous. THIS fragment may fill\r
+ // several holes. Remove the completely overlapped fragments\r
+ //\r
+ while (Cur != Head) {\r
+ Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
+ Node = IP4_GET_CLIP_INFO (Fragment);\r
+\r
+ //\r
+ // Remove fragments completely overlapped by this fragment\r
+ //\r
+ if (Node->End <= This->End) {\r
+ Cur = Cur->ForwardLink;\r
+\r
+ NetListRemoveEntry (&Fragment->List);\r
+ Assemble->CurLen -= Node->Length;\r
+\r
+ NetbufFree (Fragment);\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // The conditions are: THIS.Start <= NODE.Start, and THIS.End <\r
+ // NODE.End. Two fragments overlaps if NODE.Start < THIS.End.\r
+ // If two fragments start at the same offset, remove THIS fragment\r
+ // because ((THIS.Start == NODE.Start) && (THIS.End < NODE.End)).\r
+ //\r
+ if (Node->Start < This->End) {\r
+ if (This->Start == Node->Start) {\r
+ NetListRemoveEntry (&Packet->List);\r
+ goto DROP;\r
+ }\r
+\r
+ Ip4TrimPacket (Packet, This->Start, Node->Start);\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Update the assemble info: increase the current length. If it is\r
+ // the frist fragment, update the packet's IP head and per packet\r
+ // info. If it is the last fragment, update the total length.\r
+ //\r
+ Assemble->CurLen += This->Length;\r
+\r
+ if (This->Start == 0) {\r
+ //\r
+ // Once the first fragment is enqueued, it can't be removed\r
+ // from the fragment list. So, Assemble->Head always point\r
+ // to valid memory area.\r
+ //\r
+ ASSERT (Assemble->Head == NULL);\r
+\r
+ Assemble->Head = IpHead;\r
+ Assemble->Info = IP4_GET_CLIP_INFO (Packet);\r
+ }\r
+\r
+ //\r
+ // Don't update the length more than once.\r
+ //\r
+ if (IP4_LAST_FRAGMENT (IpHead->Fragment) && (Assemble->TotalLen == 0)) {\r
+ Assemble->TotalLen = This->End;\r
+ }\r
+\r
+ //\r
+ // Deliver the whole packet if all the fragments received.\r
+ // All fragments received if:\r
+ // 1. received the last one, so, the totoal length is know\r
+ // 2. received all the data. If the last fragment on the\r
+ // queue ends at the total length, all data is received.\r
+ //\r
+ if ((Assemble->TotalLen != 0) && (Assemble->CurLen >= Assemble->TotalLen)) {\r
+\r
+ NetListRemoveEntry (&Assemble->Link);\r
+\r
+ //\r
+ // If the packet is properly formated, the last fragment's End\r
+ // equals to the packet's total length. Otherwise, the packet\r
+ // is a fake, drop it now.\r
+ //\r
+ Fragment = NET_LIST_USER_STRUCT (Head->BackLink, NET_BUF, List);\r
+\r
+ if (IP4_GET_CLIP_INFO (Fragment)->End != Assemble->TotalLen) {\r
+ Ip4FreeAssembleEntry (Assemble);\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Wrap the packet in a net buffer then deliver it up\r
+ //\r
+ NewPacket = NetbufFromBufList (\r
+ &Assemble->Fragments,\r
+ 0,\r
+ 0,\r
+ Ip4OnFreeFragments,\r
+ Assemble\r
+ );\r
+\r
+ if (NewPacket == NULL) {\r
+ Ip4FreeAssembleEntry (Assemble);\r
+ return NULL;\r
+ }\r
+\r
+ NewPacket->Ip = Assemble->Head;\r
+ CopyMem (IP4_GET_CLIP_INFO (NewPacket), Assemble->Info, sizeof (IP4_CLIP_INFO));\r
+ return NewPacket;\r
+ }\r
+\r
+ return NULL;\r
+\r
+DROP:\r
+ NetbufFree (Packet);\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ The IP4 input routine. It is called by the IP4_INTERFACE when a\r
+ IP4 fragment is received from MNP.\r
+\r
+ @param Ip4Instance The IP4 child that request the receive, most like\r
+ it is NULL.\r
+ @param Packet The IP4 packet received.\r
+ @param IoStatus The return status of receive request.\r
+ @param Flag The link layer flag for the packet received, such\r
+ as multicast.\r
+ @param Context The IP4 service instance that own the MNP.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4AccpetFrame (\r
+ IN IP4_PROTOCOL *Ip4Instance,\r
+ IN NET_BUF *Packet,\r
+ IN EFI_STATUS IoStatus,\r
+ IN UINT32 Flag,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ IP4_CLIP_INFO *Info;\r
+ IP4_HEAD *Head;\r
+ UINT32 HeadLen;\r
+ UINT32 OptionLen;\r
+ UINT32 TotalLen;\r
+ UINT16 Checksum;\r
+\r
+ IpSb = (IP4_SERVICE *) Context;\r
+\r
+ if (EFI_ERROR (IoStatus) || (IpSb->State == IP4_SERVICE_DESTORY)) {\r
+ goto DROP;\r
+ }\r
+\r
+ //\r
+ // Check that the IP4 header is correctly formated\r
+ //\r
+ if (Packet->TotalSize < IP4_MIN_HEADLEN) {\r
+ goto RESTART;\r
+ }\r
+\r
+ Head = (IP4_HEAD *) NetbufGetByte (Packet, 0, NULL);\r
+ HeadLen = (Head->HeadLen << 2);\r
+ TotalLen = NTOHS (Head->TotalLen);\r
+\r
+ //\r
+ // Mnp may deliver frame trailer sequence up, trim it off.\r
+ //\r
+ if (TotalLen < Packet->TotalSize) {\r
+ NetbufTrim (Packet, Packet->TotalSize - TotalLen, FALSE);\r
+ }\r
+\r
+ if ((Head->Ver != 4) || (HeadLen < IP4_MIN_HEADLEN) ||\r
+ (TotalLen < HeadLen) || (TotalLen != Packet->TotalSize)) {\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // Some OS may send IP packets without checksum.\r
+ //\r
+ Checksum = ~NetblockChecksum ((UINT8 *) Head, HeadLen);\r
+\r
+ if ((Head->Checksum != 0) && (Checksum != 0)) {\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // Convert the IP header to host byte order, then get the per packet info.\r
+ //\r
+ Packet->Ip = Ip4NtohHead (Head);\r
+\r
+ Info = IP4_GET_CLIP_INFO (Packet);\r
+ Info->LinkFlag = Flag;\r
+ Info->CastType = Ip4GetHostCast (IpSb, Head->Dst, Head->Src);\r
+ Info->Start = (Head->Fragment & IP4_HEAD_OFFSET_MASK) << 3;\r
+ Info->Length = Head->TotalLen - HeadLen;\r
+ Info->End = Info->Start + Info->Length;\r
+ Info->Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // The packet is destinated to us if the CastType is non-zero.\r
+ //\r
+ if ((Info->CastType == 0) || (Info->End > IP4_MAX_PACKET_SIZE)) {\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // Validate the options. Don't call the Ip4OptionIsValid if\r
+ // there is no option to save some CPU process.\r
+ //\r
+ OptionLen = HeadLen - IP4_MIN_HEADLEN;\r
+\r
+ if ((OptionLen > 0) && !Ip4OptionIsValid ((UINT8 *) (Head + 1), OptionLen, TRUE)) {\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // Trim the head off, after this point, the packet is headless.\r
+ // and Packet->TotalLen == Info->Length.\r
+ //\r
+ NetbufTrim (Packet, HeadLen, TRUE);\r
+\r
+ //\r
+ // Reassemble the packet if this is a fragment. The packet is a\r
+ // fragment if its head has MF (more fragment) set, or it starts\r
+ // at non-zero byte.\r
+ //\r
+ if ((Head->Fragment & IP4_HEAD_MF_MASK) || (Info->Start != 0)) {\r
+ //\r
+ // Drop the fragment if DF is set but it is fragmented. Gateway\r
+ // need to send a type 4 destination unreache ICMP message here.\r
+ //\r
+ if (Head->Fragment & IP4_HEAD_DF_MASK) {\r
+ goto RESTART;\r
+ }\r
+\r
+ //\r
+ // The length of all but the last fragments is in the unit of 8 bytes.\r
+ //\r
+ if ((Head->Fragment & IP4_HEAD_MF_MASK) && (Info->Length % 8 != 0)) {\r
+ goto RESTART;\r
+ }\r
+\r
+ Packet = Ip4Reassemble (&IpSb->Assemble, Packet);\r
+\r
+ //\r
+ // Packet assembly isn't complete, start receive more packet.\r
+ //\r
+ if (Packet == NULL) {\r
+ goto RESTART;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Packet may have been changed. Head, HeadLen, TotalLen, and\r
+ // info must be reloaded bofore use. The ownership of the packet\r
+ // is transfered to the packet process logic.\r
+ //\r
+ Head = Packet->Ip;\r
+ IP4_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS;\r
+\r
+ switch (Head->Protocol) {\r
+ case IP4_PROTO_ICMP:\r
+ Ip4IcmpHandle (IpSb, Head, Packet);\r
+ break;\r
+\r
+ case IP4_PROTO_IGMP:\r
+ Ip4IgmpHandle (IpSb, Head, Packet);\r
+ break;\r
+\r
+ default:\r
+ Ip4Demultiplex (IpSb, Head, Packet);\r
+ }\r
+\r
+ Packet = NULL;\r
+\r
+RESTART:\r
+ Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);\r
+\r
+DROP:\r
+ if (Packet != NULL) {\r
+ NetbufFree (Packet);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Check whether this IP child accepts the packet.\r
+\r
+ @param IpInstance The IP child to check\r
+ @param Head The IP header of the packet\r
+ @param Packet The data of the packet\r
+\r
+ @return TRUE if the child wants to receive the packet, otherwise return FALSE.\r
+\r
+**/\r
+BOOLEAN\r
+Ip4InstanceFrameAcceptable (\r
+ IN IP4_PROTOCOL *IpInstance,\r
+ IN IP4_HEAD *Head,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ IP4_ICMP_ERROR_HEAD Icmp;\r
+ EFI_IP4_CONFIG_DATA *Config;\r
+ IP4_CLIP_INFO *Info;\r
+ UINT16 Proto;\r
+ UINT32 Index;\r
+\r
+ Config = &IpInstance->ConfigData;\r
+\r
+ //\r
+ // Dirty trick for the Tiano UEFI network stack implmentation. If\r
+ // ReceiveTimeout == -1, the receive of the packet for this instance\r
+ // is disabled. The UEFI spec don't have such captibility. We add\r
+ // this to improve the performance because IP will make a copy of\r
+ // the received packet for each accepting instance. Some IP instances\r
+ // used by UDP/TCP only send packets, they don't wants to receive.\r
+ //\r
+ if (Config->ReceiveTimeout == (UINT32)(-1)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (Config->AcceptPromiscuous) {\r
+ return TRUE;\r
+ }\r
+\r
+ //\r
+ // Use protocol from the IP header embedded in the ICMP error\r
+ // message to filter, instead of ICMP itself. ICMP handle will\r
+ // can Ip4Demultiplex to deliver ICMP errors.\r
+ //\r
+ Proto = Head->Protocol;\r
+\r
+ if (Proto == IP4_PROTO_ICMP) {\r
+ NetbufCopy (Packet, 0, sizeof (Icmp.Head), (UINT8 *) &Icmp.Head);\r
+\r
+ if (mIcmpClass[Icmp.Head.Type].IcmpClass == ICMP_ERROR_MESSAGE) {\r
+ if (!Config->AcceptIcmpErrors) {\r
+ return FALSE;\r
+ }\r
+\r
+ NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
+ Proto = Icmp.IpHead.Protocol;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Match the protocol\r
+ //\r
+ if (!Config->AcceptAnyProtocol && (Proto != Config->DefaultProtocol)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Check for broadcast, the caller has computed the packet's\r
+ // cast type for this child's interface.\r
+ //\r
+ Info = IP4_GET_CLIP_INFO (Packet);\r
+\r
+ if (IP4_IS_BROADCAST (Info->CastType)) {\r
+ return Config->AcceptBroadcast;\r
+ }\r
+\r
+ //\r
+ // If it is a multicast packet, check whether we are in the group.\r
+ //\r
+ if (Info->CastType == IP4_MULTICAST) {\r
+ //\r
+ // Receive the multicast if the instance wants to receive all packets.\r
+ //\r
+ if (!IpInstance->ConfigData.UseDefaultAddress && (IpInstance->Interface->Ip == 0)) {\r
+ return TRUE;\r
+ }\r
+\r
+ for (Index = 0; Index < IpInstance->GroupCount; Index++) {\r
+ if (IpInstance->Groups[Index] == HTONL (Head->Dst)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return (BOOLEAN)(Index < IpInstance->GroupCount);\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Enqueue a shared copy of the packet to the IP4 child if the\r
+ packet is acceptable to it. Here the data of the packet is\r
+ shared, but the net buffer isn't.\r
+\r
+ @param IpInstance The IP4 child to enqueue the packet to\r
+ @param Head The IP header of the received packet\r
+ @param Packet The data of the received packet\r
+\r
+ @retval EFI_NOT_STARTED The IP child hasn't been configured.\r
+ @retval EFI_INVALID_PARAMETER The child doesn't want to receive the packet\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource\r
+ @retval EFI_SUCCESS A shared copy the packet is enqueued to the child.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4InstanceEnquePacket (\r
+ IN IP4_PROTOCOL *IpInstance,\r
+ IN IP4_HEAD *Head,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ IP4_CLIP_INFO *Info;\r
+ NET_BUF *Clone;\r
+\r
+ //\r
+ // Check whether the packet is acceptable to this instance.\r
+ //\r
+ if (IpInstance->State != IP4_STATE_CONFIGED) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ if (!Ip4InstanceFrameAcceptable (IpInstance, Head, Packet)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Enque a shared copy of the packet.\r
+ //\r
+ Clone = NetbufClone (Packet);\r
+\r
+ if (Clone == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Set the receive time out for the assembled packet. If it expires,\r
+ // packet will be removed from the queue.\r
+ //\r
+ Info = IP4_GET_CLIP_INFO (Clone);\r
+ Info->Life = IP4_US_TO_SEC (IpInstance->ConfigData.ReceiveTimeout);\r
+\r
+ NetListInsertTail (&IpInstance->Received, &Clone->List);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ The signal handle of IP4's recycle event. It is called back\r
+ when the upper layer release the packet.\r
+\r
+ @param Event The IP4's recycle event.\r
+ @param Context The context of the handle, which is a\r
+ IP4_RXDATA_WRAP\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+Ip4OnRecyclePacket (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_RXDATA_WRAP *Wrap;\r
+\r
+ Wrap = (IP4_RXDATA_WRAP *) Context;\r
+\r
+ NET_TRYLOCK (&Wrap->IpInstance->RecycleLock);\r
+ NetListRemoveEntry (&Wrap->Link);\r
+ NET_UNLOCK (&Wrap->IpInstance->RecycleLock);\r
+\r
+ ASSERT (!NET_BUF_SHARED (Wrap->Packet));\r
+ NetbufFree (Wrap->Packet);\r
+\r
+ gBS->CloseEvent (Wrap->RxData.RecycleSignal);\r
+ NetFreePool (Wrap);\r
+}\r
+\r
+\r
+/**\r
+ Wrap the received packet to a IP4_RXDATA_WRAP, which will be\r
+ delivered to the upper layer. Each IP4 child that accepts the\r
+ packet will get a not-shared copy of the packet which is wrapped\r
+ in the IP4_RXDATA_WRAP. The IP4_RXDATA_WRAP->RxData is passed\r
+ to the upper layer. Upper layer will signal the recycle event in\r
+ it when it is done with the packet.\r
+\r
+ @param IpInstance The IP4 child to receive the packet\r
+ @param Packet The packet to deliver up.\r
+\r
+ @return NULL if failed to wrap the packet, otherwise the wrapper.\r
+\r
+**/\r
+IP4_RXDATA_WRAP *\r
+Ip4WrapRxData (\r
+ IN IP4_PROTOCOL *IpInstance,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ IP4_RXDATA_WRAP *Wrap;\r
+ EFI_IP4_RECEIVE_DATA *RxData;\r
+ EFI_STATUS Status;\r
+\r
+ Wrap = NetAllocatePool (IP4_RXDATA_WRAP_SIZE (Packet->BlockOpNum));\r
+\r
+ if (Wrap == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetListInit (&Wrap->Link);\r
+\r
+ Wrap->IpInstance = IpInstance;\r
+ Wrap->Packet = Packet;\r
+ RxData = &Wrap->RxData;\r
+\r
+ NetZeroMem (&RxData->TimeStamp, sizeof (EFI_TIME));\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ NET_TPL_RECYCLE,\r
+ Ip4OnRecyclePacket,\r
+ Wrap,\r
+ &RxData->RecycleSignal\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetFreePool (Wrap);\r
+ return NULL;\r
+ }\r
+\r
+ ASSERT (Packet->Ip != NULL);\r
+\r
+ //\r
+ // The application expects a network byte order header.\r
+ //\r
+ RxData->HeaderLength = (Packet->Ip->HeadLen << 2);\r
+ RxData->Header = (EFI_IP4_HEADER *) Ip4NtohHead (Packet->Ip);\r
+\r
+ RxData->OptionsLength = RxData->HeaderLength - IP4_MIN_HEADLEN;\r
+ RxData->Options = NULL;\r
+\r
+ if (RxData->OptionsLength != 0) {\r
+ RxData->Options = (VOID *) (RxData->Header + 1);\r
+ }\r
+\r
+ RxData->DataLength = Packet->TotalSize;\r
+\r
+ //\r
+ // Build the fragment table to be delivered up.\r
+ //\r
+ RxData->FragmentCount = Packet->BlockOpNum;\r
+ NetbufBuildExt (Packet, (NET_FRAGMENT *) RxData->FragmentTable, &RxData->FragmentCount);\r
+\r
+ return Wrap;\r
+}\r
+\r
+\r
+/**\r
+ Deliver the received packets to upper layer if there are both received\r
+ requests and enqueued packets. If the enqueued packet is shared, it will\r
+ duplicate it to a non-shared packet, release the shared packet, then\r
+ deliver the non-shared packet up.\r
+\r
+ @param IpInstance The IP child to deliver the packet up.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to deliver the\r
+ packets.\r
+ @retval EFI_SUCCESS All the enqueued packets that can be delivered\r
+ are delivered up.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4InstanceDeliverPacket (\r
+ IN IP4_PROTOCOL *IpInstance\r
+ )\r
+{\r
+ EFI_IP4_COMPLETION_TOKEN *Token;\r
+ IP4_RXDATA_WRAP *Wrap;\r
+ NET_BUF *Packet;\r
+ NET_BUF *Dup;\r
+ UINT8 *Head;\r
+\r
+ //\r
+ // Deliver a packet if there are both a packet and a receive token.\r
+ //\r
+ while (!NetListIsEmpty (&IpInstance->Received) &&\r
+ !NetMapIsEmpty (&IpInstance->RxTokens)) {\r
+\r
+ Packet = NET_LIST_HEAD (&IpInstance->Received, NET_BUF, List);\r
+\r
+ if (!NET_BUF_SHARED (Packet)) {\r
+ //\r
+ // If this is the only instance that wants the packet, wrap it up.\r
+ //\r
+ Wrap = Ip4WrapRxData (IpInstance, Packet);\r
+\r
+ if (Wrap == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NetListRemoveEntry (&Packet->List);\r
+\r
+ } else {\r
+ //\r
+ // Create a duplicated packet if this packet is shared\r
+ //\r
+ Dup = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN);\r
+\r
+ if (Dup == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Copy the IP head over. The packet to deliver up is\r
+ // headless. Trim the head off after copy. The IP head\r
+ // may be not continuous before the data.\r
+ //\r
+ Head = NetbufAllocSpace (Dup, IP4_MAX_HEADLEN, NET_BUF_HEAD);\r
+ Dup->Ip = (IP4_HEAD *) Head;\r
+\r
+ NetCopyMem (Head, Packet->Ip, Packet->Ip->HeadLen << 2);\r
+ NetbufTrim (Dup, IP4_MAX_HEADLEN, TRUE);\r
+\r
+ Wrap = Ip4WrapRxData (IpInstance, Dup);\r
+\r
+ if (Wrap == NULL) {\r
+ NetbufFree (Dup);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NetListRemoveEntry (&Packet->List);\r
+ NetbufFree (Packet);\r
+\r
+ Packet = Dup;\r
+ }\r
+\r
+ //\r
+ // Insert it into the delivered packet, then get a user's\r
+ // receive token, pass the wrapped packet up.\r
+ //\r
+ NET_TRYLOCK (&IpInstance->RecycleLock);\r
+ NetListInsertHead (&IpInstance->Delivered, &Wrap->Link);\r
+ NET_UNLOCK (&IpInstance->RecycleLock);\r
+\r
+ Token = NetMapRemoveHead (&IpInstance->RxTokens, NULL);\r
+ Token->Status = IP4_GET_CLIP_INFO (Packet)->Status;\r
+ Token->Packet.RxData = &Wrap->RxData;\r
+\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Enqueue a received packet to all the IP children that share\r
+ the same interface.\r
+\r
+ @param IpSb The IP4 service instance that receive the packet\r
+ @param Head The header of the received packet\r
+ @param Packet The data of the received packet\r
+ @param IpIf The interface to enqueue the packet to\r
+\r
+ @return The number of the IP4 children that accepts the packet\r
+\r
+**/\r
+INTN\r
+Ip4InterfaceEnquePacket (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_HEAD *Head,\r
+ IN NET_BUF *Packet,\r
+ IN IP4_INTERFACE *IpIf\r
+ )\r
+{\r
+ IP4_PROTOCOL *IpInstance;\r
+ IP4_CLIP_INFO *Info;\r
+ NET_LIST_ENTRY *Entry;\r
+ INTN Enqueued;\r
+ INTN LocalType;\r
+ INTN SavedType;\r
+\r
+ //\r
+ // First, check that the packet is acceptable to this interface\r
+ // and find the local cast type for the interface. A packet sent\r
+ // to say 192.168.1.1 should NOT be delliever to 10.0.0.1 unless\r
+ // promiscuous receiving.\r
+ //\r
+ LocalType = 0;\r
+ Info = IP4_GET_CLIP_INFO (Packet);\r
+\r
+ if ((Info->CastType == IP4_MULTICAST) || (Info->CastType == IP4_LOCAL_BROADCAST)) {\r
+ //\r
+ // If the CastType is multicast, don't need to filter against\r
+ // the group address here, Ip4InstanceFrameAcceptable will do\r
+ // that later.\r
+ //\r
+ LocalType = Info->CastType;\r
+\r
+ } else {\r
+ //\r
+ // Check the destination againist local IP. If the station\r
+ // address is 0.0.0.0, it means receiving all the IP destined\r
+ // to local non-zero IP. Otherwise, it is necessary to compare\r
+ // the destination to the interface's IP address.\r
+ //\r
+ if (IpIf->Ip == IP4_ALLZERO_ADDRESS) {\r
+ LocalType = IP4_LOCAL_HOST;\r
+\r
+ } else {\r
+ LocalType = Ip4GetNetCast (Head->Dst, IpIf);\r
+\r
+ if ((LocalType == 0) && IpIf->PromiscRecv) {\r
+ LocalType = IP4_PROMISCUOUS;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (LocalType == 0) {\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Iterate through the ip instances on the interface, enqueue\r
+ // the packet if filter passed. Save the original cast type,\r
+ // and pass the local cast type to the IP children on the\r
+ // interface. The global cast type will be restored later.\r
+ //\r
+ SavedType = Info->CastType;\r
+ Info->CastType = LocalType;\r
+\r
+ Enqueued = 0;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
+ IpInstance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);\r
+ NET_CHECK_SIGNATURE (IpInstance, IP4_PROTOCOL_SIGNATURE);\r
+\r
+ if (Ip4InstanceEnquePacket (IpInstance, Head, Packet) == EFI_SUCCESS) {\r
+ Enqueued++;\r
+ }\r
+ }\r
+\r
+ Info->CastType = SavedType;\r
+ return Enqueued;\r
+}\r
+\r
+\r
+/**\r
+ Deliver the packet for each IP4 child on the interface.\r
+\r
+ @param IpSb The IP4 service instance that received the packet\r
+ @param IpIf The IP4 interface to deliver the packet.\r
+\r
+ @retval EFI_SUCCESS It always returns EFI_SUCCESS now\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4InterfaceDeliverPacket (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_INTERFACE *IpIf\r
+ )\r
+{\r
+ IP4_PROTOCOL *Ip4Instance;\r
+ NET_LIST_ENTRY *Entry;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
+ Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);\r
+ Ip4InstanceDeliverPacket (Ip4Instance);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Demultiple the packet. the packet delivery is processed in two\r
+ passes. The first pass will enque a shared copy of the packet\r
+ to each IP4 child that accepts the packet. The second pass will\r
+ deliver a non-shared copy of the packet to each IP4 child that\r
+ has pending receive requests. Data is copied if more than one\r
+ child wants to consume the packet bacause each IP child need\r
+ its own copy of the packet to make changes.\r
+\r
+ @param IpSb The IP4 service instance that received the packet\r
+ @param Head The header of the received packet\r
+ @param Packet The data of the received packet\r
+\r
+ @retval EFI_NOT_FOUND No IP child accepts the packet\r
+ @retval EFI_SUCCESS The packet is enqueued or delivered to some IP\r
+ children.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Demultiplex (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_HEAD *Head,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_INTERFACE *IpIf;\r
+ INTN Enqueued;\r
+\r
+ //\r
+ // Two pass delivery: first, enque a shared copy of the packet\r
+ // to each instance that accept the packet.\r
+ //\r
+ Enqueued = 0;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ if (IpIf->Configured) {\r
+ Enqueued += Ip4InterfaceEnquePacket (IpSb, Head, Packet, IpIf);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Second: deliver a duplicate of the packet to each instance.\r
+ // Release the local reference first, so that the last instance\r
+ // getting the packet will not copy the data.\r
+ //\r
+ NetbufFree (Packet);\r
+\r
+ if (Enqueued == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ if (IpIf->Configured) {\r
+ Ip4InterfaceDeliverPacket (IpSb, IpIf);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Timeout the fragment and enqueued packets.\r
+\r
+ @param IpSb The IP4 service instance to timeout\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4PacketTimerTicking (\r
+ IN IP4_SERVICE *IpSb\r
+ )\r
+{\r
+ NET_LIST_ENTRY *InstanceEntry;\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_PROTOCOL *IpInstance;\r
+ IP4_ASSEMBLE_ENTRY *Assemble;\r
+ NET_BUF *Packet;\r
+ IP4_CLIP_INFO *Info;\r
+ UINT32 Index;\r
+\r
+ //\r
+ // First, time out the fragments. The packet's life is counting down\r
+ // once the first-arrived fragment was received.\r
+ //\r
+ for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->Assemble.Bucket[Index]) {\r
+ Assemble = NET_LIST_USER_STRUCT (Entry, IP4_ASSEMBLE_ENTRY, Link);\r
+\r
+ if ((Assemble->Life > 0) && (--Assemble->Life == 0)) {\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeAssembleEntry (Assemble);\r
+ }\r
+ }\r
+ }\r
+\r
+ NET_LIST_FOR_EACH (InstanceEntry, &IpSb->Children) {\r
+ IpInstance = NET_LIST_USER_STRUCT (InstanceEntry, IP4_PROTOCOL, Link);\r
+\r
+ //\r
+ // Second, time out the assembled packets enqueued on each IP child.\r
+ //\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpInstance->Received) {\r
+ Packet = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+ Info = IP4_GET_CLIP_INFO (Packet);\r
+\r
+ if ((Info->Life > 0) && (--Info->Life == 0)) {\r
+ NetListRemoveEntry (Entry);\r
+ NetbufFree (Packet);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Third: time out the transmitted packets.\r
+ //\r
+ NetMapIterate (&IpInstance->TxTokens, Ip4SentPacketTicking, NULL);\r
+ }\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Ip4Input.h
+
+Abstract:
+
+
+**/
+
+#ifndef __EFI_IP4_INPUT_H__
+#define __EFI_IP4_INPUT_H__
+
+enum {
+ IP4_MIN_HEADLEN = 20,
+ IP4_MAX_HEADLEN = 60,
+
+ IP4_ASSEMLE_HASH_SIZE = 31,
+ IP4_FRAGMENT_LIFE = 120,
+ IP4_MAX_PACKET_SIZE = 65535,
+};
+
+//
+// Per packet information for input process. LinkFlag specifies whether
+// the packet is received as Link layer unicast, multicast or broadcast.
+// The CastType is the IP layer cast type, such as IP multicast or unicast.
+// Start, End and Length are staffs used to assemble the packets. Start
+// is the sequence number of the first byte of data in the packet. Length
+// is the number of bytes of data. End = Start + Length, that is, the
+// sequence number of last byte + 1. Each assembled packet has a count down
+// life. If it isn't consumed before Life reaches zero, the packet is released.
+//
+typedef struct {
+ UINTN LinkFlag;
+ INTN CastType;
+ INTN Start;
+ INTN End;
+ INTN Length;
+ UINT32 Life;
+ EFI_STATUS Status;
+} IP4_CLIP_INFO;
+
+//
+// Structure used to assemble IP packets.
+//
+typedef struct {
+ NET_LIST_ENTRY Link;
+
+ //
+ // Identity of one IP4 packet. Each fragment of a packet has
+ // the same (Dst, Src, Id, Protocol).
+ //
+ IP4_ADDR Dst;
+ IP4_ADDR Src;
+ UINT16 Id;
+ UINT8 Protocol;
+
+ INTN TotalLen;
+ INTN CurLen;
+ NET_LIST_ENTRY Fragments; // List of all the fragments of this packet
+
+ IP4_HEAD *Head; // IP head of the first fragment
+ IP4_CLIP_INFO *Info; // Per packet info of the first fragment
+ INTN Life; // Count down life for the packet.
+} IP4_ASSEMBLE_ENTRY;
+
+//
+// Each Ip service instance has an assemble table to reassemble
+// the packets before delivery to its children. It is organized
+// as hash table.
+//
+typedef struct {
+ NET_LIST_ENTRY Bucket[IP4_ASSEMLE_HASH_SIZE];
+} IP4_ASSEMBLE_TABLE;
+
+#define IP4_GET_CLIP_INFO(Packet) ((IP4_CLIP_INFO *) ((Packet)->ProtoData))
+
+#define IP4_ASSEMBLE_HASH(Dst, Src, Id, Proto) \
+ (((Dst) + (Src) + ((Id) << 16) + (Proto)) % IP4_ASSEMLE_HASH_SIZE)
+
+#define IP4_RXDATA_WRAP_SIZE(NumFrag) \
+ (sizeof (IP4_RXDATA_WRAP) + sizeof (EFI_IP4_FRAGMENT_DATA) * ((NumFrag) - 1))
+
+VOID
+Ip4InitAssembleTable (
+ IN IP4_ASSEMBLE_TABLE *Table
+ );
+
+VOID
+Ip4CleanAssembleTable (
+ IN IP4_ASSEMBLE_TABLE *Table
+ );
+
+VOID
+Ip4AccpetFrame (
+ IN IP4_PROTOCOL *Ip4Instance,
+ IN NET_BUF *Packet,
+ IN EFI_STATUS IoStatus,
+ IN UINT32 Flag,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+Ip4Demultiplex (
+ IN IP4_SERVICE *SbInstance,
+ IN IP4_HEAD *Head,
+ IN NET_BUF *Packet
+ );
+
+INTN
+Ip4InterfaceEnquePacket (
+ IN IP4_SERVICE *SbInstance,
+ IN IP4_HEAD *Head,
+ IN NET_BUF *Packet,
+ IN IP4_INTERFACE *Interface
+ );
+
+EFI_STATUS
+Ip4InstanceDeliverPacket (
+ IN IP4_PROTOCOL *Ip4Instance
+ );
+
+VOID
+Ip4PacketTimerTicking (
+ IN IP4_SERVICE *IpSb
+ );
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Ip4Option.c\r
+\r
+Abstract:\r
+\r
+ IP4 option support functions\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+\r
+/**\r
+ Validate the IP4 option format for both the packets we received\r
+ and will transmit. It will compute the ICMP error message fields\r
+ if the option is mal-formated. But this information isn't used.\r
+\r
+ @param Option The first byte of the option\r
+ @param OptionLen The length of the whole option\r
+ @param Rcvd The option is from the packet we received if TRUE,\r
+ otherwise the option we wants to transmit.\r
+\r
+ @return TRUE: The option is properly formated\r
+ @return FALSE: The option is mal-formated\r
+\r
+**/\r
+BOOLEAN\r
+Ip4OptionIsValid (\r
+ IN UINT8 *Option,\r
+ IN UINT32 OptionLen,\r
+ IN BOOLEAN Rcvd\r
+ )\r
+{\r
+ UINT32 Cur;\r
+ UINT32 Len;\r
+ UINT32 Point;\r
+ UINT8 IcmpType;\r
+ UINT8 IcmpCode;\r
+ UINT32 IcmpPoint;\r
+\r
+ IcmpType = ICMP_PARAMETER_PROBLEM;\r
+ IcmpCode = 0;\r
+ IcmpPoint = 0;\r
+\r
+ Cur = 0;\r
+\r
+ while (Cur < OptionLen) {\r
+ switch (Option[Cur]) {\r
+ case IP4_OPTION_NOP:\r
+ Cur++;\r
+ break;\r
+\r
+ case IP4_OPTION_EOP:\r
+ Cur = OptionLen;\r
+ break;\r
+\r
+ case IP4_OPTION_LSRR:\r
+ case IP4_OPTION_SSRR:\r
+ case IP4_OPTION_RR:\r
+ Len = Option[Cur + 1];\r
+ Point = Option[Cur + 2];\r
+\r
+ //\r
+ // SRR/RR options are formated as |Type|Len|Point|Ip1|Ip2|...\r
+ //\r
+ if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) {\r
+ IcmpPoint = Cur + 1;\r
+ return FALSE;\r
+ }\r
+\r
+ if ((Point > Len + 1) || (Point % 4 != 0)) {\r
+ IcmpPoint = Cur + 2;\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // The Point must point pass the last entry if the packet is received\r
+ // by us. It must point to 4 if the packet is to be sent by us for\r
+ // source route option.\r
+ //\r
+ if ((Option[Cur] != IP4_OPTION_RR) &&\r
+ ((Rcvd && (Point != Len + 1)) || (!Rcvd && (Point != 4)))) {\r
+\r
+ IcmpType = ICMP_DEST_UNREACHABLE;\r
+ IcmpCode = ICMP_SOURCEROUTE_FAILED;\r
+ return FALSE;\r
+ }\r
+\r
+ Cur += Len;\r
+ break;\r
+\r
+ default:\r
+ Len = Option[Cur + 1];\r
+\r
+ if ((OptionLen - Cur < Len) || (Len < 2)) {\r
+ IcmpPoint = Cur + 1;\r
+ return FALSE;\r
+ }\r
+\r
+ Cur = Cur + Len;\r
+ break;\r
+ }\r
+\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Copy the option from the original option to buffer. It\r
+ handles the details such as:\r
+ 1. whether copy the single IP4 option to the first/non-first\r
+ fragments.\r
+ 2. Pad the options copied over to aligened to 4 bytes.\r
+\r
+ @param Option The original option to copy from\r
+ @param OptionLen The length of the original option\r
+ @param FirstFragment Whether it is the first fragment\r
+ @param Buf The buffer to copy options to\r
+ @param BufLen The length of the buffer\r
+\r
+ @retval EFI_SUCCESS The options are copied over\r
+ @retval EFI_BUFFER_TOO_SMALL The buffer caller provided is too small.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4CopyOption (\r
+ IN UINT8 *Option,\r
+ IN UINT32 OptionLen,\r
+ IN BOOLEAN FirstFragment,\r
+ IN UINT8 *Buf, OPTIONAL\r
+ IN OUT UINT32 *BufLen\r
+ )\r
+{\r
+ UINT8 OptBuf[40];\r
+ UINT32 Cur;\r
+ UINT32 Next;\r
+ UINT8 Type;\r
+ UINT32 Len;\r
+\r
+ ASSERT ((BufLen != NULL) && (OptionLen <= 40));\r
+\r
+ Cur = 0;\r
+ Next = 0;\r
+\r
+ while (Cur < OptionLen) {\r
+ Type = Option[Cur];\r
+ Len = Option[Cur + 1];\r
+\r
+ if (Type == IP4_OPTION_NOP) {\r
+ //\r
+ // Keep the padding, in case that the sender wants to align\r
+ // the option, say, to 4 bytes\r
+ //\r
+ OptBuf[Next] = IP4_OPTION_NOP;\r
+ Next++;\r
+ Cur++;\r
+\r
+ } else if (Type == IP4_OPTION_EOP) {\r
+ //\r
+ // Don't append the EOP to avoid including only a EOP option\r
+ //\r
+ break;\r
+\r
+ } else {\r
+ //\r
+ // don't copy options that is only valid for the first fragment\r
+ //\r
+ if (FirstFragment || (Type & IP4_OPTION_COPY_MASK)) {\r
+ NetCopyMem (OptBuf + Next, Option + Cur, Len);\r
+ Next += Len;\r
+ }\r
+\r
+ Cur += Len;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Don't append an EOP only option.\r
+ //\r
+ if (Next == 0) {\r
+ *BufLen = 0;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Append an EOP if the end of option doesn't coincide with the\r
+ // end of the IP header, that is, isn't aligned to 4 bytes..\r
+ //\r
+ if ((Next % 4) != 0) {\r
+ OptBuf[Next] = IP4_OPTION_EOP;\r
+ Next++;\r
+ }\r
+\r
+ //\r
+ // Head length is in the unit of 4 bytes. Now, Len is the\r
+ // acutal option length to appear in the IP header.\r
+ //\r
+ Len = ((Next + 3) &~0x03);\r
+\r
+ //\r
+ // If the buffer is too small, set the BufLen then return\r
+ //\r
+ if ((Buf == NULL) || (*BufLen < Len)) {\r
+ *BufLen = Len;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ //\r
+ // Copy the option to the Buf, zero the buffer first to pad\r
+ // the options with NOP to align to 4 bytes.\r
+ //\r
+ NetZeroMem (Buf, Len);\r
+ NetCopyMem (Buf, OptBuf, Next);\r
+ *BufLen = Len;\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Ip4Option.h
+
+Abstract:
+
+ IP4 option support routines.
+
+
+**/
+
+#ifndef __EFI_IP4_OPTION_H__
+#define __EFI_IP4_OPTION_H__
+
+enum {
+ IP4_OPTION_EOP = 0,
+ IP4_OPTION_NOP = 1,
+ IP4_OPTION_LSRR = 131, // Loss source and record routing, 10000011
+ IP4_OPTION_SSRR = 137, // Strict source and record routing, 10001001
+ IP4_OPTION_RR = 7, // Record routing, 00000111
+
+ IP4_OPTION_COPY_MASK = 0x80,
+};
+
+BOOLEAN
+Ip4OptionIsValid (
+ IN UINT8 *Option,
+ IN UINT32 OptLen,
+ IN BOOLEAN Rcvd
+ );
+
+EFI_STATUS
+Ip4CopyOption (
+ IN UINT8 *Option,
+ IN UINT32 OptLen,
+ IN BOOLEAN Fragment,
+ IN UINT8 *Buf, OPTIONAL
+ IN OUT UINT32 *BufLen
+ );
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Ip4Output.c\r
+\r
+Abstract:\r
+\r
+ Transmit the IP4 packet\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+UINT16 mIp4Id;\r
+\r
+\r
+/**\r
+ Prepend an IP4 head to the Packet. It will copy the options and\r
+ build the IP4 header fields. Used for IP4 fragmentation.\r
+\r
+ @param Packet The packet to prepend IP4 header to\r
+ @param Head The caller supplied header. The caller should set\r
+ the following header fields: Tos, TotalLen, Id,\r
+ Fragment, Ttl, Protocol, Src and Dst. All the fields\r
+ are in host byte order. This function will fill in\r
+ the Ver, HeadLen, and checksum.\r
+ @param Option The orginal IP4 option to copy from\r
+ @param OptLen The length of the IP4 option\r
+\r
+ @retval EFI_BAD_BUFFER_SIZE There is no enought room in the head space of\r
+ Packet.\r
+ @retval EFI_SUCCESS The IP4 header is successfully added to the packet.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4PrependHead (\r
+ IN NET_BUF *Packet,\r
+ IN IP4_HEAD *Head,\r
+ IN UINT8 *Option,\r
+ IN UINT32 OptLen\r
+ )\r
+{\r
+ UINT32 HeadLen;\r
+ UINT32 Len;\r
+ IP4_HEAD *PacketHead;\r
+ BOOLEAN FirstFragment;\r
+\r
+ //\r
+ // Prepend the options: first get the option length, then copy it over.\r
+ //\r
+ HeadLen = 0;\r
+ FirstFragment = IP4_FIRST_FRAGMENT (Head->Fragment);\r
+\r
+ Ip4CopyOption (Option, OptLen, FirstFragment, NULL, &Len);\r
+\r
+ HeadLen = IP4_MIN_HEADLEN + Len;\r
+ ASSERT (((Len %4) == 0) && (HeadLen <= IP4_MAX_HEADLEN));\r
+\r
+ PacketHead = (IP4_HEAD *) NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);\r
+\r
+ if (PacketHead == NULL) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ Ip4CopyOption (Option, OptLen, FirstFragment, (UINT8 *) (PacketHead + 1), &Len);\r
+\r
+ //\r
+ // Set the head up, convert the host byte order to network byte order\r
+ //\r
+ PacketHead->Ver = 4;\r
+ PacketHead->HeadLen = (UINT8) (HeadLen >> 2);\r
+ PacketHead->Tos = Head->Tos;\r
+ PacketHead->TotalLen = HTONS (Packet->TotalSize);\r
+ PacketHead->Id = HTONS (Head->Id);\r
+ PacketHead->Fragment = HTONS (Head->Fragment);\r
+ PacketHead->Checksum = 0;\r
+ PacketHead->Ttl = Head->Ttl;\r
+ PacketHead->Protocol = Head->Protocol;\r
+ PacketHead->Src = HTONL (Head->Src);\r
+ PacketHead->Dst = HTONL (Head->Dst);\r
+ PacketHead->Checksum = ~NetblockChecksum ((UINT8 *) PacketHead, HeadLen);\r
+\r
+ Packet->Ip = PacketHead;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Select an interface to send the packet generated in the IP4 driver\r
+ itself, that is, not by the requests of IP4 child's consumer. Such\r
+ packets include the ICMP echo replies, and other ICMP error packets.\r
+\r
+ @param IpSb The IP4 service that wants to send the packets.\r
+ @param Dst The destination of the packet\r
+ @param Src The source of the packet\r
+\r
+ @return NULL if no proper interface is found, otherwise the interface that\r
+ @return can be used to send the system packet from.\r
+\r
+**/\r
+IP4_INTERFACE *\r
+Ip4SelectInterface (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_ADDR Dst,\r
+ IN IP4_ADDR Src\r
+ )\r
+{\r
+ IP4_INTERFACE *IpIf;\r
+ IP4_INTERFACE *Selected;\r
+ NET_LIST_ENTRY *Entry;\r
+\r
+ //\r
+ // Select the interface the Dst is on if one of the connected\r
+ // network. Some IP instance may be configured with 0.0.0.0/0,\r
+ // don't select that interface now.\r
+ //\r
+ IpIf = Ip4FindNet (IpSb, Dst);\r
+\r
+ if ((IpIf != NULL) && (IpIf->Ip != IP4_ALLZERO_ADDRESS)) {\r
+ return IpIf;\r
+ }\r
+\r
+ //\r
+ // If source is one of the interface address, select it.\r
+ //\r
+ IpIf = Ip4FindInterface (IpSb, Src);\r
+\r
+ if ((IpIf != NULL) && (IpIf->Ip != IP4_ALLZERO_ADDRESS)) {\r
+ return IpIf;\r
+ }\r
+\r
+ //\r
+ // Select a configured interface as the fall back. Always prefer\r
+ // an interface with non-zero address.\r
+ //\r
+ Selected = NULL;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
+ IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);\r
+\r
+ if (IpIf->Configured && ((Selected == NULL) || (Selected->Ip == 0))) {\r
+ Selected = IpIf;\r
+ }\r
+ }\r
+\r
+ return Selected;\r
+}\r
+\r
+\r
+/**\r
+ The default callback function for system generated packet.\r
+ It will free the packet.\r
+\r
+ @param Ip4Instance The IP4 child that issued the transmission. It most\r
+ like is NULL.\r
+ @param Packet The packet that transmitted.\r
+ @param IoStatus The result of the transmission, succeeded or failed.\r
+ @param LinkFlag Not used when transmission. check IP4_FRAME_CALLBACK\r
+ for reference.\r
+ @param Context The context provided by us\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4SysPacketSent (\r
+ IP4_PROTOCOL *Ip4Instance,\r
+ NET_BUF *Packet,\r
+ EFI_STATUS IoStatus,\r
+ UINT32 LinkFlag,\r
+ VOID *Context\r
+ )\r
+{\r
+ NetbufFree (Packet);\r
+}\r
+\r
+\r
+/**\r
+ Transmit an IP4 packet. The packet comes either from the IP4\r
+ child's consumer (IpInstance != NULL) or the IP4 driver itself\r
+ (IpInstance == NULL). It will route the packet, fragment it,\r
+ then transmit all the fragments through some interface.\r
+\r
+ @param IpSb The IP4 service instance to transmit the packet\r
+ @param IpInstance The IP4 child that issues the transmission. It is\r
+ NULL if the packet is from the system.\r
+ @param Packet The user data to send, excluding the IP header.\r
+ @param Head The caller supplied header. The caller should set\r
+ the following header fields: Tos, TotalLen, Id, tl,\r
+ Fragment, Protocol, Src and Dst. All the fields are\r
+ in host byte order. This function will fill in the\r
+ Ver, HeadLen, Fragment, and checksum. The Fragment\r
+ only need to include the DF flag. Ip4Output will\r
+ compute the MF and offset for you.\r
+ @param Option The original option to append to the IP headers\r
+ @param OptLen The length of the option\r
+ @param GateWay The next hop address to transmit packet to.\r
+ 255.255.255.255 means broadcast.\r
+ @param Callback The callback function to issue when transmission\r
+ completed.\r
+ @param Context The opaque context for the callback\r
+\r
+ @retval EFI_NO_MAPPING There is no interface to the destination.\r
+ @retval EFI_NOT_FOUND There is no route to the destination\r
+ @retval EFI_SUCCESS The packet is successfully transmitted.\r
+ @retval Others Failed to transmit the packet.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Output (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN IP4_PROTOCOL *IpInstance, OPTIONAL\r
+ IN NET_BUF *Packet,\r
+ IN IP4_HEAD *Head,\r
+ IN UINT8 *Option,\r
+ IN UINT32 OptLen,\r
+ IN IP4_ADDR GateWay,\r
+ IN IP4_FRAME_CALLBACK Callback,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_INTERFACE *IpIf;\r
+ IP4_ROUTE_CACHE_ENTRY *CacheEntry;\r
+ IP4_ADDR Dest;\r
+ EFI_STATUS Status;\r
+ NET_BUF *Fragment;\r
+ UINT32 Index;\r
+ UINT32 HeadLen;\r
+ UINT32 PacketLen;\r
+ UINT32 Offset;\r
+ UINT32 Mtu;\r
+ UINT32 Num;\r
+\r
+ //\r
+ // Select an interface/source for system packet, application\r
+ // should select them itself.\r
+ //\r
+ if (IpInstance == NULL) {\r
+ IpIf = Ip4SelectInterface (IpSb, Head->Dst, Head->Src);\r
+ } else {\r
+ IpIf = IpInstance->Interface;\r
+ }\r
+\r
+ if (IpIf == NULL) {\r
+ return EFI_NO_MAPPING;\r
+ }\r
+\r
+ if ((Head->Src == IP4_ALLZERO_ADDRESS) && (IpInstance == NULL)) {\r
+ Head->Src = IpIf->Ip;\r
+ }\r
+\r
+ //\r
+ // Route the packet unless overrided, that is, GateWay isn't zero.\r
+ //\r
+ if (GateWay == IP4_ALLZERO_ADDRESS) {\r
+ Dest = Head->Dst;\r
+\r
+ if (IP4_IS_BROADCAST (Ip4GetNetCast (Dest, IpIf)) || (Dest == IP4_ALLONE_ADDRESS)) {\r
+ //\r
+ // Set the gateway to local broadcast if the Dest is\r
+ // is the broadcast address for the connected network\r
+ // or it is local broadcast.\r
+ //\r
+ GateWay = IP4_ALLONE_ADDRESS;\r
+\r
+ } else if (IP4_IS_MULTICAST (Dest)) {\r
+ //\r
+ // Set the gateway to the destination if it is an multicast\r
+ // address. The IP4_INTERFACE won't consult ARP to send local\r
+ // broadcast and multicast.\r
+ //\r
+ GateWay = Head->Dst;\r
+\r
+ } else {\r
+ //\r
+ // Consult the route table to route the packet\r
+ //\r
+ if (IpInstance == NULL) {\r
+ CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src);\r
+ } else {\r
+ CacheEntry = Ip4Route (IpInstance->RouteTable, Head->Dst, Head->Src);\r
+ }\r
+\r
+ if (CacheEntry == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ GateWay = CacheEntry->NextHop;\r
+ Ip4FreeRouteCacheEntry (CacheEntry);\r
+ }\r
+ }\r
+\r
+ //\r
+ // OK, selected the source and route, fragment the packet then send\r
+ // them. Tag each fragment other than the first one as spawn from it.\r
+ //\r
+ Mtu = IpSb->SnpMode.MaxPacketSize;\r
+ HeadLen = sizeof (IP4_HEAD) + (OptLen + 3) &~0x03;\r
+ Head->Id = mIp4Id++;\r
+\r
+ if (Packet->TotalSize + HeadLen > Mtu) {\r
+ //\r
+ // Packet is fragmented from the tail to the head, that is, the\r
+ // first frame sent is the last fragment of the packet. The first\r
+ // fragment is NOT sent in this loop. First compute how many\r
+ // fragments there are.\r
+ //\r
+ Mtu = (Mtu - HeadLen) & (~0x07);\r
+ Num = (Packet->TotalSize + Mtu - 1) / Mtu;\r
+\r
+ //\r
+ // Initialize the packet length and Offset. Other than the last\r
+ // fragment, the packet length equals to MTU. The offset is always\r
+ // aligned to MTU.\r
+ //\r
+ PacketLen = Packet->TotalSize - (Num - 1) * Mtu;\r
+ Offset = Mtu * (Num - 1);\r
+\r
+ for (Index = 0; Index < Num - 1; Index++, Offset -= Mtu) {\r
+ Fragment = NetbufGetFragment (Packet, Offset, PacketLen, IP4_MAX_HEADLEN);\r
+\r
+ if (Fragment == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Update the header's fragment. The caller fills the IP4 header\r
+ // fields that are required by Ip4PrependHead except the fragment.\r
+ //\r
+ Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, (Index != 0), Offset);\r
+ Ip4PrependHead (Fragment, Head, Option, OptLen);\r
+\r
+ //\r
+ // Transmit the fragments, pass the Packet address as the context.\r
+ // So, we can find all the fragments spawned from the Packet by\r
+ // compare the NetBuf and Context to the Packet.\r
+ //\r
+ Status = Ip4SendFrame (\r
+ IpIf,\r
+ IpInstance,\r
+ Fragment,\r
+ GateWay,\r
+ Ip4SysPacketSent,\r
+ Packet\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ PacketLen = Mtu;\r
+ }\r
+\r
+ //\r
+ // Trim the already sent data, then adjust the head's fragment field.\r
+ //\r
+ NetbufTrim (Packet, Packet->TotalSize - Mtu, FALSE);\r
+ Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, TRUE, 0);\r
+ }\r
+\r
+ //\r
+ // Send the first fragment, it is either the orginal packet, or the\r
+ // first fragment of a fragmented packet. It seems that there is a subtle\r
+ // bug here: what if the caller free the packet in Callback and IpIf (or\r
+ // MNP child used by that interface) still holds the fragments and try\r
+ // to access the data? The caller can free the packet if it recycles the\r
+ // consumer's (such as UDP) data in the Callback. But this can't happen.\r
+ // The detailed sequence is:\r
+ // 1. for the packets generated by IP4 driver itself:\r
+ // The Callback is Ip4SysPacketSent, which is the same as the\r
+ // fragments' callback. Ip4SysPacketSent simply calls NetbufFree\r
+ // to release its reference to the packet. So, no problem for\r
+ // system packets.\r
+ //\r
+ // 2. for the upper layer's packets (use UDP as an example):\r
+ // UDP requests the IP layer to transmit some data which is\r
+ // wrapped in an asynchronous token, the token is wrapped\r
+ // in IP4_TXTOKEN_WRAP by IP4. IP4 also wrap the user's data\r
+ // in a net buffer, which is Packet we get here. IP4_TXTOKEN_WRAP\r
+ // is bound with the Packet. It will only be freed when all\r
+ // the references to Packet have been released. Upon then, the\r
+ // Packet's OnFree callback will release the IP4_TXTOKEN_WRAP,\r
+ // and singal the user's recycle event. So, also no problem for\r
+ // upper layer's packets.\r
+ //\r
+ Ip4PrependHead (Packet, Head, Option, OptLen);\r
+ Status = Ip4SendFrame (IpIf, IpInstance, Packet, GateWay, Callback, Context);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ Ip4CancelPacket (IpIf, Packet, Status);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ The filter function to find a packet and all its fragments.\r
+ The packet's fragments have their Context set to the packet.\r
+\r
+ @param Frame The frames hold by the low level interface\r
+ @param Context Context to the function, which is the packet.\r
+\r
+ @retval TRUE This is the packet to cancel or its fragments.\r
+ @retval FALSE This is unrelated packet.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+Ip4CancelPacketFragments (\r
+ IP4_LINK_TX_TOKEN *Frame,\r
+ VOID *Context\r
+ )\r
+{\r
+ if ((Frame->Packet == (NET_BUF *) Context) || (Frame->Context == Context)) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Cancel the Packet and all its fragments.\r
+\r
+ @param IpIf The interface from which the Packet is sent\r
+ @param Packet The Packet to cancel\r
+ @param IoStatus The status returns to the sender.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4CancelPacket (\r
+ IN IP4_INTERFACE *IpIf,\r
+ IN NET_BUF *Packet,\r
+ IN EFI_STATUS IoStatus\r
+ )\r
+{\r
+ Ip4CancelFrames (IpIf, IoStatus, Ip4CancelPacketFragments, Packet);\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Ip4Output.h
+
+Abstract:
+
+
+**/
+
+#ifndef __EFI_IP4_OUTPUT_H__
+#define __EFI_IP4_OUTPUT_H__
+
+VOID
+Ip4SysPacketSent (
+ IP4_PROTOCOL *Ip4Instance,
+ NET_BUF *Packet,
+ EFI_STATUS IoStatus,
+ UINT32 Flag,
+ VOID *Context
+ );
+
+EFI_STATUS
+Ip4Output (
+ IN IP4_SERVICE *IpSb,
+ IN IP4_PROTOCOL *IpInstance, OPTIONAL
+ IN NET_BUF *Data,
+ IN IP4_HEAD *Head,
+ IN UINT8 *Option,
+ IN UINT32 OptLen,
+ IN IP4_ADDR GateWay,
+ IN IP4_FRAME_CALLBACK Callback,
+ IN VOID *Context
+ );
+
+VOID
+Ip4CancelPacket (
+ IN IP4_INTERFACE *IpIf,
+ IN NET_BUF *Packet,
+ IN EFI_STATUS IoStatus
+ );
+
+extern UINT16 mIp4Id;
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Ip4Route.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+\r
+/**\r
+ Allocate a route entry then initialize it with the Dest/Netmaks\r
+ and Gateway.\r
+\r
+ @param Dest The destination network\r
+ @param Netmask The destination network mask\r
+ @param GateWay The nexthop address\r
+\r
+ @return NULL if failed to allocate memeory, otherwise the newly created\r
+ @return route entry.\r
+\r
+**/\r
+STATIC\r
+IP4_ROUTE_ENTRY *\r
+Ip4CreateRouteEntry (\r
+ IN IP4_ADDR Dest,\r
+ IN IP4_ADDR Netmask,\r
+ IN IP4_ADDR GateWay\r
+ )\r
+{\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+\r
+ RtEntry = NetAllocatePool (sizeof (IP4_ROUTE_ENTRY));\r
+\r
+ if (RtEntry == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetListInit (&RtEntry->Link);\r
+\r
+ RtEntry->RefCnt = 1;\r
+ RtEntry->Dest = Dest;\r
+ RtEntry->Netmask = Netmask;\r
+ RtEntry->NextHop = GateWay;\r
+ RtEntry->Flag = 0;\r
+\r
+ return RtEntry;\r
+}\r
+\r
+\r
+/**\r
+ Free the route table entry. It is reference counted.\r
+\r
+ @param RtEntry The route entry to free.\r
+\r
+ @return NONE\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4FreeRouteEntry (\r
+ IN IP4_ROUTE_ENTRY *RtEntry\r
+ )\r
+{\r
+ ASSERT (RtEntry->RefCnt > 0);\r
+\r
+ if (--RtEntry->RefCnt == 0) {\r
+ NetFreePool (RtEntry);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Allocate and initialize a IP4 route cache entry.\r
+\r
+ @param Dst The destination address\r
+ @param Src The source address\r
+ @param GateWay The next hop address\r
+ @param Tag The tag from the caller. This marks all the cache\r
+ entries spawned from one route table entry.\r
+\r
+ @return NULL if failed to allocate memory for the cache, other point\r
+ @return to the created route cache entry.\r
+\r
+**/\r
+STATIC\r
+IP4_ROUTE_CACHE_ENTRY *\r
+Ip4CreateRouteCacheEntry (\r
+ IN IP4_ADDR Dst,\r
+ IN IP4_ADDR Src,\r
+ IN IP4_ADDR GateWay,\r
+ IN UINTN Tag\r
+ )\r
+{\r
+ IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
+\r
+ RtCacheEntry = NetAllocatePool (sizeof (IP4_ROUTE_CACHE_ENTRY));\r
+\r
+ if (RtCacheEntry == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetListInit (&RtCacheEntry->Link);\r
+\r
+ RtCacheEntry->RefCnt = 1;\r
+ RtCacheEntry->Dest = Dst;\r
+ RtCacheEntry->Src = Src;\r
+ RtCacheEntry->NextHop = GateWay;\r
+ RtCacheEntry->Tag = Tag;\r
+\r
+ return RtCacheEntry;\r
+}\r
+\r
+\r
+/**\r
+ Free the route cache entry. It is reference counted.\r
+\r
+ @param RtCacheEntry The route cache entry to free.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4FreeRouteCacheEntry (\r
+ IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry\r
+ )\r
+{\r
+ ASSERT (RtCacheEntry->RefCnt > 0);\r
+\r
+ if (--RtCacheEntry->RefCnt == 0) {\r
+ NetFreePool (RtCacheEntry);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Initialize an empty route cache table.\r
+\r
+ @param RtCache The rotue cache table to initialize.\r
+\r
+ @return NONE\r
+\r
+**/\r
+VOID\r
+Ip4InitRouteCache (\r
+ IN IP4_ROUTE_CACHE *RtCache\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {\r
+ NetListInit (&(RtCache->CacheBucket[Index]));\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Clean up a route cache, that is free all the route cache\r
+ entries enqueued in the cache.\r
+\r
+ @param RtCache The route cache table to clean up\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4CleanRouteCache (\r
+ IN IP4_ROUTE_CACHE *RtCache\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtCache->CacheBucket[Index])) {\r
+ RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
+\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeRouteCacheEntry (RtCacheEntry);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+\r
+/**\r
+ Create an empty route table, includes its internal route cache\r
+\r
+ None\r
+\r
+ @return NULL if failed to allocate memory for the route table, otherwise\r
+ @return the point to newly created route table.\r
+\r
+**/\r
+IP4_ROUTE_TABLE *\r
+Ip4CreateRouteTable (\r
+ VOID\r
+ )\r
+{\r
+ IP4_ROUTE_TABLE *RtTable;\r
+ UINT32 Index;\r
+\r
+ RtTable = NetAllocatePool (sizeof (IP4_ROUTE_TABLE));\r
+\r
+ if (RtTable == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ RtTable->RefCnt = 1;\r
+ RtTable->TotalNum = 0;\r
+\r
+ for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
+ NetListInit (&(RtTable->RouteArea[Index]));\r
+ }\r
+\r
+ RtTable->Next = NULL;\r
+\r
+ Ip4InitRouteCache (&RtTable->Cache);\r
+ return RtTable;\r
+}\r
+\r
+\r
+/**\r
+ Free the route table and its associated route cache. Route\r
+ table is reference counted.\r
+\r
+ @param RtTable The route table to free.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4FreeRouteTable (\r
+ IN IP4_ROUTE_TABLE *RtTable\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+ UINT32 Index;\r
+\r
+ ASSERT (RtTable->RefCnt > 0);\r
+\r
+ if (--RtTable->RefCnt > 0) {\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Free all the route table entry and its route cache.\r
+ //\r
+ for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtTable->RouteArea[Index])) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeRouteEntry (RtEntry);\r
+ }\r
+ }\r
+\r
+ Ip4CleanRouteCache (&RtTable->Cache);\r
+\r
+ NetFreePool (RtTable);\r
+}\r
+\r
+\r
+\r
+/**\r
+ Remove all the cache entries bearing the Tag. When a route cache\r
+ entry is created, it is tagged with the address of route entry\r
+ from which it is spawned. When a route entry is deleted, the cache\r
+ entries spawned from it are also deleted.\r
+\r
+ @param RtCache Route cache to remove the entries from\r
+ @param Tag The Tag of the entries to remove\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4PurgeRouteCache (\r
+ IN IP4_ROUTE_CACHE *RtCache,\r
+ IN UINTN Tag\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtCache->CacheBucket[Index]) {\r
+\r
+ RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
+\r
+ if (RtCacheEntry->Tag == Tag) {\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeRouteCacheEntry (RtCacheEntry);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Add a route entry to the route table. All the IP4_ADDRs are in\r
+ host byte order.\r
+\r
+ @param RtTable Route table to add route to\r
+ @param Dest The destination of the network\r
+ @param Netmask The netmask of the destination\r
+ @param Gateway The next hop address\r
+\r
+ @retval EFI_ACCESS_DENIED The same route already exists\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the entry\r
+ @retval EFI_SUCCESS The route is added successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4AddRoute (\r
+ IN IP4_ROUTE_TABLE *RtTable,\r
+ IN IP4_ADDR Dest,\r
+ IN IP4_ADDR Netmask,\r
+ IN IP4_ADDR Gateway\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Head;\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+\r
+ //\r
+ // All the route entries with the same netmask length are\r
+ // linke to the same route area\r
+ //\r
+ Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);\r
+\r
+ //\r
+ // First check whether the route exists\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, Head) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Create a route entry and insert it to the route area.\r
+ //\r
+ RtEntry = Ip4CreateRouteEntry (Dest, Netmask, Gateway);\r
+\r
+ if (RtEntry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (Gateway == IP4_ALLZERO_ADDRESS) {\r
+ RtEntry->Flag = IP4_DIRECT_ROUTE;\r
+ }\r
+\r
+ NetListInsertHead (Head, &RtEntry->Link);\r
+ RtTable->TotalNum++;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Remove a route entry and all the route caches spawn from it.\r
+\r
+ @param RtTable The route table to remove the route from\r
+ @param Dest The destination network\r
+ @param Netmask The netmask of the Dest\r
+ @param Gateway The next hop address\r
+\r
+ @retval EFI_SUCCESS The route entry is successfully removed\r
+ @retval EFI_NOT_FOUND There is no route entry in the table with that\r
+ properity.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4DelRoute (\r
+ IN IP4_ROUTE_TABLE *RtTable,\r
+ IN IP4_ADDR Dest,\r
+ IN IP4_ADDR Netmask,\r
+ IN IP4_ADDR Gateway\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Head;\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+\r
+ Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {\r
+ Ip4PurgeRouteCache (&RtTable->Cache, (UINTN) RtEntry);\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeRouteEntry (RtEntry);\r
+\r
+ RtTable->TotalNum--;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Find a route cache with the dst and src. This is used by ICMP\r
+ redirect messasge process. All kinds of redirect is treated as\r
+ host redirect according to RFC1122. So, only route cache entries\r
+ are modified according to the ICMP redirect message.\r
+\r
+ @param RtTable The route table to search the cache for\r
+ @param Dest The destination address\r
+ @param Src The source address\r
+\r
+ @return NULL if no route entry to the (Dest, Src). Otherwise the point\r
+ @return to the correct route cache entry.\r
+\r
+**/\r
+IP4_ROUTE_CACHE_ENTRY *\r
+Ip4FindRouteCache (\r
+ IN IP4_ROUTE_TABLE *RtTable,\r
+ IN IP4_ADDR Dest,\r
+ IN IP4_ADDR Src\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
+ UINT32 Index;\r
+\r
+ Index = IP4_ROUTE_CACHE_HASH (Dest, Src);\r
+\r
+ NET_LIST_FOR_EACH (Entry, &RtTable->Cache.CacheBucket[Index]) {\r
+ RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
+\r
+ if ((RtCacheEntry->Dest == Dest) && (RtCacheEntry->Src == Src)) {\r
+ NET_GET_REF (RtCacheEntry);\r
+ return RtCacheEntry;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Search the route table for a most specific match to the Dst. It searches\r
+ from the longest route area (mask length == 32) to the shortest route area (\r
+ default routes). In each route area, it will first search the instance's\r
+ route table, then the default route table. This is required by the following\r
+ requirements:\r
+ 1. IP search the route table for a most specific match\r
+ 2. The local route entries have precedence over the default route entry.\r
+\r
+ @param RtTable The route table to search from\r
+ @param Dst The destionation address to search\r
+\r
+ @return NULL if no route matches the Dst, otherwise the point to the\r
+ @return most specific route to the Dst.\r
+\r
+**/\r
+STATIC\r
+IP4_ROUTE_ENTRY *\r
+Ip4FindRouteEntry (\r
+ IN IP4_ROUTE_TABLE *RtTable,\r
+ IN IP4_ADDR Dst\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+ IP4_ROUTE_TABLE *Table;\r
+ INTN Index;\r
+\r
+ RtEntry = NULL;\r
+\r
+ for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {\r
+ for (Table = RtTable; Table != NULL; Table = Table->Next) {\r
+ NET_LIST_FOR_EACH (Entry, &Table->RouteArea[Index]) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ if (IP4_NET_EQUAL (RtEntry->Dest, Dst, RtEntry->Netmask)) {\r
+ NET_GET_REF (RtEntry);\r
+ return RtEntry;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Search the route table to route the packet. Return/creat a route\r
+ cache if there is a route to the destination.\r
+\r
+ @param RtTable The route table to search from\r
+ @param Dest The destination address to search for\r
+ @param Src The source address to search for\r
+\r
+ @return NULL if failed to route packet, otherwise a route cache\r
+ @return entry that can be used to route packet.\r
+\r
+**/\r
+IP4_ROUTE_CACHE_ENTRY *\r
+Ip4Route (\r
+ IN IP4_ROUTE_TABLE *RtTable,\r
+ IN IP4_ADDR Dest,\r
+ IN IP4_ADDR Src\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Head;\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
+ IP4_ROUTE_CACHE_ENTRY *Cache;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+ IP4_ADDR NextHop;\r
+ UINT32 Count;\r
+\r
+ ASSERT (RtTable != NULL);\r
+\r
+ Head = &RtTable->Cache.CacheBucket[IP4_ROUTE_CACHE_HASH (Dest, Src)];\r
+ RtCacheEntry = Ip4FindRouteCache (RtTable, Dest, Src);\r
+\r
+ //\r
+ // If found, promote the cache entry to the head of the hash bucket. LRU\r
+ //\r
+ if (RtCacheEntry != NULL) {\r
+ NetListRemoveEntry (&RtCacheEntry->Link);\r
+ NetListInsertHead (Head, &RtCacheEntry->Link);\r
+ return RtCacheEntry;\r
+ }\r
+\r
+ //\r
+ // Search the route table for the most specific route\r
+ //\r
+ RtEntry = Ip4FindRouteEntry (RtTable, Dest);\r
+\r
+ if (RtEntry == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Found a route to the Dest, if it is a direct route, the packet\r
+ // will be send directly to the destination, such as for connected\r
+ // network. Otherwise, it is an indirect route, the packet will be\r
+ // send the next hop router.\r
+ //\r
+ if (RtEntry->Flag & IP4_DIRECT_ROUTE) {\r
+ NextHop = Dest;\r
+ } else {\r
+ NextHop = RtEntry->NextHop;\r
+ }\r
+\r
+ Ip4FreeRouteEntry (RtEntry);\r
+\r
+ //\r
+ // Create a route cache entry, and tag it as spawned from this route entry\r
+ //\r
+ RtCacheEntry = Ip4CreateRouteCacheEntry (Dest, Src, NextHop, (UINTN) RtEntry);\r
+\r
+ if (RtCacheEntry == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetListInsertHead (Head, &RtCacheEntry->Link);\r
+ NET_GET_REF (RtCacheEntry);\r
+\r
+ //\r
+ // Each bucket of route cache can contain at most 64 entries.\r
+ // Remove the entries at the tail of the bucket. These entries\r
+ // are likely to be used least.\r
+ //\r
+ Count = 0;\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
+ if (++Count < IP4_ROUTE_CACHE_MAX) {\r
+ continue;\r
+ }\r
+\r
+ Cache = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
+\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeRouteCacheEntry (Cache);\r
+ }\r
+\r
+ return RtCacheEntry;\r
+}\r
+\r
+\r
+/**\r
+ Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of\r
+ GetModeData. The EFI_IP4_ROUTE_TABLE is clumsy to use in the\r
+ internal operation of the IP4 driver.\r
+\r
+ @param IpInstance The IP4 child that requests the route table.\r
+\r
+ @retval EFI_SUCCESS The route table is successfully build\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the rotue table.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4BuildEfiRouteTable (\r
+ IN IP4_PROTOCOL *IpInstance\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_ROUTE_TABLE *RtTable;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+ EFI_IP4_ROUTE_TABLE *Table;\r
+ UINT32 Count;\r
+ INT32 Index;\r
+\r
+ IpSb = IpInstance->Service;\r
+ RtTable = IpInstance->RouteTable;\r
+\r
+ if (IpInstance->EfiRouteTable != NULL) {\r
+ NetFreePool (IpInstance->EfiRouteTable);\r
+\r
+ IpInstance->EfiRouteTable = NULL;\r
+ IpInstance->EfiRouteCount = 0;\r
+ }\r
+\r
+ Count = RtTable->TotalNum;\r
+\r
+ if (RtTable->Next != NULL) {\r
+ Count += RtTable->Next->TotalNum;\r
+ }\r
+\r
+ if (Count == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Table = NetAllocatePool (sizeof (EFI_IP4_ROUTE_TABLE) * Count);\r
+\r
+ if (Table == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Copy the route entry to EFI route table. Keep the order of\r
+ // route entry copied from most specific to default route. That\r
+ // is, interlevel the route entry from the instance's route area\r
+ // and those from the default route table's route area.\r
+ //\r
+ Count = 0;\r
+\r
+ for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {\r
+ for (RtTable = IpInstance->RouteTable; RtTable != NULL; RtTable = RtTable->Next) {\r
+ NET_LIST_FOR_EACH (Entry, &(RtTable->RouteArea[Index])) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ EFI_IP4 (Table[Count].SubnetAddress) = HTONL (RtEntry->Dest & RtEntry->Netmask);\r
+ EFI_IP4 (Table[Count].SubnetMask) = HTONL (RtEntry->Netmask);\r
+ EFI_IP4 (Table[Count].GatewayAddress) = HTONL (RtEntry->NextHop);\r
+\r
+ Count++;\r
+ }\r
+ }\r
+ }\r
+\r
+ IpInstance->EfiRouteTable = Table;\r
+ IpInstance->EfiRouteCount = Count;\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2005 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Ip4Route.h
+
+Abstract:
+
+ EFI IP4 route table and route cache table defintions.
+
+
+**/
+
+#ifndef __EFI_IP4_ROUTE_H__
+#define __EFI_IP4_ROUTE_H__
+
+#include "IP4Common.h"
+
+enum {
+ IP4_DIRECT_ROUTE = 0x00000001,
+
+ IP4_ROUTE_CACHE_HASH = 31,
+ IP4_ROUTE_CACHE_MAX = 64, // Max NO. of cache entry per hash bucket
+};
+
+#define IP4_ROUTE_CACHE_HASH(Dst, Src) (((Dst) ^ (Src)) % IP4_ROUTE_CACHE_HASH)
+
+//
+// The route entry in the route table. Dest/Netmask is the destion
+// network. The nexthop is the gateway to send the packet to in
+// order to reach the Dest/Netmask. If the Flag has IP4_DIRECT_ROUTE
+// on, the gateway is the destination of the IP packet itself. Route
+// enties of the connected network have the flag on.
+//
+typedef struct {
+ NET_LIST_ENTRY Link;
+ INTN RefCnt;
+ IP4_ADDR Dest;
+ IP4_ADDR Netmask;
+ IP4_ADDR NextHop;
+ UINT32 Flag;
+} IP4_ROUTE_ENTRY;
+
+//
+// The route cache entry. The route cache entry is optional.
+// But it is necessary to support the ICMP redirect message.
+// Check Ip4ProcessIcmpRedirect for information.
+//
+// The cache entry field Tag is used to tag all the route
+// cache entry spawned from a route table entry. This makes
+// it simple to delete all the route cache entries from a
+// to-be-deleted route entry.
+//
+typedef struct {
+ NET_LIST_ENTRY Link;
+ INTN RefCnt;
+ IP4_ADDR Dest;
+ IP4_ADDR Src;
+ IP4_ADDR NextHop;
+ UINTN Tag;
+} IP4_ROUTE_CACHE_ENTRY;
+
+//
+// The route cache table is organized as a hash table. Each
+// IP4 route table has a embedded route cache. For now the
+// route cache and route table are binded togehter. But keep
+// the route cache a seperated structure in case we want to
+// detach them later.
+//
+typedef struct {
+ NET_LIST_ENTRY CacheBucket[IP4_ROUTE_CACHE_HASH];
+} IP4_ROUTE_CACHE;
+
+//
+// Each IP4 instance has its own route table. Each ServiceBinding
+// instance has a default route table and default address.
+//
+// All the route table entries with the same mask are linked
+// together in one route area. For example, RouteArea[0] contains
+// the default routes. A route table also contains a route cache.
+//
+typedef struct _IP4_ROUTE_TABLE IP4_ROUTE_TABLE;
+
+typedef struct _IP4_ROUTE_TABLE {
+ INTN RefCnt;
+ UINT32 TotalNum;
+ NET_LIST_ENTRY RouteArea[IP4_MASK_NUM];
+ IP4_ROUTE_TABLE *Next;
+ IP4_ROUTE_CACHE Cache;
+};
+
+IP4_ROUTE_TABLE*
+Ip4CreateRouteTable (
+ VOID
+ );
+
+VOID
+Ip4FreeRouteTable (
+ IN IP4_ROUTE_TABLE *RouteTable
+ );
+
+EFI_STATUS
+Ip4AddRoute (
+ IN IP4_ROUTE_TABLE *RtTable,
+ IN IP4_ADDR Dest,
+ IN IP4_ADDR Netmask,
+ IN IP4_ADDR Gateway
+ );
+
+EFI_STATUS
+Ip4DelRoute (
+ IN IP4_ROUTE_TABLE *RtTable,
+ IN IP4_ADDR Dest,
+ IN IP4_ADDR Netmask,
+ IN IP4_ADDR Gateway
+ );
+
+IP4_ROUTE_CACHE_ENTRY *
+Ip4FindRouteCache (
+ IN IP4_ROUTE_TABLE *RtTable,
+ IN IP4_ADDR Dest,
+ IN IP4_ADDR Src
+ );
+
+VOID
+Ip4FreeRouteCacheEntry (
+ IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry
+ );
+
+IP4_ROUTE_CACHE_ENTRY *
+Ip4Route (
+ IN IP4_ROUTE_TABLE *RtTable,
+ IN IP4_ADDR Dest,
+ IN IP4_ADDR Src
+ );
+
+EFI_STATUS
+Ip4BuildEfiRouteTable (
+ IN IP4_PROTOCOL *IpInstance
+ );
+#endif
\r
for (Index = 0; Index < Count; Index++) {\r
\r
- Nbuf = NetbufAlloc (MnpServiceData->BufferLength);\r
+ Nbuf = NetbufAlloc (MnpServiceData->BufferLength + MnpServiceData->PaddingSize);\r
if (Nbuf == NULL) {\r
\r
MNP_DEBUG_ERROR (("MnpAddFreeNbuf: NetBufAlloc failed.\n"));\r
break;\r
}\r
\r
+ if (MnpServiceData->PaddingSize > 0) {\r
+ //\r
+ // Pad padding bytes before the media header\r
+ //\r
+ NetbufAllocSpace (Nbuf, MnpServiceData->PaddingSize, NET_BUF_TAIL);\r
+ NetbufTrim (Nbuf, MnpServiceData->PaddingSize, NET_BUF_HEAD);\r
+ }\r
+\r
NetbufQueAppend (&MnpServiceData->FreeNbufQue, Nbuf);\r
}\r
\r
//\r
MnpServiceData->BufferLength = MnpServiceData->Mtu + SnpMode->MediaHeaderSize + NET_ETHER_FCS_SIZE;\r
\r
+ //\r
+ // Make sure the protocol headers immediately following the media header \r
+ // 4-byte aligned\r
+ //\r
+ MnpServiceData->PaddingSize = (4 - SnpMode->MediaHeaderSize) & 0x3;\r
+\r
//\r
// Initialize the FreeNetBufQue and pre-allocate some NET_BUFs.\r
//\r
return Status;\r
}\r
\r
-//@MT: EFI_DRIVER_ENTRY_POINT (MnpDriverEntryPoint)\r
\r
EFI_STATUS\r
EFIAPI\r
// store a packet.
//
UINT32 BufferLength;
+ UINT32 PaddingSize;
NET_BUF *RxNbufCache;
UINT8 *TxBuf;
} MNP_SERVICE_DATA;
//\r
// No receiver for this packet.\r
//\r
- NetbufAllocSpace (Nbuf, Trimmed, NET_BUF_TAIL);\r
+ if (Trimmed > 0) {\r
+ NetbufAllocSpace (Nbuf, Trimmed, NET_BUF_TAIL);\r
+ }\r
+\r
goto EXIT;\r
}\r
//\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Mtftp4Driver.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+Mtftp4ComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Mtftp4ComponentNameGetControllerName (\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 gMtftp4ComponentName = {\r
+ Mtftp4ComponentNameGetDriverName,\r
+ Mtftp4ComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mMtftp4DriverNameTable[] = {\r
+ {\r
+ "eng",\r
+ L"MTFTP4 Network Service"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Mtftp4ComponentNameGetDriverName (\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
+ gMtftp4ComponentName.SupportedLanguages,\r
+ mMtftp4DriverNameTable,\r
+ DriverName\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Mtftp4ComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by an EFI Driver.\r
+\r
+ Arguments:\r
+ This : A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ ControllerHandle :The handle of a controller that the driver specified by\r
+ This is managing. This handle specifies the controller\r
+ whose name is to be returned.\r
+ ChildHandle :The handle of the child controller to retrieve the name\r
+ of. This is an optional parameter that may be NULL. It\r
+ will be NULL for device drivers. It will also be NULL\r
+ for a bus drivers that wish to retrieve the name of the\r
+ bus controller. It will not be NULL for a bus driver\r
+ that wishes to retrieve the name of a child controller.\r
+ Language : A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language of the controller name\r
+ that that the caller is requesting, and it must match one\r
+ of the languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up to the\r
+ driver writer.\r
+ ControllerName : A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the controller specified by\r
+ ControllerHandle and ChildHandle in the language specified\r
+ by Language from the point of view of the driver specified\r
+ by This.\r
+\r
+ Returns:\r
+ EFI_SUCCESS :The Unicode string for the user readable name in the\r
+ language specified by Language for the driver\r
+ specified by This was returned in DriverName.\r
+ EFI_INVALID_PARAMETER : ControllerHandle is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER : ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER : Language is NULL.\r
+ EFI_INVALID_PARAMETER : ControllerName is NULL.\r
+ EFI_UNSUPPORTED : The driver specified by This is not currently managing\r
+ the controller specified by ControllerHandle and\r
+ ChildHandle.\r
+ EFI_UNSUPPORTED :The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ Mtftp4Driver.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Mtftp4Impl.h"\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gMtftp4DriverBinding = {\r
+ Mtftp4DriverBindingSupported,\r
+ Mtftp4DriverBindingStart,\r
+ Mtftp4DriverBindingStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+EFI_SERVICE_BINDING_PROTOCOL gMtftp4ServiceBindingTemplete = {\r
+ Mtftp4ServiceBindingCreateChild,\r
+ Mtftp4ServiceBindingDestroyChild\r
+};\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (Mtftp4DriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Mtftp4DriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ The driver entry point which installs multiple protocols to the ImageHandle.\r
+\r
+Arguments:\r
+\r
+ ImageHandle - The MTFTP's image handle\r
+ SystemTable - The system table\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The handles are successfully installed on the image. Otherwise\r
+ some EFI_ERROR.\r
+\r
+--*/\r
+{\r
+ return NetLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gMtftp4DriverBinding,\r
+ ImageHandle,\r
+ &gMtftp4ComponentName,\r
+ NULL,\r
+ NULL\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Test whether MTFTP driver support this controller.\r
+\r
+ @param This The MTFTP driver binding instance\r
+ @param Controller The controller to test\r
+ @param RemainingDevicePath The remaining device path\r
+\r
+ @retval EFI_SUCCESS The controller has UDP service binding protocol\r
+ installed, MTFTP can support it.\r
+ @retval Others MTFTP can't support the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4DriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiUdp4ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Config a NULL UDP that is used to keep the connection between UDP\r
+ and MTFTP. Just leave the Udp child unconfigured. When UDP is\r
+ unloaded, MTFTP will be informed with DriverBinding Stop.\r
+\r
+ @param UdpIo The UDP port to configure\r
+ @param Context The opaque parameter to the callback\r
+\r
+ @retval EFI_SUCCESS It always return EFI_SUCCESS directly.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4ConfigNullUdp (\r
+ IN UDP_IO_PORT *UdpIo,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Create then initialize a MTFTP service binding instance.\r
+\r
+ @param Controller The controller to install the MTFTP service\r
+ binding on\r
+ @param Image The driver binding image of the MTFTP driver\r
+ @param Service The variable to receive the created service\r
+ binding instance.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance\r
+ @retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep\r
+ connection with UDP.\r
+ @retval EFI_SUCCESS The service instance is created for the\r
+ controller.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4CreateService (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_HANDLE Image,\r
+ OUT MTFTP4_SERVICE **Service\r
+ )\r
+{\r
+ MTFTP4_SERVICE *MtftpSb;\r
+ EFI_STATUS Status;\r
+\r
+ *Service = NULL;\r
+ MtftpSb = NetAllocatePool (sizeof (MTFTP4_SERVICE));\r
+\r
+ if (MtftpSb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ MtftpSb->Signature = MTFTP4_SERVICE_SIGNATURE;\r
+ MtftpSb->ServiceBinding = gMtftp4ServiceBindingTemplete;\r
+ MtftpSb->InDestory = FALSE;\r
+ MtftpSb->ChildrenNum = 0;\r
+ NetListInit (&MtftpSb->Children);\r
+\r
+ MtftpSb->Timer = NULL;\r
+ MtftpSb->TimerToGetMap = NULL;\r
+ MtftpSb->Controller = Controller;\r
+ MtftpSb->Image = Image;\r
+ MtftpSb->ConnectUdp = NULL;\r
+\r
+ //\r
+ // Create the timer and a udp to be notified when UDP is uninstalled\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ Mtftp4OnTimerTick,\r
+ MtftpSb,\r
+ &MtftpSb->Timer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NetFreePool (MtftpSb);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Create the timer used to time out the procedure which is used to\r
+ // get the default IP address.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &MtftpSb->TimerToGetMap\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseEvent (MtftpSb->Timer);\r
+ NetFreePool (MtftpSb);\r
+ return Status;\r
+ }\r
+\r
+ MtftpSb->ConnectUdp = UdpIoCreatePort (Controller, Image, Mtftp4ConfigNullUdp, NULL);\r
+\r
+ if (MtftpSb->ConnectUdp == NULL) {\r
+ gBS->CloseEvent (MtftpSb->TimerToGetMap);\r
+ gBS->CloseEvent (MtftpSb->Timer);\r
+ NetFreePool (MtftpSb);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ *Service = MtftpSb;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Release all the resource used the MTFTP service binding instance.\r
+\r
+ @param MtftpSb The MTFTP service binding instance.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Mtftp4CleanService (\r
+ IN MTFTP4_SERVICE *MtftpSb\r
+ )\r
+{\r
+ UdpIoFreePort (MtftpSb->ConnectUdp);\r
+ gBS->CloseEvent (MtftpSb->TimerToGetMap);\r
+ gBS->CloseEvent (MtftpSb->Timer);\r
+}\r
+\r
+\r
+/**\r
+ Start the MTFTP driver on this controller. MTFTP driver will\r
+ install a MTFTP SERVICE BINDING protocol on the supported\r
+ controller, which can be used to create/destroy MTFTP children.\r
+\r
+ @param This The MTFTP driver binding protocol.\r
+ @param Controller The controller to manage.\r
+ @param RemainingDevicePath Remaining device path.\r
+\r
+ @retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been\r
+ started on the controller.\r
+ @retval EFI_SUCCESS The MTFTP service binding is installed on the\r
+ controller.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4DriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ MTFTP4_SERVICE *MtftpSb;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Directly return if driver is already running.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiMtftp4ServiceBindingProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Install the Mtftp4ServiceBinding Protocol onto Controller\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Controller,\r
+ &gEfiMtftp4ServiceBindingProtocolGuid,\r
+ &MtftpSb->ServiceBinding,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ Mtftp4CleanService (MtftpSb);\r
+ NetFreePool (MtftpSb);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop the MTFTP driver on controller. The controller is a UDP\r
+ child handle.\r
+\r
+ @param This The MTFTP driver binding protocol\r
+ @param Controller The controller to stop\r
+ @param NumberOfChildren The number of children\r
+ @param ChildHandleBuffer The array of the child handle.\r
+\r
+ @retval EFI_SUCCESS The driver is stopped on the controller.\r
+ @retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4DriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
+ MTFTP4_SERVICE *MtftpSb;\r
+ MTFTP4_PROTOCOL *Instance;\r
+ EFI_HANDLE NicHandle;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // MTFTP driver opens UDP child, So, Controller is a UDP\r
+ // child handle. Locate the Nic handle first. Then get the\r
+ // MTFTP private data back.\r
+ //\r
+ NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);\r
+\r
+ if (NicHandle == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ NicHandle,\r
+ &gEfiMtftp4ServiceBindingProtocolGuid,\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
+ MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);\r
+\r
+ if (MtftpSb->InDestory) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+ MtftpSb->InDestory = TRUE;\r
+\r
+ while (!NetListIsEmpty (&MtftpSb->Children)) {\r
+ Instance = NET_LIST_HEAD (&MtftpSb->Children, MTFTP4_PROTOCOL, Link);\r
+ Mtftp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);\r
+ }\r
+\r
+ if (MtftpSb->ChildrenNum != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = gBS->UninstallProtocolInterface (\r
+ NicHandle,\r
+ &gEfiMtftp4ServiceBindingProtocolGuid,\r
+ ServiceBinding\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Mtftp4CleanService (MtftpSb);\r
+ NetFreePool (MtftpSb);\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ MtftpSb->InDestory = FALSE;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Initialize a MTFTP protocol instance which is the child of MtftpSb.\r
+\r
+ @param MtftpSb The MTFTP service binding protocol.\r
+ @param Instance The MTFTP instance to initialize.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Mtftp4InitProtocol (\r
+ IN MTFTP4_SERVICE *MtftpSb,\r
+ IN MTFTP4_PROTOCOL *Instance\r
+ )\r
+{\r
+ NetZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));\r
+\r
+ Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;\r
+ NetListInit (&Instance->Link);\r
+ CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (EFI_MTFTP4_PROTOCOL));\r
+ Instance->State = MTFTP4_STATE_UNCONFIGED;\r
+ Instance->Indestory = FALSE;\r
+ Instance->Service = MtftpSb;\r
+\r
+ NetListInit (&Instance->Blocks);\r
+}\r
+\r
+\r
+/**\r
+ Create a MTFTP child for the service binding instance, then\r
+ install the MTFTP protocol to the ChildHandle.\r
+\r
+ @param This The MTFTP service binding instance.\r
+ @param ChildHandle The Child handle to install the MTFTP protocol.\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.\r
+ @retval EFI_SUCCESS The child is successfully create.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4ServiceBindingCreateChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
+ IN OUT EFI_HANDLE *ChildHandle\r
+ )\r
+{\r
+ MTFTP4_SERVICE *MtftpSb;\r
+ MTFTP4_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
+ MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);\r
+\r
+ Mtftp4InitProtocol (MtftpSb, Instance);\r
+\r
+ Instance->UnicastPort = UdpIoCreatePort (\r
+ MtftpSb->Controller,\r
+ MtftpSb->Image,\r
+ Mtftp4ConfigNullUdp,\r
+ Instance\r
+ );\r
+\r
+ if (Instance->UnicastPort == NULL) {\r
+ NetFreePool (Instance);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Install the MTFTP protocol onto ChildHandle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ ChildHandle,\r
+ &gEfiMtftp4ProtocolGuid,\r
+ &Instance->Mtftp4,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Instance->Handle = *ChildHandle;\r
+\r
+ //\r
+ // Open the Udp4 protocol BY_CHILD.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ MtftpSb->ConnectUdp->UdpHandle,\r
+ &gEfiUdp4ProtocolGuid,\r
+ (VOID **) &Udp4,\r
+ gMtftp4DriverBinding.DriverBindingHandle,\r
+ Instance->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ Instance->Handle,\r
+ &gEfiMtftp4ProtocolGuid,\r
+ &Instance->Mtftp4,\r
+ NULL\r
+ );\r
+\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Add it to the parent's child list.\r
+ //\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ NetListInsertTail (&MtftpSb->Children, &Instance->Link);\r
+ MtftpSb->ChildrenNum++;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ON_ERROR:\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ UdpIoFreePort (Instance->UnicastPort);\r
+ NetFreePool (Instance);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Destory one of the service binding's child.\r
+\r
+ @param This The service binding instance\r
+ @param ChildHandle The child handle to destory\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameter is invaid.\r
+ @retval EFI_UNSUPPORTED The child may have already been destoried.\r
+ @retval EFI_SUCCESS The child is destoried and removed from the\r
+ parent's child list.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4ServiceBindingDestroyChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ChildHandle\r
+ )\r
+{\r
+ MTFTP4_SERVICE *MtftpSb;\r
+ MTFTP4_PROTOCOL *Instance;\r
+ EFI_MTFTP4_PROTOCOL *Mtftp4;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\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
+ &gEfiMtftp4ProtocolGuid,\r
+ (VOID **) &Mtftp4,\r
+ gMtftp4DriverBinding.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);\r
+ MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);\r
+\r
+ if (Instance->Service != MtftpSb) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Instance->Indestory) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Instance->Indestory = TRUE;\r
+\r
+ //\r
+ // Close the Udp4 protocol.\r
+ //\r
+ gBS->CloseProtocol (\r
+ MtftpSb->ConnectUdp->UdpHandle,\r
+ &gEfiUdp4ProtocolGuid,\r
+ gMtftp4DriverBinding.DriverBindingHandle,\r
+ ChildHandle\r
+ );\r
+\r
+ //\r
+ // Uninstall the MTFTP4 protocol first to enable a top down destruction.\r
+ //\r
+ Status = gBS->UninstallProtocolInterface (\r
+ ChildHandle,\r
+ &gEfiMtftp4ProtocolGuid,\r
+ Mtftp4\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Instance->Indestory = FALSE;\r
+ return Status;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);\r
+ UdpIoFreePort (Instance->UnicastPort);\r
+\r
+ NetListRemoveEntry (&Instance->Link);\r
+ MtftpSb->ChildrenNum--;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ NetFreePool (Instance);\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Mtftp4Driver.h
+
+Abstract:
+
+
+**/
+
+#ifndef __EFI_MTFTP4_DRIVER_H__
+#define __EFI_MTFTP4_DRIVER_H__
+
+#include <PiDxe.h>
+
+#include <Protocol/ServiceBinding.h>
+
+#include <Library/NetLib.h>
+#include <Library/UefiLib.h>
+
+
+EFI_STATUS
+Mtftp4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+Mtftp4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+Mtftp4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+EFI_STATUS
+Mtftp4ServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN OUT EFI_HANDLE *ChildHandle
+ );
+
+EFI_STATUS
+Mtftp4ServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ );
+
+extern EFI_COMPONENT_NAME_PROTOCOL gMtftp4ComponentName;
+extern EFI_DRIVER_BINDING_PROTOCOL gMtftp4DriverBinding;
+
+#endif
--- /dev/null
+#/** @file\r
+# Component name for module Mtftp4\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 = Mtftp4Dxe\r
+ FILE_GUID = DC3641B8-2FA8-4ed3-BC1F-F9962A03454B\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ EDK_RELEASE_VERSION = 0x00020000\r
+ EFI_SPECIFICATION_VERSION = 0x00020000\r
+\r
+ ENTRY_POINT = Mtftp4DriverEntryPoint\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
+ Mtftp4Option.c\r
+ Mtftp4Rrq.c\r
+ Mtftp4Impl.h\r
+ ComponentName.c\r
+ Mtftp4Support.c\r
+ Mtftp4Impl.c\r
+ Mtftp4Option.h\r
+ Mtftp4Support.h\r
+ Mtftp4Driver.h\r
+ Mtftp4Driver.c\r
+ Mtftp4Wrq.c\r
+\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
+ gEfiMtftp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiMtftp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiUdp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+\r
--- /dev/null
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+ <MsaHeader>\r
+ <ModuleName>Mtftp4Dxe</ModuleName>\r
+ <ModuleType>DXE_DRIVER</ModuleType>\r
+ <GuidValue>DC3641B8-2FA8-4ed3-BC1F-F9962A03454B</GuidValue>\r
+ <Version>1.0</Version>\r
+ <Abstract>Component name for module Mtftp4</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>Mtftp4Dxe</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>Mtftp4Wrq.c</Filename>\r
+ <Filename>Mtftp4Driver.c</Filename>\r
+ <Filename>Mtftp4Driver.h</Filename>\r
+ <Filename>Mtftp4Support.h</Filename>\r
+ <Filename>Mtftp4Option.h</Filename>\r
+ <Filename>Mtftp4Impl.c</Filename>\r
+ <Filename>Mtftp4Support.c</Filename>\r
+ <Filename>ComponentName.c</Filename>\r
+ <Filename>Mtftp4Impl.h</Filename>\r
+ <Filename>Mtftp4Rrq.c</Filename>\r
+ <Filename>Mtftp4Option.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>gEfiUdp4ProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiUdp4ServiceBindingProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiMtftp4ProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiMtftp4ServiceBindingProtocolGuid</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>Mtftp4DriverEntryPoint</ModuleEntryPoint>\r
+ </Extern>\r
+ </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Mtftp4Impl.c\r
+\r
+Abstract:\r
+\r
+ Interface routine for Mtftp4\r
+\r
+\r
+**/\r
+\r
+#include "Mtftp4Impl.h"\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiMtftp4ReadFile (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ IN EFI_MTFTP4_TOKEN *Token\r
+ );\r
+\r
+\r
+/**\r
+ Get the current operation parameter for the MTFTP session\r
+\r
+ @param This The MTFTP protocol instance\r
+ @param ModeData The MTFTP mode data\r
+\r
+ @retval EFI_INVALID_PARAMETER This or ModeData is NULL\r
+ @retval EFI_SUCCESS The operation parameter is saved in ModeData\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiMtftp4GetModeData (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ OUT EFI_MTFTP4_MODE_DATA *ModeData\r
+ )\r
+{\r
+ MTFTP4_PROTOCOL *Instance;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((This == NULL) || (ModeData == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ Instance = MTFTP4_PROTOCOL_FROM_THIS (This);\r
+ ModeData->ConfigData = Instance->Config;\r
+ ModeData->SupportedOptionCount = MTFTP4_SUPPORTED_OPTIONS;\r
+ ModeData->SupportedOptoins = mMtftp4SupportedOptions;\r
+ ModeData->UnsupportedOptionCount = 0;\r
+ ModeData->UnsupportedOptoins = NULL;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Clean up the MTFTP session to get ready for new operation.\r
+\r
+ @param Instance The MTFTP session to clean up\r
+ @param Result The result to return to the caller who initiated\r
+ the operation.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Mtftp4CleanOperation (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN EFI_STATUS Result\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ MTFTP4_BLOCK_RANGE *Block;\r
+ EFI_MTFTP4_TOKEN *Token;\r
+\r
+ //\r
+ // Free various resources.\r
+ //\r
+ Token = Instance->Token;\r
+\r
+ if (Token != NULL) {\r
+ Token->Status = Result;\r
+\r
+ if (Token->Event != NULL) {\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ Instance->Token = NULL;\r
+ }\r
+\r
+ ASSERT (Instance->UnicastPort != NULL);\r
+ UdpIoCleanPort (Instance->UnicastPort);\r
+\r
+ if (Instance->LastPacket != NULL) {\r
+ NetbufFree (Instance->LastPacket);\r
+ Instance->LastPacket = NULL;\r
+ }\r
+\r
+ if (Instance->McastUdpPort != NULL) {\r
+ UdpIoFreePort (Instance->McastUdpPort);\r
+ Instance->McastUdpPort = NULL;\r
+ }\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Instance->Blocks) {\r
+ Block = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);\r
+ NetListRemoveEntry (Entry);\r
+ NetFreePool (Block);\r
+ }\r
+\r
+ NetZeroMem (&Instance->RequestOption, sizeof (MTFTP4_OPTION));\r
+\r
+ Instance->Operation = 0;\r
+\r
+ Instance->BlkSize = MTFTP4_DEFAULT_BLKSIZE;\r
+ Instance->LastBlock = 0;\r
+ Instance->ServerIp = 0;\r
+ Instance->ListeningPort = 0;\r
+ Instance->ConnectedPort = 0;\r
+ Instance->Gateway = 0;\r
+ Instance->PacketToLive = 0;\r
+ Instance->MaxRetry = 0;\r
+ Instance->CurRetry = 0;\r
+ Instance->Timeout = 0;\r
+ Instance->McastIp = 0;\r
+ Instance->McastPort = 0;\r
+ Instance->Master = TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Configure the MTFTP session for new operation or reset the current\r
+ operation if ConfigData is NULL.\r
+\r
+ @param This The MTFTP session to configure\r
+ @param ConfigData The configure parameters\r
+\r
+ @retval EFI_INVALID_PARAMETER Some of the parameter is invalid.\r
+ @retval EFI_ACCESS_DENIED There is pending operation\r
+ @retval EFI_SUCCESS The instance is configured for operation.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiMtftp4Configure (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ IN EFI_MTFTP4_CONFIG_DATA *ConfigData\r
+ )\r
+{\r
+ MTFTP4_PROTOCOL *Instance;\r
+ EFI_TPL OldTpl;\r
+ IP4_ADDR Ip;\r
+ IP4_ADDR Netmask;\r
+ IP4_ADDR Gateway;\r
+ IP4_ADDR ServerIp;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MTFTP4_PROTOCOL_FROM_THIS (This);\r
+\r
+ if (ConfigData == NULL) {\r
+ //\r
+ // Reset the operation if ConfigData is NULL\r
+ //\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ Mtftp4CleanOperation (Instance, EFI_ABORTED);\r
+ NetZeroMem (&Instance->Config, sizeof (EFI_MTFTP4_CONFIG_DATA));\r
+ Instance->State = MTFTP4_STATE_UNCONFIGED;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ } else {\r
+ //\r
+ // Configure the parameters for new operation.\r
+ //\r
+ NetCopyMem (&Ip, &ConfigData->StationIp, sizeof (IP4_ADDR));\r
+ NetCopyMem (&Netmask, &ConfigData->SubnetMask, sizeof (IP4_ADDR));\r
+ NetCopyMem (&Gateway, &ConfigData->GatewayIp, sizeof (IP4_ADDR));\r
+ NetCopyMem (&ServerIp, &ConfigData->ServerIp, sizeof (IP4_ADDR));\r
+\r
+ Ip = NTOHL (Ip);\r
+ Netmask = NTOHL (Netmask);\r
+ Gateway = NTOHL (Gateway);\r
+ ServerIp = NTOHL (ServerIp);\r
+\r
+ if (!Ip4IsUnicast (ServerIp, 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!ConfigData->UseDefaultSetting &&\r
+ ((!IP4_IS_VALID_NETMASK (Netmask) || !Ip4IsUnicast (Ip, Netmask)))) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Gateway != 0) &&\r
+ (!IP4_NET_EQUAL (Gateway, Ip, Netmask) || !Ip4IsUnicast (Gateway, Netmask))) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if ((Instance->State == MTFTP4_STATE_CONFIGED) && (Instance->Operation != 0)) {\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ Instance->Config = *ConfigData;\r
+ Instance->State = MTFTP4_STATE_CONFIGED;\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Check packet for GetInfo. GetInfo is implemented with EfiMtftp4ReadFile.\r
+ It use Mtftp4GetInfoCheckPacket to inspect the first packet from server,\r
+ then abort the session.\r
+\r
+ @param This The MTFTP4 protocol instance\r
+ @param Token The user's token\r
+ @param PacketLen The length of the packet\r
+ @param Packet The received packet.\r
+\r
+ @retval EFI_ABORTED Abort the ReadFile operation and return.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Mtftp4GetInfoCheckPacket (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ IN EFI_MTFTP4_TOKEN *Token,\r
+ IN UINT16 PacketLen,\r
+ IN EFI_MTFTP4_PACKET *Packet\r
+ )\r
+{\r
+ MTFTP4_GETINFO_STATE *State;\r
+ EFI_STATUS Status;\r
+ UINT16 OpCode;\r
+\r
+ State = (MTFTP4_GETINFO_STATE *) Token->Context;\r
+ OpCode = NTOHS (Packet->OpCode);\r
+\r
+ //\r
+ // Set the GetInfo's return status according to the OpCode.\r
+ //\r
+ switch (OpCode) {\r
+ case EFI_MTFTP4_OPCODE_ERROR:\r
+ State->Status = EFI_TFTP_ERROR;\r
+ break;\r
+\r
+ case EFI_MTFTP4_OPCODE_OACK:\r
+ State->Status = EFI_SUCCESS;\r
+ break;\r
+\r
+ default:\r
+ State->Status = EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ //\r
+ // Allocate buffer then copy the packet over. Use gBS->AllocatePool\r
+ // in case NetAllocatePool will implements something tricky.\r
+ //\r
+ Status = gBS->AllocatePool (EfiBootServicesData, PacketLen, (VOID **) State->Packet);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ State->Status = EFI_OUT_OF_RESOURCES;\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ *(State->PacketLen) = PacketLen;\r
+ NetCopyMem (*(State->Packet), Packet, PacketLen);\r
+\r
+ return EFI_ABORTED;\r
+}\r
+\r
+\r
+/**\r
+ Get the information of the download from the server. It is implemented\r
+ with EfiMtftp4ReadFile: build a token, then pass it to EfiMtftp4ReadFile.\r
+ In its check packet callback abort the opertions.\r
+\r
+ @param This The MTFTP protocol instance\r
+ @param OverrideData The MTFTP override data\r
+ @param Filename The file to get information\r
+ @param ModeStr The mode to use\r
+ @param OptionCount The number of options to append\r
+ @param OptionList The options to append\r
+ @param PacketLength The variable to receive the packet length\r
+ @param Packet The variable to receive the packet.\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameter is invaid\r
+ @retval EFI_SUCCESS The information is got\r
+ @retval Others Failed to get the information.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiMtftp4GetInfo (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ IN EFI_MTFTP4_OVERRIDE_DATA *OverrideData, OPTIONAL\r
+ IN UINT8 *Filename,\r
+ IN UINT8 *ModeStr, OPTIONAL\r
+ IN UINT8 OptionCount,\r
+ IN EFI_MTFTP4_OPTION *OptionList,\r
+ OUT UINT32 *PacketLength,\r
+ OUT EFI_MTFTP4_PACKET **Packet OPTIONAL\r
+ )\r
+{\r
+ EFI_MTFTP4_TOKEN Token;\r
+ MTFTP4_GETINFO_STATE State;\r
+ EFI_STATUS Status;\r
+\r
+ if ((This == NULL) || (Filename == NULL) || (PacketLength == NULL) ||\r
+ (OptionCount && (OptionList == NULL))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Packet != NULL) {\r
+ *Packet = NULL;\r
+ }\r
+\r
+ *PacketLength = 0;\r
+ State.Packet = Packet;\r
+ State.PacketLen = PacketLength;\r
+ State.Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Fill in the Token to issue an synchronous ReadFile operation\r
+ //\r
+ Token.Status = EFI_SUCCESS;\r
+ Token.Event = NULL;\r
+ Token.OverrideData = OverrideData;\r
+ Token.Filename = Filename;\r
+ Token.ModeStr = ModeStr;\r
+ Token.OptionCount = OptionCount;\r
+ Token.OptionList = OptionList;\r
+ Token.BufferSize = 0;\r
+ Token.Buffer = NULL;\r
+ Token.Context = &State;\r
+ Token.CheckPacket = Mtftp4GetInfoCheckPacket;\r
+ Token.TimeoutCallback = NULL;\r
+ Token.PacketNeeded = NULL;\r
+\r
+ Status = EfiMtftp4ReadFile (This, &Token);\r
+\r
+ if (EFI_ABORTED == Status) {\r
+ return State.Status;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Parse the packet into an array of options. The OptionList is allocated\r
+ by this function, and caller should free it when used.\r
+\r
+ @param This The MTFTP protocol instance\r
+ @param PacketLen The length of the packet\r
+ @param Packet The packet to parse\r
+ @param OptionCount The size of the OptionList array allocated.\r
+ @param OptionList The allocated option array to save the option\r
+ addresses.\r
+\r
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
+ @retval EFI_NOT_FOUND There is no valid option in the packet\r
+ @retval EFI_SUCCESS The packet is parsed.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiMtftp4ParseOptions (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ IN UINT32 PacketLen,\r
+ IN EFI_MTFTP4_PACKET *Packet,\r
+ IN OUT UINT32 *OptionCount,\r
+ OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if ((This == NULL) || (PacketLen < MTFTP4_OPCODE_LEN) ||\r
+ (Packet == NULL) || (OptionCount == NULL)) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = Mtftp4ExtractOptions (Packet, PacketLen, OptionCount, OptionList);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (*OptionCount == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Check whether the override data is valid. It will first\r
+ validate whether the server is a valid unicast. If a gateway\r
+ is provided in the Override, it also check that it is a\r
+ unicast on the connected network.\r
+\r
+ @param Instance The MTFTP instance\r
+ @param Override The override data to validate.\r
+\r
+ @return TRUE if the override data is valid, otherwise FALSE.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+Mtftp4OverrideValid (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN EFI_MTFTP4_OVERRIDE_DATA *Override\r
+ )\r
+{\r
+ EFI_MTFTP4_CONFIG_DATA *Config;\r
+ IP4_ADDR Ip;\r
+ IP4_ADDR Netmask;\r
+ IP4_ADDR Gateway;\r
+\r
+ NetCopyMem (&Ip, &Override->ServerIp, sizeof (IP4_ADDR));\r
+ if (!Ip4IsUnicast (NTOHL (Ip), 0)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Config = &Instance->Config;\r
+\r
+ NetCopyMem (&Gateway, &Override->GatewayIp, sizeof (IP4_ADDR));\r
+ Gateway = NTOHL (Gateway);\r
+\r
+ if (!Config->UseDefaultSetting && (Gateway != 0)) {\r
+ NetCopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));\r
+ NetCopyMem (&Ip, &Config->StationIp, sizeof (IP4_ADDR));\r
+\r
+ Netmask = NTOHL (Netmask);\r
+ Ip = NTOHL (Ip);\r
+\r
+ if (!Ip4IsUnicast (Gateway, Netmask) || !IP4_NET_EQUAL (Gateway, Ip, Netmask)) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Poll the UDP to get the IP4 default address, which may be retrieved\r
+ by DHCP. The default time out value is 5 seconds. If IP has retrieved\r
+ the default address, the UDP is reconfigured.\r
+\r
+ @param Instance The Mtftp instance\r
+ @param UdpPort The UDP port to poll\r
+ @param UdpCfgData The UDP configure data to reconfigure the UDP\r
+ port.\r
+\r
+ @return TRUE if the default address is retrieved and UDP is reconfigured.\r
+ @return Otherwise FALSE.\r
+\r
+**/\r
+BOOLEAN\r
+Mtftp4GetMapping (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN UDP_IO_PORT *UdpPort,\r
+ IN EFI_UDP4_CONFIG_DATA *UdpCfgData\r
+ )\r
+{\r
+ MTFTP4_SERVICE *Service;\r
+ EFI_IP4_MODE_DATA Ip4Mode;\r
+ EFI_UDP4_PROTOCOL *Udp;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Instance->Config.UseDefaultSetting);\r
+\r
+ Service = Instance->Service;\r
+ Udp = UdpPort->Udp;\r
+\r
+ Status = gBS->SetTimer (\r
+ Service->TimerToGetMap,\r
+ TimerRelative,\r
+ MTFTP4_TIME_TO_GETMAP * TICKS_PER_SECOND\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ while (!EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {\r
+ Udp->Poll (Udp);\r
+\r
+ if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip4Mode, NULL, NULL)) &&\r
+ Ip4Mode.IsConfigured) {\r
+\r
+ Udp->Configure (Udp, NULL);\r
+ return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Configure the UDP port for unicast receiving.\r
+\r
+ @param UdpIo The UDP port\r
+ @param Instance The MTFTP session\r
+\r
+ @retval EFI_SUCCESS The UDP port is successfully configured for the\r
+ session to unicast receive.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Mtftp4ConfigUnicastPort (\r
+ IN UDP_IO_PORT *UdpIo,\r
+ IN MTFTP4_PROTOCOL *Instance\r
+ )\r
+{\r
+ EFI_MTFTP4_CONFIG_DATA *Config;\r
+ EFI_UDP4_CONFIG_DATA UdpConfig;\r
+ EFI_STATUS Status;\r
+ IP4_ADDR Ip;\r
+\r
+ Config = &Instance->Config;\r
+\r
+ UdpConfig.AcceptBroadcast = FALSE;\r
+ UdpConfig.AcceptPromiscuous = FALSE;\r
+ UdpConfig.AcceptAnyPort = FALSE;\r
+ UdpConfig.AllowDuplicatePort = FALSE;\r
+ UdpConfig.TypeOfService = 0;\r
+ UdpConfig.TimeToLive = 64;\r
+ UdpConfig.DoNotFragment = FALSE;\r
+ UdpConfig.ReceiveTimeout = 0;\r
+ UdpConfig.TransmitTimeout = 0;\r
+ UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;\r
+ UdpConfig.StationAddress = Config->StationIp;\r
+ UdpConfig.SubnetMask = Config->SubnetMask;\r
+ UdpConfig.StationPort = 0;\r
+ UdpConfig.RemotePort = 0;\r
+\r
+ Ip = HTONL (Instance->ServerIp);\r
+ NetCopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ Status = UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfig);\r
+\r
+ if ((Status == EFI_NO_MAPPING) && Mtftp4GetMapping (Instance, UdpIo, &UdpConfig)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Start the MTFTP session to do the operation, such as read file,\r
+ write file, and read directory.\r
+\r
+ @param This The MTFTP session\r
+ @param Token The token than encapsues the user's request.\r
+ @param Operation The operation to do\r
+\r
+ @retval EFI_INVALID_PARAMETER Some of the parameters are invalid.\r
+ @retval EFI_NOT_STARTED The MTFTP session hasn't been configured.\r
+ @retval EFI_ALREADY_STARTED There is pending operation for the session.\r
+ @retval EFI_SUCCESS The operation is successfully started.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Mtftp4Start (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ IN EFI_MTFTP4_TOKEN *Token,\r
+ IN UINT16 Operation\r
+ )\r
+{\r
+ MTFTP4_PROTOCOL *Instance;\r
+ EFI_MTFTP4_OVERRIDE_DATA *Override;\r
+ EFI_MTFTP4_CONFIG_DATA *Config;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Validate the parameters\r
+ //\r
+ if ((This == NULL) || (Token == NULL) || (Token->Filename == NULL) ||\r
+ ((Token->OptionCount != 0) && (Token->OptionList == NULL))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // User must provide at least one method to collect the data for download.\r
+ //\r
+ if (((Operation == EFI_MTFTP4_OPCODE_RRQ) || (Operation == EFI_MTFTP4_OPCODE_DIR)) &&\r
+ ((Token->Buffer == NULL) && (Token->CheckPacket == NULL))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // User must provide at least one method to provide the data for upload.\r
+ //\r
+ if ((Operation == EFI_MTFTP4_OPCODE_WRQ) &&\r
+ ((Token->Buffer == NULL) && (Token->PacketNeeded == NULL))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MTFTP4_PROTOCOL_FROM_THIS (This);\r
+\r
+ Status = EFI_SUCCESS;\r
+ OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
+\r
+ if (Instance->State != MTFTP4_STATE_CONFIGED) {\r
+ Status = EFI_NOT_STARTED;\r
+ }\r
+\r
+ if (Instance->Operation != 0) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NET_RESTORE_TPL (OldTpl);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set the Operation now to prevent the application start other\r
+ // operations.\r
+ //\r
+ Instance->Operation = Operation;\r
+ Override = Token->OverrideData;\r
+\r
+ if ((Override != NULL) && !Mtftp4OverrideValid (Instance, Override)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ if (Token->OptionCount != 0) {\r
+ Status = Mtftp4ParseOption (\r
+ Token->OptionList,\r
+ Token->OptionCount,\r
+ TRUE,\r
+ &Instance->RequestOption\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Set the operation parameters from the configuration or override data.\r
+ //\r
+ Config = &Instance->Config;\r
+ Instance->Token = Token;\r
+ Instance->BlkSize = MTFTP4_DEFAULT_BLKSIZE;\r
+\r
+ NetCopyMem (&Instance->ServerIp, &Config->ServerIp, sizeof (IP4_ADDR));\r
+ Instance->ServerIp = NTOHL (Instance->ServerIp);\r
+\r
+ Instance->ListeningPort = Config->InitialServerPort;\r
+ Instance->ConnectedPort = 0;\r
+\r
+ NetCopyMem (&Instance->Gateway, &Config->GatewayIp, sizeof (IP4_ADDR));\r
+ Instance->Gateway = NTOHL (Instance->Gateway);\r
+\r
+ Instance->MaxRetry = Config->TryCount;\r
+ Instance->Timeout = Config->TimeoutValue;\r
+ Instance->Master = TRUE;\r
+\r
+ if (Override != NULL) {\r
+ NetCopyMem (&Instance->ServerIp, &Override->ServerIp, sizeof (IP4_ADDR));\r
+ NetCopyMem (&Instance->Gateway, &Override->GatewayIp, sizeof (IP4_ADDR));\r
+\r
+ Instance->ServerIp = NTOHL (Instance->ServerIp);\r
+ Instance->Gateway = NTOHL (Instance->Gateway);\r
+\r
+ Instance->ListeningPort = Override->ServerPort;\r
+ Instance->MaxRetry = Override->TryCount;\r
+ Instance->Timeout = Override->TimeoutValue;\r
+ }\r
+\r
+ if (Instance->ListeningPort == 0) {\r
+ Instance->ListeningPort = MTFTP4_DEFAULT_SERVER_PORT;\r
+ }\r
+\r
+ if (Instance->MaxRetry == 0) {\r
+ Instance->MaxRetry = MTFTP4_DEFAULT_RETRY;\r
+ }\r
+\r
+ if (Instance->Timeout == 0) {\r
+ Instance->Timeout = MTFTP4_DEFAULT_TIMEOUT;\r
+ }\r
+\r
+ //\r
+ // Config the unicast UDP child to send initial request\r
+ //\r
+ Status = Mtftp4ConfigUnicastPort (Instance->UnicastPort, Instance);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Build and send an initial requests\r
+ //\r
+ if (Operation == EFI_MTFTP4_OPCODE_WRQ) {\r
+ Status = Mtftp4WrqStart (Instance, Operation);\r
+ } else {\r
+ Status = Mtftp4RrqStart (Instance, Operation);\r
+ }\r
+\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+ //\r
+ // Return immediately for asynchronous operation or poll the\r
+ // instance for synchronous operation.\r
+ //\r
+ Token->Status = EFI_NOT_READY;\r
+\r
+ if (Token->Event != NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ while (Token->Status == EFI_NOT_READY) {\r
+ This->Poll (This);\r
+ }\r
+\r
+ return Token->Status;\r
+\r
+ON_ERROR:\r
+ Mtftp4CleanOperation (Instance, Status);\r
+ NET_RESTORE_TPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Read a file from the server.\r
+\r
+ @param This The Mtftp protocol instance.\r
+ @param Token The user's request wrap token.\r
+\r
+ @retval EFI_SUCCESS The ReadFile has finished, the file has been\r
+ downloaded if it is synchronous operation,\r
+ otherwise it has been initated.\r
+ @retval Others Some error happened.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiMtftp4ReadFile (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ IN EFI_MTFTP4_TOKEN *Token\r
+ )\r
+{\r
+ return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_RRQ);\r
+}\r
+\r
+\r
+/**\r
+ Upload a file to the server.\r
+\r
+ @param This The MTFTP protocol session\r
+ @param Token The user's request wrap token.\r
+\r
+ @retval EFI_SUCCESS The WriteFile has finished, the file has been\r
+ uploaded if it is synchronous operation, otherwise\r
+ it has been initated.\r
+ @retval Others Some error happened.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiMtftp4WriteFile (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ IN EFI_MTFTP4_TOKEN *Token\r
+ )\r
+{\r
+ return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_WRQ);\r
+}\r
+\r
+\r
+/**\r
+ Read a directory from the server. The only difference\r
+ between ReadFile and ReadDirectory is the opcode used.\r
+\r
+ @param This The MTFTP protocol session\r
+ @param Token The user's request wrap token.\r
+\r
+ @retval EFI_SUCCESS The ReadDirectory has finished, the directory has\r
+ been downloaded as a file if it is synchronous\r
+ operation, otherwise it has been initated.\r
+ @retval Others Some error happened.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiMtftp4ReadDirectory (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ IN EFI_MTFTP4_TOKEN *Token\r
+ )\r
+{\r
+ return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_DIR);\r
+}\r
+\r
+\r
+/**\r
+ Poll the network stack to accelerate the packet process.\r
+\r
+ @param This The MTFTP protocol instance.\r
+\r
+ @retval EFI_INVALID_PARAMETER This is NULL.\r
+ @retval EFI_NOT_STARTED The MTFTP session hasn't been configured.\r
+ @retval EFI_DEVICE_ERROR The MTFTP session has been destoried.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EfiMtftp4Poll (\r
+ IN EFI_MTFTP4_PROTOCOL *This\r
+ )\r
+{\r
+ MTFTP4_PROTOCOL *Instance;\r
+ EFI_UDP4_PROTOCOL *Udp;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Instance = MTFTP4_PROTOCOL_FROM_THIS (This);\r
+\r
+ if (Instance->State == MTFTP4_STATE_UNCONFIGED) {\r
+ return EFI_NOT_STARTED;\r
+ } else if (Instance->State == MTFTP4_STATE_DESTORY) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Udp = Instance->UnicastPort->Udp;\r
+ return Udp->Poll (Udp);\r
+}\r
+\r
+EFI_MTFTP4_PROTOCOL gMtftp4ProtocolTemplate = {\r
+ EfiMtftp4GetModeData,\r
+ EfiMtftp4Configure,\r
+ EfiMtftp4GetInfo,\r
+ EfiMtftp4ParseOptions,\r
+ EfiMtftp4ReadFile,\r
+ EfiMtftp4WriteFile,\r
+ EfiMtftp4ReadDirectory,\r
+ EfiMtftp4Poll\r
+};\r
--- /dev/null
+/** @file
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Mtftp4Impl.h
+
+Abstract:
+
+ Mtftp4 Implementation, it supports the following RFCs:
+ RFC1350 - THE TFTP PROTOCOL (REVISION 2)
+ RFC2090 - TFTP Multicast Option
+ RFC2347 - TFTP Option Extension
+ RFC2348 - TFTP Blocksize Option
+ RFC2349 - TFTP Timeout Interval and Transfer Size Options
+
+
+**/
+
+#ifndef __EFI_MTFTP4_IMPL_H__
+#define __EFI_MTFTP4_IMPL_H__
+
+#include <PiDxe.h>\r
+\r
+#include <Protocol/Udp4.h>\r
+#include <Protocol/Mtftp4.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/UdpIoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+
+typedef struct _MTFTP4_SERVICE MTFTP4_SERVICE;
+typedef struct _MTFTP4_PROTOCOL MTFTP4_PROTOCOL;
+
+#include "Mtftp4Driver.h"
+#include "Mtftp4Option.h"
+#include "Mtftp4Support.h"
+
+enum {
+ MTFTP4_SERVICE_SIGNATURE = EFI_SIGNATURE_32 ('T', 'F', 'T', 'P'),
+ MTFTP4_PROTOCOL_SIGNATURE = EFI_SIGNATURE_32 ('t', 'f', 't', 'p'),
+
+ MTFTP4_DEFAULT_SERVER_PORT = 69,
+ MTFTP4_DEFAULT_TIMEOUT = 3,
+ MTFTP4_DEFAULT_RETRY = 5,
+ MTFTP4_DEFAULT_BLKSIZE = 512,
+ MTFTP4_TIME_TO_GETMAP = 5,
+
+ MTFTP4_STATE_UNCONFIGED = 0,
+ MTFTP4_STATE_CONFIGED,
+ MTFTP4_STATE_DESTORY,
+};
+
+typedef struct _MTFTP4_SERVICE {
+ UINT32 Signature;
+ EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
+
+ BOOLEAN InDestory;
+
+ UINT16 ChildrenNum;
+ NET_LIST_ENTRY Children;
+
+ EFI_EVENT Timer; // Ticking timer for all the MTFTP clients
+ EFI_EVENT TimerToGetMap;
+
+ EFI_HANDLE Controller;
+ EFI_HANDLE Image;
+
+ //
+ // This UDP child is used to keep the connection between the UDP
+ // and MTFTP, so MTFTP will be notified when UDP is uninstalled.
+ //
+ UDP_IO_PORT *ConnectUdp;
+};
+
+typedef struct _MTFTP4_PROTOCOL {
+ UINT32 Signature;
+ NET_LIST_ENTRY Link;
+ EFI_MTFTP4_PROTOCOL Mtftp4;
+
+ INTN State;
+ BOOLEAN Indestory;
+
+ MTFTP4_SERVICE *Service;
+ EFI_HANDLE Handle;
+
+ EFI_MTFTP4_CONFIG_DATA Config;
+
+ //
+ // Operation parameters: token and requested options.
+ //
+ EFI_MTFTP4_TOKEN *Token;
+ MTFTP4_OPTION RequestOption;
+ UINT16 Operation;
+
+ //
+ // Blocks is a list of MTFTP4_BLOCK_RANGE which contains
+ // holes in the file
+ //
+ UINT16 BlkSize;
+ UINT16 LastBlock;
+ NET_LIST_ENTRY Blocks;
+
+ //
+ // The server's communication end point: IP and two ports. one for
+ // initial request, one for its selected port.
+ //
+ IP4_ADDR ServerIp;
+ UINT16 ListeningPort;
+ UINT16 ConnectedPort;
+ IP4_ADDR Gateway;
+ UDP_IO_PORT *UnicastPort;
+
+ //
+ // Timeout and retransmit status
+ //
+ NET_BUF *LastPacket;
+ UINT32 PacketToLive;
+ UINT32 CurRetry;
+ UINT32 MaxRetry;
+ UINT32 Timeout;
+
+ //
+ // Parameter used by RRQ's multicast download.
+ //
+ IP4_ADDR McastIp;
+ UINT16 McastPort;
+ BOOLEAN Master;
+ UDP_IO_PORT *McastUdpPort;
+};
+
+typedef struct {
+ EFI_MTFTP4_PACKET **Packet;
+ UINT32 *PacketLen;
+ EFI_STATUS Status;
+} MTFTP4_GETINFO_STATE;
+
+VOID
+Mtftp4CleanOperation (
+ IN MTFTP4_PROTOCOL *Instance,
+ IN EFI_STATUS Result
+ );
+
+EFI_STATUS
+Mtftp4WrqStart (
+ IN MTFTP4_PROTOCOL *Instance,
+ IN UINT16 Operation
+ );
+
+EFI_STATUS
+Mtftp4RrqStart (
+ IN MTFTP4_PROTOCOL *Instance,
+ IN UINT16 Operation
+ );
+
+#define MTFTP4_SERVICE_FROM_THIS(a) \
+ CR (a, MTFTP4_SERVICE, ServiceBinding, MTFTP4_SERVICE_SIGNATURE)
+
+#define MTFTP4_PROTOCOL_FROM_THIS(a) \
+ CR (a, MTFTP4_PROTOCOL, Mtftp4, MTFTP4_PROTOCOL_SIGNATURE)
+
+extern EFI_MTFTP4_PROTOCOL gMtftp4ProtocolTemplate;
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Mtftp4Option.c\r
+\r
+Abstract:\r
+ routines to process MTFTP4 options\r
+\r
+\r
+**/\r
+\r
+#include "Mtftp4Impl.h"\r
+\r
+UINT8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS] = {\r
+ "blksize",\r
+ "timeout",\r
+ "tsize",\r
+ "multicast"\r
+};\r
+\r
+\r
+/**\r
+ Go through the packet to fill the Options array with the start\r
+ addresses of each MTFTP option name/value pair.\r
+\r
+ @param Packet The packet to check\r
+ @param PacketLen The packet's length\r
+ @param Count The size of the Options on input. The actual\r
+ options on output\r
+ @param Options The option array to fill in\r
+\r
+ @retval EFI_INVALID_PARAMETER The packet is mal-formated\r
+ @retval EFI_BUFFER_TOO_SMALL The Options array is too small\r
+ @retval EFI_SUCCESS The packet has been parsed into the Options array.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Mtftp4FillOptions (\r
+ IN EFI_MTFTP4_PACKET *Packet,\r
+ IN UINT32 PacketLen,\r
+ IN OUT UINT32 *Count,\r
+ OUT EFI_MTFTP4_OPTION *Options OPTIONAL\r
+ )\r
+{\r
+ UINT8 *Cur;\r
+ UINT8 *Last;\r
+ UINT8 Num;\r
+ UINT8 *Name;\r
+ UINT8 *Value;\r
+\r
+ Num = 0;\r
+ Cur = (UINT8 *) Packet + MTFTP4_OPCODE_LEN;\r
+ Last = (UINT8 *) Packet + PacketLen - 1;\r
+\r
+ //\r
+ // process option name and value pairs. The last byte is always zero\r
+ //\r
+ while (Cur < Last) {\r
+ Name = Cur;\r
+\r
+ while (*Cur != 0) {\r
+ Cur++;\r
+ }\r
+\r
+ if (Cur == Last) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Value = ++Cur;\r
+\r
+ while (*Cur != 0) {\r
+ Cur++;\r
+ }\r
+\r
+ Num++;\r
+\r
+ if ((Options != NULL) && (Num <= *Count)) {\r
+ Options[Num - 1].OptionStr = Name;\r
+ Options[Num - 1].ValueStr = Value;\r
+ }\r
+\r
+ Cur++;\r
+ }\r
+\r
+ if ((*Count < Num) || (Options == NULL)) {\r
+ *Count = Num;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ *Count = Num;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Allocate and fill in a array of Mtftp options from the Packet. It\r
+ first calls Mtftp4FillOption to get the option number, then allocate\r
+ the array, at last, call Mtftp4FillOption again to save the options.\r
+\r
+ @param Packet The packet to parse\r
+ @param PacketLen The length of the packet\r
+ @param OptionCount The number of options in the packet\r
+ @param OptionList The point to get the option array.\r
+\r
+ @retval EFI_INVALID_PARAMETER The parametera are invalid or packet isn't a\r
+ well-formated OACK packet.\r
+ @retval EFI_SUCCESS The option array is build\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4ExtractOptions (\r
+ IN EFI_MTFTP4_PACKET *Packet,\r
+ IN UINT32 PacketLen,\r
+ IN OUT UINT32 *OptionCount,\r
+ OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ *OptionCount = 0;\r
+\r
+ if (OptionList != NULL) {\r
+ *OptionList = NULL;\r
+ }\r
+\r
+ if (NTOHS (Packet->OpCode) != EFI_MTFTP4_OPCODE_OACK) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (PacketLen == MTFTP4_OPCODE_LEN) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // The last byte must be zero to terminate the options\r
+ //\r
+ if (*((UINT8 *) Packet + PacketLen - 1) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Get the number of options\r
+ //\r
+ Status = Mtftp4FillOptions (Packet, PacketLen, OptionCount, NULL);\r
+\r
+ if ((Status == EFI_SUCCESS) || (Status != EFI_BUFFER_TOO_SMALL)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Allocate memory for the options, then call Mtftp4FillOptions to\r
+ // fill it if caller want that.\r
+ //\r
+ if (OptionList == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ *OptionList = NetAllocatePool (*OptionCount * sizeof (EFI_MTFTP4_OPTION));\r
+\r
+ if (*OptionList == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Mtftp4FillOptions (Packet, PacketLen, OptionCount, *OptionList);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Check whether two ascii strings are equel, ignore the case.\r
+\r
+ @param Str1 The first ascii string\r
+ @param Str2 The second ascii string\r
+\r
+ @retval TRUE Two strings are equal when case is ignored.\r
+ @retval FALSE Two string are not equal.\r
+\r
+**/\r
+BOOLEAN\r
+NetStringEqualNoCase (\r
+ IN UINT8 *Str1,\r
+ IN UINT8 *Str2\r
+ )\r
+{\r
+ UINT8 Ch1;\r
+ UINT8 Ch2;\r
+\r
+ ASSERT ((Str1 != NULL) && (Str2 != NULL));\r
+\r
+ for (; (*Str1 != '\0') && (*Str2 != '\0'); Str1++, Str2++) {\r
+ Ch1 = *Str1;\r
+ Ch2 = *Str2;\r
+\r
+ //\r
+ // Convert them to lower case then compare two\r
+ //\r
+ if (('A' <= Ch1) && (Ch1 <= 'Z')) {\r
+ Ch1 += 'a' - 'A';\r
+ }\r
+\r
+ if (('A' <= Ch2) && (Ch2 <= 'Z')) {\r
+ Ch2 += 'a' - 'A';\r
+ }\r
+\r
+ if (Ch1 != Ch2) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return (BOOLEAN) (*Str1 == *Str2);\r
+}\r
+\r
+\r
+/**\r
+ Convert a string to a UINT32 number.\r
+\r
+ @param Str The string to convert from\r
+\r
+ @return The number get from the string\r
+\r
+**/\r
+UINT32\r
+NetStringToU32 (\r
+ IN UINT8 *Str\r
+ )\r
+{\r
+ UINT32 Num;\r
+\r
+ ASSERT (Str != NULL);\r
+\r
+ Num = 0;\r
+\r
+ for (; NET_IS_DIGIT (*Str); Str++) {\r
+ Num = Num * 10 + (*Str - '0');\r
+ }\r
+\r
+ return Num;\r
+}\r
+\r
+\r
+/**\r
+ Convert a string of the format "192.168.0.1" to an IP address.\r
+\r
+ @param Str The string representation of IP\r
+ @param Ip The varible to get IP.\r
+\r
+ @retval EFI_INVALID_PARAMETER The IP string is invalid.\r
+ @retval EFI_SUCCESS The IP is parsed into the Ip\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+NetStringToIp (\r
+ IN UINT8 *Str,\r
+ OUT IP4_ADDR *Ip\r
+ )\r
+{\r
+ UINT32 Byte;\r
+ UINT32 Addr;\r
+ UINTN Index;\r
+\r
+ *Ip = 0;\r
+ Addr = 0;\r
+\r
+ for (Index = 0; Index < 4; Index++) {\r
+ if (!NET_IS_DIGIT (*Str)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Byte = NetStringToU32 (Str);\r
+\r
+ if (Byte > 255) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Addr = (Addr << 8) | Byte;\r
+\r
+ //\r
+ // Skip all the digitals and check whether the sepeator is the dot\r
+ //\r
+ while (NET_IS_DIGIT (*Str)) {\r
+ Str++;\r
+ }\r
+\r
+ if ((Index < 3) && (*Str != '.')) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Str++;\r
+ }\r
+\r
+ *Ip = Addr;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Parse the MTFTP multicast option.\r
+\r
+ @param Value The Mtftp multicast value string\r
+ @param Option The option to save the info into.\r
+\r
+ @retval EFI_INVALID_PARAMETER The multicast value string is invalid.\r
+ @retval EFI_SUCCESS The multicast value is parsed into the Option\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Mtftp4ExtractMcast (\r
+ IN UINT8 *Value,\r
+ IN MTFTP4_OPTION *Option\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Num;\r
+\r
+ //\r
+ // The multicast option is formated like "204.0.0.1,1857,1"\r
+ // The server can also omit the ip and port, use ",,1"\r
+ //\r
+ if (*Value == ',') {\r
+ Option->McastIp = 0;\r
+ } else {\r
+ Status = NetStringToIp (Value, &Option->McastIp);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ while (*Value && (*Value != ',')) {\r
+ Value++;\r
+ }\r
+ }\r
+\r
+ if (*Value != ',') {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Value++;\r
+\r
+ //\r
+ // Convert the port setting. the server can send us a port number or\r
+ // empty string. such as the port in ",,1"\r
+ //\r
+ if (*Value == ',') {\r
+ Option->McastPort = 0;\r
+ } else {\r
+ Num = NetStringToU32 (Value);\r
+\r
+ if (Num > 65535) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Option->McastPort = (UINT16)Num;\r
+\r
+ while (NET_IS_DIGIT (*Value)) {\r
+ Value++;\r
+ }\r
+ }\r
+\r
+ if (*Value != ',') {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Value++;\r
+\r
+ //\r
+ // Check the master/slave setting, 1 for master, 0 for slave.\r
+ //\r
+ Num = NetStringToU32 (Value);\r
+\r
+ if ((Num != 0) && (Num != 1)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Option->Master = (BOOLEAN)(Num == 1);\r
+\r
+ while (NET_IS_DIGIT (*Value)) {\r
+ Value++;\r
+ }\r
+\r
+ if (*Value != '\0') {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Parse the option in Options array to MTFTP4_OPTION which program\r
+ can access directly.\r
+\r
+ @param Options The option array, which contains addresses of each\r
+ option's name/value string.\r
+ @param Count The number of options in the Options\r
+ @param Request Whether this is a request or OACK. The format of\r
+ multicast is different according to this setting.\r
+ @param MtftpOption The MTFTP4_OPTION for easy access.\r
+\r
+ @retval EFI_INVALID_PARAMETER The option is mal-formated\r
+ @retval EFI_UNSUPPORTED Some option isn't supported\r
+ @retval EFI_SUCCESS The option are OK and has been parsed.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4ParseOption (\r
+ IN EFI_MTFTP4_OPTION *Options,\r
+ IN UINT32 Count,\r
+ IN BOOLEAN Request,\r
+ OUT MTFTP4_OPTION *MtftpOption\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Index;\r
+ UINT32 Value;\r
+ EFI_MTFTP4_OPTION *This;\r
+\r
+ MtftpOption->Exist = 0;\r
+\r
+ for (Index = 0; Index < Count; Index++) {\r
+ This = Options + Index;\r
+\r
+ if ((This->OptionStr == NULL) || (This->ValueStr == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (NetStringEqualNoCase (This->OptionStr, "blksize")) {\r
+ //\r
+ // block size option, valid value is between [8, 65464]\r
+ //\r
+ Value = NetStringToU32 (This->ValueStr);\r
+\r
+ if ((Value < 8) || (Value > 65464)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ MtftpOption->BlkSize = (UINT16) Value;\r
+ MtftpOption->Exist |= MTFTP4_BLKSIZE_EXIST;\r
+\r
+ } else if (NetStringEqualNoCase (This->OptionStr, "timeout")) {\r
+ //\r
+ // timeout option, valid value is between [1, 255]\r
+ //\r
+ Value = NetStringToU32 (This->ValueStr);\r
+\r
+ if ((Value < 1) || (Value > 255)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ MtftpOption->Timeout = (UINT8) Value;\r
+\r
+ } else if (NetStringEqualNoCase (This->OptionStr, "tsize")) {\r
+ //\r
+ // tsize option, the biggest transfer supported is 4GB with block size option\r
+ //\r
+ MtftpOption->Tsize = NetStringToU32 (This->ValueStr);\r
+ MtftpOption->Exist |= MTFTP4_TSIZE_EXIST;\r
+\r
+ } else if (NetStringEqualNoCase (This->OptionStr, "multicast")) {\r
+ //\r
+ // Multicast option, if it is a request, the value must be a zero\r
+ // length string, otherwise, it is formated like "204.0.0.1,1857,1\0"\r
+ //\r
+ if (Request) {\r
+ if (*(This->ValueStr) != '\0') {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ } else {\r
+ Status = Mtftp4ExtractMcast (This->ValueStr, MtftpOption);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ MtftpOption->Exist |= MTFTP4_MCAST_EXIST;\r
+\r
+ } else if (Request) {\r
+ //\r
+ // Ignore the unsupported option if it is a reply, and return\r
+ // EFI_UNSUPPORTED if it's a request according to the UEFI spec.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Parse the options in the OACK packet to MTFTP4_OPTION which program\r
+ can access directly.\r
+\r
+ @param Packet The OACK packet to parse\r
+ @param PacketLen The length of the packet\r
+ @param MtftpOption The MTFTP_OPTION for easy access.\r
+\r
+ @retval EFI_INVALID_PARAMETER The packet option is mal-formated\r
+ @retval EFI_UNSUPPORTED Some option isn't supported\r
+ @retval EFI_SUCCESS The option are OK and has been parsed.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4ParseOptionOack (\r
+ IN EFI_MTFTP4_PACKET *Packet,\r
+ IN UINT32 PacketLen,\r
+ OUT MTFTP4_OPTION *MtftpOption\r
+ )\r
+{\r
+ EFI_MTFTP4_OPTION *OptionList;\r
+ EFI_STATUS Status;\r
+ UINT32 Count;\r
+\r
+ MtftpOption->Exist = 0;\r
+\r
+ Status = Mtftp4ExtractOptions (Packet, PacketLen, &Count, &OptionList);\r
+\r
+ if (EFI_ERROR (Status) || (Count == 0)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = Mtftp4ParseOption (OptionList, Count, FALSE, MtftpOption);\r
+\r
+ NetFreePool (OptionList);\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Mtftp4Option.h
+
+Abstract:
+
+ Mtftp4 option process routines.
+
+
+**/
+
+#ifndef __EFI_MTFTP4_OPTION_H__
+#define __EFI_MTFTP4_OPTION_H__
+
+enum {
+ MTFTP4_SUPPORTED_OPTIONS = 4,
+ MTFTP4_OPCODE_LEN = 2,
+ MTFTP4_ERRCODE_LEN = 2,
+ MTFTP4_BLKNO_LEN = 2,
+ MTFTP4_DATA_HEAD_LEN = 4,
+
+ MTFTP4_BLKSIZE_EXIST = 0x01,
+ MTFTP4_TIMEOUT_EXIST = 0x02,
+ MTFTP4_TSIZE_EXIST = 0x04,
+ MTFTP4_MCAST_EXIST = 0x08,
+};
+
+typedef struct {
+ UINT16 BlkSize;
+ UINT8 Timeout;
+ UINT32 Tsize;
+ IP4_ADDR McastIp;
+ UINT16 McastPort;
+ BOOLEAN Master;
+ UINT32 Exist;
+} MTFTP4_OPTION;
+
+EFI_STATUS
+Mtftp4ExtractOptions (
+ IN EFI_MTFTP4_PACKET *Packet,
+ IN UINT32 PacketLen,
+ IN OUT UINT32 *OptionCount,
+ OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL
+ );
+
+EFI_STATUS
+Mtftp4ParseOption (
+ IN EFI_MTFTP4_OPTION *OptionList,
+ IN UINT32 Count,
+ IN BOOLEAN Request,
+ OUT MTFTP4_OPTION *Option
+ );
+
+EFI_STATUS
+Mtftp4ParseOptionOack (
+ IN EFI_MTFTP4_PACKET *Packet,
+ IN UINT32 PacketLen,
+ OUT MTFTP4_OPTION *Option
+ );
+
+extern UINT8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS];
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Mtftp4Rrq.c\r
+\r
+Abstract:\r
+\r
+ Routines to process Rrq (download)\r
+\r
+\r
+**/\r
+\r
+#include "Mtftp4Impl.h"\r
+\r
+VOID\r
+Mtftp4RrqInput (\r
+ IN NET_BUF *UdpPacket,\r
+ IN UDP_POINTS *Points,\r
+ IN EFI_STATUS IoStatus,\r
+ IN VOID *Context\r
+ );\r
+\r
+\r
+/**\r
+ Start the MTFTP session to download. It will first initialize some\r
+ of the internal states then build and send a RRQ reqeuest packet, at\r
+ last, it will start receive for the downloading.\r
+\r
+ @param Instance The Mtftp session\r
+ @param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ\r
+ or EFI_MTFTP4_OPCODE_DIR.\r
+\r
+ @retval EFI_SUCCESS The mtftp download session is started.\r
+ @retval Others Failed to start downloading.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4RrqStart (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN UINT16 Operation\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // The valid block number range are [1, 0xffff]. For example:\r
+ // the client sends an RRQ request to the server, the server\r
+ // transfers the DATA1 block. If option negoitation is ongoing,\r
+ // the server will send back an OACK, then client will send ACK0.\r
+ //\r
+ Status = Mtftp4InitBlockRange (&Instance->Blocks, 1, 0xffff);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = Mtftp4SendRequest (Instance);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);\r
+}\r
+\r
+\r
+/**\r
+ Build and send a ACK packet for the download session.\r
+\r
+ @param Instance The Mtftp session\r
+ @param BlkNo The BlkNo to ack.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet\r
+ @retval EFI_SUCCESS The ACK has been sent\r
+ @retval Others Failed to send the ACK.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4RrqSendAck (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN UINT16 BlkNo\r
+ )\r
+{\r
+ EFI_MTFTP4_PACKET *Ack;\r
+ NET_BUF *Packet;\r
+\r
+ Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));\r
+\r
+ if (Packet == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Ack = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (\r
+ Packet,\r
+ sizeof (EFI_MTFTP4_ACK_HEADER),\r
+ FALSE\r
+ );\r
+\r
+ Ack->Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);\r
+ Ack->Ack.Block[0] = HTONS (BlkNo);\r
+\r
+ return Mtftp4SendPacket (Instance, Packet);\r
+}\r
+\r
+\r
+/**\r
+ Deliver the received data block to the user, which can be saved\r
+ in the user provide buffer or through the CheckPacket callback.\r
+\r
+ @param Instance The Mtftp session\r
+ @param Packet The received data packet\r
+ @param Len The packet length\r
+\r
+ @retval EFI_SUCCESS The data is saved successfully\r
+ @retval EFI_ABORTED The user tells to abort by return an error through\r
+ CheckPacket\r
+ @retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is\r
+ updated to the actual buffer size needed.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4RrqSaveBlock (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN EFI_MTFTP4_PACKET *Packet,\r
+ IN UINT32 Len\r
+ )\r
+{\r
+ EFI_MTFTP4_TOKEN *Token;\r
+ EFI_STATUS Status;\r
+ UINT16 Block;\r
+ UINT64 Start;\r
+ UINT32 DataLen;\r
+\r
+ Token = Instance->Token;\r
+ Block = NTOHS (Packet->Data.Block);\r
+ DataLen = Len - MTFTP4_DATA_HEAD_LEN;\r
+\r
+ //\r
+ // This is the last block, save the block no\r
+ //\r
+ if (DataLen < Instance->BlkSize) {\r
+ Instance->LastBlock = Block;\r
+ Mtftp4SetLastBlockNum (&Instance->Blocks, Block);\r
+ }\r
+\r
+ //\r
+ // Remove this block number from the file hole. If Mtftp4RemoveBlockNum\r
+ // returns EFI_NOT_FOUND, the block has been saved, don't save it again.\r
+ //\r
+ Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block);\r
+\r
+ if (Status == EFI_NOT_FOUND) {\r
+ return EFI_SUCCESS;\r
+ } else if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Token->CheckPacket != NULL) {\r
+ Status = Token->CheckPacket (&Instance->Mtftp4, Token, (UINT16) Len, Packet);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
+ "User aborted download"\r
+ );\r
+\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ if (Token->Buffer != NULL) {\r
+ Start = MultU64x32 (Block - 1, Instance->BlkSize);\r
+\r
+ if (Start + DataLen <= Token->BufferSize) {\r
+ NetCopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);\r
+\r
+ //\r
+ // Update the file size when received the last block\r
+ //\r
+ if (Instance->LastBlock == Block) {\r
+ Token->BufferSize = Start + DataLen;\r
+ }\r
+\r
+ } else if (Instance->LastBlock != 0) {\r
+ //\r
+ // Don't save the data if the buffer is too small, return\r
+ // EFI_BUFFER_TOO_SMALL if received the last packet. This\r
+ // will give a accurate file length.\r
+ //\r
+ Token->BufferSize = Start + DataLen;\r
+\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_DISK_FULL,\r
+ "User provided memory block is too small"\r
+ );\r
+\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Function to process the received data packets. It will save the block\r
+ then send back an ACK if it is active.\r
+\r
+ @param Instance The downloading MTFTP session\r
+ @param Packet The packet received\r
+ @param Len The length of the packet\r
+ @param Multicast Whether this packet is multicast or unicast\r
+ @param Completed Return whether the download has completed\r
+\r
+ @retval EFI_SUCCESS The data packet is successfully processed\r
+ @retval EFI_ABORTED The download is aborted by the user\r
+ @retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4RrqHandleData (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN EFI_MTFTP4_PACKET *Packet,\r
+ IN UINT32 Len,\r
+ IN BOOLEAN Multicast,\r
+ OUT BOOLEAN *Completed\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 BlockNum;\r
+ INTN Expected;\r
+\r
+ *Completed = FALSE;\r
+ BlockNum = NTOHS (Packet->Data.Block);\r
+ Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
+\r
+ ASSERT (Expected >= 0);\r
+\r
+ //\r
+ // If we are active and received an unexpected packet, retransmit\r
+ // the last ACK then restart receiving. If we are passive, save\r
+ // the block.\r
+ //\r
+ if (Instance->Master && (Expected != BlockNum)) {\r
+ Mtftp4Retransmit (Instance);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = Mtftp4RrqSaveBlock (Instance, Packet, Len);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Reset the passive client's timer whenever it received a\r
+ // valid data packet.\r
+ //\r
+ if (!Instance->Master) {\r
+ Mtftp4SetTimeout (Instance);\r
+ }\r
+\r
+ //\r
+ // Check whether we have received all the blocks. Send the ACK if we\r
+ // are active (unicast client or master client for multicast download).\r
+ // If we have received all the blocks, send an ACK even if we are passive\r
+ // to tell the server that we are done.\r
+ //\r
+ Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
+\r
+ if (Instance->Master || (Expected < 0)) {\r
+ if (Expected < 0) {\r
+ //\r
+ // If we are passive client, then the just received Block maybe\r
+ // isn't the last block. We need to send an ACK to the last block\r
+ // to inform the server that we are done. If we are active client,\r
+ // the Block == Instance->LastBlock.\r
+ //\r
+ BlockNum = Instance->LastBlock;\r
+ *Completed = TRUE;\r
+\r
+ } else {\r
+ BlockNum = (UINT16) (Expected - 1);\r
+ }\r
+\r
+ Mtftp4RrqSendAck (Instance, BlockNum);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Validate whether the options received in the server's OACK packet is valid.\r
+ The options are valid only if:\r
+ 1. The server doesn't include options not requested by us\r
+ 2. The server can only use smaller blksize than that is requested\r
+ 3. The server can only use the same timeout as requested\r
+ 4. The server doesn't change its multicast channel.\r
+\r
+ @param This The downloading Mtftp session\r
+ @param Reply The options in the OACK packet\r
+ @param Request The requested options\r
+\r
+ @return TRUE if the options in the OACK is OK, otherwise FALSE.\r
+\r
+**/\r
+BOOLEAN\r
+Mtftp4RrqOackValid (\r
+ IN MTFTP4_PROTOCOL *This,\r
+ IN MTFTP4_OPTION *Reply,\r
+ IN MTFTP4_OPTION *Request\r
+ )\r
+{\r
+\r
+ //\r
+ // It is invalid for server to return options we don't request\r
+ //\r
+ if ((Reply->Exist &~Request->Exist) != 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Server can only specify a smaller block size to be used and\r
+ // return the timeout matches that requested.\r
+ //\r
+ if (((Reply->Exist & MTFTP4_BLKSIZE_EXIST) && (Reply->BlkSize > Request->BlkSize)) ||\r
+ ((Reply->Exist & MTFTP4_TIMEOUT_EXIST) && (Reply->Timeout != Request->Timeout))) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // The server can send ",,master" to client to change its master\r
+ // setting. But if it use the specific multicast channel, it can't\r
+ // change the setting.\r
+ //\r
+ if ((Reply->Exist & MTFTP4_MCAST_EXIST) && (This->McastIp != 0)) {\r
+ if ((Reply->McastIp != 0) && (Reply->McastIp != This->McastIp)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if ((Reply->McastPort != 0) && (Reply->McastPort != This->McastPort)) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Configure a UDP IO port to receive the multicast.\r
+\r
+ @param McastIo The UDP IO port to configure\r
+ @param Context The opaque parameter to the function which is the\r
+ MTFTP session.\r
+\r
+ @retval EFI_SUCCESS The udp child is successfully configured.\r
+ @retval Others Failed to configure the UDP child.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Mtftp4RrqConfigMcastPort (\r
+ IN UDP_IO_PORT *McastIo,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ MTFTP4_PROTOCOL *Instance;\r
+ EFI_MTFTP4_CONFIG_DATA *Config;\r
+ EFI_UDP4_CONFIG_DATA UdpConfig;\r
+ EFI_IPv4_ADDRESS Group;\r
+ EFI_STATUS Status;\r
+ IP4_ADDR Ip;\r
+\r
+ Instance = (MTFTP4_PROTOCOL *) Context;\r
+ Config = &Instance->Config;\r
+\r
+ UdpConfig.AcceptBroadcast = FALSE;\r
+ UdpConfig.AcceptPromiscuous = FALSE;\r
+ UdpConfig.AcceptAnyPort = FALSE;\r
+ UdpConfig.AllowDuplicatePort = FALSE;\r
+ UdpConfig.TypeOfService = 0;\r
+ UdpConfig.TimeToLive = 64;\r
+ UdpConfig.DoNotFragment = FALSE;\r
+ UdpConfig.ReceiveTimeout = 0;\r
+ UdpConfig.TransmitTimeout = 0;\r
+ UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;\r
+ UdpConfig.StationAddress = Config->StationIp;\r
+ UdpConfig.SubnetMask = Config->SubnetMask;\r
+ UdpConfig.StationPort = Instance->McastPort;\r
+ UdpConfig.RemotePort = 0;\r
+\r
+ Ip = HTONL (Instance->ServerIp);\r
+ NetCopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ Status = McastIo->Udp->Configure (McastIo->Udp, &UdpConfig);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // join the multicast group\r
+ //\r
+ Ip = HTONL (Instance->McastIp);\r
+ NetCopyMem (&Group, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ return McastIo->Udp->Groups (McastIo->Udp, TRUE, &Group);\r
+}\r
+\r
+\r
+/**\r
+ Function to process the OACK. It will first validate the OACK\r
+ packet, then update the various negotiated parameters.\r
+\r
+ @param Instance The download MTFTP session\r
+ @param Packet The packet received\r
+ @param Len The packet length\r
+ @param Multicast Whether this packet is received as a multicast\r
+ @param Completed Returns whether the download has completed. NOT\r
+ used by this function.\r
+\r
+ @retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child\r
+ @retval EFI_TFTP_ERROR Some error happened during the process\r
+ @retval EFI_SUCCESS The OACK is successfully processed.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4RrqHandleOack (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN EFI_MTFTP4_PACKET *Packet,\r
+ IN UINT32 Len,\r
+ IN BOOLEAN Multicast,\r
+ OUT BOOLEAN *Completed\r
+ )\r
+{\r
+ MTFTP4_OPTION Reply;\r
+ EFI_STATUS Status;\r
+ INTN Expected;\r
+\r
+ *Completed = FALSE;\r
+\r
+ //\r
+ // If already started the master download, don't change the\r
+ // setting. Master download always succeeds.\r
+ //\r
+ Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
+ ASSERT (Expected != -1);\r
+\r
+ if (Instance->Master && (Expected != 1)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Parse and validate the options from server\r
+ //\r
+ NetZeroMem (&Reply, sizeof (MTFTP4_OPTION));\r
+\r
+ Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);\r
+\r
+ if (EFI_ERROR (Status) ||\r
+ !Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) {\r
+ //\r
+ // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.\r
+ //\r
+ if (Status != EFI_OUT_OF_RESOURCES) {\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
+ "Mal-formated OACK packet"\r
+ );\r
+ }\r
+\r
+ return EFI_TFTP_ERROR;\r
+ }\r
+\r
+ if (Reply.Exist & MTFTP4_MCAST_EXIST) {\r
+\r
+ //\r
+ // Save the multicast info. Always update the Master, only update the\r
+ // multicast IP address, block size, timeoute at the first time. If IP\r
+ // address is updated, create a UDP child to receive the multicast.\r
+ //\r
+ Instance->Master = Reply.Master;\r
+\r
+ if (Instance->McastIp == 0) {\r
+ if ((Reply.McastIp == 0) || (Reply.McastPort == 0)) {\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
+ "Illegal multicast setting"\r
+ );\r
+\r
+ return EFI_TFTP_ERROR;\r
+ }\r
+\r
+ //\r
+ // Create a UDP child then start receive the multicast from it.\r
+ //\r
+ Instance->McastIp = Reply.McastIp;\r
+ Instance->McastPort = Reply.McastPort;\r
+ Instance->McastUdpPort = UdpIoCreatePort (\r
+ Instance->Service->Controller,\r
+ Instance->Service->Image,\r
+ Mtftp4RrqConfigMcastPort,\r
+ Instance\r
+ );\r
+\r
+ if (Instance->McastUdpPort == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION,\r
+ "Failed to create socket to receive multicast packet"\r
+ );\r
+\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Update the parameters used.\r
+ //\r
+ if (Reply.BlkSize != 0) {\r
+ Instance->BlkSize = Reply.BlkSize;\r
+ }\r
+\r
+ if (Reply.Timeout != 0) {\r
+ Instance->Timeout = Reply.Timeout;\r
+ }\r
+ }\r
+\r
+ } else {\r
+ Instance->Master = TRUE;\r
+\r
+ if (Reply.BlkSize != 0) {\r
+ Instance->BlkSize = Reply.BlkSize;\r
+ }\r
+\r
+ if (Reply.Timeout != 0) {\r
+ Instance->Timeout = Reply.Timeout;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Send an ACK to (Expected - 1) which is 0 for unicast download,\r
+ // or tell the server we want to receive the Expected block.\r
+ //\r
+ return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));\r
+}\r
+\r
+\r
+/**\r
+ The packet process callback for MTFTP download.\r
+\r
+ @param UdpPacket The packet received\r
+ @param Points The local/remote access point of the packet\r
+ @param IoStatus The status of the receiving\r
+ @param Context Opaque parameter, which is the MTFTP session\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Mtftp4RrqInput (\r
+ IN NET_BUF *UdpPacket,\r
+ IN UDP_POINTS *Points,\r
+ IN EFI_STATUS IoStatus,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ MTFTP4_PROTOCOL *Instance;\r
+ EFI_MTFTP4_PACKET *Packet;\r
+ BOOLEAN Completed;\r
+ BOOLEAN Multicast;\r
+ EFI_STATUS Status;\r
+ UINT16 Opcode;\r
+ UINT32 Len;\r
+\r
+ Instance = (MTFTP4_PROTOCOL *) Context;\r
+ NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);\r
+\r
+ Status = EFI_SUCCESS;\r
+ Packet = NULL;\r
+ Completed = FALSE;\r
+ Multicast = FALSE;\r
+\r
+ if (EFI_ERROR (IoStatus)) {\r
+ Status = IoStatus;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ ASSERT (UdpPacket != NULL);\r
+\r
+ //\r
+ // Find the port this packet is from to restart receive correctly.\r
+ //\r
+ Multicast = (BOOLEAN) (Points->LocalAddr == Instance->McastIp);\r
+\r
+ if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Client send initial request to server's listening port. Server\r
+ // will select a UDP port to communicate with the client. The server\r
+ // is required to use the same port as RemotePort to multicast the\r
+ // data.\r
+ //\r
+ if (Points->RemotePort != Instance->ConnectedPort) {\r
+ if (Instance->ConnectedPort != 0) {\r
+ goto ON_EXIT;\r
+ } else {\r
+ Instance->ConnectedPort = Points->RemotePort;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Copy the MTFTP packet to a continuous buffer if it isn't already so.\r
+ //\r
+ Len = UdpPacket->TotalSize;\r
+\r
+ if (UdpPacket->BlockOpNum > 1) {\r
+ Packet = NetAllocatePool (Len);\r
+\r
+ if (Packet == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);\r
+\r
+ } else {\r
+ Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);\r
+ }\r
+\r
+ Opcode = NTOHS (Packet->OpCode);\r
+\r
+ //\r
+ // Call the user's CheckPacket if provided. Abort the transmission\r
+ // if CheckPacket returns an EFI_ERROR code.\r
+ //\r
+ if ((Instance->Token->CheckPacket != NULL) &&\r
+ ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {\r
+\r
+ Status = Instance->Token->CheckPacket (\r
+ &Instance->Mtftp4,\r
+ Instance->Token,\r
+ (UINT16) Len,\r
+ Packet\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Send an error message to the server to inform it\r
+ //\r
+ if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
+ "User aborted the transfer"\r
+ );\r
+ }\r
+\r
+ Status = EFI_ABORTED;\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+\r
+ switch (Opcode) {\r
+ case EFI_MTFTP4_OPCODE_DATA:\r
+ if ((Len > (UINT32) (MTFTP4_DATA_HEAD_LEN + Instance->BlkSize)) ||\r
+ (Len < (UINT32) MTFTP4_DATA_HEAD_LEN)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Mtftp4RrqHandleData (Instance, Packet, Len, Multicast, &Completed);\r
+ break;\r
+\r
+ case EFI_MTFTP4_OPCODE_OACK:\r
+ if (Multicast || (Len <= MTFTP4_OPCODE_LEN)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Mtftp4RrqHandleOack (Instance, Packet, Len, Multicast, &Completed);\r
+ break;\r
+\r
+ case EFI_MTFTP4_OPCODE_ERROR:\r
+ Status = EFI_TFTP_ERROR;\r
+ break;\r
+ }\r
+\r
+ON_EXIT:\r
+\r
+ //\r
+ // Free the resources, then if !EFI_ERROR (Status), restart the\r
+ // receive, otherwise end the session.\r
+ //\r
+ if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {\r
+ NetFreePool (Packet);\r
+ }\r
+\r
+ if (UdpPacket != NULL) {\r
+ NetbufFree (UdpPacket);\r
+ }\r
+\r
+ if (!EFI_ERROR (Status) && !Completed) {\r
+ if (Multicast) {\r
+ Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);\r
+ } else {\r
+ Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status) || Completed) {\r
+ Mtftp4CleanOperation (Instance, Status);\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Mtftp4Support.c\r
+\r
+Abstract:\r
+\r
+ Support routines for Mtftp\r
+\r
+\r
+**/\r
+\r
+#include "Mtftp4Impl.h"\r
+\r
+\r
+/**\r
+ Allocate a MTFTP4 block range, then init it to the\r
+ range of [Start, End]\r
+\r
+ @param Start The start block number\r
+ @param End The last block number in the range\r
+\r
+ @return NULL if failed to allocate memory, otherwise the created block range.\r
+\r
+**/\r
+STATIC\r
+MTFTP4_BLOCK_RANGE *\r
+Mtftp4AllocateRange (\r
+ IN UINT16 Start,\r
+ IN UINT16 End\r
+ )\r
+{\r
+ MTFTP4_BLOCK_RANGE *Range;\r
+\r
+ Range = NetAllocatePool (sizeof (MTFTP4_BLOCK_RANGE));\r
+\r
+ if (Range == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetListInit (&Range->Link);\r
+ Range->Start = Start;\r
+ Range->End = End;\r
+\r
+ return Range;\r
+}\r
+\r
+\r
+/**\r
+ Initialize the block range for either RRQ or WRQ. RRQ and WRQ have\r
+ different requirements for Start and End. For example, during start\r
+ up, WRQ initializes its whole valid block range to [0, 0xffff]. This\r
+ is bacause the server will send us a ACK0 to inform us to start the\r
+ upload. When the client received ACK0, it will remove 0 from the range,\r
+ get the next block number, which is 1, then upload the BLOCK1. For RRQ\r
+ without option negotiation, the server will directly send us the BLOCK1\r
+ in response to the client's RRQ. When received BLOCK1, the client will\r
+ remove it from the block range and send an ACK. It also works if there\r
+ is option negotiation.\r
+\r
+ @param Head The block range head to initialize\r
+ @param Start The Start block number.\r
+ @param End The last block number.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for initial block range\r
+ @retval EFI_SUCCESS The initial block range is created.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4InitBlockRange (\r
+ IN NET_LIST_ENTRY *Head,\r
+ IN UINT16 Start,\r
+ IN UINT16 End\r
+ )\r
+{\r
+ MTFTP4_BLOCK_RANGE *Range;\r
+\r
+ Range = Mtftp4AllocateRange (Start, End);\r
+\r
+ if (Range == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NetListInsertTail (Head, &Range->Link);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Get the first valid block number on the range list.\r
+\r
+ @param Head The block range head\r
+\r
+ @return -1: if the block range is empty. Otherwise the first valid block number.\r
+\r
+**/\r
+INTN\r
+Mtftp4GetNextBlockNum (\r
+ IN NET_LIST_ENTRY *Head\r
+ )\r
+{\r
+ MTFTP4_BLOCK_RANGE *Range;\r
+\r
+ if (NetListIsEmpty (Head)) {\r
+ return -1;\r
+ }\r
+\r
+ Range = NET_LIST_HEAD (Head, MTFTP4_BLOCK_RANGE, Link);\r
+ return Range->Start;\r
+}\r
+\r
+\r
+/**\r
+ Set the last block number of the block range list. It will\r
+ remove all the blocks after the Last. MTFTP initialize the\r
+ block range to the maximum possible range, such as [0, 0xffff]\r
+ for WRQ. When it gets the last block number, it will call\r
+ this function to set the last block number.\r
+\r
+ @param Head The block range list\r
+ @param Last The last block number\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Mtftp4SetLastBlockNum (\r
+ IN NET_LIST_ENTRY *Head,\r
+ IN UINT16 Last\r
+ )\r
+{\r
+ MTFTP4_BLOCK_RANGE *Range;\r
+\r
+ //\r
+ // Iterate from the tail to head to remove the block number\r
+ // after the last.\r
+ //\r
+ while (!NetListIsEmpty (Head)) {\r
+ Range = NET_LIST_TAIL (Head, MTFTP4_BLOCK_RANGE, Link);\r
+\r
+ if (Range->Start > Last) {\r
+ NetListRemoveEntry (&Range->Link);\r
+ NetFreePool (Range);\r
+ continue;\r
+ }\r
+\r
+ if (Range->End > Last) {\r
+ Range->End = Last;\r
+ }\r
+\r
+ return ;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Remove the block number from the block range list.\r
+\r
+ @param Head The block range list to remove from\r
+ @param Num The block number to remove\r
+\r
+ @retval EFI_NOT_FOUND The block number isn't in the block range list\r
+ @retval EFI_SUCCESS The block number has been removed from the list\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4RemoveBlockNum (\r
+ IN NET_LIST_ENTRY *Head,\r
+ IN UINT16 Num\r
+ )\r
+{\r
+ MTFTP4_BLOCK_RANGE *Range;\r
+ MTFTP4_BLOCK_RANGE *NewRange;\r
+ NET_LIST_ENTRY *Entry;\r
+\r
+ NET_LIST_FOR_EACH (Entry, Head) {\r
+\r
+ //\r
+ // Each block represents a hole [Start, End] in the file,\r
+ // skip to the first range with End >= Num\r
+ //\r
+ Range = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);\r
+\r
+ if (Range->End < Num) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // There are three different cases for Start\r
+ // 1. (Start > Num) && (End >= Num):\r
+ // because all the holes before this one has the condition of\r
+ // End < Num, so this block number has been removed.\r
+ //\r
+ // 2. (Start == Num) && (End >= Num):\r
+ // Need to increase the Start by one, and if End == Num, this\r
+ // hole has been removed completely, remove it.\r
+ //\r
+ // 3. (Start < Num) && (End >= Num):\r
+ // if End == Num, only need to decrease the End by one because\r
+ // we have (Start < Num) && (Num == End), so (Start <= End - 1).\r
+ // if (End > Num), the hold is splited into two holes, with\r
+ // [Start, Num - 1] and [Num + 1, End].\r
+ //\r
+ if (Range->Start > Num) {\r
+ return EFI_NOT_FOUND;\r
+\r
+ } else if (Range->Start == Num) {\r
+ Range->Start++;\r
+\r
+ if (Range->Start > Range->End) {\r
+ NetListRemoveEntry (&Range->Link);\r
+ NetFreePool (Range);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ } else {\r
+ if (Range->End == Num) {\r
+ Range->End--;\r
+ } else {\r
+ NewRange = Mtftp4AllocateRange (Num + 1, (UINT16) Range->End);\r
+\r
+ if (NewRange == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Range->End = Num - 1;\r
+ NetListInsertAfter (&Range->Link, &NewRange->Link);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Build then transmit the request packet for the MTFTP session.\r
+\r
+ @param Instance The Mtftp session\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the request\r
+ @retval EFI_SUCCESS The request is built and sent\r
+ @retval Others Failed to transmit the packet.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4SendRequest (\r
+ IN MTFTP4_PROTOCOL *Instance\r
+ )\r
+{\r
+ EFI_MTFTP4_PACKET *Packet;\r
+ EFI_MTFTP4_OPTION *Options;\r
+ EFI_MTFTP4_TOKEN *Token;\r
+ NET_BUF *Nbuf;\r
+ UINT8 *Mode;\r
+ UINT8 *Cur;\r
+ UINT32 Len;\r
+ UINTN Index;\r
+\r
+ Token = Instance->Token;\r
+ Options = Token->OptionList;\r
+ Mode = Instance->Token->ModeStr;\r
+\r
+ if (Mode == NULL) {\r
+ Mode = "octet";\r
+ }\r
+\r
+ //\r
+ // Compute the packet length\r
+ //\r
+ Len = (UINT32) (AsciiStrLen (Token->Filename) + AsciiStrLen (Mode) + 4);\r
+\r
+ for (Index = 0; Index < Token->OptionCount; Index++) {\r
+ Len += (UINT32) (AsciiStrLen (Options[Index].OptionStr) +\r
+ AsciiStrLen (Options[Index].ValueStr) + 2);\r
+ }\r
+\r
+ //\r
+ // Allocate a packet then copy the data over\r
+ //\r
+ if ((Nbuf = NetbufAlloc (Len)) == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);\r
+ Packet->OpCode = HTONS (Instance->Operation);\r
+ Cur = Packet->Rrq.Filename;\r
+ Cur = AsciiStrCpy (Cur, Token->Filename);\r
+ Cur = AsciiStrCpy (Cur, Mode);\r
+\r
+ for (Index = 0; Index < Token->OptionCount; ++Index) {\r
+ Cur = AsciiStrCpy (Cur, Options[Index].OptionStr);\r
+ Cur = AsciiStrCpy (Cur, Options[Index].ValueStr);\r
+ }\r
+\r
+ return Mtftp4SendPacket (Instance, Nbuf);\r
+}\r
+\r
+\r
+/**\r
+ Build then send an error message\r
+\r
+ @param Instance The MTFTP session\r
+ @param ErrInfo The error code and message\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet\r
+ @retval EFI_SUCCESS The error packet is transmitted.\r
+ @retval Others Failed to transmit the packet.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4SendError (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN UINT16 ErrCode,\r
+ IN UINT8* ErrInfo\r
+ )\r
+{\r
+ NET_BUF *Packet;\r
+ EFI_MTFTP4_PACKET *TftpError;\r
+ UINT32 Len;\r
+\r
+ Len = (UINT32) (AsciiStrLen (ErrInfo) + sizeof (EFI_MTFTP4_ERROR_HEADER));\r
+ Packet = NetbufAlloc (Len);\r
+\r
+ if (Packet == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ TftpError = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Packet, Len, FALSE);\r
+ TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);\r
+ TftpError->Error.ErrorCode = HTONS (ErrCode);\r
+\r
+ AsciiStrCpy (TftpError->Error.ErrorMessage, ErrInfo);\r
+\r
+ return Mtftp4SendPacket (Instance, Packet);\r
+}\r
+\r
+\r
+/**\r
+ The callback function called when the packet is transmitted.\r
+ It simply frees the packet.\r
+\r
+ @param Packet The transmitted (or failed to) packet\r
+ @param Points The local and remote UDP access point\r
+ @param IoStatus The result of the transmission\r
+ @param Context Opaque parameter to the callback\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Mtftp4OnPacketSent (\r
+ NET_BUF *Packet,\r
+ UDP_POINTS *Points,\r
+ EFI_STATUS IoStatus,\r
+ VOID *Context\r
+ )\r
+{\r
+ NetbufFree (Packet);\r
+}\r
+\r
+\r
+/**\r
+ Set the timeout for the instance. User a longer time for\r
+ passive instances.\r
+\r
+ @param Instance The Mtftp session to set time out\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Mtftp4SetTimeout (\r
+ IN MTFTP4_PROTOCOL *Instance\r
+ )\r
+{\r
+ if (Instance->Master) {\r
+ Instance->PacketToLive = Instance->Timeout;\r
+ } else {\r
+ Instance->PacketToLive = Instance->Timeout * 2;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Send the packet for the instance. It will first save a reference to\r
+ the packet for later retransmission. then determine the destination\r
+ port, listen port for requests, and connected port for others. At last,\r
+ send the packet out.\r
+\r
+ @param Instance The Mtftp instance\r
+ @param Packet The packet to send\r
+\r
+ @retval EFI_SUCCESS The packet is sent out\r
+ @retval Others Failed to transmit the packet.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4SendPacket (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN NET_BUF *Packet\r
+ )\r
+{\r
+ UDP_POINTS UdpPoint;\r
+ EFI_STATUS Status;\r
+ UINT16 OpCode;\r
+\r
+ //\r
+ // Save the packet for retransmission\r
+ //\r
+ if (Instance->LastPacket != NULL) {\r
+ NetbufFree (Instance->LastPacket);\r
+ }\r
+\r
+ Instance->LastPacket = Packet;\r
+\r
+ Instance->CurRetry = 0;\r
+ Mtftp4SetTimeout (Instance);\r
+\r
+ UdpPoint.LocalAddr = 0;\r
+ UdpPoint.LocalPort = 0;\r
+ UdpPoint.RemoteAddr = Instance->ServerIp;\r
+\r
+ //\r
+ // Send the requests to the listening port, other packets\r
+ // to the connected port\r
+ //\r
+ OpCode = NTOHS (*((UINT16 *) NetbufGetByte (Packet, 0, NULL)));\r
+\r
+ if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
+ (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
+ UdpPoint.RemotePort = Instance->ListeningPort;\r
+ } else {\r
+ UdpPoint.RemotePort = Instance->ConnectedPort;\r
+ }\r
+\r
+ NET_GET_REF (Packet);\r
+\r
+ Status = UdpIoSendDatagram (\r
+ Instance->UnicastPort,\r
+ Packet,\r
+ &UdpPoint,\r
+ Instance->Gateway,\r
+ Mtftp4OnPacketSent,\r
+ Instance\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NET_PUT_REF (Packet);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Retransmit the last packet for the instance\r
+\r
+ @param Instance The Mtftp instance\r
+\r
+ @retval EFI_SUCCESS The last packet is retransmitted.\r
+ @retval Others Failed to retransmit.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4Retransmit (\r
+ IN MTFTP4_PROTOCOL *Instance\r
+ )\r
+{\r
+ UDP_POINTS UdpPoint;\r
+ EFI_STATUS Status;\r
+ UINT16 OpCode;\r
+\r
+ ASSERT (Instance->LastPacket != NULL);\r
+\r
+ UdpPoint.LocalAddr = 0;\r
+ UdpPoint.LocalPort = 0;\r
+ UdpPoint.RemoteAddr = Instance->ServerIp;\r
+\r
+ //\r
+ // Set the requests to the listening port, other packets to the connected port\r
+ //\r
+ OpCode = NTOHS (*(UINT16 *) NetbufGetByte (Instance->LastPacket, 0, NULL));\r
+\r
+ if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||\r
+ (OpCode == EFI_MTFTP4_OPCODE_WRQ)) {\r
+ UdpPoint.RemotePort = Instance->ListeningPort;\r
+ } else {\r
+ UdpPoint.RemotePort = Instance->ConnectedPort;\r
+ }\r
+\r
+ NET_GET_REF (Instance->LastPacket);\r
+\r
+ Status = UdpIoSendDatagram (\r
+ Instance->UnicastPort,\r
+ Instance->LastPacket,\r
+ &UdpPoint,\r
+ Instance->Gateway,\r
+ Mtftp4OnPacketSent,\r
+ Instance\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ NET_PUT_REF (Instance->LastPacket);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ The timer ticking function for the Mtftp service instance.\r
+\r
+ @param Event The ticking event\r
+ @param Context The Mtftp service instance\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Mtftp4OnTimerTick (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ MTFTP4_SERVICE *MtftpSb;\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ MTFTP4_PROTOCOL *Instance;\r
+ EFI_MTFTP4_TOKEN *Token;\r
+\r
+ MtftpSb = (MTFTP4_SERVICE *) Context;\r
+\r
+ //\r
+ // Iterate through all the children of the Mtftp service instance. Time\r
+ // out the packet. If maximum retries reached, clean the session up.\r
+ //\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {\r
+ Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);\r
+\r
+ if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Call the user's time out handler\r
+ //\r
+ Token = Instance->Token;\r
+\r
+ if ((Token->TimeoutCallback != NULL) &&\r
+ EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token))) {\r
+\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
+ "User aborted the transfer in time out"\r
+ );\r
+\r
+ Mtftp4CleanOperation (Instance, EFI_ABORTED);\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Retransmit the packet if haven't reach the maxmium retry count,\r
+ // otherwise exit the transfer.\r
+ //\r
+ if (++Instance->CurRetry < Instance->MaxRetry) {\r
+ Mtftp4Retransmit (Instance);\r
+ Mtftp4SetTimeout (Instance);\r
+ } else {\r
+ Mtftp4CleanOperation (Instance, EFI_TIMEOUT);\r
+ continue;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Mtftp4Support.h
+
+Abstract:
+
+ Support routines for MTFTP
+
+
+**/
+
+#ifndef __EFI_MTFTP4_SUPPORT_H__
+#define __EFI_MTFTP4_SUPPORT_H__
+
+//
+// The structure representing a range of block numbers, [Start, End].
+// It is used to remember the holes in the MTFTP block space. If all
+// the holes are filled in, then the download or upload has completed.
+//
+typedef struct {
+ NET_LIST_ENTRY Link;
+ INTN Start;
+ INTN End;
+} MTFTP4_BLOCK_RANGE;
+
+
+EFI_STATUS
+Mtftp4InitBlockRange (
+ IN NET_LIST_ENTRY *Head,
+ IN UINT16 Start,
+ IN UINT16 End
+ );
+
+INTN
+Mtftp4GetNextBlockNum (
+ IN NET_LIST_ENTRY *Head
+ );
+
+VOID
+Mtftp4SetLastBlockNum (
+ IN NET_LIST_ENTRY *Head,
+ IN UINT16 Last
+ );
+
+EFI_STATUS
+Mtftp4RemoveBlockNum (
+ IN NET_LIST_ENTRY *Head,
+ IN UINT16 Num
+ );
+
+VOID
+Mtftp4SetTimeout (
+ IN MTFTP4_PROTOCOL *Instance
+ );
+
+EFI_STATUS
+Mtftp4SendPacket (
+ IN MTFTP4_PROTOCOL *Instance,
+ IN NET_BUF *Packet
+ );
+
+EFI_STATUS
+Mtftp4SendRequest (
+ IN MTFTP4_PROTOCOL *Instance
+ );
+
+EFI_STATUS
+Mtftp4SendError (
+ IN MTFTP4_PROTOCOL *Instance,
+ IN UINT16 ErrCode,
+ IN UINT8* ErrInfo
+ );
+
+EFI_STATUS
+Mtftp4Retransmit (
+ IN MTFTP4_PROTOCOL *Instance
+ );
+
+VOID
+EFIAPI
+Mtftp4OnTimerTick (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Mtftp4Wrq.c\r
+\r
+Abstract:\r
+\r
+ Routines to process Wrq (upload)\r
+\r
+\r
+**/\r
+\r
+#include "Mtftp4Impl.h"\r
+\r
+VOID\r
+Mtftp4WrqInput (\r
+ IN NET_BUF *UdpPacket,\r
+ IN UDP_POINTS *Points,\r
+ IN EFI_STATUS IoStatus,\r
+ IN VOID *Context\r
+ );\r
+\r
+\r
+/**\r
+ Start the MTFTP session for pload. It will first init some states,\r
+ then send the WRQ request packet, and start receiving the packet.\r
+\r
+ @param Instance The MTFTP session\r
+ @param Operation Redundant parameter, which is always\r
+ EFI_MTFTP4_OPCODE_WRQ here.\r
+\r
+ @retval EFI_SUCCESS The upload process has been started.\r
+ @retval Others Failed to start the upload.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4WrqStart (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN UINT16 Operation\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // The valid block number range are [0, 0xffff]. For example:\r
+ // the client sends an WRQ request to the server, the server\r
+ // ACK with an ACK0 to let client start transfer the first\r
+ // packet.\r
+ //\r
+ Status = Mtftp4InitBlockRange (&Instance->Blocks, 0, 0xffff);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = Mtftp4SendRequest (Instance);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);\r
+}\r
+\r
+\r
+/**\r
+ Build then send a MTFTP data packet for the MTFTP upload session.\r
+\r
+ @param Instance The MTFTP upload session\r
+ @param BlockNum The block number to send\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to build the packet\r
+ @retval EFI_ABORTED The consumer of this child directs to abort the\r
+ transmission by return an error through\r
+ PacketNeeded\r
+ @retval EFI_SUCCESS The data is sent.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4WrqSendBlock (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN UINT16 BlockNum\r
+ )\r
+{\r
+ EFI_MTFTP4_PACKET *Packet;\r
+ EFI_MTFTP4_TOKEN *Token;\r
+ NET_BUF *UdpPacket;\r
+ EFI_STATUS Status;\r
+ UINT16 DataLen;\r
+ UINT8 *DataBuf;\r
+ UINT64 Start;\r
+\r
+ //\r
+ // Allocate a buffer to hold the user data\r
+ //\r
+ UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP4_DATA_HEAD_LEN);\r
+\r
+ if (UdpPacket == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Packet = (EFI_MTFTP4_PACKET *)NetbufAllocSpace (UdpPacket, MTFTP4_DATA_HEAD_LEN, FALSE);\r
+\r
+ Packet->Data.OpCode = HTONS (EFI_MTFTP4_OPCODE_DATA);\r
+ Packet->Data.Block = HTONS (BlockNum);\r
+\r
+ //\r
+ // Read the block from either the buffer or PacketNeeded callback\r
+ //\r
+ Token = Instance->Token;\r
+ DataLen = Instance->BlkSize;\r
+\r
+ if (Token->Buffer != NULL) {\r
+ Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);\r
+\r
+ if (Token->BufferSize < Start + Instance->BlkSize) {\r
+ DataLen = (UINT16) (Token->BufferSize - Start);\r
+ Instance->LastBlock = BlockNum;\r
+ Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);\r
+ }\r
+\r
+ if (DataLen > 0) {\r
+ NetbufAllocSpace (UdpPacket, DataLen, FALSE);\r
+ NetCopyMem (Packet->Data.Data, (UINT8 *) Token->Buffer + Start, DataLen);\r
+ }\r
+\r
+ } else {\r
+ //\r
+ // Get data from PacketNeeded\r
+ //\r
+ DataBuf = NULL;\r
+ Status = Token->PacketNeeded (&Instance->Mtftp4, Token, &DataLen, &DataBuf);\r
+\r
+ if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {\r
+ if (DataBuf != NULL) {\r
+ gBS->FreePool (DataBuf);\r
+ }\r
+\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
+ "User aborted the transfer"\r
+ );\r
+\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ if (DataLen < Instance->BlkSize) {\r
+ Instance->LastBlock = BlockNum;\r
+ Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);\r
+ }\r
+\r
+ if (DataLen > 0) {\r
+ NetbufAllocSpace (UdpPacket, DataLen, FALSE);\r
+ NetCopyMem (Packet->Data.Data, DataBuf, DataLen);\r
+ gBS->FreePool (DataBuf);\r
+ }\r
+ }\r
+\r
+ return Mtftp4SendPacket (Instance, UdpPacket);\r
+}\r
+\r
+\r
+/**\r
+ Function to handle received ACK packet. If the ACK number matches the\r
+ expected block number, and there are more data pending, send the next\r
+ block. Otherwise tell the caller that we are done.\r
+\r
+ @param Instance The MTFTP upload session\r
+ @param Packet The MTFTP packet received\r
+ @param Len The packet length\r
+ @param Completed Return whether the upload has finished.\r
+\r
+ @retval EFI_SUCCESS The ACK is successfully processed.\r
+ @retval EFI_TFTP_ERROR The block number loops back.\r
+ @retval Others Failed to transmit the next data packet.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4WrqHandleAck (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN EFI_MTFTP4_PACKET *Packet,\r
+ IN UINT32 Len,\r
+ OUT BOOLEAN *Completed\r
+ )\r
+{\r
+ UINT16 AckNum;\r
+ INTN Expected;\r
+\r
+ *Completed = FALSE;\r
+ AckNum = NTOHS (Packet->Ack.Block[0]);\r
+ Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
+\r
+ ASSERT (Expected >= 0);\r
+\r
+ //\r
+ // Get an unwanted ACK, return EFI_SUCCESS to let Mtftp4WrqInput\r
+ // restart receive.\r
+ //\r
+ if (Expected != AckNum) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Remove the acked block number, if this is the last block number,\r
+ // tell the Mtftp4WrqInput to finish the transfer. This is the last\r
+ // block number if the block range are empty..\r
+ //\r
+ Mtftp4RemoveBlockNum (&Instance->Blocks, AckNum);\r
+\r
+ Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
+\r
+ if (Expected < 0) {\r
+ //\r
+ // The block range is empty. It may either because the the last\r
+ // block has been ACKed, or the sequence number just looped back,\r
+ // that is, there is more than 0xffff blocks.\r
+ //\r
+ if (Instance->LastBlock == AckNum) {\r
+ ASSERT (Instance->LastBlock >= 1);\r
+ *Completed = TRUE;\r
+ return EFI_SUCCESS;\r
+\r
+ } else {\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
+ "Block number rolls back, not supported, try blksize option"\r
+ );\r
+\r
+ return EFI_TFTP_ERROR;\r
+ }\r
+ }\r
+\r
+ return Mtftp4WrqSendBlock (Instance, (UINT16) Expected);\r
+}\r
+\r
+\r
+/**\r
+ Check whether the received OACK is valid. The OACK is valid\r
+ only if:\r
+ 1. It only include options requested by us\r
+ 2. It can only include a smaller block size\r
+ 3. It can't change the proposed time out value.\r
+ 4. Other requirements of the individal MTFTP options as required.s\r
+\r
+ @param Reply The options included in the OACK\r
+ @param Request The options we requested\r
+\r
+ @return TRUE if the options included in OACK is valid, otherwise FALSE.\r
+\r
+**/\r
+BOOLEAN\r
+Mtftp4WrqOackValid (\r
+ IN MTFTP4_OPTION *Reply,\r
+ IN MTFTP4_OPTION *Request\r
+ )\r
+{\r
+ //\r
+ // It is invalid for server to return options we don't request\r
+ //\r
+ if ((Reply->Exist &~Request->Exist) != 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Server can only specify a smaller block size to be used and\r
+ // return the timeout matches that requested.\r
+ //\r
+ if (((Reply->Exist & MTFTP4_BLKSIZE_EXIST) && (Reply->BlkSize > Request->BlkSize)) ||\r
+ ((Reply->Exist & MTFTP4_TIMEOUT_EXIST) && (Reply->Timeout != Request->Timeout))) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Function to handle the MTFTP OACK packet. It parses the packet's\r
+ options, and update the internal states of the session\r
+\r
+ @param Instance The MTFTP session\r
+ @param Packet The received OACK packet\r
+ @param Len The length of the packet\r
+ @param Completed Whether the transmisson has completed. NOT used by\r
+ this function.\r
+\r
+ @retval EFI_SUCCESS The OACK process is OK\r
+ @retval EFI_TFTP_ERROR Some error occured, and the session reset.\r
+\r
+**/\r
+EFI_STATUS\r
+Mtftp4WrqHandleOack (\r
+ IN MTFTP4_PROTOCOL *Instance,\r
+ IN EFI_MTFTP4_PACKET *Packet,\r
+ IN UINT32 Len,\r
+ OUT BOOLEAN *Completed\r
+ )\r
+{\r
+ MTFTP4_OPTION Reply;\r
+ EFI_MTFTP4_PACKET Bogus;\r
+ EFI_STATUS Status;\r
+ INTN Expected;\r
+\r
+ *Completed = FALSE;\r
+\r
+ //\r
+ // Ignore the OACK if already started the upload\r
+ //\r
+ Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);\r
+\r
+ if (Expected != 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Parse and validate the options from server\r
+ //\r
+ NetZeroMem (&Reply, sizeof (MTFTP4_OPTION));\r
+ Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);\r
+\r
+ if (EFI_ERROR (Status) || !Mtftp4WrqOackValid (&Reply, &Instance->RequestOption)) {\r
+ //\r
+ // Don't send a MTFTP error packet when out of resource, it can\r
+ // only make it worse.\r
+ //\r
+ if (Status != EFI_OUT_OF_RESOURCES) {\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,\r
+ "Mal-formated OACK packet"\r
+ );\r
+ }\r
+\r
+ return EFI_TFTP_ERROR;\r
+ }\r
+\r
+ if (Reply.BlkSize != 0) {\r
+ Instance->BlkSize = Reply.BlkSize;\r
+ }\r
+\r
+ if (Reply.Timeout != 0) {\r
+ Instance->Timeout = Reply.Timeout;\r
+ }\r
+\r
+ //\r
+ // Build a bogus ACK0 packet then pass it to the Mtftp4WrqHandleAck,\r
+ // which will start the transmission of the first data block.\r
+ //\r
+ Bogus.Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);\r
+ Bogus.Ack.Block[0] = 0;\r
+\r
+ return Mtftp4WrqHandleAck (Instance, &Bogus, sizeof (EFI_MTFTP4_ACK_HEADER), Completed);\r
+}\r
+\r
+\r
+/**\r
+ The input process routine for MTFTP upload.\r
+\r
+ @param UdpPacket The received MTFTP packet.\r
+ @param Points The local/remote access point\r
+ @param IoStatus The result of the packet receiving\r
+ @param Context Opaque parameter for the callback, which is the\r
+ MTFTP session.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Mtftp4WrqInput (\r
+ IN NET_BUF *UdpPacket,\r
+ IN UDP_POINTS *Points,\r
+ IN EFI_STATUS IoStatus,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ MTFTP4_PROTOCOL *Instance;\r
+ EFI_MTFTP4_PACKET *Packet;\r
+ BOOLEAN Completed;\r
+ EFI_STATUS Status;\r
+ UINT32 Len;\r
+ UINT16 Opcode;\r
+\r
+ Instance = (MTFTP4_PROTOCOL *) Context;\r
+ NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);\r
+\r
+ Completed = FALSE;\r
+ Packet = NULL;\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (EFI_ERROR (IoStatus)) {\r
+ Status = IoStatus;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ ASSERT (UdpPacket != NULL);\r
+\r
+ if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Client send initial request to server's listening port. Server\r
+ // will select a UDP port to communicate with the client.\r
+ //\r
+ if (Points->RemotePort != Instance->ConnectedPort) {\r
+ if (Instance->ConnectedPort != 0) {\r
+ goto ON_EXIT;\r
+ } else {\r
+ Instance->ConnectedPort = Points->RemotePort;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Copy the MTFTP packet to a continuous buffer if it isn't already so.\r
+ //\r
+ Len = UdpPacket->TotalSize;\r
+\r
+ if (UdpPacket->BlockOpNum > 1) {\r
+ Packet = NetAllocatePool (Len);\r
+\r
+ if (Packet == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);\r
+\r
+ } else {\r
+ Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);\r
+ }\r
+\r
+ Opcode = NTOHS (Packet->OpCode);\r
+\r
+ //\r
+ // Call the user's CheckPacket if provided. Abort the transmission\r
+ // if CheckPacket returns an EFI_ERROR code.\r
+ //\r
+ if ((Instance->Token->CheckPacket != NULL) &&\r
+ ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {\r
+\r
+ Status = Instance->Token->CheckPacket (\r
+ &Instance->Mtftp4,\r
+ Instance->Token,\r
+ (UINT16) Len,\r
+ Packet\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Send an error message to the server to inform it\r
+ //\r
+ if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {\r
+ Mtftp4SendError (\r
+ Instance,\r
+ EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,\r
+ "User aborted the transfer"\r
+ );\r
+ }\r
+\r
+ Status = EFI_ABORTED;\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+\r
+ switch (Opcode) {\r
+ case EFI_MTFTP4_OPCODE_ACK:\r
+ if (Len != MTFTP4_OPCODE_LEN + MTFTP4_BLKNO_LEN) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Mtftp4WrqHandleAck (Instance, Packet, Len, &Completed);\r
+ break;\r
+\r
+ case EFI_MTFTP4_OPCODE_OACK:\r
+ if (Len <= MTFTP4_OPCODE_LEN) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Mtftp4WrqHandleOack (Instance, Packet, Len, &Completed);\r
+ break;\r
+\r
+ case EFI_MTFTP4_OPCODE_ERROR:\r
+ Status = EFI_TFTP_ERROR;\r
+ break;\r
+ }\r
+\r
+ON_EXIT:\r
+ //\r
+ // Free the resources, then if !EFI_ERROR (Status) and not completed,\r
+ // restart the receive, otherwise end the session.\r
+ //\r
+ if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {\r
+ NetFreePool (Packet);\r
+ }\r
+\r
+ if (UdpPacket != NULL) {\r
+ NetbufFree (UdpPacket);\r
+ }\r
+\r
+ if (!EFI_ERROR (Status) && !Completed) {\r
+ Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);\r
+ }\r
+\r
+ //\r
+ // Status may have been updated by UdpIoRecvDatagram\r
+ //\r
+ if (EFI_ERROR (Status) || Completed) {\r
+ Mtftp4CleanOperation (Instance, Status);\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ bc.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Bc.h"\r
+\r
+//\r
+//\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcDriverSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcDriverStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcDriverStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+extern\r
+VOID\r
+InitArpHeader (\r
+ VOID\r
+ );\r
+extern\r
+VOID\r
+OptionsStrucInit (\r
+ VOID\r
+ );\r
+\r
+//\r
+// helper routines\r
+//\r
+\r
+/**\r
+ Convert number to ASCII value\r
+\r
+ @param Number Numeric value to convert to decimal ASCII value.\r
+ @param Buffer Buffer to place ASCII version of the Number\r
+ @param Length Length of Buffer.\r
+\r
+ @retval none none\r
+\r
+**/\r
+VOID\r
+CvtNum (\r
+ IN UINTN Number,\r
+ IN UINT8 *Buffer,\r
+ IN INTN Length\r
+ )\r
+{\r
+ UINTN Remainder;\r
+\r
+ while (Length--) {\r
+ Remainder = Number % 10;\r
+ Number /= 10;\r
+ Buffer[Length] = (UINT8) ('0' + Remainder);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Convert number to decimal ASCII value at Buffer location\r
+\r
+ @param Number Numeric value to convert to decimal ASCII value.\r
+ @param Buffer Buffer to place ASCII version of the Number\r
+\r
+ @retval none none\r
+\r
+**/\r
+VOID\r
+UtoA10 (\r
+ IN UINTN Number,\r
+ IN UINT8 *Buffer\r
+ )\r
+{\r
+ INTN Index;\r
+ UINT8 BuffArray[31];\r
+\r
+ BuffArray[30] = 0;\r
+ CvtNum (Number, BuffArray, 30);\r
+\r
+ for (Index = 0; Index < 30; ++Index) {\r
+ if (BuffArray[Index] != '0') {\r
+ break;\r
+ }\r
+ }\r
+\r
+ CopyMem (Buffer, BuffArray + Index, 31 - Index);\r
+}\r
+\r
+\r
+/**\r
+ Convert ASCII numeric string to a UINTN value\r
+\r
+ @param Number Numeric value to convert to decimal ASCII value.\r
+ @param Buffer Buffer to place ASCII version of the Number\r
+\r
+ @retval Value UINTN value of the ASCII string.\r
+\r
+**/\r
+UINTN\r
+AtoU (\r
+ IN UINT8 *Buffer\r
+ )\r
+{\r
+ UINTN Value;\r
+ INT8 Character;\r
+\r
+ Value = 0;\r
+ Character = *Buffer++;\r
+ do {\r
+ Value = Value * 10 + Character - '0';\r
+ Character = *Buffer++;\r
+ } while (Character);\r
+\r
+ return Value;\r
+}\r
+\r
+\r
+/**\r
+ Convert ASCII numeric string to a UINTN value\r
+\r
+ @param Number Numeric value to convert to decimal ASCII value.\r
+ @param Buffer Buffer to place ASCII version of the Number\r
+\r
+ @retval Value UINTN value of the ASCII string.\r
+\r
+**/\r
+UINT64\r
+AtoU64 (\r
+ IN UINT8 *Buffer\r
+ )\r
+{\r
+ UINT64 Value;\r
+ UINT8 Character;\r
+\r
+ Value = 0;\r
+ while ((Character = *Buffer++) != '\0') {\r
+ Value = MultU64x32 (Value, 10) + (Character - '0');\r
+ }\r
+\r
+ return Value;\r
+}\r
+//\r
+// random number generator\r
+//\r
+#define RANDOM_MULTIPLIER 2053\r
+#define RANDOM_ADD_IN_VALUE 19\r
+\r
+VOID\r
+SeedRandom (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN UINT16 InitialSeed\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Initialize the Seed for the random number generator\r
+\r
+ Arguments:\r
+\r
+ Returns:\r
+ none -\r
+\r
+--*/\r
+{\r
+ if (Private != NULL) {\r
+ Private->RandomSeed = InitialSeed;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Generate and return a pseudo-random number\r
+\r
+\r
+ @retval Number UINT16 random number\r
+\r
+**/\r
+UINT16\r
+Random (\r
+ IN PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ UINTN Number;\r
+\r
+ if (Private != NULL) {\r
+ Number = -(INTN) Private->RandomSeed * RANDOM_MULTIPLIER + RANDOM_ADD_IN_VALUE;\r
+\r
+ return Private->RandomSeed = (UINT16) Number;\r
+ } else {\r
+ return 0;\r
+ }\r
+}\r
+//\r
+// calculate the internet checksum (RFC 1071)\r
+// return 16 bit ones complement of ones complement sum of 16 bit words\r
+//\r
+\r
+/**\r
+ Calculate the internet checksum (see RFC 1071)\r
+\r
+ @param Packet Buffer which contains the data to be checksummed\r
+ @param Length Length to be checksummed\r
+\r
+ @retval Checksum Returns the 16 bit ones complement of ones\r
+ complement sum of 16 bit words\r
+\r
+**/\r
+UINT16\r
+IpChecksum (\r
+ IN UINT16 *Packet,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ UINT32 Sum;\r
+ UINT8 Odd;\r
+\r
+ Sum = 0;\r
+ Odd = (UINT8) (Length & 1);\r
+ Length >>= 1;\r
+ while (Length--) {\r
+ Sum += *Packet++;\r
+ }\r
+\r
+ if (Odd) {\r
+ Sum += *(UINT8 *) Packet;\r
+ }\r
+\r
+ Sum = (Sum & 0xffff) + (Sum >> 16);\r
+ //\r
+ // in case above carried\r
+ //\r
+ Sum += Sum >> 16;\r
+\r
+ return (UINT16) (~ (UINT16) Sum);\r
+}\r
+\r
+\r
+/**\r
+ Calculate the internet checksum (see RFC 1071)\r
+ on a non contiguous header and data\r
+\r
+ @param Header Buffer which contains the data to be checksummed\r
+ @param HeaderLen Length to be checksummed\r
+ @param Message Buffer which contains the data to be checksummed\r
+ @param MessageLen Length to be checksummed\r
+\r
+ @retval Checksum Returns the 16 bit ones complement of ones\r
+ complement sum of 16 bit words\r
+\r
+**/\r
+UINT16\r
+IpChecksum2 (\r
+ IN UINT16 *Header,\r
+ IN UINTN HeaderLen,\r
+ IN UINT16 *Message,\r
+ IN UINTN MessageLen\r
+ )\r
+{\r
+ UINT32 Sum;\r
+\r
+ Sum = (UINT16)~IpChecksum (Header, HeaderLen) + (UINT16)~IpChecksum (Message, MessageLen);\r
+\r
+ //\r
+ // in case above carried\r
+ //\r
+ Sum += Sum >> 16;\r
+\r
+ return (UINT16) (~ (UINT16) Sum);\r
+}\r
+\r
+\r
+/**\r
+ Adjust the internet checksum (see RFC 1071) on a single word update.\r
+\r
+ @param OldChkSum Checksum previously calculated\r
+ @param OldWord Value\r
+ @param NewWord New Value\r
+\r
+ @retval Checksum Returns the 16 bit ones complement of ones\r
+ complement sum of 16 bit words\r
+\r
+**/\r
+UINT16\r
+UpdateChecksum (\r
+ IN UINT16 OldChksum,\r
+ IN UINT16 OldWord,\r
+ IN UINT16 NewWord\r
+ )\r
+{\r
+ UINT32 sum;\r
+\r
+ sum = ~OldChksum + NewWord - OldWord;\r
+ //\r
+ // in case above carried\r
+ //\r
+ sum += sum >> 16;\r
+ return (UINT16) (~ (UINT16) sum);\r
+}\r
+\r
+\r
+/**\r
+ See if a callback is in play\r
+\r
+ @param Private Pointer to Pxe BaseCode Protocol\r
+\r
+ @retval 0 Callbacks are active on the handle\r
+ @retval 1 Callbacks are not active on the handle\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+SetMakeCallback (\r
+ IN PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ Private->EfiBc.Mode->MakeCallbacks = (BOOLEAN) (gBS->HandleProtocol (\r
+ Private->Handle,\r
+ &gEfiPxeBaseCodeCallbackProtocolGuid,\r
+ (VOID *) &Private->CallbackProtocolPtr\r
+ ) == EFI_SUCCESS);\r
+\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nMode->MakeCallbacks == %d ",\r
+ Private->EfiBc.Mode->MakeCallbacks)\r
+ );\r
+\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nPrivate->CallbackProtocolPtr == %xh ",\r
+ Private->CallbackProtocolPtr)\r
+ );\r
+\r
+ if (Private->CallbackProtocolPtr != NULL) {\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nCallbackProtocolPtr->Revision = %xh ",\r
+ Private->CallbackProtocolPtr->Revision)\r
+ );\r
+\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nCallbackProtocolPtr->Callback = %xh ",\r
+ Private->CallbackProtocolPtr->Callback)\r
+ );\r
+ }\r
+\r
+ return Private->EfiBc.Mode->MakeCallbacks;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+ Routine which does an SNP->Receive over a timeout period and doing callbacks\r
+\r
+ @param Private Pointer to Pxe BaseCode Protocol\r
+ @param Function What PXE function to callback\r
+ @param TimeoutEvent Timer event that will trigger when we have waited\r
+ too long for an incoming packet\r
+ @param HeaderSizePtr Pointer to the size of the Header size\r
+ @param BufferSizePtr Pointer to the size of the Buffer size\r
+ @param ProtocolPtr The protocol to sniff for (namely, UDP/TCP/etc)\r
+\r
+ @retval 0 Something was returned\r
+ @retval !0 Like there was nothing to receive\r
+ (EFI_TIMEOUT/NOT_READY)\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForReceive (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN EFI_PXE_BASE_CODE_FUNCTION Function,\r
+ IN EFI_EVENT TimeoutEvent,\r
+ IN OUT UINTN *HeaderSizePtr,\r
+ IN OUT UINTN *BufferSizePtr,\r
+ IN OUT UINT16 *ProtocolPtr\r
+ )\r
+{\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;\r
+ EFI_PXE_CALLBACK CallbackPtr;\r
+ EFI_STATUS StatCode;\r
+ EFI_EVENT CallbackEvent;\r
+\r
+ //\r
+ // Initialize pointer to SNP interface\r
+ //\r
+ SnpPtr = Private->SimpleNetwork;\r
+\r
+ //\r
+ // Initialize pointer to PxeBc callback routine - if any\r
+ //\r
+ CallbackPtr = (Private->EfiBc.Mode->MakeCallbacks) ? Private->CallbackProtocolPtr->Callback : NULL;\r
+\r
+ //\r
+ // Create callback event and set timer\r
+ //\r
+ StatCode = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &CallbackEvent\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // every 100 milliseconds\r
+ //\r
+ StatCode = gBS->SetTimer (\r
+ CallbackEvent,\r
+ TimerPeriodic,\r
+ 1000000\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ gBS->CloseEvent (CallbackEvent);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Loop until a packet is received or a receive error is detected or\r
+ // a callback abort is detected or a timeout event occurs.\r
+ //\r
+ for (;;)\r
+ {\r
+ //\r
+ // Poll for received packet.\r
+ //\r
+ *BufferSizePtr = BUFFER_ALLOCATE_SIZE;\r
+\r
+ StatCode = SnpPtr->Receive (\r
+ SnpPtr,\r
+ HeaderSizePtr,\r
+ BufferSizePtr,\r
+ Private->ReceiveBufferPtr,\r
+ 0,\r
+ 0,\r
+ ProtocolPtr\r
+ );\r
+\r
+ if (!EFI_ERROR (StatCode)) {\r
+ //\r
+ // Packet was received. Make received callback then return.\r
+ //\r
+ if (CallbackPtr != NULL) {\r
+ StatCode = CallbackPtr (\r
+ Private->CallbackProtocolPtr,\r
+ Function,\r
+ TRUE,\r
+ (UINT32) *BufferSizePtr,\r
+ (EFI_PXE_BASE_CODE_PACKET *) Private->ReceiveBufferPtr\r
+ );\r
+\r
+ if (StatCode != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {\r
+ StatCode = EFI_ABORTED;\r
+ } else {\r
+ StatCode = EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ if (StatCode != EFI_NOT_READY) {\r
+ break;\r
+ }\r
+ //\r
+ // Check for callback event.\r
+ //\r
+ if (!EFI_ERROR (gBS->CheckEvent (CallbackEvent))) {\r
+ //\r
+ // Make periodic callback if callback pointer is initialized.\r
+ //\r
+ if (CallbackPtr != NULL) {\r
+ StatCode = CallbackPtr (\r
+ Private->CallbackProtocolPtr,\r
+ Function,\r
+ FALSE,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ //\r
+ // Abort if directed to by callback routine.\r
+ //\r
+ if (StatCode != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {\r
+ StatCode = EFI_ABORTED;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Check for timeout event.\r
+ //\r
+ if (TimeoutEvent == 0) {\r
+ StatCode = EFI_TIMEOUT;\r
+ break;\r
+ }\r
+\r
+ if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
+ StatCode = EFI_TIMEOUT;\r
+ break;\r
+ }\r
+ //\r
+ // Check IGMP timer events.\r
+ //\r
+ IgmpCheckTimers (Private);\r
+ }\r
+\r
+ gBS->CloseEvent (CallbackEvent);\r
+\r
+ return StatCode;\r
+}\r
+\r
+\r
+/**\r
+ Routine which does an SNP->Transmit of a buffer\r
+\r
+ @param Private Pointer to Pxe BaseCode Protocol\r
+ @param HeaderPtr Pointer to the buffer\r
+ @param PacketPtr Pointer to the packet to send\r
+ @param PacketLen The length of the entire packet to send\r
+ @param HardwareAddr Pointer to the MAC address of the destination\r
+ @param MediaProtocol What type of frame to create (RFC 1700) - IE.\r
+ Ethernet\r
+ @param Function What PXE function to callback\r
+\r
+ @retval 0 Something was sent\r
+ @retval !0 An error was encountered during sending of a packet\r
+\r
+**/\r
+EFI_STATUS\r
+SendPacket (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ VOID *HeaderPtr,\r
+ VOID *PacketPtr,\r
+ INTN PacketLen,\r
+ VOID *HardwareAddr,\r
+ UINT16 MediaProtocol,\r
+ IN EFI_PXE_BASE_CODE_FUNCTION Function\r
+ )\r
+{\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpModePtr;\r
+ EFI_PXE_CALLBACK CallbackPtr;\r
+ EFI_STATUS StatCode;\r
+ EFI_EVENT TimeoutEvent;\r
+ UINT32 IntStatus;\r
+ VOID *TxBuf;\r
+\r
+ //\r
+ //\r
+ //\r
+ CallbackPtr = Private->EfiBc.Mode->MakeCallbacks ? Private->CallbackProtocolPtr->Callback : 0;\r
+\r
+ SnpPtr = Private->SimpleNetwork;\r
+ SnpModePtr = SnpPtr->Mode;\r
+\r
+ //\r
+ // clear prior interrupt status\r
+ //\r
+ StatCode = SnpPtr->GetStatus (SnpPtr, &IntStatus, 0);\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nSendPacket() Exit #1 %xh (%r)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+ return StatCode;\r
+ }\r
+\r
+ Private->DidTransmit = FALSE;\r
+\r
+ if (CallbackPtr != NULL) {\r
+ if (CallbackPtr (\r
+ Private->CallbackProtocolPtr,\r
+ Function,\r
+ FALSE,\r
+ (UINT32) PacketLen,\r
+ PacketPtr\r
+ ) != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nSendPacket() Exit #2 %xh (%r)",\r
+ EFI_ABORTED,\r
+ EFI_ABORTED)\r
+ );\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+ //\r
+ // put packet in transmit queue\r
+ // headersize should be zero if not filled in\r
+ //\r
+ StatCode = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG (\r
+ (DEBUG_ERROR,\r
+ "Could not create transmit timeout event. %r\n",\r
+ StatCode)\r
+ );\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // 5 milliseconds\r
+ //\r
+ StatCode = gBS->SetTimer (\r
+ TimeoutEvent,\r
+ TimerRelative,\r
+ 50000\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG (\r
+ (DEBUG_ERROR,\r
+ "Could not set transmit timeout event timer. %r\n",\r
+ StatCode)\r
+ );\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ for (;;) {\r
+ StatCode = SnpPtr->Transmit (\r
+ SnpPtr,\r
+ (UINTN) SnpPtr->Mode->MediaHeaderSize,\r
+ (UINTN) (PacketLen + SnpPtr->Mode->MediaHeaderSize),\r
+ HeaderPtr,\r
+ &SnpModePtr->CurrentAddress,\r
+ (EFI_MAC_ADDRESS *) HardwareAddr,\r
+ &MediaProtocol\r
+ );\r
+\r
+ if (StatCode != EFI_NOT_READY) {\r
+ break;\r
+ }\r
+\r
+ if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
+ StatCode = EFI_TIMEOUT;\r
+ break;\r
+ }\r
+ }\r
+\r
+ gBS->CloseEvent (TimeoutEvent);\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nSendPacket() Exit #3 %xh (%r)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+ return StatCode;\r
+ }\r
+ //\r
+ // remove transmit buffer from snp's unused queue\r
+ // done this way in case someday things are buffered and we don't get it back\r
+ // immediately\r
+ //\r
+ StatCode = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG (\r
+ (DEBUG_ERROR,\r
+ "Could not create transmit status timeout event. %r\n",\r
+ StatCode)\r
+ );\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // 5 milliseconds\r
+ //\r
+ StatCode = gBS->SetTimer (\r
+ TimeoutEvent,\r
+ TimerRelative,\r
+ 50000\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG (\r
+ (DEBUG_ERROR,\r
+ "Could not set transmit status timeout event timer. %r\n",\r
+ StatCode)\r
+ );\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ for (;;) {\r
+ StatCode = SnpPtr->GetStatus (SnpPtr, &IntStatus, &TxBuf);\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nSendPacket() Exit #4 %xh (%r)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+ break;\r
+ }\r
+\r
+ if (IntStatus & EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT) {\r
+ Private->DidTransmit = TRUE;\r
+ }\r
+\r
+ if (TxBuf != NULL) {\r
+ break;\r
+ }\r
+\r
+ if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
+ StatCode = EFI_TIMEOUT;\r
+ break;\r
+ }\r
+ }\r
+\r
+ gBS->CloseEvent (TimeoutEvent);\r
+\r
+ return StatCode;\r
+}\r
+//\r
+//\r
+//\r
+\r
+/**\r
+\r
+\r
+**/\r
+EFI_BIS_PROTOCOL *\r
+PxebcBisStart (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ OUT BIS_APPLICATION_HANDLE *BisAppHandle,\r
+ OUT OPTIONAL EFI_BIS_DATA **BisDataSigInfo\r
+ )\r
+{\r
+ EFI_STATUS EfiStatus;\r
+ EFI_HANDLE BisHandleBuffer;\r
+ UINTN BisHandleCount;\r
+ EFI_BIS_PROTOCOL *BisPtr;\r
+ EFI_BIS_VERSION BisInterfaceVersion;\r
+ BOOLEAN BisCheckFlag;\r
+\r
+ BisHandleCount = sizeof (EFI_HANDLE);\r
+ BisCheckFlag = FALSE;\r
+\r
+ //\r
+ // Locate BIS protocol handle (if present).\r
+ // If BIS protocol handle is not found, return NULL.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "\ngBS->LocateHandle() "));\r
+\r
+ EfiStatus = gBS->LocateHandle (\r
+ ByProtocol,\r
+ &gEfiBisProtocolGuid,\r
+ NULL,\r
+ &BisHandleCount,\r
+ &BisHandleBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ //\r
+ // Any error means that there is no BIS.\r
+ // Note - It could mean that there are more than\r
+ // one BIS protocols installed, but that scenario\r
+ // is not yet supported.\r
+ //\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxebcBisStart()""\n gBS->LocateHandle() %r (%xh)\n",\r
+ EfiStatus,\r
+ EfiStatus)\r
+ );\r
+\r
+ return NULL;\r
+ }\r
+\r
+ if (BisHandleCount != sizeof BisHandleBuffer) {\r
+ //\r
+ // This really should never happen, but I am paranoid.\r
+ //\r
+ DEBUG (\r
+ (DEBUG_NET,\r
+ "\nPxebcBisStart() BisHandleCount != %d\n",\r
+ sizeof BisHandleBuffer)\r
+ );\r
+\r
+ return NULL;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "BIS handle found."));\r
+\r
+ //\r
+ // Locate BIS protocol interface.\r
+ // If the BIS protocol interface cannot be found, return NULL.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "\ngBS->HandleProtocol() "));\r
+\r
+ EfiStatus = gBS->HandleProtocol (\r
+ BisHandleBuffer,\r
+ &gEfiBisProtocolGuid,\r
+ (VOID **) &BisPtr\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxebcBisStart()""\n gBS->HandleProtocol() %r (%xh)\n",\r
+ EfiStatus,\r
+ EfiStatus)\r
+ );\r
+\r
+ return NULL;\r
+ }\r
+\r
+ if (BisPtr == NULL) {\r
+ //\r
+ // This really should never happen.\r
+ //\r
+ DEBUG (\r
+ (DEBUG_NET,\r
+ "\nPxebcBisStart()""\n gBS->HandleProtocoL() ""BIS protocol interface pointer is NULL!\n")\r
+ );\r
+\r
+ return NULL;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "BIS protocol interface found."));\r
+\r
+ //\r
+ // Check that all of the BIS API function pointers are not NULL.\r
+ //\r
+ if (BisPtr->Initialize == NULL ||\r
+ BisPtr->Shutdown == NULL ||\r
+ BisPtr->Free == NULL ||\r
+ BisPtr->GetBootObjectAuthorizationCertificate == NULL ||\r
+ BisPtr->GetBootObjectAuthorizationCheckFlag == NULL ||\r
+ BisPtr->GetBootObjectAuthorizationUpdateToken == NULL ||\r
+ BisPtr->GetSignatureInfo == NULL ||\r
+ BisPtr->UpdateBootObjectAuthorization == NULL ||\r
+ BisPtr->VerifyBootObject == NULL ||\r
+ BisPtr->VerifyObjectWithCredential == NULL\r
+ ) {\r
+ DEBUG (\r
+ (\r
+ DEBUG_NET,\r
+ "\nPxebcBisStart()""\n BIS protocol interface is invalid."\r
+ "\n At least one BIS protocol function pointer is NULL.\n"\r
+ )\r
+ );\r
+\r
+ return NULL;\r
+ }\r
+ //\r
+ // Initialize BIS.\r
+ // If BIS does not initialize, return NULL.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "\nBisPtr->Initialize() "));\r
+\r
+ BisInterfaceVersion.Major = BIS_VERSION_1;\r
+\r
+ EfiStatus = BisPtr->Initialize (\r
+ BisPtr,\r
+ BisAppHandle,\r
+ &BisInterfaceVersion,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxebcBisStart()""\n BisPtr->Initialize() %r (%xh)\n",\r
+ EfiStatus,\r
+ EfiStatus)\r
+ );\r
+\r
+ return NULL;\r
+ }\r
+\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ " BIS version: %d.%d",\r
+ BisInterfaceVersion.Major,\r
+ BisInterfaceVersion.Minor)\r
+ );\r
+\r
+ //\r
+ // If the requested BIS API version is not supported,\r
+ // shutdown BIS and return NULL.\r
+ //\r
+ if (BisInterfaceVersion.Major != BIS_VERSION_1) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxebcBisStart()""\n BIS version %d.%d not supported by PXE BaseCode.\n",\r
+ BisInterfaceVersion.Major,\r
+ BisInterfaceVersion.Minor)\r
+ );\r
+\r
+ BisPtr->Shutdown (*BisAppHandle);\r
+ return NULL;\r
+ }\r
+ //\r
+ // Get BIS check flag.\r
+ // If the BIS check flag cannot be read, shutdown BIS and return NULL.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "\nBisPtr->GetBootObjectAuthorizationCheckFlag() "));\r
+\r
+ EfiStatus = BisPtr->GetBootObjectAuthorizationCheckFlag (*BisAppHandle, &BisCheckFlag);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxebcBisStart()""\n BisPtr->GetBootObjectAuthorizationCheckFlag() %r (%xh)\n",\r
+ EfiStatus,\r
+ EfiStatus)\r
+ );\r
+\r
+ BisPtr->Shutdown (*BisAppHandle);\r
+ return NULL;\r
+ }\r
+ //\r
+ // If the BIS check flag is FALSE, shutdown BIS and return NULL.\r
+ //\r
+ if (!BisCheckFlag) {\r
+ DEBUG ((DEBUG_INFO, "\nBIS check flag is FALSE.\n"));\r
+ BisPtr->Shutdown (*BisAppHandle);\r
+ return NULL;\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "\nBIS check flag is TRUE."));\r
+ }\r
+ //\r
+ // Early out if caller does not want signature information.\r
+ //\r
+ if (BisDataSigInfo == NULL) {\r
+ return BisPtr;\r
+ }\r
+ //\r
+ // Get BIS signature information.\r
+ // If the signature information cannot be read or is invalid,\r
+ // shutdown BIS and return NULL.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "\nBisPtr->GetSignatureInfo() "));\r
+\r
+ EfiStatus = BisPtr->GetSignatureInfo (*BisAppHandle, BisDataSigInfo);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxebcBisStart()""\n BisPtr_GetSignatureInfo() %r (%xh)\n",\r
+ EfiStatus,\r
+ EfiStatus)\r
+ );\r
+\r
+ BisPtr->Shutdown (*BisAppHandle);\r
+ return NULL;\r
+ }\r
+\r
+ if (*BisDataSigInfo == NULL) {\r
+ //\r
+ // This should never happen.\r
+ //\r
+ DEBUG (\r
+ (DEBUG_NET,\r
+ "\nPxebcBisStart()""\n BisPtr->GetSignatureInfo() Data pointer is NULL!\n")\r
+ );\r
+\r
+ BisPtr->Shutdown (*BisAppHandle);\r
+ return NULL;\r
+ }\r
+\r
+ if ((*BisDataSigInfo)->Length < sizeof (EFI_BIS_SIGNATURE_INFO) ||\r
+ (*BisDataSigInfo)->Length % sizeof (EFI_BIS_SIGNATURE_INFO) ||\r
+ (*BisDataSigInfo)->Length > sizeof (EFI_BIS_SIGNATURE_INFO) * 63\r
+ ) {\r
+ //\r
+ // This should never happen.\r
+ //\r
+ DEBUG (\r
+ (DEBUG_NET,\r
+ "\nPxebcBisStart()""\n BisPtr->GetSignatureInfo() Invalid BIS siginfo length.\n")\r
+ );\r
+\r
+ BisPtr->Free (*BisAppHandle, *BisDataSigInfo);\r
+ BisPtr->Shutdown (*BisAppHandle);\r
+ return NULL;\r
+ }\r
+\r
+ return BisPtr;\r
+}\r
+\r
+\r
+/**\r
+\r
+\r
+**/\r
+VOID\r
+PxebcBisStop (\r
+ EFI_BIS_PROTOCOL *BisPtr,\r
+ BIS_APPLICATION_HANDLE BisAppHandle,\r
+ EFI_BIS_DATA *BisDataSigInfo\r
+ )\r
+{\r
+ if (BisPtr == NULL) {\r
+ return ;\r
+ }\r
+ //\r
+ // Free BIS allocated resources and shutdown BIS.\r
+ // Return TRUE - BIS support is officially detected.\r
+ //\r
+ if (BisDataSigInfo != NULL) {\r
+ BisPtr->Free (BisAppHandle, BisDataSigInfo);\r
+ }\r
+\r
+ BisPtr->Shutdown (BisAppHandle);\r
+}\r
+\r
+\r
+/**\r
+\r
+ @return TRUE := verified\r
+ @return FALSE := not verified\r
+\r
+**/\r
+BOOLEAN\r
+PxebcBisVerify (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ VOID *FileBuffer,\r
+ UINTN FileLength,\r
+ VOID *CredentialBuffer,\r
+ UINTN CredentialLength\r
+ )\r
+{\r
+ EFI_BIS_PROTOCOL *BisPtr;\r
+ BIS_APPLICATION_HANDLE BisAppHandle;\r
+ EFI_BIS_DATA FileData;\r
+ EFI_BIS_DATA CredentialData;\r
+ EFI_STATUS EfiStatus;\r
+ BOOLEAN IsVerified;\r
+\r
+ if (Private == NULL || FileBuffer == NULL || FileLength == 0 || CredentialBuffer == NULL || CredentialLength == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ BisPtr = PxebcBisStart (Private, &BisAppHandle, NULL);\r
+\r
+ if (BisPtr == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ FileData.Length = (UINT32) FileLength;\r
+ FileData.Data = FileBuffer;\r
+ CredentialData.Length = (UINT32) CredentialLength;\r
+ CredentialData.Data = CredentialBuffer;\r
+\r
+ EfiStatus = BisPtr->VerifyBootObject (\r
+ BisAppHandle,\r
+ &CredentialData,\r
+ &FileData,\r
+ &IsVerified\r
+ );\r
+\r
+ PxebcBisStop (BisPtr, BisAppHandle, NULL);\r
+\r
+ return (BOOLEAN) ((EFI_ERROR (EfiStatus)) ? FALSE : (IsVerified ? TRUE : FALSE));\r
+}\r
+\r
+\r
+/**\r
+\r
+ @return TRUE := BIS present\r
+ @return FALSE := BIS not present\r
+\r
+**/\r
+BOOLEAN\r
+PxebcBisDetect (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ EFI_BIS_PROTOCOL *BisPtr;\r
+ BIS_APPLICATION_HANDLE BisAppHandle;\r
+ EFI_BIS_DATA *BisDataSigInfo;\r
+\r
+ BisPtr = PxebcBisStart (Private, &BisAppHandle, &BisDataSigInfo);\r
+\r
+ if (BisPtr == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo);\r
+\r
+ return TRUE;\r
+}\r
+\r
+static VOID *BCNotifyReg;\r
+\r
+\r
+/**\r
+ Start and initialize the BaseCode protocol, Simple Network protocol and UNDI.\r
+\r
+ @param Private Pointer to Pxe BaseCode Protocol\r
+ @param UseIPv6 Do we want to support IPv6?\r
+\r
+ @return EFI_SUCCESS\r
+ @return EFI_INVALID_PARAMETER\r
+ @return EFI_UNSUPPORTED\r
+ @return EFI_ALREADY_STARTED\r
+ @return EFI_OUT_OF_RESOURCES\r
+ @return Status is also returned from SNP.Start() and SNP.Initialize().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcStart (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
+ IN BOOLEAN UseIPv6\r
+ )\r
+{\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpModePtr;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+\r
+ //\r
+ // Lock the instance data\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ //\r
+ // Make sure BaseCode is not already started.\r
+ //\r
+ if (This->Mode->Started) {\r
+ DEBUG ((DEBUG_WARN, "\nBcStart() BC is already started.\n"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+#if !SUPPORT_IPV6\r
+ //\r
+ // Fail if IPv6 is requested and not supported.\r
+ //\r
+ if (UseIPv6) {\r
+ DEBUG ((DEBUG_WARN, "\nBcStart() IPv6 is not supported.\n"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+#endif\r
+ //\r
+ // Setup shortcuts to SNP protocol and data structure.\r
+ //\r
+ SnpPtr = Private->SimpleNetwork;\r
+ SnpModePtr = SnpPtr->Mode;\r
+\r
+ //\r
+ // Start and initialize SNP.\r
+ //\r
+ if (SnpModePtr->State == EfiSimpleNetworkStopped) {\r
+ StatCode = (*SnpPtr->Start) (SnpPtr);\r
+\r
+ if (SnpModePtr->State != EfiSimpleNetworkStarted) {\r
+ DEBUG ((DEBUG_WARN, "\nBcStart() Could not start SNP.\n"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+ }\r
+ }\r
+ //\r
+ // acquire memory for mode and transmit/receive buffers\r
+ //\r
+ if (SnpModePtr->State == EfiSimpleNetworkStarted) {\r
+ StatCode = (*SnpPtr->Initialize) (SnpPtr, 0, 0);\r
+\r
+ if (SnpModePtr->State != EfiSimpleNetworkInitialized) {\r
+ DEBUG ((DEBUG_WARN, "\nBcStart() Could not initialize SNP."));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+ }\r
+ }\r
+ //\r
+ // Dump debug info.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "\nBC Start()"));\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->State %Xh",\r
+ SnpModePtr->State)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->HwAddressSize %Xh",\r
+ SnpModePtr->HwAddressSize)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->MediaHeaderSize %Xh",\r
+ SnpModePtr->MediaHeaderSize)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->MaxPacketSize %Xh",\r
+ SnpModePtr->MaxPacketSize)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->MacAddressChangeable %Xh",\r
+ SnpModePtr->MacAddressChangeable)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->MultipleTxSupported %Xh",\r
+ SnpModePtr->MultipleTxSupported)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->CurrentAddress %Xh",\r
+ *((UINTN *)&SnpModePtr->CurrentAddress))\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->BroadcastAddress %Xh",\r
+ *((UINTN *)&SnpModePtr->BroadcastAddress))\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->PermanentAddress %Xh",\r
+ *((UINTN *)&SnpModePtr->PermanentAddress))\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->NvRamSize %Xh",\r
+ SnpModePtr->NvRamSize)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->NvRamAccessSize %Xh",\r
+ SnpModePtr->NvRamAccessSize)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->ReceiveFilterMask %Xh",\r
+ SnpModePtr->ReceiveFilterMask)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->ReceiveFilterSetting %Xh",\r
+ SnpModePtr->ReceiveFilterSetting)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->MCastFilterCount %Xh",\r
+ SnpModePtr->MCastFilterCount)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->MCastFilter %Xh",\r
+ SnpModePtr->MCastFilter)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->IfType %Xh",\r
+ SnpModePtr->IfType)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->MediaPresentSupported %Xh",\r
+ SnpModePtr->MediaPresentSupported)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nSnpModePtr->MediaPresent %Xh",\r
+ SnpModePtr->MediaPresent)\r
+ );\r
+\r
+ //\r
+ // If media check is supported and there is no media,\r
+ // return error to caller.\r
+ //\r
+ if (SnpModePtr->MediaPresentSupported && !SnpModePtr->MediaPresent) {\r
+ DEBUG ((DEBUG_WARN, "\nBcStart() Media not present.\n"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_NO_MEDIA;\r
+ }\r
+ //\r
+ // Allocate Tx/Rx buffers\r
+ //\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ BUFFER_ALLOCATE_SIZE,\r
+ &Private->TransmitBufferPtr\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ ZeroMem (Private->TransmitBufferPtr, BUFFER_ALLOCATE_SIZE);\r
+ } else {\r
+ DEBUG ((DEBUG_NET, "\nBcStart() Could not alloc TxBuf.\n"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ BUFFER_ALLOCATE_SIZE,\r
+ &Private->ReceiveBufferPtr\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ ZeroMem (Private->ReceiveBufferPtr, BUFFER_ALLOCATE_SIZE);\r
+ } else {\r
+ DEBUG ((DEBUG_NET, "\nBcStart() Could not alloc RxBuf.\n"));\r
+ gBS->FreePool (Private->TransmitBufferPtr);\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ 256,\r
+ &Private->TftpErrorBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (Private->ReceiveBufferPtr);\r
+ gBS->FreePool (Private->TransmitBufferPtr);\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = gBS->AllocatePool (EfiBootServicesData, 256, &Private->TftpAckBuffer);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (Private->TftpErrorBuffer);\r
+ gBS->FreePool (Private->ReceiveBufferPtr);\r
+ gBS->FreePool (Private->TransmitBufferPtr);\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Initialize private BaseCode instance data\r
+ //\r
+ do {\r
+ Private->RandomPort = (UINT16) (Private->RandomPort + PXE_RND_PORT_LOW + Random (Private));\r
+ } while (Private->RandomPort < PXE_RND_PORT_LOW);\r
+\r
+ Private->Igmpv1TimeoutEvent = NULL;\r
+ Private->UseIgmpv1Reporting = TRUE;\r
+ Private->IpLength = IP_ADDRESS_LENGTH (Private->EfiBc.Mode);\r
+\r
+ //\r
+ // Initialize Mode structure\r
+ //\r
+ ZeroMem (Private->EfiBc.Mode, sizeof (EFI_PXE_BASE_CODE_MODE));\r
+ //\r
+ // check for callback protocol and set boolean\r
+ //\r
+ SetMakeCallback (Private);\r
+ Private->EfiBc.Mode->Started = TRUE;\r
+ Private->EfiBc.Mode->TTL = DEFAULT_TTL;\r
+ Private->EfiBc.Mode->ToS = DEFAULT_ToS;\r
+ Private->EfiBc.Mode->UsingIpv6 = UseIPv6;\r
+\r
+ //\r
+ // Set to PXE_TRUE by the BC constructor if this BC implementation\r
+ // supports IPv6.\r
+ //\r
+ Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6;\r
+\r
+ Private->EfiBc.Mode->Ipv6Available = FALSE;\r
+ //\r
+ // Set to TRUE by the BC constructor if this BC implementation\r
+ // supports BIS.\r
+ //\r
+ Private->EfiBc.Mode->BisSupported = TRUE;\r
+ Private->EfiBc.Mode->BisDetected = PxebcBisDetect (Private);\r
+\r
+ //\r
+ // This field is set to PXE_TRUE by the BC Start() function. When this\r
+ // field is PXE_TRUE, ARP packets are sent as needed to get IP and MAC\r
+ // addresses. This can cause unexpected delays in the DHCP(), Discover()\r
+ // and MTFTP() functions. Setting this to PXE_FALSE will cause these\r
+ // functions to fail if the required IP/MAC information is not in the\r
+ // ARP cache. The value of this field can be changed by an application\r
+ // at any time.\r
+ //\r
+ Private->EfiBc.Mode->AutoArp = TRUE;\r
+\r
+ //\r
+ // Unlock the instance data\r
+ //\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Stop the BaseCode protocol, Simple Network protocol and UNDI.\r
+\r
+ @param Private Pointer to Pxe BaseCode Protocol\r
+\r
+ @retval 0 Successfully stopped\r
+ @retval !0 Failed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcStop (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This\r
+ )\r
+{\r
+ //\r
+ // Lock the instance data\r
+ //\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpModePtr;\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+ SnpPtr = Private->SimpleNetwork;\r
+ SnpModePtr = SnpPtr->Mode;\r
+\r
+ //\r
+ // Issue BC command\r
+ //\r
+ StatCode = EFI_NOT_STARTED;\r
+\r
+ if (SnpModePtr->State == EfiSimpleNetworkInitialized) {\r
+ StatCode = (*SnpPtr->Shutdown) (SnpPtr);\r
+ }\r
+\r
+ if (SnpModePtr->State == EfiSimpleNetworkStarted) {\r
+ StatCode = (*SnpPtr->Stop) (SnpPtr);\r
+ }\r
+\r
+ if (Private->TransmitBufferPtr != NULL) {\r
+ gBS->FreePool (Private->TransmitBufferPtr);\r
+ Private->TransmitBufferPtr = NULL;\r
+ }\r
+\r
+ if (Private->ReceiveBufferPtr != NULL) {\r
+ gBS->FreePool (Private->ReceiveBufferPtr);\r
+ Private->ReceiveBufferPtr = NULL;\r
+ }\r
+\r
+ if (Private->ArpBuffer != NULL) {\r
+ gBS->FreePool (Private->ArpBuffer);\r
+ Private->ArpBuffer = NULL;\r
+ }\r
+\r
+ if (Private->TftpErrorBuffer != NULL) {\r
+ gBS->FreePool (Private->TftpErrorBuffer);\r
+ Private->TftpErrorBuffer = NULL;\r
+ }\r
+\r
+ if (Private->TftpAckBuffer != NULL) {\r
+ gBS->FreePool (Private->TftpAckBuffer);\r
+ Private->TftpAckBuffer = NULL;\r
+ }\r
+\r
+ if (Private->Igmpv1TimeoutEvent != NULL) {\r
+ gBS->CloseEvent (Private->Igmpv1TimeoutEvent);\r
+ Private->Igmpv1TimeoutEvent = NULL;\r
+ }\r
+\r
+ Private->FileSize = 0;\r
+\r
+ if (!Private->EfiBc.Mode->Started) {\r
+ StatCode = EFI_NOT_STARTED;\r
+ } else {\r
+ Private->EfiBc.Mode->Started = FALSE;\r
+ }\r
+\r
+ //\r
+ // Unlock the instance data\r
+ //\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+}\r
+\r
+const IPV4_ADDR AllSystemsGroup = { 224, 0, 0, 1 };\r
+\r
+\r
+/**\r
+ Set up the IP filter\r
+\r
+ @param Private Pointer to Pxe BaseCode Protocol\r
+ @param Filter Pointer to the filter\r
+\r
+ @retval 0 Successfully set the filter\r
+ @retval !0 Failed\r
+\r
+**/\r
+EFI_STATUS\r
+IpFilter (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN EFI_PXE_BASE_CODE_IP_FILTER *Filter\r
+ )\r
+{\r
+ EFI_STATUS StatCode;\r
+ EFI_MAC_ADDRESS MACadds[PXE_IP_FILTER_SIZE];\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpModePtr;\r
+ UINT32 Enable;\r
+ UINT32 Disable;\r
+ UINTN Index;\r
+ UINTN Index2;\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+ SnpPtr = Private->SimpleNetwork;\r
+ SnpModePtr = SnpPtr->Mode;\r
+\r
+ //\r
+ // validate input parameters\r
+ // must have a filter\r
+ // must not have any extra filter bits set\r
+ //\r
+ if (Filter == NULL ||\r
+ (Filter->Filters &~FILTER_BITS)\r
+ //\r
+ // must not have a count which is too large or with no IP list\r
+ //\r
+ ||\r
+ (Filter->IpCnt && (!Filter->IpList || Filter->IpCnt > PXE_IP_FILTER_SIZE))\r
+ //\r
+ // must not have incompatible filters - promiscuous incompatible with anything else\r
+ //\r
+ ||\r
+ (\r
+ (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) &&\r
+ ((Filter->Filters &~EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) || Filter->IpCnt)\r
+ )\r
+ ) {\r
+ DEBUG ((DEBUG_INFO, "\nIpFilter() Exit #1"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // promiscuous multicast incompatible with multicast in IP list\r
+ //\r
+ if (Filter->IpCnt && (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST)) {\r
+ for (Index = 0; Index < Filter->IpCnt; ++Index) {\r
+ if (IS_MULTICAST (&Filter->IpList[Index])) {\r
+ DEBUG ((DEBUG_INFO, "\nIpFilter() Exit #2"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // leave groups for all those multicast which are no longer enabled\r
+ //\r
+ for (Index = 0; Index < PxebcMode->IpFilter.IpCnt; ++Index) {\r
+ if (!IS_MULTICAST (&PxebcMode->IpFilter.IpList[Index])) {\r
+ continue;\r
+ }\r
+\r
+ for (Index2 = 0; Index2 < Filter->IpCnt; ++Index2) {\r
+ if (!CompareMem (&PxebcMode->IpFilter.IpList[Index], &Filter->IpList[Index2], IP_ADDRESS_LENGTH (PxebcMode))) {\r
+ //\r
+ // still enabled\r
+ //\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // if we didn't find it, remove from group\r
+ //\r
+ if (Index2 == Filter->IpCnt) {\r
+ IgmpLeaveGroup (Private, &PxebcMode->IpFilter.IpList[Index]);\r
+ }\r
+ }\r
+ //\r
+ // set enable bits, convert multicast ip adds, join groups\r
+ // allways leave receive broadcast enabled at hardware layer\r
+ //\r
+ Index2 = 0;\r
+\r
+ if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {\r
+ Enable = EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
+ } else {\r
+ if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) {\r
+ Enable = EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
+ } else {\r
+ Enable = EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
+\r
+ for (Index = 0; Index < Filter->IpCnt; ++Index) {\r
+ PxebcMode->IpFilter.IpList[Index] = Filter->IpList[Index];\r
+\r
+ if (IS_MULTICAST (&Filter->IpList[Index])) {\r
+ EFI_IP_ADDRESS *TmpIp;\r
+\r
+ Enable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
+\r
+ //\r
+ // if this is the first group, add the all systems group to mcast list\r
+ //\r
+ if (!Index2)\r
+ {\r
+ TmpIp = (EFI_IP_ADDRESS *) &AllSystemsGroup;\r
+ --Index;\r
+ } else {\r
+ TmpIp = (EFI_IP_ADDRESS *) &Filter->IpList[Index];\r
+ }\r
+ //\r
+ // get MAC address of IP\r
+ //\r
+ StatCode = (*SnpPtr->MCastIpToMac) (SnpPtr, PxebcMode->UsingIpv6, TmpIp, &MACadds[Index2++]);\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nIpFilter() Exit #2 %Xh (%r)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+ return StatCode;\r
+ }\r
+ } else {\r
+ Enable |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Filter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) {\r
+ Enable |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
+ }\r
+ }\r
+ //\r
+ // if nothing changed, just return\r
+ //\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nsnp->ReceiveFilterSetting == %Xh Filter->IpCnt == %Xh",\r
+ SnpModePtr->ReceiveFilterSetting,\r
+ Filter->IpCnt)\r
+ );\r
+\r
+ if (SnpModePtr->ReceiveFilterSetting == Enable && !Filter->IpCnt) {\r
+ DEBUG ((DEBUG_INFO, "\nIpFilter() Exit #4"));\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // disable those currently set but not set in new filter\r
+ //\r
+ Disable = SnpModePtr->ReceiveFilterSetting &~Enable;\r
+\r
+ StatCode = SnpPtr->ReceiveFilters (SnpPtr, Enable, Disable, FALSE, Index2, MACadds);\r
+\r
+ PxebcMode->IpFilter.IpCnt = Filter->IpCnt;\r
+\r
+ //\r
+ // join groups for all multicast in list\r
+ //\r
+ for (Index = 0; Index < Filter->IpCnt; ++Index) {\r
+ if (IS_MULTICAST (&Filter->IpList[Index])) {\r
+ IgmpJoinGroup (Private, &Filter->IpList[Index]);\r
+ }\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "\nIpFilter() Exit #5 %Xh (%r)", StatCode, StatCode));\r
+\r
+ return StatCode;\r
+}\r
+\r
+\r
+/**\r
+ Call the IP filter\r
+\r
+ @param Private Pointer to Pxe BaseCode Protocol\r
+ @param Filter Pointer to the filter\r
+\r
+ @retval 0 Successfully set the filter\r
+ @retval !0 Failed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcIpFilter (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
+ IN EFI_PXE_BASE_CODE_IP_FILTER *Filter\r
+ )\r
+{\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+ UINTN Index;\r
+ //\r
+ // Lock the instance data and make sure started\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ for (Index = 0; Index < Filter->IpCnt; ++Index) {\r
+ if ((Filter->IpList[Index].Addr[0]) == BROADCAST_IPv4) {\r
+ //\r
+ // The IP is a broadcast address.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ if (This->Mode == NULL || !This->Mode->Started) {\r
+ DEBUG ((DEBUG_ERROR, "BC was not started."));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ if (Filter == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Issue BC command\r
+ //\r
+ StatCode = IpFilter (Private, Filter);\r
+\r
+ //\r
+ // Unlock the instance data\r
+ //\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+}\r
+\r
+\r
+/**\r
+ Set the Base Code behavior parameters\r
+\r
+ @param This Pointer to Pxe BaseCode Protocol\r
+ @param AutoArpPtr Boolean to do ARP stuff\r
+ @param SendGuidPtr Boolean whether or not to send GUID info\r
+ @param TimeToLivePtr Value for Total time to live\r
+ @param TypeOfServicePtr Value for Type of Service\r
+ @param MakeCallbackPtr Boolean to determine if we make callbacks\r
+\r
+ @retval 0 Successfully set the parameters\r
+ @retval !0 Failed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcSetParameters (\r
+ EFI_PXE_BASE_CODE_PROTOCOL *This,\r
+ BOOLEAN *AutoArpPtr,\r
+ BOOLEAN *SendGuidPtr,\r
+ UINT8 *TimeToLivePtr,\r
+ UINT8 *TypeOfServicePtr,\r
+ BOOLEAN *MakeCallbackPtr\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+ EFI_GUID TmpGuid;\r
+ UINT8 *SerialNumberPtr;\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+\r
+ //\r
+ // Lock the instance data and make sure started\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ if (This->Mode == NULL || !This->Mode->Started) {\r
+ DEBUG ((DEBUG_ERROR, "BC was not started."));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "\nSetParameters() Entry. "));\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (SendGuidPtr != NULL) {\r
+ if (*SendGuidPtr) {\r
+ if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (&TmpGuid, &SerialNumberPtr) != EFI_SUCCESS) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (MakeCallbackPtr != NULL) {\r
+ if (*MakeCallbackPtr) {\r
+ if (!SetMakeCallback (Private)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ PxebcMode->MakeCallbacks = *MakeCallbackPtr;\r
+ }\r
+\r
+ if (AutoArpPtr != NULL) {\r
+ PxebcMode->AutoArp = *AutoArpPtr;\r
+ }\r
+\r
+ if (SendGuidPtr != NULL) {\r
+ PxebcMode->SendGUID = *SendGuidPtr;\r
+ }\r
+\r
+ if (TimeToLivePtr != NULL) {\r
+ PxebcMode->TTL = *TimeToLivePtr;\r
+ }\r
+\r
+ if (TypeOfServicePtr != NULL) {\r
+ PxebcMode->ToS = *TypeOfServicePtr;\r
+ }\r
+ //\r
+ // Unlock the instance data\r
+ //\r
+ DEBUG ((DEBUG_INFO, "\nSetparameters() Exit = %xh ", StatCode));\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+}\r
+//\r
+// //////////////////////////////////////////////////////////\r
+//\r
+// BC Set Station IP Routine\r
+//\r
+\r
+/**\r
+ Set the station IP address\r
+\r
+ @param This Pointer to Pxe BaseCode Protocol\r
+ @param StationIpPtr Pointer to the requested IP address to set in base\r
+ code\r
+ @param SubnetMaskPtr Pointer to the requested subnet mask for the base\r
+ code\r
+\r
+ @retval EFI_SUCCESS Successfully set the parameters\r
+ @retval EFI_NOT_STARTED BC has not started\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcSetStationIP (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
+ IN EFI_IP_ADDRESS *StationIpPtr,\r
+ IN EFI_IP_ADDRESS *SubnetMaskPtr\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+ UINT32 SubnetMask;\r
+\r
+ //\r
+ // Lock the instance data and make sure started\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ if (This->Mode == NULL || !This->Mode->Started) {\r
+ DEBUG ((DEBUG_ERROR, "BC was not started."));\r
+ StatCode = EFI_NOT_STARTED;\r
+ goto RELEASE_LOCK;\r
+ }\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+\r
+ if (!Private->GoodStationIp && ((StationIpPtr == NULL) || (SubnetMaskPtr == NULL))) {\r
+ //\r
+ // It's not allowed to only set one of the two addresses while there isn't a previous\r
+ // GOOD address configuration.\r
+ //\r
+ StatCode = EFI_INVALID_PARAMETER;\r
+ goto RELEASE_LOCK;\r
+ }\r
+\r
+ if (SubnetMaskPtr != NULL) {\r
+ SubnetMask = SubnetMaskPtr->Addr[0];\r
+\r
+ if (SubnetMask & (SubnetMask + 1)) {\r
+ //\r
+ // the subnet mask is valid if it's with leading continuous 1 bits.\r
+ //\r
+ StatCode = EFI_INVALID_PARAMETER;\r
+ goto RELEASE_LOCK;\r
+ }\r
+ } else {\r
+ SubnetMaskPtr = &PxebcMode->SubnetMask;\r
+ SubnetMask = SubnetMaskPtr->Addr[0];\r
+ }\r
+\r
+ if (StationIpPtr == NULL) {\r
+ StationIpPtr = &PxebcMode->StationIp;\r
+ }\r
+\r
+ if (!IS_INADDR_UNICAST (StationIpPtr) ||\r
+ ((StationIpPtr->Addr[0] | SubnetMask) == BROADCAST_IPv4)) {\r
+ //\r
+ // The station IP is not a unicast address.\r
+ //\r
+ StatCode = EFI_INVALID_PARAMETER;\r
+ goto RELEASE_LOCK;\r
+ }\r
+\r
+ PxebcMode->StationIp = *StationIpPtr;\r
+ PxebcMode->SubnetMask = *SubnetMaskPtr;\r
+ Private->GoodStationIp = TRUE;\r
+\r
+RELEASE_LOCK:\r
+ //\r
+ // Unlock the instance data\r
+ //\r
+ EfiReleaseLock (&Private->Lock);\r
+\r
+ return StatCode;\r
+}\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL mPxeBcDriverBinding = {\r
+ PxeBcDriverSupported,\r
+ PxeBcDriverStart,\r
+ PxeBcDriverStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+\r
+/**\r
+ Test to see if this driver supports Controller. Any Controller\r
+ than contains a Snp protocol can be supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcDriverSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpPtr;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ (VOID **) &SnpPtr,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Start the Base code driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcDriverStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PXE_BASECODE_DEVICE *Private;\r
+ LOADFILE_DEVICE *pLF;\r
+\r
+ //\r
+ // Allocate structures needed by BaseCode and LoadFile protocols.\r
+ //\r
+ Private = AllocateZeroPool (sizeof (PXE_BASECODE_DEVICE));\r
+\r
+ if (Private == NULL ) {\r
+ DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc PXE_BASECODE_DEVICE structure.\n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ pLF = AllocateZeroPool (sizeof (LOADFILE_DEVICE));\r
+ if (pLF == NULL) {\r
+ DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc LOADFILE_DEVICE structure.\n"));\r
+ FreePool (Private);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->EfiBc.Mode = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_MODE));\r
+ if (Private->EfiBc.Mode == NULL) {\r
+ DEBUG ((EFI_D_NET, "\nBcNotifySnp() Could not alloc Mode structure.\n"));\r
+ FreePool (Private);\r
+ FreePool (pLF);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Lock access, just in case\r
+ //\r
+ EfiInitializeLock (&Private->Lock, TPL_CALLBACK);\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ EfiInitializeLock (&pLF->Lock, TPL_CALLBACK);\r
+ EfiAcquireLock (&pLF->Lock);\r
+\r
+ //\r
+ // Initialize PXE structure\r
+ //\r
+ //\r
+ // First initialize the internal 'private' data that the application\r
+ // does not see.\r
+ //\r
+ Private->Signature = PXE_BASECODE_DEVICE_SIGNATURE;\r
+ Private->Handle = Controller;\r
+\r
+ //\r
+ // Get the NII interface\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
+ (VOID **) &Private->NiiPtr,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
+ (VOID **) &Private->NiiPtr,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto PxeBcError;\r
+ }\r
+ }\r
+ //\r
+ // Get the Snp interface\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ (VOID **) &Private->SimpleNetwork,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto PxeBcError;\r
+ }\r
+\r
+ //\r
+ // Next, initialize the external 'public' data that\r
+ // the application does see.\r
+ //\r
+ Private->EfiBc.Revision = EFI_PXE_BASE_CODE_PROTOCOL_REVISION;\r
+ Private->EfiBc.Start = BcStart;\r
+ Private->EfiBc.Stop = BcStop;\r
+ Private->EfiBc.Dhcp = BcDhcp;\r
+ Private->EfiBc.Discover = BcDiscover;\r
+ Private->EfiBc.Mtftp = BcMtftp;\r
+ Private->EfiBc.UdpWrite = BcUdpWrite;\r
+ Private->EfiBc.UdpRead = BcUdpRead;\r
+ Private->EfiBc.Arp = BcArp;\r
+ Private->EfiBc.SetIpFilter = BcIpFilter;\r
+ Private->EfiBc.SetParameters = BcSetParameters;\r
+ Private->EfiBc.SetStationIp = BcSetStationIP;\r
+ Private->EfiBc.SetPackets = BcSetPackets;\r
+\r
+ //\r
+ // Initialize BaseCode Mode structure\r
+ //\r
+ Private->EfiBc.Mode->Started = FALSE;\r
+ Private->EfiBc.Mode->TTL = DEFAULT_TTL;\r
+ Private->EfiBc.Mode->ToS = DEFAULT_ToS;\r
+ Private->EfiBc.Mode->UsingIpv6 = FALSE;\r
+ Private->EfiBc.Mode->AutoArp = TRUE;\r
+\r
+ //\r
+ // Set to PXE_TRUE by the BC constructor if this BC\r
+ // implementation supports IPv6.\r
+ //\r
+ Private->EfiBc.Mode->Ipv6Supported = SUPPORT_IPV6;\r
+\r
+#if SUPPORT_IPV6\r
+ Private->EfiBc.Mode->Ipv6Available = Private->NiiPtr->Ipv6Supported;\r
+#else\r
+ Private->EfiBc.Mode->Ipv6Available = FALSE;\r
+#endif\r
+ //\r
+ // Set to TRUE by the BC constructor if this BC\r
+ // implementation supports BIS.\r
+ //\r
+ Private->EfiBc.Mode->BisSupported = TRUE;\r
+ Private->EfiBc.Mode->BisDetected = PxebcBisDetect (Private);\r
+\r
+ //\r
+ // Initialize LoadFile structure.\r
+ //\r
+ pLF->Signature = LOADFILE_DEVICE_SIGNATURE;\r
+ pLF->LoadFile.LoadFile = LoadFile;\r
+ pLF->Private = Private;\r
+\r
+ //\r
+ // Install protocol interfaces.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Controller,\r
+ &gEfiPxeBaseCodeProtocolGuid,\r
+ &Private->EfiBc,\r
+ &gEfiLoadFileProtocolGuid,\r
+ &pLF->LoadFile,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ goto PxeBcError;\r
+ }\r
+ //\r
+ // Release locks.\r
+ //\r
+ EfiReleaseLock (&pLF->Lock);\r
+ EfiReleaseLock (&Private->Lock);\r
+ return Status;\r
+\r
+PxeBcError: ;\r
+ gBS->FreePool (Private->EfiBc.Mode);\r
+ gBS->FreePool (Private);\r
+ gBS->FreePool (pLF);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop the Base code driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param NumberOfChildren Not used\r
+ @param ChildHandleBuffer Not used\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcDriverStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_LOAD_FILE_PROTOCOL *LfProtocol;\r
+ LOADFILE_DEVICE *LoadDevice;\r
+\r
+ //\r
+ // Get our context back.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiLoadFileProtocolGuid,\r
+ (VOID **) &LfProtocol,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ LoadDevice = EFI_LOAD_FILE_DEV_FROM_THIS (LfProtocol);\r
+\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ Controller,\r
+ &gEfiLoadFileProtocolGuid,\r
+ &LoadDevice->LoadFile,\r
+ &gEfiPxeBaseCodeProtocolGuid,\r
+ &LoadDevice->Private->EfiBc,\r
+ NULL\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ gBS->FreePool (LoadDevice->Private->EfiBc.Mode);\r
+ gBS->FreePool (LoadDevice->Private);\r
+ gBS->FreePool (LoadDevice);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Initialize the base code drivers and install the driver binding\r
+\r
+ Standard EFI Image Entry\r
+\r
+ @retval EFI_SUCCESS This driver was successfully bound\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeBCDriver (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Initialize EFI library\r
+ //\r
+ Status = EfiLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &mPxeBcDriverBinding,\r
+ NULL,\r
+ COMPONENT_NAME,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ InitArpHeader ();\r
+ OptionsStrucInit ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* eof - bc.c */\r
--- /dev/null
+/** @file
+
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ bc.h
+
+Abstract:
+
+
+**/
+
+#ifndef _BC_H
+#define _BC_H
+
+#include <PiDxe.h>\r
+\r
+#include <Guid/SmBios.h>\r
+#include <Protocol/Bis.h>\r
+#include <Protocol/PxeBaseCode.h>\r
+#include <Protocol/PxeBaseCodeCallBack.h>\r
+#include <Protocol/NetworkInterfaceIdentifier.h>\r
+#include <Protocol/SimpleNetwork.h>\r
+#include <Protocol/LoadFile.h>\r
+#include <Protocol/DevicePath.h>
+#include <Protocol/Tcp.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>
+
+#define CALLBACK_INTERVAL 100 // ten times a second
+#define FILTER_BITS (EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP | \
+ EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST | \
+ EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS | \
+ EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST \
+ )
+
+#define WAIT_TX_TIMEOUT 1000
+
+#define SUPPORT_IPV6 0
+
+#define PXE_BASECODE_DEVICE_SIGNATURE 'pxed'
+
+//
+// Determine the classes of IPv4 address
+//
+#define IS_CLASSA_IPADDR(x) ((((EFI_IP_ADDRESS*)x)->v4.Addr[0] & 0x80) == 0x00)
+#define IS_CLASSB_IPADDR(x) ((((EFI_IP_ADDRESS*)x)->v4.Addr[0] & 0xc0) == 0x80)
+#define IS_CLASSC_IPADDR(x) ((((EFI_IP_ADDRESS*)x)->v4.Addr[0] & 0xe0) == 0xc0)
+#define IS_INADDR_UNICAST(x) ((IS_CLASSA_IPADDR(x) || IS_CLASSB_IPADDR(x) || IS_CLASSC_IPADDR(x)) && (((EFI_IP_ADDRESS*)x)->Addr[0] != 0) )
+
+//
+// Definitions for internet group management protocol version 2 message
+// structure
+// Per RFC 2236, November 1997
+//
+#pragma pack(1)
+
+typedef struct {
+ UINT8 Type;
+ UINT8 MaxRespTime; // in tenths of a second
+ UINT16 Checksum; // ones complement of ones complement sum of
+ // 16 bit words of message
+ UINT32 GroupAddress; // for general query, all systems group,
+ // for group specific, the group
+} IGMPV2_MESSAGE;
+
+#define IGMP_TYPE_QUERY 0x11
+#define IGMP_TYPE_REPORT 0x16
+#define IGMP_TYPE_V1REPORT 0x12
+#define IGMP_TYPE_LEAVE_GROUP 0x17
+
+#define IGMP_DEFAULT_MAX_RESPONSE_TIME 10 // 10 second default
+#pragma pack()
+
+#define MAX_MCAST_GROUPS 8 // most we allow ourselves to join at once
+#define MAX_OFFERS 16
+
+typedef struct {
+ UINTN Signature;
+ EFI_LOCK Lock;
+ BOOLEAN ShowErrorMessages;
+ EFI_TCP_PROTOCOL Tcp;
+ EFI_PXE_BASE_CODE_PROTOCOL EfiBc;
+ EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *CallbackProtocolPtr;
+ EFI_HANDLE Handle;
+
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiPtr;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;
+ UINT8 *TransmitBufferPtr;
+ UINT8 *ReceiveBufferPtr;
+ EFI_PXE_BASE_CODE_FUNCTION Function;
+
+ UINTN OldestArpEntry;
+ UINTN MCastGroupCount;
+ EFI_EVENT Igmpv1TimeoutEvent;
+ BOOLEAN UseIgmpv1Reporting;
+ EFI_EVENT IgmpGroupEvent[MAX_MCAST_GROUPS];
+ UINT16 RandomPort;
+
+#if SUPPORT_IPV6
+ //
+ // TBD
+ //
+#else
+ UINT32 MCastGroup[MAX_MCAST_GROUPS];
+#endif
+
+ BOOLEAN GoodStationIp;
+ BOOLEAN DidTransmit;
+ UINTN IpLength;
+ VOID *DhcpPacketBuffer;
+ UINTN FileSize;
+ VOID *BootServerReceiveBuffer;
+ EFI_IP_ADDRESS ServerIp;
+
+ //
+ // work area
+ // for dhcp
+ //
+ VOID *ReceiveBuffers;
+ VOID *TransmitBuffer;
+ UINTN NumOffersReceived;
+ UINT16 TotalSeconds;
+
+ //
+ // arrays for different types of offers
+ //
+ UINT8 ServerCount[4];
+ UINT8 OfferCount[4][MAX_OFFERS];
+ UINT8 GotBootp;
+ UINT8 GotProxy[4];
+ UINT8 BinlProxies[MAX_OFFERS];
+
+ UINT8 *ArpBuffer;
+ UINT8 *TftpAckBuffer;
+ UINT8 *TftpErrorBuffer;
+ IGMPV2_MESSAGE IgmpMessage;
+ BOOLEAN BigBlkNumFlag;
+ UINT8 Timeout;
+ UINT16 RandomSeed;
+} PXE_BASECODE_DEVICE;
+
+//
+// type index
+//
+#define DHCP_ONLY_IX 0
+#define PXE10_IX 1
+#define WfM11a_IX 2
+#define BINL_IX 3
+
+#define PXE_RND_PORT_LOW 2070
+
+//
+//
+//
+#define LOADFILE_DEVICE_SIGNATURE 'pxel'
+
+typedef struct {
+ UINTN Signature;
+ EFI_LOCK Lock;
+ EFI_LOAD_FILE_PROTOCOL LoadFile;
+ PXE_BASECODE_DEVICE *Private;
+} LOADFILE_DEVICE;
+
+#define EFI_BASE_CODE_DEV_FROM_THIS(a) CR (a, PXE_BASECODE_DEVICE, efi_bc, PXE_BASECODE_DEVICE_SIGNATURE);
+
+#define EFI_BASE_CODE_DEV_FROM_TCP(a) CR (a, PXE_BASECODE_DEVICE, Tcp, PXE_BASECODE_DEVICE_SIGNATURE);
+
+#define EFI_LOAD_FILE_DEV_FROM_THIS(a) CR (a, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE)
+
+EFI_BIS_PROTOCOL *
+PxebcBisStart (
+ PXE_BASECODE_DEVICE *Private,
+ BIS_APPLICATION_HANDLE *BisAppHandle,
+ EFI_BIS_DATA **BisDataSigInfo
+ )
+;
+
+VOID
+PxebcBisStop (
+ EFI_BIS_PROTOCOL *Bis,
+ BIS_APPLICATION_HANDLE BisAppHandle,
+ EFI_BIS_DATA *BisDataSigInfo
+ )
+;
+
+BOOLEAN
+PxebcBisVerify (
+ PXE_BASECODE_DEVICE *Private,
+ VOID *FileBuffer,
+ UINTN FileBufferLength,
+ VOID *CredentialBuffer,
+ UINTN CredentialBufferLength
+ )
+;
+
+BOOLEAN
+PxebcBisDetect (
+ PXE_BASECODE_DEVICE *Private
+ )
+;
+
+//
+// Global Variables
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gPxeBcComponentName;
+
+//
+// //////////////////////////////////////////////////////////
+//
+// prototypes
+//
+
+/**
+ Initialize the base code drivers and install the driver binding
+
+ Standard EFI Image Entry
+
+ @retval EFI_SUCCESS This driver was successfully bound
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeBCDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcStart (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN BOOLEAN UseIpv6
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcStop (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcDhcp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN BOOLEAN SortOffers
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcDiscover (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN UINT16 Type,
+ IN UINT16 *Layer,
+ IN BOOLEAN UseBis,
+ IN EFI_PXE_BASE_CODE_DISCOVER_INFO * Info OPTIONAL
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcMtftp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
+ IN OUT VOID *BufferPtr,
+ IN BOOLEAN Overwrite,
+ IN OUT UINT64 *BufferSize,
+ IN UINTN *BlockSize OPTIONAL,
+ IN EFI_IP_ADDRESS * ServerIp,
+ IN UINT8 *Filename,
+ IN EFI_PXE_BASE_CODE_MTFTP_INFO * Info OPTIONAL,
+ IN BOOLEAN DontUseBuffer
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcUdpWrite (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN UINT16 OpFlags,
+ IN EFI_IP_ADDRESS *DestIp,
+ IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort,
+ IN EFI_IP_ADDRESS *GatewayIp, OPTIONAL
+ IN EFI_IP_ADDRESS *SrcIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL
+ IN UINTN *HeaderSize, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN UINTN *BufferSize,
+ IN VOID *BufferPtr
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcUdpRead (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN UINT16 OpFlags,
+ IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL
+ IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL
+ IN UINTN *HeaderSize, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN OUT UINTN *BufferSize,
+ IN VOID *BufferPtr
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcTcpWrite (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN UINT16 OpFlags,
+ IN UINT16 *UrgentPointer,
+ IN UINT32 *SequenceNumber,
+ IN UINT32 *AckNumber,
+ IN UINT16 *HlenResCode,
+ IN UINT16 *Window,
+ IN EFI_IP_ADDRESS *DestIp,
+ IN EFI_PXE_BASE_CODE_TCP_PORT *DestPort,
+ IN EFI_IP_ADDRESS *GatewayIp, OPTIONAL
+ IN EFI_IP_ADDRESS *SrcIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_TCP_PORT *SrcPort, OPTIONAL
+ IN UINTN *HeaderSize, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN UINTN *BufferSize,
+ IN VOID *BufferPtr
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcTcpRead (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN UINT16 OpFlags,
+ IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_TCP_PORT *DestPort, OPTIONAL
+ IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_TCP_PORT *SrcPort, OPTIONAL
+ IN UINTN *HeaderSize, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN OUT UINTN *BufferSize,
+ IN VOID *BufferPtr
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcArp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN EFI_IP_ADDRESS * IpAddr,
+ IN EFI_MAC_ADDRESS * MacAddr OPTIONAL
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcIpFilter (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN EFI_PXE_BASE_CODE_IP_FILTER *NewFilter
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcSetParameters (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN BOOLEAN *NewAutoArp, OPTIONAL
+ IN BOOLEAN *NewSendGUID, OPTIONAL
+ IN UINT8 *NewTTL, OPTIONAL
+ IN UINT8 *NewToS, OPTIONAL
+ IN BOOLEAN *NewMakeCallback OPTIONAL
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcSetStationIP (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN EFI_IP_ADDRESS * NewStationIp, OPTIONAL
+ IN EFI_IP_ADDRESS * NewSubnetMask OPTIONAL
+ )
+;
+
+EFI_STATUS
+EFIAPI
+BcSetPackets (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ BOOLEAN *NewDhcpDiscoverValid, OPTIONAL
+ BOOLEAN *NewDhcpAckReceived, OPTIONAL
+ BOOLEAN *NewProxyOfferReceived, OPTIONAL
+ BOOLEAN *NewPxeDiscoverValid, OPTIONAL
+ BOOLEAN *NewPxeReplyReceived, OPTIONAL
+ BOOLEAN *NewPxeBisReplyReceived, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewDhcpDiscover, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewDhcpAck, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewProxyOffer, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeDiscover, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeReply, OPTIONAL
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeBisReply OPTIONAL
+ )
+;
+
+EFI_STATUS
+EFIAPI
+LoadFile (
+ IN EFI_LOAD_FILE_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN BOOLEAN BootPolicy,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+;
+
+EFI_STATUS
+PxeBcLibGetSmbiosSystemGuidAndSerialNumber (
+ IN EFI_GUID *SystemGuid,
+ OUT CHAR8 **SystemSerialNumber
+ )
+;
+
+#ifdef EFI_SIZE_REDUCTION_APPLIED
+ #define COMPONENT_NAME_CODE(code)
+ #define COMPONENT_NAME NULL
+#else
+ #define COMPONENT_NAME_CODE(code) code
+ #define COMPONENT_NAME &gPxeBcComponentName
+#endif
+
+
+//
+// Define SMBIOS tables.
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 AnchorString[4];
+ UINT8 EntryPointStructureChecksum;
+ UINT8 EntryPointLength;
+ UINT8 MajorVersion;
+ UINT8 MinorVersion;
+ UINT16 MaxStructureSize;
+ UINT8 EntryPointRevision;
+ UINT8 FormattedArea[5];
+ UINT8 IntermediateAnchorString[5];
+ UINT8 IntermediateChecksum;
+ UINT16 TableLength;
+ UINT32 TableAddress;
+ UINT16 NumberOfSmbiosStructures;
+ UINT8 SmbiosBcdRevision;
+} SMBIOS_STRUCTURE_TABLE;
+
+//
+// Please note that SMBIOS structures can be odd byte aligned since the
+// unformated section of each record is a set of arbitrary size strings.
+//
+typedef struct {
+ UINT8 Type;
+ UINT8 Length;
+ UINT8 Handle[2];
+} SMBIOS_HEADER;
+
+typedef UINT8 SMBIOS_STRING;
+
+typedef struct {
+ SMBIOS_HEADER Hdr;
+ SMBIOS_STRING Vendor;
+ SMBIOS_STRING BiosVersion;
+ UINT8 BiosSegment[2];
+ SMBIOS_STRING BiosReleaseDate;
+ UINT8 BiosSize;
+ UINT8 BiosCharacteristics[8];
+} SMBIOS_TYPE0;
+
+typedef struct {
+ SMBIOS_HEADER Hdr;
+ SMBIOS_STRING Manufacturer;
+ SMBIOS_STRING ProductName;
+ SMBIOS_STRING Version;
+ SMBIOS_STRING SerialNumber;
+
+ //
+ // always byte copy this data to prevent alignment faults!
+ //
+ EFI_GUID Uuid;
+
+ UINT8 WakeUpType;
+} SMBIOS_TYPE1;
+
+typedef struct {
+ SMBIOS_HEADER Hdr;
+ SMBIOS_STRING Manufacturer;
+ SMBIOS_STRING ProductName;
+ SMBIOS_STRING Version;
+ SMBIOS_STRING SerialNumber;
+} SMBIOS_TYPE2;
+
+typedef struct {
+ SMBIOS_HEADER Hdr;
+ SMBIOS_STRING Manufacturer;
+ UINT8 Type;
+ SMBIOS_STRING Version;
+ SMBIOS_STRING SerialNumber;
+ SMBIOS_STRING AssetTag;
+ UINT8 BootupState;
+ UINT8 PowerSupplyState;
+ UINT8 ThermalState;
+ UINT8 SecurityStatus;
+ UINT8 OemDefined[4];
+} SMBIOS_TYPE3;
+
+typedef struct {
+ SMBIOS_HEADER Hdr;
+ UINT8 Socket;
+ UINT8 ProcessorType;
+ UINT8 ProcessorFamily;
+ SMBIOS_STRING ProcessorManufacture;
+ UINT8 ProcessorId[8];
+ SMBIOS_STRING ProcessorVersion;
+ UINT8 Voltage;
+ UINT8 ExternalClock[2];
+ UINT8 MaxSpeed[2];
+ UINT8 CurrentSpeed[2];
+ UINT8 Status;
+ UINT8 ProcessorUpgrade;
+ UINT8 L1CacheHandle[2];
+ UINT8 L2CacheHandle[2];
+ UINT8 L3CacheHandle[2];
+} SMBIOS_TYPE4;
+
+typedef union {
+ SMBIOS_HEADER *Hdr;
+ SMBIOS_TYPE0 *Type0;
+ SMBIOS_TYPE1 *Type1;
+ SMBIOS_TYPE2 *Type2;
+ SMBIOS_TYPE3 *Type3;
+ SMBIOS_TYPE4 *Type4;
+ UINT8 *Raw;
+} SMBIOS_STRUCTURE_POINTER;
+#pragma pack()
+
+#include "ip.h"
+#include "dhcp.h"
+#include "tftp.h"
+
+#endif /* _BC_H */
+
+/* EOF - bc.h */
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Bc.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcComponentNameGetControllerName (\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 gPxeBcComponentName = {\r
+ PxeBcComponentNameGetDriverName,\r
+ PxeBcComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mPxeBcDriverNameTable[] = {\r
+ {\r
+ "eng",\r
+ L"PXE Base Code Driver"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ Language - A pointer to a three character ISO 639-2 language identifier.\r
+ This is the language of the driver name that that the caller\r
+ is requesting, and it must match one of the languages specified\r
+ in SupportedLanguages. The number of languages supported by a\r
+ driver is up to the driver writer.\r
+ DriverName - A pointer to the Unicode string to return. This Unicode string\r
+ is the name of the driver specified by This in the language\r
+ specified by Language.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The Unicode string for the Driver specified by This\r
+ and the language specified by Language was returned\r
+ in DriverName.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - DriverName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gPxeBcComponentName.SupportedLanguages,\r
+ mPxeBcDriverNameTable,\r
+ DriverName\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PxeBcComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by an EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ ControllerHandle - The handle of a controller that the driver specified by\r
+ This is managing. This handle specifies the controller\r
+ whose name is to be returned.\r
+ ChildHandle - The handle of the child controller to retrieve the name\r
+ of. This is an optional parameter that may be NULL. It\r
+ will be NULL for device drivers. It will also be NULL\r
+ for a bus drivers that wish to retrieve the name of the\r
+ bus controller. It will not be NULL for a bus driver\r
+ that wishes to retrieve the name of a child controller.\r
+ Language - A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language of the controller name\r
+ that that the caller is requesting, and it must match one\r
+ of the languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up to the\r
+ driver writer.\r
+ ControllerName - A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the controller specified by\r
+ ControllerHandle and ChildHandle in the language specified\r
+ by Language from the point of view of the driver specified\r
+ by This.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The Unicode string for the user readable name in the\r
+ language specified by Language for the driver\r
+ specified by This was returned in DriverName.\r
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This is not currently managing\r
+ the controller specified by ControllerHandle and\r
+ ChildHandle.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2004, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#ifndef _DHCP_H
+#define _DHCP_H
+
+//
+// Definitions for DHCP version 4 UDP packet.
+// The field names in this structure are defined and described in RFC 2131.
+//
+#pragma pack(1)
+
+typedef struct {
+ UINT8 op;
+#define BOOTP_REQUEST 1
+#define BOOTP_REPLY 2
+
+ UINT8 htype;
+ UINT8 hlen;
+ UINT8 hops;
+ UINT32 xid;
+ UINT16 secs;
+ UINT16 flags;
+#define DHCP_BROADCAST_FLAG 0x8000
+
+ UINT32 ciaddr;
+ UINT32 yiaddr;
+ UINT32 siaddr;
+ UINT32 giaddr;
+ UINT8 chaddr[16];
+ UINT8 sname[64];
+ UINT8 file[128];
+ UINT8 options[312];
+#define OP_PAD 0
+#define OP_END 255
+#define OP_SUBNET_MASK 1
+#define OP_TIME_OFFSET 2
+#define OP_ROUTER_LIST 3
+#define OP_TIME_SERVERS 4
+#define OP_NAME_SERVERS 5
+#define OP_DNS_SERVERS 6
+#define OP_LOG_SERVERS 7
+#define OP_COOKIE_SERVERS 8
+#define OP_LPR_SREVERS 9
+#define OP_IMPRESS_SERVERS 10
+#define OP_RES_LOC_SERVERS 11
+#define OP_HOST_NAME 12
+#define OP_BOOT_FILE_SZ 13
+#define OP_DUMP_FILE 14
+#define OP_DOMAIN_NAME 15
+#define OP_SWAP_SERVER 16
+#define OP_ROOT_PATH 17
+#define OP_EXTENSION_PATH 18
+#define OP_IP_FORWARDING 19
+#define OP_NON_LOCAL_SRC_RTE 20
+#define OP_POLICY_FILTER 21
+#define OP_MAX_DATAGRAM_SZ 22
+#define OP_DEFAULT_TTL 23
+#define OP_MTU_AGING_TIMEOUT 24
+#define OP_MTU_SIZES 25
+#define OP_MTU_TO_USE 26
+#define OP_ALL_SUBNETS_LOCAL 27
+#define OP_BROADCAST_ADD 28
+#define OP_PERFORM_MASK_DISCOVERY 29
+#define OP_RESPOND_TO_MASK_REQ 30
+#define OP_PERFORM_ROUTER_DISCOVERY 31
+#define OP_ROUTER_SOLICIT_ADDRESS 32
+#define OP_STATIC_ROUTER_LIST 33
+#define OP_USE_ARP_TRAILERS 34
+#define OP_ARP_CACHE_TIMEOUT 35
+#define OP_ETHERNET_ENCAPSULATION 36
+#define OP_TCP_DEFAULT_TTL 37
+#define OP_TCP_KEEP_ALIVE_INT 38
+#define OP_KEEP_ALIVE_GARBAGE 39
+#define OP_NIS_DOMAIN_NAME 40
+#define OP_NIS_SERVERS 41
+#define OP_NTP_SERVERS 42
+#define OP_VENDOR_SPECIFIC 43
+#define VEND_PXE_MTFTP_IP 1
+#define VEND_PXE_MTFTP_CPORT 2
+#define VEND_PXE_MTFTP_SPORT 3
+#define VEND_PXE_MTFTP_TMOUT 4
+#define VEND_PXE_MTFTP_DELAY 5
+#define VEND_PXE_DISCOVERY_CONTROL 6
+#define PXE_DISABLE_BROADCAST_DISCOVERY (1 << 0)
+#define PXE_DISABLE_MULTICAST_DISCOVERY (1 << 1)
+#define PXE_ACCEPT_ONLY_PXE_BOOT_SERVERS (1 << 2)
+#define PXE_DO_NOT_PROMPT (1 << 3)
+#define VEND_PXE_DISCOVERY_MCAST_ADDR 7
+#define VEND_PXE_BOOT_SERVERS 8
+#define VEND_PXE_BOOT_MENU 9
+#define VEND_PXE_BOOT_PROMPT 10
+#define VEND_PXE_MCAST_ADDRS_ALLOC 11
+#define VEND_PXE_CREDENTIAL_TYPES 12
+#define VEND_PXE_BOOT_ITEM 71
+#define OP_NBNS_SERVERS 44
+#define OP_NBDD_SERVERS 45
+#define OP_NETBIOS_NODE_TYPE 46
+#define OP_NETBIOS_SCOPE 47
+#define OP_XWINDOW_SYSTEM_FONT_SERVERS 48
+#define OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49
+#define OP_DHCP_REQ_IP_ADD 50
+#define OP_DHCP_LEASE_TIME 51
+#define OP_DHCP_OPTION_OVERLOAD 52
+#define OVLD_FILE 1
+#define OVLD_SRVR_NAME 2
+#define OP_DHCP_MESSAGE_TYPE 53
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNAK 6
+#define DHCPRELEASE 7
+#define DHCPINFORM 8
+#define OP_DHCP_SERVER_IP 54
+#define OP_DHCP_PARM_REQ_LIST 55
+#define OP_DHCP_ERROR_MESSAGE 56
+#define OP_DHCP_MAX_MESSAGE_SZ 57
+#define OP_DHCP_RENEWAL_TIME 58
+#define OP_DHCP_REBINDING_TIME 59
+#define OP_DHCP_CLASS_IDENTIFIER 60
+#define OP_DHCP_CLIENT_IDENTIFIER 61
+#define OP_NISPLUS_DOMAIN_NAME 64
+#define OP_NISPLUS_SERVERS 65
+#define OP_DHCP_TFTP_SERVER_NAME 66
+#define OP_DHCP_BOOTFILE 67
+#define OP_MOBILE_IP_HOME_AGENTS 68
+#define OP_SMPT_SERVERS 69
+#define OP_POP3_SERVERS 70
+#define OP_NNTP_SERVERS 71
+#define OP_WWW_SERVERS 72
+#define OP_FINGER_SERVERS 73
+#define OP_IRC_SERVERS 74
+#define OP_STREET_TALK_SERVERS 75
+#define OP_STREET_TALK_DIR_ASSIST_SERVERS 76
+#define OP_NDS_SERVERS 85
+#define OP_NDS_TREE_NAME 86
+#define OP_NDS_CONTEXT 87
+#define OP_DHCP_SYSTEM_ARCH 93
+#define OP_DHCP_NETWORK_ARCH 94
+#define OP_DHCP_PLATFORM_ID 97
+} DHCPV4_STRUCT;
+
+//
+// DHCPv4 option header
+//
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length;
+ //
+ // followed by Data[]
+ //
+} DHCPV4_OP_HEADER;
+
+//
+// Generic DHCPv4 option (header followed by data)
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Data[1];
+} DHCPV4_OP_STRUCT;
+
+//
+// Maximum DHCP packet size on ethernet
+//
+#define MAX_DHCP_MSG_SZ (MAX_ENET_DATA_SIZE - sizeof (IPV4_HEADER) - sizeof (UDPV4_HEADER))
+
+//
+// Macros used in pxe_bc_dhcp.c and pxe_loadfile.c
+//
+#define DHCPV4_TRANSMIT_BUFFER (*(DHCPV4_STRUCT *) (Private->TransmitBuffer))
+#define DHCPV4_OPTIONS_BUFFER (*(struct optionsstr *) DHCPV4_TRANSMIT_BUFFER.options)
+
+#define DHCPV4_ACK_INDEX 0
+#define PXE_BINL_INDEX 1
+#define PXE_OFFER_INDEX 1
+#define PXE_ACK_INDEX 2
+#define PXE_BIS_INDEX 3
+
+#define DHCPV4_ACK_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[DHCPV4_ACK_INDEX]
+#define PXE_BINL_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_BINL_INDEX]
+#define PXE_OFFER_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_OFFER_INDEX]
+#define PXE_ACK_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_ACK_INDEX]
+#define PXE_BIS_BUFFER ((struct DhcpReceiveBufferStruct *) Private->DhcpPacketBuffer)[PXE_BIS_INDEX]
+
+#define DHCPV4_ACK_PACKET DHCPV4_ACK_BUFFER.u.Dhcpv4
+#define PXE_BINL_PACKET PXE_BINL_BUFFER.u.Dhcpv4
+#define PXE_OFFER_PACKET PXE_OFFER_BUFFER.u.Dhcpv4
+#define PXE_ACK_PACKET PXE_ACK_BUFFER.u.Dhcpv4
+#define PXE_BIS_PACKET PXE_BIS_BUFFER.u.Dhcpv4
+
+//
+// network structure definitions
+//
+//
+// some option definitions
+//
+#define DHCPV4_OPTION_LENGTH(type) (sizeof (type) - sizeof (DHCPV4_OP_HEADER))
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Type;
+} DHCPV4_OP_MESSAGE_TYPE;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Overload;
+} DHCPV4_OP_OVERLOAD;
+
+//
+// boot server list structure
+// one or more contained in a pxe boot servers structure
+//
+typedef struct {
+ UINT8 IpCount;
+ EFI_IPv4_ADDRESS IpList[1]; // IP count of IPs
+} PXEV4_SERVER_LIST;
+
+typedef struct {
+ UINT8 IpCount;
+ EFI_IPv6_ADDRESS IpList[1]; // IP count of IPs
+} PXEV6_SERVER_LIST;
+
+typedef union {
+ PXEV4_SERVER_LIST Ipv4List;
+ PXEV6_SERVER_LIST Ipv6List;
+} PXE_SERVER_LISTS;
+
+typedef struct {
+ UINT16 Type;
+ PXE_SERVER_LISTS u;
+} PXE_SERVER_LIST;
+
+//
+// pxe boot servers structure
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ PXE_SERVER_LIST ServerList[1]; // one or more
+} PXE_OP_SERVER_LIST;
+
+//
+// pxe boot item structure
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT16 Type;
+ UINT16 Layer;
+} PXE_OP_BOOT_ITEM;
+
+//
+// pxe boot menu item structure
+//
+typedef struct {
+ UINT16 Type;
+ UINT8 DataLen;
+ UINT8 Data[1];
+} PXE_BOOT_MENU_ENTRY;
+
+//
+// pxe boot menu structure
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ PXE_BOOT_MENU_ENTRY MenuItem[1];
+} PXE_OP_BOOT_MENU;
+
+//
+// pxe boot prompt structure
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Timeout;
+ UINT8 Prompt[1];
+} PXE_OP_BOOT_PROMPT;
+
+#define PXE_BOOT_PROMPT_AUTO_SELECT 0
+#define PXE_BOOT_PROMPT_NO_TIMEOUT 255
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Class[1];
+} DHCPV4_OP_CLASS;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 File[1];
+} DHCPV4_OP_BOOTFILE;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 VendorOptions[1];
+} DHCPV4_OP_VENDOR_OPTIONS;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 MaxSize[2];
+} DHCPV4_OP_MAX_MESSAGE_SIZE;
+
+typedef struct {
+ UINT8 _OP_SUBNET_MASK; /* 1 */
+ UINT8 _OP_TIME_OFFSET; /* 2 */
+ UINT8 _OP_ROUTER_LIST; /* 3 */
+ UINT8 _OP_TIME_SERVERS; /* 4 */
+ UINT8 _OP_NAME_SERVERS; /* 5 */
+ UINT8 _OP_DNS_SERVERS; /* 6 */
+ UINT8 _OP_HOST_NAME; /* 12 */
+ UINT8 _OP_BOOT_FILE_SZ; /* 13 */
+ UINT8 _OP_DOMAIN_NAME; /* 15 */
+ UINT8 _OP_ROOT_PATH; /* 17 */
+ UINT8 _OP_EXTENSION_PATH; /* 18 */
+ UINT8 _OP_MAX_DATAGRAM_SZ; /* 22 */
+ UINT8 _OP_DEFAULT_TTL; /* 23 */
+ UINT8 _OP_BROADCAST_ADD; /* 28 */
+ UINT8 _OP_NIS_DOMAIN_NAME; /* 40 */
+ UINT8 _OP_NIS_SERVERS; /* 41 */
+ UINT8 _OP_NTP_SERVERS; /* 42 */
+ UINT8 _OP_VENDOR_SPECIFIC; /* 43 */
+ UINT8 _OP_DHCP_REQ_IP_ADD; /* 50 */
+ UINT8 _OP_DHCP_LEASE_TIME; /* 51 */
+ UINT8 _OP_DHCP_SERVER_IP; /* 54 */
+ UINT8 _OP_DHCP_RENEWAL_TIME; /* 58 */
+ UINT8 _OP_DHCP_REBINDING_TIME; /* 59 */
+ UINT8 _OP_DHCP_CLASS_IDENTIFIER; /* 60 */
+ UINT8 _OP_DHCP_TFTP_SERVER_NAME; /* 66 */
+ UINT8 _OP_DHCP_BOOTFILE; /* 67 */
+ UINT8 _OP_DHCP_PLATFORM_ID; /* 97 */
+ UINT8 VendorOption128; // vendor option 128
+ UINT8 VendorOption129; // vendor option 129
+ UINT8 VendorOption130; // vendor option 130
+ UINT8 VendorOption131; // vendor option 131
+ UINT8 VendorOption132; // vendor option 132
+ UINT8 VendorOption133; // vendor option 133
+ UINT8 VendorOption134; // vendor option 134
+ UINT8 VendorOption135; // vendor option 135
+} DHCPV4_REQUESTED_OPTIONS_DATA;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ DHCPV4_REQUESTED_OPTIONS_DATA Data;
+} DHCPV4_OP_REQUESTED_OPTIONS;
+
+typedef struct opipstr {
+ DHCPV4_OP_HEADER Header;
+ EFI_IPv4_ADDRESS Ip;
+} DHCPV4_OP_IP_ADDRESS;
+
+//
+// ip list structure - e.g. router list
+//
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ EFI_IPv4_ADDRESS IpList[1];
+} DHCPV4_OP_IP_LIST;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Type;
+ UINT8 Guid[sizeof (EFI_GUID)];
+} DHCPV4_OP_CLIENT_ID;
+
+//
+// special options start - someday obsolete ???
+//
+#define DHCPV4_OP_PLATFORM_ID DHCPV4_OP_CLIENT_ID
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT8 Type; // SNP = 2
+ UINT8 MajorVersion;
+ UINT8 MinorVersion;
+} DHCPV4_OP_NETWORK_INTERFACE;
+
+#define UNDI_TYPE 1
+#define SNP_TYPE 2
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ UINT16 Type;
+} DHCPV4_OP_ARCHITECTURE_TYPE;
+//
+// special options end - someday obsolete ???
+//
+typedef struct {
+ UINT8 ClassIdentifier[10]; // PXEClient:
+ UINT8 Lit2[5]; // Arch:
+ UINT8 ArchitectureType[5]; // 00000 - 65536
+ UINT8 Lit3[1]; // :
+ UINT8 InterfaceName[4]; // e.g. UNDI
+ UINT8 Lit4[1]; // :
+ UINT8 UndiMajor[3]; // 000 - 255
+ UINT8 UndiMinor[3]; // 000 - 255
+} DHCPV4_CLASS_ID_DATA;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ DHCPV4_CLASS_ID_DATA Data;
+} DHCPV4_OP_CLASS_ID;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ EFI_IPv4_ADDRESS Ip;
+} DHCPV4_OP_REQUESTED_IP;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ EFI_IPv4_ADDRESS Ip;
+} DHCPV4_OP_SERVER_IP;
+
+typedef struct {
+ DHCPV4_OP_HEADER Header;
+ EFI_IPv4_ADDRESS Ip;
+} DHCPV4_OP_SUBNET_MASK;
+
+typedef struct { // oppxedisctlstr {
+ DHCPV4_OP_HEADER Header;
+ UINT8 ControlBits;
+} PXE_OP_DISCOVERY_CONTROL;
+
+#define DISABLE_BCAST (1 << 0)
+#define DISABLE_MCAST (1 << 1)
+#define USE_ACCEPT_LIST (1 << 2)
+#define USE_BOOTFILE (1 << 3)
+
+#pragma pack()
+//
+// definitions of indices to populate option interest array
+//
+#define VEND_PXE_MTFTP_IP_IX 1 // multicast IP address of bootfile for MTFTP listen
+#define VEND_PXE_MTFTP_CPORT_IX 2 // UDP Port to monitor for MTFTP responses - Intel order
+#define VEND_PXE_MTFTP_SPORT_IX 3 // Server UDP Port for MTFTP open - Intel order
+#define VEND_PXE_MTFTP_TMOUT_IX 4 // Listen timeout - secs
+#define VEND_PXE_MTFTP_DELAY_IX 5 // Transmission timeout - secs
+#define VEND_PXE_DISCOVERY_CONTROL_IX 6 // bit field
+#define VEND_PXE_DISCOVERY_MCAST_ADDR_IX 7 // boot server discovery multicast address
+#define VEND_PXE_BOOT_SERVERS_IX 8 // list of boot servers of form tp(2) cnt(1) ips[cnt]
+#define VEND_PXE_BOOT_MENU_IX 9
+#define VEND_PXE_BOOT_PROMPT_IX 10
+#define VEND_PXE_MCAST_ADDRS_ALLOC_IX 0 // not used by PXE client
+#define VEND_PXE_CREDENTIAL_TYPES_IX 11
+#define VEND_13_IX 0 // not used by PXE client
+#define VEND_14_IX 0 // not used by PXE client
+#define VEND_15_IX 0 // not used by PXE client
+#define VEND_16_IX 0 // not used by PXE client
+#define VEND_17_IX 0 // not used by PXE client
+#define VEND_18_IX 0 // not used by PXE client
+#define VEND_19_IX 0 // not used by PXE client
+#define VEND_20_IX 0 // not used by PXE client
+#define VEND_21_IX 0 // not used by PXE client
+#define VEND_22_IX 0 // not used by PXE client
+#define VEND_23_IX 0 // not used by PXE client
+#define VEND_24_IX 0 // not used by PXE client
+#define VEND_25_IX 0 // not used by PXE client
+#define VEND_26_IX 0 // not used by PXE client
+#define VEND_27_IX 0 // not used by PXE client
+#define VEND_28_IX 0 // not used by PXE client
+#define VEND_29_IX 0 // not used by PXE client
+#define VEND_30_IX 0 // not used by PXE client
+#define VEND_31_IX 0 // not used by PXE client
+#define VEND_32_IX 0 // not used by PXE client
+#define VEND_33_IX 0 // not used by PXE client
+#define VEND_34_IX 0 // not used by PXE client
+#define VEND_35_IX 0 // not used by PXE client
+#define VEND_36_IX 0 // not used by PXE client
+#define VEND_37_IX 0 // not used by PXE client
+#define VEND_38_IX 0 // not used by PXE client
+#define VEND_39_IX 0 // not used by PXE client
+#define VEND_40_IX 0 // not used by PXE client
+#define VEND_41_IX 0 // not used by PXE client
+#define VEND_42_IX 0 // not used by PXE client
+#define VEND_43_IX 0 // not used by PXE client
+#define VEND_44_IX 0 // not used by PXE client
+#define VEND_45_IX 0 // not used by PXE client
+#define VEND_46_IX 0 // not used by PXE client
+#define VEND_47_IX 0 // not used by PXE client
+#define VEND_48_IX 0 // not used by PXE client
+#define VEND_49_IX 0 // not used by PXE client
+#define VEND_50_IX 0 // not used by PXE client
+#define VEND_51_IX 0 // not used by PXE client
+#define VEND_52_IX 0 // not used by PXE client
+#define VEND_53_IX 0 // not used by PXE client
+#define VEND_54_IX 0 // not used by PXE client
+#define VEND_55_IX 0 // not used by PXE client
+#define VEND_56_IX 0 // not used by PXE client
+#define VEND_57_IX 0 // not used by PXE client
+#define VEND_58_IX 0 // not used by PXE client
+#define VEND_59_IX 0 // not used by PXE client
+#define VEND_60_IX 0 // not used by PXE client
+#define VEND_61_IX 0 // not used by PXE client
+#define VEND_62_IX 0 // not used by PXE client
+#define VEND_63_IX 0 // not used by PXE client
+#define VEND_64_IX 0 // not used by PXE client
+#define VEND_65_IX 0 // not used by PXE client
+#define VEND_66_IX 0 // not used by PXE client
+#define VEND_67_IX 0 // not used by PXE client
+#define VEND_68_IX 0 // not used by PXE client
+#define VEND_69_IX 0 // not used by PXE client
+#define VEND_70_IX 0 // not used by PXE client
+#define VEND_PXE_BOOT_ITEM_IX 12
+
+#define MAX_OUR_PXE_OPT VEND_PXE_BOOT_ITEM // largest PXE option in which we are interested
+#define MAX_OUR_PXE_IX VEND_PXE_BOOT_ITEM_IX // largest PXE option index
+//
+// define various types by options that are sent
+//
+#define WfM11a_OPTS ((1<<VEND_PXE_MTFTP_IP_IX) | \
+ (1<<VEND_PXE_MTFTP_CPORT_IX) | \
+ (1<<VEND_PXE_MTFTP_SPORT_IX) | \
+ (1<<VEND_PXE_MTFTP_TMOUT_IX) | \
+ (1<<VEND_PXE_MTFTP_DELAY_IX))
+
+#define DISCOVER_OPTS ((1<<VEND_PXE_DISCOVERY_CONTROL_IX) | \
+ (1<<VEND_PXE_DISCOVERY_MCAST_ADDR_IX) | \
+ (1<<VEND_PXE_BOOT_SERVERS_IX) | \
+ (1<<VEND_PXE_BOOT_MENU_IX) | \
+ (1<<VEND_PXE_BOOT_PROMPT_IX) | \
+ (1<<VEND_PXE_BOOT_ITEM_IX))
+
+#define CREDENTIALS_OPT (1 << VEND_PXE_CREDENTIAL_TYPES_IX)
+
+//
+// definitions of indices to populate option interest array
+//
+#define OP_SUBNET_MASK_IX 1
+#define OP_TIME_OFFSET_IX 0 // not used by PXE client
+#define OP_ROUTER_LIST_IX 2
+#define OP_TIME_SERVERS_IX 0 // not used by PXE client
+#define OP_NAME_SERVERS_IX 0 // not used by PXE client
+#define OP_DNS_SERVERS_IX 0 // not used by PXE client
+#define OP_LOG_SERVERS_IX 0 // not used by PXE client
+#define OP_COOKIE_SERVERS_IX 0 // not used by PXE client
+#define OP_LPR_SREVERS_IX 0 // not used by PXE client
+#define OP_IMPRESS_SERVERS_IX 0 // not used by PXE client
+#define OP_RES_LOC_SERVERS_IX 0 // not used by PXE client
+#define OP_HOST_NAME_IX 0 // not used by PXE client
+#define OP_BOOT_FILE_SZ_IX 9
+#define OP_DUMP_FILE_IX 0 // not used by PXE client
+#define OP_DOMAIN_NAME_IX 0 // not used by PXE client
+#define OP_SWAP_SERVER_IX 0 // not used by PXE client
+#define OP_ROOT_PATH_IX 0 // not used by PXE client
+#define OP_EXTENSION_PATH_IX 0 // not used by PXE client
+#define OP_IP_FORWARDING_IX 0 // not used by PXE client
+#define OP_NON_LOCAL_SRC_RTE_IX 0 // not used by PXE client
+#define OP_POLICY_FILTER_IX 0 // not used by PXE client
+#define OP_MAX_DATAGRAM_SZ_IX 0 // not used by PXE client
+#define OP_DEFAULT_TTL_IX 0 // not used by PXE client
+#define OP_MTU_AGING_TIMEOUT_IX 0 // not used by PXE client
+#define OP_MTU_SIZES_IX 0 // not used by PXE client
+#define OP_MTU_TO_USE_IX 0 // not used by PXE client
+#define OP_ALL_SUBNETS_LOCAL_IX 0 // not used by PXE client
+#define OP_BROADCAST_ADD_IX 0 // not used by PXE client
+#define OP_PERFORM_MASK_DISCOVERY_IX 0 // not used by PXE client
+#define OP_RESPOND_TO_MASK_REQ_IX 0 // not used by PXE client
+#define OP_PERFORM_ROUTER_DISCOVERY_IX 0 // not used by PXE client
+#define OP_ROUTER_SOLICIT_ADDRESS_IX 0 // not used by PXE client
+#define OP_STATIC_ROUTER_LIST_IX 0 // not used by PXE client
+#define OP_USE_ARP_TRAILERS_IX 0 // not used by PXE client
+#define OP_ARP_CACHE_TIMEOUT_IX 0 // not used by PXE client
+#define OP_ETHERNET_ENCAPSULATION_IX 0 // not used by PXE client
+#define OP_TCP_DEFAULT_TTL_IX 0 // not used by PXE client
+#define OP_TCP_KEEP_ALIVE_INT_IX 0 // not used by PXE client
+#define OP_KEEP_ALIVE_GARBAGE_IX 0 // not used by PXE client
+#define OP_NIS_DOMAIN_NAME_IX 0 // not used by PXE client
+#define OP_NIS_SERVERS_IX 0 // not used by PXE client
+#define OP_NTP_SERVERS_IX 0 // not used by PXE client
+#define OP_VENDOR_SPECIFIC_IX 3
+#define OP_NBNS_SERVERS_IX 0 // not used by PXE client
+#define OP_NBDD_SERVERS_IX 0 // not used by PXE client
+#define OP_NETBIOS_NODE_TYPE_IX 0 // not used by PXE client
+#define OP_NETBIOS_SCOPE_IX 0 // not used by PXE client
+#define OP_XWINDOW_SYSTEM_FONT_SERVERS_IX 0 // not used by PXE client
+#define OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS_IX 0 // not used by PXE client
+// DHCP option indices
+//
+#define OP_DHCP_REQ_IP_ADD_IX 0 // not used by PXE client
+#define OP_DHCP_LEASE_TIME_IX 0 // not used by PXE client
+#define OP_DHCP_OPTION_OVERLOAD_IX 4
+#define OP_DHCP_MESSAGE_TYPE_IX 5
+#define OP_DHCP_SERVER_IP_IX 6
+#define OP_DHCP_PARM_REQ_LIST_IX 0 // not used by PXE client
+#define OP_DHCP_ERROR_MESSAGE_IX 0 // not used by PXE client
+#define OP_DHCP_MAX_MESSAGE_SZ_IX 0 // not used by PXE client
+#define OP_DHCP_RENEWAL_TIME_IX 0 // not used by PXE client
+#define OP_DHCP_REBINDING_TIME_IX 0 // not used by PXE client
+#define OP_DHCP_CLASS_IDENTIFIER_IX 7
+#define OP_DHCP_CLIENT_IDENTIFIER_IX 0 // not used by PXE client
+#define OP_RESERVED62_IX 0 // not used by PXE client
+#define OP_RESERVED63_IX 0 // not used by PXE client
+#define OP_NISPLUS_DOMAIN_NAME_IX 0 // not used by PXE client
+#define OP_NISPLUS_SERVERS_IX 0 // not used by PXE client
+#define OP_DHCP_TFTP_SERVER_NAME_IX 0 // not used by PXE client
+#define OP_DHCP_BOOTFILE_IX 8
+
+#define MAX_OUR_OPT OP_DHCP_BOOTFILE // largest option in which we are interested
+#define MAX_OUR_IX OP_BOOT_FILE_SZ_IX
+
+typedef struct {
+ DHCPV4_OP_STRUCT *PktOptAdds[MAX_OUR_IX];
+ DHCPV4_OP_STRUCT *PxeOptAdds[MAX_OUR_PXE_IX];
+ UINT8 Status;
+} OPTION_POINTERS;
+
+typedef struct DhcpReceiveBufferStruct {
+ union {
+ UINT8 ReceiveBuffer[MAX_DHCP_MSG_SZ];
+ DHCPV4_STRUCT Dhcpv4;
+ } u;
+
+ OPTION_POINTERS OpAdds;
+} DHCP_RECEIVE_BUFFER;
+
+#define PXE_TYPE (1 << 0)
+#define WfM11a_TYPE (1 << 1)
+#define DISCOVER_TYPE (1 << 2)
+#define CREDENTIALS_TYPE (1 << 3)
+#define USE_THREE_BYTE (1 << 4)
+
+#endif // _DHCP_H
+
+/* EOF - dhcp.h */
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ PxeArch.c\r
+\r
+Abstract:\r
+ Defines PXE Arch type\r
+\r
+\r
+**/\r
+\r
+\r
+#include "PxeArch.h"\r
+\r
+UINT16 mSysArch = 0;\r
+\r
+UINT16\r
+GetSysArch (\r
+ VOID\r
+ )\r
+{\r
+ if (mSysArch == 0) {\r
+ //\r
+ // This is first call\r
+ // Assign to invalid value\r
+ //\r
+ mSysArch = 0xFFFF;\r
+\r
+ //\r
+ // We do not know what is EBC architecture.\r
+ // Maybe we can try to locate DebugSupport protocol to get ISA.\r
+ // TBD now.\r
+ //\r
+ }\r
+\r
+ return mSysArch;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 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:
+ PxeArch.h
+
+Abstract:
+ Defines PXE Arch type
+
+
+**/
+
+#ifndef _EFI_PXE_ARCH_H_
+#define _EFI_PXE_ARCH_H_
+
+//
+// warning #175: subscript out of range
+//
+#pragma warning (disable: 175)
+
+#define SYS_ARCH GetSysArch()
+
+UINT16
+GetSysArch (
+ VOID
+ );
+
+#endif
--- /dev/null
+/** @file
+
+Copyright (c) 2004, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ hton.h
+
+Abstract:
+ Byte swapping macros.
+
+
+**/
+
+#ifndef _HTON_H_
+#define _HTON_H_
+
+//
+// Only Intel order functions are defined at this time.
+//
+#define HTONS(v) (UINT16) ((((v) << 8) & 0xff00) + (((v) >> 8) & 0x00ff))
+
+#define HTONL(v) \
+ (UINT32) ((((v) << 24) & 0xff000000) + (((v) << 8) & 0x00ff0000) + (((v) >> 8) & 0x0000ff00) + (((v) >> 24) & 0x000000ff))
+
+#define HTONLL(v) swap64 (v)
+
+#define U8PTR(na) ((UINT8 *) &(na))
+
+#define NTOHS(ns) ((UINT16) (((*U8PTR (ns)) << 8) +*(U8PTR (ns) + 1)))
+
+#define NTOHL(ns) \
+ ((UINT32) (((*U8PTR (ns)) << 24) + ((*(U8PTR (ns) + 1)) << 16) + ((*(U8PTR (ns) + 2)) << 8) +*(U8PTR (ns) + 3)))
+
+#endif /* _HTON_H_ */
+
+/* EOF - hton.h */
--- /dev/null
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ PxeArch.h
+
+Abstract:
+ Defines PXE Arch type
+
+
+**/
+
+#ifndef _EFI_PXE_ARCH_H_
+#define _EFI_PXE_ARCH_H_
+
+#define SYS_ARCH 0x6
+
+#endif
--- /dev/null
+/** @file
+
+Copyright (c) 2004 - 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.
+
+
+**/
+
+#ifndef _IP_H_
+#define _IP_H_
+
+#include "hton.h"
+
+//
+// portability macros
+//
+#define UDP_FILTER_MASK (EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | \
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT | \
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP | \
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT | \
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER \
+ )
+
+#define PXE_BOOT_LAYER_MASK 0x7FFF
+#define PXE_BOOT_LAYER_INITIAL 0x0000
+#define PXE_BOOT_LAYER_CREDENTIAL_FLAG 0x8000
+#define MAX_BOOT_SERVERS 32
+
+//
+// macro to evaluate IP address as TRUE if it is a multicast IP address
+//
+#define IS_MULTICAST(ptr) ((*((UINT8 *) ptr) & 0xf0) == 0xe0)
+
+//
+// length macros
+//
+#define IP_ADDRESS_LENGTH(qp) (((qp)->UsingIpv6) ? sizeof (EFI_IPv6_ADDRESS) : sizeof (EFI_IPv4_ADDRESS))
+
+#define MAX_FRAME_DATA_SIZE 1488
+#define ALLOCATE_SIZE(X) (((X) + 7) & 0xfff8)
+#define MODE_ALLOCATE_SIZE ALLOCATE_SIZE (sizeof (EFI_PXE_BASE_CODE_MODE))
+#define BUFFER_ALLOCATE_SIZE (8192 + 512)
+#define ROUTER_ALLOCATE_SIZE ALLOCATE_SIZE ((sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY) * PXE_ROUTER_TABLE_SIZE))
+#define ARP_ALLOCATE_SIZE ALLOCATE_SIZE ((sizeof (EFI_PXE_BASE_CODE_ARP_ENTRY) * PXE_ARP_CACHE_SIZE))
+#define FILTER_ALLOCATE_SIZE ALLOCATE_SIZE ((sizeof (EFI_IP_ADDRESS) * PXE_IP_FILTER_SIZE))
+#define PXE_ARP_CACHE_SIZE 8
+#define PXE_ROUTER_TABLE_SIZE 8
+#define PXE_IP_FILTER_SIZE 8
+#define ICMP_ALLOCATE_SIZE ALLOCATE_SIZE (sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR))
+#define TFTP_ERR_ALLOCATE_SIZE ALLOCATE_SIZE (sizeof (EFI_PXE_BASE_CODE_TFTP_ERROR))
+
+//
+// DHCP discover/request packets are sent to this UDP port. ProxyDHCP
+// servers listen on this port for DHCP discover packets that have a
+// class identifier (option 60) with 'PXEClient' in the first 9 bytes.
+// Bootservers also listen on this port for PXE broadcast discover
+// requests from PXE clients.
+//
+#define DHCP_SERVER_PORT 67
+
+//
+// When DHCP, proxyDHCP and Bootservers respond to DHCP and PXE broadcast
+// discover requests by broadcasting the reply packet, the packet is
+// broadcast to this port.
+//
+#define DHCP_CLIENT_PORT 68
+
+//
+// TFTP servers listen for TFTP open requests on this port.
+//
+#define TFTP_OPEN_PORT 69
+
+//
+// proxyDHCP and Bootservers listen on this port for a PXE unicast and/or
+// multicast discover requests from PXE clients. A PXE discover request
+// looks like a DHCP discover or DHCP request packet.
+//
+#define PXE_DISCOVERY_PORT 4011
+
+//
+// This port is used by the PXE client/server protocol tests.
+//
+#define PXE_PORT_PXETEST_PORT 0x8080
+
+//
+// Definitions for Ethertype protocol numbers and interface types
+// Per RFC 1700,
+//
+#define PXE_PROTOCOL_ETHERNET_IP 0x0800
+#define PXE_PROTOCOL_ETHERNET_ARP 0x0806
+#define PXE_PROTOCOL_ETHERNET_RARP 0x8035
+
+#define PXE_IFTYPE_ETHERNET 0x01
+#define PXE_IFTYPE_TOKENRING 0x04
+#define PXE_IFTYPE_FIBRE_CHANNEL 0x12
+
+//
+// Definitions for internet protocol version 4 header
+// Per RFC 791, September 1981.
+//
+#define IPVER4 4
+
+#pragma pack(1) // make network structures packed byte alignment
+typedef union {
+ UINT8 B[4];
+ UINT32 L;
+} IPV4_ADDR;
+
+#define IPV4_HEADER_LENGTH(IpHeaderPtr) (((IpHeaderPtr)->VersionIhl & 0xf) << 2)
+
+#define SET_IPV4_VER_HDL(IpHeaderPtr, IpHeaderLen) { \
+ (IpHeaderPtr)->VersionIhl = (UINT8) ((IPVER4 << 4) | ((IpHeaderLen) >> 2)); \
+ }
+
+typedef struct {
+ UINT8 VersionIhl;
+ UINT8 TypeOfService;
+ UINT16 TotalLength;
+ UINT16 Id;
+ UINT16 FragmentFields;
+ UINT8 TimeToLive;
+ UINT8 Protocol;
+ UINT16 HeaderChecksum;
+ IPV4_ADDR SrcAddr;
+ IPV4_ADDR DestAddr;
+ //
+ // options are not implemented
+ //
+} IPV4_HEADER;
+
+#define IP_FRAG_RSVD 0x8000 // reserved bit - must be zero
+#define IP_NO_FRAG 0x4000 // do not fragment bit
+#define IP_MORE_FRAG 0x2000 // not last fragment
+#define IP_FRAG_OFF_MSK 0x1fff // fragment offset in 8 byte chunks
+#define DEFAULT_RFC_TTL 64
+
+#define PROT_ICMP 1
+#define PROT_IGMP 2
+#define PROT_TCP 6
+#define PROT_UDP 17
+
+/*
+ * Definitions for internet control message protocol version 4 message
+ * structure. Per RFC 792, September 1981.
+ */
+
+//
+// icmp header for all icmp messages
+//
+typedef struct {
+ UINT8 Type; // message type
+ UINT8 Code; // type specific - 0 for types we implement
+ UINT16 Checksum; // ones complement of ones complement sum of 16 bit words of message
+} ICMPV4_HEADER;
+
+#define ICMP_DEST_UNREACHABLE 3
+#define ICMP_SOURCE_QUENCH 4
+#define ICMP_REDIRECT 5
+#define ICMP_ECHO 8
+#define ICMP_ECHO_REPLY 0
+#define ICMP_ROUTER_ADV 9
+#define ICMP_ROUTER_SOLICIT 10
+#define ICMP_TIME_EXCEEDED 11
+#define ICMP_PARAMETER_PROBLEM 12
+#define ICMP_TIMESTAMP 13
+#define ICMP_TIMESTAMP_REPLY 14
+#define ICMP_INFO_REQ 15
+#define ICMP_INFO_REQ_REPLY 16
+#define ICMP_SUBNET_MASK_REQ 17
+#define ICMP_SUBNET_MASK_REPLY 18
+//
+// other ICMP message types ignored in this implementation
+//
+// icmp general messages
+//
+typedef struct {
+ ICMPV4_HEADER Header;
+ //
+ // generally unused except byte [0] for
+ // parameter problem message
+ //
+ UINT8 GenerallyUnused[4];
+ //
+ // original message ip header of plus 64
+ // bits of data
+ //
+ IPV4_HEADER IpHeader;
+} ICMPV4_GENERAL_MESSAGE;
+
+//
+// icmp req/rply message header
+//
+typedef struct {
+ ICMPV4_HEADER Header;
+ UINT16 Id;
+ UINT16 SequenceNumber;
+} ICMPV4_REQUEST_REPLY_HEADER;
+
+//
+// icmp echo message
+//
+typedef struct {
+ ICMPV4_REQUEST_REPLY_HEADER Header;
+ UINT8 EchoData[1]; // variable length data to be echoed
+} ICMPV4_ECHO_MESSAGE;
+
+//
+// icmp timestamp message - times are milliseconds since midnight UT -
+// if non std, set high order bit
+//
+typedef struct {
+ ICMPV4_REQUEST_REPLY_HEADER Header;
+ UINT32 OriginalTime; // originating timestamp
+ UINT32 ReceiveTime; // receiving timestamp
+ UINT32 TransmitTime; // transmitting timestamp
+} ICMPV4_TIMESTAMP_MESSAGE;
+
+//
+// icmp info request structure - fill in source and dest net ip address on reply
+//
+typedef struct {
+ ICMPV4_REQUEST_REPLY_HEADER Header;
+} ICMPV4_INFO_MESSAGE;
+
+//
+// Definitions for internet control message protocol version 4 message structure
+// Router discovery
+// Per RFC 1256, September 1991.
+//
+//
+// icmp router advertisement message
+//
+typedef struct {
+ ICMPV4_HEADER Header;
+ UINT8 NumberEntries; // number of address entries
+ UINT8 EntrySize; // number of 32 bit words per address entry
+ UINT16 Lifetime; // seconds to consider info valid
+ UINT32 RouterIp;
+ UINT32 Preferance;
+} ICMPV4_ROUTER_ADVERTISE_MESSAGE;
+
+//
+// icmp router solicitation message
+//
+typedef struct {
+ ICMPV4_HEADER Header;
+ UINT32 Reserved;
+} ICMPV4_ROUTER_SOLICIT_MESSAGE;
+
+#define MAX_SOLICITATION_DELAY 1 // 1 second
+#define SOLICITATION_INTERVAL 3 // 3 seconds
+#define MAX_SOLICITATIONS 3 // 3 transmissions
+#define V1ROUTER_PRESENT_TIMEOUT 400 // 400 second timeout until v2 reports can be sent
+#define UNSOLICITED_REPORT_INTERVAL 10 // 10 seconds between unsolicited reports
+#define BROADCAST_IPv4 0xffffffff
+
+//
+// Definitions for address resolution protocol message structure
+// Per RFC 826, November 1982
+//
+typedef struct {
+ UINT16 HwType; // hardware type - e.g. ethernet (1)
+ UINT16 ProtType; // protocol type - for ethernet, 0x800 for IP
+ UINT8 HwAddLen; // byte length of a hardware address (e.g. 6 for ethernet)
+ UINT8 ProtAddLen; // byte length of a protocol address (e.g. 4 for ipv4)
+ UINT16 OpCode;
+ //
+ // source and dest hw and prot addresses follow - see example below
+ //
+} ARP_HEADER;
+
+#define ETHERNET_ADD_SPC 1
+
+#define ETHER_TYPE_IP 0x800
+
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+
+//
+// generic ARP packet
+//
+typedef struct {
+ ARP_HEADER ArpHeader;
+ EFI_MAC_ADDRESS SrcHardwareAddr;
+ EFI_IP_ADDRESS SrcProtocolAddr;
+ EFI_MAC_ADDRESS DestHardwareAddr;
+ EFI_IP_ADDRESS DestProtocolAddr;
+} ARP_PACKET;
+
+#define ENET_HWADDLEN 6
+#define IPV4_PROTADDLEN 4
+
+//
+// Definitions for user datagram protocol version 4 pseudo header & header
+// Per RFC 768, 28 August 1980
+//
+typedef struct {
+ IPV4_ADDR SrcAddr; // source ip address
+ IPV4_ADDR DestAddr; // dest ip address
+ UINT8 Zero; // 0
+ UINT8 Protocol; // protocol
+ UINT16 TotalLength; // UDP length - sizeof udpv4hdr + data length
+} UDPV4_PSEUDO_HEADER;
+
+typedef struct {
+ UINT16 SrcPort; // source port identifier
+ UINT16 DestPort; // destination port identifier
+ UINT16 TotalLength; // total length header plus data
+ //
+ // ones complement of ones complement sum of 16 bit
+ // words of pseudo header, UDP header, and data
+ // zero checksum is transmitted as -0 (ones comp)
+ // zero transmitted means checksum not computed
+ // data follows
+ //
+ UINT16 Checksum;
+} UDPV4_HEADER;
+
+typedef struct {
+ UDPV4_PSEUDO_HEADER Udpv4PseudoHeader;
+ UDPV4_HEADER Udpv4Header;
+} UDPV4_HEADERS;
+
+//
+// Definitions for transmission control protocol header
+// Per RFC 793, September, 1981
+//
+typedef struct {
+ IPV4_ADDR SrcAddr; // source ip address
+ IPV4_ADDR DestAddr; // dest ip address
+ UINT8 Zero; // 0
+ UINT8 Protocol; // protocol
+ UINT16 TotalLength; // TCP length - TCP header length + data length
+} TCPV4_PSEUDO_HEADER;
+
+typedef struct {
+ UINT16 SrcPort; // source port identifier
+ UINT16 DestPort; // destination port identifier
+ UINT32 SeqNumber; // Sequence number
+ UINT32 AckNumber; // Acknowledgement Number
+ //
+ // Nibble of HLEN (length of header in 32-bit multiples)
+ // 6bits of RESERVED
+ // Nibble of Code Bits
+ //
+ UINT16 HlenResCode;
+ UINT16 Window; // Software buffer size (sliding window size) in network-standard byte order
+ //
+ // ones complement of ones complement sum of 16 bit words of
+ // pseudo header, TCP header, and data
+ // zero checksum is transmitted as -0 (ones comp)
+ // zero transmitted means checksum not computed
+ //
+ UINT16 Checksum;
+ UINT16 UrgentPointer; // pointer to urgent data (allows sender to specify urgent data)
+} TCPV4_HEADER;
+
+typedef struct {
+ TCPV4_PSEUDO_HEADER Tcpv4PseudoHeader;
+ TCPV4_HEADER Tcpv4Header;
+} TCPV4_HEADERS;
+
+typedef struct {
+ UINT8 Kind; // one of the following:
+ UINT8 Length; // total option length including Kind and Lth
+ UINT8 Data[1]; // length = Lth - 2
+} TCPV4_OPTION;
+
+#define TCP_OP_END 0 // only used to pad to end of TCP header
+#define TCP_NOP 1 // optional - may be used to pad between options to get alignment
+#define TCP_MAX_SEG 2 // maximum receive segment size - only send at initial connection request
+#define MAX_MEDIA_HDR_SIZE 64
+#define MIN_ENET_DATA_SIZE 64
+#define MAX_ENET_DATA_SIZE 1500 // temp def - make a network based var
+#define MAX_IPV4_PKT_SIZE 65535 // maximum IP packet size
+#define MAX_IPV4_DATA_SIZE (MAX_IPV4_PKT_SIZE - sizeof (IPV4_HEADER))
+#define MAX_IPV4_FRAME_DATA_SIZE (MAX_FRAME_DATA_SIZE - sizeof (IPV4_HEADER))
+#define REAS_IPV4_PKT_SIZE 576 // minimum IP packet size all IP host can handle
+#define REAS_IPV4_DATA_SIZE (REAS_IPV4_PKT_SIZE - sizeof (IPV4_HEADER))
+
+//
+//
+//
+typedef union {
+ UINT8 Data[MAX_ENET_DATA_SIZE];
+ ICMPV4_HEADER IcmpHeader;
+ IGMPV2_MESSAGE IgmpMessage;
+ struct {
+ UDPV4_HEADER UdpHeader;
+ UINT8 Data[1];
+ } Udp;
+ struct {
+ TCPV4_HEADER TcpHeader;
+ UINT8 Data[1];
+ } Tcp;
+} PROTOCOL_UNION;
+
+//
+// out buffer structure
+//
+typedef struct {
+ UINT8 MediaHeader[MAX_MEDIA_HDR_SIZE];
+ IPV4_HEADER IpHeader;
+ //
+ // following union placement only valid if no option IP header
+ //
+ PROTOCOL_UNION u;
+} IPV4_BUFFER;
+
+typedef struct {
+ IPV4_HEADER IpHeader;
+ //
+ // following union placement only valid if no option IP header
+ //
+ PROTOCOL_UNION u;
+} IPV4_STRUCT;
+
+#pragma pack() // reset to default
+
+ ////////////////////////////////////////////////////////////
+//
+// BC IP Filter Routine
+//
+EFI_STATUS
+IpFilter (
+ PXE_BASECODE_DEVICE *Private,
+ IN EFI_PXE_BASE_CODE_IP_FILTER *Filter
+ )
+;
+
+//
+// //////////////////////////////////////////////////////////////////////
+//
+// Udp Write Routine - called by base code - e.g. TFTP - already locked
+//
+EFI_STATUS
+UdpWrite (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN UINT16 OpFlags,
+ IN EFI_IP_ADDRESS *DestIpPtr,
+ IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortptr,
+ IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL
+ IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL
+ IN UINTN *HeaderSizePtr, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN UINTN *BufferSizePtr,
+ IN VOID *BufferPtr
+ )
+;
+
+//
+// /////////////////////////////////////////////////////////////////////
+//
+// Udp Read Routine - called by base code - e.g. TFTP - already locked
+//
+EFI_STATUS
+UdpRead (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN UINT16 OpFlags,
+ IN OUT EFI_IP_ADDRESS *DestIpPtr, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPorPtrt, OPTIONAL
+ IN OUT EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL
+ IN UINTN *HeaderSizePtr, OPTIONAL
+ IN VOID *HeaderPtr, OPTIONAL
+ IN OUT UINTN *BufferSizePtr,
+ IN VOID *BufferPtr,
+ IN EFI_EVENT TimeoutEvent
+ )
+;
+
+VOID
+IgmpLeaveGroup (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *
+ )
+;
+
+VOID
+IgmpJoinGroup (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *
+ )
+;
+
+//
+// convert number to zero filled ascii value of length lth
+//
+VOID
+CvtNum (
+ UINTN Number,
+ UINT8 *BufferPtr,
+ INTN BufferLen
+ )
+;
+
+//
+// convert number to ascii string at ptr
+//
+VOID
+UtoA10 (
+ UINTN Number,
+ UINT8 *BufferPtr
+ )
+;
+
+//
+// convert ascii numeric string to UINTN
+//
+UINTN
+AtoU (
+ UINT8 *BufferPtr
+ )
+;
+
+UINT64
+AtoU64 (
+ UINT8 *BufferPtr
+ )
+;
+
+//
+// calculate the internet checksum (RFC 1071)
+// return 16 bit ones complement of ones complement sum of 16 bit words
+//
+UINT16
+IpChecksum (
+ UINT16 *MessagePtr,
+ UINTN ByteLength
+ )
+;
+
+//
+// do checksum on non contiguous header and data
+//
+UINT16
+IpChecksum2 (
+ UINT16 *Header,
+ UINTN HeaderLength,
+ UINT16 *Message,
+ UINTN MessageLength
+ )
+;
+
+//
+// update checksum when only a single word changes
+//
+UINT16
+UpdateChecksum (
+ UINT16 OldChecksum,
+ UINT16 OldWord,
+ UINT16 NewWord
+ )
+;
+
+VOID
+SeedRandom (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN UINT16 InitialSeed
+ )
+;
+
+UINT16
+Random (
+ IN PXE_BASECODE_DEVICE *Private
+ )
+;
+
+EFI_STATUS
+SendPacket (
+ PXE_BASECODE_DEVICE *Private,
+ VOID *HeaderPtr,
+ VOID *PacketPtr,
+ INTN PacketLength,
+ VOID *HardwareAddress,
+ UINT16 MediaProtocol,
+ IN EFI_PXE_BASE_CODE_FUNCTION Function
+ )
+;
+
+VOID
+HandleArpReceive (
+ PXE_BASECODE_DEVICE *Private,
+ ARP_PACKET *ArpPacketPtr,
+ VOID *HeaderPtr
+ )
+;
+
+VOID
+HandleIgmp (
+ PXE_BASECODE_DEVICE *Private,
+ IGMPV2_MESSAGE *IgmpMessageptr,
+ UINTN IgmpMessageLen
+ )
+;
+
+VOID
+IgmpCheckTimers (
+ PXE_BASECODE_DEVICE *Private
+ )
+; // poll when doing a receive
+// return hw add of IP and TRUE if available, otherwise FALSE
+//
+BOOLEAN
+GetHwAddr (
+ IN PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *ProtocolAddressPtr,
+ EFI_MAC_ADDRESS *HardwareAddressPtr
+ )
+;
+
+EFI_STATUS
+DoArp (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN EFI_IP_ADDRESS *ProtocolAddressPtr,
+ OUT EFI_MAC_ADDRESS *HardwareAddressptr
+ )
+;
+
+BOOLEAN
+OnSameSubnet (
+ UINTN IpAddressLen,
+ EFI_IP_ADDRESS *Ip1,
+ EFI_IP_ADDRESS *Ip2,
+ EFI_IP_ADDRESS *SubnetMask
+ )
+;
+
+VOID
+IpAddRouter (
+ PXE_BASECODE_DEVICE *Private,
+ EFI_IP_ADDRESS *RouterIp
+ )
+;
+
+#define Ip4AddRouter(Private, Ipv4Ptr) IpAddRouter (Private, (EFI_IP_ADDRESS *) Ipv4Ptr)
+
+//
+// routine to send ipv4 packet
+// ipv4 + upper protocol header for length TotHdrLth in xmtbuf, ipv4 header length IpHdrLth
+// routine fills in ipv4hdr Ver_Hdl, TotLth, and Checksum, moves in Data, and gets dest MAC address
+//
+EFI_STATUS
+Ipv4Xmt (
+ PXE_BASECODE_DEVICE *Private,
+ UINT32 GatewayIP,
+ UINTN IpHeaderLen,
+ UINTN TotalHeaderLen,
+ VOID *Data,
+ UINTN DataLen,
+ EFI_PXE_BASE_CODE_FUNCTION Function
+ )
+;
+
+//
+// send ipv4 packet with ipv4 option
+//
+EFI_STATUS
+Ipv4SendWOp (
+ PXE_BASECODE_DEVICE *Private,
+ UINT32 GatewayIP,
+ UINT8 *MessagePtr,
+ UINTN MessageLth,
+ UINT8 Protocol,
+ UINT8 *Option,
+ UINTN OptionLen,
+ UINT32 DestIp,
+ EFI_PXE_BASE_CODE_FUNCTION Function
+ )
+;
+
+//
+// send MsgLth message at MsgPtr - higher level protocol header already in xmtbuf, length HdrSize
+//
+EFI_STATUS
+Ip4Send (
+ IN PXE_BASECODE_DEVICE *Private, // pointer to instance data
+ IN UINTN MayFragment, //
+ IN UINT8 Protocol, // protocol
+ IN UINT32 SrcIp, // Source IP address
+ IN UINT32 DestIp, // Destination IP address
+ IN UINT32 GatewayIp, // used if not NULL and needed
+ IN UINTN HeaderSize, // protocol header byte length
+ IN UINT8 *MsgPtr, // pointer to data
+ IN UINTN MsgLength
+ )
+; // data byte length
+// receive up to MsgLth message into MsgPtr for protocol Prot
+// return message length, src/dest ips if select any, and pointer to protocol header
+//
+EFI_STATUS
+IpReceive (
+ IN PXE_BASECODE_DEVICE *Private, // pointer to instance data
+ UINT16 OpFlags, // Flags to determine if filtering on IP addresses
+ EFI_IP_ADDRESS *SrcIpPtr, // if filtering, O if accept any
+ EFI_IP_ADDRESS *DstIpPtr, // if filtering, O if accept any
+ UINT8 Protocol, // protocol
+ VOID *HeaderPtr, // address of where to put protocol header
+ UINTN HeaderSize, // protocol header byte length
+ UINT8 *MsgPtr, // pointer to data buffer
+ UINTN *MsgLenPtr, // pointer to data buffer length/ O - returned data length
+ IN EFI_EVENT TimeoutEvent
+ )
+;
+
+#if 0
+VOID
+WaitForTxComplete (
+ IN PXE_BASECODE_DEVICE *Private
+ )
+;
+#endif
+//
+// routine to cycle waiting for a receive or timeout
+//
+EFI_STATUS
+WaitForReceive (
+ IN PXE_BASECODE_DEVICE *Private,
+ IN EFI_PXE_BASE_CODE_FUNCTION Function,
+ IN EFI_EVENT TimeoutEvent,
+ IN OUT UINTN *HeaderSizePtr,
+ IN OUT UINTN *BufferSizePtr,
+ IN OUT UINT16 *ProtocolPtr
+ )
+;
+
+#endif /* _IP_H_ */
+
+/* EOF - ip.h */
--- /dev/null
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ PxeArch.h
+
+Abstract:
+ Defines PXE Arch type
+
+
+**/
+
+#ifndef _EFI_PXE_ARCH_H_
+#define _EFI_PXE_ARCH_H_
+
+#define SYS_ARCH 0x2
+
+#endif
--- /dev/null
+#/** @file\r
+# Component name for module BC\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 = PxeBcDxe\r
+ FILE_GUID = A3f436EA-A127-4EF8-957C-8048606FF670\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ EDK_RELEASE_VERSION = 0x00020000\r
+ EFI_SPECIFICATION_VERSION = 0x00020000\r
+\r
+ ENTRY_POINT = InitializeBCDriver\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
+ Pxe_bc_mtftp.c\r
+ Bc.c\r
+ Dhcp.h\r
+ Ip.h\r
+ Pxe_bc_ip.c\r
+ Pxe_bc_dhcp.c\r
+ Pxe_bc_arp.c\r
+ Hton.h\r
+ ComponentName.c\r
+ Bc.h\r
+ Pxe_loadfile.c\r
+ Tftp.h\r
+ Pxe_bc_igmp.c\r
+ Pxe_bc_udp.c\r
+\r
+[Sources.IA32]\r
+ Ia32\PxeArch.h\r
+\r
+[Sources.X64]\r
+ X64\PxeArch.h\r
+\r
+[Sources.IPF]\r
+ Ipf\PxeArch.h\r
+\r
+[Sources.EBC]\r
+ Ebc\PxeArch.h\r
+ Ebc\PxeArch.c\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ UefiLib\r
+ BaseLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ BaseMemoryLib\r
+ DebugLib\r
+\r
+\r
+[Guids]\r
+ gEfiSmbiosTableGuid # ALWAYS_CONSUMED\r
+\r
+\r
+[Protocols]\r
+ gEfiBisProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiPxeBaseCodeCallbackProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiPxeBaseCodeProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiLoadFileProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiNetworkInterfaceIdentifierProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiTcpProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiNetworkInterfaceIdentifierProtocolGuid_31 # PROTOCOL ALWAYS_CONSUMED\r
+\r
--- /dev/null
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+ <MsaHeader>\r
+ <ModuleName>BC</ModuleName>\r
+ <ModuleType>DXE_DRIVER</ModuleType>\r
+ <GuidValue>A3f436EA-A127-4EF8-957C-8048606FF670</GuidValue>\r
+ <Version>1.0</Version>\r
+ <Abstract>Component name for module BC</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>BC</OutputFileBasename>\r
+ </ModuleDefinitions>\r
+ <LibraryClassDefinitions>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>DebugLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>BaseMemoryLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiDriverEntryPoint</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiBootServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>BaseLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiLib</Keyword>\r
+ </LibraryClass>\r
+ </LibraryClassDefinitions>\r
+ <SourceFiles>\r
+ <Filename>pxe_bc_udp.c</Filename>\r
+ <Filename>pxe_bc_igmp.c</Filename>\r
+ <Filename>tftp.h</Filename>\r
+ <Filename>pxe_loadfile.c</Filename>\r
+ <Filename>bc.h</Filename>\r
+ <Filename>ComponentName.c</Filename>\r
+ <Filename>BcEntry.c</Filename>\r
+ <Filename>ipf\PxeArch.h</Filename>\r
+ <Filename>ebc\PxeArch.h</Filename>\r
+ <Filename SupArchList="X64">x64\PxeArch.h</Filename>\r
+ <Filename>pxe_bc_tcp.c</Filename>\r
+ <Filename>hton.h</Filename>\r
+ <Filename>pxe_bc_arp.c</Filename>\r
+ <Filename>pxe_bc_dhcp.c</Filename>\r
+ <Filename>pxe_bc_ip.c</Filename>\r
+ <Filename>ip.h</Filename>\r
+ <Filename>dhcp.h</Filename>\r
+ <Filename>bc.c</Filename>\r
+ <Filename>pxe_bc_mtftp.c</Filename>\r
+ <Filename>ia32\PxeArch.h</Filename>\r
+ <Filename>ebc\PxeArch.c</Filename>\r
+ </SourceFiles>\r
+ <PackageDependencies>\r
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+ </PackageDependencies>\r
+ <Protocols>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiNetworkInterfaceIdentifierProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiLoadFileProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiPxeBaseCodeProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiPxeBaseCodeCallbackProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiBisProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ </Protocols>\r
+ <Guids>\r
+ <GuidCNames Usage="ALWAYS_CONSUMED">\r
+ <GuidCName>gEfiSmbiosTableGuid</GuidCName>\r
+ </GuidCNames>\r
+ </Guids>\r
+ <Externs>\r
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+ <Extern>\r
+ <ModuleEntryPoint>InitializeBCDriver</ModuleEntryPoint>\r
+ </Extern>\r
+ </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
--- /dev/null
+/** @file\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
+ pxe_bc_arp.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Bc.h"\r
+\r
+//\r
+// Definitions for ARP\r
+// Per RFC 826\r
+//\r
+STATIC ARP_HEADER ArpHeader;\r
+\r
+#pragma pack(1)\r
+STATIC struct {\r
+ UINT8 MediaHeader[14];\r
+ ARP_HEADER ArpHeader;\r
+ UINT8 ArpData[64];\r
+} ArpReplyPacket;\r
+#pragma pack()\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return none\r
+\r
+**/\r
+VOID\r
+InitArpHeader (\r
+ VOID\r
+ )\r
+{\r
+ ArpHeader.HwType = HTONS (ETHERNET_ADD_SPC);\r
+ ArpHeader.ProtType = HTONS (ETHER_TYPE_IP);\r
+ ArpHeader.HwAddLen = ENET_HWADDLEN;\r
+ ArpHeader.ProtAddLen = IPV4_PROTADDLEN;\r
+ ArpHeader.OpCode = HTONS (ARP_REQUEST);\r
+\r
+ CopyMem (&ArpReplyPacket.ArpHeader, &ArpHeader, sizeof (ARP_HEADER));\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+VOID\r
+HandleArpReceive (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN ARP_PACKET *ArpPacketPtr,\r
+ IN VOID *MediaHeader\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+ EFI_MAC_ADDRESS TmpMacAddr;\r
+ UINTN Index;\r
+ UINT8 *SrcHwAddr;\r
+ UINT8 *SrcPrAddr;\r
+ UINT8 *DstHwAddr;\r
+ UINT8 *DstPrAddr;\r
+ UINT8 *TmpPtr;\r
+\r
+ //\r
+ //\r
+ //\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+ SnpMode = Private->SimpleNetwork->Mode;\r
+\r
+ //\r
+ // For now only ethernet addresses are supported.\r
+ // This will need to be updated when other media\r
+ // layers are supported by PxeBc, Snp and UNDI.\r
+ //\r
+ if (ArpPacketPtr->ArpHeader.HwType != HTONS (ETHERNET_ADD_SPC)) {\r
+ return ;\r
+ }\r
+ //\r
+ // For now only IP protocol addresses are supported.\r
+ // This will need to be updated when other protocol\r
+ // types are supported by PxeBc, Snp and UNDI.\r
+ //\r
+ if (ArpPacketPtr->ArpHeader.ProtType != HTONS (ETHER_TYPE_IP)) {\r
+ return ;\r
+ }\r
+ //\r
+ // For now only SNP hardware address sizes are supported.\r
+ //\r
+ if (ArpPacketPtr->ArpHeader.HwAddLen != SnpMode->HwAddressSize) {\r
+ return ;\r
+ }\r
+ //\r
+ // For now only PxeBc protocol address sizes are supported.\r
+ //\r
+ if (ArpPacketPtr->ArpHeader.ProtAddLen != Private->IpLength) {\r
+ return ;\r
+ }\r
+ //\r
+ // Ignore out of range opcodes\r
+ //\r
+ switch (ArpPacketPtr->ArpHeader.OpCode) {\r
+ case HTONS (ARP_REPLY):\r
+ case HTONS (ARP_REQUEST):\r
+ break;\r
+\r
+ default:\r
+ return ;\r
+ }\r
+ //\r
+ // update entry in our ARP cache if we have it\r
+ //\r
+ SrcHwAddr = (UINT8 *) &ArpPacketPtr->SrcHardwareAddr;\r
+ SrcPrAddr = SrcHwAddr + SnpMode->HwAddressSize;\r
+\r
+ for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) {\r
+ if (CompareMem (\r
+ &PxeBcMode->ArpCache[Index].IpAddr,\r
+ SrcPrAddr,\r
+ Private->IpLength\r
+ )) {\r
+ continue;\r
+ }\r
+\r
+ CopyMem (\r
+ &PxeBcMode->ArpCache[Index].MacAddr,\r
+ SrcHwAddr,\r
+ SnpMode->HwAddressSize\r
+ );\r
+\r
+ break;\r
+ }\r
+ //\r
+ // Done if ARP packet was not for us.\r
+ //\r
+ DstHwAddr = SrcPrAddr + Private->IpLength;\r
+ DstPrAddr = DstHwAddr + SnpMode->HwAddressSize;\r
+\r
+ if (CompareMem (DstPrAddr, &PxeBcMode->StationIp, Private->IpLength)) {\r
+ return ;\r
+ //\r
+ // not for us\r
+ //\r
+ }\r
+ //\r
+ // for us - if we did not update entry, add it\r
+ //\r
+ if (Index == PxeBcMode->ArpCacheEntries) {\r
+ //\r
+ // if we have a full table, get rid of oldest\r
+ //\r
+ if (Index == PXE_ARP_CACHE_SIZE) {\r
+ Index = Private->OldestArpEntry;\r
+\r
+ if (++Private->OldestArpEntry == PXE_ARP_CACHE_SIZE) {\r
+ Private->OldestArpEntry = 0;\r
+ }\r
+ } else {\r
+ ++PxeBcMode->ArpCacheEntries;\r
+ }\r
+\r
+ CopyMem (\r
+ &PxeBcMode->ArpCache[Index].MacAddr,\r
+ SrcHwAddr,\r
+ SnpMode->HwAddressSize\r
+ );\r
+\r
+ CopyMem (\r
+ &PxeBcMode->ArpCache[Index].IpAddr,\r
+ SrcPrAddr,\r
+ Private->IpLength\r
+ );\r
+ }\r
+ //\r
+ // if this is not a request or we don't yet have an IP, finished\r
+ //\r
+ if (ArpPacketPtr->ArpHeader.OpCode != HTONS (ARP_REQUEST) || !Private->GoodStationIp) {\r
+ return ;\r
+ }\r
+ //\r
+ // Assemble ARP reply.\r
+ //\r
+ //\r
+ // Create media header. [ dest mac | src mac | prot ]\r
+ //\r
+ CopyMem (\r
+ &ArpReplyPacket.MediaHeader[0],\r
+ SrcHwAddr,\r
+ SnpMode->HwAddressSize\r
+ );\r
+\r
+ CopyMem (\r
+ &ArpReplyPacket.MediaHeader[SnpMode->HwAddressSize],\r
+ &SnpMode->CurrentAddress,\r
+ SnpMode->HwAddressSize\r
+ );\r
+\r
+ CopyMem (\r
+ &ArpReplyPacket.MediaHeader[2 * SnpMode->HwAddressSize],\r
+ &((UINT8 *) MediaHeader)[2 * SnpMode->HwAddressSize],\r
+ sizeof (UINT16)\r
+ );\r
+\r
+ //\r
+ // ARP reply header is almost filled in,\r
+ // just insert the correct opcode.\r
+ //\r
+ ArpReplyPacket.ArpHeader.OpCode = HTONS (ARP_REPLY);\r
+\r
+ //\r
+ // Now fill in ARP data. [ src mac | src prot | dest mac | dest prot ]\r
+ //\r
+ TmpPtr = ArpReplyPacket.ArpData;\r
+ CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);\r
+\r
+ TmpPtr += SnpMode->HwAddressSize;\r
+ CopyMem (TmpPtr, &PxeBcMode->StationIp, Private->IpLength);\r
+\r
+ TmpPtr += Private->IpLength;\r
+ CopyMem (TmpPtr, SrcHwAddr, SnpMode->HwAddressSize);\r
+\r
+ TmpPtr += SnpMode->HwAddressSize;\r
+ CopyMem (TmpPtr, SrcPrAddr, Private->IpLength);\r
+\r
+ //\r
+ // Now send out the ARP reply.\r
+ //\r
+ CopyMem (&TmpMacAddr, SrcHwAddr, sizeof (EFI_MAC_ADDRESS));\r
+\r
+ SendPacket (\r
+ Private,\r
+ &ArpReplyPacket.MediaHeader,\r
+ &ArpReplyPacket.ArpHeader,\r
+ sizeof (ARP_HEADER) + 2 * (Private->IpLength + SnpMode->HwAddressSize),\r
+ &TmpMacAddr,\r
+ PXE_PROTOCOL_ETHERNET_ARP,\r
+ EFI_PXE_BASE_CODE_FUNCTION_ARP\r
+ );\r
+\r
+ //\r
+ // Give time (100 microseconds) for ARP reply to get onto wire.\r
+ //\r
+ gBS->Stall (1000);\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return TRUE := If IP address was found and MAC address was stored\r
+ @return FALSE := If IP address was not found\r
+\r
+**/\r
+BOOLEAN\r
+GetHwAddr (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN EFI_IP_ADDRESS *ProtocolAddrPtr,\r
+ OUT EFI_MAC_ADDRESS *HardwareAddrPtr\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ UINTN HardwareAddrLength;\r
+ UINTN Index;\r
+\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+ HardwareAddrLength = Private->SimpleNetwork->Mode->HwAddressSize;\r
+\r
+ for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) {\r
+ if (!CompareMem (\r
+ ProtocolAddrPtr,\r
+ &PxeBcMode->ArpCache[Index].IpAddr,\r
+ Private->IpLength\r
+ )) {\r
+ CopyMem (\r
+ HardwareAddrPtr,\r
+ &PxeBcMode->ArpCache[Index].MacAddr,\r
+ HardwareAddrLength\r
+ );\r
+\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return EFI_SUCCESS := ARP request sent\r
+ @return other := ARP request could not be sent\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+SendRequest (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN EFI_IP_ADDRESS *ProtocolAddrPtr,\r
+ IN EFI_MAC_ADDRESS *HardwareAddrPtr\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+ ARP_PACKET *ArpPacket;\r
+ EFI_STATUS Status;\r
+ UINTN HardwareAddrLength;\r
+ UINT8 *SrcProtocolAddrPtr;\r
+ UINT8 *DestHardwareAddrptr;\r
+ UINT8 *DestProtocolAddrPtr;\r
+\r
+ //\r
+ //\r
+ //\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+ SnpMode = Private->SimpleNetwork->Mode;\r
+ HardwareAddrLength = SnpMode->HwAddressSize;\r
+\r
+ //\r
+ // Allocate ARP buffer\r
+ //\r
+ if (Private->ArpBuffer == NULL) {\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ SnpMode->MediaHeaderSize + sizeof (ARP_PACKET),\r
+ &Private->ArpBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ ArpPacket = (VOID *) (Private->ArpBuffer + SnpMode->MediaHeaderSize);\r
+\r
+ //\r
+ // for now, only handle one kind of hw and pr address\r
+ //\r
+ ArpPacket->ArpHeader = ArpHeader;\r
+ ArpPacket->ArpHeader.HwAddLen = (UINT8) HardwareAddrLength;\r
+ ArpPacket->ArpHeader.ProtAddLen = (UINT8) Private->IpLength;\r
+\r
+ //\r
+ // rest more generic\r
+ //\r
+ SrcProtocolAddrPtr = (UINT8 *) (&ArpPacket->SrcHardwareAddr) + HardwareAddrLength;\r
+ DestHardwareAddrptr = SrcProtocolAddrPtr + Private->IpLength;\r
+ DestProtocolAddrPtr = DestHardwareAddrptr + HardwareAddrLength;\r
+\r
+ CopyMem (DestProtocolAddrPtr, ProtocolAddrPtr, Private->IpLength);\r
+ CopyMem (DestHardwareAddrptr, HardwareAddrPtr, HardwareAddrLength);\r
+ CopyMem (SrcProtocolAddrPtr, &PxeBcMode->StationIp, Private->IpLength);\r
+ CopyMem (\r
+ &ArpPacket->SrcHardwareAddr,\r
+ &SnpMode->CurrentAddress,\r
+ HardwareAddrLength\r
+ );\r
+\r
+ return SendPacket (\r
+ Private,\r
+ Private->ArpBuffer,\r
+ ArpPacket,\r
+ sizeof (ARP_HEADER) + ((Private->IpLength + HardwareAddrLength) << 1),\r
+ &SnpMode->BroadcastAddress,\r
+ PXE_PROTOCOL_ETHERNET_ARP,\r
+ EFI_PXE_BASE_CODE_FUNCTION_ARP\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// check for address - if not there, send ARP request, wait and check again\r
+// not how it would be done in a full system\r
+//\r
+#define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second\r
+\r
+ ////////////////////////////////////////////////////////////\r
+//\r
+// BC Arp Routine\r
+//\r
+\r
+/**\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcArp (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,\r
+ IN EFI_IP_ADDRESS * ProtocolAddrPtr,\r
+ OUT EFI_MAC_ADDRESS * HardwareAddrPtr OPTIONAL\r
+ )\r
+{\r
+ EFI_MAC_ADDRESS Mac;\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+\r
+ //\r
+ // Lock the instance data and make sure started\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ if (This->Mode == NULL || !This->Mode->Started) {\r
+ DEBUG ((DEBUG_ERROR, "BC was not started."));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "\nBcArp()"));\r
+\r
+ //\r
+ // Issue BC command\r
+ //\r
+ if (ProtocolAddrPtr == NULL) {\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nBcArp() Exit #1 %Xh (%r)",\r
+ EFI_INVALID_PARAMETER,\r
+ EFI_INVALID_PARAMETER)\r
+ );\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (HardwareAddrPtr == NULL) {\r
+ HardwareAddrPtr = &Mac;\r
+ }\r
+\r
+ ZeroMem (HardwareAddrPtr, Private->SimpleNetwork->Mode->HwAddressSize);\r
+\r
+ if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nBcArp() Exit #2 %Xh (%r)",\r
+ EFI_SUCCESS,\r
+ EFI_SUCCESS)\r
+ );\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ StatCode = DoArp (Private, ProtocolAddrPtr, HardwareAddrPtr);\r
+\r
+ DEBUG ((DEBUG_INFO, "\nBcArp() Exit #3 %Xh (%r)", StatCode, StatCode));\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return EFI_SUCCESS := MAC address found\r
+ @return other := MAC address could not be found\r
+\r
+**/\r
+EFI_STATUS\r
+DoArp (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN EFI_IP_ADDRESS *ProtocolAddrPtr,\r
+ OUT EFI_MAC_ADDRESS *HardwareAddrPtr\r
+ )\r
+{\r
+ EFI_STATUS StatCode;\r
+ EFI_EVENT TimeoutEvent;\r
+ UINTN HeaderSize;\r
+ UINTN BufferSize;\r
+ UINT16 Protocol;\r
+\r
+ DEBUG ((DEBUG_INFO, "\nDoArp()"));\r
+\r
+ //\r
+ //\r
+ //\r
+ StatCode = SendRequest (Private, ProtocolAddrPtr, HardwareAddrPtr);\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG ((DEBUG_INFO, "\nDoArp() Exit #1 %Xh (%r)", StatCode, StatCode));\r
+ return StatCode;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ StatCode = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ return StatCode;\r
+ }\r
+\r
+ StatCode = gBS->SetTimer (\r
+ TimeoutEvent,\r
+ TimerRelative,\r
+ ARP_REQUEST_TIMEOUT_MS * 10000\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return StatCode;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ for (;;) {\r
+ StatCode = WaitForReceive (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_FUNCTION_ARP,\r
+ TimeoutEvent,\r
+ &HeaderSize,\r
+ &BufferSize,\r
+ &Protocol\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ break;\r
+ }\r
+\r
+ if (Protocol != PXE_PROTOCOL_ETHERNET_ARP) {\r
+ continue;\r
+ }\r
+\r
+ HandleArpReceive (\r
+ Private,\r
+ (ARP_PACKET *) (Private->ReceiveBufferPtr + HeaderSize),\r
+ Private->ReceiveBufferPtr\r
+ );\r
+\r
+ if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nDoArp() Exit #2 %Xh, (%r)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+\r
+ gBS->CloseEvent (TimeoutEvent);\r
+\r
+ return StatCode;\r
+}\r
+\r
+/* eof - pxe_bc_arp.c */\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+ pxe_bc_dhcp.c\r
+\r
+Abstract:\r
+ DHCP and PXE discovery protocol implementations.\r
+\r
+\r
+**/\r
+\r
+#include "Bc.h"\r
+\r
+#include "PxeArch.h"\r
+\r
+STATIC EFI_PXE_BASE_CODE_UDP_PORT DhcpServerPort = DHCP_SERVER_PORT;\r
+STATIC EFI_PXE_BASE_CODE_UDP_PORT DHCPClientPort = DHCP_CLIENT_PORT;\r
+STATIC EFI_PXE_BASE_CODE_UDP_PORT PseudoDhcpServerPort = PXE_DISCOVERY_PORT;\r
+#define PSEUDO_DHCP_CLIENT_PORT PseudoDhcpServerPort\r
+STATIC EFI_IP_ADDRESS BroadcastIP = { 0xffffffff };\r
+STATIC EFI_IP_ADDRESS DefaultSubnetMask = { 0xffffff00 };\r
+\r
+typedef union {\r
+ DHCPV4_OP_STRUCT *OpPtr;\r
+ PXE_OP_SERVER_LIST *BootServersStr;\r
+ PXE_SERVER_LIST *BootServerList;\r
+ PXE_BOOT_MENU_ENTRY *BootMenuItem;\r
+ PXE_OP_DISCOVERY_CONTROL *DiscoveryControl;\r
+ PXE_OP_BOOT_MENU *BootMenu;\r
+ PXE_OP_BOOT_ITEM *BootItem;\r
+ DHCPV4_OP_VENDOR_OPTIONS *VendorOptions;\r
+ DHCPV4_OP_OVERLOAD *Overload;\r
+ DHCPV4_OP_CLASS *PxeClassStr;\r
+ DHCPV4_OP_SUBNET_MASK *SubnetMaskStr;\r
+ DHCPV4_OP_MESSAGE_TYPE *MessageType;\r
+ UINT8 *BytePtr;\r
+} UNION_PTR;\r
+\r
+#pragma pack(1)\r
+//\r
+// option structure for DHCPREQUEST at end of DISCOVER options\r
+// and for DHCPDECLINE\r
+//\r
+STATIC const struct requestopendstr {\r
+ DHCPV4_OP_REQUESTED_IP OpReqIP;\r
+ DHCPV4_OP_SERVER_IP DhcServerIpPtr;\r
+ UINT8 End[1];\r
+}\r
+RequestOpEndStr = {\r
+ {\r
+ {\r
+ OP_DHCP_REQ_IP_ADD,\r
+ DHCPV4_OPTION_LENGTH(DHCPV4_OP_REQUESTED_IP)\r
+ }\r
+ },\r
+ {\r
+ {\r
+ OP_DHCP_SERVER_IP,\r
+ DHCPV4_OPTION_LENGTH(DHCPV4_OP_SERVER_IP)\r
+ }\r
+ },\r
+ {\r
+ OP_END\r
+ }\r
+};\r
+\r
+#define DHCP_REQ_OPTIONS (*(struct requestopendstr *) DHCPV4_OPTIONS_BUFFER.End)\r
+\r
+PXE_OP_BOOT_ITEM DefaultBootItem = {\r
+ {\r
+ VEND_PXE_BOOT_ITEM,\r
+ DHCPV4_OPTION_LENGTH(PXE_OP_BOOT_ITEM)\r
+ },\r
+ 0,\r
+ 0\r
+};\r
+\r
+//\r
+// PXE discovery control default structure\r
+//\r
+STATIC PXE_OP_DISCOVERY_CONTROL DefaultDisCtl = {\r
+ { VEND_PXE_DISCOVERY_CONTROL, DHCPV4_OPTION_LENGTH(PXE_OP_DISCOVERY_CONTROL) },\r
+ 0\r
+};\r
+\r
+//\r
+// PXE credentials option structure\r
+//\r
+typedef struct {\r
+ UINT8 c[4];\r
+} PXE_CREDENTIAL;\r
+\r
+typedef struct {\r
+ DHCPV4_OP_HEADER Header;\r
+ PXE_CREDENTIAL Credentials[1];\r
+} PXE_OP_CREDENTIAL_TYPES;\r
+\r
+//\r
+// option structure for PXE discover (without credentials)\r
+//\r
+typedef struct { // discoveropendstr {\r
+ DHCPV4_OP_HEADER Header; // vendor options\r
+ PXE_OP_BOOT_ITEM BootItem;\r
+ UINT8 End[1]; // if credentials option, it starts here\r
+} PXE_DISCOVER_OPTIONS;\r
+\r
+#define DISCOVERoptions (*(PXE_DISCOVER_OPTIONS *) DHCPV4_OPTIONS_BUFFER.End)\r
+#define DISCREDoptions (*(PXE_OP_CREDENTIAL_TYPES *) DISCOVERoptions.End)\r
+\r
+//\r
+// common option beginning for all our DHCP messages except\r
+// DHCPDECLINE and DHCPRELEASE\r
+//\r
+STATIC struct optionsstr {\r
+ UINT8 DhcpCookie[4];\r
+ DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;\r
+ DHCPV4_OP_MAX_MESSAGE_SIZE DhcpMaxMessageSize;\r
+ DHCPV4_OP_REQUESTED_OPTIONS DhcpRequestedOptions;\r
+ DHCPV4_OP_PLATFORM_ID DhcpPlatformId;\r
+ DHCPV4_OP_NETWORK_INTERFACE DhcpNetworkInterface;\r
+ DHCPV4_OP_ARCHITECTURE_TYPE DhcpClientArchitecture;\r
+ DHCPV4_OP_CLASS_ID DhcpClassIdentifier;\r
+ UINT8 End[1];\r
+} DHCPOpStart;\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+VOID\r
+OptionsStrucInit (\r
+ VOID\r
+ )\r
+{\r
+ DHCPOpStart.DhcpCookie[0] = 99;\r
+ DHCPOpStart.DhcpCookie[1] = 130;\r
+ DHCPOpStart.DhcpCookie[2] = 83;\r
+ DHCPOpStart.DhcpCookie[3] = 99;\r
+ DHCPOpStart.DhcpMessageType.Header.OpCode = OP_DHCP_MESSAGE_TYPE;\r
+ DHCPOpStart.DhcpMessageType.Header.Length = 1;\r
+ DHCPOpStart.DhcpMessageType.Type = DHCPDISCOVER;\r
+ DHCPOpStart.DhcpMaxMessageSize.Header.OpCode = OP_DHCP_MAX_MESSAGE_SZ;\r
+ DHCPOpStart.DhcpMaxMessageSize.Header.Length = 2;\r
+ DHCPOpStart.DhcpMaxMessageSize.MaxSize[0] = MAX_DHCP_MSG_SZ >> 8;\r
+ DHCPOpStart.DhcpMaxMessageSize.MaxSize[1] = MAX_DHCP_MSG_SZ & 0xff;\r
+ DHCPOpStart.DhcpRequestedOptions.Header.OpCode = OP_DHCP_PARM_REQ_LIST;\r
+ DHCPOpStart.DhcpRequestedOptions.Header.Length = sizeof (DHCPV4_REQUESTED_OPTIONS_DATA);\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_SUBNET_MASK = OP_SUBNET_MASK; /* 1 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_OFFSET = OP_TIME_OFFSET; /* 2 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_ROUTER_LIST = OP_ROUTER_LIST; /* 3 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_TIME_SERVERS = OP_TIME_SERVERS; /* 4 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_NAME_SERVERS = OP_NAME_SERVERS; /* 5 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DNS_SERVERS = OP_DNS_SERVERS; /* 6 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_HOST_NAME = OP_HOST_NAME; /* 12 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_BOOT_FILE_SZ = OP_BOOT_FILE_SZ; /* 13 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DOMAIN_NAME = OP_DOMAIN_NAME; /* 15 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_ROOT_PATH = OP_ROOT_PATH; /* 17 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_EXTENSION_PATH = OP_EXTENSION_PATH; /* 18 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_MAX_DATAGRAM_SZ = OP_MAX_DATAGRAM_SZ; /* 22 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DEFAULT_TTL = OP_DEFAULT_TTL; /* 23 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_BROADCAST_ADD = OP_BROADCAST_ADD; /* 28 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_DOMAIN_NAME = OP_NIS_DOMAIN_NAME; /* 40 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_NIS_SERVERS = OP_NIS_SERVERS; /* 41 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_NTP_SERVERS = OP_NTP_SERVERS; /* 42 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_VENDOR_SPECIFIC = OP_VENDOR_SPECIFIC; /* 43 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REQ_IP_ADD = OP_DHCP_REQ_IP_ADD; /* 50 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_LEASE_TIME = OP_DHCP_LEASE_TIME; /* 51 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_SERVER_IP = OP_DHCP_SERVER_IP; /* 54 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_RENEWAL_TIME = OP_DHCP_RENEWAL_TIME; /* 58 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_REBINDING_TIME = OP_DHCP_REBINDING_TIME; /* 59 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_CLASS_IDENTIFIER = OP_DHCP_CLASS_IDENTIFIER; /* 60 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_TFTP_SERVER_NAME = OP_DHCP_TFTP_SERVER_NAME; /* 66 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_BOOTFILE = OP_DHCP_BOOTFILE; /* 67 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data._OP_DHCP_PLATFORM_ID = OP_DHCP_PLATFORM_ID; /* 97 */\r
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption128 = 128;\r
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption129 = 129;\r
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption130 = 130;\r
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption131 = 131;\r
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption132 = 132;\r
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption133 = 133, DHCPOpStart.DhcpRequestedOptions.Data.VendorOption134 = 134;\r
+ DHCPOpStart.DhcpRequestedOptions.Data.VendorOption135 = 135;\r
+ DHCPOpStart.DhcpPlatformId.Header.OpCode = OP_DHCP_PLATFORM_ID;\r
+ DHCPOpStart.DhcpPlatformId.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_PLATFORM_ID);\r
+ DHCPOpStart.DhcpNetworkInterface.Header.OpCode = OP_DHCP_NETWORK_ARCH;\r
+ DHCPOpStart.DhcpNetworkInterface.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_NETWORK_INTERFACE);\r
+ DHCPOpStart.DhcpNetworkInterface.Type = 0;\r
+ DHCPOpStart.DhcpNetworkInterface.MajorVersion = 0;\r
+ DHCPOpStart.DhcpNetworkInterface.MinorVersion = 0;\r
+ DHCPOpStart.DhcpClientArchitecture.Header.OpCode = OP_DHCP_SYSTEM_ARCH;\r
+ DHCPOpStart.DhcpClientArchitecture.Header.Length = DHCPV4_OPTION_LENGTH (DHCPV4_OP_ARCHITECTURE_TYPE);\r
+ DHCPOpStart.DhcpClientArchitecture.Type = HTONS (SYS_ARCH);\r
+ DHCPOpStart.DhcpClassIdentifier.Header.OpCode = OP_DHCP_CLASS_IDENTIFIER;\r
+ DHCPOpStart.DhcpClassIdentifier.Header.Length = sizeof (DHCPV4_CLASS_ID_DATA);\r
+ CopyMem (\r
+ DHCPOpStart.DhcpClassIdentifier.Data.ClassIdentifier,\r
+ "PXEClient:",\r
+ sizeof ("PXEClient:")\r
+ );\r
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit2, "Arch:", sizeof ("Arch:"));\r
+ CopyMem (\r
+ DHCPOpStart.DhcpClassIdentifier.Data.ArchitectureType,\r
+ "xxxxx",\r
+ sizeof ("xxxxx")\r
+ );\r
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit3, ":", sizeof (":"));\r
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.InterfaceName, "XXXX", sizeof ("XXXX"));\r
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.Lit4, ":", sizeof (":"));\r
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMajor, "yyy", sizeof ("yyy"));\r
+ CopyMem (DHCPOpStart.DhcpClassIdentifier.Data.UndiMinor, "xxx", sizeof ("xxx"));\r
+ DHCPOpStart.End[0] = OP_END;\r
+};\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// DHCPDECLINE option structure\r
+//\r
+struct opdeclinestr {\r
+ UINT8 DhcpCookie[4];\r
+ DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;\r
+ struct requestopendstr OpDeclineEnd;\r
+};\r
+\r
+#define DHCPDECLINEoptions (*(struct opdeclinestr *) DHCPV4_TRANSMIT_BUFFER.options)\r
+\r
+//\r
+// DHCPRELEASE option structure\r
+//\r
+struct opreleasestr {\r
+ UINT8 DhcpCookie[4];\r
+ DHCPV4_OP_MESSAGE_TYPE DhcpMessageType;\r
+ DHCPV4_OP_SERVER_IP DhcServerIpPtr;\r
+ UINT8 End[1];\r
+};\r
+\r
+#define DHCPRELEASEoptions (*(struct opreleasestr *) DHCPV4_TRANSMIT_BUFFER.options)\r
+\r
+//\r
+// array of PXE vendor options in which we are interested\r
+// value 0 -> not of interest, else value is index into PXE OPTION array\r
+// option values from 1 to MAX_OUR_PXE_OPT\r
+//\r
+STATIC UINT8 ourPXEopts[MAX_OUR_PXE_OPT] = {\r
+ VEND_PXE_MTFTP_IP_IX, // multicast IP address of bootfile for MTFTP listen\r
+ VEND_PXE_MTFTP_CPORT_IX, // UDP Port to monitor for MTFTP responses - Intel order\r
+ VEND_PXE_MTFTP_SPORT_IX, // Server UDP Port for MTFTP open - Intel order\r
+ VEND_PXE_MTFTP_TMOUT_IX, // Listen timeout - secs\r
+ VEND_PXE_MTFTP_DELAY_IX, // Transmission timeout - secs\r
+ VEND_PXE_DISCOVERY_CONTROL_IX, // bit field\r
+ VEND_PXE_DISCOVERY_MCAST_ADDR_IX, // boot server discovery multicast address\r
+ VEND_PXE_BOOT_SERVERS_IX, // list of boot servers of form tp(2) cnt(1) ips[cnt]\r
+ VEND_PXE_BOOT_MENU_IX,\r
+ VEND_PXE_BOOT_PROMPT_IX,\r
+ VEND_PXE_MCAST_ADDRS_ALLOC_IX, // not used by client\r
+ VEND_PXE_CREDENTIAL_TYPES_IX,\r
+ VEND_13_IX, // not used by client\r
+ VEND_14_IX, // not used by client\r
+ VEND_15_IX, // not used by client\r
+ VEND_16_IX, // not used by client\r
+ VEND_17_IX, // not used by client\r
+ VEND_18_IX, // not used by client\r
+ VEND_19_IX, // not used by client\r
+ VEND_20_IX, // not used by client\r
+ VEND_21_IX, // not used by client\r
+ VEND_22_IX, // not used by client\r
+ VEND_23_IX, // not used by client\r
+ VEND_24_IX, // not used by client\r
+ VEND_25_IX, // not used by client\r
+ VEND_26_IX, // not used by client\r
+ VEND_27_IX, // not used by client\r
+ VEND_28_IX, // not used by client\r
+ VEND_29_IX, // not used by client\r
+ VEND_30_IX, // not used by client\r
+ VEND_31_IX, // not used by client\r
+ VEND_32_IX, // not used by client\r
+ VEND_33_IX, // not used by client\r
+ VEND_34_IX, // not used by client\r
+ VEND_35_IX, // not used by client\r
+ VEND_36_IX, // not used by client\r
+ VEND_37_IX, // not used by client\r
+ VEND_38_IX, // not used by client\r
+ VEND_39_IX, // not used by client\r
+ VEND_40_IX, // not used by client\r
+ VEND_41_IX, // not used by client\r
+ VEND_42_IX, // not used by client\r
+ VEND_43_IX, // not used by client\r
+ VEND_44_IX, // not used by client\r
+ VEND_45_IX, // not used by client\r
+ VEND_46_IX, // not used by client\r
+ VEND_47_IX, // not used by client\r
+ VEND_48_IX, // not used by client\r
+ VEND_49_IX, // not used by client\r
+ VEND_50_IX, // not used by client\r
+ VEND_51_IX, // not used by client\r
+ VEND_52_IX, // not used by client\r
+ VEND_53_IX, // not used by client\r
+ VEND_54_IX, // not used by client\r
+ VEND_55_IX, // not used by client\r
+ VEND_56_IX, // not used by client\r
+ VEND_57_IX, // not used by client\r
+ VEND_58_IX, // not used by client\r
+ VEND_59_IX, // not used by client\r
+ VEND_60_IX, // not used by client\r
+ VEND_61_IX, // not used by client\r
+ VEND_62_IX, // not used by client\r
+ VEND_63_IX, // not used by client\r
+ VEND_64_IX, // not used by client\r
+ VEND_65_IX, // not used by client\r
+ VEND_66_IX, // not used by client\r
+ VEND_67_IX, // not used by client\r
+ VEND_68_IX, // not used by client\r
+ VEND_69_IX, // not used by client\r
+ VEND_70_IX, // not used by client\r
+ VEND_PXE_BOOT_ITEM_IX\r
+};\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// array of options in which we are interested\r
+// value 0 -> not of interest, else value is index into OPTION array\r
+// option values from 1 to MAX_OUR_OPT\r
+//\r
+STATIC UINT8 OurDhcpOptions[MAX_OUR_OPT] = {\r
+ OP_SUBNET_MASK_IX, // OP_SUBNET_MASK 1 // data is the subnet mask\r
+ OP_TIME_OFFSET_IX, // OP_TIME_OFFSET 2 // data is the time offset of subnet to UTC in seconds\r
+ OP_ROUTER_LIST_IX, // OP_ROUTER_LIST 3 // list of routers on subnet\r
+ OP_TIME_SERVERS_IX, // OP_TIME_SERVERS 4 // list of time servers available\r
+ OP_NAME_SERVERS_IX, // OP_NAME_SERVERS 5 // list of name servers available\r
+ OP_DNS_SERVERS_IX, // OP_DNS_SERVERS 6 // list of DNS servers available\r
+ OP_LOG_SERVERS_IX, // OP_LOG_SERVERS 7\r
+ OP_COOKIE_SERVERS_IX, // OP_COOKIE_SERVERS 8\r
+ OP_LPR_SREVERS_IX, // OP_LPR_SREVERS 9\r
+ OP_IMPRESS_SERVERS_IX, // OP_IMPRESS_SERVERS 10\r
+ OP_RES_LOC_SERVERS_IX, // OP_RES_LOC_SERVERS 11\r
+ OP_HOST_NAME_IX, // OP_HOST_NAME 12 // client name\r
+ OP_BOOT_FILE_SZ_IX, // OP_BOOT_FILE_SZ 13 // number of 512 blocks of boot file\r
+ OP_DUMP_FILE_IX, // OP_DUMP_FILE 14 // path name of dump file if client crashes\r
+ OP_DOMAIN_NAME_IX, // OP_DOMAIN_NAME 15 // domain name to use\r
+ OP_SWAP_SERVER_IX, // OP_SWAP_SERVER 16\r
+ OP_ROOT_PATH_IX, // OP_ROOT_PATH 17 // path name containing root disk\r
+ OP_EXTENSION_PATH_IX, // OP_EXTENSION_PATH 18 // name of TFTP downloadable file of form of OP\r
+ OP_IP_FORWARDING_IX, // OP_IP_FORWARDING 19 // enable/disable IP packet forwarding\r
+ OP_NON_LOCAL_SRC_RTE_IX, // OP_NON_LOCAL_SRC_RTE 20 // enable/disable non local source routing\r
+ OP_POLICY_FILTER_IX, // OP_POLICY_FILTER 21 // policy filters for non local source routing\r
+ OP_MAX_DATAGRAM_SZ_IX, // OP_MAX_DATAGRAM_SZ 22 // maximum datagram reassembly size\r
+ OP_DEFAULT_TTL_IX, // OP_DEFAULT_TTL 23 // default IP time to live\r
+ OP_MTU_AGING_TIMEOUT_IX, // OP_MTU_AGING_TIMEOUT 24\r
+ OP_MTU_SIZES_IX, // OP_MTU_SIZES 25\r
+ OP_MTU_TO_USE_IX, // OP_MTU_TO_USE 26\r
+ OP_ALL_SUBNETS_LOCAL_IX, // OP_ALL_SUBNETS_LOCAL 27\r
+ OP_BROADCAST_ADD_IX, // OP_BROADCAST_ADD 28 // broadcast address used on subnet\r
+ OP_PERFORM_MASK_DISCOVERY_IX, // OP_PERFORM_MASK_DISCOVERY 29 // perform mask discovery using ICMP\r
+ OP_RESPOND_TO_MASK_REQ_IX, // OP_RESPOND_TO_MASK_REQ 30 // respond to subnet mask requests using ICMP\r
+ OP_PERFORM_ROUTER_DISCOVERY_IX, // OP_PERFORM_ROUTER_DISCOVERY 31\r
+ OP_ROUTER_SOLICIT_ADDRESS_IX, // OP_ROUTER_SOLICIT_ADDRESS 32\r
+ OP_STATIC_ROUTER_LIST_IX, // OP_STATIC_ROUTER_LIST 33 // list of dest/route pairs\r
+ OP_USE_ARP_TRAILERS_IX, // OP_USE_ARP_TRAILERS 34\r
+ OP_ARP_CACHE_TIMEOUT_IX, // OP_ARP_CACHE_TIMEOUT 35\r
+ OP_ETHERNET_ENCAPSULATION_IX, // OP_ETHERNET_ENCAPSULATION 36 // 0 -> RFC 894, 1 -> IEEE 802.3 (RFC 1042)\r
+ OP_TCP_DEFAULT_TTL_IX, // OP_TCP_DEFAULT_TTL 37 // default time to live when sending TCP segments\r
+ OP_TCP_KEEP_ALIVE_INT_IX, // OP_TCP_KEEP_ALIVE_INT 38 // keep alive interval in seconds\r
+ OP_KEEP_ALIVE_GARBAGE_IX, // OP_KEEP_ALIVE_GARBAGE 39\r
+ OP_NIS_DOMAIN_NAME_IX, // OP_NIS_DOMAIN_NAME 40\r
+ OP_NIS_SERVERS_IX, // OP_NIS_SERVERS 41\r
+ OP_NTP_SERVERS_IX, // OP_NTP_SERVERS 42\r
+ OP_VENDOR_SPECIFIC_IX, // OP_VENDOR_SPECIFIC 43\r
+ OP_NBNS_SERVERS_IX, // OP_NBNS_SERVERS 44\r
+ OP_NBDD_SERVERS_IX, // OP_NBDD_SERVERS 45\r
+ OP_NETBIOS_NODE_TYPE_IX, // OP_NETBIOS_NODE_TYPE 46\r
+ OP_NETBIOS_SCOPE_IX, // OP_NETBIOS_SCOPE 47\r
+ OP_XWINDOW_SYSTEM_FONT_SERVERS_IX, // OP_XWINDOW_SYSTEM_FONT_SERVERS 48\r
+ OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS_IX, // OP_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49\r
+ OP_DHCP_REQ_IP_ADD_IX, // OP_DHCP_REQ_IP_ADD 50 // requested IP address - in DHCPDISCOVER\r
+ OP_DHCP_LEASE_TIME_IX, // OP_DHCP_LEASE_TIME 51 // lease time requested/granted\r
+ OP_DHCP_OPTION_OVERLOAD_IX, // OP_DHCP_OPTION_OVERLOAD 52 // file/server name/both used to hold options\r
+ OP_DHCP_MESSAGE_TYPE_IX, // OP_DHCP_MESSAGE_TYPE 53 // message type\r
+ OP_DHCP_SERVER_IP_IX, // OP_DHCP_SERVER_IP 54 // IP of server\r
+ OP_DHCP_PARM_REQ_LIST_IX, // OP_DHCP_PARM_REQ_LIST 55 // list of requested parameters\r
+ OP_DHCP_ERROR_MESSAGE_IX, // OP_DHCP_ERROR_MESSAGE 56 // in DHCPNAK or DECLINE messages\r
+ OP_DHCP_MAX_MESSAGE_SZ_IX, // OP_DHCP_MAX_MESSAGE_SZ 57 // maximum DHCP message size client will accept\r
+ OP_DHCP_RENEWAL_TIME_IX, // OP_DHCP_RENEWAL_TIME 58 // time in seconds before transitioning to RENEWING state\r
+ OP_DHCP_REBINDING_TIME_IX, // OP_DHCP_REBINDING_TIME 59 // time in seconds before transitioning to REBINDING state\r
+ OP_DHCP_CLASS_IDENTIFIER_IX, // OP_DHCP_CLASS_IDENTIFIER 60\r
+ OP_DHCP_CLIENT_IDENTIFIER_IX, // OP_DHCP_CLIENT_IDENTIFIER 61\r
+ OP_RESERVED62_IX, // OP_RESERVED62\r
+ OP_RESERVED63_IX, // OP_RESERVED63\r
+ OP_NISPLUS_DOMAIN_NAME_IX, // OP_NISPLUS_DOMAIN_NAME 64\r
+ OP_NISPLUS_SERVERS_IX, // OP_NISPLUS_SERVERS 65\r
+ OP_DHCP_TFTP_SERVER_NAME_IX, // OP_DHCP_TFTP_SERVER_NAME 66\r
+ OP_DHCP_BOOTFILE_IX // OP_DHCP_BOOTFILE 67\r
+};\r
+\r
+#define RxBuf ((DHCP_RECEIVE_BUFFER *) (Private->ReceiveBuffers))\r
+\r
+#pragma pack()\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @param Smbios Pointer to SMBIOS structure\r
+ @param StringNumber String number to return. 0 is used to skip all\r
+ strings and point to the next SMBIOS structure.\r
+\r
+ @return Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == 0\r
+\r
+**/\r
+CHAR8 *\r
+PxeBcLibGetSmbiosString (\r
+ IN SMBIOS_STRUCTURE_POINTER *Smbios,\r
+ IN UINT16 StringNumber\r
+ )\r
+{\r
+ UINT16 Index;\r
+ CHAR8 *String;\r
+\r
+ //\r
+ // Skip over formatted section\r
+ //\r
+ String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length);\r
+\r
+ //\r
+ // Look through unformated section\r
+ //\r
+ for (Index = 1; Index <= StringNumber || StringNumber == 0; Index++) {\r
+ if (StringNumber == Index) {\r
+ return String;\r
+ }\r
+ //\r
+ // Skip string\r
+ //\r
+ for (; *String != 0; String++)\r
+ ;\r
+ String++;\r
+\r
+ if (*String == 0) {\r
+ //\r
+ // If double NULL then we are done.\r
+ // Return pointer to next structure in Smbios.\r
+ // if you pass in a 0 you will always get here\r
+ //\r
+ Smbios->Raw = (UINT8 *)++String;\r
+ return NULL;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ This function gets system guid and serial number from the smbios table\r
+\r
+ @param SystemGuid The pointer of returned system guid\r
+ @param SystemSerialNumber The pointer of returned system serial number\r
+\r
+ @retval EFI_SUCCESS Successfully get the system guid and system serial\r
+ number\r
+ @retval EFI_NOT_FOUND Not find the SMBIOS table\r
+\r
+**/\r
+EFI_STATUS\r
+PxeBcLibGetSmbiosSystemGuidAndSerialNumber (\r
+ IN EFI_GUID *SystemGuid,\r
+ OUT CHAR8 **SystemSerialNumber\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SMBIOS_STRUCTURE_TABLE *SmbiosTable;\r
+ SMBIOS_STRUCTURE_POINTER Smbios;\r
+ SMBIOS_STRUCTURE_POINTER SmbiosEnd;\r
+ UINT16 Index;\r
+\r
+ Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Smbios.Hdr = (SMBIOS_HEADER *) (UINTN) SmbiosTable->TableAddress;\r
+ SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength);\r
+\r
+ for (Index = 0; Index < SmbiosTable->TableLength; Index++) {\r
+ if (Smbios.Hdr->Type == 1) {\r
+ if (Smbios.Hdr->Length < 0x19) {\r
+ //\r
+ // Older version did not support Guid and Serial number\r
+ //\r
+ continue;\r
+ }\r
+ //\r
+ // SMBIOS tables are byte packed so we need to do a byte copy to\r
+ // prevend alignment faults on Itanium-based platform.\r
+ //\r
+ CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));\r
+ *SystemSerialNumber = PxeBcLibGetSmbiosString (&Smbios, Smbios.Type1->SerialNumber);\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Make Smbios point to the next record\r
+ //\r
+ PxeBcLibGetSmbiosString (&Smbios, 0);\r
+\r
+ if (Smbios.Raw >= SmbiosEnd.Raw) {\r
+ //\r
+ // SMBIOS 2.1 incorrectly stated the length of SmbiosTable as 0x1e.\r
+ // given this we must double check against the lenght of\r
+ // the structure.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// add router list to list\r
+//\r
+STATIC\r
+VOID\r
+Ip4AddRouterList (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ DHCPV4_OP_IP_LIST *IpListPtr\r
+ )\r
+{\r
+ EFI_IP_ADDRESS TmpIp;\r
+ INTN Index;\r
+ INTN num;\r
+\r
+ if (IpListPtr == NULL) {\r
+ return ;\r
+ }\r
+\r
+ for (Index = 0, num = IpListPtr->Header.Length >> 2; Index < num; ++Index) {\r
+ CopyMem (&TmpIp, &IpListPtr->IpList[Index], 4);\r
+ Ip4AddRouter (Private, &TmpIp);\r
+ }\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// send ARP for our IP - fail if someone has it\r
+//\r
+STATIC\r
+BOOLEAN\r
+SetStationIP (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ EFI_MAC_ADDRESS DestMac;\r
+ EFI_STATUS EfiStatus;\r
+\r
+ ZeroMem (&DestMac, sizeof DestMac);\r
+\r
+ if (GetHwAddr(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac)\r
+ || DoArp(Private, (EFI_IP_ADDRESS *)&DHCP_REQ_OPTIONS.OpReqIP.Ip, (EFI_MAC_ADDRESS *)&DestMac) == EFI_SUCCESS) {\r
+ return FALSE; // somebody else has this IP\r
+ }\r
+\r
+ CopyMem (\r
+ (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->StationIp,\r
+ &DHCP_REQ_OPTIONS.OpReqIP.Ip,\r
+ sizeof (EFI_IPv4_ADDRESS)\r
+ );\r
+\r
+ Private->GoodStationIp = TRUE;\r
+\r
+ if (!Private->UseIgmpv1Reporting) {\r
+ return TRUE;\r
+ }\r
+\r
+ if (Private->Igmpv1TimeoutEvent != NULL) {\r
+ return TRUE;\r
+ }\r
+\r
+ EfiStatus = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &Private->Igmpv1TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ Private->Igmpv1TimeoutEvent = NULL;\r
+ return TRUE;\r
+ }\r
+\r
+ EfiStatus = gBS->SetTimer (\r
+ Private->Igmpv1TimeoutEvent,\r
+ TimerRelative,\r
+ (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000\r
+ ); /* 400 seconds */\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ gBS->CloseEvent (Private->Igmpv1TimeoutEvent);\r
+ Private->Igmpv1TimeoutEvent = NULL;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+VOID\r
+AddRouters (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ DHCP_RECEIVE_BUFFER *RxBufPtr\r
+ )\r
+{\r
+ Ip4AddRouterList (\r
+ Private,\r
+ (DHCPV4_OP_IP_LIST *) RxBufPtr->OpAdds.PktOptAdds[OP_ROUTER_LIST_IX - 1]\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+EFI_STATUS\r
+DoUdpWrite (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,\r
+ EFI_IP_ADDRESS *ClientIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr\r
+ )\r
+{\r
+ UINTN Len;\r
+\r
+ Len = sizeof DHCPV4_TRANSMIT_BUFFER;\r
+\r
+ return UdpWrite (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ 0,\r
+ ClientIpPtr,\r
+ ClientPortPtr,\r
+ 0,\r
+ 0,\r
+ &Len,\r
+ Private->TransmitBuffer\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// initialize the DHCP structure\r
+//\r
+typedef struct {\r
+ UINT8 x[4];\r
+} C4Str;\r
+\r
+STATIC\r
+VOID\r
+InitDhcpv4TxBuf (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ UINTN HwAddrLen;\r
+ UINT8 *String;\r
+ CHAR8 *SystemSerialNumber;\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+\r
+ ZeroMem (&DHCPV4_TRANSMIT_BUFFER, sizeof (DHCPV4_STRUCT));\r
+ DHCPV4_TRANSMIT_BUFFER.op = BOOTP_REQUEST;\r
+ DHCPV4_TRANSMIT_BUFFER.htype = Private->SimpleNetwork->Mode->IfType;\r
+ DHCPV4_TRANSMIT_BUFFER.flags = HTONS (DHCP_BROADCAST_FLAG);\r
+ CopyMem (&DHCPV4_OPTIONS_BUFFER, (VOID *) &DHCPOpStart, sizeof (DHCPOpStart));\r
+\r
+ //\r
+ // default to hardware address\r
+ //\r
+ HwAddrLen = Private->SimpleNetwork->Mode->HwAddressSize;\r
+\r
+ if (HwAddrLen > sizeof DHCPV4_TRANSMIT_BUFFER.chaddr) {\r
+ HwAddrLen = sizeof DHCPV4_TRANSMIT_BUFFER.chaddr;\r
+ }\r
+\r
+ String = (UINT8 *) &Private->SimpleNetwork->Mode->CurrentAddress;\r
+\r
+ if (PxeBcLibGetSmbiosSystemGuidAndSerialNumber (\r
+ (EFI_GUID *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid,\r
+ &SystemSerialNumber\r
+ ) == EFI_SUCCESS) {\r
+ if (PxebcMode->SendGUID) {\r
+ HwAddrLen = sizeof (EFI_GUID);\r
+ String = (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid;\r
+ }\r
+ } else {\r
+ //\r
+ // GUID not yet set - send all 0xff's to show programable (via SetVariable)\r
+ // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);\r
+ // GUID not yet set - send all 0's to show not programable\r
+ //\r
+ ZeroMem (DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof (EFI_GUID));\r
+ }\r
+\r
+ DHCPV4_TRANSMIT_BUFFER.hlen = (UINT8) HwAddrLen;\r
+ CopyMem (DHCPV4_TRANSMIT_BUFFER.chaddr, String, HwAddrLen);\r
+\r
+ CvtNum (\r
+ SYS_ARCH,\r
+ (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType,\r
+ sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.ArchitectureType\r
+ );\r
+\r
+ DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.Type = Private->NiiPtr->Type;\r
+ DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion = Private->NiiPtr->MajorVer;\r
+ DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion = Private->NiiPtr->MinorVer;\r
+\r
+ *(C4Str *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.InterfaceName = *(C4Str *) Private->NiiPtr->StringId;\r
+\r
+ CvtNum (\r
+ DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MajorVersion,\r
+ (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor,\r
+ sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMajor\r
+ );\r
+\r
+ CvtNum (\r
+ DHCPV4_OPTIONS_BUFFER.DhcpNetworkInterface.MinorVersion,\r
+ (UINT8 *) DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor,\r
+ sizeof DHCPV4_OPTIONS_BUFFER.DhcpClassIdentifier.Data.UndiMinor\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+UINT32\r
+DecodePxeOptions (\r
+ DHCP_RECEIVE_BUFFER *RxBufPtr,\r
+ UINT8 *ptr,\r
+ INTN Len\r
+ )\r
+{\r
+ UINT8 Op;\r
+ UINT8 *EndPtr;\r
+ INTN Index;\r
+ UNION_PTR LocalPtr;\r
+ UINT32 status;\r
+\r
+ status = 0;\r
+\r
+ for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {\r
+ Op = ptr[0];\r
+ Len = ptr[1];\r
+\r
+ switch (Op) {\r
+ case OP_PAD:\r
+ Len = -1;\r
+ break;\r
+\r
+ case OP_END:\r
+ return status;\r
+\r
+ default:\r
+ LocalPtr.BytePtr = ptr;\r
+ if (Op <= MAX_OUR_PXE_OPT) {\r
+ Index = ourPXEopts[Op - 1];\r
+ if (Index) {\r
+ RxBufPtr->OpAdds.PxeOptAdds[Index - 1] = LocalPtr.OpPtr;\r
+ status |= 1 << Index;\r
+ if (Index == VEND_PXE_BOOT_ITEM && LocalPtr.BootItem->Header.Length == 3) {\r
+ RxBufPtr->OpAdds.Status |= USE_THREE_BYTE;\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ return status;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+VOID\r
+DecodeOptions (\r
+ DHCP_RECEIVE_BUFFER *RxBufPtr,\r
+ UINT8 *ptr,\r
+ INTN Len\r
+ )\r
+{\r
+ UINT8 Op;\r
+ UINT8 *EndPtr;\r
+ INTN Index;\r
+ UNION_PTR LocalPtr;\r
+\r
+ for (EndPtr = ptr + Len; ptr < EndPtr; ptr += Len + 2) {\r
+ Op = ptr[0];\r
+ Len = ptr[1];\r
+\r
+ switch (Op) {\r
+ case OP_PAD:\r
+ Len = -1;\r
+ break;\r
+\r
+ case OP_END:\r
+ return ;\r
+\r
+ default:\r
+ LocalPtr.BytePtr = ptr;\r
+ if (Op <= MAX_OUR_OPT) {\r
+ Index = OurDhcpOptions[Op - 1];\r
+ if (Index) {\r
+ RxBufPtr->OpAdds.PktOptAdds[Index - 1] = LocalPtr.OpPtr;\r
+ if (Index == OP_VENDOR_SPECIFIC_IX) {\r
+ UINT32 status;\r
+ status = DecodePxeOptions (\r
+ RxBufPtr,\r
+ (UINT8 *) LocalPtr.VendorOptions->VendorOptions,\r
+ LocalPtr.VendorOptions->Header.Length\r
+ );\r
+ if (status) {\r
+ RxBufPtr->OpAdds.Status |= PXE_TYPE;\r
+ //\r
+ // check for all the MTFTP info options present - any missing is a nogo\r
+ //\r
+ if ((status & WfM11a_OPTS) == WfM11a_OPTS) {\r
+ RxBufPtr->OpAdds.Status |= WfM11a_TYPE;\r
+ }\r
+\r
+ if (status & DISCOVER_OPTS) {\r
+ RxBufPtr->OpAdds.Status |= DISCOVER_TYPE;\r
+ }\r
+\r
+ if (status & CREDENTIALS_OPT) {\r
+ RxBufPtr->OpAdds.Status |= CREDENTIALS_TYPE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+VOID\r
+Parse (\r
+ DHCP_RECEIVE_BUFFER *RxBufPtr,\r
+ INTN Len\r
+ )\r
+{\r
+ UNION_PTR LocalPtr;\r
+\r
+ //\r
+ // initialize\r
+ //\r
+ SetMem (&RxBufPtr->OpAdds, sizeof RxBufPtr->OpAdds, 0);\r
+\r
+ DecodeOptions (\r
+ RxBufPtr,\r
+ RxBufPtr->u.Dhcpv4.options + 4,\r
+ Len - (sizeof RxBufPtr->u.Dhcpv4 - sizeof RxBufPtr->u.Dhcpv4.options + 4)\r
+ );\r
+\r
+ LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_OPTION_OVERLOAD_IX - 1];\r
+\r
+ if ((LocalPtr.OpPtr) && (LocalPtr.Overload->Overload & OVLD_SRVR_NAME)) {\r
+ DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.sname, sizeof RxBufPtr->u.Dhcpv4.sname);\r
+ }\r
+\r
+ if (LocalPtr.OpPtr && (LocalPtr.Overload->Overload & OVLD_FILE)) {\r
+ DecodeOptions (RxBufPtr, RxBufPtr->u.Dhcpv4.file, sizeof RxBufPtr->u.Dhcpv4.file);\r
+ } else if (!RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && RxBufPtr->u.Dhcpv4.file[0]) {\r
+ RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] = (DHCPV4_OP_STRUCT *) (RxBufPtr->u.Dhcpv4.file - sizeof (DHCPV4_OP_HEADER));\r
+\r
+ RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length = (UINT8) AsciiStrLen (RxBufPtr->u.Dhcpv4.file);\r
+ }\r
+\r
+ LocalPtr.OpPtr = RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_CLASS_IDENTIFIER_IX - 1];\r
+\r
+ if ((LocalPtr.OpPtr) &&\r
+ LocalPtr.PxeClassStr->Header.Length >= 9 &&\r
+ !CompareMem (LocalPtr.PxeClassStr->Class, "PXEClient", 9)\r
+ ) {\r
+ RxBufPtr->OpAdds.Status |= PXE_TYPE;\r
+ }\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+VOID\r
+CopyParseRxBuf (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ INTN RxBufIndex,\r
+ INTN PacketIndex\r
+ )\r
+{\r
+ DHCP_RECEIVE_BUFFER *RxBufPtr;\r
+\r
+ RxBufPtr = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[PacketIndex];\r
+\r
+ CopyMem (\r
+ &RxBufPtr->u.Dhcpv4,\r
+ &RxBuf[RxBufIndex].u.Dhcpv4,\r
+ sizeof (RxBuf[RxBufIndex].u.Dhcpv4)\r
+ );\r
+\r
+ Parse (RxBufPtr, sizeof RxBufPtr->u.ReceiveBuffer);\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+VOID\r
+CopyProxyRxBuf (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ INTN RxBufIndex\r
+ )\r
+{\r
+ Private->EfiBc.Mode->ProxyOfferReceived = TRUE;\r
+ CopyParseRxBuf (Private, RxBufIndex, PXE_OFFER_INDEX);\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+VOID\r
+CopyParse (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ EFI_PXE_BASE_CODE_PACKET *PacketPtr,\r
+ EFI_PXE_BASE_CODE_PACKET *NewPacketPtr,\r
+ INTN Index\r
+ )\r
+{\r
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;\r
+\r
+ DhcpRxBuf = &((DHCP_RECEIVE_BUFFER *) Private->DhcpPacketBuffer)[Index];\r
+\r
+ CopyMem (\r
+ (EFI_PXE_BASE_CODE_PACKET *) &DhcpRxBuf->u.Dhcpv4,\r
+ NewPacketPtr,\r
+ sizeof (*NewPacketPtr)\r
+ );\r
+\r
+ CopyMem (&*PacketPtr, &*NewPacketPtr, sizeof (*NewPacketPtr));\r
+\r
+ Parse (DhcpRxBuf, sizeof DhcpRxBuf->u.ReceiveBuffer);\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+BOOLEAN\r
+AckEdit (\r
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf\r
+ )\r
+{\r
+ UNION_PTR LocalPtr;\r
+\r
+ LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];\r
+\r
+ //\r
+ // check that an ACK\r
+ // if a DHCP type, must be DHCPOFFER and must have server id\r
+ //\r
+ return (BOOLEAN)\r
+ (\r
+ (LocalPtr.OpPtr) &&\r
+ (LocalPtr.MessageType->Type == DHCPACK) &&\r
+ DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// if a discover type packet, make sure all required fields are present\r
+//\r
+BOOLEAN\r
+DHCPOfferAckEdit (\r
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf\r
+ )\r
+{\r
+ PXE_OP_SERVER_LIST *BootServerOpPtr;\r
+ UNION_PTR LocalPtr;\r
+\r
+ if ((DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) == 0) {\r
+ return TRUE;\r
+ }\r
+\r
+ LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];\r
+\r
+ if (LocalPtr.OpPtr == NULL) {\r
+ LocalPtr.OpPtr = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;\r
+ DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultDisCtl;\r
+ }\r
+ //\r
+ // make sure all required fields are here\r
+ // if mucticast enabled, need multicast address\r
+ //\r
+ if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST) &&\r
+ (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1] || !IS_MULTICAST (((DHCPV4_OP_STRUCT *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Data))\r
+ ) {\r
+ return FALSE;\r
+ //\r
+ // missing required field\r
+ //\r
+ }\r
+ //\r
+ // if a list, it better be good\r
+ //\r
+ BootServerOpPtr = (PXE_OP_SERVER_LIST *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1];\r
+\r
+ if (BootServerOpPtr != NULL) {\r
+ PXE_SERVER_LIST *BootServerListPtr;\r
+ INTN ServerListLen;\r
+ INTN ServerEntryLen;\r
+\r
+ BootServerListPtr = BootServerOpPtr->ServerList;\r
+ ServerListLen = BootServerOpPtr->Header.Length;\r
+\r
+ do {\r
+ EFI_IPv4_ADDRESS *IpListPtr;\r
+ INTN IpCnt;\r
+\r
+ IpCnt = BootServerListPtr->u.Ipv4List.IpCount;\r
+\r
+ ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (IpCnt - 1) * sizeof (EFI_IPv4_ADDRESS);\r
+\r
+ if (ServerListLen < ServerEntryLen) {\r
+ //\r
+ // missing required field\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ IpListPtr = BootServerListPtr->u.Ipv4List.IpList;\r
+\r
+ while (IpCnt--) {\r
+ if (IS_MULTICAST (IpListPtr)) {\r
+ //\r
+ // missing required field\r
+ //\r
+ return FALSE;\r
+ } else {\r
+ ++IpListPtr;\r
+ }\r
+ }\r
+\r
+ BootServerListPtr = (PXE_SERVER_LIST *) IpListPtr;\r
+ } while (ServerListLen -= ServerEntryLen);\r
+ }\r
+ //\r
+ // else there must be a list if use list enabled or multicast and\r
+ // broadcast disabled\r
+ //\r
+ else if ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) ||\r
+ ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))\r
+ ) {\r
+ //\r
+ // missing required field\r
+ //\r
+ return FALSE;\r
+ }\r
+ //\r
+ // if not USE_BOOTFILE or no bootfile given, must have menu stuff\r
+ //\r
+ if (!(LocalPtr.DiscoveryControl->ControlBits & USE_BOOTFILE) ||\r
+ !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]\r
+ ) {\r
+ INTN MenuLth;\r
+\r
+ LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];\r
+\r
+ if (LocalPtr.OpPtr == NULL || !DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]) {\r
+ //\r
+ // missing required field\r
+ //\r
+ return FALSE;\r
+ }\r
+ //\r
+ // make sure menu valid\r
+ //\r
+ MenuLth = LocalPtr.BootMenu->Header.Length;\r
+ LocalPtr.BootMenuItem = LocalPtr.BootMenu->MenuItem;\r
+\r
+ do {\r
+ INTN MenuItemLen;\r
+\r
+ MenuItemLen = LocalPtr.BootMenuItem->DataLen;\r
+\r
+ if (MenuItemLen == 0) {\r
+ //\r
+ // missing required field\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ MenuItemLen += sizeof (*LocalPtr.BootMenuItem) - sizeof (LocalPtr.BootMenuItem->Data);\r
+\r
+ MenuLth -= MenuItemLen;\r
+ LocalPtr.BytePtr += MenuItemLen;\r
+ } while (MenuLth > 0);\r
+\r
+ if (MenuLth != 0) {\r
+ //\r
+ // missing required field\r
+ //\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ if (!DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {\r
+ DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1] = (DHCPV4_OP_STRUCT *) &DefaultBootItem;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+BOOLEAN\r
+DHCPAckEdit (\r
+ DHCP_RECEIVE_BUFFER *RxBufPtr\r
+ )\r
+{\r
+ return (BOOLEAN) (DHCPOfferAckEdit (RxBufPtr) ? AckEdit (RxBufPtr) : FALSE);\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// get an offer/ack\r
+//\r
+EFI_STATUS\r
+GetOfferAck (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ BOOLEAN (*ExtraEdit)(DHCP_RECEIVE_BUFFER *DhcpRxBuf),\r
+ UINT16 OpFlags, // for Udp read\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,\r
+ EFI_IP_ADDRESS *ClientIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ClientPortPtr,\r
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf,\r
+ EFI_EVENT TimeoutEvent\r
+ )\r
+/*++\r
+Routine description:\r
+ Wait for an OFFER/ACK packet.\r
+\r
+Parameters:\r
+ Private := Pointer to PxeBc interface\r
+ ExtraEdit := Pointer to extra option checking function\r
+ OpFlags := UdpRead() option flags\r
+ ServerIpPtr :=\r
+ ServerPortPtr :=\r
+ ClientIpPtr :=\r
+ ClientPortPtr :=\r
+ DhcpRxBuf :=\r
+ TimeoutEvent :=\r
+\r
+Returns:\r
+--*/\r
+{\r
+ EFI_IP_ADDRESS ServerIp;\r
+ EFI_STATUS StatCode;\r
+ INTN RxBufLen;\r
+\r
+ for (;;) {\r
+ //\r
+ // Wait until we get a UDP packet.\r
+ //\r
+ ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));\r
+ RxBufLen = sizeof RxBuf[0].u.ReceiveBuffer;\r
+\r
+ if ((StatCode = UdpRead (\r
+ Private,\r
+ OpFlags,\r
+ ClientIpPtr,\r
+ ClientPortPtr,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ 0,\r
+ 0,\r
+ (UINTN *) &RxBufLen,\r
+ &DhcpRxBuf->u.Dhcpv4,\r
+ TimeoutEvent\r
+ )) != EFI_SUCCESS) {\r
+ if (StatCode == EFI_TIMEOUT) {\r
+ StatCode = EFI_NO_RESPONSE;\r
+ }\r
+\r
+ break;\r
+ }\r
+ //\r
+ // got a packet - see if a good offer\r
+ //\r
+ if (DhcpRxBuf->u.Dhcpv4.op != BOOTP_REPLY) {\r
+ continue;\r
+ }\r
+\r
+ if (DhcpRxBuf->u.Dhcpv4.xid != DHCPV4_TRANSMIT_BUFFER.xid) {\r
+ continue;\r
+ }\r
+\r
+ if (*(UINT32 *) DHCPV4_TRANSMIT_BUFFER.options != * (UINT32 *) DhcpRxBuf->u.Dhcpv4.options) {\r
+ continue;\r
+ }\r
+\r
+ if (*(UINT8 *) &DhcpRxBuf->u.Dhcpv4.yiaddr > 223) {\r
+ continue;\r
+ }\r
+\r
+ if (CompareMem (\r
+ DhcpRxBuf->u.Dhcpv4.chaddr,\r
+ DHCPV4_TRANSMIT_BUFFER.chaddr,\r
+ sizeof DhcpRxBuf->u.Dhcpv4.chaddr\r
+ )) {\r
+ //\r
+ // no good\r
+ //\r
+ continue;\r
+ }\r
+\r
+ Parse (DhcpRxBuf, RxBufLen);\r
+\r
+ if (!(*ExtraEdit) (DhcpRxBuf)) {\r
+ continue;\r
+ }\r
+ //\r
+ // Good DHCP packet.\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+ break;\r
+ }\r
+\r
+ return StatCode;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// get DHCPOFFER's\r
+//\r
+EFI_STATUS\r
+GetOffers (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ EFI_IP_ADDRESS ClientIp;\r
+ EFI_IP_ADDRESS ServerIp;\r
+ EFI_STATUS StatCode;\r
+ EFI_EVENT TimeoutEvent;\r
+ INTN NumOffers;\r
+ INTN Index;\r
+\r
+ //\r
+ //\r
+ //\r
+ ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));\r
+ NumOffers = 0;\r
+\r
+ for (Index = 0; Index < (sizeof Private->ServerCount) / sizeof Private->ServerCount[0]; ++Index) {\r
+ Private->ServerCount[Index] = 0;\r
+ Private->GotProxy[Index] = 0;\r
+ }\r
+\r
+ Private->GotBootp = 0;\r
+ //\r
+ // these we throw away\r
+ //\r
+ Private->GotProxy[DHCP_ONLY_IX] = 1;\r
+ StatCode = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ return StatCode;\r
+ }\r
+\r
+ StatCode = gBS->SetTimer (\r
+ TimeoutEvent,\r
+ TimerRelative,\r
+ Private->Timeout * 10000000 + 1000000\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return StatCode;\r
+ }\r
+ //\r
+ // get offers\r
+ //\r
+ for (;;) {\r
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;\r
+ UNION_PTR LocalPtr;\r
+\r
+ DhcpRxBuf = &RxBuf[NumOffers];\r
+\r
+ if ((\r
+ StatCode = GetOfferAck (\r
+ Private,\r
+ DHCPOfferAckEdit,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP |\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,\r
+ &ServerIp,\r
+ &DhcpServerPort,\r
+ &ClientIp,\r
+ &DHCPClientPort,\r
+ DhcpRxBuf,\r
+ TimeoutEvent\r
+ )\r
+) != EFI_SUCCESS\r
+ ) {\r
+ break;\r
+ }\r
+\r
+ LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1];\r
+\r
+ //\r
+ // check type of offer\r
+ //\r
+ if (LocalPtr.OpPtr == NULL) {\r
+ //\r
+ // bootp - we only need one and make sure has bootfile\r
+ //\r
+ if (Private->GotBootp || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {\r
+ continue;\r
+ }\r
+\r
+ Private->GotBootp = (UINT8) (NumOffers + 1);\r
+ }\r
+ //\r
+ // if a DHCP type, must be DHCPOFFER and must have server id\r
+ //\r
+ else if (LocalPtr.MessageType->Type != DHCPOFFER || !DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]) {\r
+ continue;\r
+ } else {\r
+ INTN TypeIx;\r
+\r
+ //\r
+ // get type - PXE10, WfM11a, or BINL\r
+ //\r
+ if (DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE) {\r
+ TypeIx = PXE10_IX;\r
+ } else if (DhcpRxBuf->OpAdds.Status & WfM11a_TYPE) {\r
+ //\r
+ // WfM - make sure it has a bootfile\r
+ //\r
+ if (!DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {\r
+ continue;\r
+ }\r
+\r
+ TypeIx = WfM11a_IX;\r
+ } else {\r
+ TypeIx = (DhcpRxBuf->OpAdds.Status & PXE_TYPE) ? BINL_IX : DHCP_ONLY_IX;\r
+ }\r
+ //\r
+ // check DHCP or proxy\r
+ //\r
+ if (DhcpRxBuf->u.Dhcpv4.yiaddr == 0) {\r
+ //\r
+ // proxy - only need one of each type if not BINL\r
+ // and must have at least PXE_TYPE\r
+ //\r
+ if (TypeIx == BINL_IX) {\r
+ Private->BinlProxies[Private->GotProxy[BINL_IX]++] = (UINT8) NumOffers;\r
+ } else if (Private->GotProxy[TypeIx]) {\r
+ continue;\r
+ } else {\r
+ Private->GotProxy[TypeIx] = (UINT8) (NumOffers + 1);\r
+ }\r
+ } else {\r
+ Private->OfferCount[TypeIx][Private->ServerCount[TypeIx]++] = (UINT8) NumOffers;\r
+ }\r
+ }\r
+\r
+ if (++NumOffers == MAX_OFFERS) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ Private->NumOffersReceived = NumOffers;\r
+\r
+ return (Private->NumOffersReceived) ? EFI_SUCCESS : EFI_NO_RESPONSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// send DHCPDECLINE\r
+//\r
+STATIC\r
+VOID\r
+DeclineOffer (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+ UINT16 SaveSecs;\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+ SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;\r
+\r
+ DHCPV4_TRANSMIT_BUFFER.secs = 0;\r
+ DHCPV4_TRANSMIT_BUFFER.flags = 0;\r
+ SetMem (\r
+ DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opdeclinestr),\r
+ sizeof (DHCPOpStart) - sizeof (struct opdeclinestr),\r
+ OP_PAD\r
+ );\r
+ DHCPDECLINEoptions.DhcpMessageType.Type = DHCPDECLINE;\r
+ CopyMem (&DHCPDECLINEoptions.OpDeclineEnd, &DHCP_REQ_OPTIONS, sizeof (struct requestopendstr));\r
+\r
+ {\r
+ EFI_IP_ADDRESS TmpIp;\r
+\r
+ CopyMem (&TmpIp, &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip, sizeof TmpIp);\r
+\r
+ DoUdpWrite (\r
+ Private,\r
+ &TmpIp,\r
+ &DhcpServerPort,\r
+ &PxebcMode->StationIp,\r
+ &DHCPClientPort\r
+ );\r
+ }\r
+\r
+ InitDhcpv4TxBuf (Private);\r
+ DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;\r
+ Private->GoodStationIp = FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// send DHCPRELEASE\r
+//\r
+STATIC\r
+BOOLEAN\r
+Release (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+ UINT16 SaveSecs;\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+ SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;\r
+ DHCPV4_TRANSMIT_BUFFER.secs = 0;\r
+\r
+ SetMem (\r
+ DHCPV4_TRANSMIT_BUFFER.options + sizeof (struct opreleasestr),\r
+ sizeof (DHCPOpStart) - sizeof (struct opreleasestr),\r
+ OP_PAD\r
+ );\r
+\r
+ DHCPRELEASEoptions.DhcpMessageType.Type = DHCPRELEASE;\r
+\r
+ CopyMem (\r
+ &DHCPRELEASEoptions.DhcServerIpPtr,\r
+ &(DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1],\r
+ sizeof DHCPRELEASEoptions.DhcServerIpPtr\r
+ );\r
+\r
+ DHCPRELEASEoptions.End[0] = OP_END;\r
+\r
+ {\r
+ EFI_IP_ADDRESS TmpIp;\r
+\r
+ CopyMem (&TmpIp, &DHCPRELEASEoptions.DhcServerIpPtr.Ip, sizeof TmpIp);\r
+\r
+ DoUdpWrite (\r
+ Private,\r
+ &TmpIp,\r
+ &DhcpServerPort,\r
+ &PxebcMode->StationIp,\r
+ &DHCPClientPort\r
+ );\r
+ }\r
+\r
+ InitDhcpv4TxBuf (Private);\r
+\r
+ DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;\r
+ Private->GoodStationIp = FALSE;\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+BOOLEAN\r
+GetBINLAck (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ EFI_IP_ADDRESS *ServerIpPtr\r
+ )\r
+{\r
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;\r
+ EFI_STATUS StatCode;\r
+ EFI_EVENT TimeoutEvent;\r
+\r
+ //\r
+ //\r
+ //\r
+ StatCode = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ return FALSE;\r
+ }\r
+\r
+ StatCode = gBS->SetTimer (\r
+ TimeoutEvent,\r
+ TimerRelative,\r
+ Private->Timeout * 10000000 + 1000000\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return FALSE;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ DhcpRxBuf = &PXE_BINL_BUFFER;\r
+\r
+ for (;;) {\r
+ EFI_PXE_BASE_CODE_UDP_PORT BINLSrvPort;\r
+\r
+ BINLSrvPort = 0;\r
+\r
+ if (GetOfferAck (\r
+ Private,\r
+ AckEdit,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,\r
+ ServerIpPtr,\r
+ &BINLSrvPort,\r
+ &Private->EfiBc.Mode->StationIp,\r
+ &PSEUDO_DHCP_CLIENT_PORT,\r
+ DhcpRxBuf,\r
+ TimeoutEvent\r
+ ) != EFI_SUCCESS) {\r
+ break;\r
+ }\r
+ //\r
+ // make sure from whom we wanted\r
+ //\r
+ if (!DhcpRxBuf->u.Dhcpv4.yiaddr && !CompareMem (\r
+ &ServerIpPtr->v4,\r
+ &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,\r
+ sizeof (ServerIpPtr->v4)\r
+ )) {\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ //\r
+ // got an ACK from server\r
+ //\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// make sure we can get BINL\r
+// send DHCPREQUEST to PXE server\r
+//\r
+STATIC\r
+BOOLEAN\r
+TryBINL (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ INTN OfferIx\r
+ )\r
+{\r
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;\r
+ EFI_IP_ADDRESS ServerIp;\r
+ UINT16 SaveSecs;\r
+ INTN Index;\r
+\r
+ DhcpRxBuf = &RxBuf[OfferIx];\r
+\r
+ //\r
+ // use next server address first.\r
+ //\r
+ ServerIp.Addr[0] = DhcpRxBuf->u.Dhcpv4.siaddr;\r
+ if (ServerIp.Addr[0] == 0) {\r
+ //\r
+ // next server address is NULL, use option 54.\r
+ //\r
+ CopyMem (\r
+ ((EFI_IPv4_ADDRESS *) &ServerIp),\r
+ &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,\r
+ sizeof (EFI_IPv4_ADDRESS)\r
+ );\r
+ }\r
+\r
+ //\r
+ // client IP address - filled in by client if it knows it\r
+ //\r
+ CopyMem (\r
+ ((EFI_IPv4_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr),\r
+ &DHCP_REQ_OPTIONS.OpReqIP.Ip,\r
+ sizeof (EFI_IPv4_ADDRESS)\r
+ );\r
+\r
+ SetMem (&DHCP_REQ_OPTIONS, sizeof DHCP_REQ_OPTIONS, OP_PAD);\r
+ DHCPV4_TRANSMIT_BUFFER.flags = 0;\r
+ DHCPV4_OPTIONS_BUFFER.End[0] = OP_END;\r
+ AddRouters (Private, DhcpRxBuf);\r
+ SaveSecs = DHCPV4_TRANSMIT_BUFFER.secs;\r
+\r
+ for (Index = 0; Index < 3; Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Index) {\r
+ DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);\r
+\r
+ //\r
+ // unicast DHCPREQUEST to PXE server\r
+ //\r
+ if (DoUdpWrite (\r
+ Private,\r
+ &ServerIp,\r
+ &PseudoDhcpServerPort,\r
+ (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,\r
+ &PSEUDO_DHCP_CLIENT_PORT\r
+ ) != EFI_SUCCESS) {\r
+ break;\r
+ }\r
+\r
+ if (!GetBINLAck (Private, &ServerIp)) {\r
+ continue;\r
+ }\r
+ //\r
+ // early exit failures\r
+ // make sure a good ACK\r
+ //\r
+ if (!DHCPOfferAckEdit (&PXE_BINL_BUFFER) || (\r
+ !(PXE_BINL_BUFFER.OpAdds.Status & DISCOVER_TYPE) && !PXE_BINL_BUFFER.OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]\r
+ )\r
+ ) {\r
+ break;\r
+ }\r
+\r
+ Private->EfiBc.Mode->ProxyOfferReceived = TRUE;\r
+ return TRUE;\r
+ }\r
+ //\r
+ // failed - reset seconds field, etc.\r
+ //\r
+ Private->EfiBc.Mode->RouteTableEntries = 0;\r
+ //\r
+ // reset\r
+ //\r
+ DHCPV4_TRANSMIT_BUFFER.secs = SaveSecs;\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+BOOLEAN\r
+TryFinishBINL (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ INTN OfferIx\r
+ )\r
+{\r
+ if (TryBINL (Private, OfferIx)) {\r
+ return TRUE;\r
+ }\r
+\r
+ return Release (Private);\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+BOOLEAN\r
+TryFinishProxyBINL (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ INTN Index;\r
+\r
+ for (Index = 0; Index < Private->GotProxy[BINL_IX]; ++Index) {\r
+ if (TryBINL (Private, Private->BinlProxies[Index])) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return Release (Private);\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// try to finish DORA - send DHCP request, wait for ACK, check with ARP\r
+//\r
+STATIC\r
+BOOLEAN\r
+TryFinishDORA (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ INTN OfferIx\r
+ )\r
+{\r
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;\r
+ EFI_IP_ADDRESS ClientIp;\r
+ EFI_IP_ADDRESS ServerIp;\r
+ EFI_STATUS StatCode;\r
+ UNION_PTR LocalPtr;\r
+ EFI_EVENT TimeoutEvent;\r
+\r
+ //\r
+ // send DHCP request\r
+ // if fail return false\r
+ //\r
+ DhcpRxBuf = &DHCPV4_ACK_BUFFER;\r
+ DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST;\r
+ CopyMem (&DHCP_REQ_OPTIONS, &RequestOpEndStr, sizeof (RequestOpEndStr));\r
+// DHCP_REQ_OPTIONS = RequestOpEndStr;\r
+ DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[OfferIx].u.Dhcpv4.yiaddr;\r
+\r
+ CopyMem (\r
+ &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip,\r
+ &((DHCPV4_OP_SERVER_IP *) RxBuf[OfferIx].OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,\r
+ sizeof DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip\r
+ );\r
+\r
+ CopyMem (\r
+ Private->EfiBc.Mode->SubnetMask.Addr,\r
+ &DefaultSubnetMask,\r
+ 4\r
+ );\r
+\r
+ //\r
+ // broadcast DHCPREQUEST\r
+ //\r
+ if (DoUdpWrite (\r
+ Private,\r
+ &BroadcastIP,\r
+ &DhcpServerPort,\r
+ (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,\r
+ &DHCPClientPort\r
+ ) != EFI_SUCCESS) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ StatCode = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ return FALSE;\r
+ }\r
+\r
+ StatCode = gBS->SetTimer (\r
+ TimeoutEvent,\r
+ TimerPeriodic,\r
+ Private->Timeout * 10000000 + 1000000\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return FALSE;\r
+ }\r
+ //\r
+ // wait for ACK\r
+ //\r
+ for (;;) {\r
+ if (GetOfferAck (\r
+ Private,\r
+ DHCPAckEdit,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP,\r
+ &ServerIp,\r
+ &DhcpServerPort,\r
+ &ClientIp,\r
+ &DHCPClientPort,\r
+ DhcpRxBuf,\r
+ TimeoutEvent\r
+ ) != EFI_SUCCESS) {\r
+ break;\r
+ }\r
+ //\r
+ // check type of response - need DHCPACK\r
+ //\r
+ if (CompareMem (\r
+ &DHCP_REQ_OPTIONS.OpReqIP.Ip,\r
+ &DhcpRxBuf->u.Dhcpv4.yiaddr,\r
+ sizeof (EFI_IPv4_ADDRESS)\r
+ ) || CompareMem (\r
+ &DHCP_REQ_OPTIONS.DhcServerIpPtr.Ip,\r
+ &((DHCPV4_OP_SERVER_IP *) DhcpRxBuf->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip,\r
+ sizeof (EFI_IPv4_ADDRESS)\r
+ )) {\r
+ continue;\r
+ }\r
+ //\r
+ // got ACK\r
+ // check with ARP that IP unused - good return true\r
+ //\r
+ if (!SetStationIP (Private)) {\r
+ //\r
+ // fail - send DHCPDECLINE and return false\r
+ //\r
+ DeclineOffer (Private);\r
+ break;\r
+ }\r
+\r
+ LocalPtr.OpPtr = DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1];\r
+\r
+ if (LocalPtr.OpPtr != NULL) {\r
+ CopyMem (\r
+ (EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask,\r
+ &LocalPtr.SubnetMaskStr->Ip,\r
+ sizeof (EFI_IPv4_ADDRESS)\r
+ );\r
+ }\r
+\r
+ AddRouters (Private, DhcpRxBuf);\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return TRUE;\r
+ }\r
+\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// try a DHCP server of appropriate type\r
+//\r
+STATIC\r
+BOOLEAN\r
+TryDHCPFinishDORA (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ INTN TypeIx\r
+ )\r
+{\r
+ INTN Index;\r
+\r
+ //\r
+ // go through the DHCP servers of the requested type\r
+ //\r
+ for (Index = 0; Index < Private->ServerCount[TypeIx]; ++Index) {\r
+ if (TryFinishDORA (Private, Index = Private->OfferCount[TypeIx][Index])) {\r
+ if (TypeIx == BINL_IX && !TryFinishBINL (Private, Index)) {\r
+ continue;\r
+ }\r
+\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// try a DHCP only server and a proxy of appropriate type\r
+//\r
+STATIC\r
+BOOLEAN\r
+TryProxyFinishDORA (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ INTN TypeIx\r
+ )\r
+{\r
+ INTN Index;\r
+\r
+ if (!Private->GotProxy[TypeIx]) {\r
+ //\r
+ // no proxies of the type wanted\r
+ //\r
+ return FALSE;\r
+ }\r
+ //\r
+ // go through the DHCP only servers\r
+ //\r
+ for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) {\r
+ if (TryFinishDORA (Private, Private->OfferCount[DHCP_ONLY_IX][Index])) {\r
+ if (TypeIx != BINL_IX) {\r
+ CopyProxyRxBuf (Private, Private->GotProxy[TypeIx] - 1);\r
+ } else if (!TryFinishProxyBINL (Private)) {\r
+ //\r
+ // if didn't work with this DHCP, won't work with any\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// getting to the bottom of the barrel\r
+//\r
+STATIC\r
+BOOLEAN\r
+TryAnyWithBootfileFinishDORA (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ //\r
+ // try a DHCP only server who has a bootfile\r
+ //\r
+ UNION_PTR LocalPtr;\r
+ INTN Index;\r
+\r
+ for (Index = 0; Index < Private->ServerCount[DHCP_ONLY_IX]; ++Index) {\r
+ INTN offer;\r
+\r
+ offer = Private->OfferCount[DHCP_ONLY_IX][Index];\r
+\r
+ if (RxBuf[offer].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] && TryFinishDORA (Private, offer)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ //\r
+ // really at bottom - see if be have any bootps\r
+ //\r
+ if (!Private->GotBootp) {\r
+ return FALSE;\r
+ }\r
+\r
+ DHCP_REQ_OPTIONS.OpReqIP.Ip = *(EFI_IPv4_ADDRESS *) &RxBuf[Private->GotBootp - 1].u.Dhcpv4.yiaddr;\r
+\r
+ if (!SetStationIP (Private)) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // treat BOOTP response as DHCP ACK packet\r
+ //\r
+ CopyParseRxBuf (Private, Private->GotBootp - 1, DHCPV4_ACK_INDEX);\r
+\r
+ LocalPtr.OpPtr = RxBuf[Private->GotBootp - 1].OpAdds.PktOptAdds[OP_SUBNET_MASK_IX - 1];\r
+\r
+ if (LocalPtr.OpPtr != NULL) {\r
+ *(EFI_IPv4_ADDRESS *) &Private->EfiBc.Mode->SubnetMask = LocalPtr.SubnetMaskStr->Ip;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/* DoDhcpDora()\r
+ */\r
+STATIC\r
+EFI_STATUS\r
+DoDhcpDora (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ BOOLEAN SortOffers\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_IP_FILTER Filter;\r
+ EFI_STATUS StatCode;\r
+ INTN NumOffers;\r
+\r
+ Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP | EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;\r
+\r
+ Filter.IpCnt = 0;\r
+ Filter.reserved = 0;\r
+\r
+ //\r
+ // set filter unicast or broadcast\r
+ //\r
+ if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {\r
+ return StatCode;\r
+ }\r
+ //\r
+ // seed random number with hardware address\r
+ //\r
+ SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);\r
+\r
+ for (Private->Timeout = 1;\r
+ Private->Timeout < 17;\r
+ Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), Private->Timeout <<= 1\r
+ ) {\r
+ INTN Index;\r
+\r
+ InitDhcpv4TxBuf (Private);\r
+ DHCPV4_TRANSMIT_BUFFER.xid = Random (Private);\r
+ DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);\r
+\r
+ //\r
+ // broadcast DHCPDISCOVER\r
+ //\r
+ StatCode = DoUdpWrite (\r
+ Private,\r
+ &BroadcastIP,\r
+ &DhcpServerPort,\r
+ (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,\r
+ &DHCPClientPort\r
+ );\r
+\r
+ if (StatCode != EFI_SUCCESS) {\r
+ return StatCode;\r
+ }\r
+\r
+ CopyMem (\r
+ &Private->EfiBc.Mode->DhcpDiscover,\r
+ (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,\r
+ sizeof (EFI_PXE_BASE_CODE_PACKET)\r
+ );\r
+\r
+ //\r
+ // get DHCPOFFER's\r
+ //\r
+ if ((StatCode = GetOffers (Private)) != EFI_SUCCESS) {\r
+ if (StatCode != EFI_NO_RESPONSE) {\r
+ return StatCode;\r
+ }\r
+\r
+ continue;\r
+ }\r
+ //\r
+ // select offer and reply DHCPREQUEST\r
+ //\r
+ if (SortOffers) {\r
+ if (TryDHCPFinishDORA(Private, PXE10_IX) || // try DHCP with PXE10\r
+ TryDHCPFinishDORA(Private, WfM11a_IX) || // no - try with WfM\r
+ TryProxyFinishDORA(Private, PXE10_IX) || // no - try DHCP only and proxy with PXE10\r
+ TryProxyFinishDORA(Private, WfM11a_IX) || // no - try DHCP only and proxy with WfM\r
+ TryDHCPFinishDORA(Private, BINL_IX) || // no - try with WfM\r
+ TryProxyFinishDORA(Private, BINL_IX) || // no - try DHCP only and proxy with PXE10\r
+ TryAnyWithBootfileFinishDORA(Private))\r
+ {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ continue;\r
+ }\r
+ //\r
+ // FIFO order\r
+ //\r
+ NumOffers = Private->NumOffersReceived;\r
+\r
+ for (Index = 0; Index < NumOffers; ++Index) {\r
+ //\r
+ // ignore proxies\r
+ //\r
+ if (!RxBuf[Index].u.Dhcpv4.yiaddr) {\r
+ continue;\r
+ }\r
+ //\r
+ // check if a bootp server\r
+ //\r
+ if (!RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1]) {\r
+ //\r
+ // it is - just check ARP\r
+ //\r
+ if (!SetStationIP (Private)) {\r
+ continue;\r
+ }\r
+ }\r
+ //\r
+ // else check if a DHCP only server\r
+ //\r
+ else if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE))) {\r
+ //\r
+ // it is a normal DHCP offer (without any PXE options), just finish the D.O.R.A by sending DHCP request.\r
+ //\r
+ if (!TryFinishDORA (Private, Index)) {\r
+ continue;\r
+ }\r
+ } else if (TryFinishDORA (Private, Index)) {\r
+ if (!(RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) && !TryFinishBINL (Private, Index)) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ DEBUG ((DEBUG_WARN, "\nDoDhcpDora() Got packets. "));\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // now look for DHCP onlys and a Proxy\r
+ //\r
+ for (Index = 0; Index < NumOffers; ++Index) {\r
+ INT8 Index2;\r
+\r
+ //\r
+ // ignore proxies, bootps, non DHCP onlys, and bootable DHCPS\r
+ //\r
+ if (!RxBuf[Index].u.Dhcpv4.yiaddr ||\r
+ !RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_MESSAGE_TYPE_IX - 1] ||\r
+ RxBuf[Index].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE | PXE_TYPE) ||\r
+ RxBuf[Index].OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]\r
+ ) {\r
+ continue;\r
+ }\r
+ //\r
+ // found non bootable DHCP only - try to find a proxy\r
+ //\r
+ for (Index2 = 0; Index2 < NumOffers; ++Index2) {\r
+ if (!RxBuf[Index2].u.Dhcpv4.yiaddr) {\r
+ if (!TryFinishDORA (Private, Index)) {\r
+ //\r
+ // DHCP no ACK\r
+ //\r
+ break;\r
+ }\r
+\r
+ if (RxBuf[Index2].OpAdds.Status & (DISCOVER_TYPE | WfM11a_TYPE)) {\r
+ CopyProxyRxBuf (Private, Index2);\r
+ } else if (!TryFinishBINL (Private, Index2)) {\r
+ continue;\r
+ }\r
+\r
+ DEBUG ((DEBUG_WARN, "\nDoDhcpDora() Got packets. "));\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_NO_RESPONSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// determine if the server ip is in the ip list\r
+//\r
+BOOLEAN\r
+InServerList (\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ PXE_SERVER_LISTS *ServerListPtr\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ if (!ServerListPtr || !ServerListPtr->Ipv4List.IpCount) {\r
+ return TRUE;\r
+ }\r
+\r
+ for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {\r
+ if (!CompareMem (\r
+ ServerIpPtr,\r
+ &ServerListPtr->Ipv4List.IpList[Index],\r
+ sizeof (EFI_IPv4_ADDRESS)\r
+ )) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+BOOLEAN\r
+ExtractBootServerList (\r
+ UINT16 Type,\r
+ DHCPV4_OP_STRUCT *ptr,\r
+ PXE_SERVER_LISTS **ServerListPtr\r
+ )\r
+{\r
+ UNION_PTR LocalPtr;\r
+ INTN ServerListLen;\r
+\r
+ LocalPtr.OpPtr = ptr;\r
+ ServerListLen = LocalPtr.BootServersStr->Header.Length;\r
+\r
+ //\r
+ // find type\r
+ //\r
+ LocalPtr.BootServerList = LocalPtr.BootServersStr->ServerList;\r
+\r
+ while (ServerListLen) {\r
+ INTN ServerEntryLen;\r
+\r
+ ServerEntryLen = sizeof (PXEV4_SERVER_LIST) + 2 + (LocalPtr.BootServerList->u.Ipv4List.IpCount - 1) *\r
+ sizeof (EFI_IPv4_ADDRESS);\r
+\r
+ if (NTOHS (LocalPtr.BootServerList->Type) == Type) {\r
+ *ServerListPtr = &LocalPtr.BootServerList->u;\r
+ return TRUE;\r
+ }\r
+\r
+ (LocalPtr.BytePtr) += ServerEntryLen;\r
+ ServerListLen -= ServerEntryLen;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+VOID\r
+FreeMem (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ if (Private->TransmitBuffer != NULL) {\r
+ gBS->FreePool (Private->TransmitBuffer);\r
+ Private->TransmitBuffer = NULL;\r
+ }\r
+\r
+ if (Private->ReceiveBuffers != NULL) {\r
+ gBS->FreePool (Private->ReceiveBuffers);\r
+ Private->ReceiveBuffers = NULL;\r
+ }\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+BOOLEAN\r
+GetMem (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (Private->DhcpPacketBuffer == NULL) {\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),\r
+ &Private->DhcpPacketBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {\r
+ Private->DhcpPacketBuffer = NULL;\r
+ FreeMem (Private);\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ sizeof (EFI_PXE_BASE_CODE_PACKET),\r
+ &Private->TransmitBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || Private->TransmitBuffer == NULL) {\r
+ gBS->FreePool (Private->DhcpPacketBuffer);\r
+ Private->DhcpPacketBuffer = NULL;\r
+ Private->TransmitBuffer = NULL;\r
+ FreeMem (Private);\r
+ return FALSE;\r
+ }\r
+\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ sizeof (DHCP_RECEIVE_BUFFER) * (MAX_OFFERS),\r
+ &Private->ReceiveBuffers\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || Private->ReceiveBuffers == NULL) {\r
+ gBS->FreePool (Private->TransmitBuffer);\r
+ gBS->FreePool (Private->DhcpPacketBuffer);\r
+ Private->DhcpPacketBuffer = NULL;\r
+ Private->TransmitBuffer = NULL;\r
+ Private->ReceiveBuffers = NULL;\r
+ FreeMem (Private);\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcDhcp (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
+ IN BOOLEAN SortOffers\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_IP_FILTER Filter;\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+ EFI_STATUS StatCode;\r
+\r
+ //\r
+ // Lock the instance data and make sure started\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ if (This->Mode == NULL || !This->Mode->Started) {\r
+ DEBUG ((DEBUG_ERROR, "BC was not started."));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;\r
+ Filter.IpCnt = 0;\r
+ Filter.reserved = 0;\r
+\r
+ DEBUG ((DEBUG_INFO, "\nBcDhcp() Enter. "));\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+\r
+ if (!GetMem (Private)) {\r
+ DEBUG ((DEBUG_ERROR, "\nBcDhcp() GetMem() failed.\n"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ PxebcMode->DhcpDiscoverValid = FALSE;\r
+ PxebcMode->DhcpAckReceived = FALSE;\r
+ PxebcMode->ProxyOfferReceived = FALSE;\r
+\r
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DHCP;\r
+\r
+ //\r
+ // Issue BC command\r
+ //\r
+ if (Private->TotalSeconds == 0) {\r
+ //\r
+ // put in seconds field of DHCP send packets\r
+ //\r
+ Private->TotalSeconds = 4;\r
+ }\r
+\r
+ if ((StatCode = DoDhcpDora (Private, SortOffers)) == EFI_SUCCESS) {\r
+ //\r
+ // success - copy packets\r
+ //\r
+ PxebcMode->DhcpDiscoverValid = PxebcMode->DhcpAckReceived = TRUE;\r
+\r
+ CopyMem (\r
+ &PxebcMode->DhcpAck,\r
+ (EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_ACK_PACKET,\r
+ sizeof (EFI_PXE_BASE_CODE_PACKET)\r
+ );\r
+\r
+ if (PxebcMode->ProxyOfferReceived) {\r
+ CopyMem (\r
+ &PxebcMode->ProxyOffer,\r
+ (EFI_PXE_BASE_CODE_PACKET *) &PXE_OFFER_PACKET,\r
+ sizeof (EFI_PXE_BASE_CODE_PACKET)\r
+ );\r
+ }\r
+ }\r
+ //\r
+ // set filter back to unicast\r
+ //\r
+ IpFilter (Private, &Filter);\r
+\r
+ FreeMem (Private);\r
+\r
+ //\r
+ // Unlock the instance data\r
+ //\r
+ DEBUG ((DEBUG_WARN, "\nBcDhcp() Exit = %xh ", StatCode));\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+BOOLEAN\r
+VerifyCredentialOption (\r
+ UINT8 *tx,\r
+ UINT8 *rx\r
+ )\r
+{\r
+ UINTN n;\r
+\r
+ //\r
+ // Fail verification if either pointer is NULL.\r
+ //\r
+ if (tx == NULL || rx == NULL) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // Fail verification if tx[0] is not a credential type option\r
+ // or if the length is zero or not a multiple of four.\r
+ //\r
+ if (tx[0] != VEND_PXE_CREDENTIAL_TYPES || tx[1] == 0 || tx[1] % 4 != 0) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // Fail verification if rx[0] is not a credential type option\r
+ // or if the length is not equal to four.\r
+ //\r
+ if (rx[0] != VEND_PXE_CREDENTIAL_TYPES || rx[1] != 4) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // Look through transmitted credential types for a copy\r
+ // of the received credential type.\r
+ //\r
+ for (n = 0; n < tx[1]; n += 4) {\r
+ if (!CompareMem (&tx[n + 2], &rx[2], 4)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+DoDiscover (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT16 OpFlags,\r
+ IN UINT16 Type,\r
+ IN UINT16 *LayerPtr,\r
+ IN BOOLEAN UseBis,\r
+ EFI_IP_ADDRESS *DestPtr,\r
+ PXE_SERVER_LISTS *ServerListPtr\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_UDP_PORT ClientPort;\r
+ EFI_PXE_BASE_CODE_UDP_PORT ServerPort;\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+ EFI_STATUS StatCode;\r
+ EFI_EVENT TimeoutEvent;\r
+ UINT8 OpLen;\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+\r
+ if (DestPtr->Addr[0] == 0) {\r
+ DEBUG ((DEBUG_WARN, "\nDoDiscover() !DestPtr->Addr[0]"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // seed random number with hardware address\r
+ //\r
+ SeedRandom (Private, *(UINT16 *) &Private->SimpleNetwork->Mode->CurrentAddress);\r
+\r
+ if (DestPtr->Addr[0] == BroadcastIP.Addr[0]) {\r
+ ClientPort = DHCPClientPort;\r
+ ServerPort = DhcpServerPort;\r
+ } else {\r
+ ClientPort = PSEUDO_DHCP_CLIENT_PORT;\r
+ ServerPort = PseudoDhcpServerPort;\r
+ }\r
+\r
+ if (UseBis) {\r
+ *LayerPtr |= PXE_BOOT_LAYER_CREDENTIAL_FLAG;\r
+ } else {\r
+ *LayerPtr &= PXE_BOOT_LAYER_MASK;\r
+ }\r
+\r
+ for (Private->Timeout = 1;\r
+ Private->Timeout < 5;\r
+ Private->TotalSeconds = (UINT16) (Private->TotalSeconds + Private->Timeout), ++Private->Timeout\r
+ ) {\r
+ InitDhcpv4TxBuf (Private);\r
+ //\r
+ // initialize DHCP message structure\r
+ //\r
+ DHCPV4_TRANSMIT_BUFFER.xid = Random (Private);\r
+ DHCPV4_TRANSMIT_BUFFER.secs = HTONS (Private->TotalSeconds);\r
+ CopyMem (\r
+ &DHCPV4_TRANSMIT_BUFFER.ciaddr,\r
+ &PxebcMode->StationIp,\r
+ sizeof DHCPV4_TRANSMIT_BUFFER.ciaddr\r
+ );\r
+\r
+ DHCPV4_OPTIONS_BUFFER.DhcpMessageType.Type = DHCPREQUEST;\r
+ DISCOVERoptions.Header.OpCode = OP_VENDOR_SPECIFIC;\r
+ DISCOVERoptions.BootItem.Header.OpCode = VEND_PXE_BOOT_ITEM;\r
+ DISCOVERoptions.BootItem.Header.Length = DHCPV4_OPTION_LENGTH (PXE_OP_BOOT_ITEM);\r
+ DISCOVERoptions.BootItem.Type = HTONS (Type);\r
+ DISCOVERoptions.BootItem.Layer = HTONS (*LayerPtr);\r
+\r
+ if (UseBis) {\r
+ EFI_BIS_PROTOCOL *BisPtr;\r
+ BIS_APPLICATION_HANDLE BisAppHandle;\r
+ EFI_BIS_DATA *BisDataSigInfo;\r
+ EFI_BIS_SIGNATURE_INFO *BisSigInfo;\r
+ UINTN Index;\r
+ UINTN Index2;\r
+\r
+ BisPtr = PxebcBisStart (\r
+ Private,\r
+ &BisAppHandle,\r
+ &BisDataSigInfo\r
+ );\r
+\r
+ if (BisPtr == NULL) {\r
+ //\r
+ // %%TBD - In order to get here, BIS must have\r
+ // been present when PXEBC.Start() was called.\r
+ // BIS had to be shutdown/removed/damaged\r
+ // before PXEBC.Discover() was called.\r
+ // Do we need to document a specific error\r
+ // for this case?\r
+ //\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Compute number of credential types.\r
+ //\r
+ Index2 = BisDataSigInfo->Length / sizeof (EFI_BIS_SIGNATURE_INFO);\r
+\r
+ DISCREDoptions.Header.OpCode = VEND_PXE_CREDENTIAL_TYPES;\r
+\r
+ DISCREDoptions.Header.Length = (UINT8) (Index2 * sizeof (PXE_CREDENTIAL));\r
+\r
+ OpLen = (UINT8) (DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS) + sizeof (DHCPV4_OP_HEADER) + DISCREDoptions.Header.Length);\r
+\r
+ BisSigInfo = (EFI_BIS_SIGNATURE_INFO *) BisDataSigInfo->Data;\r
+\r
+ for (Index = 0; Index < Index2; ++Index) {\r
+ UINT32 x;\r
+\r
+ CopyMem (&x, &BisSigInfo[Index], sizeof x);\r
+ x = HTONL (x);\r
+ CopyMem (&DISCREDoptions.Credentials[Index], &x, sizeof x);\r
+ }\r
+\r
+ PxebcBisStop (BisPtr, BisAppHandle, BisDataSigInfo);\r
+ } else {\r
+ OpLen = DHCPV4_OPTION_LENGTH (PXE_DISCOVER_OPTIONS);\r
+ }\r
+\r
+ DISCOVERoptions.Header.Length = OpLen;\r
+\r
+ ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen - 1] = OP_END;\r
+ ((UINT8 *) &DISCOVERoptions)[sizeof (DHCPV4_OP_HEADER) + OpLen] = OP_END;\r
+\r
+ StatCode = DoUdpWrite (\r
+ Private,\r
+ DestPtr,\r
+ &ServerPort,\r
+ (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,\r
+ &ClientPort\r
+ );\r
+\r
+ if (StatCode != EFI_SUCCESS) {\r
+ return StatCode;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ StatCode = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ return StatCode;\r
+ }\r
+\r
+ StatCode = gBS->SetTimer (\r
+ TimeoutEvent,\r
+ TimerRelative,\r
+ Private->Timeout * 10000000 + 1000000\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return StatCode;\r
+ }\r
+ //\r
+ // wait for ACK\r
+ //\r
+ for (;;) {\r
+ DHCP_RECEIVE_BUFFER *RxBufPtr;\r
+ UINT16 TmpType;\r
+ UINT16 TmpLayer;\r
+\r
+ RxBufPtr = UseBis ? &PXE_BIS_BUFFER : &PXE_ACK_BUFFER;\r
+ ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));\r
+\r
+ if (GetOfferAck (\r
+ Private,\r
+ AckEdit,\r
+ OpFlags,\r
+ (EFI_IP_ADDRESS *) &Private->ServerIp,\r
+ 0,\r
+ (EFI_IP_ADDRESS *) &DHCPV4_TRANSMIT_BUFFER.ciaddr,\r
+ &ClientPort,\r
+ RxBufPtr,\r
+ TimeoutEvent\r
+ ) != EFI_SUCCESS) {\r
+ break;\r
+ }\r
+ //\r
+ // check type of response - need PXEClient DHCPACK of proper type with bootfile\r
+ //\r
+ if (!(RxBufPtr->OpAdds.Status & PXE_TYPE) ||\r
+ (UseBis && (RxBufPtr->OpAdds.Status & USE_THREE_BYTE)) ||\r
+ !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1] ||\r
+ !RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1] ||\r
+ !InServerList((EFI_IP_ADDRESS *)&((DHCPV4_OP_SERVER_IP *)RxBufPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX-1])->Ip, ServerListPtr)) {\r
+\r
+ continue;\r
+ }\r
+\r
+ TmpType = TmpLayer = 0;\r
+\r
+ if (RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1]) {\r
+ TmpType = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Type);\r
+\r
+ if (RxBufPtr->OpAdds.Status & USE_THREE_BYTE) {\r
+ TmpLayer = (UINT16) (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer >> 8);\r
+ } else {\r
+ TmpLayer = NTOHS (((PXE_OP_BOOT_ITEM *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_ITEM_IX - 1])->Layer);\r
+ }\r
+ }\r
+\r
+ if (TmpType != Type) {\r
+ continue;\r
+ }\r
+\r
+ if (UseBis) {\r
+ if (!RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]) {\r
+ continue;\r
+ }\r
+\r
+ if (!VerifyCredentialOption (\r
+ (UINT8 *) &DISCREDoptions.Header,\r
+ (UINT8 *) RxBufPtr->OpAdds.PxeOptAdds[VEND_PXE_CREDENTIAL_TYPES_IX - 1]\r
+ )) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ *LayerPtr = TmpLayer;\r
+\r
+ if (UseBis) {\r
+ CopyMem (\r
+ &PxebcMode->PxeBisReply,\r
+ &RxBufPtr->u.Dhcpv4,\r
+ sizeof (EFI_PXE_BASE_CODE_PACKET)\r
+ );\r
+\r
+ PxebcMode->PxeBisReplyReceived = TRUE;\r
+\r
+ StatCode = DoDiscover (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,\r
+ Type,\r
+ LayerPtr,\r
+ FALSE,\r
+ &Private->ServerIp,\r
+ 0\r
+ );\r
+\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return StatCode;\r
+ }\r
+\r
+ PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = TRUE;\r
+\r
+ CopyMem (\r
+ &PxebcMode->PxeDiscover,\r
+ &*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER,\r
+ sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &DHCPV4_TRANSMIT_BUFFER)\r
+ );\r
+\r
+ CopyMem (\r
+ &PxebcMode->PxeReply,\r
+ &*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4,\r
+ sizeof (*(EFI_PXE_BASE_CODE_PACKET *) &RxBufPtr->u.Dhcpv4)\r
+ );\r
+\r
+ AddRouters (Private, RxBufPtr);\r
+\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ }\r
+ //\r
+ // end for loop\r
+ //\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+ Parameters:\r
+ Private := Pointer to PxeBc interface\r
+ Type :=\r
+ LayerPtr :=\r
+ UseBis :=\r
+ DiscoverInfoPtr :=\r
+ McastServerListPtr :=\r
+ ServerListPtr :=\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Discover (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ IN UINT16 Type,\r
+ IN UINT16 *LayerPtr,\r
+ IN BOOLEAN UseBis,\r
+ IN EFI_PXE_BASE_CODE_DISCOVER_INFO *DiscoverInfoPtr,\r
+ PXE_SERVER_LISTS *McastServerListPtr,\r
+ PXE_SERVER_LISTS *ServerListPtr\r
+ )\r
+{\r
+ EFI_IP_ADDRESS DestIp;\r
+ EFI_STATUS StatCode;\r
+\r
+ DEBUG ((DEBUG_INFO, "\nDiscover() Type=%d Layer=%d ", Type, *LayerPtr));\r
+\r
+ if (UseBis) {\r
+ DEBUG ((DEBUG_INFO, "BIS "));\r
+ }\r
+ //\r
+ // get dest IP addr - mcast, bcast, or unicast\r
+ //\r
+ if (DiscoverInfoPtr->UseMCast) {\r
+ DestIp.v4 = DiscoverInfoPtr->ServerMCastIp.v4;\r
+\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nDiscover() MCast %d.%d.%d.%d ",\r
+ DestIp.v4.Addr[0],\r
+ DestIp.v4.Addr[1],\r
+ DestIp.v4.Addr[2],\r
+ DestIp.v4.Addr[3])\r
+ );\r
+\r
+ if ((StatCode = DoDiscover (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,\r
+ Type,\r
+ LayerPtr,\r
+ UseBis,\r
+ &DestIp,\r
+ McastServerListPtr\r
+ )) != EFI_TIMEOUT) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nDiscover() status == %r (%Xh)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+\r
+ return StatCode;\r
+ }\r
+ }\r
+\r
+ if (DiscoverInfoPtr->UseBCast) {\r
+ DEBUG ((DEBUG_INFO, "\nDiscver() BCast "));\r
+\r
+ if ((StatCode = DoDiscover (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,\r
+ Type,\r
+ LayerPtr,\r
+ UseBis,\r
+ &BroadcastIP,\r
+ McastServerListPtr\r
+ )) != EFI_TIMEOUT) {\r
+\r
+ DEBUG ((DEBUG_WARN, "\nDiscover() status == %r (%Xh)", StatCode, StatCode));\r
+\r
+ return StatCode;\r
+ }\r
+ }\r
+\r
+ if (DiscoverInfoPtr->UseUCast) {\r
+ UINTN Index;\r
+\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nDiscover() UCast IP#=%d ",\r
+ ServerListPtr->Ipv4List.IpCount)\r
+ );\r
+\r
+ for (Index = 0; Index < ServerListPtr->Ipv4List.IpCount; ++Index) {\r
+ CopyMem (&DestIp, &ServerListPtr->Ipv4List.IpList[Index], 4);\r
+\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nDiscover() UCast %d.%d.%d.%d ",\r
+ DestIp.v4.Addr[0],\r
+ DestIp.v4.Addr[1],\r
+ DestIp.v4.Addr[2],\r
+ DestIp.v4.Addr[3])\r
+ );\r
+\r
+ if ((StatCode = DoDiscover (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,\r
+ Type,\r
+ LayerPtr,\r
+ UseBis,\r
+ &DestIp,\r
+ 0\r
+ )) != EFI_TIMEOUT) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nDiscover() status == %r (%Xh)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+\r
+ return StatCode;\r
+ }\r
+ }\r
+ }\r
+\r
+ DEBUG ((DEBUG_WARN, "\nDiscover() TIMEOUT"));\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/* BcDiscover()\r
+ */\r
+\r
+/**\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcDiscover (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,\r
+ IN UINT16 Type,\r
+ IN UINT16 *LayerPtr,\r
+ IN BOOLEAN UseBis,\r
+ IN EFI_PXE_BASE_CODE_DISCOVER_INFO * DiscoverInfoPtr OPTIONAL\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+ DHCP_RECEIVE_BUFFER *DhcpRxBuf;\r
+ PXE_SERVER_LISTS DefaultSrvList;\r
+ PXE_SERVER_LISTS *ServerListPtr;\r
+ PXE_SERVER_LISTS *McastServerListPtr;\r
+ UNION_PTR LocalPtr;\r
+ UINTN Index;\r
+ UINTN Index2;\r
+ BOOLEAN AcquiredSrvList;\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+\r
+ //\r
+ // Lock the instance data and make sure started\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ if (This->Mode == NULL || !This->Mode->Started) {\r
+ DEBUG ((DEBUG_ERROR, "BC was not started."));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ ServerListPtr = NULL;\r
+ McastServerListPtr = NULL;\r
+ AcquiredSrvList = FALSE;\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+\r
+ if (!GetMem (Private)) {\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (UseBis) {\r
+ if (!PxebcMode->BisSupported) {\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;\r
+\r
+ if (Private->TotalSeconds == 0) {\r
+ //\r
+ // put in seconds field of DHCP send packets\r
+ //\r
+ Private->TotalSeconds = 4;\r
+ }\r
+\r
+ ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));\r
+\r
+ //\r
+ // if layer number not zero, use previous discover\r
+ //\r
+ if (*LayerPtr != 0) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0"));\r
+\r
+ if (DiscoverInfoPtr != NULL) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && DiscoverInfoPtr != NULL\n"));\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!PxebcMode->PxeDiscoverValid) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && PxeDiscoverValid == 0\n"));\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!PxebcMode->PxeReplyReceived) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && PxeReplyReceived == 0\n"));\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (UseBis && !PxebcMode->PxeBisReplyReceived) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() layer != 0 && PxeBisReplyReceived == 0\n"));\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DefaultInfo.UseUCast = TRUE;\r
+ DiscoverInfoPtr = &DefaultInfo;\r
+\r
+ DefaultSrvList.Ipv4List.IpCount = 1;\r
+ CopyMem (&DefaultSrvList.Ipv4List.IpList[0], &Private->ServerIp, 4);\r
+\r
+ ServerListPtr = &DefaultSrvList;\r
+ }\r
+ //\r
+ // layer is zero - see if info is supplied or if we need to use info from a cached offer\r
+ //\r
+ else if (!DiscoverInfoPtr) {\r
+ //\r
+ // not supplied - generate it\r
+ // make sure that there is cached, appropriate information\r
+ // if neither DhcpAck packet nor ProxyOffer packet has pxe info, fail\r
+ //\r
+ DhcpRxBuf = (PxebcMode->ProxyOfferReceived) ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;\r
+\r
+ if (!PxebcMode->DhcpAckReceived || !(DhcpRxBuf->OpAdds.Status & DISCOVER_TYPE)) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() !ack && !proxy"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DiscoverInfoPtr = &DefaultInfo;\r
+\r
+ LocalPtr.OpPtr = DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];\r
+\r
+ //\r
+ // if multicast enabled, need multicast address\r
+ //\r
+ if (!(LocalPtr.DiscoveryControl->ControlBits & DISABLE_MCAST)) {\r
+ DefaultInfo.UseMCast = TRUE;\r
+\r
+ CopyMem (\r
+ ((EFI_IPv4_ADDRESS *) &DefaultInfo.ServerMCastIp),\r
+ &((DHCPV4_OP_IP_ADDRESS *) DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_MCAST_ADDR_IX - 1])->Ip,\r
+ sizeof (EFI_IPv4_ADDRESS)\r
+ );\r
+ }\r
+\r
+ DefaultInfo.UseBCast = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & DISABLE_BCAST) == 0);\r
+\r
+ DefaultInfo.MustUseList = (BOOLEAN) ((LocalPtr.DiscoveryControl->ControlBits & USE_ACCEPT_LIST) != 0);\r
+\r
+ DefaultInfo.UseUCast = (BOOLEAN)\r
+ (\r
+ (DefaultInfo.MustUseList) ||\r
+ ((LocalPtr.DiscoveryControl->ControlBits & (DISABLE_MCAST | DISABLE_BCAST)) == (DISABLE_MCAST | DISABLE_BCAST))\r
+ );\r
+\r
+ if ((DefaultInfo.UseUCast | DefaultInfo.MustUseList) && !ExtractBootServerList (\r
+ Type,\r
+ DhcpRxBuf->OpAdds.PxeOptAdds[VEND_PXE_BOOT_SERVERS_IX - 1],\r
+ &ServerListPtr\r
+ )) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() type not in list"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Info supplied - make SrvList if required\r
+ // if we use ucast discovery or must use list, there better be one\r
+ //\r
+ else if (DiscoverInfoPtr->UseUCast || DiscoverInfoPtr->MustUseList) {\r
+ //\r
+ // there better be a list\r
+ //\r
+ if (DiscoverInfoPtr->IpCnt == 0) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() no bootserver list"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // get its size\r
+ //\r
+ for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {\r
+ if (DiscoverInfoPtr->SrvList[Index].Type == Type) {\r
+ if (DiscoverInfoPtr->SrvList[Index].AcceptAnyResponse) {\r
+ if (Index2 != 0) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() accept any?"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ } else {\r
+ Index2 = 1;\r
+ DefaultSrvList.Ipv4List.IpCount = 0;\r
+ ServerListPtr = &DefaultSrvList;\r
+ break;\r
+ }\r
+ } else {\r
+ ++Index2;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Index2 == 0) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() !Index2?"));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (ServerListPtr == NULL) {\r
+ ServerListPtr = AllocatePool (\r
+ sizeof (PXEV4_SERVER_LIST) + (Index2 - 1) * sizeof (EFI_IPv4_ADDRESS)\r
+ );\r
+\r
+ if (ServerListPtr == NULL) {\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // build an array of IP addresses from the server list\r
+ //\r
+ AcquiredSrvList = TRUE;\r
+ ServerListPtr->Ipv4List.IpCount = (UINT8) Index2;\r
+\r
+ for (Index = Index2 = 0; Index < DiscoverInfoPtr->IpCnt; ++Index) {\r
+ if (DiscoverInfoPtr->SrvList[Index].Type == Type) {\r
+ CopyMem (\r
+ &ServerListPtr->Ipv4List.IpList[Index2++],\r
+ &DiscoverInfoPtr->SrvList[Index].IpAddr.v4,\r
+ sizeof ServerListPtr->Ipv4List.IpList[0]\r
+ );\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (DiscoverInfoPtr->MustUseList) {\r
+ McastServerListPtr = ServerListPtr;\r
+ }\r
+\r
+ if (!(DiscoverInfoPtr->UseMCast || DiscoverInfoPtr->UseBCast || DiscoverInfoPtr->UseUCast)) {\r
+ DEBUG ((DEBUG_WARN, "\nBcDiscover() Nothing to use!\n"));\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ PxebcMode->PxeDiscoverValid = PxebcMode->PxeReplyReceived = PxebcMode->PxeBisReplyReceived = FALSE;\r
+\r
+ StatCode = Discover (\r
+ Private,\r
+ Type,\r
+ LayerPtr,\r
+ UseBis,\r
+ DiscoverInfoPtr,\r
+ McastServerListPtr,\r
+ ServerListPtr\r
+ );\r
+\r
+ if (AcquiredSrvList) {\r
+ gBS->FreePool (ServerListPtr);\r
+ }\r
+\r
+ FreeMem (Private);\r
+\r
+ //\r
+ // Unlock the instance data\r
+ //\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nBcDiscover() status == %r (%Xh)\n",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcSetPackets (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,\r
+ BOOLEAN *NewDhcpDiscoverValid, OPTIONAL\r
+ BOOLEAN *NewDhcpAckReceived, OPTIONAL\r
+ BOOLEAN *NewProxyOfferReceived, OPTIONAL\r
+ BOOLEAN *NewPxeDiscoverValid, OPTIONAL\r
+ BOOLEAN *NewPxeReplyReceived, OPTIONAL\r
+ BOOLEAN *NewPxeBisReplyReceived, OPTIONAL\r
+ IN EFI_PXE_BASE_CODE_PACKET * NewDhcpDiscover, OPTIONAL\r
+ IN EFI_PXE_BASE_CODE_PACKET * NewDhcpAck, OPTIONAL\r
+ IN EFI_PXE_BASE_CODE_PACKET * NewProxyOffer, OPTIONAL\r
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeDiscover, OPTIONAL\r
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeReply, OPTIONAL\r
+ IN EFI_PXE_BASE_CODE_PACKET * NewPxeBisReply OPTIONAL\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxebcMode;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+\r
+ //\r
+ // Lock the instance data and make sure started\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ if (This->Mode == NULL || !This->Mode->Started) {\r
+ DEBUG ((DEBUG_ERROR, "BC was not started."));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ PxebcMode = Private->EfiBc.Mode;\r
+\r
+ if (Private->DhcpPacketBuffer == NULL) {\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ sizeof (DHCP_RECEIVE_BUFFER) * (PXE_BIS_INDEX + 1),\r
+ &Private->DhcpPacketBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || Private->DhcpPacketBuffer == NULL) {\r
+ Private->DhcpPacketBuffer = NULL;\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+ //\r
+ // Issue BC command\r
+ //\r
+ //\r
+ // reset\r
+ //\r
+ Private->FileSize = 0;\r
+ if (NewDhcpDiscoverValid != NULL) {\r
+ PxebcMode->DhcpDiscoverValid = *NewDhcpDiscoverValid;\r
+ }\r
+\r
+ if (NewDhcpAckReceived != NULL) {\r
+ PxebcMode->DhcpAckReceived = *NewDhcpAckReceived;\r
+ }\r
+\r
+ if (NewProxyOfferReceived != NULL) {\r
+ PxebcMode->ProxyOfferReceived = *NewProxyOfferReceived;\r
+ }\r
+\r
+ if (NewPxeDiscoverValid != NULL) {\r
+ PxebcMode->PxeDiscoverValid = *NewPxeDiscoverValid;\r
+ }\r
+\r
+ if (NewPxeReplyReceived != NULL) {\r
+ PxebcMode->PxeReplyReceived = *NewPxeReplyReceived;\r
+ }\r
+\r
+ if (NewPxeBisReplyReceived != NULL) {\r
+ PxebcMode->PxeBisReplyReceived = *NewPxeBisReplyReceived;\r
+ }\r
+\r
+ if (NewDhcpDiscover != NULL) {\r
+ CopyMem (\r
+ &PxebcMode->DhcpDiscover,\r
+ NewDhcpDiscover,\r
+ sizeof *NewDhcpDiscover\r
+ );\r
+ }\r
+\r
+ if (NewDhcpAck != NULL) {\r
+ CopyParse (Private, &PxebcMode->DhcpAck, NewDhcpAck, DHCPV4_ACK_INDEX);\r
+ }\r
+\r
+ if (NewProxyOffer != NULL) {\r
+ CopyParse (Private, &PxebcMode->ProxyOffer, NewProxyOffer, PXE_OFFER_INDEX);\r
+ }\r
+\r
+ if (NewPxeDiscover != NULL) {\r
+ CopyMem (\r
+ &PxebcMode->PxeDiscover,\r
+ NewPxeDiscover,\r
+ sizeof *NewPxeDiscover\r
+ );\r
+ }\r
+\r
+ if (NewPxeReply != NULL) {\r
+ CopyParse (Private, &PxebcMode->PxeReply, NewPxeReply, PXE_ACK_INDEX);\r
+ }\r
+\r
+ if (NewPxeBisReply != NULL) {\r
+ CopyParse (Private, &PxebcMode->PxeBisReply, NewPxeBisReply, PXE_BIS_INDEX);\r
+ }\r
+ //\r
+ // Unlock the instance data\r
+ //\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* eof - pxe_bc_dhcp.c */\r
--- /dev/null
+/** @file\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
+\r
+**/\r
+\r
+\r
+#define RAND_MAX 0x10000\r
+\r
+#include "Bc.h"\r
+\r
+//\r
+// Definitions for internet group management protocol version 2 message\r
+// structure Per RFC 2236, November 1997\r
+//\r
+STATIC UINT8 RouterAlertOption[4] = { 0x80 | 20, 4, 0, 0 };\r
+STATIC IPV4_ADDR AllRoutersGroup = { { 224, 0, 0, 2 } };\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+VOID\r
+ClearGroupTimer (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINTN TimerId\r
+ )\r
+{\r
+ if (Private == NULL) {\r
+ return ;\r
+ }\r
+\r
+ if (TimerId >= Private->MCastGroupCount) {\r
+ return ;\r
+ }\r
+\r
+ if (Private->IgmpGroupEvent[TimerId] == NULL) {\r
+ return ;\r
+ }\r
+\r
+ gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);\r
+ Private->IgmpGroupEvent[TimerId] = NULL;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SetGroupTimer (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINTN TimerId,\r
+ UINTN MaxRespTime\r
+ )\r
+{\r
+ EFI_STATUS EfiStatus;\r
+\r
+ if (Private == NULL) {\r
+ return ;\r
+ }\r
+\r
+ if (TimerId >= Private->MCastGroupCount) {\r
+ return ;\r
+ }\r
+\r
+ if (Private->IgmpGroupEvent[TimerId] != NULL) {\r
+ gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);\r
+ }\r
+\r
+ EfiStatus = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &Private->IgmpGroupEvent[TimerId]\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ Private->IgmpGroupEvent[TimerId] = NULL;\r
+ return ;\r
+ }\r
+\r
+ EfiStatus = gBS->SetTimer (\r
+ Private->IgmpGroupEvent[TimerId],\r
+ TimerRelative,\r
+ MaxRespTime * 1000000 + Random (Private) % RAND_MAX\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);\r
+ Private->IgmpGroupEvent[TimerId] = NULL;\r
+ }\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SendIgmpMessage (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT8 Type,\r
+ INTN GroupId\r
+ )\r
+{\r
+ Private->IgmpMessage.Type = Type;\r
+ Private->IgmpMessage.MaxRespTime = 0;\r
+ Private->IgmpMessage.Checksum = 0;\r
+ Private->IgmpMessage.GroupAddress = Private->MCastGroup[GroupId];\r
+ Private->IgmpMessage.Checksum = IpChecksum (\r
+ (UINT16 *) &Private->IgmpMessage,\r
+ sizeof Private->IgmpMessage\r
+ );\r
+\r
+ Ipv4SendWOp (\r
+ Private,\r
+ 0,\r
+ (UINT8 *) &Private->IgmpMessage,\r
+ sizeof Private->IgmpMessage,\r
+ PROT_IGMP,\r
+ RouterAlertOption,\r
+ sizeof RouterAlertOption,\r
+ ((Type == IGMP_TYPE_LEAVE_GROUP) ? AllRoutersGroup.L : Private->IgmpMessage.GroupAddress),\r
+ EFI_PXE_BASE_CODE_FUNCTION_IGMP\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+VOID\r
+ReportIgmp (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ INTN GroupId\r
+ )\r
+{\r
+ //\r
+ // if version 1 querier, send v1 report\r
+ //\r
+ UINT8 Type;\r
+\r
+ if (Private->Igmpv1TimeoutEvent != NULL) {\r
+ if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {\r
+ gBS->CloseEvent (Private->Igmpv1TimeoutEvent);\r
+ Private->Igmpv1TimeoutEvent = NULL;\r
+ Private->UseIgmpv1Reporting = TRUE;\r
+ }\r
+ }\r
+\r
+ Type = (UINT8) (Private->UseIgmpv1Reporting ? IGMP_TYPE_V1REPORT : IGMP_TYPE_REPORT);\r
+\r
+ SendIgmpMessage (Private, Type, GroupId);\r
+ ClearGroupTimer (Private, GroupId);\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+VOID\r
+IgmpCheckTimers (\r
+ PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ UINTN GroupId;\r
+\r
+ if (Private == NULL) {\r
+ return ;\r
+ }\r
+\r
+ for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {\r
+ if (Private->IgmpGroupEvent[GroupId] == NULL) {\r
+ continue;\r
+ }\r
+\r
+ if (!EFI_ERROR (gBS->CheckEvent (Private->IgmpGroupEvent[GroupId]))) {\r
+ //\r
+ // send a report\r
+ //\r
+ ReportIgmp (Private, GroupId);\r
+ }\r
+ }\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return 0 := Group not found\r
+ @return other := Group ID#\r
+\r
+**/\r
+STATIC\r
+INTN\r
+FindMulticastGroup (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT32 GroupAddress\r
+ )\r
+{\r
+ UINTN GroupId;\r
+\r
+ for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {\r
+ if (Private->MCastGroup[GroupId] == GroupAddress) {\r
+ return GroupId + 1;\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+VOID\r
+IgmpJoinGroup (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ EFI_IP_ADDRESS *GroupPtr\r
+ )\r
+{\r
+ UINT32 Grp;\r
+\r
+ Grp = *(UINT32 *) GroupPtr;\r
+\r
+ //\r
+ // see if we already have it or if we can't take anymore\r
+ //\r
+ if (FindMulticastGroup (Private, Grp) || Private->MCastGroupCount == MAX_MCAST_GROUPS) {\r
+ return ;\r
+ }\r
+ //\r
+ // add the group\r
+ //\r
+ Private->MCastGroup[Private->MCastGroupCount] = Grp;\r
+\r
+ ReportIgmp (Private, Private->MCastGroupCount);\r
+ //\r
+ // send a report\r
+ // so it will get sent again per RFC 2236\r
+ //\r
+ SetGroupTimer (\r
+ Private,\r
+ Private->MCastGroupCount++,\r
+ UNSOLICITED_REPORT_INTERVAL * 10\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+VOID\r
+IgmpLeaveGroup (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ EFI_IP_ADDRESS *GroupPtr\r
+ )\r
+{\r
+ UINT32 Grp;\r
+ UINTN GroupId;\r
+\r
+ Grp = *(UINT32 *) GroupPtr;\r
+\r
+ //\r
+ // if not in group, ignore\r
+ //\r
+ GroupId = FindMulticastGroup (Private, Grp);\r
+\r
+ if (GroupId == 0) {\r
+ return ;\r
+ }\r
+ //\r
+ // if not v1 querrier, send leave group IGMP message\r
+ //\r
+ if (Private->Igmpv1TimeoutEvent != NULL) {\r
+ if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {\r
+ gBS->CloseEvent (Private->Igmpv1TimeoutEvent);\r
+ Private->Igmpv1TimeoutEvent = NULL;\r
+ Private->UseIgmpv1Reporting = TRUE;\r
+ } else {\r
+ SendIgmpMessage (Private, IGMP_TYPE_LEAVE_GROUP, GroupId - 1);\r
+ }\r
+ }\r
+\r
+ while (GroupId < Private->MCastGroupCount) {\r
+ Private->MCastGroup[GroupId - 1] = Private->MCastGroup[GroupId];\r
+ Private->IgmpGroupEvent[GroupId - 1] = Private->IgmpGroupEvent[GroupId];\r
+ ++GroupId;\r
+ }\r
+\r
+ --Private->MCastGroupCount;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+VOID\r
+HandleIgmp (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ IGMPV2_MESSAGE *IgmpMessagePtr,\r
+ UINTN IgmpLength\r
+ )\r
+{\r
+ EFI_STATUS EfiStatus;\r
+ UINTN GroupId;\r
+ INTN MaxRespTime;\r
+\r
+ if (Private == NULL) {\r
+ return ;\r
+ }\r
+\r
+ if (Private->MCastGroupCount == 0) {\r
+ //\r
+ // if we don't belong to any multicast groups, ignore\r
+ //\r
+ return ;\r
+ }\r
+ //\r
+ // verify checksum\r
+ //\r
+ if (IpChecksum ((UINT16 *) IgmpMessagePtr, IgmpLength)) {\r
+ //\r
+ // bad checksum - ignore packet\r
+ //\r
+ return ;\r
+ }\r
+\r
+ switch (IgmpMessagePtr->Type) {\r
+ case IGMP_TYPE_QUERY:\r
+ //\r
+ // if a version 1 querier, note the fact and set max resp time\r
+ //\r
+ MaxRespTime = IgmpMessagePtr->MaxRespTime;\r
+\r
+ if (MaxRespTime == 0) {\r
+ Private->UseIgmpv1Reporting = TRUE;\r
+\r
+ if (Private->Igmpv1TimeoutEvent != NULL) {\r
+ gBS->CloseEvent (Private->Igmpv1TimeoutEvent);\r
+ }\r
+\r
+ EfiStatus = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &Private->Igmpv1TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ Private->Igmpv1TimeoutEvent = NULL;\r
+ } else {\r
+ EfiStatus = gBS->SetTimer (\r
+ Private->Igmpv1TimeoutEvent,\r
+ TimerRelative,\r
+ (UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000\r
+ );\r
+ }\r
+\r
+ MaxRespTime = IGMP_DEFAULT_MAX_RESPONSE_TIME * 10;\r
+ }\r
+ //\r
+ // if a general query (!GroupAddress), set all our group timers\r
+ //\r
+ if (!IgmpMessagePtr->GroupAddress) {\r
+ for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {\r
+ SetGroupTimer (Private, GroupId, MaxRespTime);\r
+ }\r
+ } else {\r
+ //\r
+ // specific query - set only specific group\r
+ //\r
+ GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);\r
+\r
+ if (GroupId != 0) {\r
+ SetGroupTimer (Private, GroupId - 1, MaxRespTime);\r
+ }\r
+ }\r
+\r
+ break;\r
+\r
+ //\r
+ // if we have a timer running for this group, clear it\r
+ //\r
+ case IGMP_TYPE_V1REPORT:\r
+ case IGMP_TYPE_REPORT:\r
+ GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);\r
+\r
+ if (GroupId != 0) {\r
+ ClearGroupTimer (Private, GroupId - 1);\r
+ }\r
+\r
+ break;\r
+ }\r
+}\r
+\r
+/* EOF - pxe_bc_igmp.c */\r
--- /dev/null
+/** @file\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
+ pxe_bc_ip.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Bc.h"\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+ Check if two IP addresses are on the same subnet.\r
+\r
+ @param IpLength Length of IP address in bytes.\r
+ @param Ip1 IP address to check.\r
+ @param Ip2 IP address to check.\r
+ @param SubnetMask Subnet mask to check with.\r
+\r
+ @retval TRUE IP addresses are on the same subnet.\r
+ @retval FALSE IP addresses are on different subnets.\r
+\r
+**/\r
+BOOLEAN\r
+OnSameSubnet (\r
+ IN UINTN IpLength,\r
+ IN EFI_IP_ADDRESS *Ip1,\r
+ IN EFI_IP_ADDRESS *Ip2,\r
+ IN EFI_IP_ADDRESS *SubnetMask\r
+ )\r
+{\r
+ if (IpLength == 0 || Ip1 == NULL || Ip2 == NULL || SubnetMask == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ while (IpLength-- != 0) {\r
+ if ((Ip1->v6.Addr[IpLength] ^ Ip2->v6.Addr[IpLength]) & SubnetMask->v6.Addr[IpLength]) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+ Add router to router table.\r
+\r
+ @param Private Pointer PxeBc instance data.\r
+ @param RouterIpPtr Pointer to router IP address.\r
+\r
+ @return Nothing\r
+\r
+**/\r
+VOID\r
+IpAddRouter (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN EFI_IP_ADDRESS *RouterIpPtr\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ UINTN Index;\r
+\r
+ if (Private == NULL || RouterIpPtr == NULL) {\r
+ return ;\r
+ }\r
+\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+\r
+ //\r
+ // if we are filled up or this is not on the same subnet, forget it\r
+ //\r
+ if ((PxeBcMode->RouteTableEntries == PXE_ROUTER_TABLE_SIZE) ||\r
+ !OnSameSubnet(Private->IpLength, &PxeBcMode->StationIp, RouterIpPtr, &PxeBcMode->SubnetMask)) {\r
+ return ;\r
+ }\r
+ //\r
+ // make sure we don't already have it\r
+ //\r
+ for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
+ if (!CompareMem (\r
+ &PxeBcMode->RouteTable[Index].GwAddr,\r
+ RouterIpPtr,\r
+ Private->IpLength\r
+ )) {\r
+ return ;\r
+ }\r
+ }\r
+ //\r
+ // keep it\r
+ //\r
+ ZeroMem (\r
+ &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries],\r
+ sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY)\r
+ );\r
+\r
+ CopyMem (\r
+ &PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries++].GwAddr,\r
+ RouterIpPtr,\r
+ Private->IpLength\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// return router ip to use for DestIp (0 if none)\r
+//\r
+STATIC\r
+EFI_IP_ADDRESS *\r
+GetRouterIp (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ EFI_IP_ADDRESS *DestIpPtr\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ UINTN Index;\r
+\r
+ if (Private == NULL || DestIpPtr == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+\r
+ for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
+ if (OnSameSubnet (\r
+ Private->IpLength,\r
+ &PxeBcMode->RouteTable[Index].IpAddr,\r
+ DestIpPtr,\r
+ &PxeBcMode->RouteTable[Index].SubnetMask\r
+ )) {\r
+ return &PxeBcMode->RouteTable[Index].GwAddr;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// routine to send ipv4 packet\r
+// ipv4 header of length HdrLth in TransmitBufferPtr\r
+// routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data\r
+// and gets dest MAC address\r
+//\r
+#define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr)\r
+#define IP_TX_HEADER IP_TX_BUFFER->IpHeader\r
+\r
+EFI_STATUS\r
+Ipv4Xmt (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT32 GatewayIp,\r
+ UINTN IpHeaderLength,\r
+ UINTN TotalHeaderLength,\r
+ VOID *Data,\r
+ UINTN DataLength,\r
+ EFI_PXE_BASE_CODE_FUNCTION Function\r
+ )\r
+{\r
+ EFI_MAC_ADDRESS DestMac;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ EFI_STATUS StatCode;\r
+ UINTN PacketLength;\r
+\r
+ Snp = Private->SimpleNetwork;\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+ StatCode = EFI_SUCCESS;\r
+ PacketLength = TotalHeaderLength + DataLength;\r
+\r
+ //\r
+ // get dest MAC address\r
+ // multicast - convert to hw equiv\r
+ // unicast on same net, use arp\r
+ // on different net, arp for router\r
+ //\r
+ if (IP_TX_HEADER.DestAddr.L == BROADCAST_IPv4) {\r
+ CopyMem (&DestMac, &Snp->Mode->BroadcastAddress, sizeof (DestMac));\r
+ } else if (IS_MULTICAST (&IP_TX_HEADER.DestAddr)) {\r
+ StatCode = (*Snp->MCastIpToMac) (Snp, PxeBcMode->UsingIpv6, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr, &DestMac);\r
+ } else {\r
+ UINT32 Ip;\r
+\r
+ if (OnSameSubnet (\r
+ Private->IpLength,\r
+ &PxeBcMode->StationIp,\r
+ (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr,\r
+ &PxeBcMode->SubnetMask\r
+ )) {\r
+ Ip = IP_TX_HEADER.DestAddr.L;\r
+ } else if (GatewayIp != 0) {\r
+ Ip = GatewayIp;\r
+ } else {\r
+ EFI_IP_ADDRESS *TmpIp;\r
+\r
+ TmpIp = GetRouterIp (Private, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr);\r
+\r
+ if (TmpIp == NULL) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nIpv4Xmit() Exit #1 %xh (%r)",\r
+ EFI_NO_RESPONSE,\r
+ EFI_NO_RESPONSE)\r
+ );\r
+\r
+ return EFI_NO_RESPONSE;\r
+ //\r
+ // no router\r
+ //\r
+ }\r
+\r
+ Ip = TmpIp->Addr[0];\r
+ }\r
+\r
+ if (!GetHwAddr (\r
+ Private,\r
+ (EFI_IP_ADDRESS *) &Ip,\r
+ (EFI_MAC_ADDRESS *) &DestMac\r
+ )) {\r
+ if (!PxeBcMode->AutoArp) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nIpv4Xmit() Exit #2 %xh (%r)",\r
+ EFI_DEVICE_ERROR,\r
+ EFI_DEVICE_ERROR)\r
+ );\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ StatCode = DoArp (\r
+ Private,\r
+ (EFI_IP_ADDRESS *) &Ip,\r
+ (EFI_MAC_ADDRESS *) &DestMac\r
+ );\r
+ }\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG ((DEBUG_WARN, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode, StatCode));\r
+ return StatCode;\r
+ }\r
+ //\r
+ // fill in packet info\r
+ //\r
+ SET_IPV4_VER_HDL (&IP_TX_HEADER, IpHeaderLength);\r
+ IP_TX_HEADER.TotalLength = HTONS (PacketLength);\r
+ IP_TX_HEADER.HeaderChecksum = IpChecksum ((UINT16 *) &IP_TX_HEADER, IpHeaderLength);\r
+ CopyMem (((UINT8 *) &IP_TX_HEADER) + TotalHeaderLength, Data, DataLength);\r
+\r
+ //\r
+ // send it\r
+ //\r
+ return SendPacket (\r
+ Private,\r
+ (UINT8 *) &IP_TX_HEADER - Snp->Mode->MediaHeaderSize,\r
+ &IP_TX_HEADER,\r
+ PacketLength,\r
+ &DestMac,\r
+ PXE_PROTOCOL_ETHERNET_IP,\r
+ Function\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// send ipv4 packet with option\r
+//\r
+EFI_STATUS\r
+Ipv4SendWOp (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT32 GatewayIp,\r
+ UINT8 *Msg,\r
+ UINTN MessageLength,\r
+ UINT8 Prot,\r
+ UINT8 *Option,\r
+ UINTN OptionLength,\r
+ UINT32 DestIp,\r
+ EFI_PXE_BASE_CODE_FUNCTION Function\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ UINTN HdrLth;\r
+\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+ HdrLth = sizeof (IPV4_HEADER) + OptionLength;\r
+\r
+ ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));\r
+ IP_TX_HEADER.TimeToLive = PxeBcMode->TTL;\r
+ IP_TX_HEADER.TypeOfService = PxeBcMode->ToS;\r
+ IP_TX_HEADER.Protocol = Prot;\r
+ IP_TX_HEADER.SrcAddr.L = *(UINT32 *) &PxeBcMode->StationIp;\r
+ IP_TX_HEADER.DestAddr.L = DestIp;\r
+ IP_TX_HEADER.Id = Random (Private);\r
+ CopyMem (IP_TX_BUFFER->u.Data, Option, OptionLength);\r
+ return Ipv4Xmt (\r
+ Private,\r
+ GatewayIp,\r
+ HdrLth,\r
+ HdrLth,\r
+ Msg,\r
+ MessageLength,\r
+ Function\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize\r
+//\r
+EFI_STATUS\r
+Ip4Send (\r
+ PXE_BASECODE_DEVICE *Private, // pointer to instance data\r
+ UINTN MayFrag, //\r
+ UINT8 Prot, // protocol\r
+ UINT32 SrcIp, // Source IP address\r
+ UINT32 DestIp, // Destination IP address\r
+ UINT32 GatewayIp, // used if not NULL and needed\r
+ UINTN HdrSize, // protocol header byte length\r
+ UINT8 *MessagePtr, // pointer to data\r
+ UINTN MessageLength // data byte length\r
+ )\r
+{\r
+ EFI_STATUS StatCode;\r
+ UINTN TotDataLength;\r
+\r
+ TotDataLength = HdrSize + MessageLength;\r
+\r
+ if (TotDataLength > MAX_IPV4_DATA_SIZE) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nIp4Send() Exit #1 %xh (%r)",\r
+ EFI_BAD_BUFFER_SIZE,\r
+ EFI_BAD_BUFFER_SIZE)\r
+ );\r
+\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));\r
+ IP_TX_HEADER.TimeToLive = DEFAULT_TTL;\r
+ IP_TX_HEADER.Protocol = Prot;\r
+ IP_TX_HEADER.SrcAddr.L = SrcIp;\r
+ IP_TX_HEADER.DestAddr.L = DestIp;\r
+ IP_TX_HEADER.Id = Random (Private);\r
+\r
+ if (!MayFrag) {\r
+ *(UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_NO_FRAG >> 8;\r
+ }\r
+ //\r
+ // check for need to fragment\r
+ //\r
+ if (TotDataLength > MAX_IPV4_FRAME_DATA_SIZE) {\r
+ UINTN DataLengthSent;\r
+ UINT16 FragmentOffset;\r
+\r
+ FragmentOffset = IP_MORE_FRAG;\r
+ //\r
+ // frag offset field\r
+ //\r
+ if (!MayFrag) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nIp4Send() Exit #2 %xh (%r)",\r
+ EFI_BAD_BUFFER_SIZE,\r
+ EFI_BAD_BUFFER_SIZE)\r
+ );\r
+\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+ //\r
+ // send out in fragments - first includes upper level header\r
+ // all are max and include more frag bit except last\r
+ //\r
+ * (UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_MORE_FRAG >> 8;\r
+\r
+#define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)\r
+#define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)\r
+\r
+ DataLengthSent = IPV4_FRAG_SIZE - HdrSize;\r
+\r
+ StatCode = Ipv4Xmt (\r
+ Private,\r
+ GatewayIp,\r
+ sizeof (IPV4_HEADER),\r
+ sizeof (IPV4_HEADER) + HdrSize,\r
+ MessagePtr,\r
+ DataLengthSent,\r
+ Private->Function\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nIp4Send() Exit #3 %xh (%r)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+\r
+ return StatCode;\r
+ }\r
+\r
+ MessagePtr += DataLengthSent;\r
+ MessageLength -= DataLengthSent;\r
+ FragmentOffset += IPV4_FRAG_OFF_INC;\r
+ IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);\r
+\r
+ while (MessageLength > IPV4_FRAG_SIZE) {\r
+ StatCode = Ipv4Xmt (\r
+ Private,\r
+ GatewayIp,\r
+ sizeof (IPV4_HEADER),\r
+ sizeof (IPV4_HEADER),\r
+ MessagePtr,\r
+ IPV4_FRAG_SIZE,\r
+ Private->Function\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nIp4Send() Exit #3 %xh (%r)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+\r
+ return StatCode;\r
+ }\r
+\r
+ MessagePtr += IPV4_FRAG_SIZE;\r
+ MessageLength -= IPV4_FRAG_SIZE;\r
+ FragmentOffset += IPV4_FRAG_OFF_INC;\r
+ IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);\r
+ }\r
+\r
+ * (UINT8 *) (&IP_TX_HEADER.FragmentFields) &= ~(IP_MORE_FRAG >> 8);\r
+ HdrSize = 0;\r
+ }\r
+ //\r
+ // transmit\r
+ //\r
+ return Ipv4Xmt (\r
+ Private,\r
+ GatewayIp,\r
+ sizeof (IPV4_HEADER),\r
+ sizeof (IPV4_HEADER) + HdrSize,\r
+ MessagePtr,\r
+ MessageLength,\r
+ Private->Function\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// return true if dst IP in receive header matched with what's enabled\r
+//\r
+STATIC\r
+BOOLEAN\r
+IPgood (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ IPV4_HEADER *IpHeader\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ UINTN Index;\r
+\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+\r
+ if (PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {\r
+ return TRUE;\r
+ }\r
+\r
+ if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) &&\r
+ IS_MULTICAST (&IpHeader->DestAddr)\r
+ ) {\r
+ return TRUE;\r
+ }\r
+\r
+ if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) &&\r
+ PxeBcMode->StationIp.Addr[0] == IpHeader->DestAddr.L\r
+ ) {\r
+ return TRUE;\r
+ }\r
+\r
+ if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) && IpHeader->DestAddr.L == BROADCAST_IPv4) {\r
+ return TRUE;\r
+ }\r
+\r
+ for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; ++Index) {\r
+ if (IpHeader->DestAddr.L == PxeBcMode->IpFilter.IpList[Index].Addr[0]) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// receive up to MessageLength message into MessagePtr for protocol Prot\r
+// return message length, src/dest ips if select any, and pointer to protocol\r
+// header routine will filter based on source and/or dest ip if OpFlags set.\r
+//\r
+EFI_STATUS\r
+IpReceive (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ PXE_OPFLAGS OpFlags,\r
+ EFI_IP_ADDRESS *SrcIpPtr,\r
+ EFI_IP_ADDRESS *DestIpPtr,\r
+ UINT8 Prot,\r
+ VOID *HeaderPtr,\r
+ UINTN HdrSize,\r
+ UINT8 *MessagePtr,\r
+ UINTN *MessageLengthPtr,\r
+ EFI_EVENT TimeoutEvent\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ EFI_STATUS StatCode;\r
+ UINTN ByteCount;\r
+ UINTN FragmentCount;\r
+ UINTN ExpectedPacketLength;\r
+ UINTN Id;\r
+ BOOLEAN GotFirstFragment;\r
+ BOOLEAN GotLastFragment;\r
+\r
+ DEBUG (\r
+ (DEBUG_NET,\r
+ "\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d",\r
+ HeaderPtr,\r
+ HdrSize,\r
+ MessagePtr,\r
+ *MessageLengthPtr)\r
+ );\r
+\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+ PxeBcMode->IcmpErrorReceived = FALSE;\r
+\r
+ ExpectedPacketLength = 0;\r
+ GotFirstFragment = FALSE;\r
+ GotLastFragment = FALSE;\r
+ FragmentCount = 0;\r
+ ByteCount = 0;\r
+ Id = 0;\r
+\r
+ for (;;) {\r
+ IPV4_HEADER IpHdr;\r
+ UINTN FFlds;\r
+ UINTN TotalLength;\r
+ UINTN FragmentOffset;\r
+ UINTN HeaderSize;\r
+ UINTN BufferSize;\r
+ UINTN IpHeaderLength;\r
+ UINTN DataLength;\r
+ UINT16 Protocol;\r
+ UINT8 *NextHdrPtr;\r
+ UINT8 *PacketPtr;\r
+\r
+ StatCode = WaitForReceive (\r
+ Private,\r
+ Private->Function,\r
+ TimeoutEvent,\r
+ &HeaderSize,\r
+ &BufferSize,\r
+ &Protocol\r
+ );\r
+\r
+ if (EFI_ERROR (StatCode)) {\r
+ return StatCode;\r
+ }\r
+\r
+ PacketPtr = Private->ReceiveBufferPtr + HeaderSize;\r
+\r
+ if (Protocol == PXE_PROTOCOL_ETHERNET_ARP) {\r
+ HandleArpReceive (\r
+ Private,\r
+ (ARP_PACKET *) PacketPtr,\r
+ Private->ReceiveBufferPtr\r
+ );\r
+\r
+ continue;\r
+ }\r
+\r
+ if (Protocol != PXE_PROTOCOL_ETHERNET_IP) {\r
+ continue;\r
+ }\r
+\r
+#define IpRxHeader ((IPV4_HEADER *) PacketPtr)\r
+\r
+ //\r
+ // filter for version & check sum\r
+ //\r
+ IpHeaderLength = IPV4_HEADER_LENGTH (IpRxHeader);\r
+\r
+ if ((IpRxHeader->VersionIhl >> 4) != IPVER4) {\r
+ continue;\r
+ }\r
+\r
+ if (IpChecksum ((UINT16 *) IpRxHeader, IpHeaderLength)) {\r
+ continue;\r
+ }\r
+\r
+ CopyMem (&IpHdr, IpRxHeader, sizeof (IpHdr));\r
+ TotalLength = NTOHS (IpHdr.TotalLength);\r
+\r
+ if (IpHdr.Protocol == PROT_TCP) {\r
+ //\r
+ // The NextHdrPtr is used to seed the header buffer we are passing back.\r
+ // That being the case, we want to see everything in pPkt which contains\r
+ // everything but the ethernet (or whatever) frame. IP + TCP in this case.\r
+ //\r
+ DataLength = TotalLength;\r
+ NextHdrPtr = PacketPtr;\r
+ } else {\r
+ DataLength = TotalLength - IpHeaderLength;\r
+ NextHdrPtr = PacketPtr + IpHeaderLength;\r
+ }\r
+ //\r
+ // If this is an ICMP, it might not be for us.\r
+ // Double check the state of the IP stack and the\r
+ // packet fields before assuming it is an ICMP\r
+ // error. ICMP requests are not supported by the\r
+ // PxeBc IP stack and should be ignored.\r
+ //\r
+ if (IpHdr.Protocol == PROT_ICMP) {\r
+ ICMPV4_HEADER *Icmpv4;\r
+\r
+ Icmpv4 = (ICMPV4_HEADER *) NextHdrPtr;\r
+\r
+ //\r
+ // For now only obvious ICMP error replies will be accepted by\r
+ // this stack. This still makes us vulnerable to DoS attacks.\r
+ // But at least we will not be killed by DHCP daemons.\r
+ //\r
+ switch (Icmpv4->Type) {\r
+ case ICMP_REDIRECT:\r
+ case ICMP_ECHO:\r
+ case ICMP_ROUTER_ADV:\r
+ case ICMP_ROUTER_SOLICIT:\r
+ case ICMP_TIMESTAMP:\r
+ case ICMP_TIMESTAMP_REPLY:\r
+ case ICMP_INFO_REQ:\r
+ case ICMP_INFO_REQ_REPLY:\r
+ case ICMP_SUBNET_MASK_REQ:\r
+ case ICMP_SUBNET_MASK_REPLY:\r
+ default:\r
+ continue;\r
+\r
+ //\r
+ // %%TBD - This should be implemented.\r
+ //\r
+ case ICMP_ECHO_REPLY:\r
+ continue;\r
+\r
+ case ICMP_DEST_UNREACHABLE:\r
+ case ICMP_TIME_EXCEEDED:\r
+ case ICMP_PARAMETER_PROBLEM:\r
+ case ICMP_SOURCE_QUENCH:\r
+ PxeBcMode->IcmpErrorReceived = TRUE;\r
+\r
+ CopyMem (\r
+ &PxeBcMode->IcmpError,\r
+ NextHdrPtr,\r
+ sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)\r
+ );\r
+\r
+ DEBUG (\r
+ (DEBUG_NET,\r
+ "\nIpReceive() Exit #1 %Xh (%r)",\r
+ EFI_ICMP_ERROR,\r
+ EFI_ICMP_ERROR)\r
+ );\r
+ }\r
+\r
+ return EFI_ICMP_ERROR;\r
+ }\r
+\r
+ if (IpHdr.Protocol == PROT_IGMP) {\r
+ HandleIgmp (Private, (IGMPV2_MESSAGE *) NextHdrPtr, DataLength);\r
+\r
+ DEBUG ((DEBUG_NET, "\n IGMP"));\r
+ continue;\r
+ }\r
+ //\r
+ // check for protocol\r
+ //\r
+ if (IpHdr.Protocol != Prot) {\r
+ continue;\r
+ }\r
+ //\r
+ // do filtering\r
+ //\r
+ if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr && SrcIpPtr->Addr[0] != IpHdr.SrcAddr.L) {\r
+ DEBUG ((DEBUG_NET, "\n Not expected source IP address."));\r
+ continue;\r
+ }\r
+\r
+ if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) {\r
+ if (!IPgood (Private, &IpHdr)) {\r
+ continue;\r
+ }\r
+ } else if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP)) {\r
+ if (DestIpPtr == NULL) {\r
+ if (PxeBcMode->StationIp.Addr[0] != IpHdr.DestAddr.L) {\r
+ continue;\r
+ }\r
+ } else if (DestIpPtr->Addr[0] != IpHdr.DestAddr.L) {\r
+ continue;\r
+ }\r
+ }\r
+ //\r
+ // get some data we need\r
+ //\r
+ FFlds = NTOHS (IpHdr.FragmentFields);\r
+ FragmentOffset = ((FFlds & IP_FRAG_OFF_MSK) << 3);\r
+\r
+ /* Keep count of fragments that belong to this session.\r
+ * If we get packets with a different IP ID number,\r
+ * ignore them. Ignored packets should be handled\r
+ * by the upper level protocol.\r
+ */\r
+ if (FragmentCount == 0) {\r
+ Id = IpHdr.Id;\r
+\r
+ if (DestIpPtr != NULL) {\r
+ DestIpPtr->Addr[0] = IpHdr.DestAddr.L;\r
+ }\r
+\r
+ if (SrcIpPtr != NULL) {\r
+ SrcIpPtr->Addr[0] = IpHdr.SrcAddr.L;\r
+ }\r
+ } else {\r
+ if (IpHdr.Id != Id) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ ++FragmentCount;\r
+\r
+ /* Fragment management.\r
+ */\r
+ if (FragmentOffset == 0) {\r
+ /* This is the first fragment (may also be the\r
+ * only fragment).\r
+ */\r
+ GotFirstFragment = TRUE;\r
+\r
+ /* If there is a separate protocol header buffer,\r
+ * copy the header, adjust the data pointer and\r
+ * the data length.\r
+ */\r
+ if (HdrSize != 0) {\r
+ CopyMem (HeaderPtr, NextHdrPtr, HdrSize);\r
+\r
+ NextHdrPtr += HdrSize;\r
+ DataLength -= HdrSize;\r
+ }\r
+ } else {\r
+ /* If there is a separate protocol header buffer,\r
+ * adjust the fragment offset.\r
+ */\r
+ FragmentOffset -= HdrSize;\r
+ }\r
+\r
+ /* See if this is the last fragment.\r
+ */\r
+ if (!(FFlds & IP_MORE_FRAG)) {\r
+ //\r
+ // This is the last fragment (may also be the only fragment).\r
+ //\r
+ GotLastFragment = TRUE;\r
+\r
+ /* Compute the expected length of the assembled\r
+ * packet. This will be used to decide if we\r
+ * have gotten all of the fragments.\r
+ */\r
+ ExpectedPacketLength = FragmentOffset + DataLength;\r
+ }\r
+\r
+ DEBUG (\r
+ (DEBUG_NET,\r
+ "\n ID = %Xh Off = %d Len = %d",\r
+ Id,\r
+ FragmentOffset,\r
+ DataLength)\r
+ );\r
+\r
+ /* Check for receive buffer overflow.\r
+ */\r
+ if (FragmentOffset + DataLength > *MessageLengthPtr) {\r
+ /* There is not enough space in the receive\r
+ * buffer for the fragment.\r
+ */\r
+ DEBUG (\r
+ (DEBUG_NET,\r
+ "\nIpReceive() Exit #3 %Xh (%r)",\r
+ EFI_BUFFER_TOO_SMALL,\r
+ EFI_BUFFER_TOO_SMALL)\r
+ );\r
+\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ /* Copy data into receive buffer.\r
+ */\r
+ if (DataLength != 0) {\r
+ DEBUG ((DEBUG_NET, " To = %Xh", MessagePtr + FragmentOffset));\r
+\r
+ CopyMem (MessagePtr + FragmentOffset, NextHdrPtr, DataLength);\r
+ ByteCount += DataLength;\r
+ }\r
+\r
+ /* If we have seen the first and last fragments and\r
+ * the receive byte count is at least as large as the\r
+ * expected byte count, return SUCCESS.\r
+ *\r
+ * We could be tricked by receiving a fragment twice\r
+ * but the upper level protocol should figure this\r
+ * out.\r
+ */\r
+ if (GotFirstFragment && GotLastFragment && ByteCount >= ExpectedPacketLength) {\r
+ *MessageLengthPtr = ExpectedPacketLength;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+}\r
+\r
+/* eof - pxe_bc_ip.c */\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ pxe_bc_mtftp.c\r
+\r
+Abstract:\r
+ TFTP and MTFTP (multicast TFTP) implementation.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// The following #define is used to create a version that does not wait to\r
+// open after a listen. This is just for a special regression test of MTFTP\r
+// server to make sure multiple opens are handled correctly. Normally this\r
+// next line should be a comment.\r
+// #define SpecialNowaitVersion // comment out for normal operation\r
+//\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+#include "bc.h"\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+UINT64\r
+Swap64 (\r
+ UINT64 n\r
+ )\r
+{\r
+ union {\r
+ UINT64 n;\r
+ UINT8 b[8];\r
+ } u;\r
+\r
+ UINT8 t;\r
+\r
+ u.n = n;\r
+\r
+ t = u.b[0];\r
+ u.b[0] = u.b[7];\r
+ u.b[7] = t;\r
+\r
+ t = u.b[1];\r
+ u.b[1] = u.b[6];\r
+ u.b[6] = t;\r
+\r
+ t = u.b[2];\r
+ u.b[2] = u.b[5];\r
+ u.b[5] = t;\r
+\r
+ t = u.b[3];\r
+ u.b[3] = u.b[4];\r
+ u.b[4] = t;\r
+\r
+ return u.n;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return EFI_SUCCESS :=\r
+ @return EFI_TFTP_ERROR :=\r
+ @return other :=\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+TftpUdpRead (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT16 Operation,\r
+ VOID *HeaderPtr,\r
+ UINTN *BufferSizePtr,\r
+ VOID *BufferPtr,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,\r
+ EFI_IP_ADDRESS *OurIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,\r
+ UINT16 Timeout\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ EFI_STATUS Status;\r
+ EFI_EVENT TimeoutEvent;\r
+ UINTN HeaderSize;\r
+\r
+ //\r
+ //\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->SetTimer (\r
+ TimeoutEvent,\r
+ TimerRelative,\r
+ Timeout * 10000000 + 1000000\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return Status;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ HeaderSize = Private->BigBlkNumFlag ? sizeof (struct Tftpv4Ack8) : sizeof (struct Tftpv4Ack);\r
+\r
+#define ERROR_MESSAGE_PTR ((struct Tftpv4Error *) HeaderPtr)\r
+\r
+ Status = UdpRead (\r
+ Private,\r
+ Operation,\r
+ OurIpPtr,\r
+ OurPortPtr,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ &HeaderSize,\r
+ HeaderPtr,\r
+ BufferSizePtr,\r
+ BufferPtr,\r
+ TimeoutEvent\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS || ERROR_MESSAGE_PTR->OpCode != HTONS (TFTP_ERROR)) {\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return Status;\r
+ }\r
+ //\r
+ // got an error packet\r
+ // write one byte error code followed by error message\r
+ //\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+ PxeBcMode->TftpErrorReceived = TRUE;\r
+ PxeBcMode->TftpError.ErrorCode = (UINT8) NTOHS (ERROR_MESSAGE_PTR->ErrCode);\r
+ HeaderSize = MIN (*BufferSizePtr, sizeof PxeBcMode->TftpError.ErrorString);\r
+ CopyMem (PxeBcMode->TftpError.ErrorString, BufferPtr, HeaderSize);\r
+\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return EFI_TFTP_ERROR;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SendError (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr\r
+ )\r
+{\r
+ struct Tftpv4Error *ErrStr;\r
+ UINTN Len;\r
+\r
+ ErrStr = (VOID *) Private->TftpErrorBuffer;\r
+ Len = sizeof *ErrStr;\r
+\r
+ ErrStr->OpCode = HTONS (TFTP_ERROR);\r
+ ErrStr->ErrCode = HTONS (TFTP_ERR_OPTION);\r
+ ErrStr->ErrMsg[0] = 0;\r
+\r
+ UdpWrite (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ 0,\r
+ 0,\r
+ OurPortPtr,\r
+ 0,\r
+ 0,\r
+ &Len,\r
+ ErrStr\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+SendAckAndGetData (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,\r
+ EFI_IP_ADDRESS *ReplyIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,\r
+ UINT16 Timeout,\r
+ UINTN *ReplyLenPtr,\r
+ UINT8 *PxeBcMode,\r
+ UINT64 *BlockNumPtr,\r
+ BOOLEAN AckOnly\r
+ )\r
+{\r
+ struct Tftpv4Data DataBuffer;\r
+ struct Tftpv4Ack *Ack2Ptr;\r
+ struct Tftpv4Ack8 *Ack8Ptr;\r
+ EFI_STATUS Status;\r
+ UINTN Len;\r
+\r
+ Ack2Ptr = (VOID *) Private->TftpAckBuffer;\r
+ Ack8Ptr = (VOID *) Private->TftpAckBuffer;\r
+\r
+ if (Private->BigBlkNumFlag) {\r
+ Len = sizeof (struct Tftpv4Ack8);\r
+\r
+ Ack8Ptr->OpCode = HTONS (TFTP_ACK8);\r
+ Ack8Ptr->BlockNum = Swap64 (*BlockNumPtr);\r
+\r
+ Status = UdpWrite (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ 0,\r
+ 0,\r
+ OurPortPtr,\r
+ 0,\r
+ 0,\r
+ &Len,\r
+ Ack8Ptr\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ Len = sizeof (struct Tftpv4Ack);\r
+\r
+ Ack2Ptr->OpCode = HTONS (TFTP_ACK);\r
+ Ack2Ptr->BlockNum = HTONS ((UINT16) *BlockNumPtr);\r
+\r
+ Status = UdpWrite (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ 0,\r
+ 0,\r
+ OurPortPtr,\r
+ 0,\r
+ 0,\r
+ &Len,\r
+ Ack2Ptr\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if (AckOnly) {\r
+ //\r
+ // ACK of last packet. This is just a courtesy.\r
+ // Do not wait for response.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // read reply\r
+ //\r
+ Status = TftpUdpRead (\r
+ Private,\r
+ 0,\r
+ &DataBuffer,\r
+ ReplyLenPtr,\r
+ PxeBcMode,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ ReplyIpPtr,\r
+ OurPortPtr,\r
+ Timeout\r
+ );\r
+\r
+ if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
+ return Status;\r
+ }\r
+ //\r
+ // got a good reply (so far)\r
+ // check for next data packet\r
+ //\r
+ if (!Private->BigBlkNumFlag && DataBuffer.Header.OpCode == HTONS (TFTP_DATA)) {\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);\r
+ }\r
+\r
+ *BlockNumPtr = NTOHS (DataBuffer.Header.BlockNum);\r
+ return Status;\r
+ }\r
+\r
+ if (Private->BigBlkNumFlag && DataBuffer.Header.OpCode == HTONS (TFTP_DATA8)) {\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);\r
+ }\r
+\r
+ *BlockNumPtr = Swap64 (*(UINT64 *) &DataBuffer.Header.BlockNum);\r
+ return Status;\r
+ }\r
+\r
+ return EFI_PROTOCOL_ERROR;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+LockStepReceive (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINTN PacketSize,\r
+ UINT64 *BufferSizePtr,\r
+ UINT64 Offset,\r
+ UINT8 *BufferPtr,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,\r
+ EFI_IP_ADDRESS *ReplyIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,\r
+ UINT64 LastBlock,\r
+ UINT16 Timeout,\r
+ IN BOOLEAN DontUseBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 BlockNum;\r
+ UINT64 BufferSize;\r
+ UINTN Retries;\r
+ UINTN SaveLen;\r
+ UINTN ReplyLen;\r
+\r
+ ReplyLen = PacketSize;\r
+ BlockNum = LastBlock;\r
+\r
+ DEBUG ((DEBUG_INFO, "\nLockStepReceive() PacketSize = %d", PacketSize));\r
+\r
+ if (DontUseBuffer) {\r
+ BufferSize = PacketSize;\r
+ } else {\r
+ BufferSize = *BufferSizePtr - Offset;\r
+ BufferPtr += Offset;\r
+ }\r
+\r
+ while (ReplyLen >= 512 && ReplyLen == PacketSize) {\r
+ if (BufferSize < PacketSize) {\r
+ ReplyLen = (UINTN) ((BufferSize > 0) ? BufferSize : 0);\r
+ }\r
+\r
+ SaveLen = ReplyLen;\r
+\r
+ //\r
+ // write an ack packet and get data - retry up to NUM_ACK_RETRIES on timeout\r
+ //\r
+ Retries = NUM_ACK_RETRIES;\r
+\r
+ do {\r
+ ReplyLen = SaveLen;\r
+\r
+ Status = SendAckAndGetData (\r
+ Private,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ ReplyIpPtr,\r
+ OurPortPtr,\r
+ Timeout,\r
+ (UINTN *) &ReplyLen,\r
+ BufferPtr,\r
+ &BlockNum,\r
+ FALSE\r
+ );\r
+\r
+ if (!EFI_ERROR (Status) || Status == EFI_BUFFER_TOO_SMALL) {\r
+ if (BlockNum == LastBlock) {\r
+ DEBUG ((DEBUG_NET, "\nresend"));\r
+ //\r
+ // a resend - continue\r
+ //\r
+ Status = EFI_TIMEOUT;\r
+ } else if (Private->BigBlkNumFlag) {\r
+ if (BlockNum != ++LastBlock) {\r
+ DEBUG ((DEBUG_NET, "\nLockStepReceive() Exit #1a"));\r
+ //\r
+ // not correct blocknum - error\r
+ //\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ } else {\r
+ LastBlock = (LastBlock + 1) & 0xFFFF;\r
+ if (BlockNum != LastBlock) {\r
+ DEBUG ((DEBUG_NET, "\nLockStepReceive() Exit #1b"));\r
+ return EFI_PROTOCOL_ERROR;\r
+ //\r
+ // not correct blocknum - error\r
+ //\r
+ }\r
+ }\r
+ }\r
+ } while (Status == EFI_TIMEOUT && --Retries);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ SendError (Private, ServerIpPtr, ServerPortPtr, OurPortPtr);\r
+ }\r
+\r
+ return Status;\r
+ }\r
+\r
+ if (DontUseBuffer) {\r
+ BufferSize += ReplyLen;\r
+ } else {\r
+ BufferPtr += ReplyLen;\r
+ BufferSize -= ReplyLen;\r
+ }\r
+ }\r
+ //\r
+ // while (ReplyLen == PacketSize);\r
+ //\r
+ if (DontUseBuffer) {\r
+ if (BufferSizePtr != NULL) {\r
+ *BufferSizePtr = (BufferSize - PacketSize);\r
+ }\r
+ } else {\r
+ *BufferSizePtr -= BufferSize;\r
+ }\r
+\r
+ /* Send ACK of last packet. */\r
+ ReplyLen = 0;\r
+\r
+ SendAckAndGetData (\r
+ Private,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ ReplyIpPtr,\r
+ OurPortPtr,\r
+ Timeout,\r
+ (UINTN *) &ReplyLen,\r
+ BufferPtr,\r
+ &BlockNum,\r
+ TRUE\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// some literals\r
+//\r
+STATIC UINT8 Mode[] = MODE_BINARY;\r
+STATIC UINT8 BlockSizeOp[] = OP_BLKSIZE;\r
+STATIC UINT8 TsizeOp[] = OP_TFRSIZE;\r
+STATIC UINT8 OverwriteOp[] = OP_OVERWRITE;\r
+STATIC UINT8 BigBlkNumOp[] = OP_BIGBLKNUM;\r
+STATIC EFI_PXE_BASE_CODE_UDP_PORT TftpRequestPort = TFTP_OPEN_PORT;\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return Pointer to value field if option found or NULL if not found.\r
+\r
+**/\r
+STATIC\r
+UINT8 *\r
+FindOption (\r
+ UINT8 *OptionPtr,\r
+ INTN OpLen,\r
+ UINT8 *OackPtr,\r
+ INTN OackSize\r
+ )\r
+{\r
+ if ((OackSize -= OpLen) <= 0) {\r
+ return NULL;\r
+ }\r
+\r
+ do {\r
+ if (!CompareMem (OackPtr, OptionPtr, OpLen)) {\r
+ return OackPtr + OpLen;\r
+ }\r
+\r
+ ++OackPtr;\r
+ } while (--OackSize);\r
+\r
+ return NULL;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+#define BKSZOP 1 // block size\r
+#define TSIZEOP 2 // transfer size\r
+#define OVERWRITEOP 4 // overwrite\r
+#define BIGBLKNUMOP 8 // big block numbers\r
+STATIC\r
+EFI_STATUS\r
+TftpRwReq (\r
+ UINT16 Req,\r
+ UINT16 Options,\r
+ PXE_BASECODE_DEVICE *Private,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,\r
+ UINT8 *FilenamePtr,\r
+ UINTN *PacketSizePtr,\r
+ VOID *Buffer\r
+ )\r
+{\r
+ union {\r
+ UINT8 Data[514];\r
+ struct Tftpv4Req ReqStr;\r
+ } *u;\r
+\r
+ UINT16 OpFlags;\r
+ INTN Len;\r
+ INTN TotalLen;\r
+ UINT8 *Ptr;\r
+\r
+ if (*OurPortPtr == 0) {\r
+ OpFlags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT;\r
+ } else {\r
+ OpFlags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT;\r
+ }\r
+ //\r
+ // build the basic request - opcode, filename, mode\r
+ //\r
+ u = Buffer;\r
+ u->ReqStr.OpCode = HTONS (Req);\r
+ TotalLen = sizeof (Mode) + sizeof (u->ReqStr.OpCode) + (Len = 1 + AsciiStrLen (FilenamePtr));\r
+\r
+ CopyMem (u->ReqStr.FileName, FilenamePtr, Len);\r
+ Ptr = (UINT8 *) (u->ReqStr.FileName + Len);\r
+\r
+ CopyMem (Ptr, Mode, sizeof (Mode));\r
+ Ptr += sizeof (Mode);\r
+\r
+ if (Options & BKSZOP) {\r
+ CopyMem (Ptr, BlockSizeOp, sizeof (BlockSizeOp));\r
+ UtoA10 (*PacketSizePtr, Ptr + sizeof (BlockSizeOp));\r
+\r
+ TotalLen += (Len = 1 + AsciiStrLen (Ptr + sizeof (BlockSizeOp)) + sizeof (BlockSizeOp));\r
+\r
+ Ptr += Len;\r
+ }\r
+\r
+ if (Options & TSIZEOP) {\r
+ CopyMem (Ptr, TsizeOp, sizeof (TsizeOp));\r
+ CopyMem (Ptr + sizeof (TsizeOp), "0", 2);\r
+ TotalLen += sizeof (TsizeOp) + 2;\r
+ Ptr += sizeof (TsizeOp) + 2;\r
+ }\r
+\r
+ if (Options & OVERWRITEOP) {\r
+ CopyMem (Ptr, OverwriteOp, sizeof (OverwriteOp));\r
+ CopyMem (Ptr + sizeof (OverwriteOp), "1", 2);\r
+ TotalLen += sizeof (OverwriteOp) + 2;\r
+ Ptr += sizeof (OverwriteOp) + 2;\r
+ }\r
+\r
+ if (Options & BIGBLKNUMOP) {\r
+ CopyMem (Ptr, BigBlkNumOp, sizeof (BigBlkNumOp));\r
+ CopyMem (Ptr + sizeof (BigBlkNumOp), "8", 2);\r
+ TotalLen += sizeof (BigBlkNumOp) + 2;\r
+ Ptr += sizeof (BigBlkNumOp) + 2;\r
+ }\r
+ //\r
+ // send it\r
+ //\r
+ return UdpWrite (\r
+ Private,\r
+ OpFlags,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ 0,\r
+ 0,\r
+ OurPortPtr,\r
+ 0,\r
+ 0,\r
+ (UINTN *) &TotalLen,\r
+ u\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+TftpRwReqwResp (\r
+ UINT16 Req,\r
+ UINT16 Options,\r
+ PXE_BASECODE_DEVICE *Private,\r
+ VOID *HeaderPtr,\r
+ UINTN *PacketSizePtr,\r
+ UINTN *ReplyLenPtr,\r
+ VOID *BufferPtr,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerPortPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *ServerReplyPortPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT *OurPortPtr,\r
+ UINT8 *FilenamePtr,\r
+ UINT16 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN SaveReplyLen;\r
+ INTN Retries;\r
+ UINT8 Buffer[514];\r
+\r
+ SaveReplyLen = *ReplyLenPtr;\r
+ Retries = 3;\r
+ Private->BigBlkNumFlag = FALSE;\r
+ *OurPortPtr = 0;\r
+ //\r
+ // generate random\r
+ //\r
+ do {\r
+ if (*OurPortPtr != 0) {\r
+ if (++ *OurPortPtr == 0) {\r
+ *OurPortPtr = PXE_RND_PORT_LOW;\r
+ }\r
+ }\r
+ //\r
+ // send request from our Ip = StationIp\r
+ //\r
+ if ((Status = TftpRwReq (\r
+ Req,\r
+ Options,\r
+ Private,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ OurPortPtr,\r
+ FilenamePtr,\r
+ PacketSizePtr,\r
+ Buffer\r
+ )) != EFI_SUCCESS) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nTftpRwReqwResp() Exit #1 %xh (%r)",\r
+ Status,\r
+ Status)\r
+ );\r
+\r
+ return Status;\r
+ }\r
+ //\r
+ // read reply to our Ip = StationIp\r
+ //\r
+ *ReplyLenPtr = SaveReplyLen;\r
+\r
+ Status = TftpUdpRead (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT,\r
+ HeaderPtr,\r
+ ReplyLenPtr,\r
+ BufferPtr,\r
+ ServerIpPtr,\r
+ ServerReplyPortPtr,\r
+ 0,\r
+ OurPortPtr,\r
+ Timeout\r
+ );\r
+ } while (Status == EFI_TIMEOUT && --Retries);\r
+\r
+ if (!Options || Status != EFI_TFTP_ERROR) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nTftpRwReqwResp() Exit #2 %xh (%r)",\r
+ Status,\r
+ Status)\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ Status = TftpRwReqwResp (\r
+ Req,\r
+ 0,\r
+ Private,\r
+ HeaderPtr,\r
+ PacketSizePtr,\r
+ ReplyLenPtr,\r
+ BufferPtr,\r
+ ServerIpPtr,\r
+ ServerPortPtr,\r
+ ServerReplyPortPtr,\r
+ OurPortPtr,\r
+ FilenamePtr,\r
+ Timeout\r
+ );\r
+\r
+ DEBUG ((DEBUG_WARN, "\nTftpRwReqwResp() Exit #3 %xh (%r)", Status, Status));\r
+\r
+ return Status;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// mtftp listen\r
+// read on mcast ip, cport, from sport, for data packet\r
+// returns success if gets multicast last packet or all up to last block\r
+// if not missing, then finished\r
+//\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MtftpListen (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT64 *BufferSizePtr,\r
+ UINT8 *BufferPtr,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr,\r
+ UINT64 *StartBlockPtr,\r
+ UINTN *NumMissedPtr,\r
+ UINT16 TransTimeout,\r
+ UINT16 ListenTimeout,\r
+ UINT64 FinalBlock,\r
+ IN BOOLEAN DontUseBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ struct Tftpv4Ack Header;\r
+ UINT64 Offset;\r
+ UINT64 BlockNum;\r
+ UINT64 LastBlockNum;\r
+ UINT64 BufferSize;\r
+ UINTN NumMissed;\r
+ UINTN PacketSize;\r
+ UINTN SaveReplyLen;\r
+ UINTN ReplyLen;\r
+ UINT16 Timeout;\r
+\r
+ LastBlockNum = *StartBlockPtr;\r
+ Timeout = ListenTimeout;\r
+ *NumMissedPtr = 0;\r
+ PacketSize = 0;\r
+ BufferSize = *BufferSizePtr;\r
+ ReplyLen = MAX_TFTP_PKT_SIZE;;\r
+\r
+ //\r
+ // receive\r
+ //\r
+ do {\r
+ if ((SaveReplyLen = ReplyLen) > BufferSize) {\r
+ SaveReplyLen = (UINTN) BufferSize;\r
+ }\r
+\r
+ /* %%TBD - add big block number support */\r
+\r
+ //\r
+ // get data - loop on resends\r
+ //\r
+ do {\r
+ ReplyLen = SaveReplyLen;\r
+\r
+ if ((Status = TftpUdpRead (\r
+ Private,\r
+ 0,\r
+ &Header,\r
+ &ReplyLen,\r
+ BufferPtr,\r
+ ServerIpPtr,\r
+ &MtftpInfoPtr->SPort,\r
+ &MtftpInfoPtr->MCastIp,\r
+ &MtftpInfoPtr->CPort,\r
+ Timeout\r
+ )) != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+ //\r
+ // make sure a data packet\r
+ //\r
+ if (Header.OpCode != HTONS (TFTP_DATA)) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ } while ((BlockNum = NTOHS (Header.BlockNum)) == LastBlockNum);\r
+\r
+ //\r
+ // make sure still going up\r
+ //\r
+ if (LastBlockNum > BlockNum) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ if (BlockNum - LastBlockNum > 0xFFFFFFFF) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ } else {\r
+ NumMissed = (UINTN) (BlockNum - LastBlockNum - 1);\r
+ }\r
+\r
+ LastBlockNum = BlockNum;\r
+\r
+ //\r
+ // if first time through, some reinitialization\r
+ //\r
+ if (!PacketSize) {\r
+ *StartBlockPtr = BlockNum;\r
+ PacketSize = ReplyLen;\r
+ Timeout = TransTimeout;\r
+ } else {\r
+ *NumMissedPtr = (UINT16) (*NumMissedPtr + NumMissed);\r
+ }\r
+ //\r
+ // if missed packets, update start block,\r
+ // etc. and move packet to proper place in buffer\r
+ //\r
+ if (NumMissed) {\r
+ *StartBlockPtr = BlockNum;\r
+ if (!DontUseBuffer) {\r
+ Offset = NumMissed * PacketSize;\r
+ CopyMem (BufferPtr + Offset, BufferPtr, ReplyLen);\r
+ BufferPtr += Offset;\r
+ BufferSize -= Offset;\r
+ }\r
+ }\r
+\r
+ if (!DontUseBuffer) {\r
+ BufferPtr += ReplyLen;\r
+ BufferSize -= ReplyLen;\r
+ }\r
+ } while (ReplyLen == PacketSize && BlockNum != FinalBlock);\r
+\r
+ *BufferSizePtr = BufferSize;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return // mtftp open session\r
+ @return // return code EFI_SUCCESS\r
+ @return // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done\r
+ @return // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest\r
+ @return // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all\r
+ @retval GOTUNI returns NO_DATA go will go to TFTP session)\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MtftpOpen (\r
+ PXE_BASECODE_DEVICE * Private,\r
+ UINT64 *BufferSizePtr,\r
+ UINT8 *BufferPtr,\r
+ UINTN *PacketSizePtr,\r
+ EFI_IP_ADDRESS * ServerIpPtr,\r
+ UINT8 *FilenamePtr,\r
+ EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr,\r
+ UINT8 *CompletionStatusPtr,\r
+#define GOTUNI 1\r
+#define GOTMULTI 2\r
+ IN BOOLEAN DontUseBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_IP_ADDRESS OurReplyIp;\r
+ struct Tftpv4Ack Header;\r
+ INTN ReplyLen;\r
+ INTN Retries;\r
+ UINT8 *BufferPtr2;\r
+ UINT8 TmpBuf[514];\r
+\r
+ Retries = NUM_MTFTP_OPEN_RETRIES;\r
+ BufferPtr2 = BufferPtr;\r
+ *PacketSizePtr = (UINTN) (MIN (*BufferSizePtr, MAX_TFTP_PKT_SIZE));\r
+\r
+ do {\r
+ //\r
+ // send a read request\r
+ //\r
+ *CompletionStatusPtr = 0;\r
+\r
+ if ((Status = TftpRwReq (\r
+ TFTP_RRQ,\r
+ 0,\r
+ Private,\r
+ ServerIpPtr,\r
+ &MtftpInfoPtr->SPort,\r
+ &MtftpInfoPtr->CPort,\r
+ FilenamePtr,\r
+ PacketSizePtr,\r
+ TmpBuf\r
+ )) != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ for (;;) {\r
+ //\r
+ // read reply\r
+ //\r
+ ZeroMem (&OurReplyIp, Private->IpLength);\r
+ ReplyLen = *PacketSizePtr;\r
+\r
+ if ((Status = TftpUdpRead (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER,\r
+ &Header,\r
+ (UINTN *) &ReplyLen,\r
+ BufferPtr2,\r
+ ServerIpPtr,\r
+ &MtftpInfoPtr->SPort,\r
+ &OurReplyIp,\r
+ &MtftpInfoPtr->CPort,\r
+ MtftpInfoPtr->TransmitTimeout\r
+ )) == EFI_SUCCESS) {\r
+ //\r
+ // check for first data packet\r
+ //\r
+ if (Header.OpCode != HTONS (TFTP_DATA)) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ //\r
+ // check block num\r
+ //\r
+ if (Header.BlockNum != HTONS (1)) {\r
+ //\r
+ // it's not first\r
+ // if we are not the primary client,\r
+ // we probably got first and now second\r
+ // multicast but no unicast, so\r
+ // *CompletionStatusPtr = GOTMULTI - if this is\r
+ // the second, can just go on to listen\r
+ // starting with 2 as the last block\r
+ // received\r
+ //\r
+ if (Header.BlockNum != HTONS (2)) {\r
+ //\r
+ // not second\r
+ //\r
+ *CompletionStatusPtr = 0;\r
+ }\r
+\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // now actual\r
+ //\r
+ *PacketSizePtr = ReplyLen;\r
+ //\r
+ // see if a unicast data packet\r
+ //\r
+ if (!CompareMem (\r
+ &OurReplyIp,\r
+ &Private->EfiBc.Mode->StationIp,\r
+ Private->IpLength\r
+ )) {\r
+ *CompletionStatusPtr |= GOTUNI;\r
+ //\r
+ // it is\r
+ // if already got multicast packet,\r
+ // got em both\r
+ //\r
+ if (*CompletionStatusPtr & GOTMULTI) {\r
+ break;\r
+ }\r
+ } else if (!CompareMem (\r
+ &OurReplyIp,\r
+ &MtftpInfoPtr->MCastIp,\r
+ Private->IpLength\r
+ )) {\r
+ //\r
+ // otherwise see if a multicast data packet\r
+ //\r
+ *CompletionStatusPtr |= GOTMULTI;\r
+ //\r
+ // it is\r
+ // got first - bump pointer so that if\r
+ // second multi comes along, we're OK\r
+ //\r
+ if (!DontUseBuffer) {\r
+ BufferPtr2 = (UINT8 *) BufferPtr + ReplyLen;\r
+ }\r
+ //\r
+ // if already got unicast packet,\r
+ // got em both\r
+ //\r
+ if (*CompletionStatusPtr & GOTUNI) {\r
+ break;\r
+ }\r
+ } else {\r
+ //\r
+ // else protocol error\r
+ //\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ } else if (Status == EFI_TIMEOUT) {\r
+ //\r
+ // bad return code - if timed out, retry\r
+ //\r
+ break;\r
+ } else {\r
+ //\r
+ // else just bad - failed MTFTP open\r
+ //\r
+ return Status;\r
+ }\r
+ }\r
+ } while (Status == EFI_TIMEOUT && --Retries);\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ //\r
+ // open failed\r
+ //\r
+ return Status;\r
+ }\r
+ //\r
+ // got em both - go into receive mode\r
+ // routine to read rest of file after a successful open (TFTP or MTFTP)\r
+ // sends ACK and gets next data packet until short packet arrives,\r
+ // then sends ACK and (hopefully) times out\r
+ //\r
+ return LockStepReceive (\r
+ Private,\r
+ (UINT16) ReplyLen,\r
+ BufferSizePtr,\r
+ ReplyLen,\r
+ BufferPtr,\r
+ ServerIpPtr,\r
+ &MtftpInfoPtr->SPort,\r
+ &MtftpInfoPtr->MCastIp,\r
+ &MtftpInfoPtr->CPort,\r
+ 1,\r
+ MtftpInfoPtr->TransmitTimeout,\r
+ DontUseBuffer\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+MtftpDownload (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT64 *BufferSizePtr,\r
+ UINT8 *BufferPtr,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ UINT8 *FilenamePtr,\r
+ EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr,\r
+ IN BOOLEAN DontUseBuffer\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_IP_FILTER Filter;\r
+ EFI_STATUS Status;\r
+ UINT64 StartBlock;\r
+ UINT64 LastBlock;\r
+ UINT64 LastStartBlock;\r
+ UINT64 BufferSize;\r
+ UINTN Offset;\r
+ UINTN NumMissed;\r
+ UINT16 TransTimeout;\r
+ UINT16 ListenTimeout;\r
+ UINT8 *BufferPtrLocal;\r
+\r
+ TransTimeout = MtftpInfoPtr->TransmitTimeout;\r
+ ListenTimeout = MtftpInfoPtr->ListenTimeout;\r
+ LastBlock = 0;\r
+ LastStartBlock = 0;\r
+ Offset = 0;\r
+\r
+ Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;\r
+ Filter.IpCnt = 2;\r
+ Filter.IpList[0] = Private->EfiBc.Mode->StationIp;\r
+ Filter.IpList[1] = MtftpInfoPtr->MCastIp;\r
+\r
+ if ((Status = IpFilter (Private, &Filter)) != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ for (;;) {\r
+ StartBlock = LastStartBlock;\r
+ BufferSize = *BufferSizePtr - Offset;\r
+\r
+ if (DontUseBuffer) {\r
+ //\r
+ // overwrie the temp buf\r
+ //\r
+ BufferPtrLocal = BufferPtr;\r
+ } else {\r
+ BufferPtrLocal = BufferPtr + Offset;\r
+\r
+ }\r
+ //\r
+ // special !!! do not leave enabled in saved version on Source Safe\r
+ // Following code put in in order to create a special version for regression\r
+ // test of MTFTP server to make sure it handles mulitple opens correctly.\r
+ // This code should NOT be enabled normally.\r
+ //\r
+#ifdef SpecialNowaitVersion\r
+#pragma message ("This is special version for MTFTP regression test")\r
+ if (StartBlock || !LastBlock)\r
+#endif\r
+ if (((Status = MtftpListen (\r
+ Private,\r
+ &BufferSize,\r
+ BufferPtrLocal,\r
+ ServerIpPtr,\r
+ MtftpInfoPtr,\r
+ &StartBlock,\r
+ &NumMissed,\r
+ TransTimeout,\r
+ ListenTimeout,\r
+ LastBlock,\r
+ DontUseBuffer\r
+ )) != EFI_SUCCESS) && (Status != EFI_TIMEOUT)) {\r
+ return Status;\r
+ //\r
+ // failed\r
+ //\r
+ }\r
+ //\r
+ // if none were received, start block is not reset\r
+ //\r
+ if (StartBlock == LastStartBlock) {\r
+ UINT8 CompStat;\r
+\r
+ //\r
+ // timed out with none received - try MTFTP open\r
+ //\r
+ if ((Status = MtftpOpen (\r
+ Private,\r
+ BufferSizePtr,\r
+ BufferPtr,\r
+ &Offset,\r
+ ServerIpPtr,\r
+ FilenamePtr,\r
+ MtftpInfoPtr,\r
+ &CompStat,\r
+ DontUseBuffer\r
+ )) != EFI_SUCCESS) {\r
+ //\r
+ // open failure - try TFTP\r
+ //\r
+ return Status;\r
+ }\r
+ //\r
+ // return code EFI_SUCCESS\r
+ // and *CompletionStatusPtr = GOTUNI | GOTMULTI means done\r
+ // and *CompletionStatusPtr = GOTMULTI means got first two multicast packets, use listen for rest\r
+ // and *CompletionStatusPtr = 0 means did not get first two multicast packets, use listen for all\r
+ // (do not get = GOTUNI - returns NO_DATA go will go to TFTP session)\r
+ //\r
+ if (CompStat == (GOTUNI | GOTMULTI)) {\r
+ //\r
+ // finished - got it all\r
+ //\r
+ return Status;\r
+ }\r
+\r
+ if (CompStat) {\r
+ //\r
+ // offset is two packet lengths\r
+ //\r
+ Offset <<= 1;\r
+ //\r
+ // last block received\r
+ //\r
+ LastStartBlock = 2;\r
+ } else {\r
+ Offset = 0;\r
+ LastStartBlock = 0;\r
+ }\r
+\r
+ ListenTimeout = TransTimeout;\r
+ continue;\r
+ }\r
+ //\r
+ // did we get the last block\r
+ //\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // yes - set the file size if this was first time\r
+ //\r
+ if (!LastBlock) {\r
+ *BufferSizePtr -= BufferSize;\r
+ }\r
+ //\r
+ // if buffer was too small, finished\r
+ //\r
+ if (!DontUseBuffer) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ //\r
+ // if we got them all, finished\r
+ //\r
+ if (!NumMissed && StartBlock == LastStartBlock + 1) {\r
+ return Status;\r
+ }\r
+ //\r
+ // did not get them all - set last block\r
+ //\r
+ LastBlock = (UINT16) (StartBlock - 1);\r
+ }\r
+ //\r
+ // compute listen timeout\r
+ //\r
+ ListenTimeout = (UINT16) ((NumMissed > MtftpInfoPtr->ListenTimeout) ? 0 : (MtftpInfoPtr->ListenTimeout - NumMissed));\r
+\r
+ //\r
+ // reset\r
+ //\r
+ Offset = 0;\r
+ LastStartBlock = 0;\r
+ }\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+TftpInfo (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT64 *BufferSizePtr,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT SrvPort,\r
+ UINT8 *FilenamePtr,\r
+ UINTN *PacketSizePtr\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_UDP_PORT OurPort;\r
+ EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;\r
+ EFI_STATUS Status;\r
+ UINT64 BlockNum;\r
+ UINTN Offset;\r
+ UINTN ReplyLen;\r
+ UINT8 *Ptr;\r
+\r
+ union {\r
+ struct Tftpv4Oack OAck2Ptr;\r
+ struct Tftpv4Ack Ack2Ptr;\r
+ struct Tftpv4Data Datastr;\r
+ } u;\r
+\r
+ OurPort = 0;\r
+ ServerReplyPort = 0;\r
+ ReplyLen = sizeof (u.Datastr.Data);\r
+\r
+ //\r
+ // send a write request with the blocksize option -\r
+ // sets our IP and port - and receive reply - sets his port\r
+ // will retry operation up to 3 times if no response,\r
+ // and will retry without options on an error reply\r
+ //\r
+ if ((Status = TftpRwReqwResp (\r
+ TFTP_RRQ,\r
+ /* BIGBLKNUMOP | */BKSZOP | TSIZEOP,\r
+ Private,\r
+ &u,\r
+ PacketSizePtr,\r
+ &ReplyLen,\r
+ u.Datastr.Data,\r
+ ServerIpPtr,\r
+ &SrvPort,\r
+ &ServerReplyPort,\r
+ &OurPort,\r
+ FilenamePtr,\r
+ REQ_RESP_TIMEOUT\r
+ )) != EFI_SUCCESS) {\r
+ DEBUG ((DEBUG_WARN, "\nTftpInfo() Exit #1"));\r
+ return Status;\r
+ }\r
+ //\r
+ // check for good OACK\r
+ //\r
+ if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {\r
+ //\r
+ // now parse it for options\r
+ // bigblk#\r
+ //\r
+ Ptr = FindOption (\r
+ BigBlkNumOp,\r
+ sizeof (BigBlkNumOp),\r
+ u.OAck2Ptr.OpAck[0].Option,\r
+ ReplyLen + sizeof (u.Ack2Ptr.BlockNum)\r
+ );\r
+\r
+ if (Ptr != NULL) {\r
+ if (AtoU (Ptr) == 8) {\r
+ Private->BigBlkNumFlag = TRUE;\r
+ } else {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ }\r
+ //\r
+ // blksize\r
+ //\r
+ Ptr = FindOption (\r
+ BlockSizeOp,\r
+ sizeof (BlockSizeOp),\r
+ u.OAck2Ptr.OpAck[0].Option,\r
+ ReplyLen += sizeof (u.Ack2Ptr.BlockNum)\r
+ );\r
+\r
+ *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;\r
+\r
+ //\r
+ // tsize\r
+ //\r
+ Ptr = FindOption (\r
+ TsizeOp,\r
+ sizeof (TsizeOp),\r
+ u.OAck2Ptr.OpAck[0].Option,\r
+ ReplyLen\r
+ );\r
+\r
+ if (Ptr != NULL) {\r
+ *BufferSizePtr = AtoU64 (Ptr);\r
+\r
+ //\r
+ // teminate session with error\r
+ //\r
+ SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Offset = 0;\r
+ BlockNum = 0;\r
+ } else {\r
+ //\r
+ // if MTFTP get filesize, return unsupported\r
+ //\r
+ if (SrvPort != TftpRequestPort) {\r
+ SendError (Private, ServerIpPtr, &ServerReplyPort, &OurPort);\r
+ DEBUG ((DEBUG_WARN, "\nTftpInfo() Exit #3"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Offset = ReplyLen;\r
+ //\r
+ // last block received\r
+ //\r
+ BlockNum = 1;\r
+ }\r
+ //\r
+ // does not support the option - do a download with no buffer\r
+ //\r
+ *BufferSizePtr = 0;\r
+\r
+ Status = LockStepReceive (\r
+ Private,\r
+ (UINT16) ReplyLen,\r
+ BufferSizePtr,\r
+ Offset,\r
+ (INT8 *) &u,\r
+ ServerIpPtr,\r
+ &ServerReplyPort,\r
+ &Private->EfiBc.Mode->StationIp,\r
+ &OurPort,\r
+ BlockNum,\r
+ ACK_TIMEOUT,\r
+ TRUE\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ DEBUG ((DEBUG_WARN, "\nTftpInfo() LockStepReceive() == %Xh", Status));\r
+ }\r
+\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+TftpDownload (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT64 *BufferSizePtr,\r
+ UINT8 *BufferPtr,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ UINT8 *FilenamePtr,\r
+ UINTN *PacketSizePtr,\r
+ EFI_PXE_BASE_CODE_UDP_PORT SrvPort,\r
+ UINT16 Req,\r
+ IN BOOLEAN DontUseBuffer\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_UDP_PORT OurPort;\r
+ EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;\r
+ EFI_STATUS Status;\r
+ UINT64 Offset;\r
+ UINT64 BlockNum;\r
+ UINTN ReplyLen;\r
+ UINT8 *Ptr;\r
+\r
+ union {\r
+ struct Tftpv4Ack Ack2Ptr;\r
+ struct Tftpv4Oack OAck2Ptr;\r
+ struct Tftpv4Data Data;\r
+ struct Tftpv4Ack8 Ack8Ptr;\r
+ struct Tftpv4Data8 Data8;\r
+ } U;\r
+\r
+ OurPort = 0;\r
+ ServerReplyPort = 0;\r
+ ReplyLen = (UINTN) ((*BufferSizePtr > 0xFFFF) ? 0xFFFF : *BufferSizePtr);\r
+\r
+ //\r
+ // send a read request with the blocksize option - sets our IP and port\r
+ // - and receive reply - sets his port will retry operation up to 3\r
+ // times if no response, and will retry without options on an error\r
+ // reply\r
+ //\r
+ if ((Status = TftpRwReqwResp (\r
+ Req,\r
+ /* BIGBLKNUMOP | */BKSZOP,\r
+ Private,\r
+ &U,\r
+ PacketSizePtr,\r
+ &ReplyLen,\r
+ BufferPtr,\r
+ ServerIpPtr,\r
+ &SrvPort,\r
+ &ServerReplyPort,\r
+ &OurPort,\r
+ FilenamePtr,\r
+ REQ_RESP_TIMEOUT\r
+ )) != EFI_SUCCESS) {\r
+ DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #1 %xh (%r)", Status, Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // check for OACK\r
+ //\r
+ if (U.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {\r
+ //\r
+ // get the OACK\r
+ //\r
+ CopyMem (U.Data.Data, BufferPtr, ReplyLen);\r
+\r
+ Ptr = FindOption (\r
+ BigBlkNumOp,\r
+ sizeof (BigBlkNumOp),\r
+ U.OAck2Ptr.OpAck[0].Option,\r
+ ReplyLen + sizeof (U.Ack2Ptr.BlockNum)\r
+ );\r
+\r
+ if (Ptr != NULL) {\r
+ if (AtoU (Ptr) == 8) {\r
+ Private->BigBlkNumFlag = TRUE;\r
+ } else {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ }\r
+ //\r
+ // now parse it for blocksize option\r
+ //\r
+ Ptr = FindOption (\r
+ BlockSizeOp,\r
+ sizeof (BlockSizeOp),\r
+ U.OAck2Ptr.OpAck[0].Option,\r
+ ReplyLen += sizeof (U.Ack2Ptr.BlockNum)\r
+ );\r
+\r
+ ReplyLen = (Ptr != NULL) ? AtoU (Ptr) : 512;\r
+\r
+ Offset = 0;\r
+ //\r
+ // last block received\r
+ //\r
+ BlockNum = 0;\r
+ } else if (U.Ack2Ptr.OpCode != HTONS (TFTP_DATA) || U.Ack2Ptr.BlockNum != HTONS (1)) {\r
+ //\r
+ // or data\r
+ //\r
+ DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #2 %xh (%r)", Status, Status));\r
+\r
+ return EFI_PROTOCOL_ERROR;\r
+ } else {\r
+ //\r
+ // got good data packet\r
+ //\r
+ Offset = ReplyLen;\r
+ //\r
+ // last block received\r
+ //\r
+ BlockNum = 1;\r
+ }\r
+\r
+ if (PacketSizePtr != NULL) {\r
+ *PacketSizePtr = ReplyLen;\r
+ }\r
+ //\r
+ // routine to read rest of file after a successful open (TFTP or MTFTP)\r
+ // sends ACK and gets next data packet until short packet arrives, then sends\r
+ // ACK and (hopefully) times out\r
+ // if first packet has been read, BufferPtr and BufferSize must reflect fact\r
+ //\r
+ Status = LockStepReceive (\r
+ Private,\r
+ ReplyLen,\r
+ BufferSizePtr,\r
+ Offset,\r
+ BufferPtr,\r
+ ServerIpPtr,\r
+ &ServerReplyPort,\r
+ &Private->EfiBc.Mode->StationIp,\r
+ &OurPort,\r
+ BlockNum,\r
+ ACK_TIMEOUT,\r
+ DontUseBuffer\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ DEBUG ((DEBUG_WARN, "\nTftpDownload() Exit #3 %xh (%r)", Status, Status));\r
+\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ Status = TftpInfo (\r
+ Private,\r
+ BufferSizePtr,\r
+ ServerIpPtr,\r
+ SrvPort,\r
+ FilenamePtr,\r
+ PacketSizePtr\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+TftpUpload (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ UINT64 *BufferSizePtr,\r
+ VOID *BufferPtr,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ UINT8 *FilenamePtr,\r
+ UINTN *PacketSizePtr,\r
+ BOOLEAN Overwrite\r
+ )\r
+{\r
+ struct Tftpv4Ack Header;\r
+ EFI_PXE_BASE_CODE_UDP_PORT OurPort;\r
+ EFI_PXE_BASE_CODE_UDP_PORT ServerReplyPort;\r
+ EFI_STATUS Status;\r
+ UINT64 BlockNum;\r
+ UINT64 TransferSize;\r
+ UINTN ReplyLen;\r
+ UINTN TransferLen;\r
+ UINT16 Options;\r
+ UINT8 *Ptr;\r
+\r
+ union {\r
+ struct Tftpv4Oack OAck2Ptr;\r
+ struct Tftpv4Ack Ack2Ptr;\r
+ struct Tftpv4Data Datastr;\r
+ } u;\r
+\r
+ OurPort = 0;\r
+ ServerReplyPort = 0;\r
+ TransferSize = *BufferSizePtr;\r
+ ReplyLen = sizeof (u.Datastr.Data);\r
+ Options = (UINT16) ((Overwrite) ? OVERWRITEOP | BKSZOP : BKSZOP);\r
+\r
+ //\r
+ // send a write request with the blocksize option - sets our IP and port -\r
+ // and receive reply - sets his port\r
+ // will retry operation up to 3 times if no response, and will retry without\r
+ // options on an error reply\r
+ //\r
+ if ((Status = TftpRwReqwResp (\r
+ TFTP_WRQ,\r
+ Options,\r
+ Private,\r
+ &u,\r
+ PacketSizePtr,\r
+ &ReplyLen,\r
+ u.Datastr.Data,\r
+ ServerIpPtr,\r
+ &TftpRequestPort,\r
+ &ServerReplyPort,\r
+ &OurPort,\r
+ FilenamePtr,\r
+ REQ_RESP_TIMEOUT\r
+ )) != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+ //\r
+ // check for OACK\r
+ //\r
+ if (u.OAck2Ptr.OpCode == HTONS (TFTP_OACK)) {\r
+ //\r
+ // parse it for blocksize option\r
+ //\r
+ Ptr = FindOption (\r
+ BlockSizeOp,\r
+ sizeof (BlockSizeOp),\r
+ u.OAck2Ptr.OpAck[0].Option,\r
+ ReplyLen += sizeof (u.Ack2Ptr.BlockNum)\r
+ );\r
+ *PacketSizePtr = (Ptr) ? AtoU (Ptr) : 512;\r
+ }\r
+ //\r
+ // or ACK\r
+ //\r
+ else if (u.Ack2Ptr.OpCode == HTONS (TFTP_ACK)) {\r
+ //\r
+ // option was not supported\r
+ //\r
+ *PacketSizePtr = 512;\r
+ } else {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ //\r
+ // loop\r
+ //\r
+ Header.OpCode = HTONS (TFTP_DATA);\r
+ BlockNum = 1;\r
+ Header.BlockNum = HTONS (1);\r
+\r
+ do {\r
+ UINTN HeaderSize;\r
+ INTN Retries;\r
+\r
+ Retries = NUM_ACK_RETRIES;\r
+ HeaderSize = sizeof (Header);\r
+ TransferLen = (UINTN) (MIN (*PacketSizePtr, TransferSize));\r
+\r
+ //\r
+ // write a data packet and get an ack\r
+ //\r
+ do {\r
+ //\r
+ // write\r
+ //\r
+ if ((Status = UdpWrite (\r
+ Private,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,\r
+ ServerIpPtr,\r
+ &ServerReplyPort,\r
+ 0,\r
+ 0,\r
+ &OurPort,\r
+ &HeaderSize,\r
+ &Header,\r
+ &TransferLen,\r
+ BufferPtr\r
+ )) != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+ //\r
+ // read reply\r
+ //\r
+ ReplyLen = sizeof (u.Datastr.Data);\r
+\r
+ if ((Status = TftpUdpRead (\r
+ Private,\r
+ 0,\r
+ &u,\r
+ &ReplyLen,\r
+ u.Datastr.Data,\r
+ ServerIpPtr,\r
+ &ServerReplyPort,\r
+ 0,\r
+ &OurPort,\r
+ ACK_TIMEOUT\r
+ )) == EFI_SUCCESS) {\r
+ //\r
+ // check for ACK for this data packet\r
+ //\r
+ if (u.Ack2Ptr.OpCode != HTONS (TFTP_ACK)) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ if (u.Ack2Ptr.BlockNum != Header.BlockNum) {\r
+ //\r
+ // not for this packet - continue\r
+ //\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+ }\r
+ } while (Status == EFI_TIMEOUT && --Retries);\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ BufferPtr = (VOID *) ((UINT8 *) (BufferPtr) + TransferLen);\r
+ TransferSize -= TransferLen;\r
+ ++BlockNum;\r
+ Header.BlockNum = HTONS ((UINT16) BlockNum);\r
+ } while (TransferLen == *PacketSizePtr);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return * EFI_INVALID_PARAMETER\r
+ @return * EFI_OUT_OF_RESOURCES\r
+ @return * EFI_BAD_BUFFER_SIZE\r
+ @return * Status is also returned from IpFilter(), TftpInfo(), MtftpDownload(),\r
+ @return * TftpDownload() and TftpUpload().\r
+\r
+**/\r
+EFI_STATUS\r
+PxeBcMtftp (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,\r
+ UINT64 *BufferSizePtr,\r
+ VOID *BufferPtr,\r
+ EFI_IP_ADDRESS *ServerIpPtr,\r
+ UINT8 *FilenamePtr,\r
+ UINTN *PacketSizePtr,\r
+ IN EFI_PXE_BASE_CODE_MTFTP_INFO *MtftpInfoPtr, OPTIONAL\r
+ IN BOOLEAN Overwrite,\r
+ IN BOOLEAN DontUseBuffer\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_IP_FILTER Filter;\r
+ EFI_STATUS StatCode;\r
+ EFI_STATUS Status;\r
+ UINT64 BufferSizeLocal;\r
+ UINTN PacketSize;\r
+ UINT8 *BufferPtrLocal;\r
+\r
+ Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;\r
+ Filter.IpCnt = 0;\r
+ Filter.reserved = 0;\r
+\r
+ /* No error has occurred, yet. */\r
+ Private->EfiBc.Mode->TftpErrorReceived = FALSE;\r
+\r
+ /* We must at least have an MTFTP server IP address and\r
+ * a pointer to the buffer size.\r
+ */\r
+ if (!ServerIpPtr || !BufferSizePtr) {\r
+ DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #1"));\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_MTFTP;\r
+\r
+ //\r
+ // make sure filter set to unicast at start\r
+ //\r
+ if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {\r
+ DEBUG (\r
+ (DEBUG_NET,\r
+ "\nPxeBcMtftp() Exit IpFilter() == %Xh",\r
+ StatCode)\r
+ );\r
+\r
+ return StatCode;\r
+ }\r
+ //\r
+ // set unset parms to default values\r
+ //\r
+ if (!PacketSizePtr) {\r
+ *(PacketSizePtr = &PacketSize) = MAX_TFTP_PKT_SIZE;\r
+ }\r
+\r
+ if (*PacketSizePtr > *BufferSizePtr) {\r
+ *PacketSizePtr = (UINTN) *BufferSizePtr;\r
+ }\r
+\r
+ if (*PacketSizePtr < MIN_TFTP_PKT_SIZE) {\r
+ *PacketSizePtr = MIN_TFTP_PKT_SIZE;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (*PacketSizePtr > BUFFER_ALLOCATE_SIZE) {\r
+ *PacketSizePtr = BUFFER_ALLOCATE_SIZE;\r
+ }\r
+\r
+ if (*PacketSizePtr > MAX_TFTP_PKT_SIZE) {\r
+ *PacketSizePtr = MAX_TFTP_PKT_SIZE;\r
+ }\r
+\r
+ if (Operation == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {\r
+ StatCode = TftpInfo (\r
+ Private,\r
+ BufferSizePtr,\r
+ ServerIpPtr,\r
+ TftpRequestPort,\r
+ FilenamePtr,\r
+ PacketSizePtr\r
+ );\r
+\r
+ if (StatCode != EFI_SUCCESS) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxeBcMtftp() Exit TftpInfo() == %Xh",\r
+ StatCode)\r
+ );\r
+ }\r
+\r
+ return StatCode;\r
+ }\r
+\r
+ if (Operation == EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE) {\r
+ if (!MtftpInfoPtr || !MtftpInfoPtr->SPort) {\r
+ DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #2"));\r
+ return EFI_INVALID_PARAMETER;\r
+ } else {\r
+ StatCode = TftpInfo (\r
+ Private,\r
+ BufferSizePtr,\r
+ ServerIpPtr,\r
+ MtftpInfoPtr->SPort,\r
+ FilenamePtr,\r
+ PacketSizePtr\r
+ );\r
+\r
+ gBS->Stall (10000);\r
+\r
+ if (StatCode != EFI_SUCCESS) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxeBcMtftp() Exit TftpInfo() == %Xh",\r
+ StatCode)\r
+ );\r
+ }\r
+\r
+ return StatCode;\r
+ }\r
+ }\r
+\r
+ if (!BufferPtr && !DontUseBuffer) {\r
+ //\r
+ // if dontusebuffer is false and no buffer???\r
+ //\r
+ DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #3"));\r
+ //\r
+ // DontUseBuffer can be true only for read_file operation\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DontUseBuffer) {\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ BUFFER_ALLOCATE_SIZE,\r
+ &BufferPtrLocal\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || BufferPtrLocal == NULL) {\r
+ DEBUG ((DEBUG_NET, "\nPxeBcMtftp() Exit #4"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ BufferSizeLocal = BUFFER_ALLOCATE_SIZE;\r
+ } else {\r
+ if (!*BufferSizePtr && Operation != EFI_PXE_BASE_CODE_TFTP_WRITE_FILE) {\r
+ DEBUG ((DEBUG_WARN, "\nPxeBcMtftp() Exit #5"));\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ BufferPtrLocal = BufferPtr;\r
+ BufferSizeLocal = *BufferSizePtr;\r
+ }\r
+\r
+ switch (Operation) {\r
+ case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:\r
+ if (FilenamePtr == NULL ||\r
+ MtftpInfoPtr == NULL ||\r
+ MtftpInfoPtr->MCastIp.Addr[0] == 0 ||\r
+ MtftpInfoPtr->SPort == 0 ||\r
+ MtftpInfoPtr->CPort == 0 ||\r
+ MtftpInfoPtr->ListenTimeout == 0 ||\r
+ MtftpInfoPtr->TransmitTimeout == 0\r
+ ) {\r
+ StatCode = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+ //\r
+ // try MTFTP - if fails, drop into TFTP read\r
+ //\r
+ if ((StatCode = MtftpDownload (\r
+ Private,\r
+ &BufferSizeLocal,\r
+ BufferPtrLocal,\r
+ ServerIpPtr,\r
+ FilenamePtr,\r
+ MtftpInfoPtr,\r
+ DontUseBuffer\r
+ )) == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {\r
+ if (BufferSizePtr /* %% !DontUseBuffer */ ) {\r
+ *BufferSizePtr = BufferSizeLocal;\r
+ }\r
+\r
+ break;\r
+ }\r
+ //\r
+ // go back to unicast\r
+ //\r
+ if ((StatCode = IpFilter (Private, &Filter)) != EFI_SUCCESS) {\r
+ break;\r
+ }\r
+\r
+ /* fall thru */\r
+ case EFI_PXE_BASE_CODE_TFTP_READ_FILE:\r
+ if (FilenamePtr == NULL) {\r
+ StatCode = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ StatCode = TftpDownload (\r
+ Private,\r
+ &BufferSizeLocal,\r
+ BufferPtrLocal,\r
+ ServerIpPtr,\r
+ FilenamePtr,\r
+ PacketSizePtr,\r
+ TftpRequestPort,\r
+ TFTP_RRQ,\r
+ DontUseBuffer\r
+ );\r
+\r
+ if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {\r
+ if (BufferSizePtr /* !DontUseBuffer */ ) {\r
+ *BufferSizePtr = BufferSizeLocal;\r
+ }\r
+ }\r
+\r
+ break;\r
+\r
+ case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:\r
+ if (FilenamePtr == NULL || DontUseBuffer) {\r
+ //\r
+ // not a valid option\r
+ //\r
+ StatCode = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ StatCode = TftpUpload (\r
+ Private,\r
+ BufferSizePtr,\r
+ BufferPtr,\r
+ ServerIpPtr,\r
+ FilenamePtr,\r
+ PacketSizePtr,\r
+ Overwrite\r
+ );\r
+\r
+ if (StatCode != EFI_SUCCESS) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxeBcMtftp() Exit #6 %xh (%r)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+ }\r
+\r
+ return StatCode;\r
+\r
+ case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:\r
+ if (FilenamePtr == NULL || DontUseBuffer) {\r
+ //\r
+ // not a valid option\r
+ //\r
+ StatCode = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ StatCode = TftpDownload (\r
+ Private,\r
+ BufferSizePtr,\r
+ BufferPtr,\r
+ ServerIpPtr,\r
+ FilenamePtr,\r
+ PacketSizePtr,\r
+ TftpRequestPort,\r
+ TFTP_DIR,\r
+ DontUseBuffer\r
+ );\r
+\r
+ if (StatCode != EFI_SUCCESS) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxeBcMtftp() Exit #7 %xh (%r)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+ }\r
+\r
+ return StatCode;\r
+\r
+ case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:\r
+ if (DontUseBuffer) {\r
+ StatCode = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ if (MtftpInfoPtr == NULL || !MtftpInfoPtr->SPort) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxeBcMtftp() Exit #9 %xh (%r)",\r
+ EFI_INVALID_PARAMETER,\r
+ EFI_INVALID_PARAMETER)\r
+ );\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ StatCode = TftpDownload (\r
+ Private,\r
+ BufferSizePtr,\r
+ BufferPtr,\r
+ ServerIpPtr,\r
+ (UINT8 *) "/",\r
+ PacketSizePtr,\r
+ MtftpInfoPtr->SPort,\r
+ TFTP_DIR,\r
+ DontUseBuffer\r
+ );\r
+\r
+ break;\r
+\r
+ default:\r
+ StatCode = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DontUseBuffer) {\r
+ gBS->FreePool (BufferPtrLocal);\r
+ }\r
+\r
+ if (StatCode != EFI_SUCCESS) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nPxeBcMtftp() Exit #8 %xh (%r)",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+ }\r
+\r
+ gBS->Stall (10000);\r
+\r
+ return StatCode;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return * EFI_INVALID_PARAMETER\r
+ @return * Status is also returned from PxeBcMtftp();\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcMtftp (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,\r
+ IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,\r
+ IN OUT VOID *BufferPtr,\r
+ IN BOOLEAN Overwrite,\r
+ IN OUT UINT64 *BufferSizePtr,\r
+ IN UINTN *BlockSizePtr OPTIONAL,\r
+ IN EFI_IP_ADDRESS * ServerIpPtr,\r
+ IN UINT8 *FilenamePtr,\r
+ IN EFI_PXE_BASE_CODE_MTFTP_INFO * MtftpInfoPtr OPTIONAL,\r
+ IN BOOLEAN DontUseBuffer\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_IP_FILTER Filter;\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+\r
+ //\r
+ // Lock the instance data and make sure started\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!IS_INADDR_UNICAST (ServerIpPtr)) {\r
+ //\r
+ // The station IP is not a unicast address.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ if (This->Mode == NULL || !This->Mode->Started) {\r
+ DEBUG ((DEBUG_ERROR, "BC was not started."));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_NOT_STARTED;\r
+ }\r
+ //\r
+ // Issue BC command\r
+ //\r
+ Filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;\r
+ Filter.IpCnt = 0;\r
+ Filter.reserved = 0;\r
+\r
+ DEBUG ((DEBUG_WARN, "\nBcMtftp() Op=%d Buf=%Xh", Operation, BufferPtr));\r
+\r
+ StatCode = PxeBcMtftp (\r
+ Private,\r
+ Operation,\r
+ BufferSizePtr,\r
+ BufferPtr,\r
+ ServerIpPtr,\r
+ FilenamePtr,\r
+ BlockSizePtr,\r
+ MtftpInfoPtr,\r
+ Overwrite,\r
+ DontUseBuffer\r
+ );\r
+\r
+ //\r
+ // restore to unicast\r
+ //\r
+ IpFilter (Private, &Filter);\r
+\r
+ //\r
+ // Unlock the instance data\r
+ //\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+}\r
+\r
+/* eof - PxeBcMtftp.c */\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+ pxe_bc_udp.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Bc.h"\r
+\r
+//\r
+// //////////////////////////////////////////////////////////////////////\r
+//\r
+// Udp Write Routine - called by base code - e.g. TFTP - already locked\r
+//\r
+\r
+/**\r
+\r
+ @return EFI_SUCCESS :=\r
+ @return EFI_INVALID_PARAMETER :=\r
+ @return other :=\r
+\r
+**/\r
+EFI_STATUS\r
+UdpWrite (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN UINT16 OpFlags,\r
+ IN EFI_IP_ADDRESS *DestIpPtr,\r
+ IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr,\r
+ IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL\r
+ IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL\r
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL\r
+ IN UINTN *HeaderSizePtr, OPTIONAL\r
+ IN VOID *HeaderPtr, OPTIONAL\r
+ IN UINTN *BufferSizeptr,\r
+ IN VOID *BufferPtr\r
+ )\r
+{\r
+ UINTN TotalLength;\r
+ UINTN HeaderSize;\r
+ EFI_PXE_BASE_CODE_UDP_PORT DefaultSrcPort;\r
+\r
+ //\r
+ //\r
+ //\r
+ HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0;\r
+ DefaultSrcPort = 0;\r
+\r
+ //\r
+ // check parameters\r
+ //\r
+ if (BufferSizeptr == NULL ||\r
+ BufferPtr == NULL ||\r
+ DestIpPtr == NULL ||\r
+ DestPortPtr == NULL ||\r
+ (HeaderSizePtr != NULL && *HeaderSizePtr == 0) ||\r
+ (HeaderSize != 0 && HeaderPtr == NULL) ||\r
+ (GatewayIpPtr != NULL && !IS_INADDR_UNICAST(GatewayIpPtr)) ||\r
+ (OpFlags &~(EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT))\r
+ ) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nUdpWrite() Exit #1 %xh (%r)",\r
+ EFI_INVALID_PARAMETER,\r
+ EFI_INVALID_PARAMETER)\r
+ );\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ TotalLength = *BufferSizeptr + HeaderSize + sizeof (UDPV4_HEADER);\r
+\r
+ if (TotalLength > 0x0000ffff) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nUdpWrite() Exit #2 %xh (%r)",\r
+ EFI_BAD_BUFFER_SIZE,\r
+ EFI_BAD_BUFFER_SIZE)\r
+ );\r
+\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (SrcIpPtr == NULL) {\r
+ SrcIpPtr = &Private->EfiBc.Mode->StationIp;\r
+ }\r
+\r
+ if (SrcPortPtr == NULL) {\r
+ SrcPortPtr = &DefaultSrcPort;\r
+ OpFlags |= EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT;\r
+ }\r
+\r
+ if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) {\r
+ *SrcPortPtr = Private->RandomPort;\r
+\r
+ if (++Private->RandomPort == 0) {\r
+ Private->RandomPort = PXE_RND_PORT_LOW;\r
+ }\r
+ }\r
+\r
+#define IpTxBuffer ((IPV4_BUFFER *) Private->TransmitBufferPtr)\r
+ //\r
+ // build pseudo header and udp header in transmit buffer\r
+ //\r
+#define Udpv4Base ((UDPV4_HEADERS *) (IpTxBuffer->u.Data - sizeof (UDPV4_PSEUDO_HEADER)))\r
+\r
+ Udpv4Base->Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];\r
+ Udpv4Base->Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];\r
+ Udpv4Base->Udpv4PseudoHeader.Zero = 0;\r
+ Udpv4Base->Udpv4PseudoHeader.Protocol = PROT_UDP;\r
+ Udpv4Base->Udpv4PseudoHeader.TotalLength = HTONS (TotalLength);\r
+ Udpv4Base->Udpv4Header.SrcPort = HTONS (*SrcPortPtr);\r
+ Udpv4Base->Udpv4Header.DestPort = HTONS (*DestPortPtr);\r
+ Udpv4Base->Udpv4Header.TotalLength = Udpv4Base->Udpv4PseudoHeader.TotalLength;\r
+ Udpv4Base->Udpv4Header.Checksum = 0;\r
+\r
+ if (HeaderSize != 0) {\r
+ CopyMem (IpTxBuffer->u.Udp.Data, HeaderPtr, HeaderSize);\r
+ }\r
+\r
+ HeaderSize += sizeof (UDPV4_HEADER);\r
+\r
+ Udpv4Base->Udpv4Header.Checksum = IpChecksum2 (\r
+ (UINT16 *) Udpv4Base,\r
+ HeaderSize + sizeof (UDPV4_PSEUDO_HEADER),\r
+ (UINT16 *) BufferPtr,\r
+ (UINT16) *BufferSizeptr\r
+ );\r
+\r
+ if (Udpv4Base->Udpv4Header.Checksum == 0) {\r
+ Udpv4Base->Udpv4Header.Checksum = 0xffff;\r
+ //\r
+ // transmit zero checksum as ones complement\r
+ //\r
+ }\r
+\r
+ return Ip4Send (\r
+ Private,\r
+ OpFlags,\r
+ PROT_UDP,\r
+ Udpv4Base->Udpv4PseudoHeader.SrcAddr.L,\r
+ Udpv4Base->Udpv4PseudoHeader.DestAddr.L,\r
+ (GatewayIpPtr) ? GatewayIpPtr->Addr[0] : 0,\r
+ HeaderSize,\r
+ BufferPtr,\r
+ *BufferSizeptr\r
+ );\r
+}\r
+//\r
+// //////////////////////////////////////////////////////////\r
+//\r
+// BC Udp Write Routine\r
+//\r
+\r
+/**\r
+\r
+ @return EFI_SUCCESS :=\r
+ @return other :=\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcUdpWrite (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
+ IN UINT16 OpFlags,\r
+ IN EFI_IP_ADDRESS *DestIpPtr,\r
+ IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr,\r
+ IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL\r
+ IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL\r
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL\r
+ IN UINTN *HeaderSizePtr, OPTIONAL\r
+ IN VOID *HeaderPtr, OPTIONAL\r
+ IN UINTN *BufferSizeptr,\r
+ IN VOID *BufferPtr\r
+ )\r
+{\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+\r
+ //\r
+ // Lock the instance data and make sure started\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ if (This->Mode == NULL || !This->Mode->Started) {\r
+ DEBUG ((DEBUG_ERROR, "BC was not started."));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_WRITE;\r
+\r
+ //\r
+ // Issue BC command\r
+ //\r
+ StatCode = UdpWrite (\r
+ Private,\r
+ OpFlags,\r
+ DestIpPtr,\r
+ DestPortPtr,\r
+ GatewayIpPtr,\r
+ SrcIpPtr,\r
+ SrcPortPtr,\r
+ HeaderSizePtr,\r
+ HeaderPtr,\r
+ BufferSizeptr,\r
+ BufferPtr\r
+ );\r
+\r
+ //\r
+ // Unlock the instance data\r
+ //\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+}\r
+//\r
+// /////////////////////////////////////////////////////////////////////\r
+//\r
+// Udp Read Routine - called by base code - e.g. TFTP - already locked\r
+//\r
+\r
+/**\r
+\r
+ @return EFI_SUCCESS :=\r
+ @return EFI_INVALID_PARAMETER :=\r
+ @return other :=\r
+\r
+**/\r
+EFI_STATUS\r
+UdpRead (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN UINT16 OpFlags,\r
+ IN OUT EFI_IP_ADDRESS *DestIpPtr, OPTIONAL\r
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr, OPTIONAL\r
+ IN OUT EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL\r
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL\r
+ IN UINTN *HeaderSizePtr, OPTIONAL\r
+ IN VOID *HeaderPtr, OPTIONAL\r
+ IN OUT UINTN *BufferSizeptr,\r
+ IN VOID *BufferPtr,\r
+ EFI_EVENT TimeoutEvent\r
+ )\r
+{\r
+ EFI_STATUS StatCode;\r
+ EFI_IP_ADDRESS TmpSrcIp;\r
+ EFI_IP_ADDRESS TmpDestIp;\r
+ UINTN BufferSize;\r
+ UINTN HeaderSize;\r
+\r
+ //\r
+ // combination structure of pseudo header/udp header\r
+ //\r
+#pragma pack (1)\r
+ struct {\r
+ UDPV4_PSEUDO_HEADER Udpv4PseudoHeader;\r
+ UDPV4_HEADER Udpv4Header;\r
+ UINT8 ProtHdr[64];\r
+ } Hdrs;\r
+#pragma pack ()\r
+\r
+ HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0;\r
+ //\r
+ // read [with filtering]\r
+ // check parameters\r
+ //\r
+ if (BufferSizeptr == NULL ||\r
+ BufferPtr == NULL ||\r
+ (HeaderSize != 0 && HeaderPtr == NULL) ||\r
+ (OpFlags &~UDP_FILTER_MASK)\r
+ //\r
+ // if filtering on a particular IP/Port, need it\r
+ //\r
+ ||\r
+ (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr == NULL) ||\r
+ (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && SrcPortPtr == NULL) ||\r
+ (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && DestPortPtr == NULL)\r
+ ) {\r
+ DEBUG ((DEBUG_INFO, "\nUdpRead() Exit #1 Invalid Parameter"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // in case we loop\r
+ //\r
+ BufferSize = *BufferSizeptr;\r
+ //\r
+ // we need source and dest IPs for pseudo header\r
+ //\r
+ if (SrcIpPtr == NULL) {\r
+ SrcIpPtr = &TmpSrcIp;\r
+ }\r
+\r
+ if (DestIpPtr == NULL) {\r
+ DestIpPtr = &TmpDestIp;\r
+ TmpDestIp = Private->EfiBc.Mode->StationIp;\r
+ }\r
+\r
+#if SUPPORT_IPV6\r
+ if (Private->EfiBc.Mode->UsingIpv6) {\r
+ //\r
+ // %%TBD\r
+ //\r
+ }\r
+#endif\r
+\r
+ for (;;) {\r
+ *BufferSizeptr = BufferSize;\r
+\r
+ StatCode = IpReceive (\r
+ Private,\r
+ OpFlags,\r
+ SrcIpPtr,\r
+ DestIpPtr,\r
+ PROT_UDP,\r
+ &Hdrs.Udpv4Header,\r
+ HeaderSize + sizeof Hdrs.Udpv4Header,\r
+ BufferPtr,\r
+ BufferSizeptr,\r
+ TimeoutEvent\r
+ );\r
+\r
+ if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {\r
+ UINT16 SPort;\r
+ UINT16 DPort;\r
+\r
+ SPort = NTOHS (Hdrs.Udpv4Header.SrcPort);\r
+ DPort = NTOHS (Hdrs.Udpv4Header.DestPort);\r
+\r
+ //\r
+ // do filtering\r
+ //\r
+ if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && *SrcPortPtr != SPort) {\r
+ continue;\r
+ }\r
+\r
+ if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && *DestPortPtr != DPort) {\r
+ continue;\r
+ }\r
+ //\r
+ // check checksum\r
+ //\r
+ if (StatCode == EFI_SUCCESS && Hdrs.Udpv4Header.Checksum) {\r
+ Hdrs.Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];\r
+ Hdrs.Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];\r
+ Hdrs.Udpv4PseudoHeader.Zero = 0;\r
+ Hdrs.Udpv4PseudoHeader.Protocol = PROT_UDP;\r
+ Hdrs.Udpv4PseudoHeader.TotalLength = Hdrs.Udpv4Header.TotalLength;\r
+\r
+ if (Hdrs.Udpv4Header.Checksum == 0xffff) {\r
+ Hdrs.Udpv4Header.Checksum = 0;\r
+ }\r
+\r
+ if (IpChecksum2 (\r
+ (UINT16 *) &Hdrs.Udpv4PseudoHeader,\r
+ HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader) + sizeof (Hdrs.Udpv4Header),\r
+ (UINT16 *) BufferPtr,\r
+ *BufferSizeptr\r
+ )) {\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nUdpRead() Hdrs.Udpv4PseudoHeader == %Xh",\r
+ Hdrs.Udpv4PseudoHeader)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nUdpRead() Header size == %d",\r
+ HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader))\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nUdpRead() BufferPtr == %Xh",\r
+ BufferPtr)\r
+ );\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nUdpRead() Buffer size == %d",\r
+ *BufferSizeptr)\r
+ );\r
+ DEBUG ((DEBUG_INFO, "\nUdpRead() Exit #2 Device Error"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ //\r
+ // all passed\r
+ //\r
+ if (SrcPortPtr != NULL) {\r
+ *SrcPortPtr = SPort;\r
+ }\r
+\r
+ if (DestPortPtr != NULL) {\r
+ *DestPortPtr = DPort;\r
+ }\r
+\r
+ if (HeaderSize != 0) {\r
+ CopyMem (HeaderPtr, Hdrs.ProtHdr, HeaderSize);\r
+ }\r
+ }\r
+\r
+ if ((StatCode != EFI_SUCCESS) && (StatCode != EFI_TIMEOUT)) {\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ "\nUdpRead() Exit #3 %Xh %r",\r
+ StatCode,\r
+ StatCode)\r
+ );\r
+ }\r
+\r
+ return StatCode;\r
+ }\r
+}\r
+//\r
+// //////////////////////////////////////////////////////////\r
+//\r
+// BC Udp Read Routine\r
+//\r
+\r
+/**\r
+\r
+ @return EFI_SUCCESS :=\r
+ @return other :=\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BcUdpRead (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
+ IN UINT16 OpFlags,\r
+ IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL\r
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL\r
+ IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL\r
+ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL\r
+ IN UINTN *HeaderSize, OPTIONAL\r
+ IN VOID *HeaderPtr, OPTIONAL\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *BufferPtr\r
+ )\r
+{\r
+ EFI_STATUS StatCode;\r
+ PXE_BASECODE_DEVICE *Private;\r
+\r
+ //\r
+ // Lock the instance data and make sure started\r
+ //\r
+ StatCode = EFI_SUCCESS;\r
+\r
+ if (This == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiAcquireLock (&Private->Lock);\r
+\r
+ if (This->Mode == NULL || !This->Mode->Started) {\r
+ DEBUG ((DEBUG_ERROR, "BC was not started."));\r
+ EfiReleaseLock (&Private->Lock);\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_READ;\r
+\r
+ //\r
+ // Issue BC command\r
+ //\r
+ StatCode = UdpRead (\r
+ Private,\r
+ OpFlags,\r
+ DestIp,\r
+ DestPort,\r
+ SrcIp,\r
+ SrcPort,\r
+ HeaderSize,\r
+ HeaderPtr,\r
+ BufferSize,\r
+ BufferPtr,\r
+ 0\r
+ );\r
+\r
+ //\r
+ // Unlock the instance data and return\r
+ //\r
+ EfiReleaseLock (&Private->Lock);\r
+ return StatCode;\r
+}\r
+\r
+/* eof - pxe_bc_udp.c */\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+ pxe_loadfile.c\r
+\r
+Abstract:\r
+ An implementation of the load file protocol for network devices.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "Bc.h"\r
+\r
+#define DO_MENU (EFI_SUCCESS)\r
+#define NO_MENU (DO_MENU + 1)\r
+#define LOCAL_BOOT (EFI_ABORTED)\r
+#define AUTO_SELECT (NO_MENU)\r
+\r
+#define NUMBER_ROWS 25 // we set to mode 0\r
+#define MAX_MENULIST 23\r
+\r
+#define Ctl(x) (0x1F & (x))\r
+\r
+typedef union {\r
+ DHCPV4_OP_STRUCT *OpPtr;\r
+ PXE_BOOT_MENU_ENTRY *CurrentMenuItemPtr;\r
+ PXE_OP_DISCOVERY_CONTROL *DiscCtlOpStr;\r
+ PXE_OP_BOOT_MENU *MenuPtr;\r
+ UINT8 *BytePtr;\r
+} UNION_PTR;\r
+\r
+\r
+\r
+/**\r
+ PxeBc callback routine for status updates and aborts.\r
+\r
+ @param This Pointer to PxeBcCallback\r
+ interface\r
+ @param Function PxeBc function ID#\r
+ @param Received Receive/transmit flag\r
+ @param PacketLength Length of received packet (0\r
+ == idle callback)\r
+ @param PacketPtr Pointer to received packet\r
+ (NULL == idle callback)\r
+\r
+ @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE\r
+ EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT\r
+ -\r
+\r
+**/\r
+STATIC\r
+EFI_PXE_BASE_CODE_CALLBACK_STATUS\r
+EFIAPI\r
+bc_callback (\r
+ IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL * This,\r
+ IN EFI_PXE_BASE_CODE_FUNCTION Function,\r
+ IN BOOLEAN Received,\r
+ IN UINT32 PacketLength,\r
+ IN EFI_PXE_BASE_CODE_PACKET * PacketPtr OPTIONAL\r
+ )\r
+{\r
+ STATIC UINTN Propeller;\r
+\r
+ EFI_INPUT_KEY Key;\r
+ UINTN Row;\r
+ UINTN Col;\r
+\r
+ Propeller = 0;\r
+ //\r
+ // Resolve Warning 4 unreferenced parameter problem\r
+ //\r
+ This = This;\r
+\r
+ //\r
+ // Check for user abort.\r
+ //\r
+ if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_SUCCESS) {\r
+ if (!Key.ScanCode) {\r
+ if (Key.UnicodeChar == Ctl ('c')) {\r
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;\r
+ }\r
+ } else if (Key.ScanCode == SCAN_ESC) {\r
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;\r
+ }\r
+ }\r
+ //\r
+ // Do nothing if this is a receive.\r
+ //\r
+ if (Received) {\r
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
+ }\r
+ //\r
+ // The display code is only for these functions.\r
+ //\r
+ switch (Function) {\r
+ case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:\r
+ //\r
+ // If this is a transmit and not a M/TFTP open request,\r
+ // return now. Do not print a dot for each M/TFTP packet\r
+ // that is sent, only for the open packets.\r
+ //\r
+ if (PacketLength != 0 && PacketPtr != NULL) {\r
+ if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {\r
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
+ }\r
+ }\r
+\r
+ break;\r
+\r
+ case EFI_PXE_BASE_CODE_FUNCTION_DHCP:\r
+ case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:\r
+ break;\r
+\r
+ default:\r
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
+ }\r
+ //\r
+ // Display routines\r
+ //\r
+ if (PacketLength != 0 && PacketPtr != NULL) {\r
+ //\r
+ // Display a '.' when a packet is transmitted.\r
+ //\r
+ AsciiPrint (".");\r
+ } else if (PacketLength == 0 && PacketPtr == NULL) {\r
+ //\r
+ // Display a propeller when waiting for packets if at\r
+ // least 200 ms have passed.\r
+ //\r
+ Row = gST->ConOut->Mode->CursorRow;\r
+ Col = gST->ConOut->Mode->CursorColumn;\r
+\r
+ AsciiPrint ("%c", "/-\\|"[Propeller]);\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, Col, Row);\r
+\r
+ Propeller = (Propeller + 1) & 3;\r
+ }\r
+\r
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
+}\r
+\r
+STATIC EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL _bc_callback = {\r
+ EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,\r
+ &bc_callback\r
+};\r
+\r
+\r
+/**\r
+ Display an IPv4 address in dot notation.\r
+\r
+ @param Ptr Pointer to IPv4 address.\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+PrintIpv4 (\r
+ UINT8 *Ptr\r
+ )\r
+{\r
+ if (Ptr != NULL) {\r
+ AsciiPrint ("%d.%d.%d.%d", Ptr[0], Ptr[1], Ptr[2], Ptr[3]);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Display client and server IP information.\r
+\r
+ @param Private Pointer to PxeBc interface\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+ShowMyInfo (\r
+ IN PXE_BASECODE_DEVICE *Private\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Do nothing if a NULL pointer is passed in.\r
+ //\r
+ if (Private == NULL) {\r
+ return ;\r
+ }\r
+ //\r
+ // Get pointer to PXE BaseCode mode structure\r
+ //\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+\r
+ //\r
+ // Display client IP address\r
+ //\r
+ AsciiPrint ("\rCLIENT IP: ");\r
+ PrintIpv4 (PxeBcMode->StationIp.v4.Addr);\r
+\r
+ //\r
+ // Display subnet mask\r
+ //\r
+ AsciiPrint (" MASK: ");\r
+ PrintIpv4 (PxeBcMode->SubnetMask.v4.Addr);\r
+\r
+ //\r
+ // Display DHCP and proxyDHCP IP addresses\r
+ //\r
+ if (PxeBcMode->ProxyOfferReceived) {\r
+ AsciiPrint ("\nDHCP IP: ");\r
+ PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);\r
+\r
+ AsciiPrint (" PROXY IP: ");\r
+ PrintIpv4 (((DHCPV4_OP_SERVER_IP *) PXE_OFFER_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);\r
+ } else {\r
+ AsciiPrint (" DHCP IP: ");\r
+ PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);\r
+ }\r
+ //\r
+ // Display gateway IP addresses\r
+ //\r
+ for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
+ if ((Index % 3) == 0) {\r
+ AsciiPrint ("\r\nGATEWAY IP:");\r
+ }\r
+\r
+ AsciiPrint (" ");\r
+ PrintIpv4 (PxeBcMode->RouteTable[Index].GwAddr.v4.Addr);\r
+ AsciiPrint (" ");\r
+ }\r
+\r
+ AsciiPrint ("\n");\r
+}\r
+\r
+\r
+/**\r
+ Display prompt and wait for input.\r
+\r
+ @param Private Pointer to PxeBc interface\r
+ @param BootPromptPtr Pointer to PXE boot prompt\r
+ option\r
+\r
+ @retval AUTO_SELECT DO_MENU -\r
+ @retval NO_MENU\r
+ @retval LOCAL_BOOT\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DoPrompt (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ PXE_OP_BOOT_PROMPT *BootPromptPtr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT TimeoutEvent;\r
+ EFI_EVENT SecondsEvent;\r
+ INT32 SecColumn;\r
+ INT32 SecRow;\r
+ UINT8 SaveChar;\r
+ UINT8 SecsLeft;\r
+\r
+ //\r
+ // if auto select, just get right to it\r
+ //\r
+ if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_AUTO_SELECT) {\r
+ return AUTO_SELECT;\r
+ }\r
+ //\r
+ // if no timeout, go directly to display of menu\r
+ //\r
+ if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_NO_TIMEOUT) {\r
+ return DO_MENU;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return DO_MENU;\r
+ }\r
+\r
+ Status = gBS->SetTimer (\r
+ TimeoutEvent,\r
+ TimerRelative,\r
+ BootPromptPtr->Timeout * 10000000 + 100000\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return DO_MENU;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &SecondsEvent\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return DO_MENU;\r
+ }\r
+\r
+ Status = gBS->SetTimer (\r
+ SecondsEvent,\r
+ TimerPeriodic,\r
+ 10000000\r
+ ); /* 1 second */\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseEvent (SecondsEvent);\r
+ gBS->CloseEvent (TimeoutEvent);\r
+ return DO_MENU;\r
+ }\r
+ //\r
+ // display the prompt\r
+ // IMPORTANT! This prompt is an ASCII character string that may\r
+ // not be terminated with a NULL byte.\r
+ //\r
+ SaveChar = BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1];\r
+ BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = 0;\r
+\r
+ AsciiPrint ("%a ", BootPromptPtr->Prompt);\r
+ BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = SaveChar;\r
+\r
+ //\r
+ // wait until time expires or selection made - menu or local\r
+ //\r
+ SecColumn = gST->ConOut->Mode->CursorColumn;\r
+ SecRow = gST->ConOut->Mode->CursorRow;\r
+ SecsLeft = BootPromptPtr->Timeout;\r
+\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);\r
+ AsciiPrint ("(%d) ", SecsLeft);\r
+\r
+ //\r
+ // set the default action to be AUTO_SELECT\r
+ //\r
+ Status = AUTO_SELECT;\r
+\r
+ while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
+ EFI_INPUT_KEY Key;\r
+\r
+ if (!EFI_ERROR (gBS->CheckEvent (SecondsEvent))) {\r
+ --SecsLeft;\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);\r
+ AsciiPrint ("(%d) ", SecsLeft);\r
+ }\r
+\r
+ if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {\r
+ UINT8 Buffer[512];\r
+ UINTN BufferSize;\r
+ EFI_STATUS Status;\r
+\r
+ BufferSize = sizeof Buffer;\r
+\r
+ Status = Private->EfiBc.UdpRead (\r
+ &Private->EfiBc,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,\r
+ NULL, /* dest ip */\r
+ NULL, /* dest port */\r
+ NULL, /* src ip */\r
+ NULL, /* src port */\r
+ NULL, /* hdr size */\r
+ NULL, /* hdr ptr */\r
+ &BufferSize,\r
+ Buffer\r
+ );\r
+\r
+ continue;\r
+ }\r
+\r
+ if (Key.ScanCode == 0) {\r
+ switch (Key.UnicodeChar) {\r
+ case Ctl ('c'):\r
+ Status = LOCAL_BOOT;\r
+ break;\r
+\r
+ case Ctl ('m'):\r
+ case 'm':\r
+ case 'M':\r
+ Status = DO_MENU;\r
+ break;\r
+\r
+ default:\r
+ continue;\r
+ }\r
+ } else {\r
+ switch (Key.ScanCode) {\r
+ case SCAN_F8:\r
+ Status = DO_MENU;\r
+ break;\r
+\r
+ case SCAN_ESC:\r
+ Status = LOCAL_BOOT;\r
+ break;\r
+\r
+ default:\r
+ continue;\r
+ }\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ gBS->CloseEvent (SecondsEvent);\r
+ gBS->CloseEvent (TimeoutEvent);\r
+\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);\r
+ AsciiPrint (" ");\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Display one menu item.\r
+\r
+ @param MenuItemPtr Pointer to PXE menu item\r
+ option.\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+PrintMenuItem (\r
+ PXE_BOOT_MENU_ENTRY *MenuItemPtr\r
+ )\r
+{\r
+ UINT8 Length;\r
+ UINT8 SaveChar;\r
+\r
+ Length = (UINT8) MIN (70, MenuItemPtr->DataLen);\r
+ SaveChar = MenuItemPtr->Data[Length];\r
+\r
+ MenuItemPtr->Data[Length] = 0;\r
+ AsciiPrint (" %a\n", MenuItemPtr->Data);\r
+ MenuItemPtr->Data[Length] = SaveChar;\r
+}\r
+\r
+\r
+/**\r
+ Display and process menu.\r
+\r
+ @param Private Pointer to PxeBc interface\r
+ @param RxBufferPtr Pointer to receive buffer\r
+\r
+ @retval NO_MENU\r
+ @retval LOCAL_BOOT\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DoMenu (\r
+ PXE_BASECODE_DEVICE *Private,\r
+ DHCP_RECEIVE_BUFFER *RxBufferPtr\r
+ )\r
+{\r
+ PXE_OP_DISCOVERY_CONTROL *DiscoveryControlPtr;\r
+ PXE_BOOT_MENU_ENTRY *MenuItemPtrs[MAX_MENULIST];\r
+ EFI_STATUS Status;\r
+ UNION_PTR Ptr;\r
+ UINTN SaveNumRte;\r
+ UINTN TopRow;\r
+ UINTN MenuLth;\r
+ UINTN NumMenuItems;\r
+ UINTN Index;\r
+ UINTN Longest;\r
+ UINTN Selected;\r
+ UINT16 Type;\r
+ UINT16 Layer;\r
+ BOOLEAN Done;\r
+\r
+ Selected = 0;\r
+ Layer = 0;\r
+\r
+ DEBUG ((DEBUG_WARN, "\nDoMenu() Enter."));\r
+\r
+ /* see if we have a menu/prompt */\r
+ if (!(RxBufferPtr->OpAdds.Status & DISCOVER_TYPE)) {\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nDoMenu() No menu/prompt info. OpAdds.Status == %xh ",\r
+ RxBufferPtr->OpAdds.Status)\r
+ );\r
+\r
+ return NO_MENU;\r
+ }\r
+\r
+ DiscoveryControlPtr = (PXE_OP_DISCOVERY_CONTROL *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];\r
+\r
+ //\r
+ // if not USE_BOOTFILE or no bootfile given, must have menu stuff\r
+ //\r
+ if ((DiscoveryControlPtr->ControlBits & USE_BOOTFILE) && RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {\r
+ DEBUG ((DEBUG_WARN, "\nDoMenu() DHCP w/ bootfile. "));\r
+ return NO_MENU;\r
+ }\r
+ //\r
+ // do prompt & menu if necessary\r
+ //\r
+ Status = DoPrompt (Private, (PXE_OP_BOOT_PROMPT *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]);\r
+\r
+ if (Status == LOCAL_BOOT) {\r
+ DEBUG ((DEBUG_WARN, "\nDoMenu() DoPrompt() returned LOCAL_BOOT. "));\r
+\r
+ return Status;\r
+ }\r
+\r
+ Ptr.BytePtr = (UINT8 *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];\r
+\r
+ MenuLth = Ptr.MenuPtr->Header.Length;\r
+ Ptr.CurrentMenuItemPtr = Ptr.MenuPtr->MenuItem;\r
+\r
+ //\r
+ // build menu items array\r
+ //\r
+ for (Longest = NumMenuItems = Index = 0; Index < MenuLth && NumMenuItems < MAX_MENULIST;) {\r
+ UINTN lth;\r
+\r
+ lth = Ptr.CurrentMenuItemPtr->DataLen + sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data);\r
+\r
+ MenuItemPtrs[NumMenuItems++] = Ptr.CurrentMenuItemPtr;\r
+\r
+ if (lth > Longest) {\r
+ //\r
+ // check if too long\r
+ //\r
+ if ((Longest = lth) > 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))) {\r
+ Longest = 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data));\r
+ }\r
+ }\r
+\r
+ Index += lth;\r
+ Ptr.BytePtr += lth;\r
+ }\r
+\r
+ if (Status != AUTO_SELECT) {\r
+ UINT8 BlankBuf[75];\r
+\r
+ SetMem (BlankBuf, sizeof BlankBuf, ' ');\r
+ BlankBuf[Longest + 5 - (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))] = 0;\r
+ AsciiPrint ("\n");\r
+\r
+ //\r
+ // now put up menu\r
+ //\r
+ for (Index = 0; Index < NumMenuItems; ++Index) {\r
+ PrintMenuItem (MenuItemPtrs[Index]);\r
+ }\r
+\r
+ TopRow = gST->ConOut->Mode->CursorRow - NumMenuItems;\r
+\r
+ //\r
+ // now wait for a selection\r
+ //\r
+ Done = FALSE;\r
+ do {\r
+ //\r
+ // highlight selection\r
+ //\r
+ EFI_INPUT_KEY Key;\r
+ UINTN NewSelected;\r
+\r
+ NewSelected = Selected;\r
+\r
+ //\r
+ // highlight selected row\r
+ //\r
+ gST->ConOut->SetAttribute (\r
+ gST->ConOut,\r
+ EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)\r
+ );\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Selected);\r
+\r
+ AsciiPrint (" --->%a\r", BlankBuf);\r
+\r
+ PrintMenuItem (MenuItemPtrs[Selected]);\r
+ gST->ConOut->SetAttribute (\r
+ gST->ConOut,\r
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)\r
+ );\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + NumMenuItems);\r
+\r
+ //\r
+ // wait for a keystroke\r
+ //\r
+ while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {\r
+ UINT8 TmpBuf[512];\r
+ UINTN TmpBufLen;\r
+\r
+ TmpBufLen = sizeof TmpBuf;\r
+\r
+ Private->EfiBc.UdpRead (\r
+ &Private->EfiBc,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,\r
+ NULL, /* dest ip */\r
+ NULL, /* dest port */\r
+ NULL, /* src ip */\r
+ NULL, /* src port */\r
+ NULL, /* hdr size */\r
+ NULL, /* hdr ptr */\r
+ &TmpBufLen,\r
+ TmpBuf\r
+ );\r
+ }\r
+\r
+ if (!Key.ScanCode) {\r
+ switch (Key.UnicodeChar) {\r
+ case Ctl ('c'):\r
+ Key.ScanCode = SCAN_ESC;\r
+ break;\r
+\r
+ case Ctl ('j'): /* linefeed */\r
+ case Ctl ('m'): /* return */\r
+ Done = TRUE;\r
+ break;\r
+\r
+ case Ctl ('i'): /* tab */\r
+ case ' ':\r
+ case 'd':\r
+ case 'D':\r
+ Key.ScanCode = SCAN_DOWN;\r
+ break;\r
+\r
+ case Ctl ('h'): /* backspace */\r
+ case 'u':\r
+ case 'U':\r
+ Key.ScanCode = SCAN_UP;\r
+ break;\r
+\r
+ default:\r
+ Key.ScanCode = 0;\r
+ }\r
+ }\r
+\r
+ switch (Key.ScanCode) {\r
+ case SCAN_LEFT:\r
+ case SCAN_UP:\r
+ if (NewSelected) {\r
+ --NewSelected;\r
+ }\r
+\r
+ break;\r
+\r
+ case SCAN_DOWN:\r
+ case SCAN_RIGHT:\r
+ if (++NewSelected == NumMenuItems) {\r
+ --NewSelected;\r
+ }\r
+\r
+ break;\r
+\r
+ case SCAN_PAGE_UP:\r
+ case SCAN_HOME:\r
+ NewSelected = 0;\r
+ break;\r
+\r
+ case SCAN_PAGE_DOWN:\r
+ case SCAN_END:\r
+ NewSelected = NumMenuItems - 1;\r
+ break;\r
+\r
+ case SCAN_ESC:\r
+ return LOCAL_BOOT;\r
+ }\r
+\r
+ /* unhighlight last selected row */\r
+ gST->ConOut->SetCursorPosition (gST->ConOut, 5, TopRow + Selected);\r
+\r
+ AsciiPrint ("%a\r", BlankBuf);\r
+\r
+ PrintMenuItem (MenuItemPtrs[Selected]);\r
+\r
+ Selected = NewSelected;\r
+ } while (!Done);\r
+ }\r
+\r
+ SaveNumRte = Private->EfiBc.Mode->RouteTableEntries;\r
+\r
+ Type = NTOHS (MenuItemPtrs[Selected]->Type);\r
+\r
+ if (Type == 0) {\r
+ DEBUG ((DEBUG_WARN, "\nDoMenu() Local boot selected. "));\r
+ return LOCAL_BOOT;\r
+ }\r
+\r
+ AsciiPrint ("Discover");\r
+\r
+ Status = Private->EfiBc.Discover (\r
+ &Private->EfiBc,\r
+ Type,\r
+ &Layer,\r
+ (BOOLEAN) (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected),\r
+ 0\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ AsciiPrint ("\r \r");\r
+\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nDoMenu() Return w/ %xh (%r).",\r
+ Status,\r
+ Status)\r
+ );\r
+\r
+ return Status;\r
+ }\r
+\r
+ AsciiPrint ("\rBOOT_SERVER_IP: ");\r
+ PrintIpv4 ((UINT8 *) &Private->ServerIp);\r
+\r
+ for (Index = SaveNumRte; Index < Private->EfiBc.Mode->RouteTableEntries; ++Index) {\r
+ if ((Index % 3) == 0) {\r
+ AsciiPrint ("\r\nGATEWAY IP:");\r
+ }\r
+\r
+ AsciiPrint (" ");\r
+ PrintIpv4 ((UINT8 *) &Private->EfiBc.Mode->RouteTable[Index].GwAddr);\r
+ AsciiPrint (" ");\r
+ }\r
+\r
+ AsciiPrint ("\n");\r
+\r
+ DEBUG ((DEBUG_WARN, "\nDoMenu() Return w/ EFI_SUCCESS. "));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Get value 8- or 16-bit value from DHCP option.\r
+\r
+ @param OpPtr Pointer to DHCP option\r
+\r
+ @return Value from DHCP option\r
+\r
+**/\r
+STATIC\r
+UINT16\r
+GetValue (\r
+ DHCPV4_OP_STRUCT *OpPtr\r
+ )\r
+{\r
+ if (OpPtr->Header.Length == 1) {\r
+ return OpPtr->Data[0];\r
+ } else {\r
+ return NTOHS (OpPtr->Data);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Locate opcode in buffer.\r
+\r
+ @param BufferPtr Pointer to buffer\r
+ @param BufferLen Length of buffer\r
+ @param OpCode Option number\r
+\r
+ @return Pointer to opcode, may be NULL\r
+\r
+**/\r
+STATIC\r
+UINT8 *\r
+_PxeBcFindOpt (\r
+ UINT8 *BufferPtr,\r
+ UINTN BufferLen,\r
+ UINT8 OpCode\r
+ )\r
+{\r
+ if (BufferPtr == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ while (BufferLen != 0) {\r
+ if (*BufferPtr == OpCode) {\r
+ return BufferPtr;\r
+ }\r
+\r
+ switch (*BufferPtr) {\r
+ case OP_END:\r
+ return NULL;\r
+\r
+ case OP_PAD:\r
+ ++BufferPtr;\r
+ --BufferLen;\r
+ continue;\r
+ }\r
+\r
+ if ((UINTN) BufferLen <= (UINTN) 2 + BufferPtr[1]) {\r
+ return NULL;\r
+ }\r
+\r
+ BufferLen -= 2 + BufferPtr[1];\r
+ BufferPtr += 2 + BufferPtr[1];\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Find option in packet\r
+\r
+ @param PacketPtr Pointer to packet\r
+ @param OpCode option number\r
+\r
+ @return Pointer to option in packet\r
+\r
+**/\r
+STATIC\r
+UINT8 *\r
+PxeBcFindDhcpOpt (\r
+ EFI_PXE_BASE_CODE_PACKET *PacketPtr,\r
+ UINT8 OpCode\r
+ )\r
+{\r
+ UINTN PacketLen;\r
+ UINT8 Overload;\r
+ UINT8 *OptionBufferPtr;\r
+\r
+ //\r
+ //\r
+ //\r
+ PacketLen = 380;\r
+ Overload = 0;\r
+\r
+ //\r
+ // Figure size of DHCP option space.\r
+ //\r
+ OptionBufferPtr = _PxeBcFindOpt (\r
+ PacketPtr->Dhcpv4.DhcpOptions,\r
+ 380,\r
+ OP_DHCP_MAX_MESSAGE_SZ\r
+ );\r
+\r
+ if (OptionBufferPtr != NULL) {\r
+ if (OptionBufferPtr[1] == 2) {\r
+ UINT16 n;\r
+\r
+ CopyMem (&n, &OptionBufferPtr[2], 2);\r
+ PacketLen = HTONS (n);\r
+\r
+ if (PacketLen < sizeof (EFI_PXE_BASE_CODE_DHCPV4_PACKET)) {\r
+ PacketLen = 380;\r
+ } else {\r
+ PacketLen -= (PacketPtr->Dhcpv4.DhcpOptions - &PacketPtr->Dhcpv4.BootpOpcode) + 28;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Look for option overloading.\r
+ //\r
+ OptionBufferPtr = _PxeBcFindOpt (\r
+ PacketPtr->Dhcpv4.DhcpOptions,\r
+ PacketLen,\r
+ OP_DHCP_OPTION_OVERLOAD\r
+ );\r
+\r
+ if (OptionBufferPtr != NULL) {\r
+ if (OptionBufferPtr[1] == 1) {\r
+ Overload = OptionBufferPtr[2];\r
+ }\r
+ }\r
+ //\r
+ // Look for caller's option.\r
+ //\r
+ OptionBufferPtr = _PxeBcFindOpt (\r
+ PacketPtr->Dhcpv4.DhcpOptions,\r
+ PacketLen,\r
+ OpCode\r
+ );\r
+\r
+ if (OptionBufferPtr != NULL) {\r
+ return OptionBufferPtr;\r
+ }\r
+\r
+ if (Overload & OVLD_FILE) {\r
+ OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpBootFile, 128, OpCode);\r
+\r
+ if (OptionBufferPtr != NULL) {\r
+ return OptionBufferPtr;\r
+ }\r
+ }\r
+\r
+ if (Overload & OVLD_SRVR_NAME) {\r
+ OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpSrvName, 64, OpCode);\r
+\r
+ if (OptionBufferPtr != NULL) {\r
+ return OptionBufferPtr;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Download file into buffer\r
+\r
+ @param Private Pointer to PxeBc interface\r
+ @param BufferSize pointer to size of download\r
+ buffer\r
+ @param Buffer Pointer to buffer\r
+\r
+ @return EFI_BUFFER_TOO_SMALL -\r
+ @return EFI_NOT_FOUND -\r
+ @return EFI_PROTOCOL_ERROR -\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DownloadFile (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN OUT UINT64 *BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MTFTP_INFO MtftpInfo;\r
+ EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode;\r
+ DHCP_RECEIVE_BUFFER *RxBuf;\r
+ EFI_STATUS Status;\r
+ UINTN BlockSize;\r
+\r
+ RxBuf = (DHCP_RECEIVE_BUFFER *) Private->BootServerReceiveBuffer;\r
+ BlockSize = 0x8000;\r
+\r
+ DEBUG ((EFI_D_WARN, "\nDownloadFile() Enter."));\r
+\r
+ if (Buffer == NULL || *BufferSize == 0 || *BufferSize < Private->FileSize) {\r
+ if (Private->FileSize != 0) {\r
+ *BufferSize = Private->FileSize;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ AsciiPrint ("\nTSize");\r
+\r
+ OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE;\r
+ } else if (RxBuf->OpAdds.Status & WfM11a_TYPE) {\r
+ OpCode = EFI_PXE_BASE_CODE_MTFTP_READ_FILE;\r
+\r
+ ZeroMem (&MtftpInfo, sizeof MtftpInfo);\r
+\r
+ *(IPV4_ADDR *) &MtftpInfo.MCastIp = *(IPV4_ADDR *) RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_IP - 1]->Data;\r
+\r
+ CopyMem (\r
+ &MtftpInfo.CPort,\r
+ RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_CPORT - 1]->Data,\r
+ sizeof MtftpInfo.CPort\r
+ );\r
+\r
+ CopyMem (\r
+ &MtftpInfo.SPort,\r
+ RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_SPORT - 1]->Data,\r
+ sizeof MtftpInfo.SPort\r
+ );\r
+\r
+ MtftpInfo.ListenTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_TMOUT - 1]);\r
+\r
+ MtftpInfo.TransmitTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_DELAY - 1]);\r
+\r
+ AsciiPrint ("\nMTFTP");\r
+ } else {\r
+ AsciiPrint ("\nTFTP");\r
+\r
+ OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;\r
+ }\r
+\r
+ Private->FileSize = 0;\r
+\r
+ RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data[RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length] = 0;\r
+\r
+ Status = Private->EfiBc.Mtftp (\r
+ &Private->EfiBc,\r
+ OpCode,\r
+ Buffer,\r
+ FALSE,\r
+ BufferSize,\r
+ &BlockSize,\r
+ &Private->ServerIp,\r
+ (UINT8 *) RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data,\r
+ &MtftpInfo,\r
+ FALSE\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {\r
+ DEBUG ((DEBUG_WARN, "\nDownloadFile() Exit #1 %Xh", Status));\r
+ return Status;\r
+ }\r
+\r
+ if (sizeof (UINTN) < sizeof (UINT64) && *BufferSize > 0xFFFFFFFF) {\r
+ Private->FileSize = 0xFFFFFFFF;\r
+ } else {\r
+ Private->FileSize = (UINTN) *BufferSize;\r
+ }\r
+\r
+ if (OpCode == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {\r
+ DEBUG ((DEBUG_WARN, "\nDownloadFile() Exit #2"));\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "\nDownloadFile() Exit #3 %Xh", Status));\r
+ return Status;\r
+ }\r
+\r
+ if (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected && Private->EfiBc.Mode->PxeBisReplyReceived) {\r
+ UINT64 CredentialLen;\r
+ UINTN BlockSize;\r
+ UINT8 CredentialFilename[256];\r
+ UINT8 *op;\r
+ VOID *CredentialBuffer;\r
+\r
+ //\r
+ // Get name of credential file. It may be in the BOOTP\r
+ // bootfile field or a DHCP option.\r
+ //\r
+ ZeroMem (CredentialFilename, sizeof CredentialFilename);\r
+\r
+ op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_DHCP_BOOTFILE);\r
+\r
+ if (op != NULL) {\r
+ if (op[1] == 0) {\r
+ /* No credential filename */\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ CopyMem (CredentialFilename, &op[2], op[1]);\r
+ } else {\r
+ if (Private->EfiBc.Mode->PxeBisReply.Dhcpv4.BootpBootFile[0] == 0) {\r
+ /* No credential filename */\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ CopyMem (CredentialFilename, &op[2], 128);\r
+ }\r
+ //\r
+ // Get size of credential file. It may be available as a\r
+ // DHCP option. If not, use the TFTP get file size.\r
+ //\r
+ CredentialLen = 0;\r
+\r
+ op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_BOOT_FILE_SZ);\r
+\r
+ if (op != NULL) {\r
+ /*\r
+ * This is actually the size of the credential file\r
+ * buffer. The actual credential file size will be\r
+ * returned when we download the file.\r
+ */\r
+ if (op[1] == 2) {\r
+ UINT16 n;\r
+\r
+ CopyMem (&n, &op[2], 2);\r
+ CredentialLen = HTONS (n) * 512;\r
+ }\r
+ }\r
+\r
+ if (CredentialLen == 0) {\r
+ BlockSize = 8192;\r
+\r
+ Status = Private->EfiBc.Mtftp (\r
+ &Private->EfiBc,\r
+ EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,\r
+ NULL,\r
+ FALSE,\r
+ &CredentialLen,\r
+ &BlockSize,\r
+ &Private->ServerIp,\r
+ CredentialFilename,\r
+ NULL,\r
+ FALSE\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (CredentialLen == 0) {\r
+ //\r
+ // %%TBD -- EFI error for invalid credential\r
+ // file.\r
+ //\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ }\r
+ //\r
+ // Allocate credential file buffer.\r
+ //\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ (UINTN) CredentialLen,\r
+ &CredentialBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Download credential file.\r
+ //\r
+ BlockSize = 8192;\r
+\r
+ Status = Private->EfiBc.Mtftp (\r
+ &Private->EfiBc,\r
+ EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
+ CredentialBuffer,\r
+ FALSE,\r
+ &CredentialLen,\r
+ &BlockSize,\r
+ &Private->ServerIp,\r
+ CredentialFilename,\r
+ NULL,\r
+ FALSE\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (CredentialBuffer);\r
+ return Status;\r
+ }\r
+ //\r
+ // Verify credentials.\r
+ //\r
+ if (PxebcBisVerify (Private, Buffer, Private->FileSize, CredentialBuffer, (UINTN) CredentialLen)) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ //\r
+ // %%TBD -- An EFI error code for failing credential verification.\r
+ //\r
+ Status = EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ gBS->FreePool (CredentialBuffer);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Start PXE DHCP. Get DHCP and proxyDHCP information.\r
+ Display remote boot menu and prompt. Select item from menu.\r
+\r
+ @param Private Pointer to PxeBc interface\r
+ @param BufferSize Pointer to download buffer\r
+ size\r
+ @param Buffer Pointer to download buffer\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_NOT_READY\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+LoadfileStart (\r
+ IN PXE_BASECODE_DEVICE *Private,\r
+ IN OUT UINT64 *BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
+ EFI_STATUS Status;\r
+ VOID *RxBuf;\r
+\r
+ DEBUG ((DEBUG_WARN, "\nLoadfileStart() Enter."));\r
+\r
+ //\r
+ // Try to start BaseCode, for now only IPv4 is supported\r
+ // so don't try to start using IPv6.\r
+ //\r
+ Status = Private->EfiBc.Start (&Private->EfiBc, FALSE);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if (Status != EFI_ALREADY_STARTED) {\r
+ DEBUG ((DEBUG_NET, "\nLoadfileStart() Exit BC.Start() == %xh", Status));\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // Get pointers to PXE mode structure, SNP protocol structure\r
+ // and SNP mode structure.\r
+ //\r
+ PxeBcMode = Private->EfiBc.Mode;\r
+ Snp = Private->SimpleNetwork;\r
+ SnpMode = Snp->Mode;\r
+\r
+ //\r
+ // Display client MAC address, like 16-bit PXE ROMs\r
+ //\r
+ AsciiPrint ("\nCLIENT MAC ADDR: ");\r
+\r
+ {\r
+ UINTN Index;\r
+ UINTN hlen;\r
+\r
+ hlen = SnpMode->HwAddressSize;\r
+\r
+ for (Index = 0; Index < hlen; ++Index) {\r
+ AsciiPrint ("%02x ", SnpMode->CurrentAddress.Addr[Index]);\r
+ }\r
+ }\r
+\r
+ AsciiPrint ("\nDHCP");\r
+\r
+ Status = Private->EfiBc.Dhcp (&Private->EfiBc, TRUE);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "\nLoadfileStart() Exit BC.Dhcp() == %Xh", Status));\r
+ AsciiPrint ("\r \r");\r
+ return Status;\r
+ }\r
+\r
+ ShowMyInfo (Private);\r
+\r
+ RxBuf = PxeBcMode->ProxyOfferReceived ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;\r
+#define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf)\r
+\r
+ Status = DoMenu (Private, RxBufferPtr);\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // did a discovery - take info from discovery packet\r
+ //\r
+ RxBuf = &PXE_ACK_BUFFER;\r
+ } else if (Status == NO_MENU) {\r
+ //\r
+ // did not do a discovery - take info from rxbuf\r
+ //\r
+ Private->ServerIp.Addr[0] = RxBufferPtr->u.Dhcpv4.siaddr;\r
+\r
+ if (!(Private->ServerIp.Addr[0])) {\r
+ *(IPV4_ADDR *) &Private->ServerIp = *(IPV4_ADDR *) RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]->Data;\r
+ }\r
+ } else {\r
+ DEBUG ((DEBUG_WARN, "\nLoadfileStart() Exit DoMenu() == %Xh", Status));\r
+ return Status;\r
+ }\r
+\r
+ if (!RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {\r
+ DEBUG ((DEBUG_WARN, "\nLoadfileStart() Exit Not ready?"));\r
+ return EFI_NOT_READY;\r
+ }\r
+ //\r
+ // check for file size option sent\r
+ //\r
+ if (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]) {\r
+ Private->FileSize = 512 * NTOHS (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]->Data);\r
+ }\r
+\r
+ Private->BootServerReceiveBuffer = RxBufferPtr;\r
+\r
+ Status = DownloadFile (Private, BufferSize, Buffer);\r
+\r
+ DEBUG (\r
+ (DEBUG_WARN,\r
+ "\nLoadfileStart() Exit. DownloadFile() = %Xh",\r
+ Status)\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Loadfile interface for PxeBc interface\r
+\r
+ @param This Pointer to Loadfile interface\r
+ @param FilePath Not used and not checked\r
+ @param BootPolicy Must be TRUE\r
+ @param BufferSize Pointer to buffer size\r
+ @param Buffer Pointer to download buffer or\r
+ NULL\r
+\r
+ @return EFI_INVALID_PARAMETER -\r
+ @return EFI_UNSUPPORTED -\r
+ @return EFI_SUCCESS -\r
+ @return EFI_BUFFER_TOO_SMALL -\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadFile (\r
+ IN EFI_LOAD_FILE_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
+ IN BOOLEAN BootPolicy,\r
+ IN OUT UINTN *BufferSize,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ LOADFILE_DEVICE *LoadfilePtr;\r
+ UINT64 TmpBufSz;\r
+ INT32 OrigMode;\r
+ INT32 OrigAttribute;\r
+ BOOLEAN RemoveCallback;\r
+ BOOLEAN NewMakeCallback;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS TempStatus;\r
+ //\r
+ //\r
+ //\r
+ OrigMode = gST->ConOut->Mode->Mode;\r
+ OrigAttribute = gST->ConOut->Mode->Attribute;\r
+ RemoveCallback = FALSE;\r
+\r
+ AsciiPrint ("Running LoadFile()\n");\r
+\r
+ //\r
+ // Resolve Warning 4 unreferenced parameter problem\r
+ //\r
+ FilePath = NULL;\r
+\r
+ //\r
+ // If either if these parameters are NULL, we cannot continue.\r
+ //\r
+ if (This == NULL || BufferSize == NULL) {\r
+ DEBUG ((DEBUG_WARN, "\nLoadFile() This or BufferSize == NULL"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // We only support BootPolicy == TRUE\r
+ //\r
+ if (!BootPolicy) {\r
+ DEBUG ((DEBUG_WARN, "\nLoadFile() BootPolicy == FALSE"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Get pointer to LoadFile protocol structure.\r
+ //\r
+ LoadfilePtr = CR (This, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE);\r
+\r
+ if (LoadfilePtr == NULL) {\r
+ DEBUG (\r
+ (DEBUG_NET,\r
+ "\nLoadFile() Could not get pointer to LoadFile structure")\r
+ );\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Lock interface\r
+ //\r
+ EfiAcquireLock (&LoadfilePtr->Lock);\r
+\r
+ //\r
+ // Set console output mode and display attribute\r
+ //\r
+ if (OrigMode != 0) {\r
+ gST->ConOut->SetMode (gST->ConOut, 0);\r
+ }\r
+\r
+ gST->ConOut->SetAttribute (\r
+ gST->ConOut,\r
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK)\r
+ );\r
+\r
+ //\r
+ // See if BaseCode already has a Callback protocol attached.\r
+ // If there is none, attach our own Callback protocol.\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ LoadfilePtr->Private->Handle,\r
+ &gEfiPxeBaseCodeCallbackProtocolGuid,\r
+ (VOID *) &LoadfilePtr->Private->CallbackProtocolPtr\r
+ );\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // There is already a callback routine. Do nothing.\r
+ //\r
+ DEBUG ((DEBUG_WARN, "\nLoadFile() BC callback exists."));\r
+\r
+ } else if (Status == EFI_UNSUPPORTED) {\r
+ //\r
+ // No BaseCode Callback protocol found. Add our own.\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &LoadfilePtr->Private->Handle,\r
+ &gEfiPxeBaseCodeCallbackProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &_bc_callback\r
+ );\r
+\r
+ DEBUG ((DEBUG_WARN, "\nLoadFile() Callback install status == %xh", Status));\r
+\r
+ RemoveCallback = (BOOLEAN) (Status == EFI_SUCCESS);\r
+\r
+ if (LoadfilePtr->Private->EfiBc.Mode != NULL && LoadfilePtr->Private->EfiBc.Mode->Started) {\r
+ NewMakeCallback = TRUE;\r
+ LoadfilePtr->Private->EfiBc.SetParameters (\r
+ &LoadfilePtr->Private->EfiBc,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ &NewMakeCallback\r
+ );\r
+ }\r
+\r
+ } else {\r
+ DEBUG ((DEBUG_WARN, "\nLoadFile() Callback check status == %xh", Status));\r
+ }\r
+ //\r
+ // Check for starting or for continuing after already getting\r
+ // the file size.\r
+ //\r
+ if (LoadfilePtr->Private->FileSize == 0) {\r
+ TmpBufSz = 0;\r
+ Status = LoadfileStart (LoadfilePtr->Private, &TmpBufSz, Buffer);\r
+\r
+ if (sizeof (UINTN) < sizeof (UINT64) && TmpBufSz > 0xFFFFFFFF) {\r
+ *BufferSize = 0xFFFFFFFF;\r
+ } else {\r
+ *BufferSize = (UINTN) TmpBufSz;\r
+ }\r
+\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // This is done so loadfile will work even if the boot manager\r
+ // did not make the first call with Buffer == NULL.\r
+ //\r
+ Buffer = NULL;\r
+ }\r
+ } else if (Buffer == NULL) {\r
+ DEBUG ((DEBUG_WARN, "\nLoadfile() Get buffer size"));\r
+\r
+ //\r
+ // Continuing from previous LoadFile request. Make sure there\r
+ // is a buffer and that it is big enough.\r
+ //\r
+ *BufferSize = LoadfilePtr->Private->FileSize;\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ DEBUG ((DEBUG_WARN, "\nLoadFile() Download file"));\r
+\r
+ //\r
+ // Everything looks good, try to download the file.\r
+ //\r
+ TmpBufSz = *BufferSize;\r
+ Status = DownloadFile (LoadfilePtr->Private, &TmpBufSz, Buffer);\r
+\r
+ //\r
+ // Next call to loadfile will start DHCP process again.\r
+ //\r
+ LoadfilePtr->Private->FileSize = 0;\r
+ }\r
+ //\r
+ // If we added a callback protocol, now is the time to remove it.\r
+ //\r
+ if (RemoveCallback) {\r
+ NewMakeCallback = FALSE;\r
+ TempStatus = LoadfilePtr->Private->EfiBc.SetParameters (\r
+ &LoadfilePtr->Private->EfiBc,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ &NewMakeCallback\r
+ );\r
+\r
+ if (TempStatus == EFI_SUCCESS) {\r
+ gBS->UninstallProtocolInterface (\r
+ LoadfilePtr->Private->Handle,\r
+ &gEfiPxeBaseCodeCallbackProtocolGuid,\r
+ &_bc_callback\r
+ );\r
+ }\r
+ }\r
+ //\r
+ // Restore display mode and attribute\r
+ //\r
+ if (OrigMode != 0) {\r
+ gST->ConOut->SetMode (gST->ConOut, OrigMode);\r
+ }\r
+\r
+ gST->ConOut->SetAttribute (gST->ConOut, OrigAttribute);\r
+\r
+ //\r
+ // Unlock interface\r
+ //\r
+ EfiReleaseLock (&LoadfilePtr->Lock);\r
+\r
+ DEBUG ((DEBUG_WARN, "\nBC.Loadfile() Status == %xh\n", Status));\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ return EFI_SUCCESS;\r
+\r
+ } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // Error is only displayed when we are actually trying to\r
+ // download the boot image.\r
+ //\r
+ if (Buffer == NULL) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ AsciiPrint ("\nPXE-E05: Download buffer is smaller than requested file.\n");\r
+\r
+ } else if (Status == EFI_DEVICE_ERROR) {\r
+ AsciiPrint ("\nPXE-E07: Network device error. Check network connection.\n");\r
+\r
+ } else if (Status == EFI_OUT_OF_RESOURCES) {\r
+ AsciiPrint ("\nPXE-E09: Could not allocate I/O buffers.\n");\r
+\r
+ } else if (Status == EFI_NO_MEDIA) {\r
+ AsciiPrint ("\nPXE-E12: Could not detect network connection. Check cable.\n");\r
+\r
+ } else if (Status == EFI_NO_RESPONSE) {\r
+ AsciiPrint ("\nPXE-E16: Valid PXE offer not received.\n");\r
+\r
+ } else if (Status == EFI_TIMEOUT) {\r
+ AsciiPrint ("\nPXE-E18: Timeout. Server did not respond.\n");\r
+\r
+ } else if (Status == EFI_ABORTED) {\r
+ AsciiPrint ("\nPXE-E21: Remote boot cancelled.\n");\r
+\r
+ } else if (Status == EFI_ICMP_ERROR) {\r
+ AsciiPrint ("\nPXE-E22: Client received ICMP error from server.\n");\r
+\r
+ if (LoadfilePtr->Private->EfiBc.Mode != NULL) {\r
+ if (LoadfilePtr->Private->EfiBc.Mode->IcmpErrorReceived) {\r
+\r
+ AsciiPrint (\r
+ "PXE-E98: Type: %xh Code: %xh ",\r
+ LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type,\r
+ LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code\r
+ );\r
+\r
+ switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type) {\r
+ case 0x03:\r
+ switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code) {\r
+ case 0x00: /* net unreachable */\r
+ AsciiPrint ("Net unreachable");\r
+ break;\r
+\r
+ case 0x01: /* host unreachable */\r
+ AsciiPrint ("Host unreachable");\r
+ break;\r
+\r
+ case 0x02: /* protocol unreachable */\r
+ AsciiPrint ("Protocol unreachable");\r
+ break;\r
+\r
+ case 0x03: /* port unreachable */\r
+ AsciiPrint ("Port unreachable");\r
+ break;\r
+\r
+ case 0x04: /* Fragmentation needed */\r
+ AsciiPrint ("Fragmentation needed");\r
+ break;\r
+\r
+ case 0x05: /* Source route failed */\r
+ AsciiPrint ("Source route failed");\r
+ break;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ AsciiPrint ("\n");\r
+ }\r
+ }\r
+\r
+ } else if (Status == EFI_TFTP_ERROR) {\r
+ AsciiPrint ("\nPXE-E23: Client received TFTP error from server.\n");\r
+\r
+ if (LoadfilePtr->Private->EfiBc.Mode != NULL) {\r
+ if (LoadfilePtr->Private->EfiBc.Mode->TftpErrorReceived) {\r
+ AsciiPrint (\r
+ "PXE-E98: Code: %xh %a\n",\r
+ LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorCode,\r
+ LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorString\r
+ );\r
+ }\r
+ }\r
+\r
+ } else {\r
+ AsciiPrint ("\nPXE-E99: Unexpected network error: %xh\n", Status);\r
+ }\r
+\r
+ LoadfilePtr->Private->EfiBc.Stop (&LoadfilePtr->Private->EfiBc);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file
+
+Copyright (c) 2004, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ tftp.h
+
+Abstract:
+
+
+**/
+
+#ifndef __TFTP_H__
+#define __TFTP_H__
+
+//
+// Definitions for trivial file transfer protocol functionality with IP v4
+// Per RFC 1350, July 1992 and RFC 2347, 8, and 9, May 1998
+//
+#pragma pack(1)
+//
+// max and min packet sizes
+// (all data packets in transmission except last)
+//
+#define MAX_TFTP_PKT_SIZE (BUFFER_ALLOCATE_SIZE - 512)
+#define MIN_TFTP_PKT_SIZE 512
+
+//
+// TFTPv4 OpCodes
+//
+#define TFTP_RRQ 1 // read request
+#define TFTP_WRQ 2 // write request
+#define TFTP_DATA 3 // data
+#define TFTP_ACK 4 // acknowledgement
+#define TFTP_ERROR 5 // error packet
+#define TFTP_OACK 6 // option acknowledge
+#define TFTP_DIR 7 // read directory request
+#define TFTP_DATA8 8
+#define TFTP_ACK8 9
+
+//
+// request packet (read or write)
+// Fields shown (except file name) are not to be referenced directly,
+// since their placement is variable within a request packet.
+// All are null terminated case insensitive ascii strings.
+//
+struct Tftpv4Req {
+ UINT16 OpCode; // TFTP Op code
+ UINT8 FileName[2]; // file name
+ UINT8 Mode[2]; // "netascii" or "octet"
+ struct { // optionally, one or more option requests
+ UINT8 Option[2]; // option name
+ UINT8 Value[2]; // value requested
+ } OpReq[1];
+};
+
+//
+// modes
+//
+#define MODE_ASCII "netascii"
+#define MODE_BINARY "octet"
+
+//
+// option strings
+//
+#define OP_BLKSIZE "blksize" // block size option
+#define OP_TIMEOUT "timeout" // time to wait before retransmitting
+#define OP_TFRSIZE "tsize" // total transfer size option
+#define OP_OVERWRITE "overwrite" // overwrite file option
+#define OP_BIGBLKNUM "bigblk#" // big block number
+// See RFC 2347, 8, and 9 for more information on TFTP options
+// option acknowledge packet (optional)
+// options not acknowledged are rejected
+//
+struct Tftpv4Oack {
+ UINT16 OpCode; // TFTP Op code
+ struct { // optionally, one or more option acknowledgements
+ UINT8 Option[2]; // option name (of those requested)
+ UINT8 Value[2]; // value acknowledged
+ } OpAck[1];
+};
+
+//
+// acknowledge packet
+//
+struct Tftpv4Ack {
+ UINT16 OpCode; // TFTP Op code
+ UINT16 BlockNum;
+};
+
+//
+// data packet
+//
+struct Tftpv4Data {
+ struct Tftpv4Ack Header;
+ UINT8 Data[512];
+};
+
+//
+// big block number ack packet
+//
+struct Tftpv4Ack8 {
+ UINT16 OpCode;
+ UINT64 BlockNum;
+};
+
+//
+// big block number data packet
+//
+struct Tftpv4Data8 {
+ struct Tftpv4Ack8 Header;
+ UINT8 Data[506];
+};
+
+//
+// error packet
+//
+struct Tftpv4Error {
+ UINT16 OpCode; // TFTP Op code
+ UINT16 ErrCode; // error code
+ UINT8 ErrMsg[1]; // error message (nul terminated)
+};
+
+#pragma pack()
+//
+// error codes
+//
+#define TFTP_ERR_UNDEF 0 // Not defined, see error message (if any).
+#define TFTP_ERR_NOT_FOUND 1 // File not found.
+#define TFTP_ERR_ACCESS 2 // Access violation.
+#define TFTP_ERR_FULL 3 // Disk full or allocation exceeded.
+#define TFTP_ERR_ILLEGAL 4 // Illegal TFTP operation.
+#define TFTP_ERR_BAD_ID 5 // Unknown transfer ID.
+#define TFTP_ERR_EXISTS 6 // File already exists.
+#define TFTP_ERR_NO_USER 7 // No such user.
+#define TFTP_ERR_OPTION 8 // Option negotiation termination
+//
+// some defines
+//
+#define REQ_RESP_TIMEOUT 5 // Wait five seconds for request response.
+#define ACK_TIMEOUT 4 // Wait four seconds for ack response.
+#define NUM_ACK_RETRIES 3
+#define NUM_MTFTP_OPEN_RETRIES 3
+
+#endif /* __TFTP_H__ */
+
+/* EOF - tftp.h */
--- /dev/null
+/** @file
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ PxeArch.h
+
+Abstract:
+ Defines PXE Arch type
+
+
+**/
+
+#ifndef _EFI_PXE_ARCH_H_
+#define _EFI_PXE_ARCH_H_
+
+#define SYS_ARCH 0x7
+
+#endif
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+ ComponentName.c\r
+\r
+Abstract:\r
+ PxeDhcp4 component name protocol declarations\r
+\r
+\r
+**/\r
+\r
+#include "PxeDhcp4.h"\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4ComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4ComponentNameGetControllerName (\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
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL gPxeDhcp4ComponentName = {\r
+ PxeDhcp4ComponentNameGetDriverName,\r
+ PxeDhcp4ComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mPxeDhcp4DriverNameTable[] = {\r
+ {\r
+ "eng",\r
+ L"PXE DHCPv4 Driver"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4ComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ Language - A pointer to a three character ISO 639-2 language identifier.\r
+ This is the language of the driver name that that the caller\r
+ is requesting, and it must match one of the languages specified\r
+ in SupportedLanguages. The number of languages supported by a\r
+ driver is up to the driver writer.\r
+ DriverName - A pointer to the Unicode string to return. This Unicode string\r
+ is the name of the driver specified by This in the language\r
+ specified by Language.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The Unicode string for the Driver specified by This\r
+ and the language specified by Language was returned\r
+ in DriverName.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - DriverName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gPxeDhcp4ComponentName.SupportedLanguages,\r
+ mPxeDhcp4DriverNameTable,\r
+ DriverName\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4ComponentNameGetControllerName (\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
+/* EOF - ComponentName.c */\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2005, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+ PxeDhcp4.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "PxeDhcp4.h"\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// Prototypes\r
+// Driver model protocol interface\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4DriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4DriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4DriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4DriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// PXE DHCP Protocol Interface\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gPxeDhcp4DriverBinding = {\r
+ PxeDhcp4DriverBindingSupported,\r
+ PxeDhcp4DriverBindingStart,\r
+ PxeDhcp4DriverBindingStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+//\r
+// PxeDhcp4 Driver Entry point funtion\r
+//\r
+\r
+/**\r
+ Register Driver Binding protocol for this driver.\r
+\r
+ @param entry EFI_IMAGE_ENTRY_POINT)\r
+\r
+ @retval EFI_SUCCESS Driver loaded.\r
+ @retval other Driver not loaded.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4DriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ return EfiLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gPxeDhcp4DriverBinding,\r
+ NULL,\r
+ COMPONENT_NAME,\r
+ NULL,\r
+ NULL\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle. Any\r
+ ControllerHandle that contains a PxeBaseCode protocol can be\r
+ supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
+ @retval other This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4DriverBindingSupported (\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
+ EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
+\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiPxeBaseCodeProtocolGuid,\r
+ (VOID **) &PxeBc,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test.\r
+ //\r
+ return gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiPxeBaseCodeProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+ Start this driver on ControllerHandle by opening a PxeBaseCode\r
+ protocol and installing a PxeDhcp4 protocol on ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to bind driver to.\r
+ @param RemainingDevicePath Not used, always produce all possible children.\r
+\r
+ @retval EFI_SUCCESS 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
+PxeDhcp4DriverBindingStart (\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
+ EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ PXE_DHCP4_PRIVATE_DATA *Private;\r
+\r
+ //\r
+ // Connect to the PxeBaseCode interface on ControllerHandle.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiPxeBaseCodeProtocolGuid,\r
+ (VOID **) &PxeBc,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // BaseCode has already grabbed the SimpleNetwork interface\r
+ // so just do a HandleProtocol() to get it.\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ ControllerHandle,\r
+ &gEfiSimpleNetworkProtocolGuid,\r
+ (VOID **) &Snp\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto error_exit;\r
+ }\r
+\r
+ ASSERT (Snp);\r
+\r
+ //\r
+ // Initialize the PXE DHCP device instance.\r
+ //\r
+ Private = AllocateZeroPool (sizeof (PXE_DHCP4_PRIVATE_DATA));\r
+ if (Private == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto error_exit;\r
+ }\r
+\r
+ Private->Signature = PXE_DHCP4_PRIVATE_DATA_SIGNATURE;\r
+ Private->PxeBc = PxeBc;\r
+ Private->Snp = Snp;\r
+ Private->Handle = ControllerHandle;\r
+ Private->PxeDhcp4.Revision = EFI_PXE_DHCP4_PROTOCOL_REVISION;\r
+ Private->PxeDhcp4.Run = PxeDhcp4Run;\r
+ Private->PxeDhcp4.Setup = PxeDhcp4Setup;\r
+ Private->PxeDhcp4.Init = PxeDhcp4Init;\r
+ Private->PxeDhcp4.Select = PxeDhcp4Select;\r
+ Private->PxeDhcp4.Renew = PxeDhcp4Renew;\r
+ Private->PxeDhcp4.Rebind = PxeDhcp4Rebind;\r
+ Private->PxeDhcp4.Release = PxeDhcp4Release;\r
+ Private->PxeDhcp4.Data = NULL;\r
+\r
+ //\r
+ // Install protocol interfaces for the PXE DHCP device.\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &ControllerHandle,\r
+ &gEfiPxeDhcp4ProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &Private->PxeDhcp4\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+error_exit: ;\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiPxeBaseCodeProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+ Stop this driver on ControllerHandle by removing PXE DHCP\r
+ protocol and closing the PXE Base Code protocol on\r
+ ControllerHandle.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param ControllerHandle Handle of device to stop driver on.\r
+ @param NumberOfChildren Not used.\r
+ @param ChildHandleBuffer Not used.\r
+\r
+ @retval EFI_SUCCESS This driver is removed ControllerHandle.\r
+ @retval other This driver was not removed from this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4DriverBindingStop (\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_PXE_DHCP4_PROTOCOL *PxeDhcp4;\r
+ PXE_DHCP4_PRIVATE_DATA *Private;\r
+\r
+ //\r
+ // Get our context back.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiPxeDhcp4ProtocolGuid,\r
+ (VOID **) &PxeDhcp4,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (PxeDhcp4);\r
+\r
+ //\r
+ // Release allocated resources\r
+ //\r
+ if (Private->PxeDhcp4.Data) {\r
+ FreePool (Private->PxeDhcp4.Data);\r
+ Private->PxeDhcp4.Data = NULL;\r
+ }\r
+ //\r
+ // Uninstall our protocol\r
+ //\r
+ Status = gBS->UninstallProtocolInterface (\r
+ ControllerHandle,\r
+ &gEfiPxeDhcp4ProtocolGuid,\r
+ &Private->PxeDhcp4\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Close any consumed protocols\r
+ //\r
+ Status = gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiPxeBaseCodeProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Release our private data\r
+ //\r
+ FreePool (Private);\r
+\r
+ return Status;\r
+}\r
+\r
+/* EOF - PxeDhcp4.c */\r
--- /dev/null
+/** @file
+
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ PxeDhcp4.h
+
+Abstract:
+ Common header for PxeDhcp4 protocol driver
+
+
+**/
+#ifndef _PXEDHCP4_H
+#define _PXEDHCP4_H
+
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/PxeBaseCode.h>\r
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/PxeDhcp4.h>
+#include <Protocol/PxeDhcp4Callback.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// PxeDhcp4 protocol instance data
+//
+typedef struct {
+ //
+ // Signature field used to locate beginning of containment record.
+ //
+ UINTN Signature;
+
+#define PXE_DHCP4_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('p', 'x', 'D', '4')
+ //
+ // Device handle the protocol is bound to.
+ //
+ EFI_HANDLE Handle;
+
+ //
+ // Public PxeDhcp4 protocol interface.
+ //
+ EFI_PXE_DHCP4_PROTOCOL PxeDhcp4;
+
+ //
+ // Consumed PxeBc, Snp and PxeDhcp4Callback protocol interfaces.
+ //
+ EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ EFI_PXE_DHCP4_CALLBACK_PROTOCOL *callback;
+
+ //
+ // PxeDhcp4 called function for PxeDhcp4Callback.
+ //
+ EFI_PXE_DHCP4_FUNCTION function;
+
+ //
+ // Timeout event and flag for PxeDhcp4Callback.
+ //
+ EFI_EVENT TimeoutEvent;
+ BOOLEAN TimeoutOccurred;
+
+ //
+ // Periodic event and flag for PxeDhcp4Callback.
+ //
+ EFI_EVENT PeriodicEvent;
+ BOOLEAN PeriodicOccurred;
+
+ //
+ // DHCP server IP address.
+ //
+ UINT32 ServerIp;
+
+ //
+ // DHCP renewal and rebinding times, in seconds.
+ //
+ UINT32 RenewTime;
+ UINT32 RebindTime;
+ UINT32 LeaseTime;
+
+ //
+ // Number of offers received & allocated offer list.
+ //
+ UINTN offers;
+ DHCP4_PACKET *offer_list;
+
+ //
+ //
+ //
+ BOOLEAN StopPxeBc;
+
+} PXE_DHCP4_PRIVATE_DATA;
+
+#define PXE_DHCP4_PRIVATE_DATA_FROM_THIS(a) CR (a, PXE_DHCP4_PRIVATE_DATA, PxeDhcp4, PXE_DHCP4_PRIVATE_DATA_SIGNATURE)
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// Protocol function prototypes.
+//
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Run (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN OPTIONAL UINTN OpLen,
+ IN OPTIONAL VOID *OpList
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Setup (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN EFI_PXE_DHCP4_DATA *Data
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Init (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN UINTN seconds_timeout,
+ OUT UINTN *offer_list_entries,
+ OUT DHCP4_PACKET **offer_list
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Select (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ IN UINTN seconds_timeout,
+ IN DHCP4_PACKET *offer_list
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Renew (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ UINTN seconds_timeout
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Rebind (
+ IN EFI_PXE_DHCP4_PROTOCOL *This,
+ UINTN seconds_timeout
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+PxeDhcp4Release (
+ IN EFI_PXE_DHCP4_PROTOCOL *This
+ )
+;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// Support function prototypes.
+//
+extern
+UINT16
+htons (
+ UINTN n
+ )
+;
+
+extern
+UINT32
+htonl (
+ UINTN n
+ )
+;
+
+extern
+VOID
+EFIAPI
+timeout_notify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+;
+
+extern
+VOID
+EFIAPI
+periodic_notify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+;
+
+extern
+EFI_STATUS
+find_opt (
+ IN DHCP4_PACKET *Packet,
+ IN UINT8 OpCode,
+ IN UINTN Skip,
+ OUT DHCP4_OP **OpPtr
+ )
+;
+
+extern
+EFI_STATUS
+add_opt (
+ IN DHCP4_PACKET *Packet,
+ IN DHCP4_OP *OpPtr
+ )
+;
+
+extern
+EFI_STATUS
+start_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN OPTIONAL EFI_IP_ADDRESS *station_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *subnet_mask
+ )
+;
+
+extern
+VOID
+stop_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private
+ )
+;
+
+extern
+EFI_STATUS
+start_receive_events (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN UINTN seconds_timeout
+ )
+;
+
+extern
+VOID
+stop_receive_events (
+ IN PXE_DHCP4_PRIVATE_DATA *Private
+ )
+;
+
+extern
+EFI_STATUS
+tx_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN EFI_IP_ADDRESS *dest_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,
+ IN EFI_IP_ADDRESS *src_ip,
+ IN VOID *buffer,
+ IN UINTN BufferSize
+ )
+;
+
+extern
+EFI_STATUS
+rx_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ OUT VOID *buffer,
+ OUT UINTN *BufferSize,
+ IN OUT EFI_IP_ADDRESS *dest_ip,
+ IN OUT EFI_IP_ADDRESS *src_ip,
+ IN UINT16 op_flags
+ )
+;
+
+extern
+EFI_STATUS
+tx_rx_udp (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN OUT EFI_IP_ADDRESS *ServerIp,
+ IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *client_ip,
+ IN OPTIONAL EFI_IP_ADDRESS *subnet_mask,
+ IN DHCP4_PACKET *tx_pkt,
+ OUT DHCP4_PACKET *rx_pkt,
+ IN INTN
+ (
+ *rx_vfy)
+ (
+ IN PXE_DHCP4_PRIVATE_DATA *Private,
+ IN DHCP4_PACKET *tx_pkt,
+ IN DHCP4_PACKET *rx_pkt,
+ IN UINTN rx_pkt_size
+ ),
+ IN UINTN seconds_timeout
+ )
+;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//
+// Global variable definitions.
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gPxeDhcp4ComponentName;
+
+EFI_STATUS
+EFIAPI
+PxeDhcp4DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+ Register Driver Binding protocol for this driver.
+
+Arguments:
+ (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
+
+Returns:
+ EFI_SUCCESS - Driver loaded.
+ other - Driver not loaded.
+
+--*/
+;
+
+#ifdef EFI_SIZE_REDUCTION_APPLIED
+ #define COMPONENT_NAME_CODE(code)
+ #define COMPONENT_NAME NULL
+#else
+ #define COMPONENT_NAME_CODE(code) code
+ #define COMPONENT_NAME &gPxeDhcp4ComponentName
+#endif
+
+#endif /* _PXEDHCP4_H */
+
+/* EOF - PxeDhcp4.h */
--- /dev/null
+#/** @file\r
+# Component name for module PxeDhcp4\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 = PxeDhcp4Dxe\r
+ FILE_GUID = a46c3330-be36-4977-9d24-a7cf92eef0fe\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ EDK_RELEASE_VERSION = 0x00020000\r
+ EFI_SPECIFICATION_VERSION = 0x00020000\r
+\r
+ ENTRY_POINT = PxeDhcp4DriverEntryPoint\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
+ support.c\r
+ PxeDhcp4Release.c\r
+ PxeDhcp4Setup.c\r
+ ComponentName.c\r
+ PxeDhcp4RenewRebind.c\r
+ PxeDhcp4.h\r
+ PxeDhcp4.c\r
+ PxeDhcp4InitSelect.c\r
+ PxeDhcp4Run.c\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ UefiLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ BaseMemoryLib\r
+ DebugLib\r
+\r
+\r
+[Protocols]\r
+ gEfiPxeBaseCodeProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiPxeDhcp4CallbackProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiPxeDhcp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+\r
--- /dev/null
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+ <MsaHeader>\r
+ <ModuleName>PxeDhcp4</ModuleName>\r
+ <ModuleType>DXE_DRIVER</ModuleType>\r
+ <GuidValue>a46c3330-be36-4977-9d24-a7cf92eef0fe</GuidValue>\r
+ <Version>1.0</Version>\r
+ <Abstract>Component name for module PxeDhcp4</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>PxeDhcp4</OutputFileBasename>\r
+ </ModuleDefinitions>\r
+ <LibraryClassDefinitions>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>DebugLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>BaseMemoryLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiDriverEntryPoint</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiBootServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiLib</Keyword>\r
+ </LibraryClass>\r
+ </LibraryClassDefinitions>\r
+ <SourceFiles>\r
+ <Filename>PxeDhcp4Run.c</Filename>\r
+ <Filename>PxeDhcp4InitSelect.c</Filename>\r
+ <Filename>PxeDhcp4Entry.c</Filename>\r
+ <Filename>PxeDhcp4.c</Filename>\r
+ <Filename>PxeDhcp4.h</Filename>\r
+ <Filename>PxeDhcp4RenewRebind.c</Filename>\r
+ <Filename>ComponentName.c</Filename>\r
+ <Filename>PxeDhcp4Setup.c</Filename>\r
+ <Filename>PxeDhcp4Release.c</Filename>\r
+ <Filename>support.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>gEfiPxeDhcp4ProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiPxeDhcp4CallbackProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiPxeBaseCodeProtocolGuid</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>PxeDhcp4DriverEntryPoint</ModuleEntryPoint>\r
+ </Extern>\r
+ </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
--- /dev/null
+/** @file\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
+ PxeDhcp4InitSelect.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "PxeDhcp4.h"\r
+\r
+#define DebugPrint(x)\r
+//\r
+// #define DebugPrint(x) Aprint x\r
+//\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+**/\r
+STATIC\r
+INTN\r
+offer_verify (\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private,\r
+ IN DHCP4_PACKET *tx_pkt,\r
+ IN DHCP4_PACKET *rx_pkt,\r
+ IN UINTN rx_pkt_size\r
+ )\r
+{\r
+ EFI_STATUS EfiStatus;\r
+ DHCP4_PACKET *tmp;\r
+ DHCP4_OP *msg_type_op;\r
+ DHCP4_OP *srvid_op;\r
+ UINT32 magik;\r
+\r
+ //\r
+ // Verify parameters. Touch unused parameters to keep\r
+ // compiler happy.\r
+ //\r
+ ASSERT (Private);\r
+ ASSERT (rx_pkt);\r
+\r
+ if (Private == NULL || rx_pkt == NULL) {\r
+ return -2;\r
+ }\r
+\r
+ tx_pkt = tx_pkt;\r
+ rx_pkt_size = rx_pkt_size;\r
+\r
+ //\r
+ // This may be a BOOTP Reply or DHCP Offer packet.\r
+ // If there is no DHCP magik number, assume that\r
+ // this is a BOOTP Reply packet.\r
+ //\r
+ magik = htonl (DHCP4_MAGIK_NUMBER);\r
+\r
+ while (!CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {\r
+ //\r
+ // If there is no DHCP message type option, assume\r
+ // this is a BOOTP reply packet and cache it.\r
+ //\r
+ EfiStatus = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ break;\r
+ }\r
+ //\r
+ // If there is a DHCP message type option, it must be a\r
+ // DHCP offer packet\r
+ //\r
+ if (msg_type_op->len != 1) {\r
+ return -1;\r
+ }\r
+\r
+ if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) {\r
+ return -1;\r
+ }\r
+ //\r
+ // There must be a server identifier option.\r
+ //\r
+ EfiStatus = find_opt (\r
+ rx_pkt,\r
+ DHCP4_SERVER_IDENTIFIER,\r
+ 0,\r
+ &srvid_op\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ return -1;\r
+ }\r
+\r
+ if (srvid_op->len != 4) {\r
+ return -1;\r
+ }\r
+ //\r
+ // Good DHCP offer packet.\r
+ //\r
+ break;\r
+ }\r
+ //\r
+ // Good DHCP (or BOOTP) packet. Cache it!\r
+ //\r
+ EfiStatus = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ (Private->offers + 1) * sizeof (DHCP4_PACKET),\r
+ (VOID **) &tmp\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ return -2;\r
+ }\r
+\r
+ ASSERT (tmp);\r
+\r
+ if (Private->offers != 0) {\r
+ CopyMem (\r
+ tmp,\r
+ Private->offer_list,\r
+ Private->offers * sizeof (DHCP4_PACKET)\r
+ );\r
+\r
+ gBS->FreePool (Private->offer_list);\r
+ }\r
+\r
+ CopyMem (&tmp[Private->offers++], rx_pkt, sizeof (DHCP4_PACKET));\r
+\r
+ Private->offer_list = tmp;\r
+\r
+ return 0;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+**/\r
+STATIC\r
+INTN\r
+acknak_verify (\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private,\r
+ IN DHCP4_PACKET *tx_pkt,\r
+ IN DHCP4_PACKET *rx_pkt,\r
+ IN UINTN rx_pkt_size\r
+ )\r
+{\r
+ EFI_STATUS EfiStatus;\r
+ DHCP4_OP *msg_type_op;\r
+ DHCP4_OP *srvid_op;\r
+ DHCP4_OP *renew_op;\r
+ DHCP4_OP *rebind_op;\r
+ DHCP4_OP *lease_time_op;\r
+ UINT32 magik;\r
+\r
+ //\r
+ // Verify parameters. Touch unused parameters to\r
+ // keep compiler happy.\r
+ //\r
+ ASSERT (Private);\r
+ ASSERT (rx_pkt);\r
+\r
+ if (Private == NULL || rx_pkt == NULL) {\r
+ return -2;\r
+ }\r
+\r
+ tx_pkt = tx_pkt;\r
+ rx_pkt_size = rx_pkt_size;\r
+\r
+ //\r
+ // This must be a DHCP Ack message.\r
+ //\r
+ magik = htonl (DHCP4_MAGIK_NUMBER);\r
+\r
+ if (CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {\r
+ return -1;\r
+ }\r
+\r
+ EfiStatus = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ return -1;\r
+ }\r
+\r
+ if (msg_type_op->len != 1) {\r
+ return -1;\r
+ }\r
+\r
+ if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_ACK) {\r
+ return -1;\r
+ }\r
+ //\r
+ // There must be a server identifier.\r
+ //\r
+ EfiStatus = find_opt (rx_pkt, DHCP4_SERVER_IDENTIFIER, 0, &srvid_op);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ return -1;\r
+ }\r
+\r
+ if (srvid_op->len != 4) {\r
+ return -1;\r
+ }\r
+ //\r
+ // There should be a renewal time.\r
+ // If there is not, we will default to the 7/8 of the rebinding time.\r
+ //\r
+ EfiStatus = find_opt (rx_pkt, DHCP4_RENEWAL_TIME, 0, &renew_op);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ renew_op = NULL;\r
+ } else if (renew_op->len != 4) {\r
+ renew_op = NULL;\r
+ }\r
+ //\r
+ // There should be a rebinding time.\r
+ // If there is not, we will default to 7/8 of the lease time.\r
+ //\r
+ EfiStatus = find_opt (rx_pkt, DHCP4_REBINDING_TIME, 0, &rebind_op);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ rebind_op = NULL;\r
+ } else if (rebind_op->len != 4) {\r
+ rebind_op = NULL;\r
+ }\r
+ //\r
+ // There should be a lease time.\r
+ // If there is not, we will default to one week.\r
+ //\r
+ EfiStatus = find_opt (rx_pkt, DHCP4_LEASE_TIME, 0, &lease_time_op);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ lease_time_op = NULL;\r
+ } else if (lease_time_op->len != 4) {\r
+ lease_time_op = NULL;\r
+ }\r
+ //\r
+ // Packet looks good. Double check the renew, rebind and lease times.\r
+ //\r
+ CopyMem (&Private->ServerIp, srvid_op->data, 4);\r
+\r
+ if (renew_op != NULL) {\r
+ CopyMem (&Private->RenewTime, renew_op->data, 4);\r
+ Private->RenewTime = htonl (Private->RenewTime);\r
+ } else {\r
+ Private->RenewTime = 0;\r
+ }\r
+\r
+ if (rebind_op != NULL) {\r
+ CopyMem (&Private->RebindTime, rebind_op->data, 4);\r
+ Private->RebindTime = htonl (Private->RebindTime);\r
+ } else {\r
+ Private->RebindTime = 0;\r
+ }\r
+\r
+ if (lease_time_op != NULL) {\r
+ CopyMem (&Private->LeaseTime, lease_time_op->data, 4);\r
+ Private->LeaseTime = htonl (Private->LeaseTime);\r
+ } else {\r
+ Private->LeaseTime = 0;\r
+ }\r
+\r
+ if (Private->LeaseTime < 60) {\r
+ Private->LeaseTime = 7 * 86400;\r
+ }\r
+\r
+ if (Private->RebindTime < 52 || Private->RebindTime >= Private->LeaseTime) {\r
+ Private->RebindTime = Private->LeaseTime / 2 + Private->LeaseTime / 4 + Private->LeaseTime / 8;\r
+ }\r
+\r
+ if (Private->RenewTime < 45 || Private->RenewTime >= Private->RebindTime) {\r
+ Private->RenewTime = Private->RebindTime / 2 + Private->RebindTime / 4 + Private->RebindTime / 8;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4Init (\r
+ IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+ IN UINTN seconds_timeout,\r
+ OUT UINTN *Offers,\r
+ OUT DHCP4_PACKET **OfferList\r
+ )\r
+{\r
+ PXE_DHCP4_PRIVATE_DATA *Private;\r
+ DHCP4_PACKET offer;\r
+ EFI_IP_ADDRESS bcast_ip;\r
+ EFI_STATUS EfiStatus;\r
+\r
+ //\r
+ // Verify parameters and protocol state.\r
+ //\r
+ if (This == NULL ||\r
+ seconds_timeout < DHCP4_MIN_SECONDS ||\r
+ seconds_timeout > DHCP4_MAX_SECONDS ||\r
+ Offers == NULL ||\r
+ OfferList == NULL\r
+ ) {\r
+ //\r
+ // Return parameters are not initialized when\r
+ // parameters are invalid!\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Offers = 0;\r
+ *OfferList = NULL;\r
+\r
+ //\r
+ // Check protocol state.\r
+ //\r
+ if (This->Data == NULL) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ if (!This->Data->SetupCompleted) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+#if 0\r
+ if (!is_good_discover (&This->Data->Discover)) {\r
+ //\r
+ // %%TBD - check discover packet fields\r
+ //\r
+ }\r
+#endif\r
+ //\r
+ // Get pointer to our instance data.\r
+ //\r
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Private == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Private->PxeBc == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Setup variables...\r
+ //\r
+ Private->offers = 0;\r
+ Private->offer_list = NULL;\r
+\r
+ EfiStatus = gBS->HandleProtocol (\r
+ Private->Handle,\r
+ &gEfiPxeDhcp4CallbackProtocolGuid,\r
+ (VOID *) &Private->callback\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ Private->callback = NULL;\r
+ }\r
+\r
+ Private->function = EFI_PXE_DHCP4_FUNCTION_INIT;\r
+\r
+ //\r
+ // Increment the transaction ID.\r
+ //\r
+ {\r
+ UINT32 xid;\r
+\r
+ CopyMem (&xid, &This->Data->Discover.dhcp4.xid, sizeof (UINT32));\r
+\r
+ xid = htonl (htonl (xid) + 1);\r
+\r
+ CopyMem (&This->Data->Discover.dhcp4.xid, &xid, sizeof (UINT32));\r
+ }\r
+ //\r
+ // Transmit discover and wait for offers...\r
+ //\r
+ SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);\r
+\r
+ EfiStatus = tx_rx_udp (\r
+ Private,\r
+ &bcast_ip,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ &This->Data->Discover,\r
+ &offer,\r
+ &offer_verify,\r
+ seconds_timeout\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ if (Private->offer_list) {\r
+ gBS->FreePool (Private->offer_list);\r
+ }\r
+\r
+ Private->offers = 0;\r
+ Private->offer_list = NULL;\r
+ Private->callback = NULL;\r
+\r
+ DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));\r
+ return EfiStatus;\r
+ }\r
+\r
+ *Offers = Private->offers;\r
+ *OfferList = Private->offer_list;\r
+\r
+ Private->offers = 0;\r
+ Private->offer_list = NULL;\r
+ Private->callback = NULL;\r
+\r
+ This->Data->InitCompleted = TRUE;\r
+ This->Data->SelectCompleted = FALSE;\r
+ This->Data->IsBootp = FALSE;\r
+ This->Data->IsAck = FALSE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4Select (\r
+ IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+ IN UINTN seconds_timeout,\r
+ IN DHCP4_PACKET *Offer\r
+ )\r
+{\r
+ PXE_DHCP4_PRIVATE_DATA *Private;\r
+ EFI_STATUS EfiStatus;\r
+ DHCP4_PACKET request;\r
+ DHCP4_PACKET acknak;\r
+ EFI_IP_ADDRESS bcast_ip;\r
+ EFI_IP_ADDRESS zero_ip;\r
+ EFI_IP_ADDRESS local_ip;\r
+ DHCP4_OP *srvid;\r
+ DHCP4_OP *op;\r
+ UINT32 dhcp4_magik;\r
+ UINT8 buf[16];\r
+ BOOLEAN is_bootp;\r
+\r
+ //\r
+ // Verify parameters.\r
+ //\r
+ if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS || Offer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Check protocol state.\r
+ //\r
+ if (This->Data == NULL) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ if (!This->Data->SetupCompleted) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ //\r
+ // Get pointer to instance data.\r
+ //\r
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Private == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Private->PxeBc == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+#if 0\r
+ if (!is_good_discover (&This->Data->Discover)) {\r
+ //\r
+ // %%TBD - check discover packet fields\r
+ //\r
+ }\r
+#endif\r
+ //\r
+ // Setup useful variables...\r
+ //\r
+ SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);\r
+\r
+ ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));\r
+\r
+ ZeroMem (&local_ip, sizeof (EFI_IP_ADDRESS));\r
+ local_ip.v4.Addr[0] = 127;\r
+ local_ip.v4.Addr[3] = 1;\r
+\r
+ This->Data->SelectCompleted = FALSE;\r
+ This->Data->IsBootp = FALSE;\r
+ This->Data->IsAck = FALSE;\r
+\r
+ EfiStatus = gBS->HandleProtocol (\r
+ Private->Handle,\r
+ &gEfiPxeDhcp4CallbackProtocolGuid,\r
+ (VOID *) &Private->callback\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ Private->callback = NULL;\r
+ }\r
+\r
+ Private->function = EFI_PXE_DHCP4_FUNCTION_SELECT;\r
+\r
+ //\r
+ // Verify offer packet fields.\r
+ //\r
+ if (Offer->dhcp4.op != BOOTP_REPLY) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Offer->dhcp4.htype != This->Data->Discover.dhcp4.htype) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Offer->dhcp4.hlen != This->Data->Discover.dhcp4.hlen) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (CompareMem (&Offer->dhcp4.xid, &This->Data->Discover.dhcp4.xid, 4)) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!CompareMem (&Offer->dhcp4.yiaddr, &bcast_ip, 4)) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!CompareMem (&Offer->dhcp4.yiaddr, &zero_ip, 4)) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!CompareMem (&Offer->dhcp4.yiaddr, &local_ip, 4)) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (CompareMem (\r
+ &Offer->dhcp4.chaddr,\r
+ &This->Data->Discover.dhcp4.chaddr,\r
+ 16\r
+ )) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // DHCP option checks\r
+ //\r
+ dhcp4_magik = htonl (DHCP4_MAGIK_NUMBER);\r
+ is_bootp = TRUE;\r
+\r
+ if (!CompareMem (&Offer->dhcp4.magik, &dhcp4_magik, 4)) {\r
+ //\r
+ // If present, DHCP message type must be offer.\r
+ //\r
+ EfiStatus = find_opt (Offer, DHCP4_MESSAGE_TYPE, 0, &op);\r
+\r
+ if (!EFI_ERROR (EfiStatus)) {\r
+ if (op->len != 1 || op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ is_bootp = FALSE;\r
+ }\r
+ //\r
+ // If present, DHCP max message size must be valid.\r
+ //\r
+ EfiStatus = find_opt (Offer, DHCP4_MAX_MESSAGE_SIZE, 0, &op);\r
+\r
+ if (!EFI_ERROR (EfiStatus)) {\r
+ if (op->len != 2 || ((op->data[0] << 8) | op->data[1]) < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // If present, DHCP server identifier must be valid.\r
+ //\r
+ EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &op);\r
+\r
+ if (!EFI_ERROR (EfiStatus)) {\r
+ if (op->len != 4 || !CompareMem (op->data, &bcast_ip, 4) || !CompareMem (op->data, &zero_ip, 4)) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // If present, DHCP subnet mask must be valid.\r
+ //\r
+ EfiStatus = find_opt (\r
+ Offer,\r
+ DHCP4_SUBNET_MASK,\r
+ 0,\r
+ &op\r
+ );\r
+\r
+ if (!EFI_ERROR (EfiStatus)) {\r
+ if (op->len != 4) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Early out for BOOTP.\r
+ //\r
+ This->Data->IsBootp = is_bootp;\r
+ if (is_bootp) {\r
+ //\r
+ // Copy offer packet to instance data.\r
+ //\r
+ CopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET));\r
+\r
+ //\r
+ // Copy discover to request and offer to acknak.\r
+ //\r
+ CopyMem (\r
+ &This->Data->Request,\r
+ &This->Data->Discover,\r
+ sizeof (DHCP4_PACKET)\r
+ );\r
+\r
+ CopyMem (\r
+ &This->Data->AckNak,\r
+ &This->Data->Offer,\r
+ sizeof (DHCP4_PACKET)\r
+ );\r
+\r
+ //\r
+ // Set state flags.\r
+ //\r
+ This->Data->SelectCompleted = TRUE;\r
+ This->Data->IsAck = TRUE;\r
+\r
+ Private->callback = NULL;\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Copy discover packet contents to request packet.\r
+ //\r
+ CopyMem (&request, &This->Data->Discover, sizeof (DHCP4_PACKET));\r
+\r
+ This->Data->IsAck = FALSE;\r
+\r
+ //\r
+ // Change DHCP message type from discover to request.\r
+ //\r
+ EfiStatus = find_opt (&request, DHCP4_MESSAGE_TYPE, 0, &op);\r
+\r
+ if (EFI_ERROR (EfiStatus) && EfiStatus != EFI_NOT_FOUND) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (EfiStatus == EFI_NOT_FOUND) {\r
+ EfiStatus = find_opt (&request, DHCP4_END, 0, &op);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ op->op = DHCP4_MESSAGE_TYPE;\r
+ op->len = 1;\r
+\r
+ op->data[1] = DHCP4_END;\r
+ }\r
+\r
+ op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST;\r
+\r
+ //\r
+ // Copy server identifier option from offer to request.\r
+ //\r
+ EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &srvid);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (srvid->len != 4) {\r
+ Private->callback = NULL;\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EfiStatus = add_opt (&request, srvid);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));\r
+ Private->callback = NULL;\r
+ return EfiStatus;\r
+ }\r
+ //\r
+ // Add requested IP address option to request packet.\r
+ //\r
+ op = (DHCP4_OP *) buf;\r
+ op->op = DHCP4_REQUESTED_IP_ADDRESS;\r
+ op->len = 4;\r
+ CopyMem (op->data, &Offer->dhcp4.yiaddr, 4);\r
+\r
+ EfiStatus = add_opt (&request, op);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));\r
+ Private->callback = NULL;\r
+ return EfiStatus;\r
+ }\r
+ //\r
+ // Transimit DHCP request and wait for DHCP ack...\r
+ //\r
+ SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);\r
+\r
+ EfiStatus = tx_rx_udp (\r
+ Private,\r
+ &bcast_ip,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ &request,\r
+ &acknak,\r
+ &acknak_verify,\r
+ seconds_timeout\r
+ );\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));\r
+ Private->callback = NULL;\r
+ return EfiStatus;\r
+ }\r
+ //\r
+ // Set Data->IsAck and return.\r
+ //\r
+ EfiStatus = find_opt (&acknak, DHCP4_MESSAGE_TYPE, 0, &op);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ Private->callback = NULL;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (op->len != 1) {\r
+ Private->callback = NULL;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ switch (op->data[0]) {\r
+ case DHCP4_MESSAGE_TYPE_ACK:\r
+ This->Data->IsAck = TRUE;\r
+ break;\r
+\r
+ case DHCP4_MESSAGE_TYPE_NAK:\r
+ This->Data->IsAck = FALSE;\r
+ break;\r
+\r
+ default:\r
+ Private->callback = NULL;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Copy packets into instance data...\r
+ //\r
+ CopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET));\r
+ CopyMem (&This->Data->Request, &request, sizeof (DHCP4_PACKET));\r
+ CopyMem (&This->Data->AckNak, &acknak, sizeof (DHCP4_PACKET));\r
+\r
+ This->Data->SelectCompleted = TRUE;\r
+\r
+ Private->callback = NULL;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* eof - PxeDhcp4InitSelect.c */\r
--- /dev/null
+/** @file\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
+ PxeDhcp4Release.c\r
+\r
+Abstract:\r
+ Transmit release packet, free allocations and shutdown PxeDhcp4.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "PxeDhcp4.h"\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4Release (\r
+ IN EFI_PXE_DHCP4_PROTOCOL *This\r
+ )\r
+{\r
+ PXE_DHCP4_PRIVATE_DATA *Private;\r
+ EFI_IP_ADDRESS ServerIp;\r
+ EFI_IP_ADDRESS client_ip;\r
+ EFI_IP_ADDRESS gateway_ip;\r
+ EFI_IP_ADDRESS subnet_mask;\r
+ EFI_STATUS efi_status;\r
+ DHCP4_OP *op;\r
+ UINT8 op_list[20];\r
+\r
+ //\r
+ // Check for invalid parameters.\r
+ //\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Release does nothing if the protocol has never been setup.\r
+ //\r
+ if (This->Data == NULL) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+ //\r
+ // Fail if we do not have valid instance data.\r
+ //\r
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Private == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Private->PxeBc == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // If this is a BOOTP session and there is not a DHCP Ack\r
+ // packet, just release storage and return.\r
+ //\r
+ if (This->Data->IsBootp || !This->Data->IsAck) {\r
+ gBS->FreePool (This->Data);\r
+ This->Data = NULL;\r
+\r
+ if (Private->StopPxeBc) {\r
+ Private->PxeBc->Stop (Private->PxeBc);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Build option list for DHCP Release packet.\r
+ // If any errors occur, just release storage and return.\r
+ //\r
+ //\r
+ // Message type is first.\r
+ //\r
+ op_list[0] = DHCP4_MESSAGE_TYPE;\r
+ op_list[1] = 1;\r
+ op_list[2] = DHCP4_MESSAGE_TYPE_RELEASE;\r
+\r
+ //\r
+ // Followed by server identifier.\r
+ //\r
+ efi_status = find_opt (\r
+ &This->Data->Request,\r
+ DHCP4_SERVER_IDENTIFIER,\r
+ 0,\r
+ &op\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ gBS->FreePool (This->Data);\r
+ This->Data = NULL;\r
+\r
+ if (Private->StopPxeBc) {\r
+ Private->PxeBc->Stop (Private->PxeBc);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (op->len != 4) {\r
+ gBS->FreePool (This->Data);\r
+ This->Data = NULL;\r
+\r
+ if (Private->StopPxeBc) {\r
+ Private->PxeBc->Stop (Private->PxeBc);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ CopyMem (&ServerIp, op->data, 4);\r
+\r
+ op_list[3] = DHCP4_SERVER_IDENTIFIER;\r
+ op_list[4] = 4;\r
+ CopyMem (&op_list[5], &ServerIp, 4);\r
+\r
+ //\r
+ // Followed by end.\r
+ //\r
+ op_list[9] = DHCP4_END;\r
+\r
+ //\r
+ // We need a subnet mask for IP stack operation.\r
+ //\r
+ efi_status = find_opt (\r
+ &This->Data->AckNak,\r
+ DHCP4_SUBNET_MASK,\r
+ 0,\r
+ &op\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ gBS->FreePool (This->Data);\r
+ This->Data = NULL;\r
+\r
+ if (Private->StopPxeBc) {\r
+ Private->PxeBc->Stop (Private->PxeBc);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (op->len != 4) {\r
+ gBS->FreePool (This->Data);\r
+ This->Data = NULL;\r
+\r
+ if (Private->StopPxeBc) {\r
+ Private->PxeBc->Stop (Private->PxeBc);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS));\r
+ CopyMem (&subnet_mask, op->data, 4);\r
+\r
+ //\r
+ // Gateway IP address may be needed.\r
+ //\r
+ ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS));\r
+ CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4);\r
+\r
+ //\r
+ // Client IP address needed for IP stack operation.\r
+ //\r
+ ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS));\r
+ CopyMem (&client_ip, &This->Data->AckNak.dhcp4.yiaddr, 4);\r
+\r
+ //\r
+ // Enable UDP...\r
+ //\r
+ efi_status = start_udp (Private, &client_ip, &subnet_mask);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ gBS->FreePool (This->Data);\r
+ This->Data = NULL;\r
+\r
+ if (Private->StopPxeBc) {\r
+ Private->PxeBc->Stop (Private->PxeBc);\r
+ }\r
+\r
+ return efi_status;\r
+ }\r
+ //\r
+ // Gather information out of DHCP request packet needed for\r
+ // DHCP release packet.\r
+ //\r
+ //\r
+ // Setup DHCP Release packet.\r
+ //\r
+ CopyMem (&This->Data->Request.dhcp4.ciaddr, &client_ip, 4);\r
+\r
+ ZeroMem (&This->Data->Request.dhcp4.yiaddr, 12);\r
+\r
+ ZeroMem (&This->Data->Request.dhcp4.sname, 64 + 128);\r
+\r
+ This->Data->Request.dhcp4.hops = 0;\r
+ This->Data->Request.dhcp4.secs = 0;\r
+ This->Data->Request.dhcp4.flags = 0;\r
+\r
+ ZeroMem (\r
+ &This->Data->Request.dhcp4.options,\r
+ sizeof This->Data->Request.dhcp4.options\r
+ );\r
+\r
+ CopyMem (&This->Data->Request.dhcp4.options, op_list, 10);\r
+\r
+ //\r
+ // Transmit DHCP Release packet.\r
+ //\r
+ tx_udp (\r
+ Private,\r
+ &ServerIp,\r
+ &gateway_ip,\r
+ &client_ip,\r
+ &This->Data->Request,\r
+ DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE)\r
+ );\r
+\r
+ gBS->Stall (1000000); /* 1/10th second */\r
+\r
+ //\r
+ // Shutdown PXE BaseCode and release local storage.\r
+ //\r
+ stop_udp (Private);\r
+\r
+ gBS->FreePool (This->Data);\r
+ This->Data = NULL;\r
+\r
+ if (Private->StopPxeBc) {\r
+ Private->PxeBc->Stop (Private->PxeBc);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* eof - PxeDhcp4Release.c */\r
--- /dev/null
+/** @file\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
+ PxeDhcp4RenewRebind.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+\r
+#include "PxeDhcp4.h"\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+ Parameters:\r
+\r
+ @return -2 = ignore, stop waiting\r
+ @return -1 = ignore, keep waiting\r
+ @return 0 = accept, keep waiting\r
+ @return 1 = accept, stop waiting\r
+\r
+**/\r
+STATIC\r
+INTN\r
+acknak_verify (\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private,\r
+ IN DHCP4_PACKET *tx_pkt,\r
+ IN DHCP4_PACKET *rx_pkt,\r
+ IN UINTN rx_pkt_size\r
+ )\r
+{\r
+ EFI_STATUS efi_status;\r
+ DHCP4_OP *msg_type_op;\r
+ DHCP4_OP *srvid_op;\r
+ DHCP4_OP *renew_op;\r
+ DHCP4_OP *rebind_op;\r
+ DHCP4_OP *lease_time_op;\r
+ UINT32 magik;\r
+\r
+ //\r
+ // Verify parameters. Unused parameters are also touched\r
+ // to make the compiler happy.\r
+ //\r
+ ASSERT (Private);\r
+ ASSERT (rx_pkt);\r
+\r
+ if (Private == NULL || rx_pkt == NULL) {\r
+ return -2;\r
+ }\r
+\r
+ tx_pkt = tx_pkt;\r
+ rx_pkt_size = rx_pkt_size;\r
+\r
+ //\r
+ // This must be a DHCP Ack message.\r
+ //\r
+ magik = htonl (DHCP4_MAGIK_NUMBER);\r
+\r
+ if (CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {\r
+ return -1;\r
+ }\r
+\r
+ efi_status = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ return -1;\r
+ }\r
+\r
+ if (msg_type_op->len != 1) {\r
+ return -1;\r
+ }\r
+\r
+ if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_ACK) {\r
+ return -1;\r
+ }\r
+ //\r
+ // There must be a server identifier.\r
+ //\r
+ efi_status = find_opt (rx_pkt, DHCP4_SERVER_IDENTIFIER, 0, &srvid_op);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ return -1;\r
+ }\r
+\r
+ if (srvid_op->len != 4) {\r
+ return -1;\r
+ }\r
+ //\r
+ // There should be a renewal time.\r
+ // If there is not, we will default to the 7/8 of the rebinding time.\r
+ //\r
+ efi_status = find_opt (rx_pkt, DHCP4_RENEWAL_TIME, 0, &renew_op);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ renew_op = NULL;\r
+ } else if (renew_op->len != 4) {\r
+ renew_op = NULL;\r
+ }\r
+ //\r
+ // There should be a rebinding time.\r
+ // If there is not, we will default to 7/8 of the lease time.\r
+ //\r
+ efi_status = find_opt (rx_pkt, DHCP4_REBINDING_TIME, 0, &rebind_op);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ rebind_op = NULL;\r
+ } else if (rebind_op->len != 4) {\r
+ rebind_op = NULL;\r
+ }\r
+ //\r
+ // There should be a lease time.\r
+ // If there is not, we will default to one week.\r
+ //\r
+ efi_status = find_opt (rx_pkt, DHCP4_LEASE_TIME, 0, &lease_time_op);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ lease_time_op = NULL;\r
+ } else if (lease_time_op->len != 4) {\r
+ lease_time_op = NULL;\r
+ }\r
+ //\r
+ // Packet looks good. Double check the renew, rebind and lease times.\r
+ //\r
+ CopyMem (&Private->ServerIp, srvid_op->data, 4);\r
+\r
+ if (renew_op != NULL) {\r
+ CopyMem (&Private->RenewTime, renew_op->data, 4);\r
+ Private->RenewTime = htonl (Private->RenewTime);\r
+ } else {\r
+ Private->RenewTime = 0;\r
+ }\r
+\r
+ if (rebind_op != NULL) {\r
+ CopyMem (&Private->RebindTime, rebind_op->data, 4);\r
+ Private->RebindTime = htonl (Private->RebindTime);\r
+ } else {\r
+ Private->RebindTime = 0;\r
+ }\r
+\r
+ if (lease_time_op != NULL) {\r
+ CopyMem (&Private->LeaseTime, lease_time_op->data, 4);\r
+ Private->LeaseTime = htonl (Private->LeaseTime);\r
+ } else {\r
+ Private->LeaseTime = 0;\r
+ }\r
+\r
+ if (Private->LeaseTime < 60) {\r
+ Private->LeaseTime = 7 * 86400;\r
+ }\r
+\r
+ if (Private->RebindTime < 52 || Private->RebindTime >= Private->LeaseTime) {\r
+ Private->RebindTime = Private->LeaseTime / 2 + Private->LeaseTime / 4 + Private->LeaseTime / 8;\r
+ }\r
+\r
+ if (Private->RenewTime < 45 || Private->RenewTime >= Private->RebindTime) {\r
+ Private->RenewTime = Private->RebindTime / 2 + Private->RebindTime / 4 + Private->RebindTime / 8;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+renew_rebind (\r
+ IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+ IN UINTN seconds_timeout,\r
+ IN BOOLEAN renew\r
+ )\r
+{\r
+ PXE_DHCP4_PRIVATE_DATA *Private;\r
+ EFI_IP_ADDRESS ServerIp;\r
+ EFI_IP_ADDRESS client_ip;\r
+ EFI_IP_ADDRESS subnet_mask;\r
+ EFI_IP_ADDRESS gateway_ip;\r
+ DHCP4_PACKET Request;\r
+ DHCP4_PACKET AckNak;\r
+ DHCP4_OP *op;\r
+ EFI_STATUS efi_status;\r
+\r
+ //\r
+ // Check for invalid parameters.\r
+ //\r
+ if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Check for proper protocol state.\r
+ //\r
+ if (This->Data == NULL) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ if (!This->Data->SelectCompleted) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ if (This->Data->IsBootp) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (!This->Data->IsAck) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Get pointer to instance data.\r
+ //\r
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Private == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Private->PxeBc == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Copy Discover packet to temporary request packet\r
+ // to be used for Renew/Rebind operation.\r
+ //\r
+ CopyMem (&Request, &This->Data->Discover, sizeof (DHCP4_PACKET));\r
+\r
+ CopyMem (&Request.dhcp4.ciaddr, &This->Data->AckNak.dhcp4.yiaddr, 4);\r
+\r
+ Request.dhcp4.flags = 0; /* Reply does not need to be broadcast. */\r
+\r
+ //\r
+ // Change message type from discover to request.\r
+ //\r
+ efi_status = find_opt (&Request, DHCP4_MESSAGE_TYPE, 0, &op);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (op->len != 1) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST;\r
+\r
+ //\r
+ // Need a subnet mask.\r
+ //\r
+ efi_status = find_opt (\r
+ &This->Data->AckNak,\r
+ DHCP4_SUBNET_MASK,\r
+ 0,\r
+ &op\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (op->len != 4) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS));\r
+ CopyMem (&subnet_mask, op->data, 4);\r
+\r
+ //\r
+ // Need a server IP address (renew) or a broadcast\r
+ // IP address (rebind).\r
+ //\r
+ ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS));\r
+\r
+ if (renew) {\r
+ efi_status = find_opt (\r
+ &This->Data->AckNak,\r
+ DHCP4_SERVER_IDENTIFIER,\r
+ 0,\r
+ &op\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (op->len != 4) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));\r
+ CopyMem (&ServerIp, op->data, 4);\r
+\r
+ //\r
+ //\r
+ //\r
+ if (CompareMem (&This->Data->AckNak.dhcp4.giaddr, &gateway_ip, 4)) {\r
+ CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4);\r
+ }\r
+ } else {\r
+ SetMem (&ServerIp, sizeof (EFI_IP_ADDRESS), 0xFF);\r
+ }\r
+ //\r
+ // Need a client IP address.\r
+ //\r
+ ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS));\r
+ CopyMem (&client_ip, &Request.dhcp4.ciaddr, 4);\r
+\r
+ //\r
+ //\r
+ //\r
+ efi_status = gBS->HandleProtocol (\r
+ Private->Handle,\r
+ &gEfiPxeDhcp4CallbackProtocolGuid,\r
+ (VOID *) &Private->callback\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ Private->callback = NULL;\r
+ }\r
+\r
+ Private->function = renew ? EFI_PXE_DHCP4_FUNCTION_RENEW : EFI_PXE_DHCP4_FUNCTION_REBIND;\r
+\r
+ //\r
+ // Transimit DHCP request and wait for DHCP ack...\r
+ //\r
+ efi_status = tx_rx_udp (\r
+ Private,\r
+ &ServerIp,\r
+ &gateway_ip,\r
+ &client_ip,\r
+ &subnet_mask,\r
+ &Request,\r
+ &AckNak,\r
+ &acknak_verify,\r
+ seconds_timeout\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ Private->callback = NULL;\r
+ return efi_status;\r
+ }\r
+ //\r
+ // Copy server identifier, renewal time and rebinding time\r
+ // from temporary ack/nak packet into cached ack/nak packet.\r
+ //\r
+ efi_status = find_opt (\r
+ &This->Data->AckNak,\r
+ DHCP4_SERVER_IDENTIFIER,\r
+ 0,\r
+ &op\r
+ );\r
+\r
+ if (!EFI_ERROR (efi_status)) {\r
+ if (op->len == 4) {\r
+ CopyMem (op->data, &Private->ServerIp, 4);\r
+ }\r
+ }\r
+\r
+ efi_status = find_opt (&This->Data->AckNak, DHCP4_RENEWAL_TIME, 0, &op);\r
+\r
+ if (!EFI_ERROR (efi_status)) {\r
+ if (op->len == 4) {\r
+ CopyMem (op->data, &Private->RenewTime, 4);\r
+ }\r
+ }\r
+\r
+ efi_status = find_opt (&This->Data->AckNak, DHCP4_REBINDING_TIME, 0, &op);\r
+\r
+ if (!EFI_ERROR (efi_status)) {\r
+ if (op->len == 4) {\r
+ CopyMem (op->data, &Private->RebindTime, 4);\r
+ }\r
+ }\r
+\r
+ Private->callback = NULL;\r
+ return efi_status;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4Renew (\r
+ IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+ IN UINTN seconds_timeout\r
+ )\r
+{\r
+ return renew_rebind (This, seconds_timeout, TRUE);\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4Rebind (\r
+ IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+ IN UINTN seconds_timeout\r
+ )\r
+{\r
+ return renew_rebind (This, seconds_timeout, FALSE);\r
+}\r
+\r
+/* eof - PxeDhcp4RenewRebind.c */\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+ PxeDhcp4Run.c\r
+\r
+Abstract:\r
+ Simplified entry point for starting basic PxeDhcp4 client operation.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "PxeDhcp4.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4Run (\r
+ IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+ IN OPTIONAL UINTN OpLen,\r
+ IN OPTIONAL VOID *OpList\r
+ )\r
+{\r
+ PXE_DHCP4_PRIVATE_DATA *Private;\r
+ DHCP4_PACKET *offer_list;\r
+ EFI_STATUS efi_status;\r
+ EFI_IP_ADDRESS zero_ip;\r
+ UINTN offers;\r
+ UINTN timeout;\r
+ UINTN n;\r
+ UINT16 seconds;\r
+\r
+ //\r
+ // Validate parameters.\r
+ //\r
+ if (This == NULL || (OpLen != 0 && OpList == NULL) || (OpLen == 0 && OpList != NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ for (n = 0; n < OpLen;) {\r
+ switch (((UINT8 *) OpList)[n]) {\r
+ case DHCP4_PAD:\r
+ ++n;\r
+ continue;\r
+\r
+ case DHCP4_END:\r
+ ++n;\r
+ break;\r
+\r
+ default:\r
+ n += 2 + ((UINT8 *) OpList)[n + 1];\r
+ continue;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ if (n != OpLen) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Get pointer to instance data.\r
+ //\r
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Private == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Private->PxeBc == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Initialize DHCP discover packet.\r
+ //\r
+ efi_status = PxeDhcp4Setup (This, NULL);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ return efi_status;\r
+ }\r
+\r
+ for (n = 0; n < OpLen;) {\r
+ switch (((UINT8 *) OpList)[n]) {\r
+ case DHCP4_PAD:\r
+ ++n;\r
+ continue;\r
+\r
+ case DHCP4_END:\r
+ ++n;\r
+ break;\r
+\r
+ default:\r
+ efi_status = add_opt (\r
+ &This->Data->Discover,\r
+ (DHCP4_OP *) &(((UINT8 *) OpList)[n])\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ return efi_status;\r
+ }\r
+\r
+ n += 2 + ((UINT8 *) OpList)[n + 1];\r
+ continue;\r
+ }\r
+\r
+ break;\r
+ }\r
+ //\r
+ // Basic DHCP D.O.R.A.\r
+ // 1, 2, 4, 8, 16 & 32 second timeouts.\r
+ // Callback routine can be used to break out earlier.\r
+ //\r
+ ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));\r
+\r
+ for (timeout = 1;;) {\r
+ //\r
+ // Broadcast DHCP discover and wait for DHCP offers.\r
+ //\r
+ efi_status = PxeDhcp4Init (This, timeout, &offers, &offer_list);\r
+\r
+ if ((efi_status != EFI_SUCCESS) &&\r
+ (efi_status != EFI_TIMEOUT) &&\r
+ (efi_status != EFI_NO_RESPONSE)) {\r
+ return efi_status;\r
+ }\r
+ //\r
+ // Try to select from each DHCP or BOOTP offer.\r
+ //\r
+ for (n = 0; n < offers; ++n) {\r
+ //\r
+ // Ignore proxyDHCP offers.\r
+ //\r
+ if (!CompareMem (&offer_list[n].dhcp4.yiaddr, &zero_ip, 4)) {\r
+ continue;\r
+ }\r
+ //\r
+ // Issue DHCP Request and wait for DHCP Ack/Nak.\r
+ //\r
+ efi_status = PxeDhcp4Select (\r
+ This,\r
+ timeout,\r
+ &offer_list[n]\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ continue;\r
+ }\r
+ //\r
+ // Exit when we have got our DHCP Ack.\r
+ //\r
+ if (This->Data->IsAck) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ //\r
+ // No DHCP Acks. Release DHCP Offer list storage.\r
+ //\r
+ if (offer_list != NULL) {\r
+ gBS->FreePool (offer_list);\r
+ offer_list = NULL;\r
+ }\r
+ //\r
+ // Try again until we have used up >= DHCP4_MAX_SECONDS.\r
+ //\r
+ if ((timeout <<= 1) > DHCP4_MAX_SECONDS) {\r
+ if (!EFI_ERROR (efi_status)) {\r
+ efi_status = EFI_TIMEOUT;\r
+ }\r
+\r
+ return efi_status;\r
+ }\r
+ //\r
+ // Next timeout value.\r
+ //\r
+ CopyMem (&seconds, &This->Data->Discover.dhcp4.secs, 2);\r
+\r
+ seconds = htons (htons (seconds) + timeout);\r
+\r
+ CopyMem (&This->Data->Discover.dhcp4.secs, &seconds, 2);\r
+ }\r
+}\r
+\r
+/* eof - PxeDhcp4Run.c */\r
--- /dev/null
+/** @file\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
+ PxeDhcp4Setup.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "PxeDhcp4.h"\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+EFI_STATUS\r
+EFIAPI\r
+PxeDhcp4Setup (\r
+ IN EFI_PXE_DHCP4_PROTOCOL *This,\r
+ IN EFI_PXE_DHCP4_DATA *Data\r
+ )\r
+{\r
+ PXE_DHCP4_PRIVATE_DATA *Private;\r
+ DHCP4_HEADER *Packet;\r
+ EFI_STATUS EfiStatus;\r
+ UINT8 *OpLen;\r
+ UINT8 *OpPtr;\r
+\r
+ //\r
+ // Return error if parameters are invalid.\r
+ //\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Private == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (This->Data != NULL) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ if (Private->PxeBc == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Check contents of provided Data structure.\r
+ //\r
+ if (Data != NULL) {\r
+ //\r
+ // Do protocol state checks first.\r
+ //\r
+ if (Data->SelectCompleted) {\r
+ if (!Data->InitCompleted || !Data->SetupCompleted) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Data->IsBootp && !Data->IsAck) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else if (Data->InitCompleted) {\r
+ if (!Data->SetupCompleted || Data->IsBootp || Data->IsAck) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else if (Data->SetupCompleted) {\r
+ if (Data->IsBootp || Data->IsAck) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Do packet content checks.\r
+ //\r
+ if (Data->SetupCompleted) {\r
+ //\r
+ // %%TBD - check discover packet\r
+ //\r
+ }\r
+\r
+ if (Data->SelectCompleted) {\r
+ if (Data->IsBootp) {\r
+ //\r
+ // %%TBD - check offer packet\r
+ //\r
+ if (CompareMem (\r
+ &Data->Discover,\r
+ &Data->Request,\r
+ sizeof (DHCP4_PACKET)\r
+ )) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (CompareMem (\r
+ &Data->Offer,\r
+ &Data->AckNak,\r
+ sizeof (DHCP4_PACKET)\r
+ )) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else {\r
+ //\r
+ // %%TBD - check offer, request & acknak packets\r
+ //\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Allocate data structure. Return error\r
+ // if there is not enough available memory.\r
+ //\r
+ This->Data = AllocatePool (sizeof (EFI_PXE_DHCP4_DATA));\r
+ if (This->Data == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Start PxeBc because we want to use its UdpWrite, UdpRead and\r
+ // SetFilter calls.\r
+ //\r
+ EfiStatus = Private->PxeBc->Start (Private->PxeBc, FALSE);\r
+\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ if (EfiStatus != EFI_ALREADY_STARTED) {\r
+ FreePool (This->Data);\r
+ This->Data = NULL;\r
+ Private->PxeBc->Stop (Private->PxeBc);\r
+ return EfiStatus;\r
+ }\r
+\r
+ Private->StopPxeBc = FALSE;\r
+ } else {\r
+ Private->StopPxeBc = TRUE;\r
+ }\r
+ //\r
+ // Use new data.\r
+ //\r
+ if (Data != NULL) {\r
+ CopyMem (This->Data, Data, sizeof (EFI_PXE_DHCP4_DATA));\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Initialize new public data structure.\r
+ //\r
+ ZeroMem (This->Data, sizeof (EFI_PXE_DHCP4_DATA));\r
+\r
+ //\r
+ // Fill in default DHCP discover packet.\r
+ // Check for MAC addresses of strange lengths, just in case.\r
+ //\r
+ Packet = &This->Data->Discover.dhcp4;\r
+\r
+ Packet->op = BOOTP_REQUEST;\r
+\r
+ Packet->htype = Private->Snp->Mode->IfType;\r
+\r
+ if (Private->Snp->Mode->HwAddressSize > 16) {\r
+ Packet->hlen = 16;\r
+ } else {\r
+ Packet->hlen = (UINT8) Private->Snp->Mode->HwAddressSize;\r
+ }\r
+\r
+ Packet->hops = 0; /* Set to zero per RFC 2131. */\r
+\r
+ if (Packet->hlen < sizeof Packet->xid) {\r
+ if (Packet->hlen != 0) {\r
+ CopyMem (\r
+ &Packet->xid,\r
+ &Private->Snp->Mode->CurrentAddress,\r
+ Packet->hlen\r
+ );\r
+ }\r
+ } else {\r
+ CopyMem (\r
+ &Packet->xid,\r
+ &Private->Snp->Mode->CurrentAddress.Addr[Packet->hlen - sizeof Packet->xid],\r
+ sizeof Packet->xid\r
+ );\r
+ }\r
+ //\r
+ // %%TBD - xid should be randomized\r
+ //\r
+ Packet->secs = htons (DHCP4_INITIAL_SECONDS);\r
+\r
+ Packet->flags = htons (DHCP4_BROADCAST_FLAG);\r
+\r
+ if (Packet->hlen != 0) {\r
+ CopyMem (Packet->chaddr, &Private->Snp->Mode->CurrentAddress, Packet->hlen);\r
+ }\r
+\r
+ Packet->magik = htonl (DHCP4_MAGIK_NUMBER);\r
+\r
+ OpPtr = Packet->options;\r
+\r
+ *OpPtr++ = DHCP4_MESSAGE_TYPE;\r
+ *OpPtr++ = 1;\r
+ *OpPtr++ = DHCP4_MESSAGE_TYPE_DISCOVER;\r
+\r
+ *OpPtr++ = DHCP4_MAX_MESSAGE_SIZE;\r
+ *OpPtr++ = 2;\r
+ *OpPtr++ = (UINT8) ((DHCP4_DEFAULT_MAX_MESSAGE_SIZE >> 8) & 0xFF);\r
+ *OpPtr++ = (UINT8) (DHCP4_DEFAULT_MAX_MESSAGE_SIZE & 0xFF);\r
+\r
+ *OpPtr++ = DHCP4_PARAMETER_REQUEST_LIST;\r
+ OpLen = OpPtr;\r
+ *OpPtr++ = 0;\r
+ *OpPtr++ = DHCP4_SUBNET_MASK;\r
+ *OpPtr++ = DHCP4_TIME_OFFSET;\r
+ *OpPtr++ = DHCP4_ROUTER_LIST;\r
+ *OpPtr++ = DHCP4_TIME_SERVERS;\r
+ *OpPtr++ = DHCP4_NAME_SERVERS;\r
+ *OpPtr++ = DHCP4_DNS_SERVERS;\r
+ *OpPtr++ = DHCP4_HOST_NAME;\r
+ *OpPtr++ = DHCP4_BOOT_FILE_SIZE;\r
+ *OpPtr++ = DHCP4_MESSAGE_TYPE;\r
+ *OpPtr++ = DHCP4_DOMAIN_NAME;\r
+ *OpPtr++ = DHCP4_ROOT_PATH;\r
+ *OpPtr++ = DHCP4_EXTENSION_PATH;\r
+ *OpPtr++ = DHCP4_MAX_DATAGRAM_SIZE;\r
+ *OpPtr++ = DHCP4_DEFAULT_TTL;\r
+ *OpPtr++ = DHCP4_BROADCAST_ADDRESS;\r
+ *OpPtr++ = DHCP4_NIS_DOMAIN_NAME;\r
+ *OpPtr++ = DHCP4_NIS_SERVERS;\r
+ *OpPtr++ = DHCP4_NTP_SERVERS;\r
+ *OpPtr++ = DHCP4_VENDOR_SPECIFIC;\r
+ *OpPtr++ = DHCP4_REQUESTED_IP_ADDRESS;\r
+ *OpPtr++ = DHCP4_LEASE_TIME;\r
+ *OpPtr++ = DHCP4_SERVER_IDENTIFIER;\r
+ *OpPtr++ = DHCP4_RENEWAL_TIME;\r
+ *OpPtr++ = DHCP4_REBINDING_TIME;\r
+ *OpPtr++ = DHCP4_CLASS_IDENTIFIER;\r
+ *OpPtr++ = DHCP4_TFTP_SERVER_NAME;\r
+ *OpPtr++ = DHCP4_BOOTFILE;\r
+ *OpPtr++ = 128;\r
+ *OpPtr++ = 129;\r
+ *OpPtr++ = 130;\r
+ *OpPtr++ = 131;\r
+ *OpPtr++ = 132;\r
+ *OpPtr++ = 133;\r
+ *OpPtr++ = 134;\r
+ *OpPtr++ = 135;\r
+ *OpLen = (UINT8) ((OpPtr - OpLen) - 1);\r
+\r
+ *OpPtr++ = DHCP4_END;\r
+\r
+ This->Data->SetupCompleted = TRUE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* eof - PxeDhcp4Setup.c */\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2004 - 2005, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+ support.c\r
+\r
+Abstract:\r
+ Miscellaneous support routines for PxeDhcp4 protocol.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "PxeDhcp4.h"\r
+\r
+#define DebugPrint(x)\r
+//\r
+// #define DebugPrint(x) Aprint x\r
+//\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+UINT16\r
+htons (\r
+ UINTN n\r
+ )\r
+{\r
+ return (UINT16) ((n >> 8) | (n << 8));\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+UINT32\r
+htonl (\r
+ UINTN n\r
+ )\r
+{\r
+ return (UINT32) ((n >> 24) | ((n >> 8) & 0xFF00) | ((n & 0xFF00) << 8) | (n << 24));\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+VOID\r
+EFIAPI\r
+timeout_notify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ ASSERT (Context);\r
+\r
+ if (Context != NULL) {\r
+ ((PXE_DHCP4_PRIVATE_DATA *) Context)->TimeoutOccurred = TRUE;\r
+ }\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+VOID\r
+EFIAPI\r
+periodic_notify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ ASSERT (Context);\r
+\r
+ if (Context != NULL) {\r
+ ((PXE_DHCP4_PRIVATE_DATA *) Context)->PeriodicOccurred = TRUE;\r
+ }\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return EFI_SUCCESS := Option was found\r
+ @return EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL\r
+ @return EFI_INVALID_PARAMETER := OpCode == DHCP4_PAD\r
+ @return EFI_INVALID_PARAMETER := OpCode == DHCP4_END && Skip != 0\r
+ @return EFI_INVALID_PARAMETER := DHCP magik number in Packet is not valid\r
+ @return EFI_NOT_FOUND := op-code was not found in packet\r
+ @return EFI_INVALID_PARAMETER := If present, DHCP_MAX_MESSAGE_SIZE option\r
+ @return does not have a valid value.\r
+\r
+**/\r
+EFI_STATUS\r
+find_opt (\r
+ IN DHCP4_PACKET *Packet,\r
+ IN UINT8 OpCode,\r
+ IN UINTN Skip,\r
+ OUT DHCP4_OP **OpPtr\r
+ )\r
+{\r
+ UINTN msg_size;\r
+ UINTN buf_len;\r
+ UINTN n;\r
+ UINT8 *buf;\r
+ UINT8 *end_ptr;\r
+ UINT8 overload;\r
+\r
+ //\r
+ // Verify parameters.\r
+ //\r
+ if (Packet == NULL || OpPtr == NULL || OpCode == DHCP4_PAD || (OpCode == DHCP4_END && Skip != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Packet->dhcp4.magik != htonl (DHCP4_MAGIK_NUMBER)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Initialize search variables.\r
+ //\r
+ *OpPtr = NULL;\r
+\r
+ msg_size = DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);\r
+\r
+ overload = 0;\r
+ end_ptr = NULL;\r
+\r
+ buf = Packet->dhcp4.options;\r
+ buf_len = msg_size - (Packet->dhcp4.options - Packet->raw);\r
+\r
+ //\r
+ // Start searching for requested option.\r
+ //\r
+ for (n = 0;;) {\r
+ //\r
+ // If match is found, decrement skip count and return\r
+ // when desired match is found.\r
+ //\r
+ if (buf[n] == OpCode) {\r
+ *OpPtr = (DHCP4_OP *) &buf[n];\r
+\r
+ if (Skip-- == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ //\r
+ // Skip past current option. Check for option overload\r
+ // and message size options since these will affect the\r
+ // amount of data to be searched.\r
+ //\r
+ switch (buf[n]) {\r
+ case DHCP4_PAD:\r
+ //\r
+ // Remember the first pad byte of a group. This\r
+ // could be the end of a badly formed packet.\r
+ //\r
+ if (end_ptr == NULL) {\r
+ end_ptr = &buf[n];\r
+ }\r
+\r
+ ++n;\r
+ break;\r
+\r
+ case DHCP4_END:\r
+ //\r
+ // If we reach the end we are done.\r
+ //\r
+ end_ptr = NULL;\r
+ return EFI_NOT_FOUND;\r
+\r
+ case DHCP4_OPTION_OVERLOAD:\r
+ //\r
+ // Remember the option overload value since it\r
+ // could cause the search to continue into\r
+ // the fname and sname fields.\r
+ //\r
+ end_ptr = NULL;\r
+\r
+ if (buf[n + 1] == 1) {\r
+ overload = buf[n + 2];\r
+ }\r
+\r
+ n += 2 + buf[n + 1];\r
+ break;\r
+\r
+ case DHCP4_MAX_MESSAGE_SIZE:\r
+ //\r
+ // Remember the message size value since it could\r
+ // change the amount of option buffer to search.\r
+ //\r
+ end_ptr = NULL;\r
+\r
+ if (buf[n + 1] == 2 && buf == Packet->dhcp4.options) {\r
+ msg_size = ((buf[n + 2] << 8) | buf[n + 3]) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);\r
+\r
+ if (msg_size < 328) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ buf_len = msg_size - (Packet->dhcp4.options - Packet->raw);\r
+\r
+ if (n + 2 + buf[n + 1] > buf_len) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ /* fall thru */\r
+ default:\r
+ end_ptr = NULL;\r
+\r
+ n += 2 + buf[n + 1];\r
+ }\r
+ //\r
+ // Keep searching until the end of the buffer is reached.\r
+ //\r
+ if (n < buf_len) {\r
+ continue;\r
+ }\r
+ //\r
+ // Reached end of current buffer. Check if we are supposed\r
+ // to search the fname and sname buffers.\r
+ //\r
+ if (buf == Packet->dhcp4.options &&\r
+ (overload == DHCP4_OVERLOAD_FNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)\r
+ ) {\r
+ buf = Packet->dhcp4.fname;\r
+ buf_len = 128;\r
+ n = 0;\r
+ continue;\r
+ }\r
+\r
+ if (buf != Packet->dhcp4.sname && (overload == DHCP4_OVERLOAD_SNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)) {\r
+ buf = Packet->dhcp4.sname;\r
+ buf_len = 64;\r
+ n = 0;\r
+ continue;\r
+ }\r
+ //\r
+ // End of last buffer reached. If this was a search\r
+ // for the end of the options, go back to the start\r
+ // of the current pad block.\r
+ //\r
+ if (OpCode == DHCP4_END && end_ptr != NULL) {\r
+ *OpPtr = (DHCP4_OP *) end_ptr;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+ }\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL\r
+ @return EFI_INVALID_PARAMETER := OpPtr->op == DHCP4_PAD || OpPtr->op == DHCP4_END\r
+ @return EFI_INVALID_PARAMETER := DHCP magik number in DHCP packet is not valid\r
+ @return EFI_INVALID_PARAMETER := If DHCP_MAX_MESSAGE_SIZE option is present and\r
+ @return is not valid\r
+ @return EFI_INVALID_PARAMETER := If DHCP_OPTION_OVERLOAD option is present and\r
+ @return is not valid\r
+ @return EFI_DEVICE_ERROR := Cannot determine end of packet\r
+ @return EFI_BUFFER_TOO_SMALL := Not enough room in packet to add option\r
+ @return EFI_SUCCESS := Option added to DHCP packet\r
+\r
+**/\r
+EFI_STATUS\r
+add_opt (\r
+ IN DHCP4_PACKET *Packet,\r
+ IN DHCP4_OP *OpPtr\r
+ )\r
+{\r
+ EFI_STATUS efi_status;\r
+ DHCP4_OP *msg_size_op;\r
+ DHCP4_OP *overload_op;\r
+ DHCP4_OP *op;\r
+ UINTN msg_size;\r
+ UINTN buf_len;\r
+ UINT32 magik;\r
+ UINT8 *buf;\r
+\r
+ //\r
+ // Verify parameters.\r
+ //\r
+ ASSERT (Packet);\r
+ ASSERT (OpPtr);\r
+\r
+ if (Packet == NULL || OpPtr == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ switch (OpPtr->op) {\r
+ case DHCP4_PAD:\r
+ case DHCP4_END:\r
+ //\r
+ // No adding PAD or END.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Check the DHCP magik number.\r
+ //\r
+ CopyMem (&magik, &Packet->dhcp4.magik, 4);\r
+\r
+ if (magik != htonl (DHCP4_MAGIK_NUMBER)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Find the DHCP message size option.\r
+ //\r
+ msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE;\r
+\r
+ efi_status = find_opt (\r
+ Packet,\r
+ DHCP4_MAX_MESSAGE_SIZE,\r
+ 0,\r
+ &msg_size_op\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ if (efi_status != EFI_NOT_FOUND) {\r
+ DebugPrint (\r
+ ("%s:%d:%r\n",\r
+ __FILE__,\r
+ __LINE__,\r
+ efi_status)\r
+ );\r
+ return efi_status;\r
+ }\r
+\r
+ msg_size_op = NULL;\r
+ } else {\r
+ CopyMem (&msg_size, msg_size_op->data, 2);\r
+ msg_size = htons (msg_size);\r
+\r
+ if (msg_size < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Find the DHCP option overload option.\r
+ //\r
+ efi_status = find_opt (\r
+ Packet,\r
+ DHCP4_OPTION_OVERLOAD,\r
+ 0,\r
+ &overload_op\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ if (efi_status != EFI_NOT_FOUND) {\r
+ DebugPrint (\r
+ ("%s:%d:%r\n",\r
+ __FILE__,\r
+ __LINE__,\r
+ efi_status)\r
+ );\r
+ return efi_status;\r
+ }\r
+\r
+ overload_op = NULL;\r
+ } else {\r
+ if (overload_op->len != 1) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ switch (overload_op->data[0]) {\r
+ case 1:\r
+ case 2:\r
+ case 3:\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Find the end of the packet.\r
+ //\r
+ efi_status = find_opt (Packet, DHCP4_END, 0, &op);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Find which buffer the end is in.\r
+ //\r
+ if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.options)) {\r
+ buf_len = (msg_size - ((UINT8 *) &Packet->dhcp4.options - (UINT8 *) &Packet->raw)) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);\r
+ } else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.fname)) {\r
+ buf_len = 128;\r
+ } else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.sname)) {\r
+ buf_len = 64;\r
+ } else {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Add option to current buffer if there is no overlow.\r
+ //\r
+ if ((UINTN) ((&op->op - buf) + 3 + op->len) < buf_len) {\r
+ CopyMem (op, OpPtr, OpPtr->len + 2);\r
+\r
+ op->data[op->len] = DHCP4_END;\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Error if there is no space for option.\r
+ //\r
+ return EFI_BUFFER_TOO_SMALL;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return EFI_INVALID_PARAMETER := Private == NULL || Private->PxeBc == NULL\r
+ @return EFI_INVALID_PARAMETER := Only one of StationIp and SubnetMask is given\r
+ @return EFI_SUCCESS := UDP stack is ready\r
+ @return other := Error from PxeBc->SetIpFilter() or PxeBc->SetStationIp()\r
+\r
+**/\r
+EFI_STATUS\r
+start_udp (\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private,\r
+ IN OPTIONAL EFI_IP_ADDRESS *StationIp,\r
+ IN OPTIONAL EFI_IP_ADDRESS *SubnetMask\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_IP_FILTER bcast_filter;\r
+ EFI_STATUS efi_status;\r
+\r
+ //\r
+ //\r
+ //\r
+ ASSERT (Private);\r
+ ASSERT (Private->PxeBc);\r
+\r
+ if (Private == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Private->PxeBc == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (StationIp != NULL && SubnetMask == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (StationIp == NULL && SubnetMask != NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Setup broadcast receive filter...\r
+ //\r
+ ZeroMem (&bcast_filter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));\r
+\r
+ bcast_filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;\r
+ bcast_filter.IpCnt = 0;\r
+\r
+ efi_status = Private->PxeBc->SetIpFilter (\r
+ Private->PxeBc,\r
+ &bcast_filter\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
+ return efi_status;\r
+ }\r
+ //\r
+ // Configure station IP address and subnet mask...\r
+ //\r
+ efi_status = Private->PxeBc->SetStationIp (\r
+ Private->PxeBc,\r
+ StationIp,\r
+ SubnetMask\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
+ }\r
+\r
+ return efi_status;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+VOID\r
+stop_udp (\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ //\r
+ //\r
+ //\r
+ ASSERT (Private);\r
+ ASSERT (Private->PxeBc);\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+start_receive_events (\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private,\r
+ IN UINTN SecondsTimeout\r
+ )\r
+{\r
+ EFI_STATUS efi_status;\r
+ UINTN random;\r
+\r
+ //\r
+ //\r
+ //\r
+ ASSERT (Private);\r
+ ASSERT (SecondsTimeout);\r
+\r
+ if (Private == NULL || SecondsTimeout == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Need a bettern randomizer...\r
+ // For now adjust the timeout value by the least significant\r
+ // digit in the MAC address.\r
+ //\r
+ random = 0;\r
+\r
+ if (Private->PxeDhcp4.Data != NULL) {\r
+ if (Private->PxeDhcp4.Data->Discover.dhcp4.hlen != 0 && Private->PxeDhcp4.Data->Discover.dhcp4.hlen <= 16) {\r
+ random = 0xFFF & Private->PxeDhcp4.Data->Discover.dhcp4.chaddr[Private->PxeDhcp4.Data->Discover.dhcp4.hlen - 1];\r
+ }\r
+ }\r
+ //\r
+ // Setup timeout event and start timer.\r
+ //\r
+ efi_status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ &timeout_notify,\r
+ Private,\r
+ &Private->TimeoutEvent\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
+ return efi_status;\r
+ }\r
+\r
+ efi_status = gBS->SetTimer (\r
+ Private->TimeoutEvent,\r
+ TimerRelative,\r
+ SecondsTimeout * 10000000 + random\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
+ gBS->CloseEvent (Private->TimeoutEvent);\r
+ return efi_status;\r
+ }\r
+\r
+ Private->TimeoutOccurred = FALSE;\r
+\r
+ //\r
+ // Setup periodic event for callbacks\r
+ //\r
+ efi_status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ &periodic_notify,\r
+ Private,\r
+ &Private->PeriodicEvent\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
+ gBS->CloseEvent (Private->TimeoutEvent);\r
+ return efi_status;\r
+ }\r
+\r
+ efi_status = gBS->SetTimer (\r
+ Private->PeriodicEvent,\r
+ TimerPeriodic,\r
+ 1000000\r
+ ); /* 1/10th second */\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
+ gBS->CloseEvent (Private->TimeoutEvent);\r
+ gBS->CloseEvent (Private->PeriodicEvent);\r
+ return efi_status;\r
+ }\r
+\r
+ Private->PeriodicOccurred = FALSE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+VOID\r
+stop_receive_events (\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ //\r
+ //\r
+ //\r
+ ASSERT (Private);\r
+\r
+ if (Private == NULL) {\r
+ return ;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ gBS->CloseEvent (Private->TimeoutEvent);\r
+ Private->TimeoutOccurred = FALSE;\r
+\r
+ //\r
+ //\r
+ //\r
+ gBS->CloseEvent (Private->PeriodicEvent);\r
+ Private->PeriodicOccurred = FALSE;\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return EFI_INVALID_PARAMETER := Private == NULL || dest_ip == NULL ||\r
+ @return buffer == NULL || BufferSize < 300 || Private->PxeBc == NULL\r
+ @return EFI_SUCCESS := Buffer was transmitted\r
+ @return other := Return from PxeBc->UdpWrite()\r
+\r
+**/\r
+EFI_STATUS\r
+tx_udp (\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private,\r
+ IN EFI_IP_ADDRESS *dest_ip,\r
+ IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,\r
+ IN EFI_IP_ADDRESS *src_ip,\r
+ IN VOID *buffer,\r
+ IN UINTN BufferSize\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_UDP_PORT dest_port;\r
+ EFI_PXE_BASE_CODE_UDP_PORT src_port;\r
+ EFI_IP_ADDRESS zero_ip;\r
+\r
+ //\r
+ //\r
+ //\r
+ ASSERT (Private);\r
+ ASSERT (dest_ip);\r
+ ASSERT (buffer);\r
+ ASSERT (BufferSize >= 300);\r
+\r
+ if (Private == NULL || dest_ip == NULL || buffer == NULL || BufferSize < 300) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ASSERT (Private->PxeBc);\r
+\r
+ if (Private->PxeBc == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Transmit DHCP discover packet...\r
+ //\r
+ ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));\r
+\r
+ if (src_ip == NULL) {\r
+ src_ip = &zero_ip;\r
+ }\r
+\r
+ dest_port = DHCP4_SERVER_PORT;\r
+ src_port = DHCP4_CLIENT_PORT;\r
+\r
+ return Private->PxeBc->UdpWrite (\r
+ Private->PxeBc,\r
+ EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,\r
+ dest_ip,\r
+ &dest_port,\r
+ gateway_ip,\r
+ src_ip,\r
+ &src_port,\r
+ NULL,\r
+ NULL,\r
+ &BufferSize,\r
+ buffer\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+\r
+/**\r
+\r
+ @return EFI_INVALID_PARAMETER :=\r
+ @return EFI_SUCCESS := Packet received\r
+ @return other := Return from PxeBc->UdpRead()\r
+\r
+**/\r
+EFI_STATUS\r
+rx_udp (\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private,\r
+ OUT VOID *buffer,\r
+ IN OUT UINTN *BufferSize,\r
+ IN OUT EFI_IP_ADDRESS *dest_ip,\r
+ IN OUT EFI_IP_ADDRESS *src_ip,\r
+ IN UINT16 op_flags\r
+ )\r
+{\r
+ EFI_PXE_BASE_CODE_UDP_PORT dest_port;\r
+ EFI_PXE_BASE_CODE_UDP_PORT src_port;\r
+\r
+ //\r
+ //\r
+ //\r
+ ASSERT (Private);\r
+ ASSERT (buffer);\r
+ ASSERT (dest_ip);\r
+ ASSERT (src_ip);\r
+\r
+ if (Private == NULL || buffer == NULL || dest_ip == NULL || src_ip == NULL || BufferSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ASSERT (Private->PxeBc);\r
+\r
+ if (Private->PxeBc == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Check for packet\r
+ //\r
+ *BufferSize = sizeof (DHCP4_PACKET);\r
+\r
+ dest_port = DHCP4_CLIENT_PORT;\r
+ src_port = DHCP4_SERVER_PORT;\r
+\r
+ return Private->PxeBc->UdpRead (\r
+ Private->PxeBc,\r
+ op_flags,\r
+ dest_ip,\r
+ &dest_port,\r
+ src_ip,\r
+ &src_port,\r
+ NULL,\r
+ NULL,\r
+ BufferSize,\r
+ buffer\r
+ );\r
+}\r
+\r
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
+EFI_STATUS\r
+tx_rx_udp (\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private,\r
+ IN OUT EFI_IP_ADDRESS *ServerIp,\r
+ IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,\r
+ IN OPTIONAL EFI_IP_ADDRESS *client_ip,\r
+ IN OPTIONAL EFI_IP_ADDRESS *SubnetMask,\r
+ IN DHCP4_PACKET *tx_pkt,\r
+ OUT DHCP4_PACKET *rx_pkt,\r
+ IN INTN (*rx_vfy)(\r
+ IN PXE_DHCP4_PRIVATE_DATA *Private,\r
+ IN DHCP4_PACKET *tx_pkt,\r
+ IN DHCP4_PACKET *rx_pkt,\r
+ IN UINTN rx_pkt_size\r
+ ),\r
+ IN UINTN SecondsTimeout\r
+ )\r
+/*++\r
+Routine description:\r
+ Transmit DHCP packet and wait for replies.\r
+\r
+Parameters:\r
+ Private := Pointer to PxeDhcp4 private data\r
+ ServerIp := Pointer to server IP address\r
+ gateway_ip := Pointer to gateway IP address or NULL\r
+ client_ip := Pointer to client IP address or NULL\r
+ SubnetMask := Pointer to subnet mask or NULL\r
+ tx_pkt := Pointer to DHCP packet to transmit\r
+ rx_pkt := Pointer to DHCP packet receive buffer\r
+ rx_vfy := Pointer to DHCP packet receive verification routine\r
+ SecondsTimeout := Number of seconds until timeout\r
+\r
+Returns:\r
+ EFI_INVALID_PARAMETER := Private == NULL || ServerIp == NULL ||\r
+ tx_pkt == NULL || rx_pkt == NULL || rx_vfy == NULL || Private->PxeBc == NULL\r
+ EFI_ABORTED := Receive aborted\r
+ EFI_TIMEOUT := No packets received\r
+ EFI_SUCCESS := Packet(s) received\r
+ other := Returns from other PxeDhcp4 support routines\r
+--*/\r
+{\r
+ EFI_PXE_DHCP4_CALLBACK_STATUS CallbackStatus;\r
+ EFI_IP_ADDRESS dest_ip;\r
+ EFI_IP_ADDRESS src_ip;\r
+ EFI_STATUS efi_status;\r
+ DHCP4_OP *msg_size_op;\r
+ UINTN pkt_size;\r
+ UINTN n;\r
+ UINT16 msg_size;\r
+ UINT16 op_flags;\r
+ BOOLEAN done_flag;\r
+ BOOLEAN got_packet;\r
+\r
+ //\r
+ // Bad programmer check...\r
+ //\r
+ ASSERT (Private);\r
+ ASSERT (ServerIp);\r
+ ASSERT (tx_pkt);\r
+ ASSERT (rx_pkt);\r
+ ASSERT (rx_vfy);\r
+\r
+ if (Private == NULL || ServerIp == NULL || tx_pkt == NULL || rx_pkt == NULL || rx_vfy == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ASSERT (Private->PxeBc);\r
+\r
+ if (Private->PxeBc == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Enable UDP...\r
+ //\r
+ efi_status = start_udp (Private, client_ip, SubnetMask);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
+ return efi_status;\r
+ }\r
+ //\r
+ // Get length of transmit packet...\r
+ //\r
+ msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE;\r
+\r
+ efi_status = find_opt (\r
+ tx_pkt,\r
+ DHCP4_MAX_MESSAGE_SIZE,\r
+ 0,\r
+ &msg_size_op\r
+ );\r
+\r
+ if (!EFI_ERROR (efi_status)) {\r
+ CopyMem (&msg_size, msg_size_op->data, 2);\r
+\r
+ if ((msg_size = htons (msg_size)) < 328) {\r
+ msg_size = 328;\r
+ }\r
+ }\r
+ //\r
+ // Transmit packet...\r
+ //\r
+ efi_status = tx_udp (\r
+ Private,\r
+ ServerIp,\r
+ gateway_ip,\r
+ client_ip,\r
+ tx_pkt,\r
+ msg_size - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE)\r
+ );\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
+ stop_udp (Private);\r
+ return efi_status;\r
+ }\r
+ //\r
+ // Enable periodic and timeout events...\r
+ //\r
+ efi_status = start_receive_events (Private, SecondsTimeout);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
+ stop_udp (Private);\r
+ return efi_status;\r
+ }\r
+ //\r
+ // Wait for packet(s)...\r
+ //\r
+#if 0\r
+ if (!client_ip) {\r
+ Aprint ("client_ip == NULL ");\r
+ } else {\r
+ Aprint (\r
+ "client_ip == %d.%d.%d.%d ",\r
+ client_ip->v4.Addr[0],\r
+ client_ip->v4.Addr[1],\r
+ client_ip->v4.Addr[2],\r
+ client_ip->v4.Addr[3]\r
+ );\r
+ }\r
+\r
+ if (!ServerIp) {\r
+ Aprint ("ServerIp == NULL\n");\r
+ } else {\r
+ Aprint (\r
+ "ServerIp == %d.%d.%d.%d\n",\r
+ ServerIp->v4.Addr[0],\r
+ ServerIp->v4.Addr[1],\r
+ ServerIp->v4.Addr[2],\r
+ ServerIp->v4.Addr[3]\r
+ );\r
+ }\r
+#endif\r
+\r
+ done_flag = FALSE;\r
+ got_packet = FALSE;\r
+\r
+ while (!done_flag) {\r
+ //\r
+ // Check for timeout event...\r
+ //\r
+ if (Private->TimeoutOccurred) {\r
+ efi_status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ //\r
+ // Check for periodic event...\r
+ //\r
+ if (Private->PeriodicOccurred && Private->callback != NULL) {\r
+ CallbackStatus = EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE;\r
+\r
+ if (Private->callback->Callback != NULL) {\r
+ CallbackStatus = (Private->callback->Callback) (&Private->PxeDhcp4, Private->function, 0, NULL);\r
+ }\r
+\r
+ switch (CallbackStatus) {\r
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE:\r
+ break;\r
+\r
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_ABORT:\r
+ default:\r
+ stop_receive_events (Private);\r
+ stop_udp (Private);\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ Private->PeriodicOccurred = FALSE;\r
+ }\r
+ //\r
+ // Check for packet...\r
+ //\r
+ if (client_ip == NULL) {\r
+ SetMem (&dest_ip, sizeof (EFI_IP_ADDRESS), 0xFF);\r
+ } else {\r
+ CopyMem (&dest_ip, client_ip, sizeof (EFI_IP_ADDRESS));\r
+ }\r
+\r
+ SetMem (&src_ip, sizeof (EFI_IP_ADDRESS), 0xFF);\r
+\r
+ if (CompareMem (&src_ip, &ServerIp, sizeof (EFI_IP_ADDRESS))) {\r
+ ZeroMem (&src_ip, sizeof (EFI_IP_ADDRESS));\r
+ op_flags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP;\r
+ } else {\r
+ op_flags = 0;\r
+ }\r
+\r
+ efi_status = rx_udp (\r
+ Private,\r
+ rx_pkt,\r
+ &pkt_size,\r
+ &dest_ip,\r
+ &src_ip,\r
+ op_flags\r
+ );\r
+\r
+ if (efi_status == EFI_TIMEOUT) {\r
+ efi_status = EFI_SUCCESS;\r
+ continue;\r
+ }\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ break;\r
+ }\r
+ //\r
+ // Some basic packet sanity checks..\r
+ //\r
+ if (pkt_size < 300) {\r
+ continue;\r
+ }\r
+\r
+ if (rx_pkt->dhcp4.op != BOOTP_REPLY) {\r
+ continue;\r
+ }\r
+\r
+ if (tx_pkt->dhcp4.htype != rx_pkt->dhcp4.htype) {\r
+ continue;\r
+ }\r
+\r
+ if ((n = tx_pkt->dhcp4.hlen) != rx_pkt->dhcp4.hlen) {\r
+ continue;\r
+ }\r
+\r
+ if (CompareMem (&tx_pkt->dhcp4.xid, &rx_pkt->dhcp4.xid, 4)) {\r
+ continue;\r
+ }\r
+\r
+ if (n != 0) {\r
+ if (n >= 16) {\r
+ n = 16;\r
+ }\r
+\r
+ if (CompareMem (tx_pkt->dhcp4.chaddr, rx_pkt->dhcp4.chaddr, n)) {\r
+ continue;\r
+ }\r
+ }\r
+ //\r
+ // Internal callback packet verification...\r
+ //\r
+ switch ((*rx_vfy) (Private, tx_pkt, rx_pkt, pkt_size)) {\r
+ case -2: /* ignore and stop */\r
+ stop_receive_events (Private);\r
+ stop_udp (Private);\r
+ return EFI_ABORTED;\r
+\r
+ case -1: /* ignore and wait */\r
+ continue;\r
+\r
+ case 0: /* accept and wait */\r
+ break;\r
+\r
+ case 1: /* accept and stop */\r
+ done_flag = TRUE;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (0);\r
+ }\r
+ //\r
+ // External callback packet verification...\r
+ //\r
+ CallbackStatus = EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE;\r
+\r
+ if (Private->callback != NULL) {\r
+ if (Private->callback->Callback != NULL) {\r
+ CallbackStatus = (Private->callback->Callback) (&Private->PxeDhcp4, Private->function, (UINT32) pkt_size, rx_pkt);\r
+ }\r
+ }\r
+\r
+ switch (CallbackStatus) {\r
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_CONTINUE:\r
+ continue;\r
+\r
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_ABORT:\r
+ done_flag = TRUE;\r
+ break;\r
+\r
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_ABORT:\r
+ stop_receive_events (Private);\r
+ stop_udp (Private);\r
+ return EFI_ABORTED;\r
+\r
+ case EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE:\r
+ default:\r
+ break;\r
+ }\r
+ //\r
+ // We did! We did get a packet!\r
+ //\r
+ got_packet = TRUE;\r
+ }\r
+ //\r
+ //\r
+ //\r
+ stop_receive_events (Private);\r
+ stop_udp (Private);\r
+\r
+ if (EFI_ERROR (efi_status)) {\r
+ DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));\r
+ return efi_status;\r
+ }\r
+\r
+ if (got_packet) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_TIMEOUT;\r
+ }\r
+}\r
+\r
+/* eof - support.c */\r
#define FOUR_GIGABYTES (UINT64) 0x100000000ULL
-//
-// Driver Consumed Protocol Prototypes
-//
-//@MT:#include EFI_PROTOCOL_DEFINITION (DevicePath)
-//@MT:#include EFI_PROTOCOL_DEFINITION (PciIo)
-//@MT:#include EFI_PROTOCOL_DEFINITION (EfiNetworkInterfaceIdentifier)
-
-//
-// Driver Produced Protocol Prototypes
-//
-//@MT:#include EFI_PROTOCOL_DEFINITION (DriverBinding)
-//@MT:#include EFI_PROTOCOL_DEFINITION (ComponentName)
-//@MT:#include EFI_PROTOCOL_DEFINITION (ComponentName2)
-//@MT:#include EFI_PROTOCOL_DEFINITION (SimpleNetwork)
#define SNP_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('s', 'n', 'd', 's')
#define MAX_MAP_LENGTH 100
SNP_DRIVER *snp\r
)\r
{\r
- PXE_CPB_START_30 *cpb;\r
+ PXE_CPB_START_30 *cpb;\r
PXE_CPB_START_31 *cpb_31;\r
\r
cpb = snp->cpb;\r
\r
AccessPoint->UseDefaultAddress = Tcb->UseDefaultAddr;\r
\r
- EFI_IP4 (AccessPoint->StationAddress) = Tcb->LocalEnd.Ip;\r
+ NetCopyMem (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
AccessPoint->SubnetMask = Tcb->SubnetMask;\r
AccessPoint->StationPort = NTOHS (Tcb->LocalEnd.Port);\r
\r
- EFI_IP4 (AccessPoint->RemoteAddress) = Tcb->RemoteEnd.Ip;\r
+ NetCopyMem (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
AccessPoint->RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
AccessPoint->ActiveFlag = (BOOLEAN) (Tcb->State != TCP_LISTEN);\r
\r
Tcb->TTL = CfgData->TimeToLive;\r
Tcb->TOS = CfgData->TypeOfService;\r
\r
- Tcb->LocalEnd.Ip = EFI_IP4 (CfgData->AccessPoint.StationAddress);\r
+ NetCopyMem (&Tcb->LocalEnd.Ip, &CfgData->AccessPoint.StationAddress, sizeof (IP4_ADDR));\r
Tcb->LocalEnd.Port = HTONS (CfgData->AccessPoint.StationPort);\r
Tcb->SubnetMask = CfgData->AccessPoint.SubnetMask;\r
\r
- Tcb->RemoteEnd.Ip = EFI_IP4 (CfgData->AccessPoint.RemoteAddress);\r
+ NetCopyMem (&Tcb->RemoteEnd.Ip, &CfgData->AccessPoint.RemoteAddress, sizeof (IP4_ADDR));\r
Tcb->RemoteEnd.Port = HTONS (CfgData->AccessPoint.RemotePort);\r
\r
Option = CfgData->ControlOption;\r
mTcp4Timer.TimerEvent = NULL;\r
}\r
\r
-//@MT: EFI_DRIVER_ENTRY_POINT (Tcp4DriverEntryPoint)\r
\r
EFI_STATUS\r
EFIAPI\r
Override.TimeToLive = 255;\r
Override.DoNotFragment = FALSE;\r
Override.Protocol = EFI_IP_PROTO_TCP;\r
- EFI_IP4 (Override.GatewayAddress) = 0;\r
- EFI_IP4 (Override.SourceAddress) = Src;\r
+ NetZeroMem (&Override.GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
+ NetCopyMem (&Override.SourceAddress, &Src, sizeof (EFI_IPv4_ADDRESS));\r
\r
Status = IpIoSend (IpIo, Nbuf, IpSender, NULL, NULL, Dest, &Override);\r
\r
EFI_TCP4_OPTION *Option;\r
SOCKET *Sock;\r
EFI_STATUS Status;\r
+ IP4_ADDR Ip;\r
\r
if (NULL == This) {\r
return EFI_INVALID_PARAMETER;\r
// Tcp protocol related parameter check will be conducted here\r
//\r
if (NULL != TcpConfigData) {\r
- if ((EFI_IP4 (TcpConfigData->AccessPoint.RemoteAddress) != 0) &&\r
- !Ip4IsUnicast (EFI_NTOHL (TcpConfigData->AccessPoint.RemoteAddress), 0)) {\r
+\r
+ NetCopyMem (&Ip, &TcpConfigData->AccessPoint.RemoteAddress, sizeof (IP4_ADDR));\r
+ if ((Ip != 0) && !Ip4IsUnicast (NTOHL (Ip), 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (TcpConfigData->AccessPoint.ActiveFlag &&\r
+ (0 == TcpConfigData->AccessPoint.RemotePort || (Ip == 0))) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
if (!TcpConfigData->AccessPoint.UseDefaultAddress) {\r
- if (!Ip4IsUnicast (EFI_NTOHL (TcpConfigData->AccessPoint.StationAddress), 0) ||\r
- !IP4_IS_VALID_NETMASK (EFI_NTOHL (TcpConfigData->AccessPoint.SubnetMask))\r
- ) {\r
+\r
+ NetCopyMem (&Ip, &TcpConfigData->AccessPoint.StationAddress, sizeof (IP4_ADDR));\r
+ if (!Ip4IsUnicast (NTOHL (Ip), 0) || !IP4_IS_VALID_NETMASK (NTOHL (Ip))) {\r
return EFI_INVALID_PARAMETER;\r
}\r
}\r
\r
- if (TcpConfigData->AccessPoint.ActiveFlag &&\r
- (0 == TcpConfigData->AccessPoint.RemotePort ||\r
- (EFI_IP4 (TcpConfigData->AccessPoint.RemoteAddress) == 0))\r
- ) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
Option = TcpConfigData->ControlOption;\r
if ((NULL != Option) &&\r
(Option->EnableSelectiveAck || Option->EnablePathMtuDiscovery)) {\r
//
// Driver Produced Protocol Prototypes
//
-//@MT:#include EFI_PROTOCOL_PRODUCER (Tcp4)
#define TCP4_DEBUG_ERROR(PrintArg) NET_DEBUG_ERROR ("Tcp", PrintArg)
#define TCP4_DEBUG_WARN(PrintArg) NET_DEBUG_WARNING ("Tcp", PrintArg)
NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
\r
- if ((EFI_IP4 (*Addr) == Tcb->LocalEnd.Ip) &&\r
+ if (EFI_IP4_EQUAL (*Addr, Tcb->LocalEnd.Ip) &&\r
(LocalPort == Tcb->LocalEnd.Port)) {\r
\r
return TRUE;\r
NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
\r
- if (((EFI_IP4 (*Addr) == Tcb->LocalEnd.Ip)) &&\r
+ if (EFI_IP4_EQUAL (*Addr, Tcb->LocalEnd.Ip) &&\r
(LocalPort == Tcb->LocalEnd.Port)) {\r
\r
return TRUE;\r
// This tcp instance belongs to the Tcp4Service.\r
//\r
Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
- EFI_IP4 (Tcp4ServicePoint->LocalAddress) = TcpPcb->LocalEnd.Ip;\r
+ NetCopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
- EFI_IP4 (Tcp4ServicePoint->RemoteAddress) = TcpPcb->RemoteEnd.Ip;\r
+ NetCopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
\r
Tcp4ServicePoint++;\r
// This tcp instance belongs to the Tcp4Service.\r
//\r
Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
- EFI_IP4 (Tcp4ServicePoint->LocalAddress) = TcpPcb->LocalEnd.Ip;\r
+ NetCopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
- EFI_IP4 (Tcp4ServicePoint->RemoteAddress) = TcpPcb->RemoteEnd.Ip;\r
+ NetCopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
\r
Tcp4ServicePoint++;\r
return EFI_SUCCESS;\r
}\r
\r
-//@MT: EFI_DRIVER_ENTRY_POINT (Udp4DriverEntryPoint)\r
\r
EFI_STATUS\r
EFIAPI\r
continue;\r
}\r
\r
- if (EFI_IP_EQUAL (ConfigData->StationAddress, *Address) &&\r
+ if (EFI_IP4_EQUAL (ConfigData->StationAddress, *Address) &&\r
(ConfigData->StationPort == Port)) {\r
//\r
// if both the address and the port are the same, return TRUE.\r
}\r
\r
if (!NewConfigData->UseDefaultAddress &&\r
- (!EFI_IP_EQUAL (NewConfigData->StationAddress, OldConfigData->StationAddress) ||\r
- !EFI_IP_EQUAL (NewConfigData->SubnetMask, OldConfigData->SubnetMask))) {\r
+ (!EFI_IP4_EQUAL (NewConfigData->StationAddress, OldConfigData->StationAddress) ||\r
+ !EFI_IP4_EQUAL (NewConfigData->SubnetMask, OldConfigData->SubnetMask))) {\r
//\r
// If the instance doesn't use the default address, and the new address or\r
// new subnet mask is different from the old values.\r
}\r
}\r
\r
- if (!EFI_IP_EQUAL (NewConfigData->RemoteAddress, OldConfigData->RemoteAddress)) {\r
+ if (!EFI_IP4_EQUAL (NewConfigData->RemoteAddress, OldConfigData->RemoteAddress)) {\r
//\r
// The remoteaddress is not the same.\r
//\r
return FALSE;\r
}\r
\r
- if ((EFI_IP4 (NewConfigData->RemoteAddress) != 0) &&\r
- (NewConfigData->RemotePort != OldConfigData->RemotePort)) {\r
+ if (!EFI_IP4_EQUAL (NewConfigData->RemoteAddress, mZeroIp4Addr) && (NewConfigData->RemotePort != OldConfigData->RemotePort)) {\r
//\r
// The RemotePort differs if it's designated in the configdata.\r
//\r
EFI_UDP4_CONFIG_DATA *ConfigData;\r
EFI_UDP4_SESSION_DATA *UdpSessionData;\r
IP4_ADDR SourceAddress;\r
+ IP4_ADDR GatewayAddress;\r
\r
if (TxToken->Event == NULL) {\r
return EFI_INVALID_PARAMETER;\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if ((TxData->GatewayAddress != NULL) &&\r
- !Ip4IsUnicast(EFI_NTOHL (*(TxData->GatewayAddress)), 0)) {\r
- //\r
- // The specified GatewayAddress is not a unicast IPv4 address while it's not 0.\r
- //\r
- return EFI_INVALID_PARAMETER;\r
+ if (TxData->GatewayAddress != NULL) {\r
+ NetCopyMem (&GatewayAddress, TxData->GatewayAddress, sizeof (IP4_ADDR));\r
+\r
+ if (!Ip4IsUnicast (NTOHL (GatewayAddress), 0)) {\r
+ //\r
+ // The specified GatewayAddress is not a unicast IPv4 address while it's not 0.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
}\r
\r
ConfigData = &Instance->ConfigData;\r
\r
if (UdpSessionData != NULL) {\r
\r
- SourceAddress = EFI_NTOHL (UdpSessionData->SourceAddress);\r
+ NetCopyMem (&SourceAddress, &UdpSessionData->SourceAddress, sizeof (IP4_ADDR));\r
\r
- if ((SourceAddress != 0) && !Ip4IsUnicast (SourceAddress, 0)) {\r
+ if ((SourceAddress != 0) && !Ip4IsUnicast (HTONL (SourceAddress), 0)) {\r
//\r
// Check whether SourceAddress is a valid IPv4 address in case it's not zero.\r
// The configured station address is used if SourceAddress is zero.\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (EFI_IP4 (UdpSessionData->DestinationAddress) == 0) {\r
+ if (EFI_IP4_EQUAL (UdpSessionData->DestinationAddress, mZeroIp4Addr)) {\r
//\r
// The DestinationAddress specified in the UdpSessionData is 0.\r
//\r
return EFI_INVALID_PARAMETER;\r
}\r
- } else if (EFI_IP4 (ConfigData->RemoteAddress) == 0) {\r
+ } else if (EFI_IP4_EQUAL (ConfigData->RemoteAddress, mZeroIp4Addr)) {\r
//\r
// the configured RemoteAddress is all zero, and the user doens't override the\r
// destination address.\r
\r
McastIp = Arg;\r
\r
- if ((McastIp != NULL) && ((UINTN) EFI_IP4 (*McastIp) != (UINTN) (Item->Key))) {\r
+ if ((McastIp != NULL) && (!EFI_IP4_EQUAL (*McastIp, (UINTN) Item->Key))) {\r
//\r
- // McastIp is not NULL and the multicast address contained in the Item\r
+ // McastIp is not NULL and the multicast address contained in the Item \r
// is not the same as McastIp.\r
//\r
return EFI_SUCCESS;\r
return FALSE;\r
}\r
\r
- if ((EFI_IP4 (ConfigData->RemoteAddress) != 0) &&\r
- !EFI_IP_EQUAL (ConfigData->RemoteAddress, Udp4Session->SourceAddress)) {\r
+ if (!EFI_IP4_EQUAL (ConfigData->RemoteAddress, mZeroIp4Addr) &&\r
+ !EFI_IP4_EQUAL (ConfigData->RemoteAddress, Udp4Session->SourceAddress)) {\r
//\r
// This datagram doesn't come from the instance's specified sender.\r
//\r
return FALSE;\r
}\r
\r
- if ((EFI_IP4 (ConfigData->StationAddress) == 0) ||\r
- EFI_IP_EQUAL (Udp4Session->DestinationAddress, ConfigData->StationAddress)) {\r
+ if (EFI_IP4_EQUAL (ConfigData->StationAddress, mZeroIp4Addr) ||\r
+ EFI_IP4_EQUAL (Udp4Session->DestinationAddress, ConfigData->StationAddress)) {\r
//\r
// The instance is configured to receive datagrams destinated to any station IP or\r
// the destination address of this datagram matches the configured station IP.\r
return TRUE;\r
}\r
\r
- Destination = EFI_IP4 (Udp4Session->DestinationAddress);\r
+ NetCopyMem (&Destination, &Udp4Session->DestinationAddress, sizeof (IP4_ADDR));\r
\r
if (IP4_IS_LOCAL_BROADCAST (Destination) && ConfigData->AcceptBroadcast) {\r
//\r
\r
gRT->GetTime (&RxData.TimeStamp, NULL);\r
\r
- Udp4Session = &RxData.UdpSession;\r
- EFI_IP4 (Udp4Session->SourceAddress) = NetSession->Source;\r
- EFI_IP4 (Udp4Session->DestinationAddress) = NetSession->Dest;\r
- Udp4Session->SourcePort = NTOHS (Udp4Header->SrcPort);\r
- Udp4Session->DestinationPort = NTOHS (Udp4Header->DstPort);\r
+ Udp4Session = &RxData.UdpSession;\r
+ Udp4Session->SourcePort = NTOHS (Udp4Header->SrcPort);\r
+ Udp4Session->DestinationPort = NTOHS (Udp4Header->DstPort);\r
+\r
+ NetCopyMem (&Udp4Session->SourceAddress, &NetSession->Source, sizeof (EFI_IPv4_ADDRESS));\r
+ NetCopyMem (&Udp4Session->DestinationAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS));\r
\r
//\r
// Trim the UDP header.\r
//\r
// Fill the override data.\r
//\r
- Override.DoNotFragment = FALSE;\r
- Override.TypeOfService = 0;\r
- Override.TimeToLive = 255;\r
- Override.Protocol = EFI_IP_PROTO_ICMP;\r
- EFI_IP4 (Override.SourceAddress) = NetSession->Dest;\r
- EFI_IP4 (Override.GatewayAddress) = 0;\r
+ Override.DoNotFragment = FALSE;\r
+ Override.TypeOfService = 0;\r
+ Override.TimeToLive = 255;\r
+ Override.Protocol = EFI_IP_PROTO_ICMP;\r
+\r
+ NetCopyMem (&Override.SourceAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS));\r
+ NetZeroMem (&Override.GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
\r
//\r
// Send out this icmp packet.\r
\r
Udp4Header = (EFI_UDP4_HEADER *) NetbufGetByte (Packet, 0, NULL);\r
\r
- EFI_IP4 (Udp4Session.SourceAddress) = NetSession->Source;\r
- EFI_IP4 (Udp4Session.DestinationAddress) = NetSession->Dest;\r
- Udp4Session.SourcePort = NTOHS (Udp4Header->DstPort);\r
- Udp4Session.DestinationPort = NTOHS (Udp4Header->SrcPort);\r
+ NetCopyMem (&Udp4Session.SourceAddress, &NetSession->Source, sizeof (EFI_IPv4_ADDRESS));\r
+ NetCopyMem (&Udp4Session.DestinationAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ Udp4Session.SourcePort = NTOHS (Udp4Header->DstPort);\r
+ Udp4Session.DestinationPort = NTOHS (Udp4Header->SrcPort);\r
\r
NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {\r
//\r
if (!Instance->Configured ||\r
Instance->ConfigData.AcceptPromiscuous ||\r
Instance->ConfigData.AcceptAnyPort ||\r
- (EFI_IP4 (Instance->ConfigData.StationAddress) == 0)) {\r
+ EFI_IP4_EQUAL (Instance->ConfigData.StationAddress, mZeroIp4Addr)) {\r
//\r
// Don't try to deliver the ICMP error to this instance if it is not configured,\r
// or it's configured to be promiscuous or accept any port or accept all the\r
IP4_ADDR SubnetMask;\r
IP4_ADDR RemoteAddress;\r
EFI_IP4_CONFIG_DATA Ip4ConfigData;\r
+ IP4_ADDR LocalAddr;\r
+ IP4_ADDR RemoteAddr;\r
\r
if (This == NULL) {\r
return EFI_INVALID_PARAMETER;\r
\r
if (UdpConfigData != NULL) {\r
\r
- StationAddress = EFI_NTOHL (UdpConfigData->StationAddress);\r
- SubnetMask = EFI_NTOHL (UdpConfigData->SubnetMask);\r
- RemoteAddress = EFI_NTOHL (UdpConfigData->RemoteAddress);\r
+ NetCopyMem (&StationAddress, &UdpConfigData->StationAddress, sizeof (IP4_ADDR));\r
+ NetCopyMem (&SubnetMask, &UdpConfigData->SubnetMask, sizeof (IP4_ADDR));\r
+ NetCopyMem (&RemoteAddress, &UdpConfigData->RemoteAddress, sizeof (IP4_ADDR));\r
+\r
+ StationAddress = NTOHL (StationAddress);\r
+ SubnetMask = NTOHL (SubnetMask);\r
+ RemoteAddress = NTOHL (RemoteAddress);\r
+ \r
\r
if (!UdpConfigData->UseDefaultAddress &&\r
(!IP4_IS_VALID_NETMASK (SubnetMask) ||\r
//\r
// Pre calculate the checksum for the pseudo head, ignore the UDP length first.\r
//\r
+ NetCopyMem (&LocalAddr, &Instance->ConfigData.StationAddress, sizeof (IP4_ADDR));\r
+ NetCopyMem (&RemoteAddr, &Instance->ConfigData.RemoteAddress, sizeof (IP4_ADDR));\r
Instance->HeadSum = NetPseudoHeadChecksum (\r
- EFI_IP4 (Instance->ConfigData.StationAddress),\r
- EFI_IP4 (Instance->ConfigData.RemoteAddress),\r
+ LocalAddr,\r
+ RemoteAddr,\r
EFI_IP_PROTO_UDP,\r
0\r
);\r
UDP4_INSTANCE_DATA *Instance;\r
EFI_IP4_PROTOCOL *Ip;\r
EFI_TPL OldTpl;\r
+ IP4_ADDR McastIp;\r
\r
- if ((This == NULL) ||\r
- (JoinFlag && (MulticastAddress == NULL)) ||\r
- (JoinFlag && !IP4_IS_MULTICAST (EFI_NTOHL (*MulticastAddress)))) {\r
+ if ((This == NULL) || (JoinFlag && (MulticastAddress == NULL))) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ McastIp = 0;\r
+ if (JoinFlag) {\r
+ NetCopyMem (&McastIp, MulticastAddress, sizeof (IP4_ADDR));\r
+\r
+ if (IP4_IS_MULTICAST (NTOHL (McastIp))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);\r
\r
if (Instance->IsNoMapping) {\r
//\r
if (JoinFlag) {\r
\r
- NetMapInsertTail (\r
- &Instance->McastIps,\r
- (VOID *) (UINTN) EFI_IP4 (*MulticastAddress),\r
- NULL\r
- );\r
+ NetMapInsertTail (&Instance->McastIps, (VOID *) (UINTN) McastIp, NULL);\r
} else {\r
\r
NetMapIterate (&Instance->McastIps, Udp4LeaveGroup, MulticastAddress);\r
NET_BUF *Packet;\r
EFI_UDP4_HEADER *Udp4Header;\r
EFI_UDP4_CONFIG_DATA *ConfigData;\r
+ IP4_ADDR Source;\r
IP4_ADDR Destination;\r
EFI_UDP4_TRANSMIT_DATA *TxData;\r
EFI_UDP4_SESSION_DATA *UdpSessionData;\r
// Set the SourceAddress, SrcPort and Destination according to the specified\r
// UdpSessionData.\r
//\r
- if (EFI_IP4 (UdpSessionData->SourceAddress) != 0) {\r
- Override.SourceAddress = UdpSessionData->SourceAddress;\r
+ if (!EFI_IP4_EQUAL (UdpSessionData->SourceAddress, mZeroIp4Addr)) {\r
+ NetCopyMem (&Override.SourceAddress, &UdpSessionData->SourceAddress, sizeof (EFI_IPv4_ADDRESS));\r
}\r
\r
if (UdpSessionData->SourcePort != 0) {\r
Udp4Header->SrcPort = HTONS (UdpSessionData->SourcePort);\r
}\r
\r
- Destination = EFI_IP4 (UdpSessionData->DestinationAddress);\r
-\r
if (UdpSessionData->DestinationPort != 0) {\r
Udp4Header->DstPort = HTONS (UdpSessionData->DestinationPort);\r
}\r
\r
+ NetCopyMem (&Source, &Override.SourceAddress, sizeof (IP4_ADDR));\r
+ NetCopyMem (&Destination, &UdpSessionData->DestinationAddress, sizeof (IP4_ADDR));\r
+\r
//\r
// calculate the pseudo head checksum using the overridden parameters.\r
//\r
HeadSum = NetPseudoHeadChecksum (\r
- EFI_IP4 (Override.SourceAddress),\r
+ Source,\r
Destination,\r
EFI_IP_PROTO_UDP,\r
0\r
//\r
// UdpSessionData is NULL, use the address and port information previously configured.\r
//\r
- Destination = EFI_IP4 (ConfigData->RemoteAddress);\r
- HeadSum = Instance->HeadSum;\r
+ NetCopyMem (&Destination, &ConfigData->RemoteAddress, sizeof (IP4_ADDR));\r
+\r
+ HeadSum = Instance->HeadSum;\r
}\r
\r
//\r
//\r
// Fill the IpIo Override data.\r
//\r
- EFI_IP4 (Override.GatewayAddress) = (TxData->GatewayAddress != NULL) ?\r
- EFI_IP4 (*(TxData->GatewayAddress)) : 0;\r
+ if (TxData->GatewayAddress != NULL) {\r
+ NetCopyMem (&Override.GatewayAddress, TxData->GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
+ } else {\r
+ NetZeroMem (&Override.GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
+ }\r
+\r
Override.Protocol = EFI_IP_PROTO_UDP;\r
Override.TypeOfService = ConfigData->TypeOfService;\r
Override.TimeToLive = ConfigData->TimeToLive;\r