Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3492 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
vanjeff
2007-07-30 02:37:10 +00:00
parent eca7eaf49b
commit 772db4bb33
113 changed files with 42735 additions and 302 deletions

View File

@ -73,11 +73,6 @@ typedef struct _ICMP_ERROR_INFO {
BOOLEAN Notify;
} ICMP_ERROR_INFO;
//
// 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)

View File

@ -188,7 +188,7 @@ typedef struct {
//
#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))
#define EFI_IP4_EQUAL(Ip1, Ip2) (NetCompareMem (&(Ip1), &(Ip2), sizeof (EFI_IPv4_ADDRESS)) == 0)
INTN
NetGetMaskLength (
@ -208,10 +208,10 @@ Ip4IsUnicast (
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.
//

View File

@ -0,0 +1,350 @@
/*++
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:
PxeDhcp4.h
Abstract:
EFI PXE DHCPv4 protocol definition
--*/
#ifndef _PXEDHCP4_H_
#define _PXEDHCP4_H_
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// PXE DHCPv4 GUID definition
//
#define EFI_PXE_DHCP4_PROTOCOL_GUID \
{ 0x03c4e624, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x29, 0x3f, 0xc1, 0x4d } }
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// Interface definition
//
typedef struct _EFI_PXE_DHCP4_PROTOCOL EFI_PXE_DHCP4_PROTOCOL;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// Descriptions of the DHCP version 4 header and options can be found
// in RFC-2131 and RFC-2132 at www.ietf.org
//
#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;
#define DHCP4_INITIAL_SECONDS 4
UINT16 flags;
#define DHCP4_BROADCAST_FLAG 0x8000
UINT32 ciaddr;
UINT32 yiaddr;
UINT32 siaddr;
UINT32 giaddr;
UINT8 chaddr[16];
UINT8 sname[64];
UINT8 fname[128];
//
// This is the minimum option length as specified in RFC-2131.
// The packet must be padded out this far with DHCP4_PAD.
// DHCPv4 packets are usually 576 bytes in length. This length
// includes the IPv4 and UDPv4 headers but not the media header.
// Note: Not all DHCP relay agents will forward DHCPv4 packets
// if they are less than 384 bytes or exceed 576 bytes. Even if
// the underlying hardware can handle smaller and larger packets,
// many older relay agents will not accept them.
//
UINT32 magik;
#define DHCP4_MAGIK_NUMBER 0x63825363
UINT8 options[308];
} DHCP4_HEADER;
#pragma pack()
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// DHCPv4 packet definition. Room for 576 bytes including IP and
// UDP header.
//
#define DHCP4_MAX_PACKET_SIZE 576
#define DHCP4_UDP_HEADER_SIZE 8
#define DHCP4_IP_HEADER_SIZE 20
#pragma pack(1)
typedef union _DHCP4_PACKET {
UINT32 _force_data_alignment;
UINT8 raw[1500];
DHCP4_HEADER dhcp4;
} DHCP4_PACKET;
#pragma pack()
#define DHCP4_SERVER_PORT 67
#define DHCP4_CLIENT_PORT 68
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// DHCPv4 and PXE option numbers.
//
#define DHCP4_PAD 0
#define DHCP4_END 255
#define DHCP4_SUBNET_MASK 1
#define DHCP4_TIME_OFFSET 2
#define DHCP4_ROUTER_LIST 3
#define DHCP4_TIME_SERVERS 4
#define DHCP4_NAME_SERVERS 5
#define DHCP4_DNS_SERVERS 6
#define DHCP4_LOG_SERVERS 7
#define DHCP4_COOKIE_SERVERS 8
#define DHCP4_LPR_SREVERS 9
#define DHCP4_IMPRESS_SERVERS 10
#define DHCP4_RESOURCE_LOCATION_SERVERS 11
#define DHCP4_HOST_NAME 12
#define DHCP4_BOOT_FILE_SIZE 13
#define DHCP4_DUMP_FILE 14
#define DHCP4_DOMAIN_NAME 15
#define DHCP4_SWAP_SERVER 16
#define DHCP4_ROOT_PATH 17
#define DHCP4_EXTENSION_PATH 18
#define DHCP4_IP_FORWARDING 19
#define DHCP4_NON_LOCAL_SOURCE_ROUTE 20
#define DHCP4_POLICY_FILTER 21
#define DHCP4_MAX_DATAGRAM_SIZE 22
#define DHCP4_DEFAULT_TTL 23
#define DHCP4_MTU_AGING_TIMEOUT 24
#define DHCP4_MTU_SIZES 25
#define DHCP4_MTU_TO_USE 26
#define DHCP4_ALL_SUBNETS_LOCAL 27
#define DHCP4_BROADCAST_ADDRESS 28
#define DHCP4_PERFORM_MASK_DISCOVERY 29
#define DHCP4_RESPOND_TO_MASK_REQ 30
#define DHCP4_PERFORM_ROUTER_DISCOVERY 31
#define DHCP4_ROUTER_SOLICIT_ADDRESS 32
#define DHCP4_STATIC_ROUTER_LIST 33
#define DHCP4_USE_ARP_TRAILERS 34
#define DHCP4_ARP_CACHE_TIMEOUT 35
#define DHCP4_ETHERNET_ENCAPSULATION 36
#define DHCP4_TCP_DEFAULT_TTL 37
#define DHCP4_TCP_KEEP_ALIVE_INT 38
#define DHCP4_KEEP_ALIVE_GARBAGE 39
#define DHCP4_NIS_DOMAIN_NAME 40
#define DHCP4_NIS_SERVERS 41
#define DHCP4_NTP_SERVERS 42
#define DHCP4_VENDOR_SPECIFIC 43
# define PXE_MTFTP_IP 1
# define PXE_MTFTP_CPORT 2
# define PXE_MTFTP_SPORT 3
# define PXE_MTFTP_TMOUT 4
# define PXE_MTFTP_DELAY 5
# define PXE_DISCOVERY_CONTROL 6
# define PXE_DISABLE_BROADCAST_DISCOVERY 0x01
# define PXE_DISABLE_MULTICAST_DISCOVERY 0x02
# define PXE_ACCEPT_ONLY_PXE_BOOT_SERVERS 0x04
# define PXE_DO_NOT_PROMPT 0x08
# define PXE_DISCOVERY_MCAST_ADDR 7
# define PXE_BOOT_SERVERS 8
# define PXE_BOOT_MENU 9
# define PXE_BOOT_PROMPT 10
# define PXE_MCAST_ADDRS_ALLOC 11
# define PXE_CREDENTIAL_TYPES 12
# define PXE_BOOT_ITEM 71
#define DHCP4_NBNS_SERVERS 44
#define DHCP4_NBDD_SERVERS 45
#define DHCP4_NETBIOS_NODE_TYPE 46
#define DHCP4_NETBIOS_SCOPE 47
#define DHCP4_XWINDOW_SYSTEM_FONT_SERVERS 48
#define DHCP4_XWINDOW_SYSTEM_DISPLAY_MANAGERS 49
#define DHCP4_REQUESTED_IP_ADDRESS 50
#define DHCP4_LEASE_TIME 51
#define DHCP4_OPTION_OVERLOAD 52
# define DHCP4_OVERLOAD_FNAME 1
# define DHCP4_OVERLOAD_SNAME 2
# define DHCP4_OVERLOAD_FNAME_AND_SNAME 3
#define DHCP4_MESSAGE_TYPE 53
# define DHCP4_MESSAGE_TYPE_DISCOVER 1
# define DHCP4_MESSAGE_TYPE_OFFER 2
# define DHCP4_MESSAGE_TYPE_REQUEST 3
# define DHCP4_MESSAGE_TYPE_DECLINE 4
# define DHCP4_MESSAGE_TYPE_ACK 5
# define DHCP4_MESSAGE_TYPE_NAK 6
# define DHCP4_MESSAGE_TYPE_RELEASE 7
# define DHCP4_MESSAGE_TYPE_INFORM 8
#define DHCP4_SERVER_IDENTIFIER 54
#define DHCP4_PARAMETER_REQUEST_LIST 55
#define DHCP4_ERROR_MESSAGE 56
#define DHCP4_MAX_MESSAGE_SIZE 57
# define DHCP4_DEFAULT_MAX_MESSAGE_SIZE 576
#define DHCP4_RENEWAL_TIME 58
#define DHCP4_REBINDING_TIME 59
#define DHCP4_CLASS_IDENTIFIER 60
#define DHCP4_CLIENT_IDENTIFIER 61
#define DHCP4_NISPLUS_DOMAIN_NAME 64
#define DHCP4_NISPLUS_SERVERS 65
#define DHCP4_TFTP_SERVER_NAME 66
#define DHCP4_BOOTFILE 67
#define DHCP4_MOBILE_IP_HOME_AGENTS 68
#define DHCP4_SMPT_SERVERS 69
#define DHCP4_POP3_SERVERS 70
#define DHCP4_NNTP_SERVERS 71
#define DHCP4_WWW_SERVERS 72
#define DHCP4_FINGER_SERVERS 73
#define DHCP4_IRC_SERVERS 74
#define DHCP4_STREET_TALK_SERVERS 75
#define DHCP4_STREET_TALK_DIR_ASSIST_SERVERS 76
#define DHCP4_NDS_SERVERS 85
#define DHCP4_NDS_TREE_NAME 86
#define DHCP4_NDS_CONTEXT 87
#define DHCP4_SYSTEM_ARCHITECTURE 93
#define DHCP4_NETWORK_ARCHITECTURE 94
#define DHCP4_PLATFORM_ID 97
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// DHCP4 option format.
//
#pragma pack(1)
typedef struct {
UINT8 op;
UINT8 len;
UINT8 data[1];
} DHCP4_OP;
#pragma pack()
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef struct {
DHCP4_PACKET Discover;
DHCP4_PACKET Offer;
DHCP4_PACKET Request;
DHCP4_PACKET AckNak;
BOOLEAN SetupCompleted;
BOOLEAN InitCompleted;
BOOLEAN SelectCompleted;
BOOLEAN IsBootp;
BOOLEAN IsAck;
} EFI_PXE_DHCP4_DATA;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef
EFI_STATUS
(EFIAPI *EFI_PXE_DHCP4_RUN) (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN OPTIONAL UINTN OpLen,
IN OPTIONAL VOID *OpList
);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef
EFI_STATUS
(EFIAPI *EFI_PXE_DHCP4_SETUP) (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN OPTIONAL EFI_PXE_DHCP4_DATA * NewData
);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef
EFI_STATUS
(EFIAPI *EFI_PXE_DHCP4_INIT) (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN UINTN SecondsTimeout,
OUT UINTN *Offers,
OUT DHCP4_PACKET **OfferList
);
#define DHCP4_MIN_SECONDS 1
#define DHCP4_MAX_SECONDS 60
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef
EFI_STATUS
(EFIAPI *EFI_PXE_DHCP4_SELECT) (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN UINTN SecondsTimeout,
IN DHCP4_PACKET * offer
);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef
EFI_STATUS
(EFIAPI *EFI_PXE_DHCP4_RENEW) (
IN EFI_PXE_DHCP4_PROTOCOL *This,
UINTN seconds_timeout
);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef
EFI_STATUS
(EFIAPI *EFI_PXE_DHCP4_REBIND) (
IN EFI_PXE_DHCP4_PROTOCOL *This,
UINTN seconds_timeout
);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
typedef
EFI_STATUS
(EFIAPI *EFI_PXE_DHCP4_RELEASE) (
IN EFI_PXE_DHCP4_PROTOCOL * This
);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#define EFI_PXE_DHCP4_PROTOCOL_REVISION 0x00010000
struct _EFI_PXE_DHCP4_PROTOCOL {
UINT64 Revision;
EFI_PXE_DHCP4_RUN Run;
EFI_PXE_DHCP4_SETUP Setup;
EFI_PXE_DHCP4_INIT Init;
EFI_PXE_DHCP4_SELECT Select;
EFI_PXE_DHCP4_RENEW Renew;
EFI_PXE_DHCP4_REBIND Rebind;
EFI_PXE_DHCP4_RELEASE Release;
EFI_PXE_DHCP4_DATA *Data;
};
//
//
//
extern EFI_GUID gEfiPxeDhcp4ProtocolGuid;
#endif /* _PXEDHCP4_H_ */
/* EOF - PxeDhcp4.h */

View File

@ -0,0 +1,85 @@
/*++
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:
PxeDhcp4Callback.h
Abstract:
EFI PXE DHCP4 Callback protocol definition.
--*/
#ifndef _PXE_DHCP4CALLBACK_H
#define _PXE_DHCP4CALLBACK_H
#include <Protocol/PxeDhcp4.h>
//
// GUID definition
//
#define EFI_PXE_DHCP4_CALLBACK_PROTOCOL_GUID \
{ 0xc1544c01, 0x92a4, 0x4198, {0x8a, 0x84, 0x77, 0x85, 0x83, 0xc2, 0x36, 0x21 } }
//
// Revision number
//
#define EFI_PXE_DHCP4_CALLBACK_INTERFACE_REVISION 0x00010000
//
// Interface definition
//
typedef struct _EFI_PXE_DHCP4_CALLBACK_PROTOCOL EFI_PXE_DHCP4_CALLBACK_PROTOCOL;
typedef enum {
EFI_PXE_DHCP4_FUNCTION_FIRST,
EFI_PXE_DHCP4_FUNCTION_INIT,
EFI_PXE_DHCP4_FUNCTION_SELECT,
EFI_PXE_DHCP4_FUNCTION_RENEW,
EFI_PXE_DHCP4_FUNCTION_REBIND,
EFI_PXE_DHCP4_FUNCTION_LAST
} EFI_PXE_DHCP4_FUNCTION;
typedef enum {
EFI_PXE_DHCP4_CALLBACK_STATUS_FIRST,
EFI_PXE_DHCP4_CALLBACK_STATUS_ABORT,
EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_ABORT,
EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_ABORT,
EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE,
EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_CONTINUE,
EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE,
EFI_PXE_DHCP4_CALLBACK_STATUS_LAST
} EFI_PXE_DHCP4_CALLBACK_STATUS;
typedef
EFI_PXE_DHCP4_CALLBACK_STATUS
(EFIAPI *EFI_PXE_DHCP4_CALLBACK) (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN EFI_PXE_DHCP4_FUNCTION Function,
IN UINT32 PacketLen,
IN DHCP4_PACKET *Packet OPTIONAL
);
struct _EFI_PXE_DHCP4_CALLBACK_PROTOCOL {
UINT64 Revision;
EFI_PXE_DHCP4_CALLBACK Callback;
};
//
// GUID declaration
//
extern EFI_GUID gEfiPxeDhcp4CallbackProtocolGuid;
#endif /* _PXE_DHCP4CALLBACK_H */
/* EOF - PxeDhcp4Callback.h */

View File

@ -0,0 +1,108 @@
/*++
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:
tcp.h
Abstract:
EFI Transmission Control Protocol
Revision History
--*/
#ifndef _EFITCP_H
#define _EFITCP_H
#include <Protocol/PxeBaseCode.h>
//
// PXE Base Code protocol
//
#define EFI_TCP_PROTOCOL_GUID \
{ 0x02b3d5f2, 0xac28, 0x11d3, { 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}
typedef UINT16 EFI_PXE_BASE_CODE_TCP_PORT;
//
// Port Receive Filter definitions
//
#define EFI_PXE_BASE_CODE_MAX_PORTCNT 8
typedef struct {
UINT8 Filters;
UINT8 IpCnt;
UINT16 reserved;
EFI_IP_ADDRESS IpList[EFI_PXE_BASE_CODE_MAX_PORTCNT];
} EFI_TCP_PORT_FILTER;
typedef
EFI_STATUS
(EFIAPI *EFI_TCP_WRITE) (
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 UINT16 *DestPort,
IN EFI_IP_ADDRESS *GatewayIp, OPTIONAL
IN EFI_IP_ADDRESS *SrcIp, OPTIONAL
IN UINT16 *SrcPort, OPTIONAL
IN UINTN *HeaderSize, OPTIONAL
IN VOID *HeaderPtr, OPTIONAL
IN UINTN *BufferSize,
IN VOID *BufferPtr
);
typedef
EFI_STATUS
(EFIAPI *EFI_TCP_READ) (
IN EFI_PXE_BASE_CODE_PROTOCOL *This,
IN UINT16 OpFlags,
IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL
IN OUT UINT16 *DestPort, OPTIONAL
IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL
IN OUT UINT16 *SrcPort, OPTIONAL
IN UINTN *HeaderSize, OPTIONAL
IN VOID *HeaderPtr, OPTIONAL
IN OUT UINTN *BufferSize,
IN VOID *BufferPtr
);
typedef
EFI_STATUS
(EFIAPI *EFI_TCP_SET_PORT_FILTER) (
IN EFI_PXE_BASE_CODE_PROTOCOL *This,
IN EFI_TCP_PORT_FILTER *NewFilter
);
//
// TCP Protocol structure
//
typedef struct _EFI_TCP_PROTOCOL {
EFI_TCP_WRITE TcpWrite;
EFI_TCP_READ TcpRead;
EFI_TCP_SET_PORT_FILTER SetPortFilter;
} EFI_TCP_PROTOCOL;
extern EFI_GUID gEfiTcpProtocolGuid;
#endif /* _EFITCP_H */

View File

@ -77,6 +77,7 @@ IP4_ADDR mIp4AllMasks[IP4_MASK_NUM] = {
0xFFFFFFFF,
};
EFI_IPv4_ADDRESS mZeroIp4Addr = {0, 0, 0, 0};
/**
Converts the low nibble of a byte to hex unicode character.

View File

@ -80,6 +80,10 @@
gEfiNicIp4ConfigProtocolGuid = {0xdca3d4d, 0x12da, 0x4728, { 0xbf, 0x7e, 0x86, 0xce, 0xb9, 0x28, 0xd0, 0x67 }}
gEfiNicIp4ConfigVariableGuid = {0xd8944553, 0xc4dd, 0x41f4, { 0x9b, 0x30, 0xe1, 0x39, 0x7c, 0xfb, 0x26, 0x7b }}
gEfiTcpProtocolGuid = { 0x02b3d5f2, 0xac28, 0x11d3, { 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}
gEfiPxeDhcp4CallbackProtocolGuid = { 0xc1544c01, 0x92a4, 0x4198, {0x8a, 0x84, 0x77, 0x85, 0x83, 0xc2, 0x36, 0x21 } }
gEfiPxeDhcp4ProtocolGuid = { 0x03c4e624, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x29, 0x3f, 0xc1, 0x4d } }
[Ppis.common]
gPeiBaseMemoryTestPpiGuid = { 0xB6EC423C, 0x21D2, 0x490D, { 0x85, 0xC6, 0xDD, 0x58, 0x64, 0xEA, 0xA6, 0x74 }}

View File

@ -55,7 +55,7 @@
[LibraryClasses.IPF]
IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
[LibraryClasses.EBC.DXE_RUNTIME_DRIVER]
[LibraryClasses.EBC]
IoLib|IntelFrameworkPkg/Library/DxeIoLibCpuIo/DxeIoLibCpuIo.inf
[LibraryClasses.common.PEI_CORE]
@ -112,6 +112,7 @@
UsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf
IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf
UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf
[LibraryClasses.common.DXE_RUNTIME_DRIVER]
HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
@ -368,8 +369,13 @@
MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf
MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf
MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf
MdeModulePkg/Universal/Network/PxeBcDxe/PxeBcDxe.inf
MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4Dxe.inf
MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf
MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf
MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf

View File

@ -0,0 +1,30 @@
/** @file
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
ArpDebug.h
Abstract:
**/
#ifndef _ARP_DEBUG_H_
#define _ARP_DEBUG_H_
#define ARP_DEBUG_TRACE(PrintArg) NET_DEBUG_TRACE ("Arp", PrintArg)
#define ARP_DEBUG_WARN(PrintArg) NET_DEBUG_WARNING ("Arp", PrintArg)
#define ARP_DEBUG_ERROR(PrintArg) NET_DEBUG_ERROR ("Arp", PrintArg)
#endif

View File

@ -0,0 +1,763 @@
/** @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:
ArpDriver.c
Abstract:
**/
#include "ArpDriver.h"
#include "ArpImpl.h"
EFI_DRIVER_BINDING_PROTOCOL gArpDriverBinding = {
ArpDriverBindingSupported,
ArpDriverBindingStart,
ArpDriverBindingStop,
0xa,
NULL,
NULL
};
/**
Create and initialize the arp service context data.
@param ImageHandle The image handle representing the loaded driver
image.
@param ControllerHandle The controller handle the driver binds to.
@param ArpService Pointer to the buffer containing the arp service
context data.
@retval EFI_SUCCESS The arp service context is initialized.
@retval other Failed to initialize the arp service context.
**/
STATIC
EFI_STATUS
ArpCreateService (
IN EFI_HANDLE ImageHandle,
IN EFI_HANDLE ControllerHandle,
IN ARP_SERVICE_DATA *ArpService
)
{
EFI_STATUS Status;
ASSERT (ArpService != NULL);
ArpService->Signature = ARP_SERVICE_DATA_SIGNATURE;
//
// Init the servicebinding protocol members.
//
ArpService->ServiceBinding.CreateChild = ArpServiceBindingCreateChild;
ArpService->ServiceBinding.DestroyChild = ArpServiceBindingDestroyChild;
//
// Save the handles.
//
ArpService->ImageHandle = ImageHandle;
ArpService->ControllerHandle = ControllerHandle;
//
// Create a MNP child instance.
//
Status = NetLibCreateServiceChild (
ControllerHandle,
ImageHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
&ArpService->MnpChildHandle
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open the MNP protocol.
//
Status = gBS->OpenProtocol (
ArpService->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
(VOID **)&ArpService->Mnp,
ImageHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto ERROR_EXIT;
}
//
// Get the underlayer Snp mode data.
//
Status = ArpService->Mnp->GetModeData (ArpService->Mnp, NULL, &ArpService->SnpMode);
if ((Status != EFI_NOT_STARTED) && EFI_ERROR (Status)) {
goto ERROR_EXIT;
}
if (ArpService->SnpMode.IfType != NET_IFTYPE_ETHERNET) {
//
// Only support the ethernet.
//
Status = EFI_UNSUPPORTED;
goto ERROR_EXIT;
}
//
// Set the Mnp config parameters.
//
ArpService->MnpConfigData.ReceivedQueueTimeoutValue = 0;
ArpService->MnpConfigData.TransmitQueueTimeoutValue = 0;
ArpService->MnpConfigData.ProtocolTypeFilter = ARP_ETHER_PROTO_TYPE;
ArpService->MnpConfigData.EnableUnicastReceive = TRUE;
ArpService->MnpConfigData.EnableMulticastReceive = FALSE;
ArpService->MnpConfigData.EnableBroadcastReceive = TRUE;
ArpService->MnpConfigData.EnablePromiscuousReceive = FALSE;
ArpService->MnpConfigData.FlushQueuesOnReset = TRUE;
ArpService->MnpConfigData.EnableReceiveTimestamps = FALSE;
ArpService->MnpConfigData.DisableBackgroundPolling = FALSE;
//
// Configure the Mnp child.
//
Status = ArpService->Mnp->Configure (ArpService->Mnp, &ArpService->MnpConfigData);
if (EFI_ERROR (Status)) {
goto ERROR_EXIT;
}
//
// Create the event used in the RxToken.
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
NET_TPL_EVENT,
ArpOnFrameRcvd,
ArpService,
&ArpService->RxToken.Event
);
if (EFI_ERROR (Status)) {
goto ERROR_EXIT;
}
//
// Create the Arp heartbeat timer.
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL | EVT_TIMER,
NET_TPL_TIMER,
ArpTimerHandler,
ArpService,
&ArpService->PeriodicTimer
);
if (EFI_ERROR (Status)) {
goto ERROR_EXIT;
}
//
// Start the heartbeat timer.
//
Status = gBS->SetTimer (
ArpService->PeriodicTimer,
TimerPeriodic,
ARP_PERIODIC_TIMER_INTERVAL
);
if (EFI_ERROR (Status)) {
goto ERROR_EXIT;
}
//
// Init the lock.
//
NET_LOCK_INIT (&ArpService->Lock);
//
// Init the lists.
//
NetListInit (&ArpService->ChildrenList);
NetListInit (&ArpService->PendingRequestTable);
NetListInit (&ArpService->DeniedCacheTable);
NetListInit (&ArpService->ResolvedCacheTable);
ERROR_EXIT:
return Status;
}
/**
Clean the arp service context data.
@param ArpService Pointer to the buffer containing the arp service
context data.
@return None.
**/
STATIC
VOID
ArpCleanService (
IN ARP_SERVICE_DATA *ArpService
)
{
NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
if (ArpService->PeriodicTimer != NULL) {
//
// Cancle and close the PeriodicTimer.
//
gBS->SetTimer (ArpService->PeriodicTimer, TimerCancel, 0);
gBS->CloseEvent (ArpService->PeriodicTimer);
}
if (ArpService->RxToken.Event != NULL) {
//
// Cancle the RxToken and close the event in the RxToken.
//
ArpService->Mnp->Cancel (ArpService->Mnp, NULL);
gBS->CloseEvent (ArpService->RxToken.Event);
}
if (ArpService->Mnp != NULL) {
//
// Reset the Mnp child and close the Mnp protocol.
//
ArpService->Mnp->Configure (ArpService->Mnp, NULL);
gBS->CloseProtocol (
ArpService->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
ArpService->ImageHandle,
ArpService->ControllerHandle
);
}
if (ArpService->MnpChildHandle != NULL) {
//
// Destroy the mnp child.
//
NetLibDestroyServiceChild(
ArpService->ControllerHandle,
ArpService->ImageHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
ArpService->MnpChildHandle
);
}
}
/**
Test to see if this driver supports ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to test.
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCES This driver supports this device
@retval EFI_ALREADY_STARTED This driver is already running on this device.
@retval other This driver does not support this device.
**/
EFI_STATUS
EFIAPI
ArpDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
//
// Test to see if Arp SB is already installed.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiArpServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (Status == EFI_SUCCESS) {
return EFI_ALREADY_STARTED;
}
//
// Test to see if MNP SB is installed.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
return Status;
}
/**
Start this driver on ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to bind driver to
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCES This driver is added to ControllerHandle
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
ArpDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
ARP_SERVICE_DATA *ArpService;
//
// Allocate a zero pool for ArpService.
//
ArpService = NetAllocateZeroPool (sizeof(ARP_SERVICE_DATA));
if (ArpService == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Initialize the arp service context data.
//
Status = ArpCreateService (This->DriverBindingHandle, ControllerHandle, ArpService);
if (EFI_ERROR (Status)) {
goto ERROR;
}
//
// Install the ARP service binding protocol.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiArpServiceBindingProtocolGuid,
&ArpService->ServiceBinding,
NULL
);
if (EFI_ERROR (Status)) {
goto ERROR;
}
//
// OK, start to receive arp packets from Mnp.
//
Status = ArpService->Mnp->Receive (ArpService->Mnp, &ArpService->RxToken);
if (EFI_ERROR (Status)) {
goto ERROR;
}
return Status;
ERROR:
//
// On error, clean the arp service context data, and free the memory allocated.
//
ArpCleanService (ArpService);
NetFreePool (ArpService);
return Status;
}
/**
Stop this driver on ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to stop driver on
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
of children is zero stop the entire bus driver.
@param ChildHandleBuffer List of Child Handles to Stop.
@retval EFI_SUCCES This driver is removed ControllerHandle
@retval other This driver was not removed from this device
**/
EFI_STATUS
EFIAPI
ArpDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
EFI_HANDLE NicHandle;
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
ARP_SERVICE_DATA *ArpService;
ARP_INSTANCE_DATA *Instance;
//
// Get the NicHandle which the arp servicebinding is installed on.
//
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
if (NicHandle == NULL) {
return EFI_SUCCESS;
}
//
// Try to get the arp servicebinding protocol on the NicHandle.
//
Status = gBS->OpenProtocol (
NicHandle,
&gEfiArpServiceBindingProtocolGuid,
(VOID **)&ServiceBinding,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
ARP_DEBUG_ERROR (("ArpDriverBindingStop: Open ArpSb failed, %r.\n", Status));
return Status;
}
ArpService = ARP_SERVICE_DATA_FROM_THIS (ServiceBinding);
while (!NetListIsEmpty (&ArpService->ChildrenList)) {
//
// Iterate all the instances.
//
Instance = NET_LIST_HEAD (&ArpService->ChildrenList, ARP_INSTANCE_DATA, List);
//
// Destroy this arp child.
//
ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
}
ASSERT (NetListIsEmpty (&ArpService->PendingRequestTable));
ASSERT (NetListIsEmpty (&ArpService->DeniedCacheTable));
ASSERT (NetListIsEmpty (&ArpService->ResolvedCacheTable));
//
// Uninstall the ARP ServiceBinding protocol.
//
Status = gBS->UninstallMultipleProtocolInterfaces (
NicHandle,
&gEfiArpServiceBindingProtocolGuid,
&ArpService->ServiceBinding,
NULL
);
if (EFI_ERROR (Status)) {
ARP_DEBUG_ERROR (("ArpDriverBindingStop: Failed to uninstall ArpSb, %r.\n", Status));
return Status;
}
//
// Clean the arp servicebinding context data and free the memory allocated.
//
ArpCleanService (ArpService);
NetFreePool (ArpService);
return Status;
}
/**
Creates a child handle with a set of I/O services.
@param This Protocol instance pointer.
@param ChildHandle Pointer to the handle of the child to create. If
it is NULL, then a new handle is created. If it is
not NULL, then the I/O services are added to the
existing child handle.
@retval EFI_SUCCES The child handle was created with the I/O
services.
@retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
the child.
@retval other The child handle was not created.
**/
EFI_STATUS
EFIAPI
ArpServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
)
{
EFI_STATUS Status;
ARP_SERVICE_DATA *ArpService;
ARP_INSTANCE_DATA *Instance;
VOID *Mnp;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
ArpService = ARP_SERVICE_DATA_FROM_THIS (This);
//
// Allocate memory for the instance context data.
//
Instance = NetAllocateZeroPool (sizeof(ARP_INSTANCE_DATA));
if (Instance == NULL) {
ARP_DEBUG_ERROR (("ArpSBCreateChild: Failed to allocate memory for Instance.\n"));
return EFI_OUT_OF_RESOURCES;
}
//
// Init the instance context data.
//
ArpInitInstance (ArpService, Instance);
//
// Install the ARP protocol onto the ChildHandle.
//
Status = gBS->InstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiArpProtocolGuid,
(VOID *)&Instance->ArpProto,
NULL
);
if (EFI_ERROR (Status)) {
ARP_DEBUG_ERROR (("ArpSBCreateChild: faild to install ARP protocol, %r.\n", Status));
NetFreePool (Instance);
return Status;
}
//
// Save the ChildHandle.
//
Instance->Handle = *ChildHandle;
//
// Open the Managed Network protocol BY_CHILD.
//
Status = gBS->OpenProtocol (
ArpService->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
(VOID **) &Mnp,
gArpDriverBinding.DriverBindingHandle,
Instance->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
goto ERROR;
}
if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {
Status = EFI_ACCESS_DENIED;
goto ERROR;
}
//
// Insert the instance into children list managed by the arp service context data.
//
NetListInsertTail (&ArpService->ChildrenList, &Instance->List);
ArpService->ChildrenNumber++;
NET_UNLOCK (&ArpService->Lock);
ERROR:
if (EFI_ERROR (Status)) {
gBS->CloseProtocol (
ArpService->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
gArpDriverBinding.DriverBindingHandle,
Instance->Handle
);
gBS->UninstallMultipleProtocolInterfaces (
Instance->Handle,
&gEfiArpProtocolGuid,
&Instance->ArpProto,
NULL
);
//
// Free the allocated memory.
//
NetFreePool (Instance);
}
return Status;
}
/**
Destroys a child handle with a set of I/O services.
@param This Protocol instance pointer.
@param ChildHandle Handle of the child to destroy.
@retval EFI_SUCCES The I/O services were removed from the child
handle.
@retval EFI_UNSUPPORTED The child handle does not support the I/O services
that are being removed.
@retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
@retval EFI_ACCESS_DENIED The child handle could not be destroyed because
its I/O services are being used.
@retval other The child handle was not destroyed.
**/
EFI_STATUS
EFIAPI
ArpServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
EFI_STATUS Status;
ARP_SERVICE_DATA *ArpService;
ARP_INSTANCE_DATA *Instance;
EFI_ARP_PROTOCOL *Arp;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
ArpService = ARP_SERVICE_DATA_FROM_THIS (This);
//
// Get the arp protocol.
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiArpProtocolGuid,
(VOID **)&Arp,
ArpService->ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Instance = ARP_INSTANCE_DATA_FROM_THIS (Arp);
if (Instance->Destroyed) {
return EFI_SUCCESS;
}
//
// Use the Destroyed as a flag to avoid re-entrance.
//
Instance->Destroyed = TRUE;
//
// Close the Managed Network protocol.
//
gBS->CloseProtocol (
ArpService->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
gArpDriverBinding.DriverBindingHandle,
ChildHandle
);
//
// Uninstall the ARP protocol.
//
Status = gBS->UninstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiArpProtocolGuid,
&Instance->ArpProto,
NULL
);
if (EFI_ERROR (Status)) {
ARP_DEBUG_ERROR (("ArpSBDestroyChild: Failed to uninstall the arp protocol, %r.\n",
Status));
Instance->Destroyed = FALSE;
return Status;
}
if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {
Instance->Destroyed = FALSE;
return EFI_ACCESS_DENIED;
}
if (Instance->Configured) {
//
// Delete the related cache entry.
//
ArpDeleteCacheEntry (Instance, FALSE, NULL, TRUE);
//
// Reset the instance configuration.
//
ArpConfigureInstance (Instance, NULL);
}
//
// Remove this instance from the ChildrenList.
//
NetListRemoveEntry (&Instance->List);
ArpService->ChildrenNumber--;
NET_UNLOCK (&ArpService->Lock);
NetFreePool (Instance);
return Status;
}
//@MT: EFI_DRIVER_ENTRY_POINT (ArpDriverEntryPoint)
EFI_STATUS
EFIAPI
ArpDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
The entry point for Arp driver which installs the driver binding and component name
protocol on its ImageHandle.
Arguments:
ImageHandle - The image handle of the driver.
SystemTable - The system table.
Returns:
EFI_SUCCESS - if the driver binding and component name protocols are successfully
installed, otherwise if failed.
--*/
{
return NetLibInstallAllDriverProtocols (
ImageHandle,
SystemTable,
&gArpDriverBinding,
ImageHandle,
&gArpComponentName,
NULL,
NULL
);
}

View File

@ -0,0 +1,84 @@
/** @file
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
ArpDriver.c
Abstract:
**/
#ifndef _ARP_DRIVER_H_
#define _ARP_DRIVER_H_
#include <PiDxe.h>
#include <Protocol/Arp.h>
#include <Protocol/ManagedNetwork.h>
#include <Protocol/ServiceBinding.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#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

View File

@ -0,0 +1,59 @@
#/** @file
# Component description file for ARP module
#
# 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
#
#
#**/
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = ArpDxe
FILE_GUID = 529D3F93-E8E9-4e73-B1E1-BDF6A9D50113
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = ArpDriverEntryPoint
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources.common]
ArpMain.c
ArpDriver.h
ComponentName.c
ArpImpl.h
ArpImpl.c
ArpDebug.h
ArpDriver.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiLib
UefiBootServicesTableLib
UefiDriverEntryPoint
DebugLib
NetLib
[Protocols]
gEfiManagedNetworkServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiArpServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiManagedNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiArpProtocolGuid # PROTOCOL ALWAYS_CONSUMED

View File

@ -0,0 +1,72 @@
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>Arp</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>529D3F93-E8E9-4e73-B1E1-BDF6A9D50113</GuidValue>
<Version>1.0</Version>
<Abstract>Component name for module Arp</Abstract>
<Description>FIX ME!</Description>
<Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
<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>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>Arp</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>ArpDriver.c</Filename>
<Filename>ArpDebug.h</Filename>
<Filename>ArpImpl.c</Filename>
<Filename>ArpImpl.h</Filename>
<Filename>ComponentName.c</Filename>
<Filename>ArpDriver.h</Filename>
<Filename>ArpMain.c</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiArpProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiManagedNetworkProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiArpServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiManagedNetworkServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>ArpDriverEntryPoint</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,341 @@
/** @file
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
ArpImpl.h
Abstract:
**/
#ifndef _ARP_IMPL_H_
#define _ARP_IMPL_H_
#include <PiDxe.h>
#include <Protocol/Arp.h>
#include <Protocol/ManagedNetwork.h>
#include <Protocol/ServiceBinding.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#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

View File

@ -0,0 +1,727 @@
/** @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:
ArpMain.c
Abstract:
**/
#include "ArpImpl.h"
/**
This function is used to assign a station address to the ARP cache for this instance
of the ARP driver. A call to this function with the ConfigData field set to NULL
will reset this ARP instance.
@param This Pointer to the EFI_ARP_PROTOCOL instance.
@param ConfigData Pointer to the EFI_ARP_CONFIG_DATA structure.
@retval EFI_SUCCESS The new station address was successfully
registered.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL. SwAddressLength is zero when
ConfigData is not NULL. StationAddress is NULL
when ConfigData is not NULL.
@retval EFI_ACCESS_DENIED The SwAddressType, SwAddressLength, or
StationAddress is different from the one that is
already registered.
@retval EFI_OUT_OF_RESOURCES Storage for the new StationAddress could not be
allocated.
**/
EFI_STATUS
EFIAPI
ArpConfigure (
IN EFI_ARP_PROTOCOL *This,
IN EFI_ARP_CONFIG_DATA *ConfigData OPTIONAL
)
{
EFI_STATUS Status;
ARP_INSTANCE_DATA *Instance;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
if ((ConfigData != NULL) &&
((ConfigData->SwAddressLength == 0) ||
(ConfigData->StationAddress == NULL) ||
(ConfigData->SwAddressType <= 1500))) {
return EFI_INVALID_PARAMETER;
}
Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
if (EFI_ERROR (NET_TRYLOCK (&Instance->ArpService->Lock))) {
return EFI_ACCESS_DENIED;
}
//
// Configure this instance, the ConfigData has already passed the basic checks.
//
Status = ArpConfigureInstance (Instance, ConfigData);
NET_UNLOCK (&Instance->ArpService->Lock);
return Status;
}
/**
This function is used to insert entries into the ARP cache.
@param This Pointer to the EFI_ARP_PROTOCOL instance.
@param DenyFlag Set to TRUE if this entry is a deny entry. Set to
FALSE if this entry is a normal entry.
@param TargetSwAddress Pointer to a protocol address to add (or deny).
May be set to NULL if DenyFlag is TRUE.
@param TargetHwAddress Pointer to a hardware address to add (or deny).
May be set to NULL if DenyFlag is TRUE.
@param TimeoutValue Time in 100-ns units that this entry will remain
in the ARP cache. A value of zero means that the
entry is permanent. A nonzero value will override
the one given by Configure() if the entry to be
added is a dynamic entry.
@param Overwrite If TRUE, the matching cache entry will be
overwritten with the supplied parameters. If
FALSE, EFI_ACCESS_DENIED is returned if the
corresponding cache entry already exists.
@retval EFI_SUCCESS The entry has been added or updated.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL. DenyFlag is FALSE and
TargetHwAddress is NULL. DenyFlag is FALSE and
TargetSwAddress is NULL. TargetHwAddress is NULL
and TargetSwAddress is NULL. Both TargetSwAddress
and TargetHwAddress are not NULL when DenyFlag is
TRUE.
@retval EFI_OUT_OF_RESOURCES The new ARP cache entry could not be allocated.
@retval EFI_ACCESS_DENIED The ARP cache entry already exists and Overwrite
is not true.
@retval EFI_NOT_STARTED The ARP driver instance has not been configured.
**/
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 Status;
ARP_INSTANCE_DATA *Instance;
ARP_SERVICE_DATA *ArpService;
ARP_CACHE_ENTRY *CacheEntry;
EFI_SIMPLE_NETWORK_MODE *SnpMode;
NET_ARP_ADDRESS MatchAddress[2];
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
if (((!DenyFlag) && ((TargetHwAddress == NULL) || (TargetSwAddress == NULL))) ||
(DenyFlag && (TargetHwAddress != NULL) && (TargetSwAddress != NULL)) ||
((TargetHwAddress == NULL) && (TargetSwAddress == NULL))) {
return EFI_INVALID_PARAMETER;
}
Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
if (!Instance->Configured) {
return EFI_NOT_STARTED;
}
Status = EFI_SUCCESS;
ArpService = Instance->ArpService;
SnpMode = &Instance->ArpService->SnpMode;
//
// Fill the hardware address part in the MatchAddress.
//
MatchAddress[Hardware].Type = SnpMode->IfType;
MatchAddress[Hardware].Length = (UINT8) SnpMode->HwAddressSize;
MatchAddress[Hardware].AddressPtr = TargetHwAddress;
//
// Fill the software address part in the MatchAddress.
//
MatchAddress[Protocol].Type = Instance->ConfigData.SwAddressType;
MatchAddress[Protocol].Length = Instance->ConfigData.SwAddressLength;
MatchAddress[Protocol].AddressPtr = TargetSwAddress;
if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {
return EFI_ACCESS_DENIED;
}
//
// See whether the entry to add exists. Check the DeinedCacheTable first.
//
CacheEntry = ArpFindDeniedCacheEntry (
ArpService,
&MatchAddress[Protocol],
&MatchAddress[Hardware]
);
if (CacheEntry == NULL) {
//
// Check the ResolvedCacheTable
//
CacheEntry = ArpFindNextCacheEntryInTable (
&ArpService->ResolvedCacheTable,
NULL,
ByBoth,
&MatchAddress[Protocol],
&MatchAddress[Hardware]
);
}
if ((CacheEntry != NULL) && !Overwrite) {
//
// The entry to add exists, if not Overwirte, deny this add request.
//
Status = EFI_ACCESS_DENIED;
goto UNLOCK_EXIT;
}
if ((CacheEntry == NULL) && (TargetSwAddress != NULL)) {
//
// Check whether there are pending requests matching the entry to be added.
//
CacheEntry = ArpFindNextCacheEntryInTable (
&ArpService->PendingRequestTable,
NULL,
ByProtoAddress,
&MatchAddress[Protocol],
NULL
);
}
if (CacheEntry != NULL) {
//
// Remove it from the Table.
//
NetListRemoveEntry (&CacheEntry->List);
} else {
//
// It's a new entry, allocate memory for the entry.
//
CacheEntry = ArpAllocCacheEntry (Instance);
if (CacheEntry == NULL) {
ARP_DEBUG_ERROR (("ArpAdd: Failed to allocate pool for CacheEntry.\n"));
Status = EFI_OUT_OF_RESOURCES;
goto UNLOCK_EXIT;
}
}
//
// Overwrite these parameters.
//
CacheEntry->DefaultDecayTime = TimeoutValue;
CacheEntry->DecayTime = TimeoutValue;
//
// Fill in the addresses.
//
ArpFillAddressInCacheEntry (
CacheEntry,
&MatchAddress[Hardware],
&MatchAddress[Protocol]
);
//
// Inform the user if there is any.
//
ArpAddressResolved (CacheEntry, NULL, NULL);
//
// Add this CacheEntry to the corresponding CacheTable.
//
if (DenyFlag) {
NetListInsertHead (&ArpService->DeniedCacheTable, &CacheEntry->List);
} else {
NetListInsertHead (&ArpService->ResolvedCacheTable, &CacheEntry->List);
}
UNLOCK_EXIT:
NET_UNLOCK (&ArpService->Lock);
return Status;
}
/**
This function searches the ARP cache for matching entries and allocates a buffer into
which those entries are copied.
@param This Pointer to the EFI_ARP_PROTOCOL instance.
@param BySwAddress Set to TRUE to look for matching software protocol
addresses. Set to FALSE to look for matching
hardware protocol addresses.
@param AddressBuffer Pointer to address buffer. Set to NULL to match
all addresses.
@param EntryLength The size of an entry in the entries buffer.
@param EntryCount The number of ARP cache entries that are found by
the specified criteria.
@param Entries Pointer to the buffer that will receive the ARP
cache entries.
@param Refresh Set to TRUE to refresh the timeout value of the
matching ARP cache entry.
@retval EFI_SUCCESS The requested ARP cache entries were copied into
the buffer.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL. Both EntryCount and EntryLength are
NULL, when Refresh is FALSE.
@retval EFI_NOT_FOUND No matching entries were found.
@retval EFI_NOT_STARTED The ARP driver instance has not been configured.
**/
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 Status;
ARP_INSTANCE_DATA *Instance;
ARP_SERVICE_DATA *ArpService;
if ((This == NULL) ||
(!Refresh && (EntryCount == NULL) && (EntryLength == NULL)) ||
((Entries != NULL) && ((EntryLength == NULL) || (EntryCount == NULL)))) {
return EFI_INVALID_PARAMETER;
}
Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
ArpService = Instance->ArpService;
if (!Instance->Configured) {
return EFI_NOT_STARTED;
}
if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {
return EFI_ACCESS_DENIED;
}
//
// All the check passed, find the cache entries now.
//
Status = ArpFindCacheEntry (
Instance,
BySwAddress,
AddressBuffer,
EntryLength,
EntryCount,
Entries,
Refresh
);
NET_UNLOCK (&ArpService->Lock);
return Status;
}
/**
This function removes specified ARP cache entries.
@param This Pointer to the EFI_ARP_PROTOCOL instance.
@param BySwAddress Set to TRUE to delete matching protocol addresses.
Set to FALSE to delete matching hardware
addresses.
@param AddressBuffer Pointer to the address buffer that is used as a
key to look for the cache entry. Set to NULL to
delete all entries.
@retval EFI_SUCCESS The entry was removed from the ARP cache.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_NOT_FOUND The specified deletion key was not found.
@retval EFI_NOT_STARTED The ARP driver instance has not been configured.
**/
EFI_STATUS
EFIAPI
ArpDelete (
IN EFI_ARP_PROTOCOL *This,
IN BOOLEAN BySwAddress,
IN VOID *AddressBuffer OPTIONAL
)
{
ARP_INSTANCE_DATA *Instance;
ARP_SERVICE_DATA *ArpService;
UINTN Count;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
if (!Instance->Configured) {
return EFI_NOT_STARTED;
}
ArpService = Instance->ArpService;
if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {
return EFI_ACCESS_DENIED;
}
//
// Delete the specified cache entries.
//
Count = ArpDeleteCacheEntry (Instance, BySwAddress, AddressBuffer, TRUE);
NET_UNLOCK (&ArpService->Lock);
return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;
}
/**
This function delete all dynamic entries from the ARP cache that match the specified
software protocol type.
@param This Pointer to the EFI_ARP_PROTOCOL instance.
@retval EFI_SUCCESS The cache has been flushed.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_NOT_FOUND There are no matching dynamic cache entries.
@retval EFI_NOT_STARTED The ARP driver instance has not been configured.
**/
EFI_STATUS
EFIAPI
ArpFlush (
IN EFI_ARP_PROTOCOL *This
)
{
ARP_INSTANCE_DATA *Instance;
ARP_SERVICE_DATA *ArpService;
UINTN Count;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
if (!Instance->Configured) {
return EFI_NOT_STARTED;
}
ArpService = Instance->ArpService;
if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {
return EFI_ACCESS_DENIED;
}
//
// Delete the dynamic entries from the cache table.
//
Count = ArpDeleteCacheEntry (Instance, FALSE, NULL, FALSE);
NET_UNLOCK (&ArpService->Lock);
return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;
}
/**
This function tries to resolve the TargetSwAddress and optionally returns a
TargetHwAddress if it already exists in the ARP cache.
@param This Pointer to the EFI_ARP_PROTOCOL instance.
@param TargetSwAddress Pointer to the protocol address to resolve.
@param ResolvedEvent Pointer to the event that will be signaled when
the address is resolved or some error occurs.
@param TargetHwAddress Pointer to the buffer for the resolved hardware
address in network byte order.
@retval EFI_SUCCESS The data is copied from the ARP cache into the
TargetHwAddress buffer.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL. TargetHwAddress is NULL.
@retval EFI_ACCESS_DENIED The requested address is not present in the normal
ARP cache but is present in the deny address list.
Outgoing traffic to that address is forbidden.
@retval EFI_NOT_STARTED The ARP driver instance has not been configured.
@retval EFI_NOT_READY The request has been started and is not finished.
**/
EFI_STATUS
EFIAPI
ArpRequest (
IN EFI_ARP_PROTOCOL *This,
IN VOID *TargetSwAddress OPTIONAL,
IN EFI_EVENT ResolvedEvent OPTIONAL,
OUT VOID *TargetHwAddress
)
{
EFI_STATUS Status;
ARP_INSTANCE_DATA *Instance;
ARP_SERVICE_DATA *ArpService;
EFI_SIMPLE_NETWORK_MODE *SnpMode;
ARP_CACHE_ENTRY *CacheEntry;
NET_ARP_ADDRESS HardwareAddress;
NET_ARP_ADDRESS ProtocolAddress;
USER_REQUEST_CONTEXT *RequestContext;
if ((This == NULL) || (TargetHwAddress == NULL)) {
return EFI_INVALID_PARAMETER;
}
Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
if (!Instance->Configured) {
return EFI_NOT_STARTED;
}
Status = EFI_SUCCESS;
ArpService = Instance->ArpService;
SnpMode = &ArpService->SnpMode;
if ((TargetSwAddress == NULL) ||
((Instance->ConfigData.SwAddressType == IPv4_ETHER_PROTO_TYPE) &&
IP4_IS_LOCAL_BROADCAST (*((UINT32 *)TargetSwAddress)))) {
//
// Return the hardware broadcast address.
//
NetCopyMem (TargetHwAddress, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);
goto SIGNAL_USER;
}
if ((Instance->ConfigData.SwAddressType == IPv4_ETHER_PROTO_TYPE) &&
IP4_IS_MULTICAST (NTOHL (*((UINT32 *)TargetSwAddress)))) {
//
// If the software address is an IPv4 multicast address, invoke Mnp to
// resolve the address.
//
Status = ArpService->Mnp->McastIpToMac (
ArpService->Mnp,
FALSE,
TargetSwAddress,
TargetHwAddress
);
goto SIGNAL_USER;
}
HardwareAddress.Type = SnpMode->IfType;
HardwareAddress.Length = (UINT8)SnpMode->HwAddressSize;
HardwareAddress.AddressPtr = NULL;
ProtocolAddress.Type = Instance->ConfigData.SwAddressType;
ProtocolAddress.Length = Instance->ConfigData.SwAddressLength;
ProtocolAddress.AddressPtr = TargetSwAddress;
//
// Initialize the TargetHwAddrss to a zero address.
//
NetZeroMem (TargetHwAddress, SnpMode->HwAddressSize);
if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {
return EFI_ACCESS_DENIED;
}
//
// Check whether the software address is in the denied table.
//
CacheEntry = ArpFindDeniedCacheEntry (ArpService, &ProtocolAddress, NULL);
if (CacheEntry != NULL) {
Status = EFI_ACCESS_DENIED;
goto UNLOCK_EXIT;
}
//
// Check whether the software address is already resolved.
//
CacheEntry = ArpFindNextCacheEntryInTable (
&ArpService->ResolvedCacheTable,
NULL,
ByProtoAddress,
&ProtocolAddress,
NULL
);
if (CacheEntry != NULL) {
//
// Resolved, copy the address into the user buffer.
//
NetCopyMem (
TargetHwAddress,
CacheEntry->Addresses[Hardware].AddressPtr,
CacheEntry->Addresses[Hardware].Length
);
goto UNLOCK_EXIT;
}
if (ResolvedEvent == NULL) {
Status = EFI_NOT_READY;
goto UNLOCK_EXIT;
}
//
// Create a request context for this arp request.
//
RequestContext = NetAllocatePool (sizeof(USER_REQUEST_CONTEXT));
if (RequestContext == NULL) {
ARP_DEBUG_ERROR (("ArpRequest: Allocate memory for RequestContext failed.\n"));
Status = EFI_OUT_OF_RESOURCES;
goto UNLOCK_EXIT;
}
RequestContext->Instance = Instance;
RequestContext->UserRequestEvent = ResolvedEvent;
RequestContext->UserHwAddrBuffer = TargetHwAddress;
NetListInit (&RequestContext->List);
//
// Check whether there is a same request.
//
CacheEntry = ArpFindNextCacheEntryInTable (
&ArpService->PendingRequestTable,
NULL,
ByProtoAddress,
&ProtocolAddress,
NULL
);
if (CacheEntry != NULL) {
CacheEntry->NextRetryTime = Instance->ConfigData.RetryTimeOut;
CacheEntry->RetryCount = Instance->ConfigData.RetryCount;
} else {
//
// Allocate a cache entry for this request.
//
CacheEntry = ArpAllocCacheEntry (Instance);
if (CacheEntry == NULL) {
ARP_DEBUG_ERROR (("ArpRequest: Allocate memory for CacheEntry failed.\n"));
NetFreePool (RequestContext);
Status = EFI_OUT_OF_RESOURCES;
goto UNLOCK_EXIT;
}
//
// Fill the software address.
//
ArpFillAddressInCacheEntry (CacheEntry, &HardwareAddress, &ProtocolAddress);
//
// Add this entry into the PendingRequestTable.
//
NetListInsertTail (&ArpService->PendingRequestTable, &CacheEntry->List);
}
//
// Link this request context into the cache entry.
//
NetListInsertHead (&CacheEntry->UserRequestList, &RequestContext->List);
//
// Send out the ARP Request frame.
//
ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REQUEST);
Status = EFI_NOT_READY;
UNLOCK_EXIT:
NET_UNLOCK (&ArpService->Lock);
SIGNAL_USER:
if ((ResolvedEvent != NULL) && (Status == EFI_SUCCESS)) {
gBS->SignalEvent (ResolvedEvent);
}
return Status;
}
/**
This function aborts the previous ARP request (identified by This, TargetSwAddress
and ResolvedEvent) that is issued by EFI_ARP_PROTOCOL.Request().
@param This Pointer to the EFI_ARP_PROTOCOL instance.
@param TargetSwAddress Pointer to the protocol address in previous
request session.
@param ResolvedEvent Pointer to the event that is used as the
notification event in previous request session.
@retval EFI_SUCCESS The pending request session(s) is/are aborted and
corresponding event(s) is/are signaled.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL. TargetSwAddress is not NULL and
ResolvedEvent is NULL. TargetSwAddress is NULL and
ResolvedEvent is not NULL.
@retval EFI_NOT_STARTED The ARP driver instance has not been configured.
@retval EFI_NOT_FOUND The request is not issued by
EFI_ARP_PROTOCOL.Request().
**/
EFI_STATUS
EFIAPI
ArpCancel (
IN EFI_ARP_PROTOCOL *This,
IN VOID *TargetSwAddress OPTIONAL,
IN EFI_EVENT ResolvedEvent OPTIONAL
)
{
ARP_INSTANCE_DATA *Instance;
ARP_SERVICE_DATA *ArpService;
UINTN Count;
if ((This == NULL) ||
((TargetSwAddress != NULL) && (ResolvedEvent == NULL)) ||
((TargetSwAddress == NULL) && (ResolvedEvent != NULL))) {
return EFI_INVALID_PARAMETER;
}
Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
if (!Instance->Configured) {
return EFI_NOT_STARTED;
}
ArpService = Instance->ArpService;
if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {
return EFI_ACCESS_DENIED;
}
//
// Cancel the specified request.
//
Count = ArpCancelRequest (Instance, TargetSwAddress, ResolvedEvent);
NET_UNLOCK (&ArpService->Lock);
return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;
}

View File

@ -0,0 +1,156 @@
/** @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:
ComponentName.c
Abstract:
**/
#include "ArpDriver.h"
//
// EFI Component Name Functions
//
EFI_STATUS
EFIAPI
ArpComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
EFI_STATUS
EFIAPI
ArpComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
//
// EFI Component Name Protocol
//
EFI_COMPONENT_NAME_PROTOCOL gArpComponentName = {
ArpComponentNameGetDriverName,
ArpComponentNameGetControllerName,
"eng"
};
STATIC EFI_UNICODE_STRING_TABLE mArpDriverNameTable[] = {
{ "eng", L"ARP Network Service Driver" },
{ NULL, NULL }
};
EFI_STATUS
EFIAPI
ArpComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
Language - A pointer to a three character ISO 639-2 language identifier.
This is the language of the driver name that that the caller
is requesting, and it must match one of the languages specified
in SupportedLanguages. The number of languages supported by a
driver is up to the driver writer.
DriverName - A pointer to the Unicode string to return. This Unicode string
is the name of the driver specified by This in the language
specified by Language.
Returns:
EFI_SUCCES - The Unicode string for the Driver specified by This
and the language specified by Language was returned
in DriverName.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - DriverName is NULL.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return LookupUnicodeString (
Language,
gArpComponentName.SupportedLanguages,
mArpDriverNameTable,
DriverName
);
}
EFI_STATUS
EFIAPI
ArpComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by an EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
ControllerHandle - The handle of a controller that the driver specified by
This is managing. This handle specifies the controller
whose name is to be returned.
ChildHandle - The handle of the child controller to retrieve the name
of. This is an optional parameter that may be NULL. It
will be NULL for device drivers. It will also be NULL
for a bus drivers that wish to retrieve the name of the
bus controller. It will not be NULL for a bus driver
that wishes to retrieve the name of a child controller.
Language - A pointer to a three character ISO 639-2 language
identifier. This is the language of the controller name
that that the caller is requesting, and it must match one
of the languages specified in SupportedLanguages. The
number of languages supported by a driver is up to the
driver writer.
ControllerName - A pointer to the Unicode string to return. This Unicode
string is the name of the controller specified by
ControllerHandle and ChildHandle in the language specified
by Language from the point of view of the driver specified
by This.
Returns:
EFI_SUCCESS - The Unicode string for the user readable name in the
language specified by Language for the driver
specified by This was returned in DriverName.
EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - ControllerName is NULL.
EFI_UNSUPPORTED - The driver specified by This is not currently managing
the controller specified by ControllerHandle and
ChildHandle.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return EFI_UNSUPPORTED;
}

View File

@ -0,0 +1,162 @@
/** @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:
ComponentName.c
Abstract:
**/
#include "Dhcp4Impl.h"
//
// EFI Component Name Functions
//
EFI_STATUS
EFIAPI
DhcpComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
EFI_STATUS
EFIAPI
DhcpComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
//
// EFI Component Name Protocol
//
EFI_COMPONENT_NAME_PROTOCOL gDhcp4ComponentName = {
DhcpComponentNameGetDriverName,
DhcpComponentNameGetControllerName,
"eng"
};
static EFI_UNICODE_STRING_TABLE mDhcpDriverNameTable[] = {
{
"eng",
L"DHCP Protocol Driver"
},
{
NULL,
NULL
}
};
EFI_STATUS
EFIAPI
DhcpComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
Language - A pointer to a three character ISO 639-2 language identifier.
This is the language of the driver name that that the caller
is requesting, and it must match one of the languages specified
in SupportedLanguages. The number of languages supported by a
driver is up to the driver writer.
DriverName - A pointer to the Unicode string to return. This Unicode string
is the name of the driver specified by This in the language
specified by Language.
Returns:
EFI_SUCCES - The Unicode string for the Driver specified by This
and the language specified by Language was returned
in DriverName.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - DriverName is NULL.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return LookupUnicodeString (
Language,
gDhcp4ComponentName.SupportedLanguages,
mDhcpDriverNameTable,
DriverName
);
}
EFI_STATUS
EFIAPI
DhcpComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by an EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
ControllerHandle - The handle of a controller that the driver specified by
This is managing. This handle specifies the controller
whose name is to be returned.
ChildHandle - The handle of the child controller to retrieve the name
of. This is an optional parameter that may be NULL. It
will be NULL for device drivers. It will also be NULL
for a bus drivers that wish to retrieve the name of the
bus controller. It will not be NULL for a bus driver
that wishes to retrieve the name of a child controller.
Language - A pointer to a three character ISO 639-2 language
identifier. This is the language of the controller name
that that the caller is requesting, and it must match one
of the languages specified in SupportedLanguages. The
number of languages supported by a driver is up to the
driver writer.
ControllerName - A pointer to the Unicode string to return. This Unicode
string is the name of the controller specified by
ControllerHandle and ChildHandle in the language
specified by Language from the point of view of the
driver specified by This.
Returns:
EFI_SUCCESS - The Unicode string for the user readable name in the
language specified by Language for the driver
specified by This was returned in DriverName.
EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - ChildHandle isn't NULL and isn't a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - ControllerName is NULL.
EFI_UNSUPPORTED - The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return EFI_UNSUPPORTED;
}

View File

@ -0,0 +1,665 @@
/** @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.c
Abstract:
**/
#include "Dhcp4Impl.h"
#include "Dhcp4Driver.h"
EFI_DRIVER_BINDING_PROTOCOL gDhcp4DriverBinding = {
Dhcp4DriverBindingSupported,
Dhcp4DriverBindingStart,
Dhcp4DriverBindingStop,
0xa,
NULL,
NULL
};
EFI_SERVICE_BINDING_PROTOCOL mDhcp4ServiceBindingTemplete = {
Dhcp4ServiceBindingCreateChild,
Dhcp4ServiceBindingDestroyChild
};
//@MT: EFI_DRIVER_ENTRY_POINT (Dhcp4DriverEntryPoint)
EFI_STATUS
EFIAPI
Dhcp4DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Entry point of the DHCP driver to install various protocols.
Arguments:
ImageHandle - The driver's image handle
SystemTable - The system table
Returns:
EFI_SUCCESS - All the related protocols are installed.
Others - Failed to install the protocols.
--*/
{
return NetLibInstallAllDriverProtocols (
ImageHandle,
SystemTable,
&gDhcp4DriverBinding,
ImageHandle,
&gDhcp4ComponentName,
NULL,
NULL
);
}
/**
Test to see if DHCP driver supports the ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to test
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCES This driver supports this device
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
Dhcp4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiUdp4ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
return Status;
}
/**
Configure the default UDP child to receive all the DHCP traffics
on this network interface.
@param UdpIo The UDP IO port to configure
@param Context The context to the function
@retval EFI_SUCCESS The UDP IO port is successfully configured.
@retval Others Failed to configure the UDP child.
**/
EFI_STATUS
DhcpConfigUdpIo (
IN UDP_IO_PORT *UdpIo,
IN VOID *Context
)
{
EFI_UDP4_CONFIG_DATA UdpConfigData;
UdpConfigData.AcceptBroadcast = TRUE;
UdpConfigData.AcceptPromiscuous = FALSE;
UdpConfigData.AcceptAnyPort = FALSE;
UdpConfigData.AllowDuplicatePort = TRUE;
UdpConfigData.TypeOfService = 0;
UdpConfigData.TimeToLive = 64;
UdpConfigData.DoNotFragment = FALSE;
UdpConfigData.ReceiveTimeout = 0;
UdpConfigData.TransmitTimeout = 0;
UdpConfigData.UseDefaultAddress = FALSE;
UdpConfigData.StationPort = DHCP_CLIENT_PORT;
UdpConfigData.RemotePort = DHCP_SERVER_PORT;
NetZeroMem (&UdpConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
NetZeroMem (&UdpConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
NetZeroMem (&UdpConfigData.RemoteAddress, sizeof (EFI_IPv4_ADDRESS));
return UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);;
}
/**
Destory the DHCP service. The Dhcp4 service may be partly initialized,
or partly destoried. If a resource is destoried, it is marked as so in
case the destory failed and being called again later.
@param DhcpSb The DHCP service instance to destory.
@retval EFI_SUCCESS The DHCP service is successfully closed.
**/
EFI_STATUS
Dhcp4CloseService (
IN DHCP_SERVICE *DhcpSb
)
{
DhcpCleanLease (DhcpSb);
if (DhcpSb->UdpIo != NULL) {
UdpIoFreePort (DhcpSb->UdpIo);
DhcpSb->UdpIo = NULL;
}
if (DhcpSb->Timer != NULL) {
gBS->SetTimer (DhcpSb->Timer, TimerCancel, 0);
gBS->CloseEvent (DhcpSb->Timer);
DhcpSb->Timer = NULL;
}
return EFI_SUCCESS;
}
/**
Create a new DHCP service binding instance for the controller.
@param Controller The controller to install DHCP service binding
protocol onto
@param ImageHandle The driver's image handle
@param Service The variable to receive the created DHCP service
instance.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource .
@retval EFI_SUCCESS The DHCP service instance is created.
**/
EFI_STATUS
Dhcp4CreateService (
IN EFI_HANDLE Controller,
IN EFI_HANDLE ImageHandle,
OUT DHCP_SERVICE **Service
)
{
DHCP_SERVICE *DhcpSb;
EFI_STATUS Status;
*Service = NULL;
DhcpSb = NetAllocateZeroPool (sizeof (DHCP_SERVICE));
if (DhcpSb == NULL) {
return EFI_OUT_OF_RESOURCES;
}
DhcpSb->Signature = DHCP_SERVICE_SIGNATURE;
DhcpSb->ServiceBinding = mDhcp4ServiceBindingTemplete;
DhcpSb->ServiceState = DHCP_UNCONFIGED;
DhcpSb->InDestory = FALSE;
DhcpSb->Controller = Controller;
DhcpSb->Image = ImageHandle;
NetListInit (&DhcpSb->Children);
DhcpSb->DhcpState = Dhcp4Stopped;
DhcpSb->Xid = NET_RANDOM (NetRandomInitSeed ());
//
// Create various resources, UdpIo, Timer, and get Mac address
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL | EVT_TIMER,
TPL_CALLBACK,
DhcpOnTimerTick,
DhcpSb,
&DhcpSb->Timer
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
DhcpSb->UdpIo = UdpIoCreatePort (Controller, ImageHandle, DhcpConfigUdpIo, NULL);
if (DhcpSb->UdpIo == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
DhcpSb->HwLen = (UINT8) DhcpSb->UdpIo->SnpMode.HwAddressSize;
DhcpSb->HwType = DhcpSb->UdpIo->SnpMode.IfType;
CopyMem (&DhcpSb->Mac, &DhcpSb->UdpIo->SnpMode.CurrentAddress, sizeof (EFI_MAC_ADDRESS));
*Service = DhcpSb;
return EFI_SUCCESS;
ON_ERROR:
Dhcp4CloseService (DhcpSb);
NetFreePool (DhcpSb);
return Status;
}
/**
Start this driver on ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to bind driver to
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCES This driver is added to ControllerHandle
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
Dhcp4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
DHCP_SERVICE *DhcpSb;
EFI_STATUS Status;
//
// First: test for the DHCP4 Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiDhcp4ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (Status == EFI_SUCCESS) {
return EFI_ALREADY_STARTED;
}
Status = Dhcp4CreateService (ControllerHandle, This->DriverBindingHandle, &DhcpSb);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->SetTimer (DhcpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
//
// Install the Dhcp4ServiceBinding Protocol onto ControlerHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiDhcp4ServiceBindingProtocolGuid,
&DhcpSb->ServiceBinding,
NULL
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
return Status;
ON_ERROR:
Dhcp4CloseService (DhcpSb);
NetFreePool (DhcpSb);
return Status;
}
/**
Stop this driver on ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to stop driver on
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
of children is zero stop the entire bus driver.
@param ChildHandleBuffer List of Child Handles to Stop.
@retval EFI_SUCCES This driver is removed ControllerHandle
@retval other This driver was not removed from this device
**/
EFI_STATUS
EFIAPI
Dhcp4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
DHCP_SERVICE *DhcpSb;
DHCP_PROTOCOL *Instance;
EFI_HANDLE NicHandle;
EFI_STATUS Status;
EFI_TPL OldTpl;
//
// DHCP driver opens UDP child, So, the ControllerHandle is the
// UDP child handle. locate the Nic handle first.
//
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);
if (NicHandle == NULL) {
return EFI_SUCCESS;
}
Status = gBS->OpenProtocol (
NicHandle,
&gEfiDhcp4ServiceBindingProtocolGuid,
(VOID **) &ServiceBinding,
This->DriverBindingHandle,
NicHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
DhcpSb = DHCP_SERVICE_FROM_THIS (ServiceBinding);
if (DhcpSb->InDestory) {
return EFI_SUCCESS;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
DhcpSb->InDestory = TRUE;
//
// Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild
// may cause other child to be deleted.
//
while (!NetListIsEmpty (&DhcpSb->Children)) {
Instance = NET_LIST_HEAD (&DhcpSb->Children, DHCP_PROTOCOL, Link);
Dhcp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);
}
if (DhcpSb->NumChildren != 0) {
Status = EFI_DEVICE_ERROR;
goto ON_ERROR;
}
DhcpSb->ServiceState = DHCP_DESTORY;
Status = gBS->UninstallProtocolInterface (
NicHandle,
&gEfiDhcp4ServiceBindingProtocolGuid,
ServiceBinding
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Dhcp4CloseService (DhcpSb);
NET_RESTORE_TPL (OldTpl);
NetFreePool (DhcpSb);
return EFI_SUCCESS;
ON_ERROR:
DhcpSb->InDestory = FALSE;
NET_RESTORE_TPL (OldTpl);
return Status;
}
/**
Initialize a new DHCP child
@param DhcpSb The dhcp service instance
@param Instance The dhcp instance to initialize
@return None
**/
VOID
DhcpInitProtocol (
IN DHCP_SERVICE *DhcpSb,
IN DHCP_PROTOCOL *Instance
)
{
Instance->Signature = DHCP_PROTOCOL_SIGNATURE;
CopyMem (&Instance->Dhcp4Protocol, &mDhcp4ProtocolTemplate, sizeof (EFI_DHCP4_PROTOCOL));
NetListInit (&Instance->Link);
Instance->Handle = NULL;
Instance->Service = DhcpSb;
Instance->InDestory = FALSE;
Instance->CompletionEvent = NULL;
Instance->RenewRebindEvent = NULL;
Instance->Token = NULL;
}
/**
Creates a child handle with a set of DHCP4 services.
@param This Protocol instance pointer.
@param ChildHandle Pointer to the handle of the child to create. If
it is NULL, then a new handle is created. If it
is not NULL, then the DHCP4 services are added to
the existing child handle.
@retval EFI_SUCCES The child handle was created with the DHCP4
services
@retval EFI_OUT_OF_RESOURCES There are not enough resources to create the child
@retval other The child handle was not created
**/
EFI_STATUS
EFIAPI
Dhcp4ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
)
{
DHCP_SERVICE *DhcpSb;
DHCP_PROTOCOL *Instance;
EFI_STATUS Status;
EFI_TPL OldTpl;
VOID *Udp4;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
Instance = NetAllocatePool (sizeof (*Instance));
if (Instance == NULL) {
return EFI_OUT_OF_RESOURCES;
}
DhcpSb = DHCP_SERVICE_FROM_THIS (This);
DhcpInitProtocol (DhcpSb, Instance);
//
// Install DHCP4 onto ChildHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiDhcp4ProtocolGuid,
&Instance->Dhcp4Protocol,
NULL
);
if (EFI_ERROR (Status)) {
NetFreePool (Instance);
return Status;
}
Instance->Handle = *ChildHandle;
//
// Open the Udp4 protocol BY_CHILD.
//
Status = gBS->OpenProtocol (
DhcpSb->UdpIo->UdpHandle,
&gEfiUdp4ProtocolGuid,
(VOID **) &Udp4,
gDhcp4DriverBinding.DriverBindingHandle,
Instance->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
gBS->UninstallMultipleProtocolInterfaces (
Instance->Handle,
&gEfiDhcp4ProtocolGuid,
&Instance->Dhcp4Protocol,
NULL
);
NetFreePool (Instance);
return Status;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
NetListInsertTail (&DhcpSb->Children, &Instance->Link);
DhcpSb->NumChildren++;
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
}
/**
Destroys a child handle with a set of DHCP4 services.
@param This Protocol instance pointer.
@param ChildHandle Handle of the child to destroy
@retval EFI_SUCCES The DHCP4 service is removed from the child handle
@retval EFI_UNSUPPORTED The child handle does not support the DHCP4
service
@retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
@retval EFI_ACCESS_DENIED The child handle could not be destroyed because
its DHCP4 services are being used.
@retval other The child handle was not destroyed
**/
EFI_STATUS
EFIAPI
Dhcp4ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
DHCP_SERVICE *DhcpSb;
DHCP_PROTOCOL *Instance;
EFI_DHCP4_PROTOCOL *Dhcp;
EFI_TPL OldTpl;
EFI_STATUS Status;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Retrieve the private context data structures
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiDhcp4ProtocolGuid,
(VOID **) &Dhcp,
gDhcp4DriverBinding.DriverBindingHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Instance = DHCP_INSTANCE_FROM_THIS (Dhcp);
DhcpSb = DHCP_SERVICE_FROM_THIS (This);
if (Instance->Service != DhcpSb) {
return EFI_INVALID_PARAMETER;
}
//
// A child can be destoried more than once. For example,
// Dhcp4DriverBindingStop will destory all of its children.
// when caller driver is being stopped, it will destory the
// dhcp child it opens.
//
if (Instance->InDestory) {
return EFI_SUCCESS;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
Instance->InDestory = TRUE;
//
// Close the Udp4 protocol.
//
gBS->CloseProtocol (
DhcpSb->UdpIo->UdpHandle,
&gEfiUdp4ProtocolGuid,
gDhcp4DriverBinding.DriverBindingHandle,
ChildHandle
);
//
// Uninstall the DHCP4 protocol first to enable a top down destruction.
//
Status = gBS->UninstallProtocolInterface (
ChildHandle,
&gEfiDhcp4ProtocolGuid,
Dhcp
);
if (EFI_ERROR (Status)) {
Instance->InDestory = FALSE;
NET_RESTORE_TPL (OldTpl);
return Status;
}
if (DhcpSb->ActiveChild == Instance) {
DhcpYieldControl (DhcpSb);
}
NetListRemoveEntry (&Instance->Link);
DhcpSb->NumChildren--;
NET_RESTORE_TPL (OldTpl);
NetFreePool (Instance);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,67 @@
/** @file
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Dhcp4Driver.h
Abstract:
Header for the DHCP4 driver
**/
#ifndef __EFI_DHCP4_DRIVER_H__
#define __EFI_DHCP4_DRIVER_H__
extern EFI_COMPONENT_NAME_PROTOCOL gDhcp4ComponentName;
EFI_STATUS
EFIAPI
Dhcp4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
EFI_STATUS
EFIAPI
Dhcp4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
EFI_STATUS
EFIAPI
Dhcp4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
);
EFI_STATUS
EFIAPI
Dhcp4ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
);
EFI_STATUS
EFIAPI
Dhcp4ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
);
#endif

View File

@ -0,0 +1,65 @@
#/** @file
# Component name for module Dhcp4
#
# 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.
#
#
#**/
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Dhcp4Dxe
FILE_GUID = 94734718-0BBC-47fb-96A5-EE7A5AE6A2AD
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = Dhcp4DriverEntryPoint
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources.common]
Dhcp4Impl.c
Dhcp4Io.c
Dhcp4Io.h
ComponentName.c
Dhcp4Driver.h
Dhcp4Driver.c
Dhcp4Option.c
Dhcp4Option.h
Dhcp4Impl.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
BaseLib
UefiLib
UefiBootServicesTableLib
UefiDriverEntryPoint
DebugLib
NetLib
UdpIoLib
[Protocols]
gEfiUdp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiDhcp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiDhcp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED

View File

@ -0,0 +1,77 @@
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>Dhcp4Dxe</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>94734718-0BBC-47fb-96A5-EE7A5AE6A2AD</GuidValue>
<Version>1.0</Version>
<Abstract>Component name for module Dhcp4</Abstract>
<Description>FIX ME!</Description>
<Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
<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>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>Dhcp4Dxe</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>Dhcp4Impl.h</Filename>
<Filename>Dhcp4Option.h</Filename>
<Filename>Dhcp4Option.c</Filename>
<Filename>Dhcp4Driver.c</Filename>
<Filename>Dhcp4Driver.h</Filename>
<Filename>ComponentName.c</Filename>
<Filename>Dhcp4Io.h</Filename>
<Filename>Dhcp4Io.c</Filename>
<Filename>Dhcp4Impl.c</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiDhcp4ProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiUdp4ProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiDhcp4ServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiUdp4ServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>Dhcp4DriverEntryPoint</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

View File

@ -0,0 +1,914 @@
/** @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:
Dhcp4Impl.c
Abstract:
This file implement the EFI_DHCP4_PROTOCOL interface.
**/
#include "Dhcp4Impl.h"
/**
Get the current operation parameter and lease for the network interface.
@param This The DHCP protocol instance
@param Dhcp4ModeData The variable to save the DHCP mode data.
@retval EFI_INVALID_PARAMETER The parameter is invalid
@retval EFI_SUCCESS The Dhcp4ModeData is updated with the current
operation parameter.
**/
STATIC
EFI_STATUS
EFIAPI
EfiDhcp4GetModeData (
IN EFI_DHCP4_PROTOCOL *This,
OUT EFI_DHCP4_MODE_DATA *Dhcp4ModeData
)
{
DHCP_PROTOCOL *Instance;
DHCP_SERVICE *DhcpSb;
DHCP_PARAMETER *Para;
EFI_TPL OldTpl;
IP4_ADDR Ip;
//
// First validate the parameters.
//
if ((This == NULL) || (Dhcp4ModeData == NULL)) {
return EFI_INVALID_PARAMETER;
}
Instance = DHCP_INSTANCE_FROM_THIS (This);
if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
DhcpSb = Instance->Service;
//
// Caller can use GetModeData to retrieve current DHCP states
// no matter whether it is the active child or not.
//
Dhcp4ModeData->State = DhcpSb->DhcpState;
CopyMem (&Dhcp4ModeData->ConfigData, &DhcpSb->ActiveConfig, sizeof (EFI_DHCP4_CONFIG_DATA));
CopyMem (&Dhcp4ModeData->ClientMacAddress, &DhcpSb->Mac, sizeof (EFI_MAC_ADDRESS));
Ip = HTONL (DhcpSb->ClientAddr);
NetCopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
Ip = HTONL (DhcpSb->Netmask);
NetCopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));
Ip = HTONL (DhcpSb->ServerAddr);
NetCopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
Para = DhcpSb->Para;
if (Para != NULL) {
Ip = HTONL (Para->Router);
NetCopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
Dhcp4ModeData->LeaseTime = Para->Lease;
} else {
NetZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS));
Dhcp4ModeData->LeaseTime = 0xffffffff;
}
Dhcp4ModeData->ReplyPacket = DhcpSb->Selected;
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
}
/**
Free the resource related to the configure parameters.
DHCP driver will make a copy of the user's configure
such as the time out value.
@param Config The DHCP configure data
@return None
**/
VOID
DhcpCleanConfigure (
IN EFI_DHCP4_CONFIG_DATA *Config
)
{
UINT32 Index;
if (Config->DiscoverTimeout != NULL) {
NetFreePool (Config->DiscoverTimeout);
}
if (Config->RequestTimeout != NULL) {
NetFreePool (Config->RequestTimeout);
}
if (Config->OptionList != NULL) {
for (Index = 0; Index < Config->OptionCount; Index++) {
if (Config->OptionList[Index] != NULL) {
NetFreePool (Config->OptionList[Index]);
}
}
NetFreePool (Config->OptionList);
}
NetZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA));
}
/**
Allocate memory for configure parameter such as timeout value for Dst,
then copy the configure parameter from Src to Dst.
@param Dst The destination DHCP configure data.
@param Src The source DHCP configure data.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
@retval EFI_SUCCESS The configure is copied.
**/
EFI_STATUS
DhcpCopyConfigure (
IN EFI_DHCP4_CONFIG_DATA *Dst,
IN EFI_DHCP4_CONFIG_DATA *Src
)
{
EFI_DHCP4_PACKET_OPTION **DstOptions;
EFI_DHCP4_PACKET_OPTION **SrcOptions;
INTN Len;
UINT32 Index;
CopyMem (Dst, Src, sizeof (EFI_DHCP4_CONFIG_DATA));
Dst->DiscoverTimeout = NULL;
Dst->RequestTimeout = NULL;
Dst->OptionList = NULL;
//
// Allocate a memory then copy DiscoverTimeout to it
//
if (Src->DiscoverTimeout != NULL) {
Len = Src->DiscoverTryCount * sizeof (UINT32);
Dst->DiscoverTimeout = NetAllocatePool (Len);
if (Dst->DiscoverTimeout == NULL) {
return EFI_OUT_OF_RESOURCES;
}
for (Index = 0; Index < Src->DiscoverTryCount; Index++) {
Dst->DiscoverTimeout[Index] = NET_MAX (Src->DiscoverTimeout[Index], 1);
}
}
//
// Allocate a memory then copy RequestTimeout to it
//
if (Src->RequestTimeout != NULL) {
Len = Src->RequestTryCount * sizeof (UINT32);
Dst->RequestTimeout = NetAllocatePool (Len);
if (Dst->RequestTimeout == NULL) {
goto ON_ERROR;
}
for (Index = 0; Index < Src->RequestTryCount; Index++) {
Dst->RequestTimeout[Index] = NET_MAX (Src->RequestTimeout[Index], 1);
}
}
//
// Allocate an array of dhcp option point, then allocate memory
// for each option and copy the source option to it
//
if (Src->OptionList != NULL) {
Len = Src->OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *);
Dst->OptionList = NetAllocateZeroPool (Len);
if (Dst->OptionList == NULL) {
goto ON_ERROR;
}
DstOptions = Dst->OptionList;
SrcOptions = Src->OptionList;
for (Index = 0; Index < Src->OptionCount; Index++) {
Len = sizeof (EFI_DHCP4_PACKET_OPTION) + NET_MAX (SrcOptions[Index]->Length - 1, 0);
DstOptions[Index] = NetAllocatePool (Len);
if (DstOptions[Index] == NULL) {
goto ON_ERROR;
}
NetCopyMem (DstOptions[Index], SrcOptions[Index], Len);
}
}
return EFI_SUCCESS;
ON_ERROR:
DhcpCleanConfigure (Dst);
return EFI_OUT_OF_RESOURCES;
}
/**
Give up the control of the DHCP service to let other child
resume. Don't change the service's DHCP state and the Client
address and option list configure as required by RFC2131.
@param DhcpSb The DHCP service instance.
@return None
**/
VOID
DhcpYieldControl (
IN DHCP_SERVICE *DhcpSb
)
{
EFI_DHCP4_CONFIG_DATA *Config;
DHCP_PROTOCOL *Instance;
Instance = DhcpSb->ActiveChild;
Config = &DhcpSb->ActiveConfig;
DhcpSb->ServiceState = DHCP_UNCONFIGED;
DhcpSb->ActiveChild = NULL;
if (Config->DiscoverTimeout != NULL) {
NetFreePool (Config->DiscoverTimeout);
Config->DiscoverTryCount = 0;
Config->DiscoverTimeout = NULL;
}
if (Config->RequestTimeout != NULL) {
NetFreePool (Config->RequestTimeout);
Config->RequestTryCount = 0;
Config->RequestTimeout = NULL;
}
Config->Dhcp4Callback = NULL;
Config->CallbackContext = NULL;
}
/**
Configure the DHCP protocol instance and its underlying DHCP service
for operation. If Dhcp4CfgData is NULL and the child is currently
controlling the DHCP service, release the control.
@param This The DHCP protocol instance
@param Dhcp4CfgData The DHCP configure data.
@retval EFI_INVALID_PARAMETER The parameters are invalid.
@retval EFI_ACCESS_DENIED The service isn't in one of configurable states,
or there is already an active child.
@retval EFI_OUT_OF_RESOURCE Failed to allocate some resources.
@retval EFI_SUCCESS The child is configured.
**/
STATIC
EFI_STATUS
EFIAPI
EfiDhcp4Configure (
IN EFI_DHCP4_PROTOCOL *This,
IN EFI_DHCP4_CONFIG_DATA *Dhcp4CfgData OPTIONAL
)
{
EFI_DHCP4_CONFIG_DATA *Config;
DHCP_PROTOCOL *Instance;
DHCP_SERVICE *DhcpSb;
EFI_STATUS Status;
EFI_TPL OldTpl;
UINT32 Index;
IP4_ADDR Ip;
//
// First validate the parameters
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Dhcp4CfgData != NULL) {
if (Dhcp4CfgData->DiscoverTryCount && (Dhcp4CfgData->DiscoverTimeout == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (Dhcp4CfgData->RequestTryCount && (Dhcp4CfgData->RequestTimeout == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (Dhcp4CfgData->OptionCount && (Dhcp4CfgData->OptionList == NULL)) {
return EFI_INVALID_PARAMETER;
}
NetCopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR));
if ((Ip != 0) && !Ip4IsUnicast (NTOHL (Ip), 0)) {
return EFI_INVALID_PARAMETER;
}
}
Instance = DHCP_INSTANCE_FROM_THIS (This);
if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
DhcpSb = Instance->Service;
Config = &DhcpSb->ActiveConfig;
Status = EFI_ACCESS_DENIED;
if ((DhcpSb->DhcpState != Dhcp4Stopped) &&
(DhcpSb->DhcpState != Dhcp4Init) &&
(DhcpSb->DhcpState != Dhcp4InitReboot) &&
(DhcpSb->DhcpState != Dhcp4Bound)) {
goto ON_EXIT;
}
if ((DhcpSb->ActiveChild != NULL) && (DhcpSb->ActiveChild != Instance)) {
goto ON_EXIT;
}
if (Dhcp4CfgData != NULL) {
Status = EFI_OUT_OF_RESOURCES;
DhcpCleanConfigure (Config);
if (EFI_ERROR (DhcpCopyConfigure (Config, Dhcp4CfgData))) {
goto ON_EXIT;
}
DhcpSb->UserOptionLen = 0;
for (Index = 0; Index < Dhcp4CfgData->OptionCount; Index++) {
DhcpSb->UserOptionLen += Dhcp4CfgData->OptionList[Index]->Length + 2;
}
DhcpSb->ActiveChild = Instance;
if (DhcpSb->DhcpState == Dhcp4Stopped) {
DhcpSb->ClientAddr = EFI_NTOHL (Dhcp4CfgData->ClientAddress);
if (DhcpSb->ClientAddr != 0) {
DhcpSb->DhcpState = Dhcp4InitReboot;
} else {
DhcpSb->DhcpState = Dhcp4Init;
}
}
DhcpSb->ServiceState = DHCP_CONFIGED;
Status = EFI_SUCCESS;
} else if (DhcpSb->ActiveChild == Instance) {
Status = EFI_SUCCESS;
DhcpYieldControl (DhcpSb);
}
ON_EXIT:
NET_RESTORE_TPL (OldTpl);
return Status;
}
/**
Start the DHCP process.
@param This The DHCP protocol instance
@param CompletionEvent The event to signal is address is acquired.
@retval EFI_INVALID_PARAMETER The parameters are invalid.
@retval EFI_NOT_STARTED The protocol hasn't been configured.
@retval EFI_ALREADY_STARTED The DHCP process has already been started.
@retval EFI_SUCCESS The DHCP process is started.
**/
STATIC
EFI_STATUS
EFIAPI
EfiDhcp4Start (
IN EFI_DHCP4_PROTOCOL *This,
IN EFI_EVENT CompletionEvent OPTIONAL
)
{
DHCP_PROTOCOL *Instance;
DHCP_SERVICE *DhcpSb;
EFI_STATUS Status;
EFI_TPL OldTpl;
//
// First validate the parameters
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DHCP_INSTANCE_FROM_THIS (This);
if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
DhcpSb = Instance->Service;
if (DhcpSb->DhcpState == Dhcp4Stopped) {
Status = EFI_NOT_STARTED;
goto ON_ERROR;
}
if ((DhcpSb->DhcpState != Dhcp4Init) && (DhcpSb->DhcpState != Dhcp4InitReboot)) {
Status = EFI_ALREADY_STARTED;
goto ON_ERROR;
}
DhcpSb->IoStatus = EFI_ALREADY_STARTED;
if (EFI_ERROR (Status = DhcpInitRequest (DhcpSb))) {
goto ON_ERROR;
}
//
// Start/Restart the receiving.
//
Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
goto ON_ERROR;
}
Instance->CompletionEvent = CompletionEvent;
//
// Restore the TPL now, don't call poll function at NET_TPL_LOCK.
//
NET_RESTORE_TPL (OldTpl);
if (CompletionEvent == NULL) {
while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {
DhcpSb->UdpIo->Udp->Poll (DhcpSb->UdpIo->Udp);
}
return DhcpSb->IoStatus;
}
return EFI_SUCCESS;
ON_ERROR:
NET_RESTORE_TPL (OldTpl);
return Status;
}
/**
Request an extra manual renew/rebind.
@param This The DHCP protocol instance
@param RebindRequest TRUE if request a rebind, otherwise renew it
@param CompletionEvent Event to signal when complete
@retval EFI_INVALID_PARAMETER The parameters are invalid
@retval EFI_NOT_STARTED The DHCP protocol hasn't been started.
@retval EFI_ACCESS_DENIED The DHCP protocol isn't in Bound state.
@retval EFI_SUCCESS The DHCP is renewed/rebound.
**/
STATIC
EFI_STATUS
EFIAPI
EfiDhcp4RenewRebind (
IN EFI_DHCP4_PROTOCOL *This,
IN BOOLEAN RebindRequest,
IN EFI_EVENT CompletionEvent OPTIONAL
)
{
DHCP_PROTOCOL *Instance;
DHCP_SERVICE *DhcpSb;
EFI_STATUS Status;
EFI_TPL OldTpl;
//
// First validate the parameters
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DHCP_INSTANCE_FROM_THIS (This);
if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
DhcpSb = Instance->Service;
if (DhcpSb->DhcpState == Dhcp4Stopped) {
Status = EFI_NOT_STARTED;
goto ON_ERROR;
}
if (DhcpSb->DhcpState != Dhcp4Bound) {
Status = EFI_ACCESS_DENIED;
goto ON_ERROR;
}
if (DHCP_IS_BOOTP (DhcpSb->Para)) {
return EFI_SUCCESS;
}
//
// Transit the states then send a extra DHCP request
//
if (!RebindRequest) {
DhcpSetState (DhcpSb, Dhcp4Renewing, FALSE);
} else {
DhcpSetState (DhcpSb, Dhcp4Rebinding, FALSE);
}
Status = DhcpSendMessage (
DhcpSb,
DhcpSb->Selected,
DhcpSb->Para,
DHCP_MSG_REQUEST,
"Extra renew/rebind by the application"
);
if (EFI_ERROR (Status)) {
DhcpSetState (DhcpSb, Dhcp4Bound, FALSE);
goto ON_ERROR;
}
DhcpSb->ExtraRefresh = TRUE;
DhcpSb->IoStatus = EFI_ALREADY_STARTED;
Instance->RenewRebindEvent = CompletionEvent;
NET_RESTORE_TPL (OldTpl);
if (CompletionEvent == NULL) {
while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {
DhcpSb->UdpIo->Udp->Poll (DhcpSb->UdpIo->Udp);
}
return DhcpSb->IoStatus;
}
return EFI_SUCCESS;
ON_ERROR:
NET_RESTORE_TPL (OldTpl);
return Status;
}
/**
Release the current acquired lease.
@param This The DHCP protocol instance
@retval EFI_INVALID_PARAMETER The parameter is invalid
@retval EFI_DEVICE_ERROR Failed to transmit the DHCP release packet
@retval EFI_ACCESS_DENIED The DHCP service isn't in one of the connected
state.
@retval EFI_SUCCESS The lease is released.
**/
STATIC
EFI_STATUS
EFIAPI
EfiDhcp4Release (
IN EFI_DHCP4_PROTOCOL *This
)
{
DHCP_PROTOCOL *Instance;
DHCP_SERVICE *DhcpSb;
EFI_STATUS Status;
EFI_TPL OldTpl;
//
// First validate the parameters
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DHCP_INSTANCE_FROM_THIS (This);
if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
DhcpSb = Instance->Service;
if ((DhcpSb->DhcpState != Dhcp4InitReboot) && (DhcpSb->DhcpState != Dhcp4Bound)) {
Status = EFI_ACCESS_DENIED;
goto ON_EXIT;
}
if (!DHCP_IS_BOOTP (DhcpSb->Para) && (DhcpSb->DhcpState == Dhcp4Bound)) {
Status = DhcpSendMessage (
DhcpSb,
DhcpSb->Selected,
DhcpSb->Para,
DHCP_MSG_RELEASE,
NULL
);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
}
DhcpCleanLease (DhcpSb);
ON_EXIT:
NET_RESTORE_TPL (OldTpl);
return Status;
}
/**
Stop the current DHCP process. After this, other DHCP child
can gain control of the service, configure and use it.
@param This The DHCP protocol instance
@retval EFI_INVALID_PARAMETER The parameter is invalid.
@retval EFI_SUCCESS The DHCP process is stopped.
**/
STATIC
EFI_STATUS
EFIAPI
EfiDhcp4Stop (
IN EFI_DHCP4_PROTOCOL *This
)
{
DHCP_PROTOCOL *Instance;
DHCP_SERVICE *DhcpSb;
EFI_TPL OldTpl;
//
// First validate the parameters
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = DHCP_INSTANCE_FROM_THIS (This);
if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
DhcpSb = Instance->Service;
DhcpCleanLease (DhcpSb);
DhcpSb->DhcpState = Dhcp4Stopped;
DhcpSb->ServiceState = DHCP_UNCONFIGED;
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
}
/**
Build a new DHCP packet from the seed packet. Options may be deleted or
appended. The caller should free the NewPacket when finished using it.
@param This The DHCP protocol instance.
@param SeedPacket The seed packet to start with
@param DeleteCount The number of options to delete
@param DeleteList The options to delete from the packet
@param AppendCount The number of options to append
@param AppendList The options to append to the packet
@param NewPacket The new packet, allocated and built by this
function.
@retval EFI_INVALID_PARAMETER The parameters are invalid.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory
@retval EFI_SUCCESS The packet is build.
**/
STATIC
EFI_STATUS
EFIAPI
EfiDhcp4Build (
IN EFI_DHCP4_PROTOCOL *This,
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
)
{
//
// First validate the parameters
//
if ((This == NULL) || (NewPacket == NULL)) {
return EFI_INVALID_PARAMETER;
}
if ((SeedPacket == NULL) || (SeedPacket->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||
EFI_ERROR (DhcpValidateOptions (SeedPacket, NULL))) {
return EFI_INVALID_PARAMETER;
}
if (((DeleteCount == 0) && (AppendCount == 0)) ||
((DeleteCount != 0) && (DeleteList == NULL)) ||
((AppendCount != 0) && (AppendList == NULL))) {
return EFI_INVALID_PARAMETER;
}
return DhcpBuild (
SeedPacket,
DeleteCount,
DeleteList,
AppendCount,
AppendList,
NewPacket
);
}
/**
Transmit and receive a packet through this DHCP service.
This is unsupported.
@param This The DHCP protocol instance
@param Token The transmit and receive instance
@retval EFI_UNSUPPORTED It always returns unsupported.
**/
STATIC
EFI_STATUS
EFIAPI
EfiDhcp4TransmitReceive (
IN EFI_DHCP4_PROTOCOL *This,
IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token
)
{
//
// This function is for PXE, leave it for now
//
return EFI_UNSUPPORTED;
}
/**
Callback function for DhcpIterateOptions. This callback sets the
EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point
the individual DHCP option in the packet.
@param Tag The DHCP option type
@param Len length of the DHCP option data
@param Data The DHCP option data
@param Context The context, to pass several parameters in.
@retval EFI_SUCCESS It always returns EFI_SUCCESS
**/
STATIC
EFI_STATUS
Dhcp4ParseCheckOption (
IN UINT8 Tag,
IN UINT8 Len,
IN UINT8 *Data,
IN VOID *Context
)
{
DHCP_PARSE_CONTEXT *Parse;
Parse = (DHCP_PARSE_CONTEXT *) Context;
Parse->Index++;
if (Parse->Index < Parse->OptionCount) {
//
// Use _CR to get the memory position of EFI_DHCP4_PACKET_OPTION for
// the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only
// pass in the point to option data.
//
Parse->Option[Parse->Index - 1] = _CR (Data, EFI_DHCP4_PACKET_OPTION, Data);
}
return EFI_SUCCESS;
}
/**
Parse the DHCP options in the Packet into the PacketOptionList.
User should allocate this array of EFI_DHCP4_PACKET_OPTION points.
@param This The DHCP protocol instance
@param Packet The DHCP packet to parse
@param OptionCount On input, the size of the PacketOptionList; On
output, the actual number of options processed.
@param PacketOptionList The array of EFI_DHCP4_PACKET_OPTION points
@retval EFI_INVALID_PARAMETER The parameters are invalid.
@retval EFI_BUFFER_TOO_SMALL A bigger array of points is needed.
@retval EFI_SUCCESS The options are parsed.
**/
STATIC
EFI_STATUS
EFIAPI
EfiDhcp4Parse (
IN EFI_DHCP4_PROTOCOL *This,
IN EFI_DHCP4_PACKET *Packet,
IN OUT UINT32 *OptionCount,
OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL
)
{
DHCP_PARSE_CONTEXT Context;
EFI_STATUS Status;
//
// First validate the parameters
//
if ((This == NULL) || (Packet == NULL) || (OptionCount == NULL)) {
return EFI_INVALID_PARAMETER;
}
if ((Packet->Size < Packet->Length + 2 * sizeof (UINT32)) ||
(Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||
EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {
return EFI_INVALID_PARAMETER;
}
if ((*OptionCount != 0) && (PacketOptionList == NULL)) {
return EFI_BUFFER_TOO_SMALL;
}
NetZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
Context.Option = PacketOptionList;
Context.OptionCount = *OptionCount;
Context.Index = 0;
Status = DhcpIterateOptions (Packet, Dhcp4ParseCheckOption, &Context);
if (EFI_ERROR (Status)) {
return Status;
}
*OptionCount = Context.Index;
if (Context.Index > Context.OptionCount) {
return EFI_BUFFER_TOO_SMALL;
}
return EFI_SUCCESS;
}
EFI_DHCP4_PROTOCOL mDhcp4ProtocolTemplate = {
EfiDhcp4GetModeData,
EfiDhcp4Configure,
EfiDhcp4Start,
EfiDhcp4RenewRebind,
EfiDhcp4Release,
EfiDhcp4Stop,
EfiDhcp4Build,
EfiDhcp4TransmitReceive,
EfiDhcp4Parse
};

View File

@ -0,0 +1,159 @@
/** @file
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Dhcp4Impl.h
Abstract:
EFI DHCP protocol implementation
RFCs supported are:
RFC 2131: Dynamic Host Configuration Protocol
RFC 2132: DHCP Options and BOOTP Vendor Extensions
RFC 1534: Interoperation Between DHCP and BOOTP
RFC 3396: Encoding Long Options in DHCP
**/
#ifndef __EFI_DHCP4_IMPL_H__
#define __EFI_DHCP4_IMPL_H__
#include <PiDxe.h>
#include <Protocol/Dhcp4.h>
#include <Protocol/Udp4.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
/** @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

View File

@ -0,0 +1,906 @@
/** @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.c
Abstract:
Function to validate, parse, process the DHCP options
**/
#include "Dhcp4Impl.h"
//
// A list of the format of DHCP Options sorted by option tag
// to validate a dhcp message. Refere the comments of the
// DHCP_OPTION_FORMAT structure.
//
STATIC
DHCP_OPTION_FORMAT
DhcpOptionFormats [] = {
{DHCP_TAG_NETMASK, DHCP_OPTION_IP, 1, 1 , TRUE},
{DHCP_TAG_TIME_OFFSET, DHCP_OPTION_INT32, 1, 1 , FALSE},
{DHCP_TAG_ROUTER, DHCP_OPTION_IP, 1, -1 , TRUE},
{DHCP_TAG_TIME_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_NAME_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_DNS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_LOG_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_COOKIE_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_LPR_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_IMPRESS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_RL_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_HOSTNAME, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_BOOTFILE_LEN, DHCP_OPTION_INT16, 1, 1 , FALSE},
{DHCP_TAG_DUMP, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_DOMAINNAME, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_SWAP_SERVER, DHCP_OPTION_IP, 1, 1 , FALSE},
{DHCP_TAG_ROOTPATH, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_EXTEND_PATH, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_IPFORWARD, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP_TAG_NONLOCAL_SRR, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP_TAG_POLICY_SRR, DHCP_OPTION_IPPAIR, 1, -1 , FALSE},
{DHCP_TAG_EMTU, DHCP_OPTION_INT16, 1, 1 , FALSE},
{DHCP_TAG_TTL, DHCP_OPTION_INT8, 1, 1 , FALSE},
{DHCP_TAG_PATHMTU_AGE, DHCP_OPTION_INT32, 1, 1 , FALSE},
{DHCP_TAG_PATHMTU_PLATEAU,DHCP_OPTION_INT16, 1, -1 , FALSE},
{DHCP_TAG_IFMTU, DHCP_OPTION_INT16, 1, 1 , FALSE},
{DHCP_TAG_SUBNET_LOCAL, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP_TAG_BROADCAST, DHCP_OPTION_IP, 1, 1 , FALSE},
{DHCP_TAG_DISCOVER_MASK, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP_TAG_SUPPLY_MASK, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP_TAG_DISCOVER_ROUTE, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP_TAG_ROUTER_SOLICIT, DHCP_OPTION_IP, 1, 1 , FALSE},
{DHCP_TAG_STATIC_ROUTE, DHCP_OPTION_IPPAIR, 1, -1 , FALSE},
{DHCP_TAG_TRAILER, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP_TAG_ARPAGE, DHCP_OPTION_INT32, 1, 1 , FALSE},
{DHCP_TAG_ETHER_ENCAP, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP_TAG_TCP_TTL, DHCP_OPTION_INT8, 1, 1 , FALSE},
{DHCP_TAG_KEEP_INTERVAL, DHCP_OPTION_INT32, 1, 1 , FALSE},
{DHCP_TAG_KEEP_GARBAGE, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP_TAG_NIS_DOMAIN, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_NIS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_NTP_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_VENDOR, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_NBNS, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_NBDD, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_NBTYPE, DHCP_OPTION_INT8, 1, 1 , FALSE},
{DHCP_TAG_NBSCOPE, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_XFONT, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_XDM, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_REQUEST_IP, DHCP_OPTION_IP, 1, 1 , FALSE},
{DHCP_TAG_LEASE, DHCP_OPTION_INT32, 1, 1 , TRUE},
{DHCP_TAG_OVERLOAD, DHCP_OPTION_INT8, 1, 1 , TRUE},
{DHCP_TAG_TYPE, DHCP_OPTION_INT8, 1, 1 , TRUE},
{DHCP_TAG_SERVER_ID, DHCP_OPTION_IP, 1, 1 , TRUE},
{DHCP_TAG_PARA_LIST, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_MESSAGE, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_MAXMSG, DHCP_OPTION_INT16, 1, 1 , FALSE},
{DHCP_TAG_T1, DHCP_OPTION_INT32, 1, 1 , TRUE},
{DHCP_TAG_T2, DHCP_OPTION_INT32, 1, 1 , TRUE},
{DHCP_TAG_VENDOR_CLASS, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_CLIENT_ID, DHCP_OPTION_INT8, 2, -1 , FALSE},
{DHCP_TAG_NISPLUS, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_NISPLUS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_TFTP, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_BOOTFILE, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP_TAG_MOBILEIP, DHCP_OPTION_IP, 0, -1 , FALSE},
{DHCP_TAG_SMTP, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_POP3, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_NNTP, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_WWW, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_FINGER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_IRC, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_STTALK, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_STDA, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP_TAG_CLASSLESS_ROUTE,DHCP_OPTION_INT8, 5, -1 , FALSE},
};
/**
Binary search the DhcpOptionFormats array to find the format
information about a specific option.
@param Tag The option's tag.
@return The point to the option's format, NULL if not found.
**/
STATIC
DHCP_OPTION_FORMAT *
DhcpFindOptionFormat (
IN UINT8 Tag
)
{
INTN Left;
INTN Right;
INTN Middle;
Left = 0;
Right = sizeof (DhcpOptionFormats) / sizeof (DHCP_OPTION_FORMAT) - 1;
while (Right >= Left) {
Middle = (Left + Right) / 2;
if (Tag == DhcpOptionFormats[Middle].Tag) {
return &DhcpOptionFormats[Middle];
}
if (Tag < DhcpOptionFormats[Middle].Tag) {
Right = Middle - 1;
} else {
Left = Middle + 1;
}
}
return NULL;
}
/**
Validate whether a single DHCP option is valid according to its format.
@param Format The option's format
@param OptValue The value of the option
@param Len The length of the option value
@return TRUE is the option is valid, otherwise FALSE.
**/
STATIC
BOOLEAN
DhcpOptionIsValid (
IN DHCP_OPTION_FORMAT *Format,
IN UINT8 *OptValue,
IN INTN Len
)
{
INTN Unit;
INTN Occur;
INTN Index;
Unit = 0;
switch (Format->Type) {
case DHCP_OPTION_SWITCH:
case DHCP_OPTION_INT8:
Unit = 1;
break;
case DHCP_OPTION_INT16:
Unit = 2;
break;
case DHCP_OPTION_INT32:
case DHCP_OPTION_IP:
Unit = 4;
break;
case DHCP_OPTION_IPPAIR:
Unit = 8;
break;
}
ASSERT (Unit != 0);
//
// Validate that the option appears in the full units.
//
if ((Len % Unit) != 0) {
return FALSE;
}
//
// Validate the occurance of the option unit is with in [MinOccur, MaxOccur]
//
Occur = Len / Unit;
if (((Format->MinOccur != -1) && (Occur < Format->MinOccur)) ||
((Format->MaxOccur != -1) && (Occur > Format->MaxOccur))) {
return FALSE;
}
//
// If the option is of type switch, only 0/1 are valid values.
//
if (Format->Type == DHCP_OPTION_SWITCH) {
for (Index = 0; Index < Occur; Index++) {
if ((OptValue[Index] != 0) && (OptValue[Index] != 1)) {
return FALSE;
}
}
}
return TRUE;
}
/**
Extract the client interested options, all the parameters are
converted to host byte order.
@param Tag The DHCP option tag
@param Len The length of the option
@param Data The value of the DHCP option
@param Para The variable to save the interested parameter
@retval EFI_SUCCESS The DHCP option is successfully extracted.
@retval EFI_INVALID_PARAMETER The DHCP option is mal-formated
**/
STATIC
EFI_STATUS
DhcpGetParameter (
IN UINT8 Tag,
IN INTN Len,
IN UINT8 *Data,
IN DHCP_PARAMETER *Para
)
{
switch (Tag) {
case DHCP_TAG_NETMASK:
Para->NetMask = NetGetUint32 (Data);
break;
case DHCP_TAG_ROUTER:
//
// Return the first router to consumer which is the preferred one
//
Para->Router = NetGetUint32 (Data);
break;
case DHCP_TAG_LEASE:
Para->Lease = NetGetUint32 (Data);
break;
case DHCP_TAG_OVERLOAD:
Para->Overload = *Data;
if ((Para->Overload < 1) || (Para->Overload > 3)) {
return EFI_INVALID_PARAMETER;
}
break;
case DHCP_TAG_TYPE:
Para->DhcpType = *Data;
if ((Para->DhcpType < 1) || (Para->DhcpType > 9)) {
return EFI_INVALID_PARAMETER;
}
break;
case DHCP_TAG_SERVER_ID:
Para->ServerId = NetGetUint32 (Data);
break;
case DHCP_TAG_T1:
Para->T1 = NetGetUint32 (Data);
break;
case DHCP_TAG_T2:
Para->T2 = NetGetUint32 (Data);
break;
}
return EFI_SUCCESS;
}
/**
Inspect all the options in a single buffer. DHCP options may be contained
in several buffers, such as the BOOTP options filed, boot file or server
name. Each option buffer is required to end with DHCP_TAG_EOP.
@param Buffer The buffer which contains DHCP options
@param BufLen The length of the buffer
@param Check The callback function for each option found
@param Context The opaque parameter for the Check
@param Overload variable to save the value of DHCP_TAG_OVERLOAD
option.
@retval EFI_SUCCESS All the options are valid
@retval EFI_INVALID_PARAMETER The options are mal-formated.
**/
STATIC
EFI_STATUS
DhcpIterateBufferOptions (
IN UINT8 *Buffer,
IN INTN BufLen,
IN DHCP_CHECK_OPTION Check, OPTIONAL
IN VOID *Context,
OUT UINT8 *Overload OPTIONAL
)
{
INTN Cur;
UINT8 Tag;
UINT8 Len;
Cur = 0;
while (Cur < BufLen) {
Tag = Buffer[Cur];
if (Tag == DHCP_TAG_PAD) {
Cur++;
continue;
} else if (Tag == DHCP_TAG_EOP) {
return EFI_SUCCESS;
}
Cur++;
if (Cur == BufLen) {
return EFI_INVALID_PARAMETER;
}
Len = Buffer[Cur++];
if (Cur + Len > BufLen) {
return EFI_INVALID_PARAMETER;
}
if ((Tag == DHCP_TAG_OVERLOAD) && (Overload != NULL)) {
if (Len != 1) {
return EFI_INVALID_PARAMETER;
}
*Overload = Buffer[Cur];
}
if ((Check != NULL) && EFI_ERROR (Check (Tag, Len, Buffer + Cur, Context))) {
return EFI_INVALID_PARAMETER;
}
Cur += Len;
}
//
// Each option buffer is expected to end with an EOP
//
return EFI_INVALID_PARAMETER;
}
/**
Iterate through a DHCP message to visit each option. First inspect
all the options in the OPTION field. Then if overloaded, inspect
the options in FILENAME and SERVERNAME fields. One option may be
encoded in several places. See RFC 3396 Encoding Long Options in DHCP
@param Packet The DHCP packet to check the options for
@param Check The callback function to be called for each option
found
@param Context The opaque parameter for Check
@retval EFI_SUCCESS The DHCP packet's options are well formated
@retval Others The DHCP packet's options are not well formated
**/
EFI_STATUS
DhcpIterateOptions (
IN EFI_DHCP4_PACKET *Packet,
IN DHCP_CHECK_OPTION Check, OPTIONAL
IN VOID *Context
)
{
EFI_STATUS Status;
UINT8 Overload;
Overload = 0;
Status = DhcpIterateBufferOptions (
Packet->Dhcp4.Option,
Packet->Length - sizeof (EFI_DHCP4_HEADER) - sizeof (UINT32),
Check,
Context,
&Overload
);
if (EFI_ERROR (Status)) {
return Status;
}
if ((Overload == DHCP_OVERLOAD_FILENAME) || (Overload == DHCP_OVERLOAD_BOTH)) {
Status = DhcpIterateBufferOptions (
Packet->Dhcp4.Header.BootFileName,
128,
Check,
Context,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
}
if ((Overload == DHCP_OVERLOAD_SVRNAME) || (Overload == DHCP_OVERLOAD_BOTH)) {
Status = DhcpIterateBufferOptions (
Packet->Dhcp4.Header.ServerName,
64,
Check,
Context,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
}
return EFI_SUCCESS;
}
/**
Call back function to DhcpiterateOptions to compute each option's
length. It just adds the data length of all the occurances of this
Tag. Context is an array of 256 DHCP_OPTION_COUNT.
@param Tag The current option to check
@param Len The length of the option data
@param Data The option data
@param Context The context, which is a array of 256
DHCP_OPTION_COUNT.
@retval EFI_SUCCESS It always returns EFI_SUCCESS.
**/
STATIC
EFI_STATUS
DhcpGetOptionLen (
IN UINT8 Tag,
IN UINT8 Len,
IN UINT8 *Data,
IN VOID *Context
)
{
DHCP_OPTION_COUNT *OpCount;
OpCount = (DHCP_OPTION_COUNT *) Context;
OpCount[Tag].Offset = OpCount[Tag].Offset + Len;
return EFI_SUCCESS;
}
/**
Call back function to DhcpiterateOptions to consolidate each option's
data. There are maybe several occurance of the same option.
@param Tag The option to consolidate its data
@param Len The length of option data
@param Data The data of the option's current occurance
@param Context The context, which is DHCP_OPTION_CONTEXT. This
array is just a wrap to pass THREE parameters.
@retval EFI_SUCCESS It always returns EFI_SUCCESS
**/
STATIC
EFI_STATUS
DhcpFillOption (
IN UINT8 Tag,
IN UINT8 Len,
IN UINT8 *Data,
IN VOID *Context
)
{
DHCP_OPTION_CONTEXT *OptContext;
DHCP_OPTION_COUNT *OptCount;
DHCP_OPTION *Options;
UINT8 *Buf;
UINT8 Index;
OptContext = (DHCP_OPTION_CONTEXT *) Context;
OptCount = OptContext->OpCount;
Index = OptCount[Tag].Index;
Options = OptContext->Options;
Buf = OptContext->Buf;
if (Options[Index].Data == NULL) {
Options[Index].Tag = Tag;
Options[Index].Data = Buf + OptCount[Tag].Offset;
}
NetCopyMem (Buf + OptCount[Tag].Offset, Data, Len);
OptCount[Tag].Offset = OptCount[Tag].Offset + Len;
Options[Index].Len = Options[Index].Len + Len;
return EFI_SUCCESS;
}
/**
Parse the options of a DHCP packet. It supports RFC 3396: Encoding
Long Options in DHCP. That is, it will combine all the option value
of all the occurances of each option.
A little bit of implemenation:
It adopts the "Key indexed counting" algorithm. First, it allocates
an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded
as a UINT8. It then iterates the DHCP packet to get data length of
each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it
knows the number of present options and their length. It allocates a
array of DHCP_OPTION and a continous buffer after the array to put
all the options' data. Each option's data is pointed to by the Data
field in DHCP_OPTION structure. At last, it call DhcpIterateOptions
with DhcpFillOption to fill each option's data to its position in the
buffer.
@param Packet The DHCP packet to parse the options
@param Count The number of valid dhcp options present in the
packet
@param OptionPoint The array that contains the DHCP options. Caller
should free it.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory to parse the packet.
@retval EFI_INVALID_PARAMETER The options are mal-formated
@retval EFI_SUCCESS The options are parsed into OptionPoint
**/
EFI_STATUS
DhcpParseOption (
IN EFI_DHCP4_PACKET *Packet,
OUT INTN *Count,
OUT DHCP_OPTION **OptionPoint
)
{
DHCP_OPTION_CONTEXT Context;
DHCP_OPTION *Options;
DHCP_OPTION_COUNT *OptCount;
EFI_STATUS Status;
UINT16 TotalLen;
INTN OptNum;
INTN Index;
ASSERT ((Count != NULL) && (OptionPoint != NULL));
//
// First compute how many options and how long each option is
// with the "Key indexed counting" algorithms.
//
OptCount = NetAllocateZeroPool (DHCP_MAX_OPTIONS * sizeof (DHCP_OPTION_COUNT));
if (OptCount == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = DhcpIterateOptions (Packet, DhcpGetOptionLen, OptCount);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
//
// Before the loop, Offset is the length of the option. After loop,
// OptCount[Index].Offset specifies the offset into the continuous
// option value buffer to put the data.
//
TotalLen = 0;
OptNum = 0;
for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
if (OptCount[Index].Offset != 0) {
OptCount[Index].Index = (UINT8) OptNum;
TotalLen = TotalLen + OptCount[Index].Offset;
OptCount[Index].Offset = TotalLen - OptCount[Index].Offset;
OptNum++;
}
}
*Count = OptNum;
*OptionPoint = NULL;
if (OptNum == 0) {
goto ON_EXIT;
}
//
// Allocate a buffer to hold the DHCP options, and after that, a
// continuous buffer to put all the options' data.
//
Options = NetAllocateZeroPool (OptNum * sizeof (DHCP_OPTION) + TotalLen);
if (Options == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT;
}
Context.OpCount = OptCount;
Context.Options = Options;
Context.Buf = (UINT8 *) (Options + OptNum);
Status = DhcpIterateOptions (Packet, DhcpFillOption, &Context);
if (EFI_ERROR (Status)) {
NetFreePool (Options);
goto ON_EXIT;
}
*OptionPoint = Options;
ON_EXIT:
NetFreePool (OptCount);
return Status;
}
/**
Validate the packet's options. If necessary, allocate
and fill in the interested parameters.
@param Packet The packet to validate the options
@param Para The variable to save the DHCP parameters.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory to validate the packet.
@retval EFI_INVALID_PARAMETER The options are mal-formated
@retval EFI_SUCCESS The options are parsed into OptionPoint
**/
EFI_STATUS
DhcpValidateOptions (
IN EFI_DHCP4_PACKET *Packet,
OUT DHCP_PARAMETER **Para OPTIONAL
)
{
DHCP_PARAMETER Parameter;
DHCP_OPTION_FORMAT *Format;
DHCP_OPTION *AllOption;
DHCP_OPTION *Option;
EFI_STATUS Status;
BOOLEAN Updated;
INTN Count;
INTN Index;
if (Para != NULL) {
*Para = NULL;
}
AllOption = NULL;
Status = DhcpParseOption (Packet, &Count, &AllOption);
if (EFI_ERROR (Status) || (Count == 0)) {
return Status;
}
Updated = FALSE;
NetZeroMem (&Parameter, sizeof (Parameter));
for (Index = 0; Index < Count; Index++) {
Option = &AllOption[Index];
//
// Find the format of the option then validate it.
//
Format = DhcpFindOptionFormat (Option->Tag);
if (Format == NULL) {
continue;
}
if (!DhcpOptionIsValid (Format, Option->Data, Option->Len)) {
Status = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
//
// Get the client interested parameters
//
if (Format->Alert && (Para != NULL)) {
Updated = TRUE;
Status = DhcpGetParameter (Option->Tag, Option->Len, Option->Data, &Parameter);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
}
}
if (Updated && (Para != NULL)) {
if ((*Para = NetAllocatePool (sizeof (DHCP_PARAMETER))) == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT;
}
CopyMem (*Para, &Parameter, sizeof (DHCP_PARAMETER));
}
ON_EXIT:
NetFreePool (AllOption);
return Status;
}
/**
Append an option to the memory, if the option is longer than
255 bytes, splits it into several options.
@param Buf The buffer to append the option to
@param Tag The option's tag
@param DataLen The length of the option's data
@param Data The option's data
@return The position to append the next option
**/
UINT8 *
DhcpAppendOption (
IN UINT8 *Buf,
IN UINT8 Tag,
IN UINT16 DataLen,
IN UINT8 *Data
)
{
INTN Index;
INTN Len;
ASSERT (DataLen != 0);
for (Index = 0; Index < (DataLen + 254) / 255; Index++) {
Len = NET_MIN (255, DataLen - Index * 255);
*(Buf++) = Tag;
*(Buf++) = (UINT8) Len;
NetCopyMem (Buf, Data + Index * 255, Len);
Buf += Len;
}
return Buf;
}
/**
Build a new DHCP packet from a seed packet. Options may be deleted or
appended. The caller should free the NewPacket when finished using it.
@param SeedPacket The seed packet to start with
@param DeleteCount The number of options to delete
@param DeleteList The options to delete from the packet
@param AppendCount The number of options to append
@param AppendList The options to append to the packet
@param NewPacket The new packet, allocated and built by this
function.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory
@retval EFI_SUCCESS The packet is build.
**/
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
)
{
DHCP_OPTION *Mark;
DHCP_OPTION *SeedOptions;
EFI_DHCP4_PACKET *Packet;
EFI_STATUS Status;
INTN Count;
UINT32 Index;
UINT32 Len;
UINT8 *Buf;
//
// Use an array of DHCP_OPTION to mark the existance
// and position of each valid options.
//
Mark = NetAllocatePool (sizeof (DHCP_OPTION) * DHCP_MAX_OPTIONS);
if (Mark == NULL) {
return EFI_OUT_OF_RESOURCES;
}
for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
Mark[Index].Tag = (UINT8) Index;
Mark[Index].Len = 0;
}
//
// Get list of the options from the seed packet, then put
// them to the mark array according to their tags.
//
SeedOptions = NULL;
Status = DhcpParseOption (SeedPacket, &Count, &SeedOptions);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
for (Index = 0; Index < (UINT32) Count; Index++) {
Mark[SeedOptions[Index].Tag] = SeedOptions[Index];
}
//
// Mark the option's length is zero if it is in the DeleteList.
//
for (Index = 0; Index < DeleteCount; Index++) {
Mark[DeleteList[Index]].Len = 0;
}
//
// Add or replace the option if it is in the append list.
//
for (Index = 0; Index < AppendCount; Index++) {
Mark[AppendList[Index]->OpCode].Len = AppendList[Index]->Length;
Mark[AppendList[Index]->OpCode].Data = AppendList[Index]->Data;
}
//
// compute the new packet length. No need to add 1 byte for
// EOP option since EFI_DHCP4_PACKET includes one extra byte
// for option. It is necessary to split the option if it is
// longer than 255 bytes.
//
Len = sizeof (EFI_DHCP4_PACKET);
for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
if (Mark[Index].Len != 0) {
Len += ((Mark[Index].Len + 254) / 255) * 2 + Mark[Index].Len;
}
}
Status = EFI_OUT_OF_RESOURCES;
Packet = (EFI_DHCP4_PACKET *) NetAllocatePool (Len);
if (Packet == NULL) {
goto ON_ERROR;
}
Packet->Size = Len;
Packet->Length = 0;
CopyMem (&Packet->Dhcp4.Header, &SeedPacket->Dhcp4.Header, sizeof (EFI_DHCP4_HEADER));
Packet->Dhcp4.Magik = DHCP_OPTION_MAGIC;
Buf = Packet->Dhcp4.Option;
for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
if (Mark[Index].Len != 0) {
Buf = DhcpAppendOption (Buf, Mark[Index].Tag, Mark[Index].Len, Mark[Index].Data);
}
}
*(Buf++) = DHCP_TAG_EOP;
Packet->Length = sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)
+ (UINT32) (Buf - Packet->Dhcp4.Option);
*NewPacket = Packet;
Status = EFI_SUCCESS;
ON_ERROR:
if (SeedOptions != NULL) {
NetFreePool (SeedOptions);
}
NetFreePool (Mark);
return Status;
}

View File

@ -0,0 +1,266 @@
/** @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

View File

@ -590,6 +590,8 @@ Ip4ConfigOnDhcp4Complete (
EFI_STATUS Status;
BOOLEAN Perment;
IP4_ADDR Subnet;
IP4_ADDR Ip1;
IP4_ADDR Ip2;
Instance = (IP4_CONFIG_INSTANCE *) Context;
ASSERT (Instance->Dhcp4 != NULL);
@ -641,20 +643,24 @@ Ip4ConfigOnDhcp4Complete (
//
Ip4Config->RouteTableSize = 1;
Subnet = EFI_NTOHL (Dhcp4Mode.ClientAddress) & EFI_NTOHL (Dhcp4Mode.SubnetMask);
NetCopyMem (&Ip1, &Dhcp4Mode.ClientAddress, sizeof (IP4_ADDR));
NetCopyMem (&Ip2, &Dhcp4Mode.SubnetMask, sizeof (IP4_ADDR));
EFI_IP4 (Ip4Config->RouteTable[0].SubnetAddress) = HTONL (Subnet);
Ip4Config->RouteTable[0].SubnetMask = Dhcp4Mode.SubnetMask;
EFI_IP4 (Ip4Config->RouteTable[0].GatewayAddress) = 0;
Subnet = Ip1 & Ip2;
NetCopyMem (&Ip4Config->RouteTable[0].SubnetAddress, &Subnet, sizeof (EFI_IPv4_ADDRESS));
NetCopyMem (&Ip4Config->RouteTable[0].SubnetMask, &Dhcp4Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
NetZeroMem (&Ip4Config->RouteTable[0].GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
//
// Create a route if there is a default router.
//
if (EFI_IP4 (Dhcp4Mode.RouterAddress) != 0) {
if (!EFI_IP4_EQUAL (Dhcp4Mode.RouterAddress, mZeroIp4Addr)) {
Ip4Config->RouteTableSize = 2;
EFI_IP4 (Ip4Config->RouteTable[1].SubnetAddress) = 0;
EFI_IP4 (Ip4Config->RouteTable[1].SubnetMask) = 0;
Ip4Config->RouteTable[1].GatewayAddress = Dhcp4Mode.RouterAddress;
NetZeroMem (&Ip4Config->RouteTable[1].SubnetAddress, sizeof (EFI_IPv4_ADDRESS));
NetZeroMem (&Ip4Config->RouteTable[1].SubnetMask, sizeof (EFI_IPv4_ADDRESS));
NetCopyMem (&Ip4Config->RouteTable[1].GatewayAddress, &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
}
Instance->Result = EFI_SUCCESS;

View File

@ -60,7 +60,6 @@ EfiIp4ConfigUnload (
return NetLibDefaultUnload (ImageHandle);
}
//@MT: EFI_DRIVER_ENTRY_POINT (Ip4ConfigDriverEntryPoint)
EFI_STATUS
Ip4ConfigDriverEntryPoint (

View File

@ -0,0 +1,166 @@
/** @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:
ComponentName.c
Abstract:
**/
#include "Ip4Impl.h"
//
// EFI Component Name Functions
//
EFI_STATUS
EFIAPI
Ip4ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
EFI_STATUS
EFIAPI
Ip4ComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
//
// EFI Component Name Protocol
//
EFI_COMPONENT_NAME_PROTOCOL gIp4ComponentName = {
Ip4ComponentNameGetDriverName,
Ip4ComponentNameGetControllerName,
"eng"
};
static EFI_UNICODE_STRING_TABLE mIp4DriverNameTable[] = {
{
"eng",
L"IP4 Network Service Driver"
},
{
NULL,
NULL
}
};
EFI_STATUS
EFIAPI
Ip4ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable
name of the EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
Language - A pointer to a three character ISO 639-2 language
identifier. This is the language of the driver name
that that the caller is requesting, and it must match
one of the languages specified in SupportedLanguages.
The number of languages supported by a driver is up to
the driver writer.
DriverName - A pointer to the Unicode string to return. This Unicode
string is the name of the driver specified by This in the
language specified by Language.
Returns:
EFI_SUCCES - The Unicode string for the Driver specified by This
and the language specified by Language was returned
in DriverName.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - DriverName is NULL.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return LookupUnicodeString (
Language,
gIp4ComponentName.SupportedLanguages,
mIp4DriverNameTable,
DriverName
);
}
EFI_STATUS
EFIAPI
Ip4ComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of
the controller that is being managed by an EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
ControllerHandle - The handle of a controller that the driver specified by
This is managing. This handle specifies the controller
whose name is to be returned.
ChildHandle - The handle of the child controller to retrieve the name
of. This is an optional parameter that may be NULL. It
will be NULL for device drivers. It will also be NULL
for a bus drivers that wish to retrieve the name of the
bus controller. It will not be NULL for a bus driver
that wishes to retrieve the name of a child controller.
Language - A pointer to a three character ISO 639-2 language
identifier. This is the language of the controller name
that that the caller is requesting, and it must match one
of the languages specified in SupportedLanguages. The
number of languages supported by a driver is up to the
driver writer.
ControllerName - A pointer to the Unicode string to return. This Unicode
string is the name of the controller specified by
ControllerHandle and ChildHandle in the language
specified by Language from the point of view of the
driver specified by This.
Returns:
EFI_SUCCESS - The Unicode string for the user readable name in the
language specified by Language for the driver
specified by This was returned in DriverName.
EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not
a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - ControllerName is NULL.
EFI_UNSUPPORTED - The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return EFI_UNSUPPORTED;
}

View File

@ -0,0 +1,421 @@
/** @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.c
Abstract:
**/
#include "Ip4Impl.h"
/**
Return the cast type (Unicast/Boradcast) specific to a
interface. All the addresses are host byte ordered.
@param IpAddr The IP address to classify in host byte order
@param IpIf The interface that IpAddr received from
@return The cast type of this IP address specific to the interface.
@retval IP4_LOCAL_HOST The IpAddr equals to the interface's address
@retval IP4_SUBNET_BROADCAST The IpAddr is a directed subnet boradcast to the
interface
@retval IP4_NET_BROADCAST The IpAddr is a network broadcast to the interface
**/
INTN
Ip4GetNetCast (
IN IP4_ADDR IpAddr,
IN IP4_INTERFACE *IpIf
)
{
if (IpAddr == IpIf->Ip) {
return IP4_LOCAL_HOST;
} else if (IpAddr == IpIf->SubnetBrdcast) {
return IP4_SUBNET_BROADCAST;
} else if (IpAddr == IpIf->NetBrdcast) {
return IP4_NET_BROADCAST;
}
return 0;
}
/**
Find the cast type of the packet related to the local host.
This isn't the same as link layer cast type. For example, DHCP
server may send local broadcast to the local unicast MAC.
@param IpSb The IP4 service binding instance that received the
packet
@param Dst The destination address in the packet (host byte
order)
@param Src The source address in the packet (host byte order)
@return The cast type for the Dst, it will return on the first non-promiscuous
@return cast type to a configured interface. If the packet doesn't match any of
@return the interface, multicast address and local broadcast address are checked.
**/
INTN
Ip4GetHostCast (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Dst,
IN IP4_ADDR Src
)
{
NET_LIST_ENTRY *Entry;
IP4_INTERFACE *IpIf;
INTN Type;
INTN Class;
Type = 0;
if (IpSb->MnpConfigData.EnablePromiscuousReceive) {
Type = IP4_PROMISCUOUS;
}
//
// Go through the interface list of the IP service, most likely.
//
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
//
// Skip the unconfigured interface and invalid source address:
// source address can't be broadcast.
//
if (!IpIf->Configured || IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
continue;
}
if ((Class = Ip4GetNetCast (Dst, IpIf)) > Type) {
return Class;
}
}
//
// If it is local broadcast address. The source address must
// be a unicast address on one of the direct connected network.
// If it is a multicast address, accept it only if we are in
// the group.
//
if (Dst == IP4_ALLONE_ADDRESS) {
IpIf = Ip4FindNet (IpSb, Src);
if (IpIf && !IP4_IS_BROADCAST (Ip4GetNetCast (Src, IpIf))) {
return IP4_LOCAL_BROADCAST;
}
} else if (IP4_IS_MULTICAST (Dst) && Ip4FindGroup (&IpSb->IgmpCtrl, Dst)) {
return IP4_MULTICAST;
}
return Type;
}
/**
Find an interface whose configured IP address is Ip
@param IpSb The IP4 service binding instance
@param Ip The Ip address (host byte order) to find
@return The IP4_INTERFACE point if found, otherwise NULL
**/
IP4_INTERFACE *
Ip4FindInterface (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Ip
)
{
NET_LIST_ENTRY *Entry;
IP4_INTERFACE *IpIf;
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
if (IpIf->Configured && (IpIf->Ip == Ip)) {
return IpIf;
}
}
return NULL;
}
/**
Find an interface that Ip is on that connected network.
@param IpSb The IP4 service binding instance
@param Ip The Ip address (host byte order) to find
@return The IP4_INTERFACE point if found, otherwise NULL
**/
IP4_INTERFACE *
Ip4FindNet (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Ip
)
{
NET_LIST_ENTRY *Entry;
IP4_INTERFACE *IpIf;
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
if (IpIf->Configured && IP4_NET_EQUAL (Ip, IpIf->Ip, IpIf->SubnetMask)) {
return IpIf;
}
}
return NULL;
}
/**
Find an interface of the service with the same Ip/Netmask pair.
@param IpSb Ip4 service binding instance
@param Ip The Ip adress to find (host byte order)
@param Netmask The network to find (host byte order)
@return The IP4_INTERFACE point if found, otherwise NULL
**/
IP4_INTERFACE *
Ip4FindStationAddress (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Ip,
IN IP4_ADDR Netmask
)
{
NET_LIST_ENTRY *Entry;
IP4_INTERFACE *IpIf;
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
if (IpIf->Configured && (IpIf->Ip == Ip) && (IpIf->SubnetMask == Netmask)) {
return IpIf;
}
}
return NULL;
}
/**
Get the MAC address for a multicast IP address. Call
Mnp's McastIpToMac to find the MAC address in stead of
hard code the NIC to be Ethernet.
@param Mnp The Mnp instance to get the MAC address.
@param Multicast The multicast IP address to translate.
@param Mac The buffer to hold the translated address.
@return Returns EFI_SUCCESS if the multicast IP is successfully
@return translated to a multicast MAC address. Otherwise some error.
**/
EFI_STATUS
Ip4GetMulticastMac (
IN EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
IN IP4_ADDR Multicast,
OUT EFI_MAC_ADDRESS *Mac
)
{
EFI_IP_ADDRESS EfiIp;
EFI_IP4 (EfiIp.v4) = HTONL (Multicast);
return Mnp->McastIpToMac (Mnp, FALSE, &EfiIp, Mac);
}
/**
Convert the multibyte field in IP header's byter order.
In spite of its name, it can also be used to convert from
host to network byte order.
@param Head The IP head to convert
@return Point to the converted IP head
**/
IP4_HEAD *
Ip4NtohHead (
IN IP4_HEAD *Head
)
{
Head->TotalLen = NTOHS (Head->TotalLen);
Head->Id = NTOHS (Head->Id);
Head->Fragment = NTOHS (Head->Fragment);
Head->Src = NTOHL (Head->Src);
Head->Dst = NTOHL (Head->Dst);
return Head;
}
/**
Set the Ip4 variable data.
@param IpSb Ip4 service binding instance
@retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.
@retval other Set variable failed.
**/
EFI_STATUS
Ip4SetVariableData (
IN IP4_SERVICE *IpSb
)
{
UINT32 NumConfiguredInstance;
NET_LIST_ENTRY *Entry;
UINTN VariableDataSize;
EFI_IP4_VARIABLE_DATA *Ip4VariableData;
EFI_IP4_ADDRESS_PAIR *Ip4AddressPair;
IP4_PROTOCOL *IpInstance;
CHAR16 *NewMacString;
EFI_STATUS Status;
NumConfiguredInstance = 0;
//
// Go through the children list to count the configured children.
//
NET_LIST_FOR_EACH (Entry, &IpSb->Children) {
IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);
if (IpInstance->State == IP4_STATE_CONFIGED) {
NumConfiguredInstance++;
}
}
//
// Calculate the size of the Ip4VariableData. As there may be no IP child,
// we should add extra buffer for the address paris only if the number of configured
// children is more than 1.
//
VariableDataSize = sizeof (EFI_IP4_VARIABLE_DATA);
if (NumConfiguredInstance > 1) {
VariableDataSize += sizeof (EFI_IP4_ADDRESS_PAIR) * (NumConfiguredInstance - 1);
}
Ip4VariableData = NetAllocatePool (VariableDataSize);
if (Ip4VariableData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Ip4VariableData->DriverHandle = IpSb->Image;
Ip4VariableData->AddressCount = NumConfiguredInstance;
Ip4AddressPair = &Ip4VariableData->AddressPairs[0];
//
// Go through the children list to fill the configured children's address pairs.
//
NET_LIST_FOR_EACH (Entry, &IpSb->Children) {
IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);
if (IpInstance->State == IP4_STATE_CONFIGED) {
Ip4AddressPair->InstanceHandle = IpInstance->Handle;
EFI_IP4 (Ip4AddressPair->Ip4Address) = NTOHL (IpInstance->Interface->Ip);
EFI_IP4 (Ip4AddressPair->SubnetMask) = NTOHL (IpInstance->Interface->SubnetMask);
Ip4AddressPair++;
}
}
//
// Get the mac string.
//
Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &NewMacString);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
if (IpSb->MacString != NULL) {
//
// The variable is set already, we're going to update it.
//
if (StrCmp (IpSb->MacString, NewMacString) != 0) {
//
// The mac address is changed, delete the previous variable first.
//
gRT->SetVariable (
IpSb->MacString,
&gEfiIp4ServiceBindingProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
0,
NULL
);
}
NetFreePool (IpSb->MacString);
}
IpSb->MacString = NewMacString;
Status = gRT->SetVariable (
IpSb->MacString,
&gEfiIp4ServiceBindingProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
VariableDataSize,
(VOID *) Ip4VariableData
);
ON_ERROR:
NetFreePool (Ip4VariableData);
return Status;
}
/**
Clear the variable and free the resource.
@param IpSb Ip4 service binding instance
@return None.
**/
VOID
Ip4ClearVariableData (
IN IP4_SERVICE *IpSb
)
{
ASSERT (IpSb->MacString != NULL);
gRT->SetVariable (
IpSb->MacString,
&gEfiIp4ServiceBindingProtocolGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
0,
NULL
);
NetFreePool (IpSb->MacString);
IpSb->MacString = NULL;
}

View File

@ -0,0 +1,143 @@
/** @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

View File

@ -0,0 +1,932 @@
/** @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:
Ip4Driver.c
Abstract:
The driver binding and service binding protocol for IP4 driver.
**/
#include "Ip4Impl.h"
EFI_DRIVER_BINDING_PROTOCOL gIp4DriverBinding = {
Ip4DriverBindingSupported,
Ip4DriverBindingStart,
Ip4DriverBindingStop,
0xa,
NULL,
NULL
};
//@MT: EFI_DRIVER_ENTRY_POINT (Ip4DriverEntryPoint)
EFI_STATUS
EFIAPI
Ip4DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
The entry point for IP4 driver which install the driver
binding and component name protocol on its image.
Arguments:
ImageHandle - The image handle of the driver
SystemTable - The system table
Returns:
EFI_SUCCESS if the driver binding and component name protocols
are successfully installed, otherwise if failed.
--*/
{
return NetLibInstallAllDriverProtocols (
ImageHandle,
SystemTable,
&gIp4DriverBinding,
ImageHandle,
&gIp4ComponentName,
NULL,
NULL
);
}
/**
Test to see if this driver supports ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to test
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCES This driver supports this device
@retval EFI_ALREADY_STARTED This driver is already running on this device
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
Ip4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL * This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
//
// Test for the MNP service binding Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Test for the Arp service binding Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiArpServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
return Status;
}
STATIC
EFI_STATUS
Ip4CleanService (
IN IP4_SERVICE *IpSb
);
/**
Create a new IP4 driver service binding protocol
@param Controller The controller that has MNP service binding
installed
@param ImageHandle The IP4 driver's image handle
@param Service The variable to receive the newly created IP4
service.
@retval EFI_OUT_OF_RESOURCES Failed to allocate some resource
@retval EFI_SUCCESS A new IP4 service binding private is created.
**/
STATIC
EFI_STATUS
Ip4CreateService (
IN EFI_HANDLE Controller,
IN EFI_HANDLE ImageHandle,
OUT IP4_SERVICE **Service
)
{
IP4_SERVICE *IpSb;
EFI_STATUS Status;
ASSERT (Service != NULL);
*Service = NULL;
//
// allocate a service private data then initialize all the filed to
// empty resources, so if any thing goes wrong when allocating
// resources, Ip4CleanService can be called to clean it up.
//
IpSb = NetAllocatePool (sizeof (IP4_SERVICE));
if (IpSb == NULL) {
return EFI_OUT_OF_RESOURCES;
}
IpSb->Signature = IP4_SERVICE_SIGNATURE;
IpSb->ServiceBinding.CreateChild = Ip4ServiceBindingCreateChild;
IpSb->ServiceBinding.DestroyChild = Ip4ServiceBindingDestroyChild;
IpSb->State = IP4_SERVICE_UNSTARTED;
IpSb->InDestory = FALSE;
IpSb->NumChildren = 0;
NetListInit (&IpSb->Children);
NetListInit (&IpSb->Interfaces);
IpSb->DefaultInterface = NULL;
IpSb->DefaultRouteTable = NULL;
Ip4InitAssembleTable (&IpSb->Assemble);
IpSb->IgmpCtrl.Igmpv1QuerySeen = 0;
NetListInit (&IpSb->IgmpCtrl.Groups);
IpSb->Image = ImageHandle;
IpSb->Controller = Controller;
IpSb->MnpChildHandle = NULL;
IpSb->Mnp = NULL;
IpSb->MnpConfigData.ReceivedQueueTimeoutValue = 0;
IpSb->MnpConfigData.TransmitQueueTimeoutValue = 0;
IpSb->MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO;
IpSb->MnpConfigData.EnableUnicastReceive = TRUE;
IpSb->MnpConfigData.EnableMulticastReceive = TRUE;
IpSb->MnpConfigData.EnableBroadcastReceive = TRUE;
IpSb->MnpConfigData.EnablePromiscuousReceive = FALSE;
IpSb->MnpConfigData.FlushQueuesOnReset = TRUE;
IpSb->MnpConfigData.EnableReceiveTimestamps = FALSE;
IpSb->MnpConfigData.DisableBackgroundPolling = FALSE;
NetZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));
IpSb->Timer = NULL;
IpSb->Ip4Config = NULL;
IpSb->DoneEvent = NULL;
IpSb->ReconfigEvent = NULL;
//
// Create various resources. First create the route table, timer
// event and MNP child. IGMP, interface's initialization depend
// on the MNP child.
//
IpSb->DefaultRouteTable = Ip4CreateRouteTable ();
if (IpSb->DefaultRouteTable == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL | EVT_TIMER,
TPL_CALLBACK,
Ip4TimerTicking,
IpSb,
&IpSb->Timer
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = NetLibCreateServiceChild (
Controller,
ImageHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
&IpSb->MnpChildHandle
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = gBS->OpenProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
(VOID **) &IpSb->Mnp,
ImageHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip4ServiceConfigMnp (IpSb, TRUE);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip4InitIgmp (IpSb);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
IpSb->DefaultInterface = Ip4CreateInterface (IpSb->Mnp, Controller, ImageHandle);
if (IpSb->DefaultInterface == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
NetListInsertHead (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);
IpSb->MacString = NULL;
*Service = IpSb;
return EFI_SUCCESS;
ON_ERROR:
Ip4CleanService (IpSb);
NetFreePool (IpSb);
return Status;
}
/**
Clean up a IP4 service binding instance. It will release all
the resource allocated by the instance. The instance may be
partly initialized, or partly destoried. If a resource is
destoried, it is marked as that in case the destory failed and
being called again later.
@param IpSb The IP4 serviceing binding instance to clean up
@retval EFI_SUCCESS The resource used by the instance are cleaned up
@retval Others Failed to clean up some of the resources.
**/
EFI_STATUS
Ip4CleanService (
IN IP4_SERVICE *IpSb
)
{
EFI_STATUS Status;
if (IpSb->DefaultInterface != NULL) {
Status = Ip4FreeInterface (IpSb->DefaultInterface, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
IpSb->DefaultInterface = NULL;
}
if (IpSb->DefaultRouteTable != NULL) {
Ip4FreeRouteTable (IpSb->DefaultRouteTable);
IpSb->DefaultRouteTable = NULL;
}
Ip4CleanAssembleTable (&IpSb->Assemble);
if (IpSb->MnpChildHandle != NULL) {
if (IpSb->Mnp) {
gBS->CloseProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
IpSb->Image,
IpSb->Controller
);
IpSb->Mnp = NULL;
}
NetLibDestroyServiceChild (
IpSb->Controller,
IpSb->Image,
&gEfiManagedNetworkServiceBindingProtocolGuid,
IpSb->MnpChildHandle
);
IpSb->MnpChildHandle = NULL;
}
if (IpSb->Timer != NULL) {
gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
gBS->CloseEvent (IpSb->Timer);
IpSb->Timer = NULL;
}
if (IpSb->Ip4Config != NULL) {
IpSb->Ip4Config->Stop (IpSb->Ip4Config);
gBS->CloseProtocol (
IpSb->Controller,
&gEfiIp4ConfigProtocolGuid,
IpSb->Image,
IpSb->Controller
);
gBS->CloseEvent (IpSb->DoneEvent);
gBS->CloseEvent (IpSb->ReconfigEvent);
IpSb->Ip4Config = NULL;
}
return EFI_SUCCESS;
}
/**
Start this driver on ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to bind driver to
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCES This driver is added to ControllerHandle
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
Ip4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL * This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
)
{
IP4_SERVICE *IpSb;
EFI_STATUS Status;
//
// Test for the Ip4 service binding protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (Status == EFI_SUCCESS) {
return EFI_ALREADY_STARTED;
}
Status = Ip4CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Install the Ip4ServiceBinding Protocol onto ControlerHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
&IpSb->ServiceBinding,
NULL
);
if (EFI_ERROR (Status)) {
goto FREE_SERVICE;
}
//
// ready to go: start the receiving and timer
//
Status = Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);
if (EFI_ERROR (Status)) {
goto UNINSTALL_PROTOCOL;
}
Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
if (EFI_ERROR (Status)) {
goto UNINSTALL_PROTOCOL;
}
//
// Initialize the IP4 ID
//
mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());
Ip4SetVariableData (IpSb);
return Status;
UNINSTALL_PROTOCOL:
gBS->UninstallProtocolInterface (
ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
&IpSb->ServiceBinding
);
FREE_SERVICE:
Ip4CleanService (IpSb);
NetFreePool (IpSb);
return Status;
}
/**
Stop this driver on ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to stop driver on
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
of children is zero stop the entire bus driver.
@param ChildHandleBuffer List of Child Handles to Stop.
@retval EFI_SUCCES This driver is removed ControllerHandle
@retval other This driver was not removed from this device
**/
EFI_STATUS
EFIAPI
Ip4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
IP4_SERVICE *IpSb;
IP4_PROTOCOL *IpInstance;
EFI_HANDLE NicHandle;
EFI_STATUS Status;
EFI_TPL OldTpl;
INTN State;
//
// IP4 driver opens the MNP child, ARP children or the IP4_CONFIG protocol
// by driver. So the ControllerHandle may be the MNP child handle, ARP child
// handle, or the NIC (UNDI) handle because IP4_CONFIG protocol is installed
// in the NIC handle.
//
//
// First, check whether it is the IP4_CONFIG protocol being uninstalled.
// IP4_CONFIG protocol is installed on the NIC handle. It isn't necessary
// to clean up the default configuration if IP4_CONFIG is being stopped.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp4ConfigProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (Status == EFI_SUCCESS) {
//
// Retrieve the IP4 service binding protocol. If failed, it is
// likely that Ip4 ServiceBinding is uninstalled already. In this
// case, return immediately.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
(VOID **) &ServiceBinding,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
if (IpSb->Ip4Config && (IpSb->State != IP4_SERVICE_DESTORY)) {
IpSb->Ip4Config->Stop (IpSb->Ip4Config);
Status = gBS->CloseProtocol (
ControllerHandle,
&gEfiIp4ConfigProtocolGuid,
IpSb->Image,
ControllerHandle
);
if (EFI_ERROR (Status)) {
NET_RESTORE_TPL (OldTpl);
return Status;
}
//
// If the auto configure hasn't complete, mark it as not started.
//
if (IpSb->State == IP4_SERVICE_STARTED) {
IpSb->State = IP4_SERVICE_UNSTARTED;
}
IpSb->Ip4Config = NULL;
gBS->CloseEvent (IpSb->DoneEvent);
gBS->CloseEvent (IpSb->ReconfigEvent);
}
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
}
//
// Either MNP or ARP protocol is being uninstalled. The controller
// handle is either the MNP child or ARP child. But, the IP4's
// service binding is installed on the NIC handle. So, need to open
// the protocol info to find the NIC handle.
//
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
if (NicHandle == NULL) {
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
}
if (NicHandle == NULL) {
return EFI_SUCCESS;
}
//
// Retrieve the IP4 service binding protocol
//
Status = gBS->OpenProtocol (
NicHandle,
&gEfiIp4ServiceBindingProtocolGuid,
(VOID **) &ServiceBinding,
This->DriverBindingHandle,
NicHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
if (IpSb->InDestory) {
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
}
IpSb->InDestory = TRUE;
State = IpSb->State;
IpSb->State = IP4_SERVICE_DESTORY;
//
// Destory all the children first. If not all children are destoried,
// the IP driver can operate correctly, so restore it state. Don't
// use NET_LIST_FOR_EACH_SAFE here, because it will cache the next
// pointer, which may point to the child that has already been destoried.
// For example, if there are two child in the list, the first is UDP
// listen child, the send is the MTFTP's child. When Udp child is
// destoried, it will destory the MTFTP's child. Then Next point to
// a invalid child.
//
while (!NetListIsEmpty (&IpSb->Children)) {
IpInstance = NET_LIST_HEAD (&IpSb->Children, IP4_PROTOCOL, Link);
Ip4ServiceBindingDestroyChild (ServiceBinding, IpInstance->Handle);
}
if (IpSb->NumChildren != 0) {
IpSb->State = State;
Status = EFI_DEVICE_ERROR;
goto ON_ERROR;
}
//
// Clear the variable data.
//
Ip4ClearVariableData (IpSb);
//
// OK, clean other resources then uninstall the service binding protocol.
//
Status = Ip4CleanService (IpSb);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = gBS->UninstallProtocolInterface (
NicHandle,
&gEfiIp4ServiceBindingProtocolGuid,
ServiceBinding
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
NET_RESTORE_TPL (OldTpl);
NetFreePool (IpSb);
return EFI_SUCCESS;
ON_ERROR:
IpSb->InDestory = FALSE;
NET_RESTORE_TPL (OldTpl);
return Status;
}
/**
Creates a child handle with a set of I/O services.
@param This Protocol instance pointer.
@param ChildHandle Pointer to the handle of the child to create. If
it is NULL, then a new handle is created. If it
is not NULL, then the I/O services are added to
the existing child handle.
@retval EFI_SUCCES The child handle was created with the I/O services
@retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
the child
@retval other The child handle was not created
**/
EFI_STATUS
EFIAPI
Ip4ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
)
{
IP4_SERVICE *IpSb;
IP4_PROTOCOL *IpInstance;
EFI_TPL OldTpl;
EFI_STATUS Status;
VOID *Mnp;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
IpInstance = NetAllocatePool (sizeof (IP4_PROTOCOL));
if (IpInstance == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Ip4InitProtocol (IpSb, IpInstance);
//
// Install Ip4 onto ChildHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiIp4ProtocolGuid,
&IpInstance->Ip4Proto,
NULL
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
IpInstance->Handle = *ChildHandle;
//
// Open the Managed Network protocol BY_CHILD.
//
Status = gBS->OpenProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
(VOID **) &Mnp,
gIp4DriverBinding.DriverBindingHandle,
IpInstance->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
gBS->UninstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiIp4ProtocolGuid,
&IpInstance->Ip4Proto,
NULL
);
goto ON_ERROR;
}
//
// Insert it into the service binding instance.
//
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
NetListInsertTail (&IpSb->Children, &IpInstance->Link);
IpSb->NumChildren++;
NET_RESTORE_TPL (OldTpl);
ON_ERROR:
if (EFI_ERROR (Status)) {
Ip4CleanProtocol (IpInstance);
NetFreePool (IpInstance);
}
return Status;
}
/**
Destroys a child handle with a set of I/O services.
@param This Protocol instance pointer.
@param ChildHandle Handle of the child to destroy
@retval EFI_SUCCES The I/O services were removed from the child
handle
@retval EFI_UNSUPPORTED The child handle does not support the I/O services
that are being removed
@retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
@retval EFI_ACCESS_DENIED The child handle could not be destroyed because
its I/O services are being used.
@retval other The child handle was not destroyed
**/
EFI_STATUS
EFIAPI
Ip4ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
EFI_STATUS Status;
IP4_SERVICE *IpSb;
IP4_PROTOCOL *IpInstance;
EFI_IP4_PROTOCOL *Ip4;
EFI_TPL OldTpl;
INTN State;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Retrieve the private context data structures
//
IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiIp4ProtocolGuid,
(VOID **) &Ip4,
gIp4DriverBinding.DriverBindingHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);
if (IpInstance->Service != IpSb) {
return EFI_INVALID_PARAMETER;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
//
// A child can be destoried more than once. For example,
// Ip4DriverBindingStop will destory all of its children.
// when UDP driver is being stopped, it will destory all
// the IP child it opens.
//
if (IpInstance->State == IP4_STATE_DESTORY) {
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
}
State = IpInstance->State;
IpInstance->State = IP4_STATE_DESTORY;
//
// Close the Managed Network protocol.
//
gBS->CloseProtocol (
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
gIp4DriverBinding.DriverBindingHandle,
ChildHandle
);
//
// Uninstall the IP4 protocol first. Many thing happens during
// this:
// 1. The consumer of the IP4 protocol will be stopped if it
// opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
// stopped, IP driver's stop function will be called, and uninstall
// EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
// makes it possible to create the network stack bottom up, and
// stop it top down.
// 2. the upper layer will recycle the received packet. The recycle
// event's TPL is higher than this function. The recycle events
// will be called back before preceeding. If any packets not recycled,
// that means there is a resource leak.
//
Status = gBS->UninstallProtocolInterface (
ChildHandle,
&gEfiIp4ProtocolGuid,
&IpInstance->Ip4Proto
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip4CleanProtocol (IpInstance);
Ip4SetVariableData (IpSb);
if (EFI_ERROR (Status)) {
gBS->InstallMultipleProtocolInterfaces (
&ChildHandle,
&gEfiIp4ProtocolGuid,
Ip4,
NULL
);
goto ON_ERROR;
}
NetListRemoveEntry (&IpInstance->Link);
IpSb->NumChildren--;
NET_RESTORE_TPL (OldTpl);
NetFreePool (IpInstance);
return EFI_SUCCESS;
ON_ERROR:
IpInstance->State = State;
NET_RESTORE_TPL (OldTpl);
return Status;
}

View File

@ -0,0 +1,84 @@
/** @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

View File

@ -0,0 +1,81 @@
#/** @file
# Component name for module Ip4
#
# 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.
#
#
#**/
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Ip4Dxe
FILE_GUID = 9FB1A1F3-3B71-4324-B39A-745CBB015FFF
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = Ip4DriverEntryPoint
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources.common]
Ip4Driver.c
Ip4Option.h
Ip4Route.h
Ip4If.c
Ip4Igmp.h
Ip4Output.c
Ip4Icmp.c
Ip4Igmp.c
Ip4Impl.c
Ip4Common.h
Ip4Impl.h
Ip4Driver.h
Ip4Common.c
Ip4If.h
Ip4Option.c
Ip4Output.h
ComponentName.c
Ip4Input.h
Ip4Route.c
Ip4Icmp.h
Ip4Input.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiLib
BaseLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
DebugLib
NetLib
[Protocols]
gEfiIp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiManagedNetworkServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiIp4ConfigProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiArpServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiIp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiManagedNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiArpProtocolGuid # PROTOCOL ALWAYS_CONSUMED

View File

@ -0,0 +1,101 @@
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>Ip4Dxe</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>9FB1A1F3-3B71-4324-B39A-745CBB015FFF</GuidValue>
<Version>1.0</Version>
<Abstract>Component name for module Ip4</Abstract>
<Description>FIX ME!</Description>
<Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
<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>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>Ip4Dxe</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiRuntimeServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>Ip4Input.c</Filename>
<Filename>Ip4Icmp.h</Filename>
<Filename>Ip4Route.c</Filename>
<Filename>Ip4Input.h</Filename>
<Filename>ComponentName.c</Filename>
<Filename>Ip4Output.h</Filename>
<Filename>Ip4Option.c</Filename>
<Filename>Ip4If.h</Filename>
<Filename>Ip4Common.c</Filename>
<Filename>Ip4Driver.h</Filename>
<Filename>Ip4Impl.h</Filename>
<Filename>Ip4Common.h</Filename>
<Filename>Ip4Impl.c</Filename>
<Filename>Ip4Igmp.c</Filename>
<Filename>Ip4Icmp.c</Filename>
<Filename>Ip4Output.c</Filename>
<Filename>Ip4Igmp.h</Filename>
<Filename>Ip4If.c</Filename>
<Filename>Ip4Route.h</Filename>
<Filename>Ip4Option.h</Filename>
<Filename>Ip4Driver.c</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiArpProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiManagedNetworkProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiIp4ServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiArpServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiIp4ConfigProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiManagedNetworkServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiIp4ProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>Ip4DriverEntryPoint</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

View File

@ -0,0 +1,372 @@
/** @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.c
Abstract:
**/
#include "Ip4Impl.h"
IP4_ICMP_CLASS
mIcmpClass[] = {
{ICMP_ECHO_REPLY, ICMP_QUERY_MESSAGE },
{1, ICMP_INVALID_MESSAGE},
{2, ICMP_INVALID_MESSAGE},
{ICMP_DEST_UNREACHABLE, ICMP_ERROR_MESSAGE },
{ICMP_SOURCE_QUENCH, ICMP_ERROR_MESSAGE },
{ICMP_REDIRECT, ICMP_ERROR_MESSAGE },
{6, ICMP_INVALID_MESSAGE},
{7, ICMP_INVALID_MESSAGE},
{ICMP_ECHO_REQUEST, ICMP_QUERY_MESSAGE },
{9, ICMP_INVALID_MESSAGE},
{10, ICMP_INVALID_MESSAGE},
{ICMP_TIME_EXCEEDED, ICMP_ERROR_MESSAGE },
{ICMP_PARAMETER_PROBLEM, ICMP_ERROR_MESSAGE },
{ICMP_TIMESTAMP , ICMP_QUERY_MESSAGE },
{14, ICMP_INVALID_MESSAGE},
{ICMP_INFO_REQUEST , ICMP_QUERY_MESSAGE },
{ICMP_INFO_REPLY , ICMP_QUERY_MESSAGE },
};
EFI_IP4_ICMP_TYPE
mIp4SupportedIcmp [23] = {
{ICMP_ECHO_REPLY, ICMP_DEFAULT_CODE },
{ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE },
{ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE },
{ICMP_DEST_UNREACHABLE, ICMP_PROTO_UNREACHABLE },
{ICMP_DEST_UNREACHABLE, ICMP_PORT_UNREACHABLE },
{ICMP_DEST_UNREACHABLE, ICMP_FRAGMENT_FAILED },
{ICMP_DEST_UNREACHABLE, ICMP_SOURCEROUTE_FAILED},
{ICMP_DEST_UNREACHABLE, ICMP_NET_UNKNOWN },
{ICMP_DEST_UNREACHABLE, ICMP_HOST_UNKNOWN },
{ICMP_DEST_UNREACHABLE, ICMP_SOURCE_ISOLATED },
{ICMP_DEST_UNREACHABLE, ICMP_NET_PROHIBITED },
{ICMP_DEST_UNREACHABLE, ICMP_HOST_PROHIBITED },
{ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE_TOS },
{ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE_TOS},
{ICMP_SOURCE_QUENCH, ICMP_DEFAULT_CODE },
{ICMP_REDIRECT, ICMP_NET_REDIRECT },
{ICMP_REDIRECT, ICMP_HOST_REDIRECT },
{ICMP_REDIRECT, ICMP_NET_TOS_REDIRECT },
{ICMP_REDIRECT, ICMP_HOST_TOS_REDIRECT },
{ICMP_ECHO_REQUEST, ICMP_DEFAULT_CODE },
{ICMP_TIME_EXCEEDED, ICMP_TIMEOUT_IN_TRANSIT},
{ICMP_TIME_EXCEEDED, ICMp_TIMEOUT_REASSEMBLE},
{ICMP_PARAMETER_PROBLEM, ICMP_DEFAULT_CODE },
};
/**
Process the ICMP redirect. Find the instance then update
its route cache.
All kinds of redirect is treated as host redirect as
specified by RFC1122 3.3.1.2:
"Since the subnet mask appropriate to the destination
address is generally not known, a Network Redirect
message SHOULD be treated identically to a Host Redirect
message;"
@param IpSb The IP4 service binding instance that received the
packet
@param Head The IP head of the received ICMPpacket.
@param Packet The content of the ICMP redirect packet with IP
head removed.
@param Icmp The buffer to store the ICMP error message if
something is wrong.
@retval EFI_INVALID_PARAMETER The parameter is invalid
@retval EFI_SUCCESS Successfully updated the route caches
**/
STATIC
EFI_STATUS
Ip4ProcessIcmpRedirect (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet,
IN IP4_ICMP_ERROR_HEAD *Icmp
)
{
NET_LIST_ENTRY *Entry;
IP4_PROTOCOL *Ip4Instance;
IP4_ROUTE_CACHE_ENTRY *CacheEntry;
IP4_INTERFACE *IpIf;
IP4_ADDR Gateway;
//
// Find the interface whose IP address is the source of the
// orgianl IP packet.
//
IpIf = Ip4FindInterface (IpSb, NTOHL (Icmp->IpHead.Src));
Gateway = NTOHL (Icmp->Fourth);
//
// discard the packet if the new gateway address it specifies
// is not on the same connected net through which the Redirect
// arrived. (RFC1122 3.2.2.2).
//
if ((IpIf == NULL) || !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask)) {
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}
//
// Update each IP child's route cache on the interface.
//
NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);
if (Ip4Instance->RouteTable == NULL) {
continue;
}
CacheEntry = Ip4FindRouteCache (
Ip4Instance->RouteTable,
NTOHL (Icmp->IpHead.Dst),
NTOHL (Icmp->IpHead.Src)
);
//
// Only update the route cache's gateway if the source of the
// Redirect is the current first-hop gateway
//
if ((CacheEntry != NULL) && (NTOHL (Head->Src) == CacheEntry->NextHop)) {
CacheEntry->NextHop = Gateway;
}
}
NetbufFree (Packet);
return EFI_SUCCESS;
}
/**
Process the ICMP error packet. If it is an ICMP redirect packet,
update call Ip4ProcessIcmpRedirect to update the IP instance's
route cache, otherwise, deliver the packet to upper layer.
@param IpSb The IP service that received the packet.
@param Head The IP head of the ICMP error packet
@param Packet The content of the ICMP error with IP head
removed.
@retval EFI_INVALID_PARAMETER The packet is invalid
@retval Others Failed to process the packet.
@retval EFI_SUCCESS The ICMP error is processed successfully.
**/
STATIC
EFI_STATUS
Ip4ProcessIcmpError (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
{
IP4_ICMP_ERROR_HEAD Icmp;
if (Packet->TotalSize < sizeof (Icmp)) {
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}
NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
//
// If it is an ICMP redirect error, update the route cache
// as RFC1122. Otherwise, demultiplex it to IP instances.
//
if (Icmp.Head.Type == ICMP_REDIRECT) {
return Ip4ProcessIcmpRedirect (IpSb, Head, Packet, &Icmp);
}
IP4_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;
return Ip4Demultiplex (IpSb, Head, Packet);
}
/**
Replay an ICMP echo request.
@param IpSb The IP service that receivd the packet
@param Head The IP head of the ICMP error packet
@param Packet The content of the ICMP error with IP head
removed.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
@retval EFI_SUCCESS The ICMP Echo request is successfully answered.
@retval Others Failed to answer the ICMP echo request.
**/
EFI_STATUS
Ip4IcmpReplyEcho (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
{
IP4_ICMP_QUERY_HEAD *Icmp;
NET_BUF *Data;
EFI_STATUS Status;
IP4_HEAD ReplyHead;
//
// make a copy the packet, it is really a bad idea to
// send the MNP's buffer back to MNP.
//
Data = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN);
if (Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT;
}
//
// Change the ICMP type to echo reply, exchange the source
// and destination, then send it. The source is updated to
// use specific destination. See RFC1122. SRR/RR option
// update is omitted.
//
Icmp = (IP4_ICMP_QUERY_HEAD *) NetbufGetByte (Data, 0, NULL);
Icmp->Head.Type = ICMP_ECHO_REPLY;
Icmp->Head.Checksum = 0;
Icmp->Head.Checksum = ~NetblockChecksum ((UINT8 *) Icmp, Data->TotalSize);
ReplyHead.Tos = 0;
ReplyHead.Fragment = 0;
ReplyHead.Ttl = 64;
ReplyHead.Protocol = IP4_PROTO_ICMP;
ReplyHead.Src = 0;
//
// Ip4Output will select a source for us
//
ReplyHead.Dst = Head->Src;
Status = Ip4Output (
IpSb,
NULL,
Data,
&ReplyHead,
NULL,
0,
IP4_ALLZERO_ADDRESS,
Ip4SysPacketSent,
NULL
);
ON_EXIT:
NetbufFree (Packet);
return Status;
}
/**
Process the ICMP query message. If it is an ICMP echo
request, answer it. Otherwise deliver it to upper layer.
@param IpSb The IP service that receivd the packet
@param Head The IP head of the ICMP query packet
@param Packet The content of the ICMP query with IP head
removed.
@retval EFI_INVALID_PARAMETER The packet is invalid
@retval EFI_SUCCESS The ICMP query message is processed
**/
EFI_STATUS
Ip4ProcessIcmpQuery (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
{
IP4_ICMP_QUERY_HEAD Icmp;
if (Packet->TotalSize < sizeof (Icmp)) {
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}
NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
if (Icmp.Head.Type == ICMP_ECHO_REQUEST) {
return Ip4IcmpReplyEcho (IpSb, Head, Packet);
}
return Ip4Demultiplex (IpSb, Head, Packet);
}
/**
Handle the ICMP packet. First validate the message format,
then according to the message types, process it as query or
error packet.
@param IpSb The IP service that receivd the packet
@param Head The IP head of the ICMP query packet
@param Packet The content of the ICMP query with IP head
removed.
@retval EFI_INVALID_PARAMETER The packet is malformated.
@retval EFI_SUCCESS The ICMP message is successfully processed.
**/
EFI_STATUS
Ip4IcmpHandle (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
{
IP4_ICMP_HEAD Icmp;
UINT16 Checksum;
if (Packet->TotalSize < sizeof (Icmp)) {
goto DROP;
}
NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
if (Icmp.Type > ICMP_TYPE_MAX) {
goto DROP;
}
Checksum = ~NetbufChecksum (Packet);
if ((Icmp.Checksum != 0) && (Checksum != 0)) {
goto DROP;
}
if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_ERROR_MESSAGE) {
return Ip4ProcessIcmpError (IpSb, Head, Packet);
} else if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_QUERY_MESSAGE) {
return Ip4ProcessIcmpQuery (IpSb, Head, Packet);
}
DROP:
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}

View File

@ -0,0 +1,99 @@
/** @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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,238 @@
/** @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

View File

@ -0,0 +1,629 @@
/** @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.c
Abstract:
This file implements the RFC2236: IGMP v2
**/
#include "Ip4Impl.h"
//
// Route Alert option in IGMP report to direct routers to
// examine the packet more closely.
//
UINT32 mRouteAlertOption = 0x00000494;
/**
Init the IGMP control data of the IP4 service instance, configure
MNP to receive ALL SYSTEM multicast.
@param IpSb The IP4 service whose IGMP is to be initialized.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to initialize IGMP.
@retval Others Failed to initialize the IGMP of IpSb.
@retval EFI_SUCCESS IGMP of the IpSb is successfully initialized.
**/
EFI_STATUS
Ip4InitIgmp (
IN IP4_SERVICE *IpSb
)
{
IGMP_SERVICE_DATA *IgmpCtrl;
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
IGMP_GROUP *Group;
EFI_STATUS Status;
IgmpCtrl = &IpSb->IgmpCtrl;
//
// Configure MNP to receive ALL_SYSTEM multicast
//
Group = NetAllocatePool (sizeof (IGMP_GROUP));
if (Group == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Mnp = IpSb->Mnp;
Group->Address = IP4_ALLSYSTEM_ADDRESS;
Group->RefCnt = 1;
Group->DelayTime = 0;
Group->ReportByUs = FALSE;
Status = Ip4GetMulticastMac (Mnp, IP4_ALLSYSTEM_ADDRESS, &Group->Mac);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Mnp->Groups (Mnp, TRUE, &Group->Mac);
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
goto ON_ERROR;
}
NetListInsertHead (&IgmpCtrl->Groups, &Group->Link);
return EFI_SUCCESS;
ON_ERROR:
NetFreePool (Group);
return Status;
}
/**
Find the IGMP_GROUP structure which contains the status of multicast
group Address in this IGMP control block
@param IgmpCtrl The IGMP control block to search from
@param Address The multicast address to search
@return NULL if the multicast address isn't in the IGMP control block. Otherwise
@return the point to the IGMP_GROUP which contains the status of multicast group
@return for Address.
**/
IGMP_GROUP *
Ip4FindGroup (
IN IGMP_SERVICE_DATA *IgmpCtrl,
IN IP4_ADDR Address
)
{
NET_LIST_ENTRY *Entry;
IGMP_GROUP *Group;
NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);
if (Group->Address == Address) {
return Group;
}
}
return NULL;
}
/**
Count the number of IP4 multicast groups that are mapped to the
same MAC address. Several IP4 multicast address may be mapped to
the same MAC address.
@param IgmpCtrl The IGMP control block to search in
@param Mac The MAC address to search
@return The number of the IP4 multicast group that mapped to the same
@return multicast group Mac.
**/
INTN
Ip4FindMac (
IN IGMP_SERVICE_DATA *IgmpCtrl,
IN EFI_MAC_ADDRESS *Mac
)
{
NET_LIST_ENTRY *Entry;
IGMP_GROUP *Group;
INTN Count;
Count = 0;
NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);
if (NET_MAC_EQUAL (&Group->Mac, Mac, sizeof (EFI_MAC_ADDRESS))) {
Count++;
}
}
return Count;
}
/**
Send an IGMP protocol message to the Dst, such as IGMP v1 membership report.
@param IpSb The IP4 service instance that requests the
transmission
@param Dst The destinaton to send to
@param Type The IGMP message type, such as IGMP v2 membership
report
@param Group The group address in the IGMP message head.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory to build the message
@retval EFI_SUCCESS The IGMP message is successfully send
@retval Others Failed to send the IGMP message.
**/
EFI_STATUS
Ip4SendIgmpMessage (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Dst,
IN UINT8 Type,
IN IP4_ADDR Group
)
{
IP4_HEAD Head;
NET_BUF *Packet;
IGMP_HEAD *Igmp;
//
// Allocate a net buffer to hold the message
//
Packet = NetbufAlloc (IP4_MAX_HEADLEN + sizeof (IGMP_HEAD));
if (Packet == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Fill in the IGMP and IP header, then transmit the message
//
NetbufReserve (Packet, IP4_MAX_HEADLEN);
Igmp = (IGMP_HEAD *) NetbufAllocSpace (Packet, sizeof (IGMP_HEAD), FALSE);
Igmp->Type = Type;
Igmp->MaxRespTime = 0;
Igmp->Checksum = 0;
Igmp->Group = HTONL (Group);
Igmp->Checksum = ~NetblockChecksum ((UINT8 *) Igmp, sizeof (IGMP_HEAD));
Head.Tos = 0;
Head.Protocol = IP4_PROTO_IGMP;
Head.Ttl = 1;
Head.Fragment = 0;
Head.Dst = Dst;
Head.Src = IP4_ALLZERO_ADDRESS;
return Ip4Output (
IpSb,
NULL,
Packet,
&Head,
(UINT8 *) &mRouteAlertOption,
sizeof (UINT32),
IP4_ALLZERO_ADDRESS,
Ip4SysPacketSent,
NULL
);
}
/**
Send an IGMP membership report. Depends on whether the server is
v1 or v2, it will send either a V1 or V2 membership report.
@param IpSb The IP4 service instance that requests the
transmission.
@param Group The group address to report
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory to build the message
@retval EFI_SUCCESS The IGMP report message is successfully send
@retval Others Failed to send the report.
**/
EFI_STATUS
Ip4SendIgmpReport (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Group
)
{
if (IpSb->IgmpCtrl.Igmpv1QuerySeen != 0) {
return Ip4SendIgmpMessage (IpSb, Group, IGMP_V1_MEMBERSHIP_REPORT, Group);
} else {
return Ip4SendIgmpMessage (IpSb, Group, IGMP_V2_MEMBERSHIP_REPORT, Group);
}
}
/**
Join the multicast group on behavior of this IP4 child
@param IpInstance The IP4 child that wants to join the group
@param Address The group to join
@retval EFI_SUCCESS Successfully join the multicast group
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources
@retval Others Failed to join the multicast group.
**/
EFI_STATUS
Ip4JoinGroup (
IN IP4_PROTOCOL *IpInstance,
IN IP4_ADDR Address
)
{
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
IP4_SERVICE *IpSb;
IGMP_SERVICE_DATA *IgmpCtrl;
IGMP_GROUP *Group;
EFI_STATUS Status;
IpSb = IpInstance->Service;
IgmpCtrl = &IpSb->IgmpCtrl;
Mnp = IpSb->Mnp;
//
// If the IP service already is a member in the group, just
// increase the refernce count and return.
//
Group = Ip4FindGroup (IgmpCtrl, Address);
if (Group != NULL) {
Group->RefCnt++;
return EFI_SUCCESS;
}
//
// Otherwise, create a new IGMP_GROUP, Get the multicast's MAC address,
// send a report, then direct MNP to receive the multicast.
//
Group = NetAllocatePool (sizeof (IGMP_GROUP));
if (Group == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Group->Address = Address;
Group->RefCnt = 1;
Group->DelayTime = IGMP_UNSOLICIATED_REPORT;
Group->ReportByUs = TRUE;
Status = Ip4GetMulticastMac (Mnp, Address, &Group->Mac);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Ip4SendIgmpReport (IpSb, Address);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = Mnp->Groups (Mnp, TRUE, &Group->Mac);
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
goto ON_ERROR;
}
NetListInsertHead (&IgmpCtrl->Groups, &Group->Link);
return EFI_SUCCESS;
ON_ERROR:
NetFreePool (Group);
return Status;
}
/**
Leave the IP4 multicast group on behavior of IpInstance.
@param IpInstance The IP4 child that wants to leave the group
address
@param Address The group address to leave
@retval EFI_NOT_FOUND The IP4 service instance isn't in the group
@retval EFI_SUCCESS Successfully leave the multicast group.
@retval Others Failed to leave the multicast group.
**/
EFI_STATUS
Ip4LeaveGroup (
IN IP4_PROTOCOL *IpInstance,
IN IP4_ADDR Address
)
{
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
IP4_SERVICE *IpSb;
IGMP_SERVICE_DATA *IgmpCtrl;
IGMP_GROUP *Group;
EFI_STATUS Status;
IpSb = IpInstance->Service;
IgmpCtrl = &IpSb->IgmpCtrl;
Mnp = IpSb->Mnp;
Group = Ip4FindGroup (IgmpCtrl, Address);
if (Group == NULL) {
return EFI_NOT_FOUND;
}
//
// If more than one instance is in the group, decrease
// the RefCnt then return.
//
if (--Group->RefCnt > 0) {
return EFI_SUCCESS;
}
//
// If multiple IP4 group addresses are mapped to the same
// multicast MAC address, don't configure the MNP to leave
// the MAC.
//
if (Ip4FindMac (IgmpCtrl, &Group->Mac) == 1) {
Status = Mnp->Groups (Mnp, FALSE, &Group->Mac);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
return Status;
}
}
//
// Send a leave report if the membership is reported by us
// and we are talking IGMPv2.
//
if (Group->ReportByUs && !IgmpCtrl->Igmpv1QuerySeen) {
Ip4SendIgmpMessage (IpSb, IP4_ALLROUTER_ADDRESS, IGMP_LEAVE_GROUP, Group->Address);
}
NetListRemoveEntry (&Group->Link);
NetFreePool (Group);
return EFI_SUCCESS;
}
/**
Handle the received IGMP message for the IP4 service instance.
@param IpSb The IP4 service instance that received the message
@param Head The IP4 header of the received message
@param Packet The IGMP message, without IP4 header
@retval EFI_INVALID_PARAMETER The IGMP message is malformated.
@retval EFI_SUCCESS The IGMP message is successfully processed.
**/
EFI_STATUS
Ip4IgmpHandle (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
{
IGMP_SERVICE_DATA *IgmpCtrl;
IGMP_HEAD Igmp;
IGMP_GROUP *Group;
IP4_ADDR Address;
NET_LIST_ENTRY *Entry;
IgmpCtrl = &IpSb->IgmpCtrl;
//
// Must checksum over the whole packet, later IGMP version
// may employ message longer than 8 bytes. IP's header has
// already been trimmed off.
//
if ((Packet->TotalSize < sizeof (Igmp)) || (NetbufChecksum (Packet) != 0)) {
NetbufFree (Packet);
return EFI_INVALID_PARAMETER;
}
//
// Copy the packet in case it is fragmented
//
NetbufCopy (Packet, 0, sizeof (IGMP_HEAD), (UINT8 *)&Igmp);
switch (Igmp.Type) {
case IGMP_MEMBERSHIP_QUERY:
//
// If MaxRespTIme is zero, it is most likely that we are
// talking to a V1 router
//
if (Igmp.MaxRespTime == 0) {
IgmpCtrl->Igmpv1QuerySeen = IGMP_V1ROUTER_PRESENT;
Igmp.MaxRespTime = 100;
}
//
// Igmp is ticking once per second but MaxRespTime is in
// the unit of 100ms.
//
Igmp.MaxRespTime /= 10;
Address = NTOHL (Igmp.Group);
if (Address == IP4_ALLSYSTEM_ADDRESS) {
break;
}
NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);
//
// If address is all zero, all the memberships will be reported.
// otherwise only one is reported.
//
if ((Address == IP4_ALLZERO_ADDRESS) || (Address == Group->Address)) {
//
// If the timer is pending, only update it if the time left
// is longer than the MaxRespTime. TODO: randomize the DelayTime.
//
if ((Group->DelayTime == 0) || (Group->DelayTime > Igmp.MaxRespTime)) {
Group->DelayTime = NET_MAX (1, Igmp.MaxRespTime);
}
}
}
break;
case IGMP_V1_MEMBERSHIP_REPORT:
case IGMP_V2_MEMBERSHIP_REPORT:
Address = NTOHL (Igmp.Group);
Group = Ip4FindGroup (IgmpCtrl, Address);
if ((Group != NULL) && (Group->DelayTime > 0)) {
Group->DelayTime = 0;
Group->ReportByUs = FALSE;
}
break;
}
NetbufFree (Packet);
return EFI_SUCCESS;
}
/**
The periodical timer function for IGMP. It does the following
things:
1. Decrease the Igmpv1QuerySeen to make it possible to refresh
the IGMP server type.
2. Decrease the report timer for each IGMP group in "delaying
member" state.
@param IpSb The IP4 service instance that is ticking
@return None
**/
VOID
Ip4IgmpTicking (
IN IP4_SERVICE *IpSb
)
{
IGMP_SERVICE_DATA *IgmpCtrl;
NET_LIST_ENTRY *Entry;
IGMP_GROUP *Group;
IgmpCtrl = &IpSb->IgmpCtrl;
if (IgmpCtrl->Igmpv1QuerySeen > 0) {
IgmpCtrl->Igmpv1QuerySeen--;
}
//
// Decrease the report timer for each IGMP group in "delaying member"
//
NET_LIST_FOR_EACH (Entry, &IgmpCtrl->Groups) {
Group = NET_LIST_USER_STRUCT (Entry, IGMP_GROUP, Link);
ASSERT (Group->DelayTime >= 0);
if (Group->DelayTime > 0) {
Group->DelayTime--;
if (Group->DelayTime == 0) {
Ip4SendIgmpReport (IpSb, Group->Address);
Group->ReportByUs = TRUE;
}
}
}
}
/**
Add a group address to the array of group addresses.
The caller should make sure that no duplicated address
existed in the array. Although the function doesn't
assume the byte order of the both Source and Addr, the
network byte order is used by the caller.
@param Source The array of group addresses to add to
@param Count The number of group addresses in the Source
@param Addr The IP4 multicast address to add
@return NULL if failed to allocate memory for the new groups,
@return otherwise the new combined group addresses.
**/
IP4_ADDR *
Ip4CombineGroups (
IN IP4_ADDR *Source,
IN UINT32 Count,
IN IP4_ADDR Addr
)
{
IP4_ADDR *Groups;
Groups = NetAllocatePool (sizeof (IP4_ADDR) * (Count + 1));
if (Groups == NULL) {
return NULL;
}
NetCopyMem (Groups, Source, Count * sizeof (IP4_ADDR));
Groups[Count] = Addr;
return Groups;
}
/**
Remove a group address frome the array of group addresses.
Although the function doesn't assume the byte order of the
both Groups and Addr, the network byte order is used by
the caller.
@param Groups The array of group addresses to remove from
@param Count The number of group addresses in the Groups
@param Addr The IP4 multicast address to remove
@return The nubmer of group addresses in the Groups after remove.
@return It is Count if the Addr isn't in the Groups.
**/
INTN
Ip4RemoveGroupAddr (
IN IP4_ADDR *Groups,
IN UINT32 Count,
IN IP4_ADDR Addr
)
{
UINT32 Index;
for (Index = 0; Index < Count; Index++) {
if (Groups[Index] == Addr) {
break;
}
}
while (Index < Count - 1) {
Groups[Index] = Groups[Index + 1];
Index++;
}
return Index;
}

View File

@ -0,0 +1,120 @@
/** @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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,258 @@
/** @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>
#include <Protocol/IP4.h>
#include <Protocol/IP4Config.h>
#include <Protocol/Arp.h>
#include <Protocol/ManagedNetwork.h>
#include <Library/DebugLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseLib.h>
#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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
/** @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

View File

@ -0,0 +1,231 @@
/** @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.c
Abstract:
IP4 option support functions
**/
#include "Ip4Impl.h"
/**
Validate the IP4 option format for both the packets we received
and will transmit. It will compute the ICMP error message fields
if the option is mal-formated. But this information isn't used.
@param Option The first byte of the option
@param OptionLen The length of the whole option
@param Rcvd The option is from the packet we received if TRUE,
otherwise the option we wants to transmit.
@return TRUE: The option is properly formated
@return FALSE: The option is mal-formated
**/
BOOLEAN
Ip4OptionIsValid (
IN UINT8 *Option,
IN UINT32 OptionLen,
IN BOOLEAN Rcvd
)
{
UINT32 Cur;
UINT32 Len;
UINT32 Point;
UINT8 IcmpType;
UINT8 IcmpCode;
UINT32 IcmpPoint;
IcmpType = ICMP_PARAMETER_PROBLEM;
IcmpCode = 0;
IcmpPoint = 0;
Cur = 0;
while (Cur < OptionLen) {
switch (Option[Cur]) {
case IP4_OPTION_NOP:
Cur++;
break;
case IP4_OPTION_EOP:
Cur = OptionLen;
break;
case IP4_OPTION_LSRR:
case IP4_OPTION_SSRR:
case IP4_OPTION_RR:
Len = Option[Cur + 1];
Point = Option[Cur + 2];
//
// SRR/RR options are formated as |Type|Len|Point|Ip1|Ip2|...
//
if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) {
IcmpPoint = Cur + 1;
return FALSE;
}
if ((Point > Len + 1) || (Point % 4 != 0)) {
IcmpPoint = Cur + 2;
return FALSE;
}
//
// The Point must point pass the last entry if the packet is received
// by us. It must point to 4 if the packet is to be sent by us for
// source route option.
//
if ((Option[Cur] != IP4_OPTION_RR) &&
((Rcvd && (Point != Len + 1)) || (!Rcvd && (Point != 4)))) {
IcmpType = ICMP_DEST_UNREACHABLE;
IcmpCode = ICMP_SOURCEROUTE_FAILED;
return FALSE;
}
Cur += Len;
break;
default:
Len = Option[Cur + 1];
if ((OptionLen - Cur < Len) || (Len < 2)) {
IcmpPoint = Cur + 1;
return FALSE;
}
Cur = Cur + Len;
break;
}
}
return TRUE;
}
/**
Copy the option from the original option to buffer. It
handles the details such as:
1. whether copy the single IP4 option to the first/non-first
fragments.
2. Pad the options copied over to aligened to 4 bytes.
@param Option The original option to copy from
@param OptionLen The length of the original option
@param FirstFragment Whether it is the first fragment
@param Buf The buffer to copy options to
@param BufLen The length of the buffer
@retval EFI_SUCCESS The options are copied over
@retval EFI_BUFFER_TOO_SMALL The buffer caller provided is too small.
**/
EFI_STATUS
Ip4CopyOption (
IN UINT8 *Option,
IN UINT32 OptionLen,
IN BOOLEAN FirstFragment,
IN UINT8 *Buf, OPTIONAL
IN OUT UINT32 *BufLen
)
{
UINT8 OptBuf[40];
UINT32 Cur;
UINT32 Next;
UINT8 Type;
UINT32 Len;
ASSERT ((BufLen != NULL) && (OptionLen <= 40));
Cur = 0;
Next = 0;
while (Cur < OptionLen) {
Type = Option[Cur];
Len = Option[Cur + 1];
if (Type == IP4_OPTION_NOP) {
//
// Keep the padding, in case that the sender wants to align
// the option, say, to 4 bytes
//
OptBuf[Next] = IP4_OPTION_NOP;
Next++;
Cur++;
} else if (Type == IP4_OPTION_EOP) {
//
// Don't append the EOP to avoid including only a EOP option
//
break;
} else {
//
// don't copy options that is only valid for the first fragment
//
if (FirstFragment || (Type & IP4_OPTION_COPY_MASK)) {
NetCopyMem (OptBuf + Next, Option + Cur, Len);
Next += Len;
}
Cur += Len;
}
}
//
// Don't append an EOP only option.
//
if (Next == 0) {
*BufLen = 0;
return EFI_SUCCESS;
}
//
// Append an EOP if the end of option doesn't coincide with the
// end of the IP header, that is, isn't aligned to 4 bytes..
//
if ((Next % 4) != 0) {
OptBuf[Next] = IP4_OPTION_EOP;
Next++;
}
//
// Head length is in the unit of 4 bytes. Now, Len is the
// acutal option length to appear in the IP header.
//
Len = ((Next + 3) &~0x03);
//
// If the buffer is too small, set the BufLen then return
//
if ((Buf == NULL) || (*BufLen < Len)) {
*BufLen = Len;
return EFI_BUFFER_TOO_SMALL;
}
//
// Copy the option to the Buf, zero the buffer first to pad
// the options with NOP to align to 4 bytes.
//
NetZeroMem (Buf, Len);
NetCopyMem (Buf, OptBuf, Next);
*BufLen = Len;
return EFI_SUCCESS;
}

View File

@ -0,0 +1,52 @@
/** @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

View File

@ -0,0 +1,457 @@
/** @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.c
Abstract:
Transmit the IP4 packet
**/
#include "Ip4Impl.h"
UINT16 mIp4Id;
/**
Prepend an IP4 head to the Packet. It will copy the options and
build the IP4 header fields. Used for IP4 fragmentation.
@param Packet The packet to prepend IP4 header to
@param Head The caller supplied header. The caller should set
the following header fields: Tos, TotalLen, Id,
Fragment, Ttl, Protocol, Src and Dst. All the fields
are in host byte order. This function will fill in
the Ver, HeadLen, and checksum.
@param Option The orginal IP4 option to copy from
@param OptLen The length of the IP4 option
@retval EFI_BAD_BUFFER_SIZE There is no enought room in the head space of
Packet.
@retval EFI_SUCCESS The IP4 header is successfully added to the packet.
**/
EFI_STATUS
Ip4PrependHead (
IN NET_BUF *Packet,
IN IP4_HEAD *Head,
IN UINT8 *Option,
IN UINT32 OptLen
)
{
UINT32 HeadLen;
UINT32 Len;
IP4_HEAD *PacketHead;
BOOLEAN FirstFragment;
//
// Prepend the options: first get the option length, then copy it over.
//
HeadLen = 0;
FirstFragment = IP4_FIRST_FRAGMENT (Head->Fragment);
Ip4CopyOption (Option, OptLen, FirstFragment, NULL, &Len);
HeadLen = IP4_MIN_HEADLEN + Len;
ASSERT (((Len %4) == 0) && (HeadLen <= IP4_MAX_HEADLEN));
PacketHead = (IP4_HEAD *) NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);
if (PacketHead == NULL) {
return EFI_BAD_BUFFER_SIZE;
}
Ip4CopyOption (Option, OptLen, FirstFragment, (UINT8 *) (PacketHead + 1), &Len);
//
// Set the head up, convert the host byte order to network byte order
//
PacketHead->Ver = 4;
PacketHead->HeadLen = (UINT8) (HeadLen >> 2);
PacketHead->Tos = Head->Tos;
PacketHead->TotalLen = HTONS (Packet->TotalSize);
PacketHead->Id = HTONS (Head->Id);
PacketHead->Fragment = HTONS (Head->Fragment);
PacketHead->Checksum = 0;
PacketHead->Ttl = Head->Ttl;
PacketHead->Protocol = Head->Protocol;
PacketHead->Src = HTONL (Head->Src);
PacketHead->Dst = HTONL (Head->Dst);
PacketHead->Checksum = ~NetblockChecksum ((UINT8 *) PacketHead, HeadLen);
Packet->Ip = PacketHead;
return EFI_SUCCESS;
}
/**
Select an interface to send the packet generated in the IP4 driver
itself, that is, not by the requests of IP4 child's consumer. Such
packets include the ICMP echo replies, and other ICMP error packets.
@param IpSb The IP4 service that wants to send the packets.
@param Dst The destination of the packet
@param Src The source of the packet
@return NULL if no proper interface is found, otherwise the interface that
@return can be used to send the system packet from.
**/
IP4_INTERFACE *
Ip4SelectInterface (
IN IP4_SERVICE *IpSb,
IN IP4_ADDR Dst,
IN IP4_ADDR Src
)
{
IP4_INTERFACE *IpIf;
IP4_INTERFACE *Selected;
NET_LIST_ENTRY *Entry;
//
// Select the interface the Dst is on if one of the connected
// network. Some IP instance may be configured with 0.0.0.0/0,
// don't select that interface now.
//
IpIf = Ip4FindNet (IpSb, Dst);
if ((IpIf != NULL) && (IpIf->Ip != IP4_ALLZERO_ADDRESS)) {
return IpIf;
}
//
// If source is one of the interface address, select it.
//
IpIf = Ip4FindInterface (IpSb, Src);
if ((IpIf != NULL) && (IpIf->Ip != IP4_ALLZERO_ADDRESS)) {
return IpIf;
}
//
// Select a configured interface as the fall back. Always prefer
// an interface with non-zero address.
//
Selected = NULL;
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
if (IpIf->Configured && ((Selected == NULL) || (Selected->Ip == 0))) {
Selected = IpIf;
}
}
return Selected;
}
/**
The default callback function for system generated packet.
It will free the packet.
@param Ip4Instance The IP4 child that issued the transmission. It most
like is NULL.
@param Packet The packet that transmitted.
@param IoStatus The result of the transmission, succeeded or failed.
@param LinkFlag Not used when transmission. check IP4_FRAME_CALLBACK
for reference.
@param Context The context provided by us
@return None
**/
VOID
Ip4SysPacketSent (
IP4_PROTOCOL *Ip4Instance,
NET_BUF *Packet,
EFI_STATUS IoStatus,
UINT32 LinkFlag,
VOID *Context
)
{
NetbufFree (Packet);
}
/**
Transmit an IP4 packet. The packet comes either from the IP4
child's consumer (IpInstance != NULL) or the IP4 driver itself
(IpInstance == NULL). It will route the packet, fragment it,
then transmit all the fragments through some interface.
@param IpSb The IP4 service instance to transmit the packet
@param IpInstance The IP4 child that issues the transmission. It is
NULL if the packet is from the system.
@param Packet The user data to send, excluding the IP header.
@param Head The caller supplied header. The caller should set
the following header fields: Tos, TotalLen, Id, tl,
Fragment, Protocol, Src and Dst. All the fields are
in host byte order. This function will fill in the
Ver, HeadLen, Fragment, and checksum. The Fragment
only need to include the DF flag. Ip4Output will
compute the MF and offset for you.
@param Option The original option to append to the IP headers
@param OptLen The length of the option
@param GateWay The next hop address to transmit packet to.
255.255.255.255 means broadcast.
@param Callback The callback function to issue when transmission
completed.
@param Context The opaque context for the callback
@retval EFI_NO_MAPPING There is no interface to the destination.
@retval EFI_NOT_FOUND There is no route to the destination
@retval EFI_SUCCESS The packet is successfully transmitted.
@retval Others Failed to transmit the packet.
**/
EFI_STATUS
Ip4Output (
IN IP4_SERVICE *IpSb,
IN IP4_PROTOCOL *IpInstance, OPTIONAL
IN NET_BUF *Packet,
IN IP4_HEAD *Head,
IN UINT8 *Option,
IN UINT32 OptLen,
IN IP4_ADDR GateWay,
IN IP4_FRAME_CALLBACK Callback,
IN VOID *Context
)
{
IP4_INTERFACE *IpIf;
IP4_ROUTE_CACHE_ENTRY *CacheEntry;
IP4_ADDR Dest;
EFI_STATUS Status;
NET_BUF *Fragment;
UINT32 Index;
UINT32 HeadLen;
UINT32 PacketLen;
UINT32 Offset;
UINT32 Mtu;
UINT32 Num;
//
// Select an interface/source for system packet, application
// should select them itself.
//
if (IpInstance == NULL) {
IpIf = Ip4SelectInterface (IpSb, Head->Dst, Head->Src);
} else {
IpIf = IpInstance->Interface;
}
if (IpIf == NULL) {
return EFI_NO_MAPPING;
}
if ((Head->Src == IP4_ALLZERO_ADDRESS) && (IpInstance == NULL)) {
Head->Src = IpIf->Ip;
}
//
// Route the packet unless overrided, that is, GateWay isn't zero.
//
if (GateWay == IP4_ALLZERO_ADDRESS) {
Dest = Head->Dst;
if (IP4_IS_BROADCAST (Ip4GetNetCast (Dest, IpIf)) || (Dest == IP4_ALLONE_ADDRESS)) {
//
// Set the gateway to local broadcast if the Dest is
// is the broadcast address for the connected network
// or it is local broadcast.
//
GateWay = IP4_ALLONE_ADDRESS;
} else if (IP4_IS_MULTICAST (Dest)) {
//
// Set the gateway to the destination if it is an multicast
// address. The IP4_INTERFACE won't consult ARP to send local
// broadcast and multicast.
//
GateWay = Head->Dst;
} else {
//
// Consult the route table to route the packet
//
if (IpInstance == NULL) {
CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src);
} else {
CacheEntry = Ip4Route (IpInstance->RouteTable, Head->Dst, Head->Src);
}
if (CacheEntry == NULL) {
return EFI_NOT_FOUND;
}
GateWay = CacheEntry->NextHop;
Ip4FreeRouteCacheEntry (CacheEntry);
}
}
//
// OK, selected the source and route, fragment the packet then send
// them. Tag each fragment other than the first one as spawn from it.
//
Mtu = IpSb->SnpMode.MaxPacketSize;
HeadLen = sizeof (IP4_HEAD) + (OptLen + 3) &~0x03;
Head->Id = mIp4Id++;
if (Packet->TotalSize + HeadLen > Mtu) {
//
// Packet is fragmented from the tail to the head, that is, the
// first frame sent is the last fragment of the packet. The first
// fragment is NOT sent in this loop. First compute how many
// fragments there are.
//
Mtu = (Mtu - HeadLen) & (~0x07);
Num = (Packet->TotalSize + Mtu - 1) / Mtu;
//
// Initialize the packet length and Offset. Other than the last
// fragment, the packet length equals to MTU. The offset is always
// aligned to MTU.
//
PacketLen = Packet->TotalSize - (Num - 1) * Mtu;
Offset = Mtu * (Num - 1);
for (Index = 0; Index < Num - 1; Index++, Offset -= Mtu) {
Fragment = NetbufGetFragment (Packet, Offset, PacketLen, IP4_MAX_HEADLEN);
if (Fragment == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
//
// Update the header's fragment. The caller fills the IP4 header
// fields that are required by Ip4PrependHead except the fragment.
//
Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, (Index != 0), Offset);
Ip4PrependHead (Fragment, Head, Option, OptLen);
//
// Transmit the fragments, pass the Packet address as the context.
// So, we can find all the fragments spawned from the Packet by
// compare the NetBuf and Context to the Packet.
//
Status = Ip4SendFrame (
IpIf,
IpInstance,
Fragment,
GateWay,
Ip4SysPacketSent,
Packet
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
PacketLen = Mtu;
}
//
// Trim the already sent data, then adjust the head's fragment field.
//
NetbufTrim (Packet, Packet->TotalSize - Mtu, FALSE);
Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, TRUE, 0);
}
//
// Send the first fragment, it is either the orginal packet, or the
// first fragment of a fragmented packet. It seems that there is a subtle
// bug here: what if the caller free the packet in Callback and IpIf (or
// MNP child used by that interface) still holds the fragments and try
// to access the data? The caller can free the packet if it recycles the
// consumer's (such as UDP) data in the Callback. But this can't happen.
// The detailed sequence is:
// 1. for the packets generated by IP4 driver itself:
// The Callback is Ip4SysPacketSent, which is the same as the
// fragments' callback. Ip4SysPacketSent simply calls NetbufFree
// to release its reference to the packet. So, no problem for
// system packets.
//
// 2. for the upper layer's packets (use UDP as an example):
// UDP requests the IP layer to transmit some data which is
// wrapped in an asynchronous token, the token is wrapped
// in IP4_TXTOKEN_WRAP by IP4. IP4 also wrap the user's data
// in a net buffer, which is Packet we get here. IP4_TXTOKEN_WRAP
// is bound with the Packet. It will only be freed when all
// the references to Packet have been released. Upon then, the
// Packet's OnFree callback will release the IP4_TXTOKEN_WRAP,
// and singal the user's recycle event. So, also no problem for
// upper layer's packets.
//
Ip4PrependHead (Packet, Head, Option, OptLen);
Status = Ip4SendFrame (IpIf, IpInstance, Packet, GateWay, Callback, Context);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
return EFI_SUCCESS;
ON_ERROR:
Ip4CancelPacket (IpIf, Packet, Status);
return Status;
}
/**
The filter function to find a packet and all its fragments.
The packet's fragments have their Context set to the packet.
@param Frame The frames hold by the low level interface
@param Context Context to the function, which is the packet.
@retval TRUE This is the packet to cancel or its fragments.
@retval FALSE This is unrelated packet.
**/
STATIC
BOOLEAN
Ip4CancelPacketFragments (
IP4_LINK_TX_TOKEN *Frame,
VOID *Context
)
{
if ((Frame->Packet == (NET_BUF *) Context) || (Frame->Context == Context)) {
return TRUE;
}
return FALSE;
}
/**
Cancel the Packet and all its fragments.
@param IpIf The interface from which the Packet is sent
@param Packet The Packet to cancel
@param IoStatus The status returns to the sender.
@return None
**/
VOID
Ip4CancelPacket (
IN IP4_INTERFACE *IpIf,
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus
)
{
Ip4CancelFrames (IpIf, IoStatus, Ip4CancelPacketFragments, Packet);
}

View File

@ -0,0 +1,54 @@
/** @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

View File

@ -0,0 +1,690 @@
/** @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.c
Abstract:
**/
#include "Ip4Impl.h"
/**
Allocate a route entry then initialize it with the Dest/Netmaks
and Gateway.
@param Dest The destination network
@param Netmask The destination network mask
@param GateWay The nexthop address
@return NULL if failed to allocate memeory, otherwise the newly created
@return route entry.
**/
STATIC
IP4_ROUTE_ENTRY *
Ip4CreateRouteEntry (
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR GateWay
)
{
IP4_ROUTE_ENTRY *RtEntry;
RtEntry = NetAllocatePool (sizeof (IP4_ROUTE_ENTRY));
if (RtEntry == NULL) {
return NULL;
}
NetListInit (&RtEntry->Link);
RtEntry->RefCnt = 1;
RtEntry->Dest = Dest;
RtEntry->Netmask = Netmask;
RtEntry->NextHop = GateWay;
RtEntry->Flag = 0;
return RtEntry;
}
/**
Free the route table entry. It is reference counted.
@param RtEntry The route entry to free.
@return NONE
**/
STATIC
VOID
Ip4FreeRouteEntry (
IN IP4_ROUTE_ENTRY *RtEntry
)
{
ASSERT (RtEntry->RefCnt > 0);
if (--RtEntry->RefCnt == 0) {
NetFreePool (RtEntry);
}
}
/**
Allocate and initialize a IP4 route cache entry.
@param Dst The destination address
@param Src The source address
@param GateWay The next hop address
@param Tag The tag from the caller. This marks all the cache
entries spawned from one route table entry.
@return NULL if failed to allocate memory for the cache, other point
@return to the created route cache entry.
**/
STATIC
IP4_ROUTE_CACHE_ENTRY *
Ip4CreateRouteCacheEntry (
IN IP4_ADDR Dst,
IN IP4_ADDR Src,
IN IP4_ADDR GateWay,
IN UINTN Tag
)
{
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
RtCacheEntry = NetAllocatePool (sizeof (IP4_ROUTE_CACHE_ENTRY));
if (RtCacheEntry == NULL) {
return NULL;
}
NetListInit (&RtCacheEntry->Link);
RtCacheEntry->RefCnt = 1;
RtCacheEntry->Dest = Dst;
RtCacheEntry->Src = Src;
RtCacheEntry->NextHop = GateWay;
RtCacheEntry->Tag = Tag;
return RtCacheEntry;
}
/**
Free the route cache entry. It is reference counted.
@param RtCacheEntry The route cache entry to free.
@return None
**/
VOID
Ip4FreeRouteCacheEntry (
IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry
)
{
ASSERT (RtCacheEntry->RefCnt > 0);
if (--RtCacheEntry->RefCnt == 0) {
NetFreePool (RtCacheEntry);
}
}
/**
Initialize an empty route cache table.
@param RtCache The rotue cache table to initialize.
@return NONE
**/
VOID
Ip4InitRouteCache (
IN IP4_ROUTE_CACHE *RtCache
)
{
UINT32 Index;
for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {
NetListInit (&(RtCache->CacheBucket[Index]));
}
}
/**
Clean up a route cache, that is free all the route cache
entries enqueued in the cache.
@param RtCache The route cache table to clean up
@return None
**/
VOID
Ip4CleanRouteCache (
IN IP4_ROUTE_CACHE *RtCache
)
{
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
UINT32 Index;
for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtCache->CacheBucket[Index])) {
RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
NetListRemoveEntry (Entry);
Ip4FreeRouteCacheEntry (RtCacheEntry);
}
}
}
/**
Create an empty route table, includes its internal route cache
None
@return NULL if failed to allocate memory for the route table, otherwise
@return the point to newly created route table.
**/
IP4_ROUTE_TABLE *
Ip4CreateRouteTable (
VOID
)
{
IP4_ROUTE_TABLE *RtTable;
UINT32 Index;
RtTable = NetAllocatePool (sizeof (IP4_ROUTE_TABLE));
if (RtTable == NULL) {
return NULL;
}
RtTable->RefCnt = 1;
RtTable->TotalNum = 0;
for (Index = 0; Index < IP4_MASK_NUM; Index++) {
NetListInit (&(RtTable->RouteArea[Index]));
}
RtTable->Next = NULL;
Ip4InitRouteCache (&RtTable->Cache);
return RtTable;
}
/**
Free the route table and its associated route cache. Route
table is reference counted.
@param RtTable The route table to free.
@return None
**/
VOID
Ip4FreeRouteTable (
IN IP4_ROUTE_TABLE *RtTable
)
{
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_ROUTE_ENTRY *RtEntry;
UINT32 Index;
ASSERT (RtTable->RefCnt > 0);
if (--RtTable->RefCnt > 0) {
return ;
}
//
// Free all the route table entry and its route cache.
//
for (Index = 0; Index < IP4_MASK_NUM; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtTable->RouteArea[Index])) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
NetListRemoveEntry (Entry);
Ip4FreeRouteEntry (RtEntry);
}
}
Ip4CleanRouteCache (&RtTable->Cache);
NetFreePool (RtTable);
}
/**
Remove all the cache entries bearing the Tag. When a route cache
entry is created, it is tagged with the address of route entry
from which it is spawned. When a route entry is deleted, the cache
entries spawned from it are also deleted.
@param RtCache Route cache to remove the entries from
@param Tag The Tag of the entries to remove
@return None
**/
STATIC
VOID
Ip4PurgeRouteCache (
IN IP4_ROUTE_CACHE *RtCache,
IN UINTN Tag
)
{
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
UINT32 Index;
for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtCache->CacheBucket[Index]) {
RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
if (RtCacheEntry->Tag == Tag) {
NetListRemoveEntry (Entry);
Ip4FreeRouteCacheEntry (RtCacheEntry);
}
}
}
}
/**
Add a route entry to the route table. All the IP4_ADDRs are in
host byte order.
@param RtTable Route table to add route to
@param Dest The destination of the network
@param Netmask The netmask of the destination
@param Gateway The next hop address
@retval EFI_ACCESS_DENIED The same route already exists
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the entry
@retval EFI_SUCCESS The route is added successfully.
**/
EFI_STATUS
Ip4AddRoute (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR Gateway
)
{
NET_LIST_ENTRY *Head;
NET_LIST_ENTRY *Entry;
IP4_ROUTE_ENTRY *RtEntry;
//
// All the route entries with the same netmask length are
// linke to the same route area
//
Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);
//
// First check whether the route exists
//
NET_LIST_FOR_EACH (Entry, Head) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {
return EFI_ACCESS_DENIED;
}
}
//
// Create a route entry and insert it to the route area.
//
RtEntry = Ip4CreateRouteEntry (Dest, Netmask, Gateway);
if (RtEntry == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (Gateway == IP4_ALLZERO_ADDRESS) {
RtEntry->Flag = IP4_DIRECT_ROUTE;
}
NetListInsertHead (Head, &RtEntry->Link);
RtTable->TotalNum++;
return EFI_SUCCESS;
}
/**
Remove a route entry and all the route caches spawn from it.
@param RtTable The route table to remove the route from
@param Dest The destination network
@param Netmask The netmask of the Dest
@param Gateway The next hop address
@retval EFI_SUCCESS The route entry is successfully removed
@retval EFI_NOT_FOUND There is no route entry in the table with that
properity.
**/
EFI_STATUS
Ip4DelRoute (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Netmask,
IN IP4_ADDR Gateway
)
{
NET_LIST_ENTRY *Head;
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_ROUTE_ENTRY *RtEntry;
Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);
NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {
Ip4PurgeRouteCache (&RtTable->Cache, (UINTN) RtEntry);
NetListRemoveEntry (Entry);
Ip4FreeRouteEntry (RtEntry);
RtTable->TotalNum--;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
Find a route cache with the dst and src. This is used by ICMP
redirect messasge process. All kinds of redirect is treated as
host redirect according to RFC1122. So, only route cache entries
are modified according to the ICMP redirect message.
@param RtTable The route table to search the cache for
@param Dest The destination address
@param Src The source address
@return NULL if no route entry to the (Dest, Src). Otherwise the point
@return to the correct route cache entry.
**/
IP4_ROUTE_CACHE_ENTRY *
Ip4FindRouteCache (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Src
)
{
NET_LIST_ENTRY *Entry;
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
UINT32 Index;
Index = IP4_ROUTE_CACHE_HASH (Dest, Src);
NET_LIST_FOR_EACH (Entry, &RtTable->Cache.CacheBucket[Index]) {
RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
if ((RtCacheEntry->Dest == Dest) && (RtCacheEntry->Src == Src)) {
NET_GET_REF (RtCacheEntry);
return RtCacheEntry;
}
}
return NULL;
}
/**
Search the route table for a most specific match to the Dst. It searches
from the longest route area (mask length == 32) to the shortest route area (
default routes). In each route area, it will first search the instance's
route table, then the default route table. This is required by the following
requirements:
1. IP search the route table for a most specific match
2. The local route entries have precedence over the default route entry.
@param RtTable The route table to search from
@param Dst The destionation address to search
@return NULL if no route matches the Dst, otherwise the point to the
@return most specific route to the Dst.
**/
STATIC
IP4_ROUTE_ENTRY *
Ip4FindRouteEntry (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dst
)
{
NET_LIST_ENTRY *Entry;
IP4_ROUTE_ENTRY *RtEntry;
IP4_ROUTE_TABLE *Table;
INTN Index;
RtEntry = NULL;
for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {
for (Table = RtTable; Table != NULL; Table = Table->Next) {
NET_LIST_FOR_EACH (Entry, &Table->RouteArea[Index]) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
if (IP4_NET_EQUAL (RtEntry->Dest, Dst, RtEntry->Netmask)) {
NET_GET_REF (RtEntry);
return RtEntry;
}
}
}
}
return NULL;
}
/**
Search the route table to route the packet. Return/creat a route
cache if there is a route to the destination.
@param RtTable The route table to search from
@param Dest The destination address to search for
@param Src The source address to search for
@return NULL if failed to route packet, otherwise a route cache
@return entry that can be used to route packet.
**/
IP4_ROUTE_CACHE_ENTRY *
Ip4Route (
IN IP4_ROUTE_TABLE *RtTable,
IN IP4_ADDR Dest,
IN IP4_ADDR Src
)
{
NET_LIST_ENTRY *Head;
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
IP4_ROUTE_CACHE_ENTRY *Cache;
IP4_ROUTE_ENTRY *RtEntry;
IP4_ADDR NextHop;
UINT32 Count;
ASSERT (RtTable != NULL);
Head = &RtTable->Cache.CacheBucket[IP4_ROUTE_CACHE_HASH (Dest, Src)];
RtCacheEntry = Ip4FindRouteCache (RtTable, Dest, Src);
//
// If found, promote the cache entry to the head of the hash bucket. LRU
//
if (RtCacheEntry != NULL) {
NetListRemoveEntry (&RtCacheEntry->Link);
NetListInsertHead (Head, &RtCacheEntry->Link);
return RtCacheEntry;
}
//
// Search the route table for the most specific route
//
RtEntry = Ip4FindRouteEntry (RtTable, Dest);
if (RtEntry == NULL) {
return NULL;
}
//
// Found a route to the Dest, if it is a direct route, the packet
// will be send directly to the destination, such as for connected
// network. Otherwise, it is an indirect route, the packet will be
// send the next hop router.
//
if (RtEntry->Flag & IP4_DIRECT_ROUTE) {
NextHop = Dest;
} else {
NextHop = RtEntry->NextHop;
}
Ip4FreeRouteEntry (RtEntry);
//
// Create a route cache entry, and tag it as spawned from this route entry
//
RtCacheEntry = Ip4CreateRouteCacheEntry (Dest, Src, NextHop, (UINTN) RtEntry);
if (RtCacheEntry == NULL) {
return NULL;
}
NetListInsertHead (Head, &RtCacheEntry->Link);
NET_GET_REF (RtCacheEntry);
//
// Each bucket of route cache can contain at most 64 entries.
// Remove the entries at the tail of the bucket. These entries
// are likely to be used least.
//
Count = 0;
NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
if (++Count < IP4_ROUTE_CACHE_MAX) {
continue;
}
Cache = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
NetListRemoveEntry (Entry);
Ip4FreeRouteCacheEntry (Cache);
}
return RtCacheEntry;
}
/**
Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of
GetModeData. The EFI_IP4_ROUTE_TABLE is clumsy to use in the
internal operation of the IP4 driver.
@param IpInstance The IP4 child that requests the route table.
@retval EFI_SUCCESS The route table is successfully build
@retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the rotue table.
**/
EFI_STATUS
Ip4BuildEfiRouteTable (
IN IP4_PROTOCOL *IpInstance
)
{
IP4_SERVICE *IpSb;
NET_LIST_ENTRY *Entry;
IP4_ROUTE_TABLE *RtTable;
IP4_ROUTE_ENTRY *RtEntry;
EFI_IP4_ROUTE_TABLE *Table;
UINT32 Count;
INT32 Index;
IpSb = IpInstance->Service;
RtTable = IpInstance->RouteTable;
if (IpInstance->EfiRouteTable != NULL) {
NetFreePool (IpInstance->EfiRouteTable);
IpInstance->EfiRouteTable = NULL;
IpInstance->EfiRouteCount = 0;
}
Count = RtTable->TotalNum;
if (RtTable->Next != NULL) {
Count += RtTable->Next->TotalNum;
}
if (Count == 0) {
return EFI_SUCCESS;
}
Table = NetAllocatePool (sizeof (EFI_IP4_ROUTE_TABLE) * Count);
if (Table == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Copy the route entry to EFI route table. Keep the order of
// route entry copied from most specific to default route. That
// is, interlevel the route entry from the instance's route area
// and those from the default route table's route area.
//
Count = 0;
for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {
for (RtTable = IpInstance->RouteTable; RtTable != NULL; RtTable = RtTable->Next) {
NET_LIST_FOR_EACH (Entry, &(RtTable->RouteArea[Index])) {
RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
EFI_IP4 (Table[Count].SubnetAddress) = HTONL (RtEntry->Dest & RtEntry->Netmask);
EFI_IP4 (Table[Count].SubnetMask) = HTONL (RtEntry->Netmask);
EFI_IP4 (Table[Count].GatewayAddress) = HTONL (RtEntry->NextHop);
Count++;
}
}
}
IpInstance->EfiRouteTable = Table;
IpInstance->EfiRouteCount = Count;
return EFI_SUCCESS;
}

View File

@ -0,0 +1,151 @@
/** @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

View File

@ -139,7 +139,7 @@ MnpAddFreeNbuf (
for (Index = 0; Index < Count; Index++) {
Nbuf = NetbufAlloc (MnpServiceData->BufferLength);
Nbuf = NetbufAlloc (MnpServiceData->BufferLength + MnpServiceData->PaddingSize);
if (Nbuf == NULL) {
MNP_DEBUG_ERROR (("MnpAddFreeNbuf: NetBufAlloc failed.\n"));
@ -147,6 +147,14 @@ MnpAddFreeNbuf (
break;
}
if (MnpServiceData->PaddingSize > 0) {
//
// Pad padding bytes before the media header
//
NetbufAllocSpace (Nbuf, MnpServiceData->PaddingSize, NET_BUF_TAIL);
NetbufTrim (Nbuf, MnpServiceData->PaddingSize, NET_BUF_HEAD);
}
NetbufQueAppend (&MnpServiceData->FreeNbufQue, Nbuf);
}
@ -328,6 +336,12 @@ MnpInitializeServiceData (
//
MnpServiceData->BufferLength = MnpServiceData->Mtu + SnpMode->MediaHeaderSize + NET_ETHER_FCS_SIZE;
//
// Make sure the protocol headers immediately following the media header
// 4-byte aligned
//
MnpServiceData->PaddingSize = (4 - SnpMode->MediaHeaderSize) & 0x3;
//
// Initialize the FreeNetBufQue and pre-allocate some NET_BUFs.
//

View File

@ -521,7 +521,6 @@ MnpServiceBindingDestroyChild (
return Status;
}
//@MT: EFI_DRIVER_ENTRY_POINT (MnpDriverEntryPoint)
EFI_STATUS
EFIAPI

View File

@ -82,6 +82,7 @@ typedef struct _MNP_SERVICE_DATA {
// store a packet.
//
UINT32 BufferLength;
UINT32 PaddingSize;
NET_BUF *RxNbufCache;
UINT8 *TxBuf;
} MNP_SERVICE_DATA;

View File

@ -974,7 +974,10 @@ MnpReceivePacket (
//
// No receiver for this packet.
//
if (Trimmed > 0) {
NetbufAllocSpace (Nbuf, Trimmed, NET_BUF_TAIL);
}
goto EXIT;
}
//

View File

@ -0,0 +1,161 @@
/** @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:
ComponentName.c
Abstract:
**/
#include "Mtftp4Driver.h"
//
// EFI Component Name Functions
//
EFI_STATUS
EFIAPI
Mtftp4ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
EFI_STATUS
EFIAPI
Mtftp4ComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
//
// EFI Component Name Protocol
//
EFI_COMPONENT_NAME_PROTOCOL gMtftp4ComponentName = {
Mtftp4ComponentNameGetDriverName,
Mtftp4ComponentNameGetControllerName,
"eng"
};
static EFI_UNICODE_STRING_TABLE mMtftp4DriverNameTable[] = {
{
"eng",
L"MTFTP4 Network Service"
},
{
NULL,
NULL
}
};
EFI_STATUS
EFIAPI
Mtftp4ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the EFI Driver.
Arguments:
This : A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
Language : A pointer to a three character ISO 639-2 language identifier.
This is the language of the driver name that that the caller
is requesting, and it must match one of the languages specified
in SupportedLanguages. The number of languages supported by a
driver is up to the driver writer.
DriverName : A pointer to the Unicode string to return. This Unicode string
is the name of the driver specified by This in the language
specified by Language.
Returns:
EFI_SUCCES : The Unicode string for the Driver specified by This
and the language specified by Language was returned
in DriverName.
EFI_INVALID_PARAMETER : Language is NULL.
EFI_INVALID_PARAMETER : DriverName is NULL.
EFI_UNSUPPORTED : The driver specified by This does not support the
language specified by Language.
--*/
{
return LookupUnicodeString (
Language,
gMtftp4ComponentName.SupportedLanguages,
mMtftp4DriverNameTable,
DriverName
);
}
EFI_STATUS
EFIAPI
Mtftp4ComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by an EFI Driver.
Arguments:
This : A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
ControllerHandle :The handle of a controller that the driver specified by
This is managing. This handle specifies the controller
whose name is to be returned.
ChildHandle :The handle of the child controller to retrieve the name
of. This is an optional parameter that may be NULL. It
will be NULL for device drivers. It will also be NULL
for a bus drivers that wish to retrieve the name of the
bus controller. It will not be NULL for a bus driver
that wishes to retrieve the name of a child controller.
Language : A pointer to a three character ISO 639-2 language
identifier. This is the language of the controller name
that that the caller is requesting, and it must match one
of the languages specified in SupportedLanguages. The
number of languages supported by a driver is up to the
driver writer.
ControllerName : A pointer to the Unicode string to return. This Unicode
string is the name of the controller specified by
ControllerHandle and ChildHandle in the language specified
by Language from the point of view of the driver specified
by This.
Returns:
EFI_SUCCESS :The Unicode string for the user readable name in the
language specified by Language for the driver
specified by This was returned in DriverName.
EFI_INVALID_PARAMETER : ControllerHandle is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER : ChildHandle is not NULL and it is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER : Language is NULL.
EFI_INVALID_PARAMETER : ControllerName is NULL.
EFI_UNSUPPORTED : The driver specified by This is not currently managing
the controller specified by ControllerHandle and
ChildHandle.
EFI_UNSUPPORTED :The driver specified by This does not support the
language specified by Language.
--*/
{
return EFI_UNSUPPORTED;
}

View File

@ -0,0 +1,643 @@
/** @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.c
Abstract:
**/
#include "Mtftp4Impl.h"
EFI_DRIVER_BINDING_PROTOCOL gMtftp4DriverBinding = {
Mtftp4DriverBindingSupported,
Mtftp4DriverBindingStart,
Mtftp4DriverBindingStop,
0xa,
NULL,
NULL
};
EFI_SERVICE_BINDING_PROTOCOL gMtftp4ServiceBindingTemplete = {
Mtftp4ServiceBindingCreateChild,
Mtftp4ServiceBindingDestroyChild
};
//@MT: EFI_DRIVER_ENTRY_POINT (Mtftp4DriverEntryPoint)
EFI_STATUS
EFIAPI
Mtftp4DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
The driver entry point which installs multiple protocols to the ImageHandle.
Arguments:
ImageHandle - The MTFTP's image handle
SystemTable - The system table
Returns:
EFI_SUCCESS - The handles are successfully installed on the image. Otherwise
some EFI_ERROR.
--*/
{
return NetLibInstallAllDriverProtocols (
ImageHandle,
SystemTable,
&gMtftp4DriverBinding,
ImageHandle,
&gMtftp4ComponentName,
NULL,
NULL
);
}
/**
Test whether MTFTP driver support this controller.
@param This The MTFTP driver binding instance
@param Controller The controller to test
@param RemainingDevicePath The remaining device path
@retval EFI_SUCCESS The controller has UDP service binding protocol
installed, MTFTP can support it.
@retval Others MTFTP can't support the controller.
**/
EFI_STATUS
Mtftp4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
Status = gBS->OpenProtocol (
Controller,
&gEfiUdp4ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
return Status;
}
/**
Config a NULL UDP that is used to keep the connection between UDP
and MTFTP. Just leave the Udp child unconfigured. When UDP is
unloaded, MTFTP will be informed with DriverBinding Stop.
@param UdpIo The UDP port to configure
@param Context The opaque parameter to the callback
@retval EFI_SUCCESS It always return EFI_SUCCESS directly.
**/
EFI_STATUS
Mtftp4ConfigNullUdp (
IN UDP_IO_PORT *UdpIo,
IN VOID *Context
)
{
return EFI_SUCCESS;
}
/**
Create then initialize a MTFTP service binding instance.
@param Controller The controller to install the MTFTP service
binding on
@param Image The driver binding image of the MTFTP driver
@param Service The variable to receive the created service
binding instance.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the instance
@retval EFI_DEVICE_ERROR Failed to create a NULL UDP port to keep
connection with UDP.
@retval EFI_SUCCESS The service instance is created for the
controller.
**/
EFI_STATUS
Mtftp4CreateService (
IN EFI_HANDLE Controller,
IN EFI_HANDLE Image,
OUT MTFTP4_SERVICE **Service
)
{
MTFTP4_SERVICE *MtftpSb;
EFI_STATUS Status;
*Service = NULL;
MtftpSb = NetAllocatePool (sizeof (MTFTP4_SERVICE));
if (MtftpSb == NULL) {
return EFI_OUT_OF_RESOURCES;
}
MtftpSb->Signature = MTFTP4_SERVICE_SIGNATURE;
MtftpSb->ServiceBinding = gMtftp4ServiceBindingTemplete;
MtftpSb->InDestory = FALSE;
MtftpSb->ChildrenNum = 0;
NetListInit (&MtftpSb->Children);
MtftpSb->Timer = NULL;
MtftpSb->TimerToGetMap = NULL;
MtftpSb->Controller = Controller;
MtftpSb->Image = Image;
MtftpSb->ConnectUdp = NULL;
//
// Create the timer and a udp to be notified when UDP is uninstalled
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL | EVT_TIMER,
TPL_CALLBACK,
Mtftp4OnTimerTick,
MtftpSb,
&MtftpSb->Timer
);
if (EFI_ERROR (Status)) {
NetFreePool (MtftpSb);
return Status;
}
//
// Create the timer used to time out the procedure which is used to
// get the default IP address.
//
Status = gBS->CreateEvent (
EVT_TIMER,
TPL_CALLBACK,
NULL,
NULL,
&MtftpSb->TimerToGetMap
);
if (EFI_ERROR (Status)) {
gBS->CloseEvent (MtftpSb->Timer);
NetFreePool (MtftpSb);
return Status;
}
MtftpSb->ConnectUdp = UdpIoCreatePort (Controller, Image, Mtftp4ConfigNullUdp, NULL);
if (MtftpSb->ConnectUdp == NULL) {
gBS->CloseEvent (MtftpSb->TimerToGetMap);
gBS->CloseEvent (MtftpSb->Timer);
NetFreePool (MtftpSb);
return EFI_DEVICE_ERROR;
}
*Service = MtftpSb;
return EFI_SUCCESS;
}
/**
Release all the resource used the MTFTP service binding instance.
@param MtftpSb The MTFTP service binding instance.
@return None
**/
VOID
Mtftp4CleanService (
IN MTFTP4_SERVICE *MtftpSb
)
{
UdpIoFreePort (MtftpSb->ConnectUdp);
gBS->CloseEvent (MtftpSb->TimerToGetMap);
gBS->CloseEvent (MtftpSb->Timer);
}
/**
Start the MTFTP driver on this controller. MTFTP driver will
install a MTFTP SERVICE BINDING protocol on the supported
controller, which can be used to create/destroy MTFTP children.
@param This The MTFTP driver binding protocol.
@param Controller The controller to manage.
@param RemainingDevicePath Remaining device path.
@retval EFI_ALREADY_STARTED The MTFTP service binding protocol has been
started on the controller.
@retval EFI_SUCCESS The MTFTP service binding is installed on the
controller.
**/
EFI_STATUS
Mtftp4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
MTFTP4_SERVICE *MtftpSb;
EFI_STATUS Status;
//
// Directly return if driver is already running.
//
Status = gBS->OpenProtocol (
Controller,
&gEfiMtftp4ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (Status == EFI_SUCCESS) {
return EFI_ALREADY_STARTED;
}
Status = Mtftp4CreateService (Controller, This->DriverBindingHandle, &MtftpSb);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->SetTimer (MtftpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
//
// Install the Mtftp4ServiceBinding Protocol onto Controller
//
Status = gBS->InstallMultipleProtocolInterfaces (
&Controller,
&gEfiMtftp4ServiceBindingProtocolGuid,
&MtftpSb->ServiceBinding,
NULL
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
return EFI_SUCCESS;
ON_ERROR:
Mtftp4CleanService (MtftpSb);
NetFreePool (MtftpSb);
return Status;
}
/**
Stop the MTFTP driver on controller. The controller is a UDP
child handle.
@param This The MTFTP driver binding protocol
@param Controller The controller to stop
@param NumberOfChildren The number of children
@param ChildHandleBuffer The array of the child handle.
@retval EFI_SUCCESS The driver is stopped on the controller.
@retval EFI_DEVICE_ERROR Failed to stop the driver on the controller.
**/
EFI_STATUS
Mtftp4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
MTFTP4_SERVICE *MtftpSb;
MTFTP4_PROTOCOL *Instance;
EFI_HANDLE NicHandle;
EFI_STATUS Status;
EFI_TPL OldTpl;
//
// MTFTP driver opens UDP child, So, Controller is a UDP
// child handle. Locate the Nic handle first. Then get the
// MTFTP private data back.
//
NicHandle = NetLibGetNicHandle (Controller, &gEfiUdp4ProtocolGuid);
if (NicHandle == NULL) {
return EFI_SUCCESS;
}
Status = gBS->OpenProtocol (
NicHandle,
&gEfiMtftp4ServiceBindingProtocolGuid,
(VOID **) &ServiceBinding,
This->DriverBindingHandle,
NicHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
MtftpSb = MTFTP4_SERVICE_FROM_THIS (ServiceBinding);
if (MtftpSb->InDestory) {
return EFI_SUCCESS;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
MtftpSb->InDestory = TRUE;
while (!NetListIsEmpty (&MtftpSb->Children)) {
Instance = NET_LIST_HEAD (&MtftpSb->Children, MTFTP4_PROTOCOL, Link);
Mtftp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);
}
if (MtftpSb->ChildrenNum != 0) {
Status = EFI_DEVICE_ERROR;
goto ON_ERROR;
}
Status = gBS->UninstallProtocolInterface (
NicHandle,
&gEfiMtftp4ServiceBindingProtocolGuid,
ServiceBinding
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Mtftp4CleanService (MtftpSb);
NetFreePool (MtftpSb);
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
ON_ERROR:
MtftpSb->InDestory = FALSE;
NET_RESTORE_TPL (OldTpl);
return Status;
}
/**
Initialize a MTFTP protocol instance which is the child of MtftpSb.
@param MtftpSb The MTFTP service binding protocol.
@param Instance The MTFTP instance to initialize.
@return None
**/
VOID
Mtftp4InitProtocol (
IN MTFTP4_SERVICE *MtftpSb,
IN MTFTP4_PROTOCOL *Instance
)
{
NetZeroMem (Instance, sizeof (MTFTP4_PROTOCOL));
Instance->Signature = MTFTP4_PROTOCOL_SIGNATURE;
NetListInit (&Instance->Link);
CopyMem (&Instance->Mtftp4, &gMtftp4ProtocolTemplate, sizeof (EFI_MTFTP4_PROTOCOL));
Instance->State = MTFTP4_STATE_UNCONFIGED;
Instance->Indestory = FALSE;
Instance->Service = MtftpSb;
NetListInit (&Instance->Blocks);
}
/**
Create a MTFTP child for the service binding instance, then
install the MTFTP protocol to the ChildHandle.
@param This The MTFTP service binding instance.
@param ChildHandle The Child handle to install the MTFTP protocol.
@retval EFI_INVALID_PARAMETER The parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the new child.
@retval EFI_SUCCESS The child is successfully create.
**/
EFI_STATUS
Mtftp4ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN OUT EFI_HANDLE *ChildHandle
)
{
MTFTP4_SERVICE *MtftpSb;
MTFTP4_PROTOCOL *Instance;
EFI_STATUS Status;
EFI_TPL OldTpl;
VOID *Udp4;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
Instance = NetAllocatePool (sizeof (*Instance));
if (Instance == NULL) {
return EFI_OUT_OF_RESOURCES;
}
MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
Mtftp4InitProtocol (MtftpSb, Instance);
Instance->UnicastPort = UdpIoCreatePort (
MtftpSb->Controller,
MtftpSb->Image,
Mtftp4ConfigNullUdp,
Instance
);
if (Instance->UnicastPort == NULL) {
NetFreePool (Instance);
return EFI_OUT_OF_RESOURCES;
}
//
// Install the MTFTP protocol onto ChildHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiMtftp4ProtocolGuid,
&Instance->Mtftp4,
NULL
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Instance->Handle = *ChildHandle;
//
// Open the Udp4 protocol BY_CHILD.
//
Status = gBS->OpenProtocol (
MtftpSb->ConnectUdp->UdpHandle,
&gEfiUdp4ProtocolGuid,
(VOID **) &Udp4,
gMtftp4DriverBinding.DriverBindingHandle,
Instance->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
gBS->UninstallMultipleProtocolInterfaces (
Instance->Handle,
&gEfiMtftp4ProtocolGuid,
&Instance->Mtftp4,
NULL
);
goto ON_ERROR;
}
//
// Add it to the parent's child list.
//
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
NetListInsertTail (&MtftpSb->Children, &Instance->Link);
MtftpSb->ChildrenNum++;
NET_RESTORE_TPL (OldTpl);
ON_ERROR:
if (EFI_ERROR (Status)) {
UdpIoFreePort (Instance->UnicastPort);
NetFreePool (Instance);
}
return Status;
}
/**
Destory one of the service binding's child.
@param This The service binding instance
@param ChildHandle The child handle to destory
@retval EFI_INVALID_PARAMETER The parameter is invaid.
@retval EFI_UNSUPPORTED The child may have already been destoried.
@retval EFI_SUCCESS The child is destoried and removed from the
parent's child list.
**/
EFI_STATUS
Mtftp4ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
MTFTP4_SERVICE *MtftpSb;
MTFTP4_PROTOCOL *Instance;
EFI_MTFTP4_PROTOCOL *Mtftp4;
EFI_STATUS Status;
EFI_TPL OldTpl;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Retrieve the private context data structures
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiMtftp4ProtocolGuid,
(VOID **) &Mtftp4,
gMtftp4DriverBinding.DriverBindingHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Instance = MTFTP4_PROTOCOL_FROM_THIS (Mtftp4);
MtftpSb = MTFTP4_SERVICE_FROM_THIS (This);
if (Instance->Service != MtftpSb) {
return EFI_INVALID_PARAMETER;
}
if (Instance->Indestory) {
return EFI_SUCCESS;
}
Instance->Indestory = TRUE;
//
// Close the Udp4 protocol.
//
gBS->CloseProtocol (
MtftpSb->ConnectUdp->UdpHandle,
&gEfiUdp4ProtocolGuid,
gMtftp4DriverBinding.DriverBindingHandle,
ChildHandle
);
//
// Uninstall the MTFTP4 protocol first to enable a top down destruction.
//
Status = gBS->UninstallProtocolInterface (
ChildHandle,
&gEfiMtftp4ProtocolGuid,
Mtftp4
);
if (EFI_ERROR (Status)) {
Instance->Indestory = FALSE;
return Status;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
Mtftp4CleanOperation (Instance, EFI_DEVICE_ERROR);
UdpIoFreePort (Instance->UnicastPort);
NetListRemoveEntry (&Instance->Link);
MtftpSb->ChildrenNum--;
NET_RESTORE_TPL (OldTpl);
NetFreePool (Instance);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,69 @@
/** @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

View File

@ -0,0 +1,68 @@
#/** @file
# Component name for module Mtftp4
#
# 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.
#
#
#**/
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Mtftp4Dxe
FILE_GUID = DC3641B8-2FA8-4ed3-BC1F-F9962A03454B
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = Mtftp4DriverEntryPoint
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources.common]
Mtftp4Option.c
Mtftp4Rrq.c
Mtftp4Impl.h
ComponentName.c
Mtftp4Support.c
Mtftp4Impl.c
Mtftp4Option.h
Mtftp4Support.h
Mtftp4Driver.h
Mtftp4Driver.c
Mtftp4Wrq.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
BaseLib
UefiLib
UefiBootServicesTableLib
UefiDriverEntryPoint
DebugLib
NetLib
UdpIoLib
[Protocols]
gEfiMtftp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiMtftp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiUdp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiUdp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED

View File

@ -0,0 +1,79 @@
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>Mtftp4Dxe</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>DC3641B8-2FA8-4ed3-BC1F-F9962A03454B</GuidValue>
<Version>1.0</Version>
<Abstract>Component name for module Mtftp4</Abstract>
<Description>FIX ME!</Description>
<Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
<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>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>Mtftp4Dxe</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>Mtftp4Wrq.c</Filename>
<Filename>Mtftp4Driver.c</Filename>
<Filename>Mtftp4Driver.h</Filename>
<Filename>Mtftp4Support.h</Filename>
<Filename>Mtftp4Option.h</Filename>
<Filename>Mtftp4Impl.c</Filename>
<Filename>Mtftp4Support.c</Filename>
<Filename>ComponentName.c</Filename>
<Filename>Mtftp4Impl.h</Filename>
<Filename>Mtftp4Rrq.c</Filename>
<Filename>Mtftp4Option.c</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiUdp4ProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiUdp4ServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiMtftp4ProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiMtftp4ServiceBindingProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>Mtftp4DriverEntryPoint</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

View File

@ -0,0 +1,892 @@
/** @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.c
Abstract:
Interface routine for Mtftp4
**/
#include "Mtftp4Impl.h"
STATIC
EFI_STATUS
EFIAPI
EfiMtftp4ReadFile (
IN EFI_MTFTP4_PROTOCOL *This,
IN EFI_MTFTP4_TOKEN *Token
);
/**
Get the current operation parameter for the MTFTP session
@param This The MTFTP protocol instance
@param ModeData The MTFTP mode data
@retval EFI_INVALID_PARAMETER This or ModeData is NULL
@retval EFI_SUCCESS The operation parameter is saved in ModeData
**/
STATIC
EFI_STATUS
EFIAPI
EfiMtftp4GetModeData (
IN EFI_MTFTP4_PROTOCOL *This,
OUT EFI_MTFTP4_MODE_DATA *ModeData
)
{
MTFTP4_PROTOCOL *Instance;
EFI_TPL OldTpl;
if ((This == NULL) || (ModeData == NULL)) {
return EFI_INVALID_PARAMETER;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
Instance = MTFTP4_PROTOCOL_FROM_THIS (This);
ModeData->ConfigData = Instance->Config;
ModeData->SupportedOptionCount = MTFTP4_SUPPORTED_OPTIONS;
ModeData->SupportedOptoins = mMtftp4SupportedOptions;
ModeData->UnsupportedOptionCount = 0;
ModeData->UnsupportedOptoins = NULL;
NET_RESTORE_TPL (OldTpl);
return EFI_SUCCESS;
}
/**
Clean up the MTFTP session to get ready for new operation.
@param Instance The MTFTP session to clean up
@param Result The result to return to the caller who initiated
the operation.
@return None
**/
VOID
Mtftp4CleanOperation (
IN MTFTP4_PROTOCOL *Instance,
IN EFI_STATUS Result
)
{
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
MTFTP4_BLOCK_RANGE *Block;
EFI_MTFTP4_TOKEN *Token;
//
// Free various resources.
//
Token = Instance->Token;
if (Token != NULL) {
Token->Status = Result;
if (Token->Event != NULL) {
gBS->SignalEvent (Token->Event);
}
Instance->Token = NULL;
}
ASSERT (Instance->UnicastPort != NULL);
UdpIoCleanPort (Instance->UnicastPort);
if (Instance->LastPacket != NULL) {
NetbufFree (Instance->LastPacket);
Instance->LastPacket = NULL;
}
if (Instance->McastUdpPort != NULL) {
UdpIoFreePort (Instance->McastUdpPort);
Instance->McastUdpPort = NULL;
}
NET_LIST_FOR_EACH_SAFE (Entry, Next, &Instance->Blocks) {
Block = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);
NetListRemoveEntry (Entry);
NetFreePool (Block);
}
NetZeroMem (&Instance->RequestOption, sizeof (MTFTP4_OPTION));
Instance->Operation = 0;
Instance->BlkSize = MTFTP4_DEFAULT_BLKSIZE;
Instance->LastBlock = 0;
Instance->ServerIp = 0;
Instance->ListeningPort = 0;
Instance->ConnectedPort = 0;
Instance->Gateway = 0;
Instance->PacketToLive = 0;
Instance->MaxRetry = 0;
Instance->CurRetry = 0;
Instance->Timeout = 0;
Instance->McastIp = 0;
Instance->McastPort = 0;
Instance->Master = TRUE;
}
/**
Configure the MTFTP session for new operation or reset the current
operation if ConfigData is NULL.
@param This The MTFTP session to configure
@param ConfigData The configure parameters
@retval EFI_INVALID_PARAMETER Some of the parameter is invalid.
@retval EFI_ACCESS_DENIED There is pending operation
@retval EFI_SUCCESS The instance is configured for operation.
**/
STATIC
EFI_STATUS
EFIAPI
EfiMtftp4Configure (
IN EFI_MTFTP4_PROTOCOL *This,
IN EFI_MTFTP4_CONFIG_DATA *ConfigData
)
{
MTFTP4_PROTOCOL *Instance;
EFI_TPL OldTpl;
IP4_ADDR Ip;
IP4_ADDR Netmask;
IP4_ADDR Gateway;
IP4_ADDR ServerIp;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = MTFTP4_PROTOCOL_FROM_THIS (This);
if (ConfigData == NULL) {
//
// Reset the operation if ConfigData is NULL
//
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
Mtftp4CleanOperation (Instance, EFI_ABORTED);
NetZeroMem (&Instance->Config, sizeof (EFI_MTFTP4_CONFIG_DATA));
Instance->State = MTFTP4_STATE_UNCONFIGED;
NET_RESTORE_TPL (OldTpl);
} else {
//
// Configure the parameters for new operation.
//
NetCopyMem (&Ip, &ConfigData->StationIp, sizeof (IP4_ADDR));
NetCopyMem (&Netmask, &ConfigData->SubnetMask, sizeof (IP4_ADDR));
NetCopyMem (&Gateway, &ConfigData->GatewayIp, sizeof (IP4_ADDR));
NetCopyMem (&ServerIp, &ConfigData->ServerIp, sizeof (IP4_ADDR));
Ip = NTOHL (Ip);
Netmask = NTOHL (Netmask);
Gateway = NTOHL (Gateway);
ServerIp = NTOHL (ServerIp);
if (!Ip4IsUnicast (ServerIp, 0)) {
return EFI_INVALID_PARAMETER;
}
if (!ConfigData->UseDefaultSetting &&
((!IP4_IS_VALID_NETMASK (Netmask) || !Ip4IsUnicast (Ip, Netmask)))) {
return EFI_INVALID_PARAMETER;
}
if ((Gateway != 0) &&
(!IP4_NET_EQUAL (Gateway, Ip, Netmask) || !Ip4IsUnicast (Gateway, Netmask))) {
return EFI_INVALID_PARAMETER;
}
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
if ((Instance->State == MTFTP4_STATE_CONFIGED) && (Instance->Operation != 0)) {
NET_RESTORE_TPL (OldTpl);
return EFI_ACCESS_DENIED;
}
Instance->Config = *ConfigData;
Instance->State = MTFTP4_STATE_CONFIGED;
NET_RESTORE_TPL (OldTpl);
}
return EFI_SUCCESS;
}
/**
Check packet for GetInfo. GetInfo is implemented with EfiMtftp4ReadFile.
It use Mtftp4GetInfoCheckPacket to inspect the first packet from server,
then abort the session.
@param This The MTFTP4 protocol instance
@param Token The user's token
@param PacketLen The length of the packet
@param Packet The received packet.
@retval EFI_ABORTED Abort the ReadFile operation and return.
**/
STATIC
EFI_STATUS
Mtftp4GetInfoCheckPacket (
IN EFI_MTFTP4_PROTOCOL *This,
IN EFI_MTFTP4_TOKEN *Token,
IN UINT16 PacketLen,
IN EFI_MTFTP4_PACKET *Packet
)
{
MTFTP4_GETINFO_STATE *State;
EFI_STATUS Status;
UINT16 OpCode;
State = (MTFTP4_GETINFO_STATE *) Token->Context;
OpCode = NTOHS (Packet->OpCode);
//
// Set the GetInfo's return status according to the OpCode.
//
switch (OpCode) {
case EFI_MTFTP4_OPCODE_ERROR:
State->Status = EFI_TFTP_ERROR;
break;
case EFI_MTFTP4_OPCODE_OACK:
State->Status = EFI_SUCCESS;
break;
default:
State->Status = EFI_PROTOCOL_ERROR;
}
//
// Allocate buffer then copy the packet over. Use gBS->AllocatePool
// in case NetAllocatePool will implements something tricky.
//
Status = gBS->AllocatePool (EfiBootServicesData, PacketLen, (VOID **) State->Packet);
if (EFI_ERROR (Status)) {
State->Status = EFI_OUT_OF_RESOURCES;
return EFI_ABORTED;
}
*(State->PacketLen) = PacketLen;
NetCopyMem (*(State->Packet), Packet, PacketLen);
return EFI_ABORTED;
}
/**
Get the information of the download from the server. It is implemented
with EfiMtftp4ReadFile: build a token, then pass it to EfiMtftp4ReadFile.
In its check packet callback abort the opertions.
@param This The MTFTP protocol instance
@param OverrideData The MTFTP override data
@param Filename The file to get information
@param ModeStr The mode to use
@param OptionCount The number of options to append
@param OptionList The options to append
@param PacketLength The variable to receive the packet length
@param Packet The variable to receive the packet.
@retval EFI_INVALID_PARAMETER The parameter is invaid
@retval EFI_SUCCESS The information is got
@retval Others Failed to get the information.
**/
STATIC
EFI_STATUS
EFIAPI
EfiMtftp4GetInfo (
IN EFI_MTFTP4_PROTOCOL *This,
IN EFI_MTFTP4_OVERRIDE_DATA *OverrideData, OPTIONAL
IN UINT8 *Filename,
IN UINT8 *ModeStr, OPTIONAL
IN UINT8 OptionCount,
IN EFI_MTFTP4_OPTION *OptionList,
OUT UINT32 *PacketLength,
OUT EFI_MTFTP4_PACKET **Packet OPTIONAL
)
{
EFI_MTFTP4_TOKEN Token;
MTFTP4_GETINFO_STATE State;
EFI_STATUS Status;
if ((This == NULL) || (Filename == NULL) || (PacketLength == NULL) ||
(OptionCount && (OptionList == NULL))) {
return EFI_INVALID_PARAMETER;
}
if (Packet != NULL) {
*Packet = NULL;
}
*PacketLength = 0;
State.Packet = Packet;
State.PacketLen = PacketLength;
State.Status = EFI_SUCCESS;
//
// Fill in the Token to issue an synchronous ReadFile operation
//
Token.Status = EFI_SUCCESS;
Token.Event = NULL;
Token.OverrideData = OverrideData;
Token.Filename = Filename;
Token.ModeStr = ModeStr;
Token.OptionCount = OptionCount;
Token.OptionList = OptionList;
Token.BufferSize = 0;
Token.Buffer = NULL;
Token.Context = &State;
Token.CheckPacket = Mtftp4GetInfoCheckPacket;
Token.TimeoutCallback = NULL;
Token.PacketNeeded = NULL;
Status = EfiMtftp4ReadFile (This, &Token);
if (EFI_ABORTED == Status) {
return State.Status;
}
return Status;
}
/**
Parse the packet into an array of options. The OptionList is allocated
by this function, and caller should free it when used.
@param This The MTFTP protocol instance
@param PacketLen The length of the packet
@param Packet The packet to parse
@param OptionCount The size of the OptionList array allocated.
@param OptionList The allocated option array to save the option
addresses.
@retval EFI_INVALID_PARAMETER The parameters are invalid.
@retval EFI_NOT_FOUND There is no valid option in the packet
@retval EFI_SUCCESS The packet is parsed.
**/
STATIC
EFI_STATUS
EFIAPI
EfiMtftp4ParseOptions (
IN EFI_MTFTP4_PROTOCOL *This,
IN UINT32 PacketLen,
IN EFI_MTFTP4_PACKET *Packet,
IN OUT UINT32 *OptionCount,
OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL
)
{
EFI_STATUS Status;
if ((This == NULL) || (PacketLen < MTFTP4_OPCODE_LEN) ||
(Packet == NULL) || (OptionCount == NULL)) {
return EFI_INVALID_PARAMETER;
}
Status = Mtftp4ExtractOptions (Packet, PacketLen, OptionCount, OptionList);
if (EFI_ERROR (Status)) {
return Status;
}
if (*OptionCount == 0) {
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
/**
Check whether the override data is valid. It will first
validate whether the server is a valid unicast. If a gateway
is provided in the Override, it also check that it is a
unicast on the connected network.
@param Instance The MTFTP instance
@param Override The override data to validate.
@return TRUE if the override data is valid, otherwise FALSE.
**/
STATIC
BOOLEAN
Mtftp4OverrideValid (
IN MTFTP4_PROTOCOL *Instance,
IN EFI_MTFTP4_OVERRIDE_DATA *Override
)
{
EFI_MTFTP4_CONFIG_DATA *Config;
IP4_ADDR Ip;
IP4_ADDR Netmask;
IP4_ADDR Gateway;
NetCopyMem (&Ip, &Override->ServerIp, sizeof (IP4_ADDR));
if (!Ip4IsUnicast (NTOHL (Ip), 0)) {
return FALSE;
}
Config = &Instance->Config;
NetCopyMem (&Gateway, &Override->GatewayIp, sizeof (IP4_ADDR));
Gateway = NTOHL (Gateway);
if (!Config->UseDefaultSetting && (Gateway != 0)) {
NetCopyMem (&Netmask, &Config->SubnetMask, sizeof (IP4_ADDR));
NetCopyMem (&Ip, &Config->StationIp, sizeof (IP4_ADDR));
Netmask = NTOHL (Netmask);
Ip = NTOHL (Ip);
if (!Ip4IsUnicast (Gateway, Netmask) || !IP4_NET_EQUAL (Gateway, Ip, Netmask)) {
return FALSE;
}
}
return TRUE;
}
/**
Poll the UDP to get the IP4 default address, which may be retrieved
by DHCP. The default time out value is 5 seconds. If IP has retrieved
the default address, the UDP is reconfigured.
@param Instance The Mtftp instance
@param UdpPort The UDP port to poll
@param UdpCfgData The UDP configure data to reconfigure the UDP
port.
@return TRUE if the default address is retrieved and UDP is reconfigured.
@return Otherwise FALSE.
**/
BOOLEAN
Mtftp4GetMapping (
IN MTFTP4_PROTOCOL *Instance,
IN UDP_IO_PORT *UdpPort,
IN EFI_UDP4_CONFIG_DATA *UdpCfgData
)
{
MTFTP4_SERVICE *Service;
EFI_IP4_MODE_DATA Ip4Mode;
EFI_UDP4_PROTOCOL *Udp;
EFI_STATUS Status;
ASSERT (Instance->Config.UseDefaultSetting);
Service = Instance->Service;
Udp = UdpPort->Udp;
Status = gBS->SetTimer (
Service->TimerToGetMap,
TimerRelative,
MTFTP4_TIME_TO_GETMAP * TICKS_PER_SECOND
);
if (EFI_ERROR (Status)) {
return FALSE;
}
while (!EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {
Udp->Poll (Udp);
if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip4Mode, NULL, NULL)) &&
Ip4Mode.IsConfigured) {
Udp->Configure (Udp, NULL);
return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);
}
}
return FALSE;
}
/**
Configure the UDP port for unicast receiving.
@param UdpIo The UDP port
@param Instance The MTFTP session
@retval EFI_SUCCESS The UDP port is successfully configured for the
session to unicast receive.
**/
STATIC
EFI_STATUS
Mtftp4ConfigUnicastPort (
IN UDP_IO_PORT *UdpIo,
IN MTFTP4_PROTOCOL *Instance
)
{
EFI_MTFTP4_CONFIG_DATA *Config;
EFI_UDP4_CONFIG_DATA UdpConfig;
EFI_STATUS Status;
IP4_ADDR Ip;
Config = &Instance->Config;
UdpConfig.AcceptBroadcast = FALSE;
UdpConfig.AcceptPromiscuous = FALSE;
UdpConfig.AcceptAnyPort = FALSE;
UdpConfig.AllowDuplicatePort = FALSE;
UdpConfig.TypeOfService = 0;
UdpConfig.TimeToLive = 64;
UdpConfig.DoNotFragment = FALSE;
UdpConfig.ReceiveTimeout = 0;
UdpConfig.TransmitTimeout = 0;
UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;
UdpConfig.StationAddress = Config->StationIp;
UdpConfig.SubnetMask = Config->SubnetMask;
UdpConfig.StationPort = 0;
UdpConfig.RemotePort = 0;
Ip = HTONL (Instance->ServerIp);
NetCopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
Status = UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfig);
if ((Status == EFI_NO_MAPPING) && Mtftp4GetMapping (Instance, UdpIo, &UdpConfig)) {
return EFI_SUCCESS;
}
return Status;
}
/**
Start the MTFTP session to do the operation, such as read file,
write file, and read directory.
@param This The MTFTP session
@param Token The token than encapsues the user's request.
@param Operation The operation to do
@retval EFI_INVALID_PARAMETER Some of the parameters are invalid.
@retval EFI_NOT_STARTED The MTFTP session hasn't been configured.
@retval EFI_ALREADY_STARTED There is pending operation for the session.
@retval EFI_SUCCESS The operation is successfully started.
**/
STATIC
EFI_STATUS
Mtftp4Start (
IN EFI_MTFTP4_PROTOCOL *This,
IN EFI_MTFTP4_TOKEN *Token,
IN UINT16 Operation
)
{
MTFTP4_PROTOCOL *Instance;
EFI_MTFTP4_OVERRIDE_DATA *Override;
EFI_MTFTP4_CONFIG_DATA *Config;
EFI_TPL OldTpl;
EFI_STATUS Status;
//
// Validate the parameters
//
if ((This == NULL) || (Token == NULL) || (Token->Filename == NULL) ||
((Token->OptionCount != 0) && (Token->OptionList == NULL))) {
return EFI_INVALID_PARAMETER;
}
//
// User must provide at least one method to collect the data for download.
//
if (((Operation == EFI_MTFTP4_OPCODE_RRQ) || (Operation == EFI_MTFTP4_OPCODE_DIR)) &&
((Token->Buffer == NULL) && (Token->CheckPacket == NULL))) {
return EFI_INVALID_PARAMETER;
}
//
// User must provide at least one method to provide the data for upload.
//
if ((Operation == EFI_MTFTP4_OPCODE_WRQ) &&
((Token->Buffer == NULL) && (Token->PacketNeeded == NULL))) {
return EFI_INVALID_PARAMETER;
}
Instance = MTFTP4_PROTOCOL_FROM_THIS (This);
Status = EFI_SUCCESS;
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
if (Instance->State != MTFTP4_STATE_CONFIGED) {
Status = EFI_NOT_STARTED;
}
if (Instance->Operation != 0) {
Status = EFI_ACCESS_DENIED;
}
if (EFI_ERROR (Status)) {
NET_RESTORE_TPL (OldTpl);
return Status;
}
//
// Set the Operation now to prevent the application start other
// operations.
//
Instance->Operation = Operation;
Override = Token->OverrideData;
if ((Override != NULL) && !Mtftp4OverrideValid (Instance, Override)) {
Status = EFI_INVALID_PARAMETER;
goto ON_ERROR;
}
if (Token->OptionCount != 0) {
Status = Mtftp4ParseOption (
Token->OptionList,
Token->OptionCount,
TRUE,
&Instance->RequestOption
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
}
//
// Set the operation parameters from the configuration or override data.
//
Config = &Instance->Config;
Instance->Token = Token;
Instance->BlkSize = MTFTP4_DEFAULT_BLKSIZE;
NetCopyMem (&Instance->ServerIp, &Config->ServerIp, sizeof (IP4_ADDR));
Instance->ServerIp = NTOHL (Instance->ServerIp);
Instance->ListeningPort = Config->InitialServerPort;
Instance->ConnectedPort = 0;
NetCopyMem (&Instance->Gateway, &Config->GatewayIp, sizeof (IP4_ADDR));
Instance->Gateway = NTOHL (Instance->Gateway);
Instance->MaxRetry = Config->TryCount;
Instance->Timeout = Config->TimeoutValue;
Instance->Master = TRUE;
if (Override != NULL) {
NetCopyMem (&Instance->ServerIp, &Override->ServerIp, sizeof (IP4_ADDR));
NetCopyMem (&Instance->Gateway, &Override->GatewayIp, sizeof (IP4_ADDR));
Instance->ServerIp = NTOHL (Instance->ServerIp);
Instance->Gateway = NTOHL (Instance->Gateway);
Instance->ListeningPort = Override->ServerPort;
Instance->MaxRetry = Override->TryCount;
Instance->Timeout = Override->TimeoutValue;
}
if (Instance->ListeningPort == 0) {
Instance->ListeningPort = MTFTP4_DEFAULT_SERVER_PORT;
}
if (Instance->MaxRetry == 0) {
Instance->MaxRetry = MTFTP4_DEFAULT_RETRY;
}
if (Instance->Timeout == 0) {
Instance->Timeout = MTFTP4_DEFAULT_TIMEOUT;
}
//
// Config the unicast UDP child to send initial request
//
Status = Mtftp4ConfigUnicastPort (Instance->UnicastPort, Instance);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
//
// Build and send an initial requests
//
if (Operation == EFI_MTFTP4_OPCODE_WRQ) {
Status = Mtftp4WrqStart (Instance, Operation);
} else {
Status = Mtftp4RrqStart (Instance, Operation);
}
NET_RESTORE_TPL (OldTpl);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
//
// Return immediately for asynchronous operation or poll the
// instance for synchronous operation.
//
Token->Status = EFI_NOT_READY;
if (Token->Event != NULL) {
return EFI_SUCCESS;
}
while (Token->Status == EFI_NOT_READY) {
This->Poll (This);
}
return Token->Status;
ON_ERROR:
Mtftp4CleanOperation (Instance, Status);
NET_RESTORE_TPL (OldTpl);
return Status;
}
/**
Read a file from the server.
@param This The Mtftp protocol instance.
@param Token The user's request wrap token.
@retval EFI_SUCCESS The ReadFile has finished, the file has been
downloaded if it is synchronous operation,
otherwise it has been initated.
@retval Others Some error happened.
**/
STATIC
EFI_STATUS
EFIAPI
EfiMtftp4ReadFile (
IN EFI_MTFTP4_PROTOCOL *This,
IN EFI_MTFTP4_TOKEN *Token
)
{
return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_RRQ);
}
/**
Upload a file to the server.
@param This The MTFTP protocol session
@param Token The user's request wrap token.
@retval EFI_SUCCESS The WriteFile has finished, the file has been
uploaded if it is synchronous operation, otherwise
it has been initated.
@retval Others Some error happened.
**/
STATIC
EFI_STATUS
EFIAPI
EfiMtftp4WriteFile (
IN EFI_MTFTP4_PROTOCOL *This,
IN EFI_MTFTP4_TOKEN *Token
)
{
return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_WRQ);
}
/**
Read a directory from the server. The only difference
between ReadFile and ReadDirectory is the opcode used.
@param This The MTFTP protocol session
@param Token The user's request wrap token.
@retval EFI_SUCCESS The ReadDirectory has finished, the directory has
been downloaded as a file if it is synchronous
operation, otherwise it has been initated.
@retval Others Some error happened.
**/
STATIC
EFI_STATUS
EFIAPI
EfiMtftp4ReadDirectory (
IN EFI_MTFTP4_PROTOCOL *This,
IN EFI_MTFTP4_TOKEN *Token
)
{
return Mtftp4Start (This, Token, EFI_MTFTP4_OPCODE_DIR);
}
/**
Poll the network stack to accelerate the packet process.
@param This The MTFTP protocol instance.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_NOT_STARTED The MTFTP session hasn't been configured.
@retval EFI_DEVICE_ERROR The MTFTP session has been destoried.
**/
STATIC
EFI_STATUS
EFIAPI
EfiMtftp4Poll (
IN EFI_MTFTP4_PROTOCOL *This
)
{
MTFTP4_PROTOCOL *Instance;
EFI_UDP4_PROTOCOL *Udp;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = MTFTP4_PROTOCOL_FROM_THIS (This);
if (Instance->State == MTFTP4_STATE_UNCONFIGED) {
return EFI_NOT_STARTED;
} else if (Instance->State == MTFTP4_STATE_DESTORY) {
return EFI_DEVICE_ERROR;
}
Udp = Instance->UnicastPort->Udp;
return Udp->Poll (Udp);
}
EFI_MTFTP4_PROTOCOL gMtftp4ProtocolTemplate = {
EfiMtftp4GetModeData,
EfiMtftp4Configure,
EfiMtftp4GetInfo,
EfiMtftp4ParseOptions,
EfiMtftp4ReadFile,
EfiMtftp4WriteFile,
EfiMtftp4ReadDirectory,
EfiMtftp4Poll
};

View File

@ -0,0 +1,176 @@
/** @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>
#include <Protocol/Udp4.h>
#include <Protocol/Mtftp4.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#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

View File

@ -0,0 +1,542 @@
/** @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.c
Abstract:
routines to process MTFTP4 options
**/
#include "Mtftp4Impl.h"
UINT8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS] = {
"blksize",
"timeout",
"tsize",
"multicast"
};
/**
Go through the packet to fill the Options array with the start
addresses of each MTFTP option name/value pair.
@param Packet The packet to check
@param PacketLen The packet's length
@param Count The size of the Options on input. The actual
options on output
@param Options The option array to fill in
@retval EFI_INVALID_PARAMETER The packet is mal-formated
@retval EFI_BUFFER_TOO_SMALL The Options array is too small
@retval EFI_SUCCESS The packet has been parsed into the Options array.
**/
STATIC
EFI_STATUS
Mtftp4FillOptions (
IN EFI_MTFTP4_PACKET *Packet,
IN UINT32 PacketLen,
IN OUT UINT32 *Count,
OUT EFI_MTFTP4_OPTION *Options OPTIONAL
)
{
UINT8 *Cur;
UINT8 *Last;
UINT8 Num;
UINT8 *Name;
UINT8 *Value;
Num = 0;
Cur = (UINT8 *) Packet + MTFTP4_OPCODE_LEN;
Last = (UINT8 *) Packet + PacketLen - 1;
//
// process option name and value pairs. The last byte is always zero
//
while (Cur < Last) {
Name = Cur;
while (*Cur != 0) {
Cur++;
}
if (Cur == Last) {
return EFI_INVALID_PARAMETER;
}
Value = ++Cur;
while (*Cur != 0) {
Cur++;
}
Num++;
if ((Options != NULL) && (Num <= *Count)) {
Options[Num - 1].OptionStr = Name;
Options[Num - 1].ValueStr = Value;
}
Cur++;
}
if ((*Count < Num) || (Options == NULL)) {
*Count = Num;
return EFI_BUFFER_TOO_SMALL;
}
*Count = Num;
return EFI_SUCCESS;
}
/**
Allocate and fill in a array of Mtftp options from the Packet. It
first calls Mtftp4FillOption to get the option number, then allocate
the array, at last, call Mtftp4FillOption again to save the options.
@param Packet The packet to parse
@param PacketLen The length of the packet
@param OptionCount The number of options in the packet
@param OptionList The point to get the option array.
@retval EFI_INVALID_PARAMETER The parametera are invalid or packet isn't a
well-formated OACK packet.
@retval EFI_SUCCESS The option array is build
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array
**/
EFI_STATUS
Mtftp4ExtractOptions (
IN EFI_MTFTP4_PACKET *Packet,
IN UINT32 PacketLen,
IN OUT UINT32 *OptionCount,
OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL
)
{
EFI_STATUS Status;
*OptionCount = 0;
if (OptionList != NULL) {
*OptionList = NULL;
}
if (NTOHS (Packet->OpCode) != EFI_MTFTP4_OPCODE_OACK) {
return EFI_INVALID_PARAMETER;
}
if (PacketLen == MTFTP4_OPCODE_LEN) {
return EFI_SUCCESS;
}
//
// The last byte must be zero to terminate the options
//
if (*((UINT8 *) Packet + PacketLen - 1) != 0) {
return EFI_INVALID_PARAMETER;
}
//
// Get the number of options
//
Status = Mtftp4FillOptions (Packet, PacketLen, OptionCount, NULL);
if ((Status == EFI_SUCCESS) || (Status != EFI_BUFFER_TOO_SMALL)) {
return Status;
}
//
// Allocate memory for the options, then call Mtftp4FillOptions to
// fill it if caller want that.
//
if (OptionList == NULL) {
return EFI_SUCCESS;
}
*OptionList = NetAllocatePool (*OptionCount * sizeof (EFI_MTFTP4_OPTION));
if (*OptionList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Mtftp4FillOptions (Packet, PacketLen, OptionCount, *OptionList);
return EFI_SUCCESS;
}
/**
Check whether two ascii strings are equel, ignore the case.
@param Str1 The first ascii string
@param Str2 The second ascii string
@retval TRUE Two strings are equal when case is ignored.
@retval FALSE Two string are not equal.
**/
BOOLEAN
NetStringEqualNoCase (
IN UINT8 *Str1,
IN UINT8 *Str2
)
{
UINT8 Ch1;
UINT8 Ch2;
ASSERT ((Str1 != NULL) && (Str2 != NULL));
for (; (*Str1 != '\0') && (*Str2 != '\0'); Str1++, Str2++) {
Ch1 = *Str1;
Ch2 = *Str2;
//
// Convert them to lower case then compare two
//
if (('A' <= Ch1) && (Ch1 <= 'Z')) {
Ch1 += 'a' - 'A';
}
if (('A' <= Ch2) && (Ch2 <= 'Z')) {
Ch2 += 'a' - 'A';
}
if (Ch1 != Ch2) {
return FALSE;
}
}
return (BOOLEAN) (*Str1 == *Str2);
}
/**
Convert a string to a UINT32 number.
@param Str The string to convert from
@return The number get from the string
**/
UINT32
NetStringToU32 (
IN UINT8 *Str
)
{
UINT32 Num;
ASSERT (Str != NULL);
Num = 0;
for (; NET_IS_DIGIT (*Str); Str++) {
Num = Num * 10 + (*Str - '0');
}
return Num;
}
/**
Convert a string of the format "192.168.0.1" to an IP address.
@param Str The string representation of IP
@param Ip The varible to get IP.
@retval EFI_INVALID_PARAMETER The IP string is invalid.
@retval EFI_SUCCESS The IP is parsed into the Ip
**/
STATIC
EFI_STATUS
NetStringToIp (
IN UINT8 *Str,
OUT IP4_ADDR *Ip
)
{
UINT32 Byte;
UINT32 Addr;
UINTN Index;
*Ip = 0;
Addr = 0;
for (Index = 0; Index < 4; Index++) {
if (!NET_IS_DIGIT (*Str)) {
return EFI_INVALID_PARAMETER;
}
Byte = NetStringToU32 (Str);
if (Byte > 255) {
return EFI_INVALID_PARAMETER;
}
Addr = (Addr << 8) | Byte;
//
// Skip all the digitals and check whether the sepeator is the dot
//
while (NET_IS_DIGIT (*Str)) {
Str++;
}
if ((Index < 3) && (*Str != '.')) {
return EFI_INVALID_PARAMETER;
}
Str++;
}
*Ip = Addr;
return EFI_SUCCESS;
}
/**
Parse the MTFTP multicast option.
@param Value The Mtftp multicast value string
@param Option The option to save the info into.
@retval EFI_INVALID_PARAMETER The multicast value string is invalid.
@retval EFI_SUCCESS The multicast value is parsed into the Option
**/
STATIC
EFI_STATUS
Mtftp4ExtractMcast (
IN UINT8 *Value,
IN MTFTP4_OPTION *Option
)
{
EFI_STATUS Status;
UINT32 Num;
//
// The multicast option is formated like "204.0.0.1,1857,1"
// The server can also omit the ip and port, use ",,1"
//
if (*Value == ',') {
Option->McastIp = 0;
} else {
Status = NetStringToIp (Value, &Option->McastIp);
if (EFI_ERROR (Status)) {
return Status;
}
while (*Value && (*Value != ',')) {
Value++;
}
}
if (*Value != ',') {
return EFI_INVALID_PARAMETER;
}
Value++;
//
// Convert the port setting. the server can send us a port number or
// empty string. such as the port in ",,1"
//
if (*Value == ',') {
Option->McastPort = 0;
} else {
Num = NetStringToU32 (Value);
if (Num > 65535) {
return EFI_INVALID_PARAMETER;
}
Option->McastPort = (UINT16)Num;
while (NET_IS_DIGIT (*Value)) {
Value++;
}
}
if (*Value != ',') {
return EFI_INVALID_PARAMETER;
}
Value++;
//
// Check the master/slave setting, 1 for master, 0 for slave.
//
Num = NetStringToU32 (Value);
if ((Num != 0) && (Num != 1)) {
return EFI_INVALID_PARAMETER;
}
Option->Master = (BOOLEAN)(Num == 1);
while (NET_IS_DIGIT (*Value)) {
Value++;
}
if (*Value != '\0') {
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
/**
Parse the option in Options array to MTFTP4_OPTION which program
can access directly.
@param Options The option array, which contains addresses of each
option's name/value string.
@param Count The number of options in the Options
@param Request Whether this is a request or OACK. The format of
multicast is different according to this setting.
@param MtftpOption The MTFTP4_OPTION for easy access.
@retval EFI_INVALID_PARAMETER The option is mal-formated
@retval EFI_UNSUPPORTED Some option isn't supported
@retval EFI_SUCCESS The option are OK and has been parsed.
**/
EFI_STATUS
Mtftp4ParseOption (
IN EFI_MTFTP4_OPTION *Options,
IN UINT32 Count,
IN BOOLEAN Request,
OUT MTFTP4_OPTION *MtftpOption
)
{
EFI_STATUS Status;
UINT32 Index;
UINT32 Value;
EFI_MTFTP4_OPTION *This;
MtftpOption->Exist = 0;
for (Index = 0; Index < Count; Index++) {
This = Options + Index;
if ((This->OptionStr == NULL) || (This->ValueStr == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (NetStringEqualNoCase (This->OptionStr, "blksize")) {
//
// block size option, valid value is between [8, 65464]
//
Value = NetStringToU32 (This->ValueStr);
if ((Value < 8) || (Value > 65464)) {
return EFI_INVALID_PARAMETER;
}
MtftpOption->BlkSize = (UINT16) Value;
MtftpOption->Exist |= MTFTP4_BLKSIZE_EXIST;
} else if (NetStringEqualNoCase (This->OptionStr, "timeout")) {
//
// timeout option, valid value is between [1, 255]
//
Value = NetStringToU32 (This->ValueStr);
if ((Value < 1) || (Value > 255)) {
return EFI_INVALID_PARAMETER;
}
MtftpOption->Timeout = (UINT8) Value;
} else if (NetStringEqualNoCase (This->OptionStr, "tsize")) {
//
// tsize option, the biggest transfer supported is 4GB with block size option
//
MtftpOption->Tsize = NetStringToU32 (This->ValueStr);
MtftpOption->Exist |= MTFTP4_TSIZE_EXIST;
} else if (NetStringEqualNoCase (This->OptionStr, "multicast")) {
//
// Multicast option, if it is a request, the value must be a zero
// length string, otherwise, it is formated like "204.0.0.1,1857,1\0"
//
if (Request) {
if (*(This->ValueStr) != '\0') {
return EFI_INVALID_PARAMETER;
}
} else {
Status = Mtftp4ExtractMcast (This->ValueStr, MtftpOption);
if (EFI_ERROR (Status)) {
return Status;
}
}
MtftpOption->Exist |= MTFTP4_MCAST_EXIST;
} else if (Request) {
//
// Ignore the unsupported option if it is a reply, and return
// EFI_UNSUPPORTED if it's a request according to the UEFI spec.
//
return EFI_UNSUPPORTED;
}
}
return EFI_SUCCESS;
}
/**
Parse the options in the OACK packet to MTFTP4_OPTION which program
can access directly.
@param Packet The OACK packet to parse
@param PacketLen The length of the packet
@param MtftpOption The MTFTP_OPTION for easy access.
@retval EFI_INVALID_PARAMETER The packet option is mal-formated
@retval EFI_UNSUPPORTED Some option isn't supported
@retval EFI_SUCCESS The option are OK and has been parsed.
**/
EFI_STATUS
Mtftp4ParseOptionOack (
IN EFI_MTFTP4_PACKET *Packet,
IN UINT32 PacketLen,
OUT MTFTP4_OPTION *MtftpOption
)
{
EFI_MTFTP4_OPTION *OptionList;
EFI_STATUS Status;
UINT32 Count;
MtftpOption->Exist = 0;
Status = Mtftp4ExtractOptions (Packet, PacketLen, &Count, &OptionList);
if (EFI_ERROR (Status) || (Count == 0)) {
return Status;
}
Status = Mtftp4ParseOption (OptionList, Count, FALSE, MtftpOption);
NetFreePool (OptionList);
return Status;
}

View File

@ -0,0 +1,73 @@
/** @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

View File

@ -0,0 +1,735 @@
/** @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:
Mtftp4Rrq.c
Abstract:
Routines to process Rrq (download)
**/
#include "Mtftp4Impl.h"
VOID
Mtftp4RrqInput (
IN NET_BUF *UdpPacket,
IN UDP_POINTS *Points,
IN EFI_STATUS IoStatus,
IN VOID *Context
);
/**
Start the MTFTP session to download. It will first initialize some
of the internal states then build and send a RRQ reqeuest packet, at
last, it will start receive for the downloading.
@param Instance The Mtftp session
@param Operation The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ
or EFI_MTFTP4_OPCODE_DIR.
@retval EFI_SUCCESS The mtftp download session is started.
@retval Others Failed to start downloading.
**/
EFI_STATUS
Mtftp4RrqStart (
IN MTFTP4_PROTOCOL *Instance,
IN UINT16 Operation
)
{
EFI_STATUS Status;
//
// The valid block number range are [1, 0xffff]. For example:
// the client sends an RRQ request to the server, the server
// transfers the DATA1 block. If option negoitation is ongoing,
// the server will send back an OACK, then client will send ACK0.
//
Status = Mtftp4InitBlockRange (&Instance->Blocks, 1, 0xffff);
if (EFI_ERROR (Status)) {
return Status;
}
Status = Mtftp4SendRequest (Instance);
if (EFI_ERROR (Status)) {
return Status;
}
return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
}
/**
Build and send a ACK packet for the download session.
@param Instance The Mtftp session
@param BlkNo The BlkNo to ack.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet
@retval EFI_SUCCESS The ACK has been sent
@retval Others Failed to send the ACK.
**/
EFI_STATUS
Mtftp4RrqSendAck (
IN MTFTP4_PROTOCOL *Instance,
IN UINT16 BlkNo
)
{
EFI_MTFTP4_PACKET *Ack;
NET_BUF *Packet;
Packet = NetbufAlloc (sizeof (EFI_MTFTP4_ACK_HEADER));
if (Packet == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Ack = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (
Packet,
sizeof (EFI_MTFTP4_ACK_HEADER),
FALSE
);
Ack->Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);
Ack->Ack.Block[0] = HTONS (BlkNo);
return Mtftp4SendPacket (Instance, Packet);
}
/**
Deliver the received data block to the user, which can be saved
in the user provide buffer or through the CheckPacket callback.
@param Instance The Mtftp session
@param Packet The received data packet
@param Len The packet length
@retval EFI_SUCCESS The data is saved successfully
@retval EFI_ABORTED The user tells to abort by return an error through
CheckPacket
@retval EFI_BUFFER_TOO_SMALL The user's buffer is too small and buffer length is
updated to the actual buffer size needed.
**/
EFI_STATUS
Mtftp4RrqSaveBlock (
IN MTFTP4_PROTOCOL *Instance,
IN EFI_MTFTP4_PACKET *Packet,
IN UINT32 Len
)
{
EFI_MTFTP4_TOKEN *Token;
EFI_STATUS Status;
UINT16 Block;
UINT64 Start;
UINT32 DataLen;
Token = Instance->Token;
Block = NTOHS (Packet->Data.Block);
DataLen = Len - MTFTP4_DATA_HEAD_LEN;
//
// This is the last block, save the block no
//
if (DataLen < Instance->BlkSize) {
Instance->LastBlock = Block;
Mtftp4SetLastBlockNum (&Instance->Blocks, Block);
}
//
// Remove this block number from the file hole. If Mtftp4RemoveBlockNum
// returns EFI_NOT_FOUND, the block has been saved, don't save it again.
//
Status = Mtftp4RemoveBlockNum (&Instance->Blocks, Block);
if (Status == EFI_NOT_FOUND) {
return EFI_SUCCESS;
} else if (EFI_ERROR (Status)) {
return Status;
}
if (Token->CheckPacket != NULL) {
Status = Token->CheckPacket (&Instance->Mtftp4, Token, (UINT16) Len, Packet);
if (EFI_ERROR (Status)) {
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
"User aborted download"
);
return EFI_ABORTED;
}
}
if (Token->Buffer != NULL) {
Start = MultU64x32 (Block - 1, Instance->BlkSize);
if (Start + DataLen <= Token->BufferSize) {
NetCopyMem ((UINT8 *) Token->Buffer + Start, Packet->Data.Data, DataLen);
//
// Update the file size when received the last block
//
if (Instance->LastBlock == Block) {
Token->BufferSize = Start + DataLen;
}
} else if (Instance->LastBlock != 0) {
//
// Don't save the data if the buffer is too small, return
// EFI_BUFFER_TOO_SMALL if received the last packet. This
// will give a accurate file length.
//
Token->BufferSize = Start + DataLen;
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_DISK_FULL,
"User provided memory block is too small"
);
return EFI_BUFFER_TOO_SMALL;
}
}
return EFI_SUCCESS;
}
/**
Function to process the received data packets. It will save the block
then send back an ACK if it is active.
@param Instance The downloading MTFTP session
@param Packet The packet received
@param Len The length of the packet
@param Multicast Whether this packet is multicast or unicast
@param Completed Return whether the download has completed
@retval EFI_SUCCESS The data packet is successfully processed
@retval EFI_ABORTED The download is aborted by the user
@retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
**/
EFI_STATUS
Mtftp4RrqHandleData (
IN MTFTP4_PROTOCOL *Instance,
IN EFI_MTFTP4_PACKET *Packet,
IN UINT32 Len,
IN BOOLEAN Multicast,
OUT BOOLEAN *Completed
)
{
EFI_STATUS Status;
UINT16 BlockNum;
INTN Expected;
*Completed = FALSE;
BlockNum = NTOHS (Packet->Data.Block);
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
ASSERT (Expected >= 0);
//
// If we are active and received an unexpected packet, retransmit
// the last ACK then restart receiving. If we are passive, save
// the block.
//
if (Instance->Master && (Expected != BlockNum)) {
Mtftp4Retransmit (Instance);
return EFI_SUCCESS;
}
Status = Mtftp4RrqSaveBlock (Instance, Packet, Len);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Reset the passive client's timer whenever it received a
// valid data packet.
//
if (!Instance->Master) {
Mtftp4SetTimeout (Instance);
}
//
// Check whether we have received all the blocks. Send the ACK if we
// are active (unicast client or master client for multicast download).
// If we have received all the blocks, send an ACK even if we are passive
// to tell the server that we are done.
//
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
if (Instance->Master || (Expected < 0)) {
if (Expected < 0) {
//
// If we are passive client, then the just received Block maybe
// isn't the last block. We need to send an ACK to the last block
// to inform the server that we are done. If we are active client,
// the Block == Instance->LastBlock.
//
BlockNum = Instance->LastBlock;
*Completed = TRUE;
} else {
BlockNum = (UINT16) (Expected - 1);
}
Mtftp4RrqSendAck (Instance, BlockNum);
}
return EFI_SUCCESS;
}
/**
Validate whether the options received in the server's OACK packet is valid.
The options are valid only if:
1. The server doesn't include options not requested by us
2. The server can only use smaller blksize than that is requested
3. The server can only use the same timeout as requested
4. The server doesn't change its multicast channel.
@param This The downloading Mtftp session
@param Reply The options in the OACK packet
@param Request The requested options
@return TRUE if the options in the OACK is OK, otherwise FALSE.
**/
BOOLEAN
Mtftp4RrqOackValid (
IN MTFTP4_PROTOCOL *This,
IN MTFTP4_OPTION *Reply,
IN MTFTP4_OPTION *Request
)
{
//
// It is invalid for server to return options we don't request
//
if ((Reply->Exist &~Request->Exist) != 0) {
return FALSE;
}
//
// Server can only specify a smaller block size to be used and
// return the timeout matches that requested.
//
if (((Reply->Exist & MTFTP4_BLKSIZE_EXIST) && (Reply->BlkSize > Request->BlkSize)) ||
((Reply->Exist & MTFTP4_TIMEOUT_EXIST) && (Reply->Timeout != Request->Timeout))) {
return FALSE;
}
//
// The server can send ",,master" to client to change its master
// setting. But if it use the specific multicast channel, it can't
// change the setting.
//
if ((Reply->Exist & MTFTP4_MCAST_EXIST) && (This->McastIp != 0)) {
if ((Reply->McastIp != 0) && (Reply->McastIp != This->McastIp)) {
return FALSE;
}
if ((Reply->McastPort != 0) && (Reply->McastPort != This->McastPort)) {
return FALSE;
}
}
return TRUE;
}
/**
Configure a UDP IO port to receive the multicast.
@param McastIo The UDP IO port to configure
@param Context The opaque parameter to the function which is the
MTFTP session.
@retval EFI_SUCCESS The udp child is successfully configured.
@retval Others Failed to configure the UDP child.
**/
STATIC
EFI_STATUS
Mtftp4RrqConfigMcastPort (
IN UDP_IO_PORT *McastIo,
IN VOID *Context
)
{
MTFTP4_PROTOCOL *Instance;
EFI_MTFTP4_CONFIG_DATA *Config;
EFI_UDP4_CONFIG_DATA UdpConfig;
EFI_IPv4_ADDRESS Group;
EFI_STATUS Status;
IP4_ADDR Ip;
Instance = (MTFTP4_PROTOCOL *) Context;
Config = &Instance->Config;
UdpConfig.AcceptBroadcast = FALSE;
UdpConfig.AcceptPromiscuous = FALSE;
UdpConfig.AcceptAnyPort = FALSE;
UdpConfig.AllowDuplicatePort = FALSE;
UdpConfig.TypeOfService = 0;
UdpConfig.TimeToLive = 64;
UdpConfig.DoNotFragment = FALSE;
UdpConfig.ReceiveTimeout = 0;
UdpConfig.TransmitTimeout = 0;
UdpConfig.UseDefaultAddress = Config->UseDefaultSetting;
UdpConfig.StationAddress = Config->StationIp;
UdpConfig.SubnetMask = Config->SubnetMask;
UdpConfig.StationPort = Instance->McastPort;
UdpConfig.RemotePort = 0;
Ip = HTONL (Instance->ServerIp);
NetCopyMem (&UdpConfig.RemoteAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
Status = McastIo->Udp->Configure (McastIo->Udp, &UdpConfig);
if (EFI_ERROR (Status)) {
return Status;
}
//
// join the multicast group
//
Ip = HTONL (Instance->McastIp);
NetCopyMem (&Group, &Ip, sizeof (EFI_IPv4_ADDRESS));
return McastIo->Udp->Groups (McastIo->Udp, TRUE, &Group);
}
/**
Function to process the OACK. It will first validate the OACK
packet, then update the various negotiated parameters.
@param Instance The download MTFTP session
@param Packet The packet received
@param Len The packet length
@param Multicast Whether this packet is received as a multicast
@param Completed Returns whether the download has completed. NOT
used by this function.
@retval EFI_DEVICE_ERROR Failed to create/start a multicast UDP child
@retval EFI_TFTP_ERROR Some error happened during the process
@retval EFI_SUCCESS The OACK is successfully processed.
**/
EFI_STATUS
Mtftp4RrqHandleOack (
IN MTFTP4_PROTOCOL *Instance,
IN EFI_MTFTP4_PACKET *Packet,
IN UINT32 Len,
IN BOOLEAN Multicast,
OUT BOOLEAN *Completed
)
{
MTFTP4_OPTION Reply;
EFI_STATUS Status;
INTN Expected;
*Completed = FALSE;
//
// If already started the master download, don't change the
// setting. Master download always succeeds.
//
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
ASSERT (Expected != -1);
if (Instance->Master && (Expected != 1)) {
return EFI_SUCCESS;
}
//
// Parse and validate the options from server
//
NetZeroMem (&Reply, sizeof (MTFTP4_OPTION));
Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);
if (EFI_ERROR (Status) ||
!Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) {
//
// Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
//
if (Status != EFI_OUT_OF_RESOURCES) {
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
"Mal-formated OACK packet"
);
}
return EFI_TFTP_ERROR;
}
if (Reply.Exist & MTFTP4_MCAST_EXIST) {
//
// Save the multicast info. Always update the Master, only update the
// multicast IP address, block size, timeoute at the first time. If IP
// address is updated, create a UDP child to receive the multicast.
//
Instance->Master = Reply.Master;
if (Instance->McastIp == 0) {
if ((Reply.McastIp == 0) || (Reply.McastPort == 0)) {
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
"Illegal multicast setting"
);
return EFI_TFTP_ERROR;
}
//
// Create a UDP child then start receive the multicast from it.
//
Instance->McastIp = Reply.McastIp;
Instance->McastPort = Reply.McastPort;
Instance->McastUdpPort = UdpIoCreatePort (
Instance->Service->Controller,
Instance->Service->Image,
Mtftp4RrqConfigMcastPort,
Instance
);
if (Instance->McastUdpPort == NULL) {
return EFI_DEVICE_ERROR;
}
Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
if (EFI_ERROR (Status)) {
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION,
"Failed to create socket to receive multicast packet"
);
return Status;
}
//
// Update the parameters used.
//
if (Reply.BlkSize != 0) {
Instance->BlkSize = Reply.BlkSize;
}
if (Reply.Timeout != 0) {
Instance->Timeout = Reply.Timeout;
}
}
} else {
Instance->Master = TRUE;
if (Reply.BlkSize != 0) {
Instance->BlkSize = Reply.BlkSize;
}
if (Reply.Timeout != 0) {
Instance->Timeout = Reply.Timeout;
}
}
//
// Send an ACK to (Expected - 1) which is 0 for unicast download,
// or tell the server we want to receive the Expected block.
//
return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));
}
/**
The packet process callback for MTFTP download.
@param UdpPacket The packet received
@param Points The local/remote access point of the packet
@param IoStatus The status of the receiving
@param Context Opaque parameter, which is the MTFTP session
@return None
**/
VOID
Mtftp4RrqInput (
IN NET_BUF *UdpPacket,
IN UDP_POINTS *Points,
IN EFI_STATUS IoStatus,
IN VOID *Context
)
{
MTFTP4_PROTOCOL *Instance;
EFI_MTFTP4_PACKET *Packet;
BOOLEAN Completed;
BOOLEAN Multicast;
EFI_STATUS Status;
UINT16 Opcode;
UINT32 Len;
Instance = (MTFTP4_PROTOCOL *) Context;
NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);
Status = EFI_SUCCESS;
Packet = NULL;
Completed = FALSE;
Multicast = FALSE;
if (EFI_ERROR (IoStatus)) {
Status = IoStatus;
goto ON_EXIT;
}
ASSERT (UdpPacket != NULL);
//
// Find the port this packet is from to restart receive correctly.
//
Multicast = (BOOLEAN) (Points->LocalAddr == Instance->McastIp);
if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {
goto ON_EXIT;
}
//
// Client send initial request to server's listening port. Server
// will select a UDP port to communicate with the client. The server
// is required to use the same port as RemotePort to multicast the
// data.
//
if (Points->RemotePort != Instance->ConnectedPort) {
if (Instance->ConnectedPort != 0) {
goto ON_EXIT;
} else {
Instance->ConnectedPort = Points->RemotePort;
}
}
//
// Copy the MTFTP packet to a continuous buffer if it isn't already so.
//
Len = UdpPacket->TotalSize;
if (UdpPacket->BlockOpNum > 1) {
Packet = NetAllocatePool (Len);
if (Packet == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT;
}
NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
} else {
Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
}
Opcode = NTOHS (Packet->OpCode);
//
// Call the user's CheckPacket if provided. Abort the transmission
// if CheckPacket returns an EFI_ERROR code.
//
if ((Instance->Token->CheckPacket != NULL) &&
((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {
Status = Instance->Token->CheckPacket (
&Instance->Mtftp4,
Instance->Token,
(UINT16) Len,
Packet
);
if (EFI_ERROR (Status)) {
//
// Send an error message to the server to inform it
//
if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
"User aborted the transfer"
);
}
Status = EFI_ABORTED;
goto ON_EXIT;
}
}
switch (Opcode) {
case EFI_MTFTP4_OPCODE_DATA:
if ((Len > (UINT32) (MTFTP4_DATA_HEAD_LEN + Instance->BlkSize)) ||
(Len < (UINT32) MTFTP4_DATA_HEAD_LEN)) {
goto ON_EXIT;
}
Status = Mtftp4RrqHandleData (Instance, Packet, Len, Multicast, &Completed);
break;
case EFI_MTFTP4_OPCODE_OACK:
if (Multicast || (Len <= MTFTP4_OPCODE_LEN)) {
goto ON_EXIT;
}
Status = Mtftp4RrqHandleOack (Instance, Packet, Len, Multicast, &Completed);
break;
case EFI_MTFTP4_OPCODE_ERROR:
Status = EFI_TFTP_ERROR;
break;
}
ON_EXIT:
//
// Free the resources, then if !EFI_ERROR (Status), restart the
// receive, otherwise end the session.
//
if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {
NetFreePool (Packet);
}
if (UdpPacket != NULL) {
NetbufFree (UdpPacket);
}
if (!EFI_ERROR (Status) && !Completed) {
if (Multicast) {
Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
} else {
Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
}
}
if (EFI_ERROR (Status) || Completed) {
Mtftp4CleanOperation (Instance, Status);
}
}

View File

@ -0,0 +1,591 @@
/** @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:
Mtftp4Support.c
Abstract:
Support routines for Mtftp
**/
#include "Mtftp4Impl.h"
/**
Allocate a MTFTP4 block range, then init it to the
range of [Start, End]
@param Start The start block number
@param End The last block number in the range
@return NULL if failed to allocate memory, otherwise the created block range.
**/
STATIC
MTFTP4_BLOCK_RANGE *
Mtftp4AllocateRange (
IN UINT16 Start,
IN UINT16 End
)
{
MTFTP4_BLOCK_RANGE *Range;
Range = NetAllocatePool (sizeof (MTFTP4_BLOCK_RANGE));
if (Range == NULL) {
return NULL;
}
NetListInit (&Range->Link);
Range->Start = Start;
Range->End = End;
return Range;
}
/**
Initialize the block range for either RRQ or WRQ. RRQ and WRQ have
different requirements for Start and End. For example, during start
up, WRQ initializes its whole valid block range to [0, 0xffff]. This
is bacause the server will send us a ACK0 to inform us to start the
upload. When the client received ACK0, it will remove 0 from the range,
get the next block number, which is 1, then upload the BLOCK1. For RRQ
without option negotiation, the server will directly send us the BLOCK1
in response to the client's RRQ. When received BLOCK1, the client will
remove it from the block range and send an ACK. It also works if there
is option negotiation.
@param Head The block range head to initialize
@param Start The Start block number.
@param End The last block number.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for initial block range
@retval EFI_SUCCESS The initial block range is created.
**/
EFI_STATUS
Mtftp4InitBlockRange (
IN NET_LIST_ENTRY *Head,
IN UINT16 Start,
IN UINT16 End
)
{
MTFTP4_BLOCK_RANGE *Range;
Range = Mtftp4AllocateRange (Start, End);
if (Range == NULL) {
return EFI_OUT_OF_RESOURCES;
}
NetListInsertTail (Head, &Range->Link);
return EFI_SUCCESS;
}
/**
Get the first valid block number on the range list.
@param Head The block range head
@return -1: if the block range is empty. Otherwise the first valid block number.
**/
INTN
Mtftp4GetNextBlockNum (
IN NET_LIST_ENTRY *Head
)
{
MTFTP4_BLOCK_RANGE *Range;
if (NetListIsEmpty (Head)) {
return -1;
}
Range = NET_LIST_HEAD (Head, MTFTP4_BLOCK_RANGE, Link);
return Range->Start;
}
/**
Set the last block number of the block range list. It will
remove all the blocks after the Last. MTFTP initialize the
block range to the maximum possible range, such as [0, 0xffff]
for WRQ. When it gets the last block number, it will call
this function to set the last block number.
@param Head The block range list
@param Last The last block number
@return None
**/
VOID
Mtftp4SetLastBlockNum (
IN NET_LIST_ENTRY *Head,
IN UINT16 Last
)
{
MTFTP4_BLOCK_RANGE *Range;
//
// Iterate from the tail to head to remove the block number
// after the last.
//
while (!NetListIsEmpty (Head)) {
Range = NET_LIST_TAIL (Head, MTFTP4_BLOCK_RANGE, Link);
if (Range->Start > Last) {
NetListRemoveEntry (&Range->Link);
NetFreePool (Range);
continue;
}
if (Range->End > Last) {
Range->End = Last;
}
return ;
}
}
/**
Remove the block number from the block range list.
@param Head The block range list to remove from
@param Num The block number to remove
@retval EFI_NOT_FOUND The block number isn't in the block range list
@retval EFI_SUCCESS The block number has been removed from the list
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource
**/
EFI_STATUS
Mtftp4RemoveBlockNum (
IN NET_LIST_ENTRY *Head,
IN UINT16 Num
)
{
MTFTP4_BLOCK_RANGE *Range;
MTFTP4_BLOCK_RANGE *NewRange;
NET_LIST_ENTRY *Entry;
NET_LIST_FOR_EACH (Entry, Head) {
//
// Each block represents a hole [Start, End] in the file,
// skip to the first range with End >= Num
//
Range = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);
if (Range->End < Num) {
continue;
}
//
// There are three different cases for Start
// 1. (Start > Num) && (End >= Num):
// because all the holes before this one has the condition of
// End < Num, so this block number has been removed.
//
// 2. (Start == Num) && (End >= Num):
// Need to increase the Start by one, and if End == Num, this
// hole has been removed completely, remove it.
//
// 3. (Start < Num) && (End >= Num):
// if End == Num, only need to decrease the End by one because
// we have (Start < Num) && (Num == End), so (Start <= End - 1).
// if (End > Num), the hold is splited into two holes, with
// [Start, Num - 1] and [Num + 1, End].
//
if (Range->Start > Num) {
return EFI_NOT_FOUND;
} else if (Range->Start == Num) {
Range->Start++;
if (Range->Start > Range->End) {
NetListRemoveEntry (&Range->Link);
NetFreePool (Range);
}
return EFI_SUCCESS;
} else {
if (Range->End == Num) {
Range->End--;
} else {
NewRange = Mtftp4AllocateRange (Num + 1, (UINT16) Range->End);
if (NewRange == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Range->End = Num - 1;
NetListInsertAfter (&Range->Link, &NewRange->Link);
}
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
Build then transmit the request packet for the MTFTP session.
@param Instance The Mtftp session
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the request
@retval EFI_SUCCESS The request is built and sent
@retval Others Failed to transmit the packet.
**/
EFI_STATUS
Mtftp4SendRequest (
IN MTFTP4_PROTOCOL *Instance
)
{
EFI_MTFTP4_PACKET *Packet;
EFI_MTFTP4_OPTION *Options;
EFI_MTFTP4_TOKEN *Token;
NET_BUF *Nbuf;
UINT8 *Mode;
UINT8 *Cur;
UINT32 Len;
UINTN Index;
Token = Instance->Token;
Options = Token->OptionList;
Mode = Instance->Token->ModeStr;
if (Mode == NULL) {
Mode = "octet";
}
//
// Compute the packet length
//
Len = (UINT32) (AsciiStrLen (Token->Filename) + AsciiStrLen (Mode) + 4);
for (Index = 0; Index < Token->OptionCount; Index++) {
Len += (UINT32) (AsciiStrLen (Options[Index].OptionStr) +
AsciiStrLen (Options[Index].ValueStr) + 2);
}
//
// Allocate a packet then copy the data over
//
if ((Nbuf = NetbufAlloc (Len)) == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Packet = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Nbuf, Len, FALSE);
Packet->OpCode = HTONS (Instance->Operation);
Cur = Packet->Rrq.Filename;
Cur = AsciiStrCpy (Cur, Token->Filename);
Cur = AsciiStrCpy (Cur, Mode);
for (Index = 0; Index < Token->OptionCount; ++Index) {
Cur = AsciiStrCpy (Cur, Options[Index].OptionStr);
Cur = AsciiStrCpy (Cur, Options[Index].ValueStr);
}
return Mtftp4SendPacket (Instance, Nbuf);
}
/**
Build then send an error message
@param Instance The MTFTP session
@param ErrInfo The error code and message
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the error packet
@retval EFI_SUCCESS The error packet is transmitted.
@retval Others Failed to transmit the packet.
**/
EFI_STATUS
Mtftp4SendError (
IN MTFTP4_PROTOCOL *Instance,
IN UINT16 ErrCode,
IN UINT8* ErrInfo
)
{
NET_BUF *Packet;
EFI_MTFTP4_PACKET *TftpError;
UINT32 Len;
Len = (UINT32) (AsciiStrLen (ErrInfo) + sizeof (EFI_MTFTP4_ERROR_HEADER));
Packet = NetbufAlloc (Len);
if (Packet == NULL) {
return EFI_OUT_OF_RESOURCES;
}
TftpError = (EFI_MTFTP4_PACKET *) NetbufAllocSpace (Packet, Len, FALSE);
TftpError->OpCode = HTONS (EFI_MTFTP4_OPCODE_ERROR);
TftpError->Error.ErrorCode = HTONS (ErrCode);
AsciiStrCpy (TftpError->Error.ErrorMessage, ErrInfo);
return Mtftp4SendPacket (Instance, Packet);
}
/**
The callback function called when the packet is transmitted.
It simply frees the packet.
@param Packet The transmitted (or failed to) packet
@param Points The local and remote UDP access point
@param IoStatus The result of the transmission
@param Context Opaque parameter to the callback
@return None
**/
STATIC
VOID
Mtftp4OnPacketSent (
NET_BUF *Packet,
UDP_POINTS *Points,
EFI_STATUS IoStatus,
VOID *Context
)
{
NetbufFree (Packet);
}
/**
Set the timeout for the instance. User a longer time for
passive instances.
@param Instance The Mtftp session to set time out
@return None
**/
VOID
Mtftp4SetTimeout (
IN MTFTP4_PROTOCOL *Instance
)
{
if (Instance->Master) {
Instance->PacketToLive = Instance->Timeout;
} else {
Instance->PacketToLive = Instance->Timeout * 2;
}
}
/**
Send the packet for the instance. It will first save a reference to
the packet for later retransmission. then determine the destination
port, listen port for requests, and connected port for others. At last,
send the packet out.
@param Instance The Mtftp instance
@param Packet The packet to send
@retval EFI_SUCCESS The packet is sent out
@retval Others Failed to transmit the packet.
**/
EFI_STATUS
Mtftp4SendPacket (
IN MTFTP4_PROTOCOL *Instance,
IN NET_BUF *Packet
)
{
UDP_POINTS UdpPoint;
EFI_STATUS Status;
UINT16 OpCode;
//
// Save the packet for retransmission
//
if (Instance->LastPacket != NULL) {
NetbufFree (Instance->LastPacket);
}
Instance->LastPacket = Packet;
Instance->CurRetry = 0;
Mtftp4SetTimeout (Instance);
UdpPoint.LocalAddr = 0;
UdpPoint.LocalPort = 0;
UdpPoint.RemoteAddr = Instance->ServerIp;
//
// Send the requests to the listening port, other packets
// to the connected port
//
OpCode = NTOHS (*((UINT16 *) NetbufGetByte (Packet, 0, NULL)));
if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||
(OpCode == EFI_MTFTP4_OPCODE_WRQ)) {
UdpPoint.RemotePort = Instance->ListeningPort;
} else {
UdpPoint.RemotePort = Instance->ConnectedPort;
}
NET_GET_REF (Packet);
Status = UdpIoSendDatagram (
Instance->UnicastPort,
Packet,
&UdpPoint,
Instance->Gateway,
Mtftp4OnPacketSent,
Instance
);
if (EFI_ERROR (Status)) {
NET_PUT_REF (Packet);
}
return Status;
}
/**
Retransmit the last packet for the instance
@param Instance The Mtftp instance
@retval EFI_SUCCESS The last packet is retransmitted.
@retval Others Failed to retransmit.
**/
EFI_STATUS
Mtftp4Retransmit (
IN MTFTP4_PROTOCOL *Instance
)
{
UDP_POINTS UdpPoint;
EFI_STATUS Status;
UINT16 OpCode;
ASSERT (Instance->LastPacket != NULL);
UdpPoint.LocalAddr = 0;
UdpPoint.LocalPort = 0;
UdpPoint.RemoteAddr = Instance->ServerIp;
//
// Set the requests to the listening port, other packets to the connected port
//
OpCode = NTOHS (*(UINT16 *) NetbufGetByte (Instance->LastPacket, 0, NULL));
if ((OpCode == EFI_MTFTP4_OPCODE_RRQ) || (OpCode == EFI_MTFTP4_OPCODE_DIR) ||
(OpCode == EFI_MTFTP4_OPCODE_WRQ)) {
UdpPoint.RemotePort = Instance->ListeningPort;
} else {
UdpPoint.RemotePort = Instance->ConnectedPort;
}
NET_GET_REF (Instance->LastPacket);
Status = UdpIoSendDatagram (
Instance->UnicastPort,
Instance->LastPacket,
&UdpPoint,
Instance->Gateway,
Mtftp4OnPacketSent,
Instance
);
if (EFI_ERROR (Status)) {
NET_PUT_REF (Instance->LastPacket);
}
return Status;
}
/**
The timer ticking function for the Mtftp service instance.
@param Event The ticking event
@param Context The Mtftp service instance
@return None
**/
VOID
EFIAPI
Mtftp4OnTimerTick (
IN EFI_EVENT Event,
IN VOID *Context
)
{
MTFTP4_SERVICE *MtftpSb;
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
MTFTP4_PROTOCOL *Instance;
EFI_MTFTP4_TOKEN *Token;
MtftpSb = (MTFTP4_SERVICE *) Context;
//
// Iterate through all the children of the Mtftp service instance. Time
// out the packet. If maximum retries reached, clean the session up.
//
NET_LIST_FOR_EACH_SAFE (Entry, Next, &MtftpSb->Children) {
Instance = NET_LIST_USER_STRUCT (Entry, MTFTP4_PROTOCOL, Link);
if ((Instance->PacketToLive == 0) || (--Instance->PacketToLive > 0)) {
continue;
}
//
// Call the user's time out handler
//
Token = Instance->Token;
if ((Token->TimeoutCallback != NULL) &&
EFI_ERROR (Token->TimeoutCallback (&Instance->Mtftp4, Token))) {
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
"User aborted the transfer in time out"
);
Mtftp4CleanOperation (Instance, EFI_ABORTED);
continue;
}
//
// Retransmit the packet if haven't reach the maxmium retry count,
// otherwise exit the transfer.
//
if (++Instance->CurRetry < Instance->MaxRetry) {
Mtftp4Retransmit (Instance);
Mtftp4SetTimeout (Instance);
} else {
Mtftp4CleanOperation (Instance, EFI_TIMEOUT);
continue;
}
}
}

View File

@ -0,0 +1,96 @@
/** @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

View File

@ -0,0 +1,522 @@
/** @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:
Mtftp4Wrq.c
Abstract:
Routines to process Wrq (upload)
**/
#include "Mtftp4Impl.h"
VOID
Mtftp4WrqInput (
IN NET_BUF *UdpPacket,
IN UDP_POINTS *Points,
IN EFI_STATUS IoStatus,
IN VOID *Context
);
/**
Start the MTFTP session for pload. It will first init some states,
then send the WRQ request packet, and start receiving the packet.
@param Instance The MTFTP session
@param Operation Redundant parameter, which is always
EFI_MTFTP4_OPCODE_WRQ here.
@retval EFI_SUCCESS The upload process has been started.
@retval Others Failed to start the upload.
**/
EFI_STATUS
Mtftp4WrqStart (
IN MTFTP4_PROTOCOL *Instance,
IN UINT16 Operation
)
{
EFI_STATUS Status;
//
// The valid block number range are [0, 0xffff]. For example:
// the client sends an WRQ request to the server, the server
// ACK with an ACK0 to let client start transfer the first
// packet.
//
Status = Mtftp4InitBlockRange (&Instance->Blocks, 0, 0xffff);
if (EFI_ERROR (Status)) {
return Status;
}
Status = Mtftp4SendRequest (Instance);
if (EFI_ERROR (Status)) {
return Status;
}
return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);
}
/**
Build then send a MTFTP data packet for the MTFTP upload session.
@param Instance The MTFTP upload session
@param BlockNum The block number to send
@retval EFI_OUT_OF_RESOURCES Failed to build the packet
@retval EFI_ABORTED The consumer of this child directs to abort the
transmission by return an error through
PacketNeeded
@retval EFI_SUCCESS The data is sent.
**/
EFI_STATUS
Mtftp4WrqSendBlock (
IN MTFTP4_PROTOCOL *Instance,
IN UINT16 BlockNum
)
{
EFI_MTFTP4_PACKET *Packet;
EFI_MTFTP4_TOKEN *Token;
NET_BUF *UdpPacket;
EFI_STATUS Status;
UINT16 DataLen;
UINT8 *DataBuf;
UINT64 Start;
//
// Allocate a buffer to hold the user data
//
UdpPacket = NetbufAlloc (Instance->BlkSize + MTFTP4_DATA_HEAD_LEN);
if (UdpPacket == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Packet = (EFI_MTFTP4_PACKET *)NetbufAllocSpace (UdpPacket, MTFTP4_DATA_HEAD_LEN, FALSE);
Packet->Data.OpCode = HTONS (EFI_MTFTP4_OPCODE_DATA);
Packet->Data.Block = HTONS (BlockNum);
//
// Read the block from either the buffer or PacketNeeded callback
//
Token = Instance->Token;
DataLen = Instance->BlkSize;
if (Token->Buffer != NULL) {
Start = MultU64x32 (BlockNum - 1, Instance->BlkSize);
if (Token->BufferSize < Start + Instance->BlkSize) {
DataLen = (UINT16) (Token->BufferSize - Start);
Instance->LastBlock = BlockNum;
Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);
}
if (DataLen > 0) {
NetbufAllocSpace (UdpPacket, DataLen, FALSE);
NetCopyMem (Packet->Data.Data, (UINT8 *) Token->Buffer + Start, DataLen);
}
} else {
//
// Get data from PacketNeeded
//
DataBuf = NULL;
Status = Token->PacketNeeded (&Instance->Mtftp4, Token, &DataLen, &DataBuf);
if (EFI_ERROR (Status) || (DataLen > Instance->BlkSize)) {
if (DataBuf != NULL) {
gBS->FreePool (DataBuf);
}
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
"User aborted the transfer"
);
return EFI_ABORTED;
}
if (DataLen < Instance->BlkSize) {
Instance->LastBlock = BlockNum;
Mtftp4SetLastBlockNum (&Instance->Blocks, BlockNum);
}
if (DataLen > 0) {
NetbufAllocSpace (UdpPacket, DataLen, FALSE);
NetCopyMem (Packet->Data.Data, DataBuf, DataLen);
gBS->FreePool (DataBuf);
}
}
return Mtftp4SendPacket (Instance, UdpPacket);
}
/**
Function to handle received ACK packet. If the ACK number matches the
expected block number, and there are more data pending, send the next
block. Otherwise tell the caller that we are done.
@param Instance The MTFTP upload session
@param Packet The MTFTP packet received
@param Len The packet length
@param Completed Return whether the upload has finished.
@retval EFI_SUCCESS The ACK is successfully processed.
@retval EFI_TFTP_ERROR The block number loops back.
@retval Others Failed to transmit the next data packet.
**/
EFI_STATUS
Mtftp4WrqHandleAck (
IN MTFTP4_PROTOCOL *Instance,
IN EFI_MTFTP4_PACKET *Packet,
IN UINT32 Len,
OUT BOOLEAN *Completed
)
{
UINT16 AckNum;
INTN Expected;
*Completed = FALSE;
AckNum = NTOHS (Packet->Ack.Block[0]);
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
ASSERT (Expected >= 0);
//
// Get an unwanted ACK, return EFI_SUCCESS to let Mtftp4WrqInput
// restart receive.
//
if (Expected != AckNum) {
return EFI_SUCCESS;
}
//
// Remove the acked block number, if this is the last block number,
// tell the Mtftp4WrqInput to finish the transfer. This is the last
// block number if the block range are empty..
//
Mtftp4RemoveBlockNum (&Instance->Blocks, AckNum);
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
if (Expected < 0) {
//
// The block range is empty. It may either because the the last
// block has been ACKed, or the sequence number just looped back,
// that is, there is more than 0xffff blocks.
//
if (Instance->LastBlock == AckNum) {
ASSERT (Instance->LastBlock >= 1);
*Completed = TRUE;
return EFI_SUCCESS;
} else {
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
"Block number rolls back, not supported, try blksize option"
);
return EFI_TFTP_ERROR;
}
}
return Mtftp4WrqSendBlock (Instance, (UINT16) Expected);
}
/**
Check whether the received OACK is valid. The OACK is valid
only if:
1. It only include options requested by us
2. It can only include a smaller block size
3. It can't change the proposed time out value.
4. Other requirements of the individal MTFTP options as required.s
@param Reply The options included in the OACK
@param Request The options we requested
@return TRUE if the options included in OACK is valid, otherwise FALSE.
**/
BOOLEAN
Mtftp4WrqOackValid (
IN MTFTP4_OPTION *Reply,
IN MTFTP4_OPTION *Request
)
{
//
// It is invalid for server to return options we don't request
//
if ((Reply->Exist &~Request->Exist) != 0) {
return FALSE;
}
//
// Server can only specify a smaller block size to be used and
// return the timeout matches that requested.
//
if (((Reply->Exist & MTFTP4_BLKSIZE_EXIST) && (Reply->BlkSize > Request->BlkSize)) ||
((Reply->Exist & MTFTP4_TIMEOUT_EXIST) && (Reply->Timeout != Request->Timeout))) {
return FALSE;
}
return TRUE;
}
/**
Function to handle the MTFTP OACK packet. It parses the packet's
options, and update the internal states of the session
@param Instance The MTFTP session
@param Packet The received OACK packet
@param Len The length of the packet
@param Completed Whether the transmisson has completed. NOT used by
this function.
@retval EFI_SUCCESS The OACK process is OK
@retval EFI_TFTP_ERROR Some error occured, and the session reset.
**/
EFI_STATUS
Mtftp4WrqHandleOack (
IN MTFTP4_PROTOCOL *Instance,
IN EFI_MTFTP4_PACKET *Packet,
IN UINT32 Len,
OUT BOOLEAN *Completed
)
{
MTFTP4_OPTION Reply;
EFI_MTFTP4_PACKET Bogus;
EFI_STATUS Status;
INTN Expected;
*Completed = FALSE;
//
// Ignore the OACK if already started the upload
//
Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
if (Expected != 0) {
return EFI_SUCCESS;
}
//
// Parse and validate the options from server
//
NetZeroMem (&Reply, sizeof (MTFTP4_OPTION));
Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);
if (EFI_ERROR (Status) || !Mtftp4WrqOackValid (&Reply, &Instance->RequestOption)) {
//
// Don't send a MTFTP error packet when out of resource, it can
// only make it worse.
//
if (Status != EFI_OUT_OF_RESOURCES) {
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
"Mal-formated OACK packet"
);
}
return EFI_TFTP_ERROR;
}
if (Reply.BlkSize != 0) {
Instance->BlkSize = Reply.BlkSize;
}
if (Reply.Timeout != 0) {
Instance->Timeout = Reply.Timeout;
}
//
// Build a bogus ACK0 packet then pass it to the Mtftp4WrqHandleAck,
// which will start the transmission of the first data block.
//
Bogus.Ack.OpCode = HTONS (EFI_MTFTP4_OPCODE_ACK);
Bogus.Ack.Block[0] = 0;
return Mtftp4WrqHandleAck (Instance, &Bogus, sizeof (EFI_MTFTP4_ACK_HEADER), Completed);
}
/**
The input process routine for MTFTP upload.
@param UdpPacket The received MTFTP packet.
@param Points The local/remote access point
@param IoStatus The result of the packet receiving
@param Context Opaque parameter for the callback, which is the
MTFTP session.
@return None
**/
VOID
Mtftp4WrqInput (
IN NET_BUF *UdpPacket,
IN UDP_POINTS *Points,
IN EFI_STATUS IoStatus,
IN VOID *Context
)
{
MTFTP4_PROTOCOL *Instance;
EFI_MTFTP4_PACKET *Packet;
BOOLEAN Completed;
EFI_STATUS Status;
UINT32 Len;
UINT16 Opcode;
Instance = (MTFTP4_PROTOCOL *) Context;
NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);
Completed = FALSE;
Packet = NULL;
Status = EFI_SUCCESS;
if (EFI_ERROR (IoStatus)) {
Status = IoStatus;
goto ON_EXIT;
}
ASSERT (UdpPacket != NULL);
if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {
goto ON_EXIT;
}
//
// Client send initial request to server's listening port. Server
// will select a UDP port to communicate with the client.
//
if (Points->RemotePort != Instance->ConnectedPort) {
if (Instance->ConnectedPort != 0) {
goto ON_EXIT;
} else {
Instance->ConnectedPort = Points->RemotePort;
}
}
//
// Copy the MTFTP packet to a continuous buffer if it isn't already so.
//
Len = UdpPacket->TotalSize;
if (UdpPacket->BlockOpNum > 1) {
Packet = NetAllocatePool (Len);
if (Packet == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT;
}
NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);
} else {
Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
}
Opcode = NTOHS (Packet->OpCode);
//
// Call the user's CheckPacket if provided. Abort the transmission
// if CheckPacket returns an EFI_ERROR code.
//
if ((Instance->Token->CheckPacket != NULL) &&
((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {
Status = Instance->Token->CheckPacket (
&Instance->Mtftp4,
Instance->Token,
(UINT16) Len,
Packet
);
if (EFI_ERROR (Status)) {
//
// Send an error message to the server to inform it
//
if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {
Mtftp4SendError (
Instance,
EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
"User aborted the transfer"
);
}
Status = EFI_ABORTED;
goto ON_EXIT;
}
}
switch (Opcode) {
case EFI_MTFTP4_OPCODE_ACK:
if (Len != MTFTP4_OPCODE_LEN + MTFTP4_BLKNO_LEN) {
goto ON_EXIT;
}
Status = Mtftp4WrqHandleAck (Instance, Packet, Len, &Completed);
break;
case EFI_MTFTP4_OPCODE_OACK:
if (Len <= MTFTP4_OPCODE_LEN) {
goto ON_EXIT;
}
Status = Mtftp4WrqHandleOack (Instance, Packet, Len, &Completed);
break;
case EFI_MTFTP4_OPCODE_ERROR:
Status = EFI_TFTP_ERROR;
break;
}
ON_EXIT:
//
// Free the resources, then if !EFI_ERROR (Status) and not completed,
// restart the receive, otherwise end the session.
//
if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {
NetFreePool (Packet);
}
if (UdpPacket != NULL) {
NetbufFree (UdpPacket);
}
if (!EFI_ERROR (Status) && !Completed) {
Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);
}
//
// Status may have been updated by UdpIoRecvDatagram
//
if (EFI_ERROR (Status) || Completed) {
Mtftp4CleanOperation (Instance, Status);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,564 @@
/** @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>
#include <Guid/SmBios.h>
#include <Protocol/Bis.h>
#include <Protocol/PxeBaseCode.h>
#include <Protocol/PxeBaseCodeCallBack.h>
#include <Protocol/NetworkInterfaceIdentifier.h>
#include <Protocol/SimpleNetwork.h>
#include <Protocol/LoadFile.h>
#include <Protocol/DevicePath.h>
#include <Protocol/Tcp.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseLib.h>
#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 */

View File

@ -0,0 +1,160 @@
/** @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:
ComponentName.c
Abstract:
**/
#include "Bc.h"
//
// EFI Component Name Functions
//
EFI_STATUS
EFIAPI
PxeBcComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
EFI_STATUS
EFIAPI
PxeBcComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
//
// EFI Component Name Protocol
//
EFI_COMPONENT_NAME_PROTOCOL gPxeBcComponentName = {
PxeBcComponentNameGetDriverName,
PxeBcComponentNameGetControllerName,
"eng"
};
static EFI_UNICODE_STRING_TABLE mPxeBcDriverNameTable[] = {
{
"eng",
L"PXE Base Code Driver"
},
{
NULL,
NULL
}
};
EFI_STATUS
EFIAPI
PxeBcComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
Language - A pointer to a three character ISO 639-2 language identifier.
This is the language of the driver name that that the caller
is requesting, and it must match one of the languages specified
in SupportedLanguages. The number of languages supported by a
driver is up to the driver writer.
DriverName - A pointer to the Unicode string to return. This Unicode string
is the name of the driver specified by This in the language
specified by Language.
Returns:
EFI_SUCCESS - The Unicode string for the Driver specified by This
and the language specified by Language was returned
in DriverName.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - DriverName is NULL.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return LookupUnicodeString (
Language,
gPxeBcComponentName.SupportedLanguages,
mPxeBcDriverNameTable,
DriverName
);
}
EFI_STATUS
EFIAPI
PxeBcComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by an EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
ControllerHandle - The handle of a controller that the driver specified by
This is managing. This handle specifies the controller
whose name is to be returned.
ChildHandle - The handle of the child controller to retrieve the name
of. This is an optional parameter that may be NULL. It
will be NULL for device drivers. It will also be NULL
for a bus drivers that wish to retrieve the name of the
bus controller. It will not be NULL for a bus driver
that wishes to retrieve the name of a child controller.
Language - A pointer to a three character ISO 639-2 language
identifier. This is the language of the controller name
that that the caller is requesting, and it must match one
of the languages specified in SupportedLanguages. The
number of languages supported by a driver is up to the
driver writer.
ControllerName - A pointer to the Unicode string to return. This Unicode
string is the name of the controller specified by
ControllerHandle and ChildHandle in the language specified
by Language from the point of view of the driver specified
by This.
Returns:
EFI_SUCCESS - The Unicode string for the user readable name in the
language specified by Language for the driver
specified by This was returned in DriverName.
EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - ControllerName is NULL.
EFI_UNSUPPORTED - The driver specified by This is not currently managing
the controller specified by ControllerHandle and
ChildHandle.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return EFI_UNSUPPORTED;
}

View File

@ -0,0 +1,632 @@
/** @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 */

View File

@ -0,0 +1,46 @@
/** @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.c
Abstract:
Defines PXE Arch type
**/
#include "PxeArch.h"
UINT16 mSysArch = 0;
UINT16
GetSysArch (
VOID
)
{
if (mSysArch == 0) {
//
// This is first call
// Assign to invalid value
//
mSysArch = 0xFFFF;
//
// We do not know what is EBC architecture.
// Maybe we can try to locate DebugSupport protocol to get ISA.
// TBD now.
//
}
return mSysArch;
}

View File

@ -0,0 +1,36 @@
/** @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

View File

@ -0,0 +1,43 @@
/** @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 */

View File

@ -0,0 +1,26 @@
/** @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

View File

@ -0,0 +1,736 @@
/** @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 */

View File

@ -0,0 +1,26 @@
/** @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

View File

@ -0,0 +1,92 @@
#/** @file
# Component name for module BC
#
# 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.
#
#
#**/
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = PxeBcDxe
FILE_GUID = A3f436EA-A127-4EF8-957C-8048606FF670
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = InitializeBCDriver
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources.common]
Pxe_bc_mtftp.c
Bc.c
Dhcp.h
Ip.h
Pxe_bc_ip.c
Pxe_bc_dhcp.c
Pxe_bc_arp.c
Hton.h
ComponentName.c
Bc.h
Pxe_loadfile.c
Tftp.h
Pxe_bc_igmp.c
Pxe_bc_udp.c
[Sources.IA32]
Ia32\PxeArch.h
[Sources.X64]
X64\PxeArch.h
[Sources.IPF]
Ipf\PxeArch.h
[Sources.EBC]
Ebc\PxeArch.h
Ebc\PxeArch.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiLib
BaseLib
UefiBootServicesTableLib
UefiDriverEntryPoint
BaseMemoryLib
DebugLib
[Guids]
gEfiSmbiosTableGuid # ALWAYS_CONSUMED
[Protocols]
gEfiBisProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiPxeBaseCodeCallbackProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiPxeBaseCodeProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiLoadFileProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiNetworkInterfaceIdentifierProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiTcpProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiNetworkInterfaceIdentifierProtocolGuid_31 # PROTOCOL ALWAYS_CONSUMED

View File

@ -0,0 +1,106 @@
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>BC</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>A3f436EA-A127-4EF8-957C-8048606FF670</GuidValue>
<Version>1.0</Version>
<Abstract>Component name for module BC</Abstract>
<Description>FIX ME!</Description>
<Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
<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>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>BC</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseMemoryLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>pxe_bc_udp.c</Filename>
<Filename>pxe_bc_igmp.c</Filename>
<Filename>tftp.h</Filename>
<Filename>pxe_loadfile.c</Filename>
<Filename>bc.h</Filename>
<Filename>ComponentName.c</Filename>
<Filename>BcEntry.c</Filename>
<Filename>ipf\PxeArch.h</Filename>
<Filename>ebc\PxeArch.h</Filename>
<Filename SupArchList="X64">x64\PxeArch.h</Filename>
<Filename>pxe_bc_tcp.c</Filename>
<Filename>hton.h</Filename>
<Filename>pxe_bc_arp.c</Filename>
<Filename>pxe_bc_dhcp.c</Filename>
<Filename>pxe_bc_ip.c</Filename>
<Filename>ip.h</Filename>
<Filename>dhcp.h</Filename>
<Filename>bc.c</Filename>
<Filename>pxe_bc_mtftp.c</Filename>
<Filename>ia32\PxeArch.h</Filename>
<Filename>ebc\PxeArch.c</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiNetworkInterfaceIdentifierProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiLoadFileProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiPxeBaseCodeProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiPxeBaseCodeCallbackProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiBisProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Guids>
<GuidCNames Usage="ALWAYS_CONSUMED">
<GuidCName>gEfiSmbiosTableGuid</GuidCName>
</GuidCNames>
</Guids>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>InitializeBCDriver</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

View File

@ -0,0 +1,583 @@
/** @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:
pxe_bc_arp.c
Abstract:
**/
#include "Bc.h"
//
// Definitions for ARP
// Per RFC 826
//
STATIC ARP_HEADER ArpHeader;
#pragma pack(1)
STATIC struct {
UINT8 MediaHeader[14];
ARP_HEADER ArpHeader;
UINT8 ArpData[64];
} ArpReplyPacket;
#pragma pack()
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
@return none
**/
VOID
InitArpHeader (
VOID
)
{
ArpHeader.HwType = HTONS (ETHERNET_ADD_SPC);
ArpHeader.ProtType = HTONS (ETHER_TYPE_IP);
ArpHeader.HwAddLen = ENET_HWADDLEN;
ArpHeader.ProtAddLen = IPV4_PROTADDLEN;
ArpHeader.OpCode = HTONS (ARP_REQUEST);
CopyMem (&ArpReplyPacket.ArpHeader, &ArpHeader, sizeof (ARP_HEADER));
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
**/
VOID
HandleArpReceive (
IN PXE_BASECODE_DEVICE *Private,
IN ARP_PACKET *ArpPacketPtr,
IN VOID *MediaHeader
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
EFI_SIMPLE_NETWORK_MODE *SnpMode;
EFI_MAC_ADDRESS TmpMacAddr;
UINTN Index;
UINT8 *SrcHwAddr;
UINT8 *SrcPrAddr;
UINT8 *DstHwAddr;
UINT8 *DstPrAddr;
UINT8 *TmpPtr;
//
//
//
PxeBcMode = Private->EfiBc.Mode;
SnpMode = Private->SimpleNetwork->Mode;
//
// For now only ethernet addresses are supported.
// This will need to be updated when other media
// layers are supported by PxeBc, Snp and UNDI.
//
if (ArpPacketPtr->ArpHeader.HwType != HTONS (ETHERNET_ADD_SPC)) {
return ;
}
//
// For now only IP protocol addresses are supported.
// This will need to be updated when other protocol
// types are supported by PxeBc, Snp and UNDI.
//
if (ArpPacketPtr->ArpHeader.ProtType != HTONS (ETHER_TYPE_IP)) {
return ;
}
//
// For now only SNP hardware address sizes are supported.
//
if (ArpPacketPtr->ArpHeader.HwAddLen != SnpMode->HwAddressSize) {
return ;
}
//
// For now only PxeBc protocol address sizes are supported.
//
if (ArpPacketPtr->ArpHeader.ProtAddLen != Private->IpLength) {
return ;
}
//
// Ignore out of range opcodes
//
switch (ArpPacketPtr->ArpHeader.OpCode) {
case HTONS (ARP_REPLY):
case HTONS (ARP_REQUEST):
break;
default:
return ;
}
//
// update entry in our ARP cache if we have it
//
SrcHwAddr = (UINT8 *) &ArpPacketPtr->SrcHardwareAddr;
SrcPrAddr = SrcHwAddr + SnpMode->HwAddressSize;
for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) {
if (CompareMem (
&PxeBcMode->ArpCache[Index].IpAddr,
SrcPrAddr,
Private->IpLength
)) {
continue;
}
CopyMem (
&PxeBcMode->ArpCache[Index].MacAddr,
SrcHwAddr,
SnpMode->HwAddressSize
);
break;
}
//
// Done if ARP packet was not for us.
//
DstHwAddr = SrcPrAddr + Private->IpLength;
DstPrAddr = DstHwAddr + SnpMode->HwAddressSize;
if (CompareMem (DstPrAddr, &PxeBcMode->StationIp, Private->IpLength)) {
return ;
//
// not for us
//
}
//
// for us - if we did not update entry, add it
//
if (Index == PxeBcMode->ArpCacheEntries) {
//
// if we have a full table, get rid of oldest
//
if (Index == PXE_ARP_CACHE_SIZE) {
Index = Private->OldestArpEntry;
if (++Private->OldestArpEntry == PXE_ARP_CACHE_SIZE) {
Private->OldestArpEntry = 0;
}
} else {
++PxeBcMode->ArpCacheEntries;
}
CopyMem (
&PxeBcMode->ArpCache[Index].MacAddr,
SrcHwAddr,
SnpMode->HwAddressSize
);
CopyMem (
&PxeBcMode->ArpCache[Index].IpAddr,
SrcPrAddr,
Private->IpLength
);
}
//
// if this is not a request or we don't yet have an IP, finished
//
if (ArpPacketPtr->ArpHeader.OpCode != HTONS (ARP_REQUEST) || !Private->GoodStationIp) {
return ;
}
//
// Assemble ARP reply.
//
//
// Create media header. [ dest mac | src mac | prot ]
//
CopyMem (
&ArpReplyPacket.MediaHeader[0],
SrcHwAddr,
SnpMode->HwAddressSize
);
CopyMem (
&ArpReplyPacket.MediaHeader[SnpMode->HwAddressSize],
&SnpMode->CurrentAddress,
SnpMode->HwAddressSize
);
CopyMem (
&ArpReplyPacket.MediaHeader[2 * SnpMode->HwAddressSize],
&((UINT8 *) MediaHeader)[2 * SnpMode->HwAddressSize],
sizeof (UINT16)
);
//
// ARP reply header is almost filled in,
// just insert the correct opcode.
//
ArpReplyPacket.ArpHeader.OpCode = HTONS (ARP_REPLY);
//
// Now fill in ARP data. [ src mac | src prot | dest mac | dest prot ]
//
TmpPtr = ArpReplyPacket.ArpData;
CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
TmpPtr += SnpMode->HwAddressSize;
CopyMem (TmpPtr, &PxeBcMode->StationIp, Private->IpLength);
TmpPtr += Private->IpLength;
CopyMem (TmpPtr, SrcHwAddr, SnpMode->HwAddressSize);
TmpPtr += SnpMode->HwAddressSize;
CopyMem (TmpPtr, SrcPrAddr, Private->IpLength);
//
// Now send out the ARP reply.
//
CopyMem (&TmpMacAddr, SrcHwAddr, sizeof (EFI_MAC_ADDRESS));
SendPacket (
Private,
&ArpReplyPacket.MediaHeader,
&ArpReplyPacket.ArpHeader,
sizeof (ARP_HEADER) + 2 * (Private->IpLength + SnpMode->HwAddressSize),
&TmpMacAddr,
PXE_PROTOCOL_ETHERNET_ARP,
EFI_PXE_BASE_CODE_FUNCTION_ARP
);
//
// Give time (100 microseconds) for ARP reply to get onto wire.
//
gBS->Stall (1000);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
@return TRUE := If IP address was found and MAC address was stored
@return FALSE := If IP address was not found
**/
BOOLEAN
GetHwAddr (
IN PXE_BASECODE_DEVICE *Private,
IN EFI_IP_ADDRESS *ProtocolAddrPtr,
OUT EFI_MAC_ADDRESS *HardwareAddrPtr
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
UINTN HardwareAddrLength;
UINTN Index;
PxeBcMode = Private->EfiBc.Mode;
HardwareAddrLength = Private->SimpleNetwork->Mode->HwAddressSize;
for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) {
if (!CompareMem (
ProtocolAddrPtr,
&PxeBcMode->ArpCache[Index].IpAddr,
Private->IpLength
)) {
CopyMem (
HardwareAddrPtr,
&PxeBcMode->ArpCache[Index].MacAddr,
HardwareAddrLength
);
return TRUE;
}
}
return FALSE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
@return EFI_SUCCESS := ARP request sent
@return other := ARP request could not be sent
**/
STATIC
EFI_STATUS
SendRequest (
IN PXE_BASECODE_DEVICE *Private,
IN EFI_IP_ADDRESS *ProtocolAddrPtr,
IN EFI_MAC_ADDRESS *HardwareAddrPtr
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
EFI_SIMPLE_NETWORK_MODE *SnpMode;
ARP_PACKET *ArpPacket;
EFI_STATUS Status;
UINTN HardwareAddrLength;
UINT8 *SrcProtocolAddrPtr;
UINT8 *DestHardwareAddrptr;
UINT8 *DestProtocolAddrPtr;
//
//
//
PxeBcMode = Private->EfiBc.Mode;
SnpMode = Private->SimpleNetwork->Mode;
HardwareAddrLength = SnpMode->HwAddressSize;
//
// Allocate ARP buffer
//
if (Private->ArpBuffer == NULL) {
Status = gBS->AllocatePool (
EfiBootServicesData,
SnpMode->MediaHeaderSize + sizeof (ARP_PACKET),
&Private->ArpBuffer
);
if (EFI_ERROR (Status)) {
return Status;
}
}
ArpPacket = (VOID *) (Private->ArpBuffer + SnpMode->MediaHeaderSize);
//
// for now, only handle one kind of hw and pr address
//
ArpPacket->ArpHeader = ArpHeader;
ArpPacket->ArpHeader.HwAddLen = (UINT8) HardwareAddrLength;
ArpPacket->ArpHeader.ProtAddLen = (UINT8) Private->IpLength;
//
// rest more generic
//
SrcProtocolAddrPtr = (UINT8 *) (&ArpPacket->SrcHardwareAddr) + HardwareAddrLength;
DestHardwareAddrptr = SrcProtocolAddrPtr + Private->IpLength;
DestProtocolAddrPtr = DestHardwareAddrptr + HardwareAddrLength;
CopyMem (DestProtocolAddrPtr, ProtocolAddrPtr, Private->IpLength);
CopyMem (DestHardwareAddrptr, HardwareAddrPtr, HardwareAddrLength);
CopyMem (SrcProtocolAddrPtr, &PxeBcMode->StationIp, Private->IpLength);
CopyMem (
&ArpPacket->SrcHardwareAddr,
&SnpMode->CurrentAddress,
HardwareAddrLength
);
return SendPacket (
Private,
Private->ArpBuffer,
ArpPacket,
sizeof (ARP_HEADER) + ((Private->IpLength + HardwareAddrLength) << 1),
&SnpMode->BroadcastAddress,
PXE_PROTOCOL_ETHERNET_ARP,
EFI_PXE_BASE_CODE_FUNCTION_ARP
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// check for address - if not there, send ARP request, wait and check again
// not how it would be done in a full system
//
#define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second
////////////////////////////////////////////////////////////
//
// BC Arp Routine
//
/**
**/
EFI_STATUS
EFIAPI
BcArp (
IN EFI_PXE_BASE_CODE_PROTOCOL * This,
IN EFI_IP_ADDRESS * ProtocolAddrPtr,
OUT EFI_MAC_ADDRESS * HardwareAddrPtr OPTIONAL
)
{
EFI_MAC_ADDRESS Mac;
EFI_STATUS StatCode;
PXE_BASECODE_DEVICE *Private;
//
// Lock the instance data and make sure started
//
StatCode = EFI_SUCCESS;
if (This == NULL) {
DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
return EFI_INVALID_PARAMETER;
}
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
if (Private == NULL) {
DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
return EFI_INVALID_PARAMETER;
}
EfiAcquireLock (&Private->Lock);
if (This->Mode == NULL || !This->Mode->Started) {
DEBUG ((DEBUG_ERROR, "BC was not started."));
EfiReleaseLock (&Private->Lock);
return EFI_NOT_STARTED;
}
DEBUG ((DEBUG_INFO, "\nBcArp()"));
//
// Issue BC command
//
if (ProtocolAddrPtr == NULL) {
DEBUG (
(DEBUG_INFO,
"\nBcArp() Exit #1 %Xh (%r)",
EFI_INVALID_PARAMETER,
EFI_INVALID_PARAMETER)
);
EfiReleaseLock (&Private->Lock);
return EFI_INVALID_PARAMETER;
}
if (HardwareAddrPtr == NULL) {
HardwareAddrPtr = &Mac;
}
ZeroMem (HardwareAddrPtr, Private->SimpleNetwork->Mode->HwAddressSize);
if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {
DEBUG (
(DEBUG_INFO,
"\nBcArp() Exit #2 %Xh (%r)",
EFI_SUCCESS,
EFI_SUCCESS)
);
EfiReleaseLock (&Private->Lock);
return EFI_SUCCESS;
}
StatCode = DoArp (Private, ProtocolAddrPtr, HardwareAddrPtr);
DEBUG ((DEBUG_INFO, "\nBcArp() Exit #3 %Xh (%r)", StatCode, StatCode));
EfiReleaseLock (&Private->Lock);
return StatCode;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
@return EFI_SUCCESS := MAC address found
@return other := MAC address could not be found
**/
EFI_STATUS
DoArp (
IN PXE_BASECODE_DEVICE *Private,
IN EFI_IP_ADDRESS *ProtocolAddrPtr,
OUT EFI_MAC_ADDRESS *HardwareAddrPtr
)
{
EFI_STATUS StatCode;
EFI_EVENT TimeoutEvent;
UINTN HeaderSize;
UINTN BufferSize;
UINT16 Protocol;
DEBUG ((DEBUG_INFO, "\nDoArp()"));
//
//
//
StatCode = SendRequest (Private, ProtocolAddrPtr, HardwareAddrPtr);
if (EFI_ERROR (StatCode)) {
DEBUG ((DEBUG_INFO, "\nDoArp() Exit #1 %Xh (%r)", StatCode, StatCode));
return StatCode;
}
//
//
//
StatCode = gBS->CreateEvent (
EVT_TIMER,
TPL_CALLBACK,
NULL,
NULL,
&TimeoutEvent
);
if (EFI_ERROR (StatCode)) {
return StatCode;
}
StatCode = gBS->SetTimer (
TimeoutEvent,
TimerRelative,
ARP_REQUEST_TIMEOUT_MS * 10000
);
if (EFI_ERROR (StatCode)) {
gBS->CloseEvent (TimeoutEvent);
return StatCode;
}
//
//
//
for (;;) {
StatCode = WaitForReceive (
Private,
EFI_PXE_BASE_CODE_FUNCTION_ARP,
TimeoutEvent,
&HeaderSize,
&BufferSize,
&Protocol
);
if (EFI_ERROR (StatCode)) {
break;
}
if (Protocol != PXE_PROTOCOL_ETHERNET_ARP) {
continue;
}
HandleArpReceive (
Private,
(ARP_PACKET *) (Private->ReceiveBufferPtr + HeaderSize),
Private->ReceiveBufferPtr
);
if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {
break;
}
}
DEBUG (
(DEBUG_INFO,
"\nDoArp() Exit #2 %Xh, (%r)",
StatCode,
StatCode)
);
gBS->CloseEvent (TimeoutEvent);
return StatCode;
}
/* eof - pxe_bc_arp.c */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,421 @@
/** @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.
**/
#define RAND_MAX 0x10000
#include "Bc.h"
//
// Definitions for internet group management protocol version 2 message
// structure Per RFC 2236, November 1997
//
STATIC UINT8 RouterAlertOption[4] = { 0x80 | 20, 4, 0, 0 };
STATIC IPV4_ADDR AllRoutersGroup = { { 224, 0, 0, 2 } };
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
STATIC
VOID
ClearGroupTimer (
PXE_BASECODE_DEVICE *Private,
UINTN TimerId
)
{
if (Private == NULL) {
return ;
}
if (TimerId >= Private->MCastGroupCount) {
return ;
}
if (Private->IgmpGroupEvent[TimerId] == NULL) {
return ;
}
gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
Private->IgmpGroupEvent[TimerId] = NULL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
**/
STATIC
VOID
SetGroupTimer (
PXE_BASECODE_DEVICE *Private,
UINTN TimerId,
UINTN MaxRespTime
)
{
EFI_STATUS EfiStatus;
if (Private == NULL) {
return ;
}
if (TimerId >= Private->MCastGroupCount) {
return ;
}
if (Private->IgmpGroupEvent[TimerId] != NULL) {
gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
}
EfiStatus = gBS->CreateEvent (
EVT_TIMER,
TPL_CALLBACK,
NULL,
NULL,
&Private->IgmpGroupEvent[TimerId]
);
if (EFI_ERROR (EfiStatus)) {
Private->IgmpGroupEvent[TimerId] = NULL;
return ;
}
EfiStatus = gBS->SetTimer (
Private->IgmpGroupEvent[TimerId],
TimerRelative,
MaxRespTime * 1000000 + Random (Private) % RAND_MAX
);
if (EFI_ERROR (EfiStatus)) {
gBS->CloseEvent (Private->IgmpGroupEvent[TimerId]);
Private->IgmpGroupEvent[TimerId] = NULL;
}
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
**/
STATIC
VOID
SendIgmpMessage (
PXE_BASECODE_DEVICE *Private,
UINT8 Type,
INTN GroupId
)
{
Private->IgmpMessage.Type = Type;
Private->IgmpMessage.MaxRespTime = 0;
Private->IgmpMessage.Checksum = 0;
Private->IgmpMessage.GroupAddress = Private->MCastGroup[GroupId];
Private->IgmpMessage.Checksum = IpChecksum (
(UINT16 *) &Private->IgmpMessage,
sizeof Private->IgmpMessage
);
Ipv4SendWOp (
Private,
0,
(UINT8 *) &Private->IgmpMessage,
sizeof Private->IgmpMessage,
PROT_IGMP,
RouterAlertOption,
sizeof RouterAlertOption,
((Type == IGMP_TYPE_LEAVE_GROUP) ? AllRoutersGroup.L : Private->IgmpMessage.GroupAddress),
EFI_PXE_BASE_CODE_FUNCTION_IGMP
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
**/
STATIC
VOID
ReportIgmp (
PXE_BASECODE_DEVICE *Private,
INTN GroupId
)
{
//
// if version 1 querier, send v1 report
//
UINT8 Type;
if (Private->Igmpv1TimeoutEvent != NULL) {
if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {
gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
Private->Igmpv1TimeoutEvent = NULL;
Private->UseIgmpv1Reporting = TRUE;
}
}
Type = (UINT8) (Private->UseIgmpv1Reporting ? IGMP_TYPE_V1REPORT : IGMP_TYPE_REPORT);
SendIgmpMessage (Private, Type, GroupId);
ClearGroupTimer (Private, GroupId);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
**/
VOID
IgmpCheckTimers (
PXE_BASECODE_DEVICE *Private
)
{
UINTN GroupId;
if (Private == NULL) {
return ;
}
for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
if (Private->IgmpGroupEvent[GroupId] == NULL) {
continue;
}
if (!EFI_ERROR (gBS->CheckEvent (Private->IgmpGroupEvent[GroupId]))) {
//
// send a report
//
ReportIgmp (Private, GroupId);
}
}
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
@return 0 := Group not found
@return other := Group ID#
**/
STATIC
INTN
FindMulticastGroup (
PXE_BASECODE_DEVICE *Private,
UINT32 GroupAddress
)
{
UINTN GroupId;
for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
if (Private->MCastGroup[GroupId] == GroupAddress) {
return GroupId + 1;
}
}
return 0;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
**/
VOID
IgmpJoinGroup (
PXE_BASECODE_DEVICE *Private,
EFI_IP_ADDRESS *GroupPtr
)
{
UINT32 Grp;
Grp = *(UINT32 *) GroupPtr;
//
// see if we already have it or if we can't take anymore
//
if (FindMulticastGroup (Private, Grp) || Private->MCastGroupCount == MAX_MCAST_GROUPS) {
return ;
}
//
// add the group
//
Private->MCastGroup[Private->MCastGroupCount] = Grp;
ReportIgmp (Private, Private->MCastGroupCount);
//
// send a report
// so it will get sent again per RFC 2236
//
SetGroupTimer (
Private,
Private->MCastGroupCount++,
UNSOLICITED_REPORT_INTERVAL * 10
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
**/
VOID
IgmpLeaveGroup (
PXE_BASECODE_DEVICE *Private,
EFI_IP_ADDRESS *GroupPtr
)
{
UINT32 Grp;
UINTN GroupId;
Grp = *(UINT32 *) GroupPtr;
//
// if not in group, ignore
//
GroupId = FindMulticastGroup (Private, Grp);
if (GroupId == 0) {
return ;
}
//
// if not v1 querrier, send leave group IGMP message
//
if (Private->Igmpv1TimeoutEvent != NULL) {
if (!EFI_ERROR (gBS->CheckEvent (Private->Igmpv1TimeoutEvent))) {
gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
Private->Igmpv1TimeoutEvent = NULL;
Private->UseIgmpv1Reporting = TRUE;
} else {
SendIgmpMessage (Private, IGMP_TYPE_LEAVE_GROUP, GroupId - 1);
}
}
while (GroupId < Private->MCastGroupCount) {
Private->MCastGroup[GroupId - 1] = Private->MCastGroup[GroupId];
Private->IgmpGroupEvent[GroupId - 1] = Private->IgmpGroupEvent[GroupId];
++GroupId;
}
--Private->MCastGroupCount;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
**/
VOID
HandleIgmp (
PXE_BASECODE_DEVICE *Private,
IGMPV2_MESSAGE *IgmpMessagePtr,
UINTN IgmpLength
)
{
EFI_STATUS EfiStatus;
UINTN GroupId;
INTN MaxRespTime;
if (Private == NULL) {
return ;
}
if (Private->MCastGroupCount == 0) {
//
// if we don't belong to any multicast groups, ignore
//
return ;
}
//
// verify checksum
//
if (IpChecksum ((UINT16 *) IgmpMessagePtr, IgmpLength)) {
//
// bad checksum - ignore packet
//
return ;
}
switch (IgmpMessagePtr->Type) {
case IGMP_TYPE_QUERY:
//
// if a version 1 querier, note the fact and set max resp time
//
MaxRespTime = IgmpMessagePtr->MaxRespTime;
if (MaxRespTime == 0) {
Private->UseIgmpv1Reporting = TRUE;
if (Private->Igmpv1TimeoutEvent != NULL) {
gBS->CloseEvent (Private->Igmpv1TimeoutEvent);
}
EfiStatus = gBS->CreateEvent (
EVT_TIMER,
TPL_CALLBACK,
NULL,
NULL,
&Private->Igmpv1TimeoutEvent
);
if (EFI_ERROR (EfiStatus)) {
Private->Igmpv1TimeoutEvent = NULL;
} else {
EfiStatus = gBS->SetTimer (
Private->Igmpv1TimeoutEvent,
TimerRelative,
(UINT64) V1ROUTER_PRESENT_TIMEOUT * 10000000
);
}
MaxRespTime = IGMP_DEFAULT_MAX_RESPONSE_TIME * 10;
}
//
// if a general query (!GroupAddress), set all our group timers
//
if (!IgmpMessagePtr->GroupAddress) {
for (GroupId = 0; GroupId < Private->MCastGroupCount; ++GroupId) {
SetGroupTimer (Private, GroupId, MaxRespTime);
}
} else {
//
// specific query - set only specific group
//
GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);
if (GroupId != 0) {
SetGroupTimer (Private, GroupId - 1, MaxRespTime);
}
}
break;
//
// if we have a timer running for this group, clear it
//
case IGMP_TYPE_V1REPORT:
case IGMP_TYPE_REPORT:
GroupId = FindMulticastGroup (Private, IgmpMessagePtr->GroupAddress);
if (GroupId != 0) {
ClearGroupTimer (Private, GroupId - 1);
}
break;
}
}
/* EOF - pxe_bc_igmp.c */

View File

@ -0,0 +1,846 @@
/** @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:
pxe_bc_ip.c
Abstract:
**/
#include "Bc.h"
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
Check if two IP addresses are on the same subnet.
@param IpLength Length of IP address in bytes.
@param Ip1 IP address to check.
@param Ip2 IP address to check.
@param SubnetMask Subnet mask to check with.
@retval TRUE IP addresses are on the same subnet.
@retval FALSE IP addresses are on different subnets.
**/
BOOLEAN
OnSameSubnet (
IN UINTN IpLength,
IN EFI_IP_ADDRESS *Ip1,
IN EFI_IP_ADDRESS *Ip2,
IN EFI_IP_ADDRESS *SubnetMask
)
{
if (IpLength == 0 || Ip1 == NULL || Ip2 == NULL || SubnetMask == NULL) {
return FALSE;
}
while (IpLength-- != 0) {
if ((Ip1->v6.Addr[IpLength] ^ Ip2->v6.Addr[IpLength]) & SubnetMask->v6.Addr[IpLength]) {
return FALSE;
}
}
return TRUE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
Add router to router table.
@param Private Pointer PxeBc instance data.
@param RouterIpPtr Pointer to router IP address.
@return Nothing
**/
VOID
IpAddRouter (
IN PXE_BASECODE_DEVICE *Private,
IN EFI_IP_ADDRESS *RouterIpPtr
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
UINTN Index;
if (Private == NULL || RouterIpPtr == NULL) {
return ;
}
PxeBcMode = Private->EfiBc.Mode;
//
// if we are filled up or this is not on the same subnet, forget it
//
if ((PxeBcMode->RouteTableEntries == PXE_ROUTER_TABLE_SIZE) ||
!OnSameSubnet(Private->IpLength, &PxeBcMode->StationIp, RouterIpPtr, &PxeBcMode->SubnetMask)) {
return ;
}
//
// make sure we don't already have it
//
for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
if (!CompareMem (
&PxeBcMode->RouteTable[Index].GwAddr,
RouterIpPtr,
Private->IpLength
)) {
return ;
}
}
//
// keep it
//
ZeroMem (
&PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries],
sizeof (EFI_PXE_BASE_CODE_ROUTE_ENTRY)
);
CopyMem (
&PxeBcMode->RouteTable[PxeBcMode->RouteTableEntries++].GwAddr,
RouterIpPtr,
Private->IpLength
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// return router ip to use for DestIp (0 if none)
//
STATIC
EFI_IP_ADDRESS *
GetRouterIp (
PXE_BASECODE_DEVICE *Private,
EFI_IP_ADDRESS *DestIpPtr
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
UINTN Index;
if (Private == NULL || DestIpPtr == NULL) {
return NULL;
}
PxeBcMode = Private->EfiBc.Mode;
for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
if (OnSameSubnet (
Private->IpLength,
&PxeBcMode->RouteTable[Index].IpAddr,
DestIpPtr,
&PxeBcMode->RouteTable[Index].SubnetMask
)) {
return &PxeBcMode->RouteTable[Index].GwAddr;
}
}
return NULL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// routine to send ipv4 packet
// ipv4 header of length HdrLth in TransmitBufferPtr
// routine fills in ipv4hdr Ver_Hdl, TotalLength, and Checksum, moves in Data
// and gets dest MAC address
//
#define IP_TX_BUFFER ((IPV4_BUFFER *) Private->TransmitBufferPtr)
#define IP_TX_HEADER IP_TX_BUFFER->IpHeader
EFI_STATUS
Ipv4Xmt (
PXE_BASECODE_DEVICE *Private,
UINT32 GatewayIp,
UINTN IpHeaderLength,
UINTN TotalHeaderLength,
VOID *Data,
UINTN DataLength,
EFI_PXE_BASE_CODE_FUNCTION Function
)
{
EFI_MAC_ADDRESS DestMac;
EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
EFI_STATUS StatCode;
UINTN PacketLength;
Snp = Private->SimpleNetwork;
PxeBcMode = Private->EfiBc.Mode;
StatCode = EFI_SUCCESS;
PacketLength = TotalHeaderLength + DataLength;
//
// get dest MAC address
// multicast - convert to hw equiv
// unicast on same net, use arp
// on different net, arp for router
//
if (IP_TX_HEADER.DestAddr.L == BROADCAST_IPv4) {
CopyMem (&DestMac, &Snp->Mode->BroadcastAddress, sizeof (DestMac));
} else if (IS_MULTICAST (&IP_TX_HEADER.DestAddr)) {
StatCode = (*Snp->MCastIpToMac) (Snp, PxeBcMode->UsingIpv6, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr, &DestMac);
} else {
UINT32 Ip;
if (OnSameSubnet (
Private->IpLength,
&PxeBcMode->StationIp,
(EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr,
&PxeBcMode->SubnetMask
)) {
Ip = IP_TX_HEADER.DestAddr.L;
} else if (GatewayIp != 0) {
Ip = GatewayIp;
} else {
EFI_IP_ADDRESS *TmpIp;
TmpIp = GetRouterIp (Private, (EFI_IP_ADDRESS *) &IP_TX_HEADER.DestAddr);
if (TmpIp == NULL) {
DEBUG (
(DEBUG_WARN,
"\nIpv4Xmit() Exit #1 %xh (%r)",
EFI_NO_RESPONSE,
EFI_NO_RESPONSE)
);
return EFI_NO_RESPONSE;
//
// no router
//
}
Ip = TmpIp->Addr[0];
}
if (!GetHwAddr (
Private,
(EFI_IP_ADDRESS *) &Ip,
(EFI_MAC_ADDRESS *) &DestMac
)) {
if (!PxeBcMode->AutoArp) {
DEBUG (
(DEBUG_WARN,
"\nIpv4Xmit() Exit #2 %xh (%r)",
EFI_DEVICE_ERROR,
EFI_DEVICE_ERROR)
);
return EFI_DEVICE_ERROR;
} else {
StatCode = DoArp (
Private,
(EFI_IP_ADDRESS *) &Ip,
(EFI_MAC_ADDRESS *) &DestMac
);
}
}
}
if (EFI_ERROR (StatCode)) {
DEBUG ((DEBUG_WARN, "\nIpv4Xmit() Exit #3 %xh (%r)", StatCode, StatCode));
return StatCode;
}
//
// fill in packet info
//
SET_IPV4_VER_HDL (&IP_TX_HEADER, IpHeaderLength);
IP_TX_HEADER.TotalLength = HTONS (PacketLength);
IP_TX_HEADER.HeaderChecksum = IpChecksum ((UINT16 *) &IP_TX_HEADER, IpHeaderLength);
CopyMem (((UINT8 *) &IP_TX_HEADER) + TotalHeaderLength, Data, DataLength);
//
// send it
//
return SendPacket (
Private,
(UINT8 *) &IP_TX_HEADER - Snp->Mode->MediaHeaderSize,
&IP_TX_HEADER,
PacketLength,
&DestMac,
PXE_PROTOCOL_ETHERNET_IP,
Function
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// send ipv4 packet with option
//
EFI_STATUS
Ipv4SendWOp (
PXE_BASECODE_DEVICE *Private,
UINT32 GatewayIp,
UINT8 *Msg,
UINTN MessageLength,
UINT8 Prot,
UINT8 *Option,
UINTN OptionLength,
UINT32 DestIp,
EFI_PXE_BASE_CODE_FUNCTION Function
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
UINTN HdrLth;
PxeBcMode = Private->EfiBc.Mode;
HdrLth = sizeof (IPV4_HEADER) + OptionLength;
ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));
IP_TX_HEADER.TimeToLive = PxeBcMode->TTL;
IP_TX_HEADER.TypeOfService = PxeBcMode->ToS;
IP_TX_HEADER.Protocol = Prot;
IP_TX_HEADER.SrcAddr.L = *(UINT32 *) &PxeBcMode->StationIp;
IP_TX_HEADER.DestAddr.L = DestIp;
IP_TX_HEADER.Id = Random (Private);
CopyMem (IP_TX_BUFFER->u.Data, Option, OptionLength);
return Ipv4Xmt (
Private,
GatewayIp,
HdrLth,
HdrLth,
Msg,
MessageLength,
Function
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// send MessageLength message at MessagePtr - higher level protocol header already in TransmitBufferPtr, length HdrSize
//
EFI_STATUS
Ip4Send (
PXE_BASECODE_DEVICE *Private, // pointer to instance data
UINTN MayFrag, //
UINT8 Prot, // protocol
UINT32 SrcIp, // Source IP address
UINT32 DestIp, // Destination IP address
UINT32 GatewayIp, // used if not NULL and needed
UINTN HdrSize, // protocol header byte length
UINT8 *MessagePtr, // pointer to data
UINTN MessageLength // data byte length
)
{
EFI_STATUS StatCode;
UINTN TotDataLength;
TotDataLength = HdrSize + MessageLength;
if (TotDataLength > MAX_IPV4_DATA_SIZE) {
DEBUG (
(DEBUG_WARN,
"\nIp4Send() Exit #1 %xh (%r)",
EFI_BAD_BUFFER_SIZE,
EFI_BAD_BUFFER_SIZE)
);
return EFI_BAD_BUFFER_SIZE;
}
ZeroMem ((VOID *) &IP_TX_HEADER, sizeof (IPV4_HEADER));
IP_TX_HEADER.TimeToLive = DEFAULT_TTL;
IP_TX_HEADER.Protocol = Prot;
IP_TX_HEADER.SrcAddr.L = SrcIp;
IP_TX_HEADER.DestAddr.L = DestIp;
IP_TX_HEADER.Id = Random (Private);
if (!MayFrag) {
*(UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_NO_FRAG >> 8;
}
//
// check for need to fragment
//
if (TotDataLength > MAX_IPV4_FRAME_DATA_SIZE) {
UINTN DataLengthSent;
UINT16 FragmentOffset;
FragmentOffset = IP_MORE_FRAG;
//
// frag offset field
//
if (!MayFrag) {
DEBUG (
(DEBUG_WARN,
"\nIp4Send() Exit #2 %xh (%r)",
EFI_BAD_BUFFER_SIZE,
EFI_BAD_BUFFER_SIZE)
);
return EFI_BAD_BUFFER_SIZE;
}
//
// send out in fragments - first includes upper level header
// all are max and include more frag bit except last
//
* (UINT8 *) (&IP_TX_HEADER.FragmentFields) = IP_MORE_FRAG >> 8;
#define IPV4_FRAG_SIZE (MAX_IPV4_FRAME_DATA_SIZE & 0xfff8)
#define IPV4_FRAG_OFF_INC (IPV4_FRAG_SIZE >> 3)
DataLengthSent = IPV4_FRAG_SIZE - HdrSize;
StatCode = Ipv4Xmt (
Private,
GatewayIp,
sizeof (IPV4_HEADER),
sizeof (IPV4_HEADER) + HdrSize,
MessagePtr,
DataLengthSent,
Private->Function
);
if (EFI_ERROR (StatCode)) {
DEBUG (
(DEBUG_WARN,
"\nIp4Send() Exit #3 %xh (%r)",
StatCode,
StatCode)
);
return StatCode;
}
MessagePtr += DataLengthSent;
MessageLength -= DataLengthSent;
FragmentOffset += IPV4_FRAG_OFF_INC;
IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);
while (MessageLength > IPV4_FRAG_SIZE) {
StatCode = Ipv4Xmt (
Private,
GatewayIp,
sizeof (IPV4_HEADER),
sizeof (IPV4_HEADER),
MessagePtr,
IPV4_FRAG_SIZE,
Private->Function
);
if (EFI_ERROR (StatCode)) {
DEBUG (
(DEBUG_WARN,
"\nIp4Send() Exit #3 %xh (%r)",
StatCode,
StatCode)
);
return StatCode;
}
MessagePtr += IPV4_FRAG_SIZE;
MessageLength -= IPV4_FRAG_SIZE;
FragmentOffset += IPV4_FRAG_OFF_INC;
IP_TX_HEADER.FragmentFields = HTONS (FragmentOffset);
}
* (UINT8 *) (&IP_TX_HEADER.FragmentFields) &= ~(IP_MORE_FRAG >> 8);
HdrSize = 0;
}
//
// transmit
//
return Ipv4Xmt (
Private,
GatewayIp,
sizeof (IPV4_HEADER),
sizeof (IPV4_HEADER) + HdrSize,
MessagePtr,
MessageLength,
Private->Function
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// return true if dst IP in receive header matched with what's enabled
//
STATIC
BOOLEAN
IPgood (
PXE_BASECODE_DEVICE *Private,
IPV4_HEADER *IpHeader
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
UINTN Index;
PxeBcMode = Private->EfiBc.Mode;
if (PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) {
return TRUE;
}
if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) &&
IS_MULTICAST (&IpHeader->DestAddr)
) {
return TRUE;
}
if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) &&
PxeBcMode->StationIp.Addr[0] == IpHeader->DestAddr.L
) {
return TRUE;
}
if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) && IpHeader->DestAddr.L == BROADCAST_IPv4) {
return TRUE;
}
for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; ++Index) {
if (IpHeader->DestAddr.L == PxeBcMode->IpFilter.IpList[Index].Addr[0]) {
return TRUE;
}
}
return FALSE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// receive up to MessageLength message into MessagePtr for protocol Prot
// return message length, src/dest ips if select any, and pointer to protocol
// header routine will filter based on source and/or dest ip if OpFlags set.
//
EFI_STATUS
IpReceive (
PXE_BASECODE_DEVICE *Private,
PXE_OPFLAGS OpFlags,
EFI_IP_ADDRESS *SrcIpPtr,
EFI_IP_ADDRESS *DestIpPtr,
UINT8 Prot,
VOID *HeaderPtr,
UINTN HdrSize,
UINT8 *MessagePtr,
UINTN *MessageLengthPtr,
EFI_EVENT TimeoutEvent
)
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
EFI_STATUS StatCode;
UINTN ByteCount;
UINTN FragmentCount;
UINTN ExpectedPacketLength;
UINTN Id;
BOOLEAN GotFirstFragment;
BOOLEAN GotLastFragment;
DEBUG (
(DEBUG_NET,
"\nIpReceive() Hdr=%Xh HdrSz=%d Data=%Xh DataSz=%d",
HeaderPtr,
HdrSize,
MessagePtr,
*MessageLengthPtr)
);
PxeBcMode = Private->EfiBc.Mode;
PxeBcMode->IcmpErrorReceived = FALSE;
ExpectedPacketLength = 0;
GotFirstFragment = FALSE;
GotLastFragment = FALSE;
FragmentCount = 0;
ByteCount = 0;
Id = 0;
for (;;) {
IPV4_HEADER IpHdr;
UINTN FFlds;
UINTN TotalLength;
UINTN FragmentOffset;
UINTN HeaderSize;
UINTN BufferSize;
UINTN IpHeaderLength;
UINTN DataLength;
UINT16 Protocol;
UINT8 *NextHdrPtr;
UINT8 *PacketPtr;
StatCode = WaitForReceive (
Private,
Private->Function,
TimeoutEvent,
&HeaderSize,
&BufferSize,
&Protocol
);
if (EFI_ERROR (StatCode)) {
return StatCode;
}
PacketPtr = Private->ReceiveBufferPtr + HeaderSize;
if (Protocol == PXE_PROTOCOL_ETHERNET_ARP) {
HandleArpReceive (
Private,
(ARP_PACKET *) PacketPtr,
Private->ReceiveBufferPtr
);
continue;
}
if (Protocol != PXE_PROTOCOL_ETHERNET_IP) {
continue;
}
#define IpRxHeader ((IPV4_HEADER *) PacketPtr)
//
// filter for version & check sum
//
IpHeaderLength = IPV4_HEADER_LENGTH (IpRxHeader);
if ((IpRxHeader->VersionIhl >> 4) != IPVER4) {
continue;
}
if (IpChecksum ((UINT16 *) IpRxHeader, IpHeaderLength)) {
continue;
}
CopyMem (&IpHdr, IpRxHeader, sizeof (IpHdr));
TotalLength = NTOHS (IpHdr.TotalLength);
if (IpHdr.Protocol == PROT_TCP) {
//
// The NextHdrPtr is used to seed the header buffer we are passing back.
// That being the case, we want to see everything in pPkt which contains
// everything but the ethernet (or whatever) frame. IP + TCP in this case.
//
DataLength = TotalLength;
NextHdrPtr = PacketPtr;
} else {
DataLength = TotalLength - IpHeaderLength;
NextHdrPtr = PacketPtr + IpHeaderLength;
}
//
// If this is an ICMP, it might not be for us.
// Double check the state of the IP stack and the
// packet fields before assuming it is an ICMP
// error. ICMP requests are not supported by the
// PxeBc IP stack and should be ignored.
//
if (IpHdr.Protocol == PROT_ICMP) {
ICMPV4_HEADER *Icmpv4;
Icmpv4 = (ICMPV4_HEADER *) NextHdrPtr;
//
// For now only obvious ICMP error replies will be accepted by
// this stack. This still makes us vulnerable to DoS attacks.
// But at least we will not be killed by DHCP daemons.
//
switch (Icmpv4->Type) {
case ICMP_REDIRECT:
case ICMP_ECHO:
case ICMP_ROUTER_ADV:
case ICMP_ROUTER_SOLICIT:
case ICMP_TIMESTAMP:
case ICMP_TIMESTAMP_REPLY:
case ICMP_INFO_REQ:
case ICMP_INFO_REQ_REPLY:
case ICMP_SUBNET_MASK_REQ:
case ICMP_SUBNET_MASK_REPLY:
default:
continue;
//
// %%TBD - This should be implemented.
//
case ICMP_ECHO_REPLY:
continue;
case ICMP_DEST_UNREACHABLE:
case ICMP_TIME_EXCEEDED:
case ICMP_PARAMETER_PROBLEM:
case ICMP_SOURCE_QUENCH:
PxeBcMode->IcmpErrorReceived = TRUE;
CopyMem (
&PxeBcMode->IcmpError,
NextHdrPtr,
sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
);
DEBUG (
(DEBUG_NET,
"\nIpReceive() Exit #1 %Xh (%r)",
EFI_ICMP_ERROR,
EFI_ICMP_ERROR)
);
}
return EFI_ICMP_ERROR;
}
if (IpHdr.Protocol == PROT_IGMP) {
HandleIgmp (Private, (IGMPV2_MESSAGE *) NextHdrPtr, DataLength);
DEBUG ((DEBUG_NET, "\n IGMP"));
continue;
}
//
// check for protocol
//
if (IpHdr.Protocol != Prot) {
continue;
}
//
// do filtering
//
if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr && SrcIpPtr->Addr[0] != IpHdr.SrcAddr.L) {
DEBUG ((DEBUG_NET, "\n Not expected source IP address."));
continue;
}
if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) {
if (!IPgood (Private, &IpHdr)) {
continue;
}
} else if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP)) {
if (DestIpPtr == NULL) {
if (PxeBcMode->StationIp.Addr[0] != IpHdr.DestAddr.L) {
continue;
}
} else if (DestIpPtr->Addr[0] != IpHdr.DestAddr.L) {
continue;
}
}
//
// get some data we need
//
FFlds = NTOHS (IpHdr.FragmentFields);
FragmentOffset = ((FFlds & IP_FRAG_OFF_MSK) << 3);
/* Keep count of fragments that belong to this session.
* If we get packets with a different IP ID number,
* ignore them. Ignored packets should be handled
* by the upper level protocol.
*/
if (FragmentCount == 0) {
Id = IpHdr.Id;
if (DestIpPtr != NULL) {
DestIpPtr->Addr[0] = IpHdr.DestAddr.L;
}
if (SrcIpPtr != NULL) {
SrcIpPtr->Addr[0] = IpHdr.SrcAddr.L;
}
} else {
if (IpHdr.Id != Id) {
continue;
}
}
++FragmentCount;
/* Fragment management.
*/
if (FragmentOffset == 0) {
/* This is the first fragment (may also be the
* only fragment).
*/
GotFirstFragment = TRUE;
/* If there is a separate protocol header buffer,
* copy the header, adjust the data pointer and
* the data length.
*/
if (HdrSize != 0) {
CopyMem (HeaderPtr, NextHdrPtr, HdrSize);
NextHdrPtr += HdrSize;
DataLength -= HdrSize;
}
} else {
/* If there is a separate protocol header buffer,
* adjust the fragment offset.
*/
FragmentOffset -= HdrSize;
}
/* See if this is the last fragment.
*/
if (!(FFlds & IP_MORE_FRAG)) {
//
// This is the last fragment (may also be the only fragment).
//
GotLastFragment = TRUE;
/* Compute the expected length of the assembled
* packet. This will be used to decide if we
* have gotten all of the fragments.
*/
ExpectedPacketLength = FragmentOffset + DataLength;
}
DEBUG (
(DEBUG_NET,
"\n ID = %Xh Off = %d Len = %d",
Id,
FragmentOffset,
DataLength)
);
/* Check for receive buffer overflow.
*/
if (FragmentOffset + DataLength > *MessageLengthPtr) {
/* There is not enough space in the receive
* buffer for the fragment.
*/
DEBUG (
(DEBUG_NET,
"\nIpReceive() Exit #3 %Xh (%r)",
EFI_BUFFER_TOO_SMALL,
EFI_BUFFER_TOO_SMALL)
);
return EFI_BUFFER_TOO_SMALL;
}
/* Copy data into receive buffer.
*/
if (DataLength != 0) {
DEBUG ((DEBUG_NET, " To = %Xh", MessagePtr + FragmentOffset));
CopyMem (MessagePtr + FragmentOffset, NextHdrPtr, DataLength);
ByteCount += DataLength;
}
/* If we have seen the first and last fragments and
* the receive byte count is at least as large as the
* expected byte count, return SUCCESS.
*
* We could be tricked by receiving a fragment twice
* but the upper level protocol should figure this
* out.
*/
if (GotFirstFragment && GotLastFragment && ByteCount >= ExpectedPacketLength) {
*MessageLengthPtr = ExpectedPacketLength;
return EFI_SUCCESS;
}
}
}
/* eof - pxe_bc_ip.c */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,517 @@
/** @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:
pxe_bc_udp.c
Abstract:
**/
#include "Bc.h"
//
// //////////////////////////////////////////////////////////////////////
//
// Udp Write Routine - called by base code - e.g. TFTP - already locked
//
/**
@return EFI_SUCCESS :=
@return EFI_INVALID_PARAMETER :=
@return other :=
**/
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
)
{
UINTN TotalLength;
UINTN HeaderSize;
EFI_PXE_BASE_CODE_UDP_PORT DefaultSrcPort;
//
//
//
HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0;
DefaultSrcPort = 0;
//
// check parameters
//
if (BufferSizeptr == NULL ||
BufferPtr == NULL ||
DestIpPtr == NULL ||
DestPortPtr == NULL ||
(HeaderSizePtr != NULL && *HeaderSizePtr == 0) ||
(HeaderSize != 0 && HeaderPtr == NULL) ||
(GatewayIpPtr != NULL && !IS_INADDR_UNICAST(GatewayIpPtr)) ||
(OpFlags &~(EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT))
) {
DEBUG (
(DEBUG_WARN,
"\nUdpWrite() Exit #1 %xh (%r)",
EFI_INVALID_PARAMETER,
EFI_INVALID_PARAMETER)
);
return EFI_INVALID_PARAMETER;
}
TotalLength = *BufferSizeptr + HeaderSize + sizeof (UDPV4_HEADER);
if (TotalLength > 0x0000ffff) {
DEBUG (
(DEBUG_WARN,
"\nUdpWrite() Exit #2 %xh (%r)",
EFI_BAD_BUFFER_SIZE,
EFI_BAD_BUFFER_SIZE)
);
return EFI_BAD_BUFFER_SIZE;
}
if (SrcIpPtr == NULL) {
SrcIpPtr = &Private->EfiBc.Mode->StationIp;
}
if (SrcPortPtr == NULL) {
SrcPortPtr = &DefaultSrcPort;
OpFlags |= EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT;
}
if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) {
*SrcPortPtr = Private->RandomPort;
if (++Private->RandomPort == 0) {
Private->RandomPort = PXE_RND_PORT_LOW;
}
}
#define IpTxBuffer ((IPV4_BUFFER *) Private->TransmitBufferPtr)
//
// build pseudo header and udp header in transmit buffer
//
#define Udpv4Base ((UDPV4_HEADERS *) (IpTxBuffer->u.Data - sizeof (UDPV4_PSEUDO_HEADER)))
Udpv4Base->Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];
Udpv4Base->Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];
Udpv4Base->Udpv4PseudoHeader.Zero = 0;
Udpv4Base->Udpv4PseudoHeader.Protocol = PROT_UDP;
Udpv4Base->Udpv4PseudoHeader.TotalLength = HTONS (TotalLength);
Udpv4Base->Udpv4Header.SrcPort = HTONS (*SrcPortPtr);
Udpv4Base->Udpv4Header.DestPort = HTONS (*DestPortPtr);
Udpv4Base->Udpv4Header.TotalLength = Udpv4Base->Udpv4PseudoHeader.TotalLength;
Udpv4Base->Udpv4Header.Checksum = 0;
if (HeaderSize != 0) {
CopyMem (IpTxBuffer->u.Udp.Data, HeaderPtr, HeaderSize);
}
HeaderSize += sizeof (UDPV4_HEADER);
Udpv4Base->Udpv4Header.Checksum = IpChecksum2 (
(UINT16 *) Udpv4Base,
HeaderSize + sizeof (UDPV4_PSEUDO_HEADER),
(UINT16 *) BufferPtr,
(UINT16) *BufferSizeptr
);
if (Udpv4Base->Udpv4Header.Checksum == 0) {
Udpv4Base->Udpv4Header.Checksum = 0xffff;
//
// transmit zero checksum as ones complement
//
}
return Ip4Send (
Private,
OpFlags,
PROT_UDP,
Udpv4Base->Udpv4PseudoHeader.SrcAddr.L,
Udpv4Base->Udpv4PseudoHeader.DestAddr.L,
(GatewayIpPtr) ? GatewayIpPtr->Addr[0] : 0,
HeaderSize,
BufferPtr,
*BufferSizeptr
);
}
//
// //////////////////////////////////////////////////////////
//
// BC Udp Write Routine
//
/**
@return EFI_SUCCESS :=
@return other :=
**/
EFI_STATUS
EFIAPI
BcUdpWrite (
IN EFI_PXE_BASE_CODE_PROTOCOL *This,
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
)
{
EFI_STATUS StatCode;
PXE_BASECODE_DEVICE *Private;
//
// Lock the instance data and make sure started
//
StatCode = EFI_SUCCESS;
if (This == NULL) {
DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
return EFI_INVALID_PARAMETER;
}
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
if (Private == NULL) {
DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
return EFI_INVALID_PARAMETER;
}
EfiAcquireLock (&Private->Lock);
if (This->Mode == NULL || !This->Mode->Started) {
DEBUG ((DEBUG_ERROR, "BC was not started."));
EfiReleaseLock (&Private->Lock);
return EFI_NOT_STARTED;
}
Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_WRITE;
//
// Issue BC command
//
StatCode = UdpWrite (
Private,
OpFlags,
DestIpPtr,
DestPortPtr,
GatewayIpPtr,
SrcIpPtr,
SrcPortPtr,
HeaderSizePtr,
HeaderPtr,
BufferSizeptr,
BufferPtr
);
//
// Unlock the instance data
//
EfiReleaseLock (&Private->Lock);
return StatCode;
}
//
// /////////////////////////////////////////////////////////////////////
//
// Udp Read Routine - called by base code - e.g. TFTP - already locked
//
/**
@return EFI_SUCCESS :=
@return EFI_INVALID_PARAMETER :=
@return other :=
**/
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 *DestPortPtr, 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,
EFI_EVENT TimeoutEvent
)
{
EFI_STATUS StatCode;
EFI_IP_ADDRESS TmpSrcIp;
EFI_IP_ADDRESS TmpDestIp;
UINTN BufferSize;
UINTN HeaderSize;
//
// combination structure of pseudo header/udp header
//
#pragma pack (1)
struct {
UDPV4_PSEUDO_HEADER Udpv4PseudoHeader;
UDPV4_HEADER Udpv4Header;
UINT8 ProtHdr[64];
} Hdrs;
#pragma pack ()
HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0;
//
// read [with filtering]
// check parameters
//
if (BufferSizeptr == NULL ||
BufferPtr == NULL ||
(HeaderSize != 0 && HeaderPtr == NULL) ||
(OpFlags &~UDP_FILTER_MASK)
//
// if filtering on a particular IP/Port, need it
//
||
(!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr == NULL) ||
(!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && SrcPortPtr == NULL) ||
(!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && DestPortPtr == NULL)
) {
DEBUG ((DEBUG_INFO, "\nUdpRead() Exit #1 Invalid Parameter"));
return EFI_INVALID_PARAMETER;
}
//
// in case we loop
//
BufferSize = *BufferSizeptr;
//
// we need source and dest IPs for pseudo header
//
if (SrcIpPtr == NULL) {
SrcIpPtr = &TmpSrcIp;
}
if (DestIpPtr == NULL) {
DestIpPtr = &TmpDestIp;
TmpDestIp = Private->EfiBc.Mode->StationIp;
}
#if SUPPORT_IPV6
if (Private->EfiBc.Mode->UsingIpv6) {
//
// %%TBD
//
}
#endif
for (;;) {
*BufferSizeptr = BufferSize;
StatCode = IpReceive (
Private,
OpFlags,
SrcIpPtr,
DestIpPtr,
PROT_UDP,
&Hdrs.Udpv4Header,
HeaderSize + sizeof Hdrs.Udpv4Header,
BufferPtr,
BufferSizeptr,
TimeoutEvent
);
if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
UINT16 SPort;
UINT16 DPort;
SPort = NTOHS (Hdrs.Udpv4Header.SrcPort);
DPort = NTOHS (Hdrs.Udpv4Header.DestPort);
//
// do filtering
//
if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && *SrcPortPtr != SPort) {
continue;
}
if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && *DestPortPtr != DPort) {
continue;
}
//
// check checksum
//
if (StatCode == EFI_SUCCESS && Hdrs.Udpv4Header.Checksum) {
Hdrs.Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];
Hdrs.Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];
Hdrs.Udpv4PseudoHeader.Zero = 0;
Hdrs.Udpv4PseudoHeader.Protocol = PROT_UDP;
Hdrs.Udpv4PseudoHeader.TotalLength = Hdrs.Udpv4Header.TotalLength;
if (Hdrs.Udpv4Header.Checksum == 0xffff) {
Hdrs.Udpv4Header.Checksum = 0;
}
if (IpChecksum2 (
(UINT16 *) &Hdrs.Udpv4PseudoHeader,
HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader) + sizeof (Hdrs.Udpv4Header),
(UINT16 *) BufferPtr,
*BufferSizeptr
)) {
DEBUG (
(DEBUG_INFO,
"\nUdpRead() Hdrs.Udpv4PseudoHeader == %Xh",
Hdrs.Udpv4PseudoHeader)
);
DEBUG (
(DEBUG_INFO,
"\nUdpRead() Header size == %d",
HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader))
);
DEBUG (
(DEBUG_INFO,
"\nUdpRead() BufferPtr == %Xh",
BufferPtr)
);
DEBUG (
(DEBUG_INFO,
"\nUdpRead() Buffer size == %d",
*BufferSizeptr)
);
DEBUG ((DEBUG_INFO, "\nUdpRead() Exit #2 Device Error"));
return EFI_DEVICE_ERROR;
}
}
//
// all passed
//
if (SrcPortPtr != NULL) {
*SrcPortPtr = SPort;
}
if (DestPortPtr != NULL) {
*DestPortPtr = DPort;
}
if (HeaderSize != 0) {
CopyMem (HeaderPtr, Hdrs.ProtHdr, HeaderSize);
}
}
if ((StatCode != EFI_SUCCESS) && (StatCode != EFI_TIMEOUT)) {
DEBUG (
(DEBUG_INFO,
"\nUdpRead() Exit #3 %Xh %r",
StatCode,
StatCode)
);
}
return StatCode;
}
}
//
// //////////////////////////////////////////////////////////
//
// BC Udp Read Routine
//
/**
@return EFI_SUCCESS :=
@return other :=
**/
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 StatCode;
PXE_BASECODE_DEVICE *Private;
//
// Lock the instance data and make sure started
//
StatCode = EFI_SUCCESS;
if (This == NULL) {
DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
return EFI_INVALID_PARAMETER;
}
Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
if (Private == NULL) {
DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
return EFI_INVALID_PARAMETER;
}
EfiAcquireLock (&Private->Lock);
if (This->Mode == NULL || !This->Mode->Started) {
DEBUG ((DEBUG_ERROR, "BC was not started."));
EfiReleaseLock (&Private->Lock);
return EFI_NOT_STARTED;
}
Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_READ;
//
// Issue BC command
//
StatCode = UdpRead (
Private,
OpFlags,
DestIp,
DestPort,
SrcIp,
SrcPort,
HeaderSize,
HeaderPtr,
BufferSize,
BufferPtr,
0
);
//
// Unlock the instance data and return
//
EfiReleaseLock (&Private->Lock);
return StatCode;
}
/* eof - pxe_bc_udp.c */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,154 @@
/** @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 */

View File

@ -0,0 +1,26 @@
/** @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

View File

@ -0,0 +1,169 @@
/** @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:
ComponentName.c
Abstract:
PxeDhcp4 component name protocol declarations
**/
#include "PxeDhcp4.h"
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// EFI Component Name Functions
//
EFI_STATUS
EFIAPI
PxeDhcp4ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
EFI_STATUS
EFIAPI
PxeDhcp4ComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// EFI Component Name Protocol
//
EFI_COMPONENT_NAME_PROTOCOL gPxeDhcp4ComponentName = {
PxeDhcp4ComponentNameGetDriverName,
PxeDhcp4ComponentNameGetControllerName,
"eng"
};
static EFI_UNICODE_STRING_TABLE mPxeDhcp4DriverNameTable[] = {
{
"eng",
L"PXE DHCPv4 Driver"
},
{
NULL,
NULL
}
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
EFIAPI
PxeDhcp4ComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
Language - A pointer to a three character ISO 639-2 language identifier.
This is the language of the driver name that that the caller
is requesting, and it must match one of the languages specified
in SupportedLanguages. The number of languages supported by a
driver is up to the driver writer.
DriverName - A pointer to the Unicode string to return. This Unicode string
is the name of the driver specified by This in the language
specified by Language.
Returns:
EFI_SUCCESS - The Unicode string for the Driver specified by This
and the language specified by Language was returned
in DriverName.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - DriverName is NULL.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return LookupUnicodeString (
Language,
gPxeDhcp4ComponentName.SupportedLanguages,
mPxeDhcp4DriverNameTable,
DriverName
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
EFIAPI
PxeDhcp4ComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by an EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
ControllerHandle - The handle of a controller that the driver specified by
This is managing. This handle specifies the controller
whose name is to be returned.
ChildHandle - The handle of the child controller to retrieve the name
of. This is an optional parameter that may be NULL. It
will be NULL for device drivers. It will also be NULL
for a bus drivers that wish to retrieve the name of the
bus controller. It will not be NULL for a bus driver
that wishes to retrieve the name of a child controller.
Language - A pointer to a three character ISO 639-2 language
identifier. This is the language of the controller name
that that the caller is requesting, and it must match one
of the languages specified in SupportedLanguages. The
number of languages supported by a driver is up to the
driver writer.
ControllerName - A pointer to the Unicode string to return. This Unicode
string is the name of the controller specified by
ControllerHandle and ChildHandle in the language specified
by Language from the point of view of the driver specified
by This.
Returns:
EFI_SUCCESS - The Unicode string for the user readable name in the
language specified by Language for the driver
specified by This was returned in DriverName.
EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - ControllerName is NULL.
EFI_UNSUPPORTED - The driver specified by This is not currently managing
the controller specified by ControllerHandle and
ChildHandle.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return EFI_UNSUPPORTED;
}
/* EOF - ComponentName.c */

View File

@ -0,0 +1,355 @@
/** @file
Copyright (c) 2004 - 2005, 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.c
Abstract:
**/
#include "PxeDhcp4.h"
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// Prototypes
// Driver model protocol interface
//
EFI_STATUS
EFIAPI
PxeDhcp4DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
EFI_STATUS
EFIAPI
PxeDhcp4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
EFI_STATUS
EFIAPI
PxeDhcp4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
EFI_STATUS
EFIAPI
PxeDhcp4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// PXE DHCP Protocol Interface
//
EFI_DRIVER_BINDING_PROTOCOL gPxeDhcp4DriverBinding = {
PxeDhcp4DriverBindingSupported,
PxeDhcp4DriverBindingStart,
PxeDhcp4DriverBindingStop,
0xa,
NULL,
NULL
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//
// PxeDhcp4 Driver Entry point funtion
//
/**
Register Driver Binding protocol for this driver.
@param entry EFI_IMAGE_ENTRY_POINT)
@retval EFI_SUCCESS Driver loaded.
@retval other Driver not loaded.
**/
EFI_STATUS
EFIAPI
PxeDhcp4DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return EfiLibInstallAllDriverProtocols (
ImageHandle,
SystemTable,
&gPxeDhcp4DriverBinding,
NULL,
COMPONENT_NAME,
NULL,
NULL
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
Test to see if this driver supports ControllerHandle. Any
ControllerHandle that contains a PxeBaseCode protocol can be
supported.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to test.
@param RemainingDevicePath Not used.
@retval EFI_SUCCESS This driver supports this device.
@retval EFI_ALREADY_STARTED This driver is already running on this device.
@retval other This driver does not support this device.
**/
EFI_STATUS
EFIAPI
PxeDhcp4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL * This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
//
// Open the IO Abstraction(s) needed to perform the supported test.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiPxeBaseCodeProtocolGuid,
(VOID **) &PxeBc,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Close the I/O Abstraction(s) used to perform the supported test.
//
return gBS->CloseProtocol (
ControllerHandle,
&gEfiPxeBaseCodeProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
Start this driver on ControllerHandle by opening a PxeBaseCode
protocol and installing a PxeDhcp4 protocol on ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to bind driver to.
@param RemainingDevicePath Not used, always produce all possible children.
@retval EFI_SUCCESS This driver is added to ControllerHandle.
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
@retval other This driver does not support this device.
**/
EFI_STATUS
EFIAPI
PxeDhcp4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL * This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
PXE_DHCP4_PRIVATE_DATA *Private;
//
// Connect to the PxeBaseCode interface on ControllerHandle.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiPxeBaseCodeProtocolGuid,
(VOID **) &PxeBc,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// BaseCode has already grabbed the SimpleNetwork interface
// so just do a HandleProtocol() to get it.
//
Status = gBS->HandleProtocol (
ControllerHandle,
&gEfiSimpleNetworkProtocolGuid,
(VOID **) &Snp
);
if (EFI_ERROR (Status)) {
goto error_exit;
}
ASSERT (Snp);
//
// Initialize the PXE DHCP device instance.
//
Private = AllocateZeroPool (sizeof (PXE_DHCP4_PRIVATE_DATA));
if (Private == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto error_exit;
}
Private->Signature = PXE_DHCP4_PRIVATE_DATA_SIGNATURE;
Private->PxeBc = PxeBc;
Private->Snp = Snp;
Private->Handle = ControllerHandle;
Private->PxeDhcp4.Revision = EFI_PXE_DHCP4_PROTOCOL_REVISION;
Private->PxeDhcp4.Run = PxeDhcp4Run;
Private->PxeDhcp4.Setup = PxeDhcp4Setup;
Private->PxeDhcp4.Init = PxeDhcp4Init;
Private->PxeDhcp4.Select = PxeDhcp4Select;
Private->PxeDhcp4.Renew = PxeDhcp4Renew;
Private->PxeDhcp4.Rebind = PxeDhcp4Rebind;
Private->PxeDhcp4.Release = PxeDhcp4Release;
Private->PxeDhcp4.Data = NULL;
//
// Install protocol interfaces for the PXE DHCP device.
//
Status = gBS->InstallProtocolInterface (
&ControllerHandle,
&gEfiPxeDhcp4ProtocolGuid,
EFI_NATIVE_INTERFACE,
&Private->PxeDhcp4
);
if (!EFI_ERROR (Status)) {
return Status;
}
error_exit: ;
gBS->CloseProtocol (
ControllerHandle,
&gEfiPxeBaseCodeProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return Status;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
Stop this driver on ControllerHandle by removing PXE DHCP
protocol and closing the PXE Base Code protocol on
ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to stop driver on.
@param NumberOfChildren Not used.
@param ChildHandleBuffer Not used.
@retval EFI_SUCCESS This driver is removed ControllerHandle.
@retval other This driver was not removed from this device.
**/
EFI_STATUS
EFIAPI
PxeDhcp4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
EFI_PXE_DHCP4_PROTOCOL *PxeDhcp4;
PXE_DHCP4_PRIVATE_DATA *Private;
//
// Get our context back.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiPxeDhcp4ProtocolGuid,
(VOID **) &PxeDhcp4,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (PxeDhcp4);
//
// Release allocated resources
//
if (Private->PxeDhcp4.Data) {
FreePool (Private->PxeDhcp4.Data);
Private->PxeDhcp4.Data = NULL;
}
//
// Uninstall our protocol
//
Status = gBS->UninstallProtocolInterface (
ControllerHandle,
&gEfiPxeDhcp4ProtocolGuid,
&Private->PxeDhcp4
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Close any consumed protocols
//
Status = gBS->CloseProtocol (
ControllerHandle,
&gEfiPxeBaseCodeProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Release our private data
//
FreePool (Private);
return Status;
}
/* EOF - PxeDhcp4.c */

View File

@ -0,0 +1,353 @@
/** @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
#include <PiDxe.h>
#include <Protocol/PxeBaseCode.h>
#include <Protocol/SimpleNetwork.h>
#include <Protocol/PxeDhcp4.h>
#include <Protocol/PxeDhcp4Callback.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#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 */

View File

@ -0,0 +1,64 @@
#/** @file
# Component name for module PxeDhcp4
#
# 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.
#
#
#**/
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = PxeDhcp4Dxe
FILE_GUID = a46c3330-be36-4977-9d24-a7cf92eef0fe
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = PxeDhcp4DriverEntryPoint
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources.common]
support.c
PxeDhcp4Release.c
PxeDhcp4Setup.c
ComponentName.c
PxeDhcp4RenewRebind.c
PxeDhcp4.h
PxeDhcp4.c
PxeDhcp4InitSelect.c
PxeDhcp4Run.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiLib
UefiBootServicesTableLib
UefiDriverEntryPoint
BaseMemoryLib
DebugLib
[Protocols]
gEfiPxeBaseCodeProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiPxeDhcp4CallbackProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiPxeDhcp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED

View File

@ -0,0 +1,78 @@
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>PxeDhcp4</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>a46c3330-be36-4977-9d24-a7cf92eef0fe</GuidValue>
<Version>1.0</Version>
<Abstract>Component name for module PxeDhcp4</Abstract>
<Description>FIX ME!</Description>
<Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
<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>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>PxeDhcp4</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseMemoryLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>PxeDhcp4Run.c</Filename>
<Filename>PxeDhcp4InitSelect.c</Filename>
<Filename>PxeDhcp4Entry.c</Filename>
<Filename>PxeDhcp4.c</Filename>
<Filename>PxeDhcp4.h</Filename>
<Filename>PxeDhcp4RenewRebind.c</Filename>
<Filename>ComponentName.c</Filename>
<Filename>PxeDhcp4Setup.c</Filename>
<Filename>PxeDhcp4Release.c</Filename>
<Filename>support.c</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiPxeDhcp4ProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiPxeDhcp4CallbackProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiPxeBaseCodeProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>PxeDhcp4DriverEntryPoint</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

View File

@ -0,0 +1,784 @@
/** @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:
PxeDhcp4InitSelect.c
Abstract:
**/
#include "PxeDhcp4.h"
#define DebugPrint(x)
//
// #define DebugPrint(x) Aprint x
//
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
**/
STATIC
INTN
offer_verify (
IN PXE_DHCP4_PRIVATE_DATA *Private,
IN DHCP4_PACKET *tx_pkt,
IN DHCP4_PACKET *rx_pkt,
IN UINTN rx_pkt_size
)
{
EFI_STATUS EfiStatus;
DHCP4_PACKET *tmp;
DHCP4_OP *msg_type_op;
DHCP4_OP *srvid_op;
UINT32 magik;
//
// Verify parameters. Touch unused parameters to keep
// compiler happy.
//
ASSERT (Private);
ASSERT (rx_pkt);
if (Private == NULL || rx_pkt == NULL) {
return -2;
}
tx_pkt = tx_pkt;
rx_pkt_size = rx_pkt_size;
//
// This may be a BOOTP Reply or DHCP Offer packet.
// If there is no DHCP magik number, assume that
// this is a BOOTP Reply packet.
//
magik = htonl (DHCP4_MAGIK_NUMBER);
while (!CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {
//
// If there is no DHCP message type option, assume
// this is a BOOTP reply packet and cache it.
//
EfiStatus = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);
if (EFI_ERROR (EfiStatus)) {
break;
}
//
// If there is a DHCP message type option, it must be a
// DHCP offer packet
//
if (msg_type_op->len != 1) {
return -1;
}
if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) {
return -1;
}
//
// There must be a server identifier option.
//
EfiStatus = find_opt (
rx_pkt,
DHCP4_SERVER_IDENTIFIER,
0,
&srvid_op
);
if (EFI_ERROR (EfiStatus)) {
return -1;
}
if (srvid_op->len != 4) {
return -1;
}
//
// Good DHCP offer packet.
//
break;
}
//
// Good DHCP (or BOOTP) packet. Cache it!
//
EfiStatus = gBS->AllocatePool (
EfiBootServicesData,
(Private->offers + 1) * sizeof (DHCP4_PACKET),
(VOID **) &tmp
);
if (EFI_ERROR (EfiStatus)) {
return -2;
}
ASSERT (tmp);
if (Private->offers != 0) {
CopyMem (
tmp,
Private->offer_list,
Private->offers * sizeof (DHCP4_PACKET)
);
gBS->FreePool (Private->offer_list);
}
CopyMem (&tmp[Private->offers++], rx_pkt, sizeof (DHCP4_PACKET));
Private->offer_list = tmp;
return 0;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
**/
STATIC
INTN
acknak_verify (
IN PXE_DHCP4_PRIVATE_DATA *Private,
IN DHCP4_PACKET *tx_pkt,
IN DHCP4_PACKET *rx_pkt,
IN UINTN rx_pkt_size
)
{
EFI_STATUS EfiStatus;
DHCP4_OP *msg_type_op;
DHCP4_OP *srvid_op;
DHCP4_OP *renew_op;
DHCP4_OP *rebind_op;
DHCP4_OP *lease_time_op;
UINT32 magik;
//
// Verify parameters. Touch unused parameters to
// keep compiler happy.
//
ASSERT (Private);
ASSERT (rx_pkt);
if (Private == NULL || rx_pkt == NULL) {
return -2;
}
tx_pkt = tx_pkt;
rx_pkt_size = rx_pkt_size;
//
// This must be a DHCP Ack message.
//
magik = htonl (DHCP4_MAGIK_NUMBER);
if (CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {
return -1;
}
EfiStatus = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);
if (EFI_ERROR (EfiStatus)) {
return -1;
}
if (msg_type_op->len != 1) {
return -1;
}
if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_ACK) {
return -1;
}
//
// There must be a server identifier.
//
EfiStatus = find_opt (rx_pkt, DHCP4_SERVER_IDENTIFIER, 0, &srvid_op);
if (EFI_ERROR (EfiStatus)) {
return -1;
}
if (srvid_op->len != 4) {
return -1;
}
//
// There should be a renewal time.
// If there is not, we will default to the 7/8 of the rebinding time.
//
EfiStatus = find_opt (rx_pkt, DHCP4_RENEWAL_TIME, 0, &renew_op);
if (EFI_ERROR (EfiStatus)) {
renew_op = NULL;
} else if (renew_op->len != 4) {
renew_op = NULL;
}
//
// There should be a rebinding time.
// If there is not, we will default to 7/8 of the lease time.
//
EfiStatus = find_opt (rx_pkt, DHCP4_REBINDING_TIME, 0, &rebind_op);
if (EFI_ERROR (EfiStatus)) {
rebind_op = NULL;
} else if (rebind_op->len != 4) {
rebind_op = NULL;
}
//
// There should be a lease time.
// If there is not, we will default to one week.
//
EfiStatus = find_opt (rx_pkt, DHCP4_LEASE_TIME, 0, &lease_time_op);
if (EFI_ERROR (EfiStatus)) {
lease_time_op = NULL;
} else if (lease_time_op->len != 4) {
lease_time_op = NULL;
}
//
// Packet looks good. Double check the renew, rebind and lease times.
//
CopyMem (&Private->ServerIp, srvid_op->data, 4);
if (renew_op != NULL) {
CopyMem (&Private->RenewTime, renew_op->data, 4);
Private->RenewTime = htonl (Private->RenewTime);
} else {
Private->RenewTime = 0;
}
if (rebind_op != NULL) {
CopyMem (&Private->RebindTime, rebind_op->data, 4);
Private->RebindTime = htonl (Private->RebindTime);
} else {
Private->RebindTime = 0;
}
if (lease_time_op != NULL) {
CopyMem (&Private->LeaseTime, lease_time_op->data, 4);
Private->LeaseTime = htonl (Private->LeaseTime);
} else {
Private->LeaseTime = 0;
}
if (Private->LeaseTime < 60) {
Private->LeaseTime = 7 * 86400;
}
if (Private->RebindTime < 52 || Private->RebindTime >= Private->LeaseTime) {
Private->RebindTime = Private->LeaseTime / 2 + Private->LeaseTime / 4 + Private->LeaseTime / 8;
}
if (Private->RenewTime < 45 || Private->RenewTime >= Private->RebindTime) {
Private->RenewTime = Private->RebindTime / 2 + Private->RebindTime / 4 + Private->RebindTime / 8;
}
return 1;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
EFIAPI
PxeDhcp4Init (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN UINTN seconds_timeout,
OUT UINTN *Offers,
OUT DHCP4_PACKET **OfferList
)
{
PXE_DHCP4_PRIVATE_DATA *Private;
DHCP4_PACKET offer;
EFI_IP_ADDRESS bcast_ip;
EFI_STATUS EfiStatus;
//
// Verify parameters and protocol state.
//
if (This == NULL ||
seconds_timeout < DHCP4_MIN_SECONDS ||
seconds_timeout > DHCP4_MAX_SECONDS ||
Offers == NULL ||
OfferList == NULL
) {
//
// Return parameters are not initialized when
// parameters are invalid!
//
return EFI_INVALID_PARAMETER;
}
*Offers = 0;
*OfferList = NULL;
//
// Check protocol state.
//
if (This->Data == NULL) {
return EFI_NOT_STARTED;
}
if (!This->Data->SetupCompleted) {
return EFI_NOT_READY;
}
#if 0
if (!is_good_discover (&This->Data->Discover)) {
//
// %%TBD - check discover packet fields
//
}
#endif
//
// Get pointer to our instance data.
//
Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
if (Private == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Private->PxeBc == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Setup variables...
//
Private->offers = 0;
Private->offer_list = NULL;
EfiStatus = gBS->HandleProtocol (
Private->Handle,
&gEfiPxeDhcp4CallbackProtocolGuid,
(VOID *) &Private->callback
);
if (EFI_ERROR (EfiStatus)) {
Private->callback = NULL;
}
Private->function = EFI_PXE_DHCP4_FUNCTION_INIT;
//
// Increment the transaction ID.
//
{
UINT32 xid;
CopyMem (&xid, &This->Data->Discover.dhcp4.xid, sizeof (UINT32));
xid = htonl (htonl (xid) + 1);
CopyMem (&This->Data->Discover.dhcp4.xid, &xid, sizeof (UINT32));
}
//
// Transmit discover and wait for offers...
//
SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
EfiStatus = tx_rx_udp (
Private,
&bcast_ip,
NULL,
NULL,
NULL,
&This->Data->Discover,
&offer,
&offer_verify,
seconds_timeout
);
if (EFI_ERROR (EfiStatus)) {
if (Private->offer_list) {
gBS->FreePool (Private->offer_list);
}
Private->offers = 0;
Private->offer_list = NULL;
Private->callback = NULL;
DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
return EfiStatus;
}
*Offers = Private->offers;
*OfferList = Private->offer_list;
Private->offers = 0;
Private->offer_list = NULL;
Private->callback = NULL;
This->Data->InitCompleted = TRUE;
This->Data->SelectCompleted = FALSE;
This->Data->IsBootp = FALSE;
This->Data->IsAck = FALSE;
return EFI_SUCCESS;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
EFIAPI
PxeDhcp4Select (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN UINTN seconds_timeout,
IN DHCP4_PACKET *Offer
)
{
PXE_DHCP4_PRIVATE_DATA *Private;
EFI_STATUS EfiStatus;
DHCP4_PACKET request;
DHCP4_PACKET acknak;
EFI_IP_ADDRESS bcast_ip;
EFI_IP_ADDRESS zero_ip;
EFI_IP_ADDRESS local_ip;
DHCP4_OP *srvid;
DHCP4_OP *op;
UINT32 dhcp4_magik;
UINT8 buf[16];
BOOLEAN is_bootp;
//
// Verify parameters.
//
if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS || Offer == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check protocol state.
//
if (This->Data == NULL) {
return EFI_NOT_STARTED;
}
if (!This->Data->SetupCompleted) {
return EFI_NOT_READY;
}
//
// Get pointer to instance data.
//
Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
if (Private == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Private->PxeBc == NULL) {
return EFI_DEVICE_ERROR;
}
#if 0
if (!is_good_discover (&This->Data->Discover)) {
//
// %%TBD - check discover packet fields
//
}
#endif
//
// Setup useful variables...
//
SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));
ZeroMem (&local_ip, sizeof (EFI_IP_ADDRESS));
local_ip.v4.Addr[0] = 127;
local_ip.v4.Addr[3] = 1;
This->Data->SelectCompleted = FALSE;
This->Data->IsBootp = FALSE;
This->Data->IsAck = FALSE;
EfiStatus = gBS->HandleProtocol (
Private->Handle,
&gEfiPxeDhcp4CallbackProtocolGuid,
(VOID *) &Private->callback
);
if (EFI_ERROR (EfiStatus)) {
Private->callback = NULL;
}
Private->function = EFI_PXE_DHCP4_FUNCTION_SELECT;
//
// Verify offer packet fields.
//
if (Offer->dhcp4.op != BOOTP_REPLY) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
if (Offer->dhcp4.htype != This->Data->Discover.dhcp4.htype) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
if (Offer->dhcp4.hlen != This->Data->Discover.dhcp4.hlen) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
if (CompareMem (&Offer->dhcp4.xid, &This->Data->Discover.dhcp4.xid, 4)) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
if (!CompareMem (&Offer->dhcp4.yiaddr, &bcast_ip, 4)) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
if (!CompareMem (&Offer->dhcp4.yiaddr, &zero_ip, 4)) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
if (!CompareMem (&Offer->dhcp4.yiaddr, &local_ip, 4)) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
if (CompareMem (
&Offer->dhcp4.chaddr,
&This->Data->Discover.dhcp4.chaddr,
16
)) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
//
// DHCP option checks
//
dhcp4_magik = htonl (DHCP4_MAGIK_NUMBER);
is_bootp = TRUE;
if (!CompareMem (&Offer->dhcp4.magik, &dhcp4_magik, 4)) {
//
// If present, DHCP message type must be offer.
//
EfiStatus = find_opt (Offer, DHCP4_MESSAGE_TYPE, 0, &op);
if (!EFI_ERROR (EfiStatus)) {
if (op->len != 1 || op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
is_bootp = FALSE;
}
//
// If present, DHCP max message size must be valid.
//
EfiStatus = find_opt (Offer, DHCP4_MAX_MESSAGE_SIZE, 0, &op);
if (!EFI_ERROR (EfiStatus)) {
if (op->len != 2 || ((op->data[0] << 8) | op->data[1]) < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
}
//
// If present, DHCP server identifier must be valid.
//
EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &op);
if (!EFI_ERROR (EfiStatus)) {
if (op->len != 4 || !CompareMem (op->data, &bcast_ip, 4) || !CompareMem (op->data, &zero_ip, 4)) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
}
//
// If present, DHCP subnet mask must be valid.
//
EfiStatus = find_opt (
Offer,
DHCP4_SUBNET_MASK,
0,
&op
);
if (!EFI_ERROR (EfiStatus)) {
if (op->len != 4) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
}
}
//
// Early out for BOOTP.
//
This->Data->IsBootp = is_bootp;
if (is_bootp) {
//
// Copy offer packet to instance data.
//
CopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET));
//
// Copy discover to request and offer to acknak.
//
CopyMem (
&This->Data->Request,
&This->Data->Discover,
sizeof (DHCP4_PACKET)
);
CopyMem (
&This->Data->AckNak,
&This->Data->Offer,
sizeof (DHCP4_PACKET)
);
//
// Set state flags.
//
This->Data->SelectCompleted = TRUE;
This->Data->IsAck = TRUE;
Private->callback = NULL;
return EFI_SUCCESS;
}
//
// Copy discover packet contents to request packet.
//
CopyMem (&request, &This->Data->Discover, sizeof (DHCP4_PACKET));
This->Data->IsAck = FALSE;
//
// Change DHCP message type from discover to request.
//
EfiStatus = find_opt (&request, DHCP4_MESSAGE_TYPE, 0, &op);
if (EFI_ERROR (EfiStatus) && EfiStatus != EFI_NOT_FOUND) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
if (EfiStatus == EFI_NOT_FOUND) {
EfiStatus = find_opt (&request, DHCP4_END, 0, &op);
if (EFI_ERROR (EfiStatus)) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
op->op = DHCP4_MESSAGE_TYPE;
op->len = 1;
op->data[1] = DHCP4_END;
}
op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST;
//
// Copy server identifier option from offer to request.
//
EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &srvid);
if (EFI_ERROR (EfiStatus)) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
if (srvid->len != 4) {
Private->callback = NULL;
return EFI_INVALID_PARAMETER;
}
EfiStatus = add_opt (&request, srvid);
if (EFI_ERROR (EfiStatus)) {
DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
Private->callback = NULL;
return EfiStatus;
}
//
// Add requested IP address option to request packet.
//
op = (DHCP4_OP *) buf;
op->op = DHCP4_REQUESTED_IP_ADDRESS;
op->len = 4;
CopyMem (op->data, &Offer->dhcp4.yiaddr, 4);
EfiStatus = add_opt (&request, op);
if (EFI_ERROR (EfiStatus)) {
DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
Private->callback = NULL;
return EfiStatus;
}
//
// Transimit DHCP request and wait for DHCP ack...
//
SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
EfiStatus = tx_rx_udp (
Private,
&bcast_ip,
NULL,
NULL,
NULL,
&request,
&acknak,
&acknak_verify,
seconds_timeout
);
if (EFI_ERROR (EfiStatus)) {
DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
Private->callback = NULL;
return EfiStatus;
}
//
// Set Data->IsAck and return.
//
EfiStatus = find_opt (&acknak, DHCP4_MESSAGE_TYPE, 0, &op);
if (EFI_ERROR (EfiStatus)) {
Private->callback = NULL;
return EFI_DEVICE_ERROR;
}
if (op->len != 1) {
Private->callback = NULL;
return EFI_DEVICE_ERROR;
}
switch (op->data[0]) {
case DHCP4_MESSAGE_TYPE_ACK:
This->Data->IsAck = TRUE;
break;
case DHCP4_MESSAGE_TYPE_NAK:
This->Data->IsAck = FALSE;
break;
default:
Private->callback = NULL;
return EFI_DEVICE_ERROR;
}
//
// Copy packets into instance data...
//
CopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET));
CopyMem (&This->Data->Request, &request, sizeof (DHCP4_PACKET));
CopyMem (&This->Data->AckNak, &acknak, sizeof (DHCP4_PACKET));
This->Data->SelectCompleted = TRUE;
Private->callback = NULL;
return EFI_SUCCESS;
}
/* eof - PxeDhcp4InitSelect.c */

View File

@ -0,0 +1,247 @@
/** @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:
PxeDhcp4Release.c
Abstract:
Transmit release packet, free allocations and shutdown PxeDhcp4.
**/
#include "PxeDhcp4.h"
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
EFIAPI
PxeDhcp4Release (
IN EFI_PXE_DHCP4_PROTOCOL *This
)
{
PXE_DHCP4_PRIVATE_DATA *Private;
EFI_IP_ADDRESS ServerIp;
EFI_IP_ADDRESS client_ip;
EFI_IP_ADDRESS gateway_ip;
EFI_IP_ADDRESS subnet_mask;
EFI_STATUS efi_status;
DHCP4_OP *op;
UINT8 op_list[20];
//
// Check for invalid parameters.
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Release does nothing if the protocol has never been setup.
//
if (This->Data == NULL) {
return EFI_NOT_STARTED;
}
//
// Fail if we do not have valid instance data.
//
Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
if (Private == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Private->PxeBc == NULL) {
return EFI_DEVICE_ERROR;
}
//
// If this is a BOOTP session and there is not a DHCP Ack
// packet, just release storage and return.
//
if (This->Data->IsBootp || !This->Data->IsAck) {
gBS->FreePool (This->Data);
This->Data = NULL;
if (Private->StopPxeBc) {
Private->PxeBc->Stop (Private->PxeBc);
}
return EFI_SUCCESS;
}
//
// Build option list for DHCP Release packet.
// If any errors occur, just release storage and return.
//
//
// Message type is first.
//
op_list[0] = DHCP4_MESSAGE_TYPE;
op_list[1] = 1;
op_list[2] = DHCP4_MESSAGE_TYPE_RELEASE;
//
// Followed by server identifier.
//
efi_status = find_opt (
&This->Data->Request,
DHCP4_SERVER_IDENTIFIER,
0,
&op
);
if (EFI_ERROR (efi_status)) {
gBS->FreePool (This->Data);
This->Data = NULL;
if (Private->StopPxeBc) {
Private->PxeBc->Stop (Private->PxeBc);
}
return EFI_SUCCESS;
}
if (op->len != 4) {
gBS->FreePool (This->Data);
This->Data = NULL;
if (Private->StopPxeBc) {
Private->PxeBc->Stop (Private->PxeBc);
}
return EFI_SUCCESS;
}
CopyMem (&ServerIp, op->data, 4);
op_list[3] = DHCP4_SERVER_IDENTIFIER;
op_list[4] = 4;
CopyMem (&op_list[5], &ServerIp, 4);
//
// Followed by end.
//
op_list[9] = DHCP4_END;
//
// We need a subnet mask for IP stack operation.
//
efi_status = find_opt (
&This->Data->AckNak,
DHCP4_SUBNET_MASK,
0,
&op
);
if (EFI_ERROR (efi_status)) {
gBS->FreePool (This->Data);
This->Data = NULL;
if (Private->StopPxeBc) {
Private->PxeBc->Stop (Private->PxeBc);
}
return EFI_SUCCESS;
}
if (op->len != 4) {
gBS->FreePool (This->Data);
This->Data = NULL;
if (Private->StopPxeBc) {
Private->PxeBc->Stop (Private->PxeBc);
}
return EFI_SUCCESS;
}
ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS));
CopyMem (&subnet_mask, op->data, 4);
//
// Gateway IP address may be needed.
//
ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS));
CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4);
//
// Client IP address needed for IP stack operation.
//
ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS));
CopyMem (&client_ip, &This->Data->AckNak.dhcp4.yiaddr, 4);
//
// Enable UDP...
//
efi_status = start_udp (Private, &client_ip, &subnet_mask);
if (EFI_ERROR (efi_status)) {
gBS->FreePool (This->Data);
This->Data = NULL;
if (Private->StopPxeBc) {
Private->PxeBc->Stop (Private->PxeBc);
}
return efi_status;
}
//
// Gather information out of DHCP request packet needed for
// DHCP release packet.
//
//
// Setup DHCP Release packet.
//
CopyMem (&This->Data->Request.dhcp4.ciaddr, &client_ip, 4);
ZeroMem (&This->Data->Request.dhcp4.yiaddr, 12);
ZeroMem (&This->Data->Request.dhcp4.sname, 64 + 128);
This->Data->Request.dhcp4.hops = 0;
This->Data->Request.dhcp4.secs = 0;
This->Data->Request.dhcp4.flags = 0;
ZeroMem (
&This->Data->Request.dhcp4.options,
sizeof This->Data->Request.dhcp4.options
);
CopyMem (&This->Data->Request.dhcp4.options, op_list, 10);
//
// Transmit DHCP Release packet.
//
tx_udp (
Private,
&ServerIp,
&gateway_ip,
&client_ip,
&This->Data->Request,
DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE)
);
gBS->Stall (1000000); /* 1/10th second */
//
// Shutdown PXE BaseCode and release local storage.
//
stop_udp (Private);
gBS->FreePool (This->Data);
This->Data = NULL;
if (Private->StopPxeBc) {
Private->PxeBc->Stop (Private->PxeBc);
}
return EFI_SUCCESS;
}
/* eof - PxeDhcp4Release.c */

View File

@ -0,0 +1,408 @@
/** @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:
PxeDhcp4RenewRebind.c
Abstract:
**/
#include "PxeDhcp4.h"
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
Parameters:
@return -2 = ignore, stop waiting
@return -1 = ignore, keep waiting
@return 0 = accept, keep waiting
@return 1 = accept, stop waiting
**/
STATIC
INTN
acknak_verify (
IN PXE_DHCP4_PRIVATE_DATA *Private,
IN DHCP4_PACKET *tx_pkt,
IN DHCP4_PACKET *rx_pkt,
IN UINTN rx_pkt_size
)
{
EFI_STATUS efi_status;
DHCP4_OP *msg_type_op;
DHCP4_OP *srvid_op;
DHCP4_OP *renew_op;
DHCP4_OP *rebind_op;
DHCP4_OP *lease_time_op;
UINT32 magik;
//
// Verify parameters. Unused parameters are also touched
// to make the compiler happy.
//
ASSERT (Private);
ASSERT (rx_pkt);
if (Private == NULL || rx_pkt == NULL) {
return -2;
}
tx_pkt = tx_pkt;
rx_pkt_size = rx_pkt_size;
//
// This must be a DHCP Ack message.
//
magik = htonl (DHCP4_MAGIK_NUMBER);
if (CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {
return -1;
}
efi_status = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);
if (EFI_ERROR (efi_status)) {
return -1;
}
if (msg_type_op->len != 1) {
return -1;
}
if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_ACK) {
return -1;
}
//
// There must be a server identifier.
//
efi_status = find_opt (rx_pkt, DHCP4_SERVER_IDENTIFIER, 0, &srvid_op);
if (EFI_ERROR (efi_status)) {
return -1;
}
if (srvid_op->len != 4) {
return -1;
}
//
// There should be a renewal time.
// If there is not, we will default to the 7/8 of the rebinding time.
//
efi_status = find_opt (rx_pkt, DHCP4_RENEWAL_TIME, 0, &renew_op);
if (EFI_ERROR (efi_status)) {
renew_op = NULL;
} else if (renew_op->len != 4) {
renew_op = NULL;
}
//
// There should be a rebinding time.
// If there is not, we will default to 7/8 of the lease time.
//
efi_status = find_opt (rx_pkt, DHCP4_REBINDING_TIME, 0, &rebind_op);
if (EFI_ERROR (efi_status)) {
rebind_op = NULL;
} else if (rebind_op->len != 4) {
rebind_op = NULL;
}
//
// There should be a lease time.
// If there is not, we will default to one week.
//
efi_status = find_opt (rx_pkt, DHCP4_LEASE_TIME, 0, &lease_time_op);
if (EFI_ERROR (efi_status)) {
lease_time_op = NULL;
} else if (lease_time_op->len != 4) {
lease_time_op = NULL;
}
//
// Packet looks good. Double check the renew, rebind and lease times.
//
CopyMem (&Private->ServerIp, srvid_op->data, 4);
if (renew_op != NULL) {
CopyMem (&Private->RenewTime, renew_op->data, 4);
Private->RenewTime = htonl (Private->RenewTime);
} else {
Private->RenewTime = 0;
}
if (rebind_op != NULL) {
CopyMem (&Private->RebindTime, rebind_op->data, 4);
Private->RebindTime = htonl (Private->RebindTime);
} else {
Private->RebindTime = 0;
}
if (lease_time_op != NULL) {
CopyMem (&Private->LeaseTime, lease_time_op->data, 4);
Private->LeaseTime = htonl (Private->LeaseTime);
} else {
Private->LeaseTime = 0;
}
if (Private->LeaseTime < 60) {
Private->LeaseTime = 7 * 86400;
}
if (Private->RebindTime < 52 || Private->RebindTime >= Private->LeaseTime) {
Private->RebindTime = Private->LeaseTime / 2 + Private->LeaseTime / 4 + Private->LeaseTime / 8;
}
if (Private->RenewTime < 45 || Private->RenewTime >= Private->RebindTime) {
Private->RenewTime = Private->RebindTime / 2 + Private->RebindTime / 4 + Private->RebindTime / 8;
}
return 1;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
STATIC
EFI_STATUS
EFIAPI
renew_rebind (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN UINTN seconds_timeout,
IN BOOLEAN renew
)
{
PXE_DHCP4_PRIVATE_DATA *Private;
EFI_IP_ADDRESS ServerIp;
EFI_IP_ADDRESS client_ip;
EFI_IP_ADDRESS subnet_mask;
EFI_IP_ADDRESS gateway_ip;
DHCP4_PACKET Request;
DHCP4_PACKET AckNak;
DHCP4_OP *op;
EFI_STATUS efi_status;
//
// Check for invalid parameters.
//
if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS) {
return EFI_INVALID_PARAMETER;
}
//
// Check for proper protocol state.
//
if (This->Data == NULL) {
return EFI_NOT_STARTED;
}
if (!This->Data->SelectCompleted) {
return EFI_NOT_READY;
}
if (This->Data->IsBootp) {
return EFI_SUCCESS;
}
if (!This->Data->IsAck) {
return EFI_INVALID_PARAMETER;
}
//
// Get pointer to instance data.
//
Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
if (Private == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Private->PxeBc == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Copy Discover packet to temporary request packet
// to be used for Renew/Rebind operation.
//
CopyMem (&Request, &This->Data->Discover, sizeof (DHCP4_PACKET));
CopyMem (&Request.dhcp4.ciaddr, &This->Data->AckNak.dhcp4.yiaddr, 4);
Request.dhcp4.flags = 0; /* Reply does not need to be broadcast. */
//
// Change message type from discover to request.
//
efi_status = find_opt (&Request, DHCP4_MESSAGE_TYPE, 0, &op);
if (EFI_ERROR (efi_status)) {
return EFI_INVALID_PARAMETER;
}
if (op->len != 1) {
return EFI_INVALID_PARAMETER;
}
op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST;
//
// Need a subnet mask.
//
efi_status = find_opt (
&This->Data->AckNak,
DHCP4_SUBNET_MASK,
0,
&op
);
if (EFI_ERROR (efi_status)) {
return EFI_INVALID_PARAMETER;
}
if (op->len != 4) {
return EFI_INVALID_PARAMETER;
}
ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS));
CopyMem (&subnet_mask, op->data, 4);
//
// Need a server IP address (renew) or a broadcast
// IP address (rebind).
//
ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS));
if (renew) {
efi_status = find_opt (
&This->Data->AckNak,
DHCP4_SERVER_IDENTIFIER,
0,
&op
);
if (EFI_ERROR (efi_status)) {
return EFI_INVALID_PARAMETER;
}
if (op->len != 4) {
return EFI_INVALID_PARAMETER;
}
ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
CopyMem (&ServerIp, op->data, 4);
//
//
//
if (CompareMem (&This->Data->AckNak.dhcp4.giaddr, &gateway_ip, 4)) {
CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4);
}
} else {
SetMem (&ServerIp, sizeof (EFI_IP_ADDRESS), 0xFF);
}
//
// Need a client IP address.
//
ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS));
CopyMem (&client_ip, &Request.dhcp4.ciaddr, 4);
//
//
//
efi_status = gBS->HandleProtocol (
Private->Handle,
&gEfiPxeDhcp4CallbackProtocolGuid,
(VOID *) &Private->callback
);
if (EFI_ERROR (efi_status)) {
Private->callback = NULL;
}
Private->function = renew ? EFI_PXE_DHCP4_FUNCTION_RENEW : EFI_PXE_DHCP4_FUNCTION_REBIND;
//
// Transimit DHCP request and wait for DHCP ack...
//
efi_status = tx_rx_udp (
Private,
&ServerIp,
&gateway_ip,
&client_ip,
&subnet_mask,
&Request,
&AckNak,
&acknak_verify,
seconds_timeout
);
if (EFI_ERROR (efi_status)) {
Private->callback = NULL;
return efi_status;
}
//
// Copy server identifier, renewal time and rebinding time
// from temporary ack/nak packet into cached ack/nak packet.
//
efi_status = find_opt (
&This->Data->AckNak,
DHCP4_SERVER_IDENTIFIER,
0,
&op
);
if (!EFI_ERROR (efi_status)) {
if (op->len == 4) {
CopyMem (op->data, &Private->ServerIp, 4);
}
}
efi_status = find_opt (&This->Data->AckNak, DHCP4_RENEWAL_TIME, 0, &op);
if (!EFI_ERROR (efi_status)) {
if (op->len == 4) {
CopyMem (op->data, &Private->RenewTime, 4);
}
}
efi_status = find_opt (&This->Data->AckNak, DHCP4_REBINDING_TIME, 0, &op);
if (!EFI_ERROR (efi_status)) {
if (op->len == 4) {
CopyMem (op->data, &Private->RebindTime, 4);
}
}
Private->callback = NULL;
return efi_status;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
EFIAPI
PxeDhcp4Renew (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN UINTN seconds_timeout
)
{
return renew_rebind (This, seconds_timeout, TRUE);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
EFIAPI
PxeDhcp4Rebind (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN UINTN seconds_timeout
)
{
return renew_rebind (This, seconds_timeout, FALSE);
}
/* eof - PxeDhcp4RenewRebind.c */

View File

@ -0,0 +1,191 @@
/** @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:
PxeDhcp4Run.c
Abstract:
Simplified entry point for starting basic PxeDhcp4 client operation.
**/
#include "PxeDhcp4.h"
EFI_STATUS
EFIAPI
PxeDhcp4Run (
IN EFI_PXE_DHCP4_PROTOCOL *This,
IN OPTIONAL UINTN OpLen,
IN OPTIONAL VOID *OpList
)
{
PXE_DHCP4_PRIVATE_DATA *Private;
DHCP4_PACKET *offer_list;
EFI_STATUS efi_status;
EFI_IP_ADDRESS zero_ip;
UINTN offers;
UINTN timeout;
UINTN n;
UINT16 seconds;
//
// Validate parameters.
//
if (This == NULL || (OpLen != 0 && OpList == NULL) || (OpLen == 0 && OpList != NULL)) {
return EFI_INVALID_PARAMETER;
}
for (n = 0; n < OpLen;) {
switch (((UINT8 *) OpList)[n]) {
case DHCP4_PAD:
++n;
continue;
case DHCP4_END:
++n;
break;
default:
n += 2 + ((UINT8 *) OpList)[n + 1];
continue;
}
break;
}
if (n != OpLen) {
return EFI_INVALID_PARAMETER;
}
//
// Get pointer to instance data.
//
Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
if (Private == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Private->PxeBc == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Initialize DHCP discover packet.
//
efi_status = PxeDhcp4Setup (This, NULL);
if (EFI_ERROR (efi_status)) {
return efi_status;
}
for (n = 0; n < OpLen;) {
switch (((UINT8 *) OpList)[n]) {
case DHCP4_PAD:
++n;
continue;
case DHCP4_END:
++n;
break;
default:
efi_status = add_opt (
&This->Data->Discover,
(DHCP4_OP *) &(((UINT8 *) OpList)[n])
);
if (EFI_ERROR (efi_status)) {
return efi_status;
}
n += 2 + ((UINT8 *) OpList)[n + 1];
continue;
}
break;
}
//
// Basic DHCP D.O.R.A.
// 1, 2, 4, 8, 16 & 32 second timeouts.
// Callback routine can be used to break out earlier.
//
ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));
for (timeout = 1;;) {
//
// Broadcast DHCP discover and wait for DHCP offers.
//
efi_status = PxeDhcp4Init (This, timeout, &offers, &offer_list);
if ((efi_status != EFI_SUCCESS) &&
(efi_status != EFI_TIMEOUT) &&
(efi_status != EFI_NO_RESPONSE)) {
return efi_status;
}
//
// Try to select from each DHCP or BOOTP offer.
//
for (n = 0; n < offers; ++n) {
//
// Ignore proxyDHCP offers.
//
if (!CompareMem (&offer_list[n].dhcp4.yiaddr, &zero_ip, 4)) {
continue;
}
//
// Issue DHCP Request and wait for DHCP Ack/Nak.
//
efi_status = PxeDhcp4Select (
This,
timeout,
&offer_list[n]
);
if (EFI_ERROR (efi_status)) {
continue;
}
//
// Exit when we have got our DHCP Ack.
//
if (This->Data->IsAck) {
return EFI_SUCCESS;
}
}
//
// No DHCP Acks. Release DHCP Offer list storage.
//
if (offer_list != NULL) {
gBS->FreePool (offer_list);
offer_list = NULL;
}
//
// Try again until we have used up >= DHCP4_MAX_SECONDS.
//
if ((timeout <<= 1) > DHCP4_MAX_SECONDS) {
if (!EFI_ERROR (efi_status)) {
efi_status = EFI_TIMEOUT;
}
return efi_status;
}
//
// Next timeout value.
//
CopyMem (&seconds, &This->Data->Discover.dhcp4.secs, 2);
seconds = htons (htons (seconds) + timeout);
CopyMem (&This->Data->Discover.dhcp4.secs, &seconds, 2);
}
}
/* eof - PxeDhcp4Run.c */

Some files were not shown because too many files have changed in this diff Show More