[U-Boot] [PATCH] net: introduce packet capture support

Alex Marginean alexm.osslist at gmail.com
Fri Jun 21 11:40:18 UTC 2019


Hi Ramon,

On 6/14/2019 9:18 AM, Ramon Fried wrote:
> Add support for capturing ethernet packets and storing
> them in memory in PCAP(2.4) format, later to be analyzed by
> any PCAP viewer software (IE. Wireshark)
> 
> This feature greatly assist debugging network issues such
> as detecting dropped packets, packet corruption etc.
> 
> Signed-off-by: Ramon Fried <rfried.dev at gmail.com>
> ---
> 
>   include/net.h | 29 ++++++++++++++++++
>   net/Kconfig   | 22 ++++++++++++++
>   net/Makefile  |  1 +
>   net/net.c     | 11 +++++++
>   net/pcap.c    | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   5 files changed, 146 insertions(+)
>   create mode 100644 net/pcap.c

Reviewed-by: Alex Marginean <alexm.osslist at gmail.com>
Tested-by: Alex Marginean <alexm.osslist at gmail.com>

There's one typo in filling the packet time which makes it come out
wrong, see below.

This is a really nice feature, I suggest you consider adding a pcap
command to:
- set start address, making NET_PCAP_ADDR optional,
- start/stop capture,
- restart the capture from the beginning of the buffer,
- maybe print the current state - buffer address, pcap size, on/off
state.

I used tftpput to copy the pcap out, fatwrite should also work.

> 
> diff --git a/include/net.h b/include/net.h
> index 44b32385c4..d1dc864896 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -630,6 +630,31 @@ bool arp_is_waiting(void);		/* Waiting for ARP reply? */
>   void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */
>   void net_set_timeout_handler(ulong, thand_f *);/* Set timeout handler */
>   
> +/* PCAP extension */
> +
> +/**
> + * pcap_init() - Initialize PCAP memory buffer
> + *
> + * @return	0 on success, -ERROR on error
> + */
> +int pcap_init(void);
> +
> +/**
> + * pcap_post() - Post a packet to PCAP file
> + *
> + * @packet:	packet to post
> + * @len:	packet length in bytes
> + * @return	0 on success, -ERROR on error
> + */
> +int pcap_post(const void *packet, size_t len);
> +
> +/**
> + * pcap_size() - get size of PCAP file
> + *
> + * @return	size of PCAP file in bytes
> + */
> +unsigned int pcap_size(void);
> +
>   /* Network loop state */
>   enum net_loop_state {
>   	NETLOOP_CONTINUE,
> @@ -658,6 +683,10 @@ static inline void net_send_packet(uchar *pkt, int len)
>   {
>   	/* Currently no way to return errors from eth_send() */
>   	(void) eth_send(pkt, len);
> +
> +#if defined(CONFIG_NET_PCAP)
> +	pcap_post(pkt, len);
> +#endif
>   }
>   
>   /*
> diff --git a/net/Kconfig b/net/Kconfig
> index f2363e5256..8b8ab88e57 100644
> --- a/net/Kconfig
> +++ b/net/Kconfig
> @@ -8,6 +8,28 @@ menuconfig NET
>   
>   if NET
>   
> +config NET_PCAP
> +	bool "PCAP network capture"
> +	help
> +	  Selecting this will capture all Ethernet packets and store
> +	  them in a PCAP formated file later to be analyzed by PCAP
> +	  reader application (IE. WireShark).
> +
> +config NET_PCAP_ADDR
> +	hex "Address of PCAP file in memory"
> +	depends on NET_PCAP
> +	help
> +	  Sets the address of the PCAP file in physical memory.
> +
> +config NET_PCAP_SIZE
> +	hex "Size of PCAP file"
> +	depends on NET_PCAP
> +	default 0x100000
> +	help
> +	  Sets the maximum size of PCAP file in bytes.
> +	  When it fills up completely, it will stop capturing
> +	  packets silently.
> +
>   config NET_RANDOM_ETHADDR
>   	bool "Random ethaddr if unset"
>   	help
> diff --git a/net/Makefile b/net/Makefile
> index ce36362168..85103fee93 100644
> --- a/net/Makefile
> +++ b/net/Makefile
> @@ -18,6 +18,7 @@ endif
>   obj-$(CONFIG_NET)      += eth_common.o
>   obj-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
>   obj-$(CONFIG_NET)      += net.o
> +obj-$(CONFIG_NET_PCAP) += pcap.o
>   obj-$(CONFIG_CMD_NFS)  += nfs.o
>   obj-$(CONFIG_CMD_PING) += ping.o
>   obj-$(CONFIG_CMD_RARP) += rarp.o
> diff --git a/net/net.c b/net/net.c
> index 58b0417cbe..d0bdf8fe20 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -387,6 +387,10 @@ void net_init(void)
>   
>   		/* Only need to setup buffer pointers once. */
>   		first_call = 0;
> +
> +#if defined(CONFIG_NET_PCAP)
> +		pcap_init();
> +#endif
>   	}
>   
>   	net_init_loop();
> @@ -671,6 +675,10 @@ done:
>   	net_set_icmp_handler(NULL);
>   #endif
>   	net_set_state(prev_net_state);
> +
> +#if defined(CONFIG_NET_PCAP)
> +	printf("PCAP len: 0x%x\n", pcap_size());
> +#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_NET_PCAP)
> +	pcap_post(in_packet, len);
> +#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..dadfa7563b
> --- /dev/null
> +++ b/net/pcap.c
> @@ -0,0 +1,83 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2019 Ramon Fried <rfried.dev at gmail.com>
> + */
> +
> +#include <common.h>
> +#include <net.h>
> +#include <time.h>
> +#include <asm/io.h>
> +
> +#define LINKTYPE_ETHERNET	1
> +
> +static void *buf;
> +static unsigned int pos;
> +
> +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(void)
> +{
> +	buf = map_physmem(CONFIG_NET_PCAP_ADDR, CONFIG_NET_PCAP_SIZE, 0);
> +	if (!buf) {
> +		printf("Failed mapping PCAP memory\n");
> +		return -ENOMEM;
> +	}
> +
> +	printf("PCAP capture initialized: addr: 0x%lx max length: 0x%x\n",
> +	       (unsigned long)buf, CONFIG_NET_PCAP_SIZE);
> +
> +	memcpy(buf, &file_header, sizeof(file_header));
> +	pos += sizeof(file_header);
> +	return 0;
> +}
> +
> +int pcap_post(const void *packet, size_t len)
> +{
> +	struct pcap_packet_header header;
> +	u64 cur_time = timer_get_us();
> +
> +	if (!buf)
> +		return -ENODEV;
> +	if ((pos + len + sizeof(header)) >= CONFIG_NET_PCAP_SIZE)
> +		return -ENOMEM;
> +
> +	header.ts_sec = cur_time / 1000000;
> +	header.ts_sec = cur_time % 1000000;

This should be header.ts_usec.

Thank you!
Alex

> +	header.incl_len = len;
> +	header.orig_len = len;
> +
> +	memcpy(buf + pos, &header, sizeof(header));
> +	pos += sizeof(header);
> +	memcpy(buf + pos, packet, len);
> +	pos += len;
> +
> +	return 0;
> +}
> +
> +unsigned int pcap_size(void)
> +{
> +	return pos;
> +}
> 



More information about the U-Boot mailing list