diff --git a/cmd/Kconfig b/cmd/Kconfig
index 67284d8a5f..86aa5d8c00 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1263,6 +1263,13 @@ config BOOTP_NTPSERVER
 	bool "Request & store 'ntpserverip' from BOOTP/DHCP server"
 	depends on CMD_BOOTP
 
+config CMD_PCAP
+	bool "pcap capture"
+	help
+	  Selecting this will allow capturing all Ethernet packets and store
+	  them in physical memory in a PCAP formated file,
+	  later to be analyzed by PCAP reader application (IE. WireShark).
+
 config BOOTP_PXE
 	bool "Send PXE client arch to BOOTP/DHCP server"
 	default y
diff --git a/cmd/Makefile b/cmd/Makefile
index 0aa3741453..61d5bc885a 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o
 obj-$(CONFIG_CMD_ONENAND) += onenand.o
 obj-$(CONFIG_CMD_OSD) += osd.o
 obj-$(CONFIG_CMD_PART) += part.o
+obj-$(CONFIG_CMD_PCAP) += pcap.o
 ifdef CONFIG_PCI
 obj-$(CONFIG_CMD_PCI) += pci.o
 endif
diff --git a/cmd/pcap.c b/cmd/pcap.c
new file mode 100644
index 0000000000..980603f7bd
--- /dev/null
+++ b/cmd/pcap.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019
+ * Ramon Fried <rfried.dev@gmail.com>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <net/pcap.h>
+
+static int do_pcap_init(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	phys_addr_t addr;
+	unsigned int size;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	addr = simple_strtoul(argv[1], NULL, 16);
+	size = simple_strtoul(argv[2], NULL, 10);
+
+	return pcap_init(addr, size) ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static int do_pcap_start(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char * const argv[])
+{
+	return pcap_start_stop(true) ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static int do_pcap_stop(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	return pcap_start_stop(false) ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static int do_pcap_status(cmd_tbl_t *cmdtp, int flag, int argc,
+			  char * const argv[])
+{
+	return pcap_print_status() ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static int do_pcap_clear(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char * const argv[])
+{
+	return pcap_clear() ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static char pcap_help_text[] =
+	"- network packet capture\n\n"
+	"pcap\n"
+	"pcap init\t\t\t<addr> <max_size>\n"
+	"pcap start\t\t\tstart capture\n"
+	"pcap stop\t\t\tstop capture\n"
+	"pcap status\t\t\tprint status\n"
+	"pcap clear\t\t\tclear capture buffer\n"
+	"\n"
+	"With:\n"
+	"\t<addr>: user address to which pcap will be stored (hexedcimal)\n"
+	"\t<max_size>: Maximum size of pcap file (decimal)\n"
+	"\n";
+
+U_BOOT_CMD_WITH_SUBCMDS(pcap, "pcap", pcap_help_text,
+			U_BOOT_SUBCMD_MKENT(init, 3, 0, do_pcap_init),
+			U_BOOT_SUBCMD_MKENT(start, 1, 0, do_pcap_start),
+			U_BOOT_SUBCMD_MKENT(stop, 1, 0, do_pcap_stop),
+			U_BOOT_SUBCMD_MKENT(status, 1, 0, do_pcap_status),
+			U_BOOT_SUBCMD_MKENT(clear, 1, 0, do_pcap_clear),
+);
diff --git a/include/net/pcap.h b/include/net/pcap.h
new file mode 100644
index 0000000000..512ba982f1
--- /dev/null
+++ b/include/net/pcap.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019
+ * Ramon Fried <rfried.dev@gmail.com>
+ */
+
+/**
+ * pcap_init() - Initialize PCAP memory buffer
+ *
+ * @paddr	physicaly memory address to store buffer
+ * @size	maximum size of capture file in memory
+ *
+ * @return	0 on success, -ERROR on error
+ */
+int pcap_init(phys_addr_t paddr, unsigned long size);
+
+/**
+ * pcap_start_stop() - start / stop pcap capture
+ *
+ * @start	if true, start capture if false stop capture
+ *
+ * @return	0 on success, -ERROR on error
+ */
+int pcap_start_stop(bool start);
+
+/**
+ * pcap_clear() - clear pcap capture buffer and statistics
+ *
+ * @return	0 on success, -ERROR on error
+ */
+int pcap_clear(void);
+
+/**
+ * pcap_print_status() - print status of pcap capture
+ *
+ * @return	0 on success, -ERROR on error
+ */
+int pcap_print_status(void);
+
+/**
+ * pcap_active() - check if pcap is enabled
+ *
+ * @return	TRUE if active, FALSE if not.
+ */
+bool pcap_active(void);
+
+/**
+ * pcap_post() - Post a packet to PCAP file
+ *
+ * @packet:	packet to post
+ * @len:	packet length in bytes
+ * @outgoing	packet direction (outgoing/incoming)
+ * @return	0 on success, -ERROR on error
+ */
+int pcap_post(const void *packet, size_t len, bool outgoing);
diff --git a/net/Makefile b/net/Makefile
index 6251ff3991..b975badeda 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
 obj-$(CONFIG_NET)      += net.o
 obj-$(CONFIG_CMD_NFS)  += nfs.o
 obj-$(CONFIG_CMD_PING) += ping.o
+obj-$(CONFIG_CMD_PCAP) += pcap.o
 obj-$(CONFIG_CMD_RARP) += rarp.o
 obj-$(CONFIG_CMD_SNTP) += sntp.o
 obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
diff --git a/net/eth-uclass.c b/net/eth-uclass.c
index 031d558625..4252a02659 100644
--- a/net/eth-uclass.c
+++ b/net/eth-uclass.c
@@ -9,6 +9,9 @@
 #include <dm.h>
 #include <environment.h>
 #include <net.h>
+#if defined(CONFIG_CMD_PCAP)
+#include <net/pcap.h>
+#endif
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
 #include "eth_internal.h"
@@ -344,6 +347,10 @@ int eth_send(void *packet, int length)
 		/* We cannot completely return the error at present */
 		debug("%s: send() returned error %d\n", __func__, ret);
 	}
+#if defined(CONFIG_CMD_PCAP)
+	if (ret >= 0)
+		pcap_post(packet, length, true);
+#endif
 	return ret;
 }
 
diff --git a/net/eth_legacy.c b/net/eth_legacy.c
index e250a430f3..0705b7ccea 100644
--- a/net/eth_legacy.c
+++ b/net/eth_legacy.c
@@ -9,6 +9,9 @@
 #include <command.h>
 #include <environment.h>
 #include <net.h>
+#if defined(CONFIG_CMD_PCAP)
+#include <net/pcap.h>
+#endif
 #include <phy.h>
 #include <linux/errno.h>
 #include "eth_internal.h"
@@ -352,10 +355,17 @@ int eth_is_active(struct eth_device *dev)
 
 int eth_send(void *packet, int length)
 {
+	int ret;
+
 	if (!eth_current)
 		return -ENODEV;
 
-	return eth_current->send(eth_current, packet, length);
+	ret = eth_current->send(eth_current, packet, length);
+#if defined(CONFIG_CMD_PCAP)
+	if (ret >= 0)
+		pcap_post(packet, lengeth, true);
+#endif
+	return ret;
 }
 
 int eth_rx(void)
diff --git a/net/net.c b/net/net.c
index 58b0417cbe..722fa7a705 100644
--- a/net/net.c
+++ b/net/net.c
@@ -95,6 +95,9 @@
 #include <net.h>
 #include <net/fastboot.h>
 #include <net/tftp.h>
+#if defined(CONFIG_CMD_PCAP)
+#include <net/pcap.h>
+#endif
 #if defined(CONFIG_LED_STATUS)
 #include <miiphy.h>
 #include <status_led.h>
@@ -671,6 +674,11 @@ done:
 	net_set_icmp_handler(NULL);
 #endif
 	net_set_state(prev_net_state);
+
+#if defined(CONFIG_CMD_PCAP)
+	if (pcap_active())
+		pcap_print_status();
+#endif
 	return ret;
 }
 
@@ -1083,6 +1091,9 @@ void net_process_received_packet(uchar *in_packet, int len)
 
 	debug_cond(DEBUG_NET_PKT, "packet received\n");
 
+#if defined(CONFIG_CMD_PCAP)
+	pcap_post(in_packet, len, false);
+#endif
 	net_rx_packet = in_packet;
 	net_rx_packet_len = len;
 	et = (struct ethernet_hdr *)in_packet;
diff --git a/net/pcap.c b/net/pcap.c
new file mode 100644
index 0000000000..4036d8a3fa
--- /dev/null
+++ b/net/pcap.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Ramon Fried <rfried.dev@gmail.com>
+ */
+
+#include <common.h>
+#include <net.h>
+#include <net/pcap.h>
+#include <time.h>
+#include <asm/io.h>
+
+#define LINKTYPE_ETHERNET	1
+
+static bool initialized;
+static bool running;
+static bool buffer_full;
+static void *buf;
+static unsigned int max_size;
+static unsigned int pos;
+
+static unsigned long incoming_count;
+static unsigned long outgoing_count;
+
+struct pcap_header {
+	u32 magic;
+	u16 version_major;
+	u16 version_minor;
+	s32 thiszone;
+	u32 sigfigs;
+	u32 snaplen;
+	u32 network;
+};
+
+struct pcap_packet_header {
+	u32 ts_sec;
+	u32 ts_usec;
+	u32 incl_len;
+	u32 orig_len;
+};
+
+static struct pcap_header file_header = {
+	.magic = 0xa1b2c3d4,
+	.version_major = 2,
+	.version_minor = 4,
+	.snaplen = 65535,
+	.network = LINKTYPE_ETHERNET,
+};
+
+int pcap_init(phys_addr_t paddr, unsigned long size)
+{
+	buf = map_physmem(paddr, size, 0);
+	if (!buf) {
+		printf("Failed mapping PCAP memory\n");
+		return -ENOMEM;
+	}
+
+	printf("PCAP capture initialized: addr: 0x%lx max length: %lu\n",
+	       (unsigned long)buf, size);
+
+	memcpy(buf, &file_header, sizeof(file_header));
+	pos = sizeof(file_header);
+	max_size = size;
+	initialized = true;
+	running = false;
+	buffer_full = false;
+	incoming_count = 0;
+	outgoing_count = 0;
+	return 0;
+}
+
+int pcap_start_stop(bool start)
+{
+	if (!initialized) {
+		printf("error: pcap was not initialized\n");
+		return -ENODEV;
+	}
+
+	running = start;
+
+	return 0;
+}
+
+int pcap_clear(void)
+{
+	if (!initialized) {
+		printf("error: pcap was not initialized\n");
+		return -ENODEV;
+	}
+
+	pos = sizeof(file_header);
+	incoming_count = 0;
+	outgoing_count = 0;
+	buffer_full = false;
+
+	printf("pcap capture cleared\n");
+	return 0;
+}
+
+int pcap_post(const void *packet, size_t len, bool outgoing)
+{
+	struct pcap_packet_header header;
+	u64 cur_time = timer_get_us();
+
+	if (!initialized || !running || !buf)
+		return -ENODEV;
+
+	if (buffer_full)
+		return -ENOMEM;
+
+	if ((pos + len + sizeof(header)) >= max_size) {
+		buffer_full = true;
+		printf("\n!!! Buffer is full, consider increasing buffer size !!!\n");
+		return -ENOMEM;
+	}
+
+	header.ts_sec = cur_time / 1000000;
+	header.ts_usec = cur_time % 1000000;
+	header.incl_len = len;
+	header.orig_len = len;
+
+	memcpy(buf + pos, &header, sizeof(header));
+	pos += sizeof(header);
+	memcpy(buf + pos, packet, len);
+	pos += len;
+
+	if (outgoing)
+		outgoing_count++;
+	else
+		incoming_count++;
+
+	env_set_hex("pcapsize", pos);
+
+	return 0;
+}
+
+int pcap_print_status(void)
+{
+	if (!initialized) {
+		printf("pcap was not initialized\n");
+		return -ENODEV;
+	}
+	printf("PCAP status:\n");
+	printf("\tInitialized addr: 0x%lx\tmax length: %u\n",
+	       (unsigned long)buf, max_size);
+	printf("\tStatus: %s.\t file size: %u\n", running ? "Active" : "Idle",
+	       pos);
+	printf("\tIncoming packets: %lu Outgoing packets: %lu\n",
+	       incoming_count, outgoing_count);
+
+	return 0;
+}
+
+bool pcap_active(void)
+{
+	return running;
+}
