#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; }