From a9e2e535e1900ac887517b125b48994fe76e88e9 Mon Sep 17 00:00:00 2001
From: Michael Tuexen <tuexen@fh-muenster.de>
Date: Tue, 23 Dec 2014 19:09:12 +0100
Subject: [PATCH] Fix alignment of headers in the packet buffer

This patch makes sure that all heaaders start at a four byte
boundary. This is done by not having the ethernet header, which
is 14 bytes long, in the packet buffer.
This fixes the remote mode for platforms having strict alignment
restrictions, like ARM. Without this patch you can't use the remote
mode on a Rasperry Pi running FreeBSD.
This patch has been tested on Linux (Intel) in local and remote mode
and one FreeBSD (Intel and ARM) in local and remote mode.

Signed-off-by: Michael Tuexen <tuexen@fh-muenster.de>
---
 gtests/net/packetdrill/checksum.c             |  7 +--
 gtests/net/packetdrill/checksum_test.c        |  8 +--
 gtests/net/packetdrill/netdev.c               | 13 ++---
 gtests/net/packetdrill/netdev.h               |  1 -
 gtests/net/packetdrill/packet.c               |  4 +-
 gtests/net/packetdrill/packet.h               |  1 -
 gtests/net/packetdrill/packet_parser.c        | 35 ++----------
 gtests/net/packetdrill/packet_parser.h        |  8 +--
 gtests/net/packetdrill/packet_parser_test.c   | 17 +++---
 gtests/net/packetdrill/packet_socket.h        |  2 +-
 gtests/net/packetdrill/packet_socket_linux.c  | 52 +++++++++++++++---
 gtests/net/packetdrill/packet_socket_pcap.c   | 53 ++++++++++++++-----
 .../net/packetdrill/packet_to_string_test.c   | 10 ++--
 gtests/net/packetdrill/types.h                |  3 ++
 gtests/net/packetdrill/wire_server_netdev.c   |  5 +-
 15 files changed, 122 insertions(+), 97 deletions(-)

