diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/Makefile | 1 | ||||
-rw-r--r-- | net/eth-uclass.c | 5 | ||||
-rw-r--r-- | net/eth_legacy.c | 10 | ||||
-rw-r--r-- | net/net.c | 11 | ||||
-rw-r--r-- | net/pcap.c | 156 |
5 files changed, 182 insertions, 1 deletions
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) @@ -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; +} |