summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/Kconfig7
-rw-r--r--cmd/Makefile1
-rw-r--r--cmd/pcap.c71
-rw-r--r--include/net/pcap.h55
-rw-r--r--net/Makefile1
-rw-r--r--net/eth-uclass.c5
-rw-r--r--net/eth_legacy.c10
-rw-r--r--net/net.c11
-rw-r--r--net/pcap.c156
9 files changed, 316 insertions, 1 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 05872fa0d7..98647f58b7 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1339,6 +1339,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 58827b5679..ac843b4b16 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -103,6 +103,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 826544f05f..2a700c8401 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -22,6 +22,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 1d5d2f03b7..3bd98b01ad 100644
--- a/net/eth-uclass.c
+++ b/net/eth-uclass.c
@@ -11,6 +11,7 @@
#include <net.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
+#include <net/pcap.h>
#include "eth_internal.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -344,6 +345,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 850f362d87..41f5263526 100644
--- a/net/eth_legacy.c
+++ b/net/eth_legacy.c
@@ -11,6 +11,7 @@
#include <net.h>
#include <phy.h>
#include <linux/errno.h>
+#include <net/pcap.h>
#include "eth_internal.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -352,10 +353,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 40511db645..74a8a36b5a 100644
--- a/net/net.c
+++ b/net/net.c
@@ -96,6 +96,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>
@@ -672,6 +675,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;
}
@@ -1084,6 +1092,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;
+}