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