Cada camada só conversa com a camada equivalente do outro lado e só liga pro próprio header. O TCP não sabe se vai por WiFi ou fibra; o IP não sabe se é HTTP ou e-mail. Esse desacoplamento é o que deixou a internet evoluir em pedaços (dá pra trocar o enlace sem mexer no transporte).
Em Go, as camadas ficam escondidas
// Você escreve no topo (Aplicação).
// O SO cuida de TCP, IP e Ethernet por baixo.
conn, _ := net.Dial("tcp", "exemplo.com:80")
// ^transporte ^rede(DNS+IP) ^porta
conn.Write([]byte("GET / HTTP/1.1\r\n\r\n"))
// 1 Write seu vira 1 segmento TCP + 1 pacote IP + 1 frame.
O que cada protocolo carrega no header
// TCP: portas origem/destino, seq, ack, flags
// IP: IP origem/destino, TTL, protocolo
// Eth: MAC origem/destino, + checksum no trailer