#define ICMP_TYPE_ECHO_REPLY	0
#define ICMP_TYPE_ECHO_REQUEST	8
#define ICMP_CODE_ECHO			0 // RFC 792: "Echo or Echo Reply Message". 0 is the only code explicitly defined for Echo.

class CICMPHeader
{
	U8	type;
	U8	code;
	U16 checksum;

	U16 identifier;
	U16 sequence_number;
};


U0 ICMPReplySend(U32 destination_ip_address,
				  U16 identifier,
				  U16 sequence_number,
				  U16 request_checksum,
				  U8 *payload,
				  I64 length)
{
	U8			*icmp_frame;
	I64			 de_index;
	CICMPHeader	*header;

	de_index = IPV4PacketAllocate(&icmp_frame,
								  IP_PROTOCOL_ICMP,
								  IPV4AddressGet,
								  destination_ip_address,
								  sizeof(CICMPHeader) + length);
	if (de_index < 0)
	{
		NetErr("ICMP SEND REPLY: Failed to allocate IPV4 packet.");
		return;
	}

	header = icmp_frame;

	header->type				= ICMP_TYPE_ECHO_REPLY;
	header->code				= 0;	// why is 0 okay?
	header->checksum			= EndianU16(EndianU16(request_checksum) + 0x0800);
	header->identifier			= identifier;
	header->sequence_number		= sequence_number;
	// TODO: header checksum is awful. Shrine says hack alert.

	MemCopy(icmp_frame + sizeof(CICMPHeader), payload, length);

	IPV4PacketFinish(de_index);
}

I64 ICMPHandler(CIPV4Packet *packet)
{
	CICMPHeader *header;

	if (packet->length < sizeof(CICMPHeader))
	{
		NetErr("ICMP HANDLER: Caught wrong IPV4 length.");
		return -1;
	}

	header = packet->data;

	if (header->type == ICMP_TYPE_ECHO_REQUEST && header->code == ICMP_CODE_ECHO)
	{
		ARPCachePut(packet->source_ip_address, packet->ethernet_frame->source_address);

		ICMPReplySend(packet->source_ip_address,
					  header->identifier,
					  header->sequence_number,
					  header->checksum,
					  packet->data   + sizeof(CICMPHeader),	// Data payload at IPV4Packet data location after the ICMP header
					  packet->length - sizeof(CICMPHeader));// Payload length is size of packet after dropping header.
	}
	else
		NetWarn("ICMP HANDLER: Unhandled ICMP packet. type, code: 0x%X, 0x%X", header->type, header->code);

	NetLog("ICMP HANDLER: Exiting.");

	return 0;
}