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

Ramon Fried rfried.dev at gmail.com
Fri Jun 21 14:02:20 UTC 2019


On Fri, Jun 21, 2019 at 2:40 PM Alex Marginean <alexm.osslist at gmail.com> wrote:
>
> 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.
Right !
Thanks,
Ramon
>
> 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