The Ethernet frame format contains a critical 2-byte field that can serve dual purposes:
+-------------------+-------------------+-------------------+ | Destination MAC | Source MAC | Type/Length | | (6 bytes) | (6 bytes) | (2 bytes) | +-------------------+-------------------+-------------------+
This field operates differently based on its value:
- If value ≤ 1500 (0x05DC): Indicates payload length (IEEE 802.3 standard)
- If value ≥ 1536 (0x0600): Indicates EtherType (Ethernet II frame)
Here's how network interfaces determine frame length:
// Pseudo-code for frame length determination if (type_length_field <= 1500) { // IEEE 802.3 frame with explicit length frame_length = 14 + type_length_field + 4; // Header + data + FCS } else { // Ethernet II frame - must parse payload switch(type_length_field) { case 0x0800: // IPv4 frame_length = 14 + parse_ipv4_length(payload) + 4; break; case 0x86DD: // IPv6 frame_length = 14 + parse_ipv6_length(payload) + 4; break; // Other EtherType cases... } }
When dealing with IPv4 payloads (EtherType 0x0800), the length is determined from the IP header:
// C code example for parsing IPv4 length struct ip_header { uint8_t version_ihl; uint8_t dscp_ecn; uint16_t total_length; // ... other IP header fields }; uint16_t get_ethernet_frame_length(const uint8_t *frame) { uint16_t type_length = ntohs(*(uint16_t*)(frame + 12)); if (type_length <= 1500) { return 14 + type_length + 4; } else if (type_length == 0x0800) { struct ip_header *ip = (struct ip_header*)(frame + 14); return 14 + ntohs(ip->total_length) + 4; } // Additional cases for other protocols return 0; }
Modern networks often include VLAN tags which add complexity:
// Modified length calculation with VLAN support uint16_t get_ethernet_frame_length_with_vlan(const uint8_t *frame) { uint16_t type_length = ntohs(*(uint16_t*)(frame + 12)); if (type_length == 0x8100) { // VLAN tag present uint16_t inner_type = ntohs(*(uint16_t*)(frame + 16)); if (inner_type <= 1500) { return 18 + inner_type + 4; // 18 = 14 + 4 (VLAN tag) } // Handle other inner types... } // Original logic for non-VLAN frames return get_ethernet_frame_length(frame); }
Modern network interface cards implement this parsing logic in hardware:
- Early demultiplexing optimizes packet processing
- DMA engines use frame length to determine transfer size
- Checksum validation requires accurate length information
The Ethernet frame structure contains a critical 2-byte field at offset 12-13 in the header that serves dual purposes. This field can represent either:
- The total length of the payload (when value ≤ 1500 bytes)
- The EtherType protocol identifier (when value ≥ 1536)
// Example frame header structure
struct ethernet_header {
uint8_t dest_mac[6];
uint8_t src_mac[6];
uint16_t type_length;
// Followed by payload and FCS
};
The receiving NIC implements this decision logic:
bool is_length_field(uint16_t type_length) {
return type_length <= 1500; // IEEE 802.3 maximum frame size
}
bool is_ethertype(uint16_t type_length) {
return type_length >= 1536; // Starts at 0x0600
}
When the field indicates length:
frame_size = 14 (header) + length + 4 (FCS)
When the field indicates EtherType (e.g., IPv4/IPv6):
// For IPv4
struct ip_header {
uint8_t version_ihl;
// ... other fields ...
uint16_t total_length;
};
void parse_ethernet_frame(uint8_t* frame) {
if (ntohs(*(uint16_t*)(frame+12)) == 0x0800) {
uint16_t ip_length = ntohs(*(uint16_t*)(frame+16));
frame_size = 14 + ip_length + 4;
}
}
Modern network stacks handle this automatically, but understanding the mechanics is crucial for:
- Network protocol development
- Packet sniffing tools
- Custom NIC drivers
Examining a sample capture shows this behavior clearly:
Frame 1: 60 bytes on wire (480 bits)
Ethernet II, Src: 00:1a:2b:3c:4d:5e, Dst: 00:0d:0e:0f:10:11
Type: IPv4 (0x0800)
Internet Protocol Version 4, Src: 192.168.1.100, Dst: 8.8.8.8
Total Length: 46
Special scenarios to consider:
- Jumbo frames (length > 1500)
- VLAN tagged frames (additional 4-byte header)
- Malformed packets with length/type conflicts