diff --git a/gtests/net/packetdrill/checksum.c b/gtests/net/packetdrill/checksum.c
index da19714f..b37dc00b 100644
--- a/gtests/net/packetdrill/checksum.c
+++ b/gtests/net/packetdrill/checksum.c
@@ -32,11 +32,8 @@
  */
 static u64 ip_checksum_partial(const void *p, size_t len, u64 sum)
 {
-	/* Main loop: 32 bits at a time.
-	 * We take advantage of intel's ability to do unaligned memory
-	 * accesses with minimal additional cost. Other architectures
-	 * probably want to be more careful here.
-	 */
+	assert(((uintptr_t)p & 0x03) == 0);
+	/* Main loop: 32 bits at a time. */
 	const u32 *p32 = (const u32 *)(p);
 	for (; len >= sizeof(*p32); len -= sizeof(*p32))
 		sum += *p32++;
diff --git a/gtests/net/packetdrill/checksum_test.c b/gtests/net/packetdrill/checksum_test.c
index e080163c..55ac51e2 100644
--- a/gtests/net/packetdrill/checksum_test.c
+++ b/gtests/net/packetdrill/checksum_test.c
@@ -33,7 +33,7 @@
 
 static void test_tcp_udp_v4_checksum(void)
 {
-	u8 data[] = {
+	u8 data[] __aligned(4) = {
 		0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
 		0xff, 0x06, 0xf9, 0x10, 0x01, 0x01, 0x01, 0x01,
 		0xc0, 0xa8, 0x00, 0x01, 0x04, 0xd2, 0xeb, 0x35,
@@ -64,7 +64,7 @@ static void test_tcp_udp_v4_checksum(void)
 
 static void test_tcp_udp_v6_checksum(void)
 {
-	u8 data[] = {
+	u8 data[] __aligned(4) = {
 		0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0xff,
 		0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
@@ -97,7 +97,7 @@ static void test_tcp_udp_v6_checksum(void)
 
 static void test_ipv4_checksum(void)
 {
-	u8 data[] = {
+	u8 data[] __aligned(4) = {
 		0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
 		0xff, 0x06, 0xf9, 0x10, 0x01, 0x01, 0x01, 0x01,
 		0xc0, 0xa8, 0x00, 0x01,
@@ -115,7 +115,7 @@ static void test_ipv4_checksum(void)
 
 static void test_sctp_crc32c(void)
 {
-	u8 data[] = {
+	u8 data[] __aligned(4) = {
 		0x07, 0xd0, 0xd6, 0x61, 0x11, 0x0c, 0xc5, 0x6c,
 		0xda, 0xd7, 0x37, 0x74, 0x06, 0x00, 0x00, 0x0f,
 		0x00, 0x0c, 0x00, 0x0b, 0x47, 0x6f, 0x6f, 0x64,
diff --git a/gtests/net/packetdrill/netdev.c b/gtests/net/packetdrill/netdev.c
index aeca2da0..c6e36fcb 100644
--- a/gtests/net/packetdrill/netdev.c
+++ b/gtests/net/packetdrill/netdev.c
@@ -399,20 +399,20 @@ static int local_netdev_receive(struct netdev *a_netdev,
 
 	DEBUGP("local_netdev_receive\n");
 
-	status = netdev_receive_loop(netdev->psock, PACKET_LAYER_3_IP,
-				     DIRECTION_OUTBOUND, packet, &num_packets,
-				     error);
+	status = netdev_receive_loop(netdev->psock, DIRECTION_OUTBOUND, packet,
+				     &num_packets, error);
 	local_netdev_read_queue(netdev, num_packets);
 	return status;
 }
 
 int netdev_receive_loop(struct packet_socket *psock,
-			enum packet_layer_t layer,
 			enum direction_t direction,
 			struct packet **packet,
 			int *num_packets,
 			char **error)
 {
+	u16 ether_type;
+
 	assert(*packet == NULL);	/* should be no packet yet */
 
 	*num_packets = 0;
@@ -423,11 +423,12 @@ int netdev_receive_loop(struct packet_socket *psock,
 		*packet = packet_new(PACKET_READ_BYTES);
 
 		/* Sniff the next outbound packet from the kernel under test. */
-		if (packet_socket_receive(psock, direction, *packet, &in_bytes))
+		if (packet_socket_receive(psock, direction, &ether_type,
+					  *packet, &in_bytes))
 			continue;
 
 		++*num_packets;
-		result = parse_packet(*packet, in_bytes, layer, error);
+		result = parse_packet(*packet, in_bytes, ether_type, error);
 
 		if (result == PACKET_OK)
 			return STATUS_OK;
diff --git a/gtests/net/packetdrill/netdev.h b/gtests/net/packetdrill/netdev.h
index c69c1384..115c3453 100644
--- a/gtests/net/packetdrill/netdev.h
+++ b/gtests/net/packetdrill/netdev.h
@@ -87,7 +87,6 @@ static inline int netdev_receive(struct netdev *netdev,
  * packet. Caller must free the packet with packet_free().
  */
 extern int netdev_receive_loop(struct packet_socket *psock,
-			       enum packet_layer_t layer,
 			       enum direction_t direction,
 			       struct packet **packet,
 			       int *num_packets,
diff --git a/gtests/net/packetdrill/packet.c b/gtests/net/packetdrill/packet.c
index b1810ff1..c52bb143 100644
--- a/gtests/net/packetdrill/packet.c
+++ b/gtests/net/packetdrill/packet.c
@@ -102,7 +102,6 @@ struct header *packet_append_header(struct packet *packet,
 {
 	struct header *header = NULL;
 	int num_headers = packet_header_count(packet);
-	int packet_bytes;
 
 	assert(num_headers <= PACKET_MAX_HEADERS);
 	if (num_headers == PACKET_MAX_HEADERS)
@@ -112,8 +111,7 @@ struct header *packet_append_header(struct packet *packet,
 
 	if (packet->ip_bytes + header_bytes > packet->buffer_bytes)
 		return NULL;
-	packet_bytes = packet->l2_header_bytes + packet->ip_bytes;
-	header->h.ptr = packet->buffer + packet_bytes;
+	header->h.ptr = packet->buffer + packet->ip_bytes;
 	packet->ip_bytes += header_bytes;
 
 	header->type = header_type;
diff --git a/gtests/net/packetdrill/packet.h b/gtests/net/packetdrill/packet.h
index 83869bcf..fd4a50ce 100644
--- a/gtests/net/packetdrill/packet.h
+++ b/gtests/net/packetdrill/packet.h
@@ -69,7 +69,6 @@ static const int PACKET_READ_BYTES = 64 * 1024;
 struct packet {
 	u8 *buffer;		/* data buffer: full contents of packet */
 	u32 buffer_bytes;	/* bytes of space in data buffer */
-	u32 l2_header_bytes;	/* bytes in outer hardware/layer-2 header */
 	u32 ip_bytes;		/* bytes in outermost IP hdrs/payload */
 	enum direction_t direction;	/* direction packet is traveling */
 
diff --git a/gtests/net/packetdrill/packet_parser.c b/gtests/net/packetdrill/packet_parser.c
index 0c95a702..b1acd3fe 100644
--- a/gtests/net/packetdrill/packet_parser.c
+++ b/gtests/net/packetdrill/packet_parser.c
@@ -57,29 +57,6 @@ static int parse_layer4(struct packet *packet, u8 *header_start,
 			int layer4_protocol, int layer4_bytes,
 			u8 *packet_end, bool *is_inner, char **error);
 
-static int parse_layer2_packet(struct packet *packet,
-			       u8 *header_start, u8 *packet_end,
-			       char **error)
-{
-	u8 *p = header_start;
-	struct ether_header *ether = NULL;
-
-	/* Find Ethernet header */
-	if (p + sizeof(*ether) > packet_end) {
-		asprintf(error, "Ethernet header overflows packet");
-		goto error_out;
-	}
-	ether = (struct ether_header *)p;
-	p += sizeof(*ether);
-	packet->l2_header_bytes = sizeof(*ether);
-
-	return parse_layer3_packet_by_proto(packet, ntohs(ether->ether_type),
-					    p, packet_end, error);
-
-error_out:
-	return PACKET_BAD;
-}
-
 static int parse_layer3_packet_by_proto(struct packet *packet,
 					u16 proto, u8 *header_start,
 					u8 *packet_end, char **error)
@@ -163,7 +140,7 @@ static int parse_layer3_packet(struct packet *packet,
 }
 
 int parse_packet(struct packet *packet, int in_bytes,
-			 enum packet_layer_t layer, char **error)
+		 u16 ether_type, char **error)
 {
 	assert(in_bytes <= packet->buffer_bytes);
 	char *message = NULL;		/* human-readable error summary */
@@ -173,14 +150,8 @@ int parse_packet(struct packet *packet, int in_bytes,
 	/* packet_end points to the byte beyond the end of packet. */
 	u8 *packet_end = packet->buffer + in_bytes;
 
-	if (layer == PACKET_LAYER_2_ETHERNET)
-		result = parse_layer2_packet(packet, header_start, packet_end,
-					     error);
-	else if (layer == PACKET_LAYER_3_IP)
-		result = parse_layer3_packet(packet, header_start, packet_end,
-					     error);
-	else
-		assert(!"bad layer");
+	result = parse_layer3_packet_by_proto(packet, ether_type,
+					      header_start, packet_end, error);
 
 	if (result != PACKET_BAD)
 		return result;
diff --git a/gtests/net/packetdrill/packet_parser.h b/gtests/net/packetdrill/packet_parser.h
index 8bd65126..160be514 100644
--- a/gtests/net/packetdrill/packet_parser.h
+++ b/gtests/net/packetdrill/packet_parser.h
@@ -27,12 +27,6 @@
 
 #include "packet.h"
 
-/* What layer of headers is at the head of the packet? */
-enum packet_layer_t {
-	PACKET_LAYER_3_IP = 0,		/* no layer 2 headers */
-	PACKET_LAYER_2_ETHERNET,	/* layer 2 is Ethernet */
-};
-
 enum packet_parse_result_t {
 	PACKET_OK,		/* no errors detected */
 	PACKET_BAD,		/* illegal header */
@@ -48,6 +42,6 @@ enum packet_parse_result_t {
  * error message.
  */
 int parse_packet(struct packet *packet, int in_bytes,
-		 enum packet_layer_t layer, char **error);
+		 u16 ether_type, char **error);
 
 #endif /* __PACKET_PARSER_H__ */
diff --git a/gtests/net/packetdrill/packet_parser_test.c b/gtests/net/packetdrill/packet_parser_test.c
index 3aae4e3d..c2545e7d 100644
--- a/gtests/net/packetdrill/packet_parser_test.c
+++ b/gtests/net/packetdrill/packet_parser_test.c
@@ -22,6 +22,7 @@
  * Test for parsing IP packets.
  */
 
+#include "ethernet.h"
 #include "packet_parser.h"
 
 #include <assert.h>
@@ -52,7 +53,7 @@ static void test_parse_tcp_ipv4_packet(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
+		parse_packet(packet, sizeof(data), ETHERTYPE_IP,
 				     &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
@@ -99,7 +100,7 @@ static void test_parse_tcp_ipv6_packet(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
+		parse_packet(packet, sizeof(data), ETHERTYPE_IPV6,
 				     &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
@@ -139,7 +140,7 @@ static void test_parse_udp_ipv4_packet(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
+		parse_packet(packet, sizeof(data), ETHERTYPE_IP,
 				     &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
@@ -183,7 +184,7 @@ static void test_parse_udp_ipv6_packet(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
+		parse_packet(packet, sizeof(data), ETHERTYPE_IPV6,
 				     &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
@@ -233,7 +234,7 @@ static void test_parse_ipv4_gre_ipv4_tcp_packet(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
+		parse_packet(packet, sizeof(data), ETHERTYPE_IP,
 				     &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
@@ -324,7 +325,7 @@ static void test_parse_ipv4_gre_mpls_ipv4_tcp_packet(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
+		parse_packet(packet, sizeof(data), ETHERTYPE_IP,
 				     &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
@@ -401,7 +402,7 @@ static void test_parse_icmpv4_packet(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
+		parse_packet(packet, sizeof(data), ETHERTYPE_IP,
 				     &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
@@ -454,7 +455,7 @@ static void test_parse_icmpv6_packet(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
+		parse_packet(packet, sizeof(data), ETHERTYPE_IPV6,
 				     &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
diff --git a/gtests/net/packetdrill/packet_socket.h b/gtests/net/packetdrill/packet_socket.h
index a2defd39..769378c5 100644
--- a/gtests/net/packetdrill/packet_socket.h
+++ b/gtests/net/packetdrill/packet_socket.h
@@ -63,7 +63,7 @@ extern int packet_socket_writev(struct packet_socket *psock,
  * retry).
  */
 extern int packet_socket_receive(struct packet_socket *psock,
-				 enum direction_t direction,
+				 enum direction_t direction, u16 *ether_type,
 				 struct packet *packet, int *in_bytes);
 
 #endif /* __PACKET_SOCKET_H__ */
diff --git a/gtests/net/packetdrill/packet_socket_linux.c b/gtests/net/packetdrill/packet_socket_linux.c
index 4e889972..95e852bd 100644
--- a/gtests/net/packetdrill/packet_socket_linux.c
+++ b/gtests/net/packetdrill/packet_socket_linux.c
@@ -48,6 +48,7 @@ struct packet_socket {
 	int packet_fd;	/* socket for sending, sniffing timestamped packets */
 	char *name;	/* malloc-allocated copy of interface name */
 	int index;	/* interface index from if_nametoindex */
+	bool trim_ethernet_header;
 };
 
 /* Set the receive buffer for a socket to the given size in bytes. */
@@ -178,6 +179,8 @@ void packet_socket_set_filter(struct packet_socket *psock,
 		       &bpfcode, sizeof(bpfcode)) < 0) {
 		die_perror("setsockopt SOL_SOCKET, SO_ATTACH_FILTER");
 	}
+
+	psock->trim_ethernet_header = true;
 }
 
 struct packet_socket *packet_socket_new(const char *device_name)
@@ -186,6 +189,7 @@ struct packet_socket *packet_socket_new(const char *device_name)
 
 	psock->name = strdup(device_name);
 	psock->packet_fd = -1;
+	psock->trim_ethernet_header = false;
 
 	packet_socket_setup(psock);
 
@@ -215,18 +219,39 @@ int packet_socket_writev(struct packet_socket *psock,
 }
 
 int packet_socket_receive(struct packet_socket *psock,
-			  enum direction_t direction,
+			  enum direction_t direction, u16 *ether_type,
 			  struct packet *packet, int *in_bytes)
 {
 	struct sockaddr_ll from;
-	memset(&from, 0, sizeof(from));
-	socklen_t from_len = sizeof(from);
+	struct ether_header ether;
+	struct iovec iov[2];
+	struct msghdr msg;
 
 	/* Read the packet out of our kernel packet socket buffer. */
-	*in_bytes = recvfrom(psock->packet_fd,
-			     packet->buffer, packet->buffer_bytes, 0,
-			     (struct sockaddr *)&from, &from_len);
-	assert(*in_bytes <= packet->buffer_bytes);
+	memset(&from, 0, sizeof(from));
+	if (psock->trim_ethernet_header) {
+		iov[0].iov_base = &ether;
+		iov[0].iov_len = sizeof(struct ether_header);
+		iov[1].iov_base = packet->buffer;
+		iov[1].iov_len = packet->buffer_bytes;
+	} else {
+		iov[0].iov_base = packet->buffer;
+		iov[0].iov_len = packet->buffer_bytes;
+	}
+	msg.msg_name = &from;
+	msg.msg_namelen = (socklen_t)sizeof(struct sockaddr_ll);
+	msg.msg_iov = iov;
+	msg.msg_iovlen = (psock->trim_ethernet_header == 1) ? 2 : 1;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags = 0;
+	*in_bytes = recvmsg(psock->packet_fd, &msg, 0);
+
+	if (psock->trim_ethernet_header)
+		assert(*in_bytes <=
+		       packet->buffer_bytes + sizeof(struct ether_header));
+	else
+		assert(*in_bytes <= packet->buffer_bytes);
 	if (*in_bytes < 0) {
 		if (errno == EINTR) {
 			DEBUGP("EINTR\n");
@@ -267,6 +292,19 @@ int packet_socket_receive(struct packet_socket *psock,
 	       (u32)tv.tv_sec, (u32)tv.tv_usec,
 	       packet->time_usecs);
 
+	DEBUGP("reported sll_protocol = 0x%04x\n", ntohs(from.sll_protocol));
+	if (psock->trim_ethernet_header) {
+		if (*in_bytes < sizeof(struct ether_header)) {
+			DEBUGP("packet does not contain ethernet header\n");
+			return STATUS_ERR;
+		} else {
+			*ether_type = ntohs(ether.ether_type);
+			*in_bytes -= sizeof(struct ether_header);
+		}
+	} else {
+		*ether_type = ntohs(from.sll_protocol);
+	}
+	DEBUGP("ether_type is 0x%04x\n", *ether_type);
 	return STATUS_OK;
 }
 
diff --git a/gtests/net/packetdrill/packet_socket_pcap.c b/gtests/net/packetdrill/packet_socket_pcap.c
index 04e31063..27d51f73 100644
--- a/gtests/net/packetdrill/packet_socket_pcap.c
+++ b/gtests/net/packetdrill/packet_socket_pcap.c
@@ -52,6 +52,7 @@ struct packet_socket {
 				/* also used for sending packets */
 	char pcap_error[PCAP_ERRBUF_SIZE];	/* for libpcap errors */
 	int pcap_offset;  /* offset of packet data in pcap buffer */
+	int data_link;
 };
 
 #if defined(__OpenBSD__)
@@ -73,7 +74,7 @@ extern void die_pcap_perror(pcap_t *pcap, char *message)
 
 static void packet_socket_setup(struct packet_socket *psock)
 {
-	int data_link = -1, bpf_fd = -1, val = -1;
+	int bpf_fd = -1, val = -1;
 
 	DEBUGP("calling pcap_create() with %s\n", psock->name);
 	psock->pcap_in = pcap_create(psock->name, psock->pcap_error);
@@ -130,26 +131,22 @@ static void packet_socket_setup(struct packet_socket *psock)
 		die_perror("ioctl BIOCIMMEDIATE on bpf fd");
 
 	/* Find data link type. */
-	data_link = pcap_datalink(psock->pcap_in);
-	DEBUGP("data_link: %d\n", data_link);
+	psock->data_link = pcap_datalink(psock->pcap_in);
+	DEBUGP("data_link: %d\n", psock->data_link);
 
 	/* Based on the data_link type, calculate the offset of the
 	 * packet data in the buffer.
 	 */
-	switch (data_link) {
+	switch (psock->data_link) {
 	case DLT_EN10MB:
-		psock->pcap_offset = 0;
+		psock->pcap_offset = sizeof(struct ether_header);
 		break;
 	case DLT_LOOP:
 	case DLT_NULL:
-		psock->pcap_offset = 4;
-		break;
-	case DLT_SLIP:
-	case DLT_RAW:
-		psock->pcap_offset = 0;
+		psock->pcap_offset = sizeof(u32);
 		break;
 	default:
-		die("Unknown data_link type %d\n", data_link);
+		die("Unknown data_link type %d\n", psock->data_link);
 		break;
 	}
 }
@@ -248,13 +245,15 @@ int packet_socket_writev(struct packet_socket *psock,
 }
 
 int packet_socket_receive(struct packet_socket *psock,
-			  enum direction_t direction,
+			  enum direction_t direction, u16 *ether_type,
 			  struct packet *packet, int *in_bytes)
 {
 	int status = 0;
 	struct pcap_pkthdr *pkt_header = NULL;
 	const u8 *pkt_data = NULL;
 	pcap_t *pcap;
+	struct ether_header *ether;
+	u32 address_family;
 
 	DEBUGP("calling pcap_next_ex() for direction %s\n",
 	       direction == DIRECTION_INBOUND ? "inbound" : "outbound");
@@ -320,9 +319,37 @@ int packet_socket_receive(struct packet_socket *psock,
 	assert(pkt_header->len <= packet->buffer_bytes);
 
 	assert(pkt_header->len > psock->pcap_offset);
+	switch (psock->data_link) {
+	case DLT_EN10MB:
+		ether = (struct ether_header *)pkt_data;
+		*ether_type = ntohs(ether->ether_type);
+		break;
+	case DLT_LOOP:
+	case DLT_NULL:
+#if defined(__OpenBSD__)
+		address_family = ntohl(*(u32 *)pkt_data);
+#else
+		address_family = *(u32 *)pkt_data;
+#endif
+		switch (address_family) {
+		case AF_INET:
+			*ether_type = ETHERTYPE_IP;
+			break;
+		case AF_INET6:
+			*ether_type = ETHERTYPE_IPV6;
+			break;
+		default:
+			DEBUGP("Unknown address family %d.\n", address_family);
+			return STATUS_ERR;
+		}
+		break;
+	default:
+		assert(!"not reached");
+		break;
+	}
+	DEBUGP("ether_type is 0x%04x\n", *ether_type);
 	*in_bytes = pkt_header->len - psock->pcap_offset;
 	memcpy(packet->buffer, pkt_data + psock->pcap_offset, *in_bytes);
-
 	return STATUS_OK;
 }
 
diff --git a/gtests/net/packetdrill/packet_to_string_test.c b/gtests/net/packetdrill/packet_to_string_test.c
index fc3b21c7..4d339710 100644
--- a/gtests/net/packetdrill/packet_to_string_test.c
+++ b/gtests/net/packetdrill/packet_to_string_test.c
@@ -27,6 +27,7 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
+#include "ethernet.h"
 #include "packet_parser.h"
 
 static void test_tcp_ipv4_packet_to_string(void)
@@ -56,8 +57,7 @@ static void test_tcp_ipv4_packet_to_string(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
-				     &error);
+		parse_packet(packet, sizeof(data), ETHERTYPE_IP, &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
 
@@ -142,8 +142,7 @@ static void test_tcp_ipv6_packet_to_string(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
-				     &error);
+		parse_packet(packet, sizeof(data), ETHERTYPE_IPV6, &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
 
@@ -224,8 +223,7 @@ static void test_gre_mpls_tcp_ipv4_packet_to_string(void)
 	memcpy(packet->buffer, data, sizeof(data));
 	char *error = NULL;
 	enum packet_parse_result_t result =
-		parse_packet(packet, sizeof(data), PACKET_LAYER_3_IP,
-				     &error);
+		parse_packet(packet, sizeof(data), ETHERTYPE_IP, &error);
 	assert(result == PACKET_OK);
 	assert(error == NULL);
 
diff --git a/gtests/net/packetdrill/types.h b/gtests/net/packetdrill/types.h
index 50d7edf2..ffb24e00 100644
--- a/gtests/net/packetdrill/types.h
+++ b/gtests/net/packetdrill/types.h
@@ -49,6 +49,9 @@
 #ifndef __packed
 #define __packed __attribute__ ((packed))
 #endif
+#ifndef __aligned
+#define __aligned(x) __attribute__ ((aligned(x)))
+#endif
 
 /* We use kernel-style names for standard integer types. */
 typedef unsigned char u8;
diff --git a/gtests/net/packetdrill/wire_server_netdev.c b/gtests/net/packetdrill/wire_server_netdev.c
index cee64e7a..8ef26f3a 100644
--- a/gtests/net/packetdrill/wire_server_netdev.c
+++ b/gtests/net/packetdrill/wire_server_netdev.c
@@ -192,9 +192,8 @@ static int wire_server_netdev_receive(struct netdev *a_netdev,
 
 	DEBUGP("wire_server_netdev_receive\n");
 
-	return netdev_receive_loop(netdev->psock, PACKET_LAYER_2_ETHERNET,
-				   DIRECTION_INBOUND, packet, &num_packets,
-				   error);
+	return netdev_receive_loop(netdev->psock, DIRECTION_INBOUND, packet,
+				   &num_packets, error);
 }
 
 struct netdev_ops wire_server_netdev_ops = {
-- 
GitLab